1 |
/* |
2 |
rdesktop: A Remote Desktop Protocol client. |
3 |
User interface services - VNC target |
4 |
Copyright (C) Matthew Chapman 1999-2000 |
5 |
Copyright (C) 2000 Tim Edmonds |
6 |
Copyright (C) 2001 James "Wez" Weatherall |
7 |
Copyright (C) 2001 Johannes E. Schindelin |
8 |
|
9 |
This program is free software; you can redistribute it and/or modify |
10 |
it under the terms of the GNU General Public License as published by |
11 |
the Free Software Foundation; either version 2 of the License, or |
12 |
(at your option) any later version. |
13 |
|
14 |
This program is distributed in the hope that it will be useful, |
15 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
GNU General Public License for more details. |
18 |
|
19 |
You should have received a copy of the GNU General Public License |
20 |
along with this program; if not, write to the Free Software |
21 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 |
*/ |
23 |
|
24 |
|
25 |
#include <stdio.h> |
26 |
#include <time.h> |
27 |
|
28 |
#ifdef WIN32 |
29 |
#define close closesocket |
30 |
#define strcasecmp _strcmpi |
31 |
#else |
32 |
#include <unistd.h> |
33 |
#include <sys/time.h> /* timeval */ |
34 |
#include <sys/socket.h> |
35 |
#endif |
36 |
|
37 |
#include "../rdesktop.h" |
38 |
#undef VERSION |
39 |
|
40 |
#ifdef WIN32 |
41 |
#define HBITMAP R_HBITMAP |
42 |
#define HCURSOR R_HCURSOR |
43 |
#define WORD R_WORD |
44 |
#endif |
45 |
#include "vnc.h" |
46 |
#ifdef WIN32 |
47 |
#undef HBITMAP |
48 |
#undef HCURSOR |
49 |
#undef WORD |
50 |
#endif |
51 |
|
52 |
#include <errno.h> |
53 |
#include <sys/socket.h> |
54 |
extern int ListenOnTCPPort(int port); |
55 |
extern int rfbClientSocket; |
56 |
|
57 |
#include <rfb/rfbregion.h> |
58 |
|
59 |
#define BITSPERBYTES 8 |
60 |
#define TOBYTES(bits) ((bits)/BITSPERBYTES) |
61 |
|
62 |
extern int g_width; |
63 |
extern int g_height; |
64 |
extern int keylayout; |
65 |
extern BOOL sendmotion; |
66 |
#ifdef ENABLE_SHADOW |
67 |
extern int client_counter; |
68 |
#endif |
69 |
|
70 |
|
71 |
int rfb_port = 5923; |
72 |
int defer_time = 5; |
73 |
int rfbClientSocket = 0; |
74 |
static rfbScreenInfoPtr server = NULL; |
75 |
static vncBuffer *frameBuffer = NULL; |
76 |
static uint8_t reverseByte[0x100]; |
77 |
BOOL g_enable_compose = False; |
78 |
int g_display = 0; |
79 |
|
80 |
/* ignored */ |
81 |
BOOL owncolmap = False; |
82 |
BOOL enable_compose = False; |
83 |
|
84 |
void |
85 |
vncHideCursor() |
86 |
{ |
87 |
if (server->clientHead) |
88 |
rfbUndrawCursor(server); |
89 |
} |
90 |
|
91 |
/* -=- mouseLookup |
92 |
* Table converting mouse button number (0-2) to flag |
93 |
*/ |
94 |
|
95 |
int mouseLookup[3] = { |
96 |
MOUSE_FLAG_BUTTON1, MOUSE_FLAG_BUTTON3, MOUSE_FLAG_BUTTON2 |
97 |
}; |
98 |
|
99 |
int clipX, clipY, clipW, clipH; |
100 |
|
101 |
BOOL |
102 |
vncwinClipRect(int *x, int *y, int *cx, int *cy) |
103 |
{ |
104 |
if (*x + *cx > clipX + clipW) |
105 |
*cx = clipX + clipW - *x; |
106 |
if (*y + *cy > clipY + clipH) |
107 |
*cy = clipY + clipH - *y; |
108 |
if (*x < clipX) |
109 |
{ |
110 |
*cx -= clipX - *x; |
111 |
*x = clipX; |
112 |
} |
113 |
if (*y < clipY) |
114 |
{ |
115 |
*cy -= clipY - *y; |
116 |
*y = clipY; |
117 |
} |
118 |
if (*cx < 0 || *cy < 0) |
119 |
*cx = *cy = 0; |
120 |
return (*cx > 0 && *cy > 0 && *x < server->width && *y < server->height); |
121 |
} |
122 |
|
123 |
void |
124 |
xwin_toggle_fullscreen(void) |
125 |
{ |
126 |
} |
127 |
|
128 |
static int lastbuttons = 0; |
129 |
|
130 |
#define FIRST_MODIFIER XK_Shift_L |
131 |
#define LAST_MODIFIER XK_Hyper_R |
132 |
|
133 |
static BOOL keystate[LAST_MODIFIER - FIRST_MODIFIER]; |
134 |
|
135 |
void |
136 |
init_keyboard() |
137 |
{ |
138 |
int i; |
139 |
for (i = 0; i < LAST_MODIFIER - FIRST_MODIFIER; i++) |
140 |
keystate[i] = 0; |
141 |
|
142 |
xkeymap_init(); |
143 |
} |
144 |
|
145 |
BOOL |
146 |
get_key_state(unsigned int state, uint32 keysym) |
147 |
{ |
148 |
if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER) |
149 |
return keystate[keysym - FIRST_MODIFIER]; |
150 |
return 0; |
151 |
} |
152 |
|
153 |
void |
154 |
vncKey(rfbBool down, rfbKeySym keysym, struct _rfbClientRec *cl) |
155 |
{ |
156 |
uint32 ev_time = time(NULL); |
157 |
key_translation tr = { 0, 0 }; |
158 |
|
159 |
if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER) |
160 |
{ |
161 |
/* TODO: fake local state */ |
162 |
keystate[keysym - FIRST_MODIFIER] = down; |
163 |
} |
164 |
|
165 |
if (down) |
166 |
{ |
167 |
/* TODO: fake local state */ |
168 |
if (handle_special_keys(keysym, 0, ev_time, True)) |
169 |
return; |
170 |
|
171 |
/* TODO: fake local state */ |
172 |
tr = xkeymap_translate_key(keysym, 0, 0); |
173 |
|
174 |
if (tr.scancode == 0) |
175 |
return; |
176 |
|
177 |
ensure_remote_modifiers(ev_time, tr); |
178 |
|
179 |
rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode); |
180 |
} |
181 |
else |
182 |
{ |
183 |
/* todO: fake local state */ |
184 |
if (handle_special_keys(keysym, 0, ev_time, False)) |
185 |
return; |
186 |
|
187 |
/* todO: fake local state */ |
188 |
tr = xkeymap_translate_key(keysym, 0, 0); |
189 |
|
190 |
if (tr.scancode == 0) |
191 |
return; |
192 |
|
193 |
rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode); |
194 |
} |
195 |
} |
196 |
|
197 |
void |
198 |
vncMouse(int buttonMask, int x, int y, struct _rfbClientRec *cl) |
199 |
{ |
200 |
int b; |
201 |
uint32 ev_time = time(NULL); |
202 |
|
203 |
rdp_send_input(ev_time, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, x, y); |
204 |
|
205 |
for (b = 0; b < 3; b++) |
206 |
{ |
207 |
int bb = 1 << (b); |
208 |
if (!(lastbuttons & bb) && (buttonMask & bb)) |
209 |
{ |
210 |
rdp_send_input(ev_time, RDP_INPUT_MOUSE, |
211 |
(mouseLookup[b]) | MOUSE_FLAG_DOWN, x, y); |
212 |
} |
213 |
else if ((lastbuttons & bb) && !(buttonMask & bb)) |
214 |
{ |
215 |
rdp_send_input(ev_time, RDP_INPUT_MOUSE, (mouseLookup[b]), x, y); |
216 |
} |
217 |
} |
218 |
lastbuttons = buttonMask; |
219 |
|
220 |
/* handle cursor */ |
221 |
rfbDefaultPtrAddEvent(buttonMask, x, y, cl); |
222 |
} |
223 |
|
224 |
|
225 |
void |
226 |
rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password, |
227 |
char *shell, char *directory) |
228 |
{ |
229 |
struct sockaddr addr; |
230 |
fd_set fdset; |
231 |
struct timeval tv; |
232 |
int rfbListenSock, addrlen = sizeof(addr); |
233 |
|
234 |
rfbListenSock = rfbListenOnTCPPort(rfb_port); |
235 |
fprintf(stderr, "Listening on VNC port %d\n", rfb_port); |
236 |
if (rfbListenSock <= 0) |
237 |
error("Cannot listen on port %d", rfb_port); |
238 |
else |
239 |
while (1) |
240 |
{ |
241 |
FD_ZERO(&fdset); |
242 |
FD_SET(rfbListenSock, &fdset); |
243 |
tv.tv_sec = 5; |
244 |
tv.tv_usec = 0; |
245 |
if (select(rfbListenSock + 1, &fdset, NULL, NULL, &tv) > 0) |
246 |
{ |
247 |
rfbClientSocket = accept(rfbListenSock, &addr, &addrlen); |
248 |
if (rfbClientSocket < 0) |
249 |
{ |
250 |
error("Error accepting client (%d: %s.\n", |
251 |
errno, strerror(errno)); |
252 |
continue; |
253 |
} |
254 |
ui_create_window(); |
255 |
if (!rdp_connect(server, flags, domain, password, shell, directory)) |
256 |
{ |
257 |
error("Error connecting to RDP server.\n"); |
258 |
continue; |
259 |
} |
260 |
if (!fork()) |
261 |
{ |
262 |
BOOL deactivated; |
263 |
uint32_t ext_disc_reason; |
264 |
printf("Connection successful.\n"); |
265 |
rdp_main_loop(&deactivated, &ext_disc_reason); |
266 |
printf("Disconnecting...\n"); |
267 |
rdp_disconnect(); |
268 |
ui_destroy_window(); |
269 |
exit(0); |
270 |
} |
271 |
} |
272 |
} |
273 |
} |
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
extern char g_title[]; |
280 |
BOOL |
281 |
ui_create_window() |
282 |
{ |
283 |
int i; |
284 |
|
285 |
for (i = 0; i < 0x100; i++) |
286 |
reverseByte[i] = |
287 |
(((i >> 7) & 1)) | (((i >> 6) & 1) << 1) | (((i >> 5) & 1) << 2) | |
288 |
(((i >> 4) & 1) << 3) | (((i >> 3) & 1) << 4) | (((i >> 2) & 1) << 5) | |
289 |
(((i >> 1) & 1) << 6) | (((i >> 0) & 1) << 7); |
290 |
|
291 |
server = rfbGetScreen(0, NULL, g_width, g_height, 8, 1, 1); |
292 |
server->desktopName = g_title; |
293 |
server->frameBuffer = (char *) malloc(g_width * g_height); |
294 |
server->ptrAddEvent = vncMouse; |
295 |
server->kbdAddEvent = vncKey; |
296 |
#ifdef ENABLE_SHADOW |
297 |
server->httpPort = 6124 + client_counter; |
298 |
server->port = 5924 + client_counter; |
299 |
rfbInitSockets(server); |
300 |
server->alwaysShared = TRUE; |
301 |
server->neverShared = FALSE; |
302 |
#else |
303 |
server->port = -1; |
304 |
server->alwaysShared = FALSE; |
305 |
server->neverShared = FALSE; |
306 |
#endif |
307 |
server->inetdSock = rfbClientSocket; |
308 |
server->serverFormat.trueColour = FALSE; /* activate colour maps */ |
309 |
server->deferUpdateTime = defer_time; |
310 |
|
311 |
frameBuffer = (vncBuffer *) malloc(sizeof(vncBuffer)); |
312 |
frameBuffer->w = g_width; |
313 |
frameBuffer->h = g_height; |
314 |
frameBuffer->linew = g_width; |
315 |
frameBuffer->data = server->frameBuffer; |
316 |
frameBuffer->owner = FALSE; |
317 |
frameBuffer->format = &server->serverFormat; |
318 |
|
319 |
ui_set_clip(0, 0, g_width, g_height); |
320 |
|
321 |
rfbInitServer(server); |
322 |
#ifndef ENABLE_SHADOW |
323 |
server->port = rfb_port; |
324 |
#else |
325 |
fprintf(stderr, "server listening on port %d (socket %d)\n", server->port, |
326 |
server->listenSock); |
327 |
#endif |
328 |
|
329 |
init_keyboard(); |
330 |
|
331 |
return (server != NULL); |
332 |
} |
333 |
|
334 |
void |
335 |
ui_destroy_window() |
336 |
{ |
337 |
rfbCloseClient(server->clientHead); |
338 |
} |
339 |
|
340 |
|
341 |
int |
342 |
ui_select(int rdpSocket) |
343 |
{ |
344 |
fd_set fds; |
345 |
struct timeval tv; |
346 |
int n, m = server->maxFd; |
347 |
|
348 |
if (rdpSocket > m) |
349 |
m = rdpSocket; |
350 |
while (1) |
351 |
{ |
352 |
fds = server->allFds; |
353 |
FD_SET(rdpSocket, &fds); |
354 |
tv.tv_sec = defer_time / 1000; |
355 |
tv.tv_usec = (defer_time % 1000) * 1000; |
356 |
n = select(m + 1, &fds, NULL, NULL, &tv); |
357 |
rfbProcessEvents(server, 0); |
358 |
/* if client is gone, close connection */ |
359 |
if (!server->clientHead) |
360 |
close(rdpSocket); |
361 |
if (FD_ISSET(rdpSocket, &fds)) |
362 |
return 1; |
363 |
} |
364 |
return 0; |
365 |
} |
366 |
|
367 |
void |
368 |
ui_move_pointer(int x, int y) |
369 |
{ |
370 |
// TODO: Is there a way to send x,y even if cursor encoding is active? |
371 |
rfbUndrawCursor(server); |
372 |
server->cursorX = x; |
373 |
server->cursorY = y; |
374 |
} |
375 |
|
376 |
HBITMAP |
377 |
ui_create_bitmap(int width, int height, uint8 * data) |
378 |
{ |
379 |
vncBuffer *buf; |
380 |
|
381 |
buf = vncNewBuffer(width, height, 8); |
382 |
memcpy(buf->data, data, width * height); |
383 |
|
384 |
return (HBITMAP) buf; |
385 |
} |
386 |
|
387 |
void |
388 |
ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data) |
389 |
{ |
390 |
vncBuffer *buf; |
391 |
buf = ui_create_bitmap(width, height, data); |
392 |
vncCopyBlitFrom(server, x, y, cx, cy, buf, 0, 0); |
393 |
vncDeleteBuffer(buf); |
394 |
} |
395 |
|
396 |
void |
397 |
ui_destroy_bitmap(HBITMAP bmp) |
398 |
{ |
399 |
vncDeleteBuffer((vncBuffer *) bmp); |
400 |
} |
401 |
|
402 |
uint8_t |
403 |
vncLookupColour(rfbColourMap * colourMap, uint8_t * p) |
404 |
{ |
405 |
uint8_t i, i1 = 0; |
406 |
uint8_t *cm = colourMap->data.bytes; |
407 |
uint32_t m, m1 = abs(cm[0] - p[0]) + abs(cm[1] - p[1]) + abs(cm[2] - p[2]); |
408 |
for (i = 1; i < 255; i++) |
409 |
{ |
410 |
m = abs(cm[i * 3] - p[0]) + abs(cm[i * 3 + 1] - p[1]) + abs(cm[i * 3 + 2] - p[2]); |
411 |
if (m < m1) |
412 |
{ |
413 |
m1 = m; |
414 |
i1 = i; |
415 |
} |
416 |
} |
417 |
return (i1); |
418 |
} |
419 |
|
420 |
HCURSOR |
421 |
ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * mask, uint8 * data) |
422 |
{ |
423 |
int i, j; |
424 |
uint8_t *d0, *d1; |
425 |
uint8_t *cdata; |
426 |
uint8_t white[3] = { 0xff, 0xff, 0xff }; |
427 |
uint8_t black[3] = { 0, 0, 0 }; |
428 |
uint8_t *cur; |
429 |
rfbCursorPtr cursor; |
430 |
rfbColourMap *colourMap = &server->colourMap; |
431 |
|
432 |
cdata = xmalloc(sizeof(uint8_t) * width * height); |
433 |
d0 = xmalloc(sizeof(uint32_t) * width * height / 4); |
434 |
d1 = (uint8_t *) mask; |
435 |
for (j = 0; j < height; j++) |
436 |
for (i = 0; i < width / 8; i++) |
437 |
{ |
438 |
d0[j * width / 8 + i] = d1[(height - 1 - j) * width / 8 + i] ^ 0xffffffff; |
439 |
} |
440 |
for (j = 0; j < height; j++) |
441 |
{ |
442 |
for (i = 0; i < width; i++) |
443 |
{ |
444 |
//strange that the pointer is in 24bit depth when everything |
445 |
//else is in 8bit palletized. |
446 |
cur = data + ((height - 1 - j) * width + i) * 3; |
447 |
if (cur[0] > 0x80 || cur[1] > 0x80 || cur[2] > 0x80) |
448 |
{ |
449 |
if (!(d0[(j * width + i) / 8] & (0x80 >> (i & 7)))) |
450 |
{ |
451 |
/* text cursor! */ |
452 |
cdata[j * width + i] = vncLookupColour(colourMap, black); |
453 |
d0[(j * width + i) / 8] |= 0x80 >> (i & 7); |
454 |
} |
455 |
else |
456 |
cdata[j * width + i] = vncLookupColour(colourMap, white); |
457 |
} |
458 |
else |
459 |
cdata[j * width + i] = vncLookupColour(colourMap, cur); |
460 |
} |
461 |
} |
462 |
cursor = (rfbCursorPtr) xmalloc(sizeof(rfbCursor)); |
463 |
cursor->width = width; |
464 |
cursor->height = height; |
465 |
cursor->xhot = x; |
466 |
cursor->yhot = y; |
467 |
cursor->mask = (char *) d0; |
468 |
cursor->source = 0; |
469 |
cursor->richSource = cdata; |
470 |
cursor->cleanup = 0; // workaround: this produces a memleak |
471 |
|
472 |
cursor->backRed = cursor->backGreen = cursor->backBlue = 0xffff; |
473 |
cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0; |
474 |
|
475 |
return (HCURSOR) cursor; |
476 |
} |
477 |
|
478 |
void |
479 |
ui_set_cursor(HCURSOR cursor) |
480 |
{ |
481 |
/* FALSE means: don't delete old cursor */ |
482 |
rfbSetCursor(server, (rfbCursorPtr) cursor, FALSE); |
483 |
} |
484 |
|
485 |
void |
486 |
ui_destroy_cursor(HCURSOR cursor) |
487 |
{ |
488 |
if (cursor) |
489 |
rfbFreeCursor((rfbCursorPtr) cursor); |
490 |
} |
491 |
|
492 |
void |
493 |
ui_set_null_cursor(void) |
494 |
{ |
495 |
rfbSetCursor(server, 0, FALSE); |
496 |
} |
497 |
|
498 |
HGLYPH |
499 |
ui_create_glyph(int width, int height, uint8 * data) |
500 |
{ |
501 |
int x, y; |
502 |
vncBuffer *buf; |
503 |
|
504 |
buf = vncNewBuffer(width, height, 8); |
505 |
|
506 |
//data is padded to multiple of 16bit line lengths |
507 |
for (y = 0; y < height; y++) |
508 |
{ |
509 |
for (x = 0; x < width; x++) |
510 |
{ |
511 |
int byte = x / 8 + (y * ((width + 7) / 8)); |
512 |
byte = rfbEndianTest ? reverseByte[data[byte]] : data[byte]; |
513 |
byte = (byte >> (x & 7)) & 0x01; |
514 |
vncSetPixel(buf, x, y, byte ? 0x7f : 0x00); |
515 |
} |
516 |
} |
517 |
|
518 |
return (HGLYPH) buf; |
519 |
} |
520 |
|
521 |
void |
522 |
ui_destroy_glyph(HGLYPH glyph) |
523 |
{ |
524 |
ui_destroy_bitmap((HBITMAP) glyph); |
525 |
} |
526 |
|
527 |
HCOLOURMAP |
528 |
ui_create_colourmap(COLOURMAP * colours) |
529 |
{ |
530 |
int i; |
531 |
rfbColourMap *map = vncNewColourMap(server, colours->ncolours); |
532 |
for (i = 0; i < colours->ncolours; i++) |
533 |
{ |
534 |
vncSetColourMapEntry(map, i, colours->colours[i].red, |
535 |
colours->colours[i].green, colours->colours[i].blue); |
536 |
} |
537 |
return map; |
538 |
} |
539 |
|
540 |
void |
541 |
ui_destroy_colourmap(HCOLOURMAP map) |
542 |
{ |
543 |
vncDeleteColourMap(map); |
544 |
} |
545 |
|
546 |
void |
547 |
ui_set_colourmap(HCOLOURMAP map) |
548 |
{ |
549 |
vncSetColourMap(server, map); |
550 |
} |
551 |
|
552 |
void |
553 |
ui_set_clip(int x, int y, int cx, int cy) |
554 |
{ |
555 |
clipX = x; |
556 |
clipY = y; |
557 |
clipW = cx; |
558 |
clipH = cy; |
559 |
} |
560 |
|
561 |
void |
562 |
ui_reset_clip() |
563 |
{ |
564 |
clipX = 0; |
565 |
clipY = 0; |
566 |
clipW = 64000; |
567 |
clipH = 64000; |
568 |
} |
569 |
|
570 |
void |
571 |
ui_bell() |
572 |
{ |
573 |
rfbSendBell(server); |
574 |
} |
575 |
|
576 |
void |
577 |
ui_destblt(uint8 opcode, |
578 |
/* dest */ int x, int y, int cx, int cy) |
579 |
{ |
580 |
int i; |
581 |
vncBuffer *buf; |
582 |
|
583 |
switch (opcode) |
584 |
{ |
585 |
case 0: |
586 |
case 15: |
587 |
ui_rect(x, y, cx, cy, 0xff); |
588 |
break; |
589 |
case 5: // invert |
590 |
buf = vncGetRect(server, x, y, cx, cy); |
591 |
for (i = 0; i < cx * cy; i++) |
592 |
((char *) (buf->data))[i] = !((char *) (buf->data))[i]; |
593 |
break; |
594 |
default: |
595 |
unimpl("ui_destblt: opcode=%d %d,%d %dx%d\n", opcode, x, y, cx, cy); |
596 |
} |
597 |
} |
598 |
|
599 |
void |
600 |
ui_patblt(uint8 opcode, |
601 |
/* dest */ int x, int y, int cx, int cy, |
602 |
/* brush */ BRUSH * brush, int bgcolour, int fgcolour) |
603 |
{ |
604 |
switch (brush->style) |
605 |
{ |
606 |
case 0: /* Solid */ |
607 |
switch (opcode) |
608 |
{ |
609 |
case ROP2_XOR: |
610 |
{ |
611 |
int xx, yy; |
612 |
vncBuffer *fill = vncNewBuffer(cx, cy, 8); |
613 |
for (yy = 0; yy < cy; yy++) |
614 |
for (xx = 0; xx < cx; xx++) |
615 |
vncSetPixel(fill, xx, yy, fgcolour); |
616 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
617 |
vncXorBlitFrom(server, x, y, cx, cy, fill, |
618 |
0, 0); |
619 |
break; |
620 |
} |
621 |
|
622 |
default: |
623 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
624 |
vncSetRect(server, x, y, cx, cy, fgcolour); |
625 |
} |
626 |
break; |
627 |
|
628 |
case 3: /* Pattern */ |
629 |
{ |
630 |
int xx, yy; |
631 |
vncBuffer *fill; |
632 |
fill = (vncBuffer *) ui_create_glyph(8, 8, brush->pattern); |
633 |
|
634 |
for (yy = 0; yy < 8; yy++) |
635 |
{ |
636 |
for (xx = 0; xx < 8; xx++) |
637 |
{ |
638 |
vncSetPixel(fill, xx, yy, |
639 |
vncGetPixel(fill, xx, |
640 |
yy) ? fgcolour : bgcolour); |
641 |
} |
642 |
} |
643 |
|
644 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
645 |
{ |
646 |
switch (opcode) |
647 |
{ |
648 |
case ROP2_COPY: |
649 |
vncCopyBlitFrom(server, x, y, cx, cy, fill, |
650 |
0, 0); |
651 |
break; |
652 |
case ROP2_XOR: |
653 |
vncXorBlitFrom(server, x, y, cx, cy, fill, |
654 |
0, 0); |
655 |
break; |
656 |
default: |
657 |
unimpl("pattern blit (%d,%d) opcode=%d bg=%d fg=%d\n", x, y, opcode, bgcolour, fgcolour); |
658 |
vncCopyBlitFrom(server, x, y, cx, cy, fill, |
659 |
0, 0); |
660 |
break; |
661 |
} |
662 |
} |
663 |
|
664 |
ui_destroy_glyph((HGLYPH) fill); |
665 |
break; |
666 |
|
667 |
} |
668 |
default: |
669 |
unimpl("brush %d\n", brush->style); |
670 |
} |
671 |
} |
672 |
|
673 |
void |
674 |
ui_screenblt(uint8 opcode, |
675 |
/* dest */ int x, int y, int cx, int cy, |
676 |
/* src */ int srcx, int srcy) |
677 |
{ |
678 |
int ox, oy; |
679 |
|
680 |
ox = x; |
681 |
oy = y; |
682 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
683 |
{ |
684 |
//if we clipped top or left, we have to adjust srcx,srcy; |
685 |
srcx += x - ox; |
686 |
srcy += y - oy; |
687 |
vncCopyBlit(server, x, y, cx, cy, srcx, srcy); |
688 |
} |
689 |
} |
690 |
|
691 |
void |
692 |
ui_memblt(uint8 opcode, |
693 |
/* dest */ int x, int y, int cx, int cy, |
694 |
/* src */ HBITMAP src, int srcx, int srcy) |
695 |
{ |
696 |
int ox, oy; |
697 |
ox = x; |
698 |
oy = y; |
699 |
|
700 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
701 |
{ |
702 |
//if we clipped top or left, we have to adjust srcx,srcy; |
703 |
srcx += x - ox; |
704 |
srcy += y - oy; |
705 |
switch (ROP2_S(opcode)) |
706 |
{ |
707 |
case ROP2_OR: |
708 |
vncTransBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, |
709 |
srcy, 0x0); |
710 |
break; |
711 |
case ROP2_XOR: |
712 |
vncXorBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, srcy); |
713 |
break; |
714 |
case ROP2_AND: |
715 |
vncAndBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, srcy); |
716 |
break; |
717 |
case ROP2_COPY: |
718 |
vncCopyBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, |
719 |
srcy); |
720 |
break; |
721 |
default: |
722 |
unimpl("ui_memblt: op%d %d,%d %dx%d\n", opcode, x, y, cx, cy); |
723 |
vncCopyBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, |
724 |
srcy); |
725 |
break; |
726 |
} |
727 |
} |
728 |
} |
729 |
|
730 |
void |
731 |
ui_triblt(uint8 opcode, |
732 |
/* dest */ int x, int y, int cx, int cy, |
733 |
/* src */ HBITMAP src, int srcx, int srcy, |
734 |
/* brush */ BRUSH * brush, int bgcolour, int fgcolour) |
735 |
{ |
736 |
/* This is potentially difficult to do in general. Until someone |
737 |
comes up with a more efficient way of doing it I am using cases. */ |
738 |
|
739 |
switch (opcode) |
740 |
{ |
741 |
case 0x69: /* PDSxxn */ |
742 |
ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy); |
743 |
ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour); |
744 |
break; |
745 |
|
746 |
case 0xb8: /* PSDPxax */ |
747 |
ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); |
748 |
ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy); |
749 |
ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); |
750 |
break; |
751 |
|
752 |
default: |
753 |
unimpl("ui_triblt 1x%x\n", opcode); |
754 |
ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy); |
755 |
} |
756 |
|
757 |
} |
758 |
|
759 |
void |
760 |
ui_line(uint8 opcode, |
761 |
/* dest */ int startx, int starty, int endx, int endy, |
762 |
/* pen */ PEN * pen) |
763 |
{ |
764 |
//vncSetRect(server,startx,starty,1+endx-startx,endy-starty,pen->colour); |
765 |
//unimpl("drawline: pen colour=%d\n",pen->colour); |
766 |
/* TODO: implement opcodes */ |
767 |
rfbDrawLine(server, startx, starty, endx, endy, pen->colour); |
768 |
} |
769 |
|
770 |
void |
771 |
ui_rect( |
772 |
/* dest */ int x, int y, int cx, int cy, |
773 |
/* brush */ int colour) |
774 |
{ |
775 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
776 |
{ |
777 |
vncSetRect(server, x, y, cx, cy, colour); |
778 |
} |
779 |
} |
780 |
|
781 |
void |
782 |
ui_draw_glyph(int mixmode, |
783 |
/* dest */ int x, int y, int cx, int cy, |
784 |
/* src */ HGLYPH glyph, int srcx, int srcy, |
785 |
/* colours */ int bgcolour, int fgcolour) |
786 |
{ |
787 |
int xx, yy; |
788 |
int ox, oy; |
789 |
vncBuffer *buf = vncDupBuffer(glyph); |
790 |
|
791 |
x &= 0xffff; |
792 |
y &= 0xffff; |
793 |
|
794 |
/* yes, sometimes same fgcolour and bgcolour are sent, but because |
795 |
* of transparency, we have to change that! */ |
796 |
if (mixmode == MIX_TRANSPARENT && fgcolour == bgcolour) |
797 |
bgcolour = fgcolour ^ 0xff; |
798 |
|
799 |
ox = x; |
800 |
oy = y; |
801 |
|
802 |
for (yy = srcy; yy < srcy + cy; yy++) |
803 |
{ |
804 |
for (xx = srcx; xx < srcx + cx; xx++) |
805 |
{ |
806 |
vncSetPixel(buf, xx, yy, vncGetPixel(buf, xx, yy) ? fgcolour : bgcolour); |
807 |
} |
808 |
} |
809 |
|
810 |
switch (mixmode) |
811 |
{ |
812 |
case MIX_TRANSPARENT: |
813 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
814 |
{ |
815 |
//if we clipped top or left, we have to adjust srcx,srcy; |
816 |
srcx += x - ox; |
817 |
srcy += y - oy; |
818 |
vncTransBlitFrom(server, x, y, cx, cy, buf, srcx, srcy, bgcolour); |
819 |
} |
820 |
break; |
821 |
case MIX_OPAQUE: |
822 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
823 |
{ |
824 |
//if we clipped top or left, we have to adjust srcx,srcy; |
825 |
srcx += x - ox; |
826 |
srcy += y - oy; |
827 |
vncCopyBlitFrom(server, x, y, cx, cy, buf, srcx, srcy); |
828 |
} |
829 |
break; |
830 |
|
831 |
default: |
832 |
unimpl("mix %d\n", mixmode); |
833 |
} |
834 |
vncDeleteBuffer(buf); |
835 |
} |
836 |
|
837 |
#define DO_GLYPH(ttext,idx) \ |
838 |
{\ |
839 |
glyph = cache_get_font (font, ttext[idx]);\ |
840 |
if (!(flags & TEXT2_IMPLICIT_X))\ |
841 |
{\ |
842 |
offset = ttext[++idx];\ |
843 |
if ((offset & 0x80))\ |
844 |
offset = ((offset & 0x7f) << 8) | ttext[++idx];\ |
845 |
if (flags & TEXT2_VERTICAL)\ |
846 |
y += offset;\ |
847 |
else\ |
848 |
x += offset;\ |
849 |
}\ |
850 |
if (glyph != NULL)\ |
851 |
{\ |
852 |
ui_draw_glyph (mixmode, x + (short) glyph->offset,\ |
853 |
y + (short) glyph->baseline,\ |
854 |
glyph->width, glyph->height,\ |
855 |
glyph->pixmap, 0, 0, bgcolour, fgcolour);\ |
856 |
if (flags & TEXT2_IMPLICIT_X)\ |
857 |
x += glyph->width;\ |
858 |
}\ |
859 |
} |
860 |
|
861 |
|
862 |
void |
863 |
ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, |
864 |
int clipx, int clipy, int clipcx, int clipcy, |
865 |
int boxx, int boxy, int boxcx, int boxcy, |
866 |
int bgcolour, int fgcolour, uint8 * text, uint8 length) |
867 |
{ |
868 |
FONTGLYPH *glyph; |
869 |
int i, j, offset; |
870 |
DATABLOB *entry; |
871 |
|
872 |
if (boxcx > 1) |
873 |
{ |
874 |
ui_rect(boxx, boxy, boxcx, boxcy, bgcolour); |
875 |
} |
876 |
else if (mixmode == MIX_OPAQUE) |
877 |
{ |
878 |
ui_rect(clipx, clipy, clipcx, clipcy, bgcolour); |
879 |
} |
880 |
|
881 |
/* Paint text, character by character */ |
882 |
for (i = 0; i < length;) |
883 |
{ |
884 |
switch (text[i]) |
885 |
{ |
886 |
case 0xff: |
887 |
if (i + 2 < length) |
888 |
cache_put_text(text[i + 1], &(text[i - text[i + 2]]), |
889 |
text[i + 2]); |
890 |
else |
891 |
{ |
892 |
error("this shouldn't be happening\n"); |
893 |
break; |
894 |
} |
895 |
/* this will move pointer from start to first character after FF command */ |
896 |
length -= i + 3; |
897 |
text = &(text[i + 3]); |
898 |
i = 0; |
899 |
break; |
900 |
|
901 |
case 0xfe: |
902 |
entry = cache_get_text(text[i + 1]); |
903 |
if (entry != NULL) |
904 |
{ |
905 |
if ((((uint8 *) (entry->data))[1] == 0) |
906 |
&& (!(flags & TEXT2_IMPLICIT_X))) |
907 |
{ |
908 |
if (flags & 0x04) /* vertical text */ |
909 |
y += text[i + 2]; |
910 |
else |
911 |
x += text[i + 2]; |
912 |
} |
913 |
if (i + 2 < length) |
914 |
i += 3; |
915 |
else |
916 |
i += 2; |
917 |
length -= i; |
918 |
/* this will move pointer from start to first character after FE command */ |
919 |
text = &(text[i]); |
920 |
i = 0; |
921 |
for (j = 0; j < entry->size; j++) |
922 |
DO_GLYPH(((uint8 *) (entry->data)), j); |
923 |
} |
924 |
break; |
925 |
default: |
926 |
DO_GLYPH(text, i); |
927 |
i++; |
928 |
break; |
929 |
} |
930 |
} |
931 |
} |
932 |
|
933 |
void |
934 |
ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) |
935 |
{ |
936 |
vncBuffer *buf; |
937 |
|
938 |
buf = vncGetRect(server, x, y, cx, cy); |
939 |
offset *= TOBYTES(server->serverFormat.bitsPerPixel); |
940 |
cache_put_desktop(offset, cx, cy, cx, TOBYTES(server->serverFormat.bitsPerPixel), |
941 |
(buf->data)); |
942 |
} |
943 |
|
944 |
void |
945 |
ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) |
946 |
{ |
947 |
uint8 *data; |
948 |
vncBuffer *buf; |
949 |
int ox, oy, srcx, srcy; |
950 |
|
951 |
srcx = srcy = 0; |
952 |
ox = x; |
953 |
oy = y; |
954 |
|
955 |
offset *= TOBYTES(server->serverFormat.bitsPerPixel); |
956 |
data = cache_get_desktop(offset, cx, cy, TOBYTES(server->serverFormat.bitsPerPixel)); |
957 |
if (data == NULL) |
958 |
return; |
959 |
|
960 |
buf = vncNewBuffer(cx, cy, 8); |
961 |
memcpy(buf->data, data, cx * cy * 1); |
962 |
|
963 |
if (vncwinClipRect(&x, &y, &cx, &cy)) |
964 |
{ |
965 |
srcx += x - ox; |
966 |
srcy += y - oy; |
967 |
vncCopyBlitFrom(server, x, y, cx, cy, buf, srcx, srcy); |
968 |
} |
969 |
vncDeleteBuffer(buf); |
970 |
} |
971 |
|
972 |
rfbPixelFormat vnc_formats[] = { |
973 |
/* bpp, depth,BE,TC, rmax, gmax, bmax, rsh, gsh, bsh */ |
974 |
{8, 8, 1, 0, 7, 7, 3, 0, 3, 6} |
975 |
, |
976 |
{16, 16, 1, 1, 31, 63, 31, 0, 5, 10} |
977 |
, |
978 |
{32, 24, 1, 1, 255, 255, 255, 0, 8, 16} |
979 |
, //non-existant |
980 |
{32, 32, 1, 1, 2047, 2047, 1023, 0, 11, 22} |
981 |
}; |
982 |
|
983 |
rfbPixelFormat * |
984 |
vncNewFormat(int depth) |
985 |
{ |
986 |
return &(vnc_formats[(depth + 1) / 8 - 1]); |
987 |
} |
988 |
|
989 |
vncBuffer * |
990 |
vncNewBuffer(int w, int h, int depth) |
991 |
{ |
992 |
vncBuffer *b = (vncBuffer *) xmalloc(sizeof(vncBuffer)); |
993 |
b->format = vncNewFormat(depth); |
994 |
b->data = (void *) xmalloc(w * h * (b->format->bitsPerPixel / 8)); |
995 |
b->owner = 1; |
996 |
b->w = w; |
997 |
b->h = h; |
998 |
b->linew = w; |
999 |
return b; |
1000 |
} |
1001 |
|
1002 |
vncBuffer * |
1003 |
vncDupBuffer(vncBuffer * b) |
1004 |
{ |
1005 |
vncBuffer *buf = vncNewBuffer(b->w, b->h, b->format->depth); |
1006 |
memcpy(buf->data, b->data, b->linew * b->h * b->format->bitsPerPixel / 8); |
1007 |
return buf; |
1008 |
} |
1009 |
|
1010 |
void |
1011 |
vncPrintStats() |
1012 |
{ |
1013 |
if (server && server->clientHead) |
1014 |
rfbPrintStats(server->clientHead); |
1015 |
} |
1016 |
|
1017 |
/* blit */ |
1018 |
|
1019 |
#define GETPIXEL(buf,x,y) \ |
1020 |
(((uint8_t*)(buf->data))[(x)+((y)*buf->linew)]) |
1021 |
#define SETPIXEL(buf,x,y,p) \ |
1022 |
(((uint8_t*)(buf->data))[(x)+((y)*buf->linew)] = (uint8_t)p) |
1023 |
|
1024 |
void |
1025 |
vncCopyBlitFromNoEncode(rfbScreenInfoPtr s, int x, int y, int w, int h, |
1026 |
vncBuffer * src, int srcx, int srcy) |
1027 |
{ |
1028 |
int xx, yy; |
1029 |
|
1030 |
vncHideCursor(); |
1031 |
|
1032 |
if (s->serverFormat.bitsPerPixel == src->format->bitsPerPixel |
1033 |
&& srcx + w <= src->w && srcy + h <= src->h) |
1034 |
{ |
1035 |
//simple copy |
1036 |
uint8_t *srcdata, *dstdata; |
1037 |
srcdata = src->data + (srcy * src->linew + srcx); |
1038 |
dstdata = s->frameBuffer + (y * s->paddedWidthInBytes + x); |
1039 |
for (yy = 0; yy < h; yy++) |
1040 |
{ |
1041 |
memcpy(dstdata, srcdata, w); |
1042 |
dstdata += s->paddedWidthInBytes; |
1043 |
srcdata += src->linew; |
1044 |
} |
1045 |
} |
1046 |
else |
1047 |
{ |
1048 |
// xsrc,ysrc provide tiling copy support. |
1049 |
for (yy = y; yy < y + h; yy++) |
1050 |
{ |
1051 |
int ysrc = srcy + yy - y; |
1052 |
while (ysrc >= src->h) |
1053 |
ysrc -= src->h; |
1054 |
for (xx = x; xx < x + w; xx++) |
1055 |
{ |
1056 |
vncPixel p; |
1057 |
int xsrc = srcx + xx - x; |
1058 |
while (xsrc >= src->linew) |
1059 |
xsrc -= src->linew; |
1060 |
p = GETPIXEL(src, xsrc, ysrc); |
1061 |
SETPIXEL(frameBuffer, xx, yy, p); |
1062 |
} |
1063 |
} |
1064 |
} |
1065 |
} |
1066 |
|
1067 |
void |
1068 |
vncCopyBlit(rfbScreenInfoPtr s, int x, int y, int w, int h, int srcx, int srcy) |
1069 |
{ |
1070 |
/* LibVNCServer already knows how to copy the data. */ |
1071 |
rfbDoCopyRect(s, x, y, x + w, y + h, x - srcx, y - srcy); |
1072 |
} |
1073 |
|
1074 |
void |
1075 |
vncCopyBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) |
1076 |
{ |
1077 |
vncCopyBlitFromNoEncode(s, x, y, w, h, src, srcx, srcy); |
1078 |
rfbMarkRectAsModified(s, x, y, x + w, y + h); |
1079 |
} |
1080 |
|
1081 |
void |
1082 |
vncTransBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, |
1083 |
vncBuffer * src, int srcx, int srcy, int bg) |
1084 |
{ |
1085 |
int xx, yy; |
1086 |
|
1087 |
vncHideCursor(); |
1088 |
|
1089 |
// xsrc,ysrc provide tiling copy support. |
1090 |
for (yy = y; yy < y + h; yy++) |
1091 |
{ |
1092 |
int ysrc = srcy + yy - y; |
1093 |
while (ysrc >= src->h) |
1094 |
ysrc -= src->h; |
1095 |
for (xx = x; xx < x + w; xx++) |
1096 |
{ |
1097 |
vncPixel p; |
1098 |
int xsrc = srcx + xx - x; |
1099 |
while (xsrc >= src->linew) |
1100 |
xsrc -= src->linew; |
1101 |
p = GETPIXEL(src, xsrc, ysrc); |
1102 |
// transparent blit! |
1103 |
if (p != bg) |
1104 |
SETPIXEL(frameBuffer, xx, yy, p); |
1105 |
} |
1106 |
} |
1107 |
|
1108 |
rfbMarkRectAsModified(s, x, y, x + w, y + h); |
1109 |
} |
1110 |
|
1111 |
void |
1112 |
vncXorBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) |
1113 |
{ |
1114 |
int xx, yy; |
1115 |
|
1116 |
vncHideCursor(); |
1117 |
|
1118 |
// xsrc,ysrc provide tiling copy support. |
1119 |
for (yy = y; yy < y + h; yy++) |
1120 |
{ |
1121 |
int ysrc = srcy + yy - y; |
1122 |
while (ysrc >= src->h) |
1123 |
ysrc -= src->h; |
1124 |
for (xx = x; xx < x + w; xx++) |
1125 |
{ |
1126 |
vncPixel p, pp; |
1127 |
int xsrc = srcx + xx - x; |
1128 |
while (xsrc >= src->linew) |
1129 |
xsrc -= src->linew; |
1130 |
p = GETPIXEL(src, xsrc, ysrc); |
1131 |
pp = GETPIXEL(frameBuffer, xx, yy); |
1132 |
// xor blit! |
1133 |
SETPIXEL(frameBuffer, xx, yy, p ^ pp); |
1134 |
} |
1135 |
} |
1136 |
|
1137 |
rfbMarkRectAsModified(s, x, y, x + w, y + h); |
1138 |
} |
1139 |
|
1140 |
void |
1141 |
vncAndBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) |
1142 |
{ |
1143 |
int xx, yy; |
1144 |
|
1145 |
vncHideCursor(); |
1146 |
|
1147 |
// xsrc,ysrc provide tiling copy support. |
1148 |
for (yy = y; yy < y + h; yy++) |
1149 |
{ |
1150 |
int ysrc = srcy + yy - y; |
1151 |
while (ysrc >= src->h) |
1152 |
ysrc -= src->h; |
1153 |
for (xx = x; xx < x + w; xx++) |
1154 |
{ |
1155 |
vncPixel p, pp; |
1156 |
int xsrc = srcx + xx - x; |
1157 |
while (xsrc >= src->linew) |
1158 |
xsrc -= src->linew; |
1159 |
p = GETPIXEL(src, xsrc, ysrc); |
1160 |
pp = GETPIXEL(frameBuffer, xx, yy); |
1161 |
// and blit! |
1162 |
SETPIXEL(frameBuffer, xx, yy, p & pp); |
1163 |
} |
1164 |
} |
1165 |
|
1166 |
rfbMarkRectAsModified(s, x, y, x + w, y + h); |
1167 |
} |
1168 |
|
1169 |
void |
1170 |
vncDeleteBuffer(vncBuffer * b) |
1171 |
{ |
1172 |
if (b->owner) |
1173 |
xfree(b->data); |
1174 |
xfree(b); |
1175 |
} |
1176 |
|
1177 |
/* cursor */ |
1178 |
rfbCursorPtr |
1179 |
vncNewCursor(vncBuffer * mask, vncBuffer * pointer, int hotx, int hoty) |
1180 |
{ |
1181 |
int i, j, w = (mask->w + 7) / 8, mask_size = w * mask->h, |
1182 |
pointer_size = pointer->w * pointer->h; |
1183 |
rfbCursorPtr c = (rfbCursorPtr) xmalloc(sizeof(rfbCursor)); |
1184 |
|
1185 |
if (mask->w != pointer->w || mask->h != pointer->h) |
1186 |
error("ERROR! Mask is %dx%d, Pointer is %dx%d\n", |
1187 |
mask->w, mask->h, pointer->w, pointer->h); |
1188 |
|
1189 |
c->xhot = hotx; |
1190 |
c->yhot = hoty; |
1191 |
c->width = mask->w; |
1192 |
c->height = mask->h; |
1193 |
|
1194 |
c->mask = (char *) xmalloc(mask_size); |
1195 |
for (j = 0; j < c->height; j++) |
1196 |
for (i = 0; i < w; i++) |
1197 |
c->mask[j * w + i] = |
1198 |
reverseByte[((unsigned char *) mask->data)[(j) * w + i]]; |
1199 |
vncDeleteBuffer(mask); |
1200 |
|
1201 |
c->source = 0; |
1202 |
c->richSource = (char *) xmalloc(pointer_size); |
1203 |
memcpy(c->richSource, pointer->data, pointer_size); |
1204 |
vncDeleteBuffer(pointer); |
1205 |
|
1206 |
return c; |
1207 |
} |
1208 |
|
1209 |
/* No FreeCursor, because the cursors are buffered. We only get a "HANDLE" */ |
1210 |
void |
1211 |
vncSetCursor(rfbScreenInfoPtr s, rfbCursorPtr c) |
1212 |
{ |
1213 |
rfbSetCursor(s, c, FALSE); |
1214 |
} |
1215 |
|
1216 |
/* these functions work even if vncBuffer's pixel format is not 1 byte/pixel */ |
1217 |
vncPixel |
1218 |
vncGetPixel(vncBuffer * b, int x, int y) |
1219 |
{ |
1220 |
unsigned long offset = (x + (y * (b->linew))) * (b->format->bitsPerPixel >> 3); |
1221 |
return ((uint8_t *) (b->data))[offset]; |
1222 |
} |
1223 |
|
1224 |
void |
1225 |
vncSetPixel(vncBuffer * b, int x, int y, vncPixel c) |
1226 |
{ |
1227 |
unsigned long offset = (x + (y * (b->linew))) * (b->format->bitsPerPixel >> 3); |
1228 |
((uint8_t *) (b->data))[offset] = c; |
1229 |
} |
1230 |
|
1231 |
void |
1232 |
vncSetRect(rfbScreenInfoPtr s, int x, int y, int w, int h, vncPixel c) |
1233 |
{ |
1234 |
int xx, yy; |
1235 |
|
1236 |
if (x + w > s->width) |
1237 |
w = s->width - x; |
1238 |
if (y + h > s->height) |
1239 |
h = s->height - y; |
1240 |
if (w <= 0 || h <= 0) |
1241 |
return; |
1242 |
|
1243 |
vncHideCursor(); |
1244 |
|
1245 |
// - Fill the rect in the local framebuffer |
1246 |
if (s->serverFormat.bitsPerPixel == 8) |
1247 |
{ |
1248 |
// - Simple 8-bit fill |
1249 |
uint8_t *dstdata; |
1250 |
dstdata = s->frameBuffer + (y * s->paddedWidthInBytes + x); |
1251 |
for (yy = 0; yy < h; yy++) |
1252 |
{ |
1253 |
memset(dstdata, c, w); |
1254 |
dstdata += s->paddedWidthInBytes; |
1255 |
} |
1256 |
} |
1257 |
else |
1258 |
{ |
1259 |
for (yy = y; yy < y + h; yy++) |
1260 |
{ |
1261 |
for (xx = x; xx < x + w; xx++) |
1262 |
{ |
1263 |
SETPIXEL(frameBuffer, xx, yy, c); |
1264 |
} |
1265 |
} |
1266 |
} |
1267 |
|
1268 |
rfbMarkRectAsModified(s, x, y, x + w, y + h); |
1269 |
} |
1270 |
|
1271 |
vncBuffer * |
1272 |
vncGetRect(rfbScreenInfoPtr s, int x, int y, int w, int h) |
1273 |
{ |
1274 |
int xx, yy; |
1275 |
vncBuffer *b = vncNewBuffer(w, h, s->serverFormat.depth); |
1276 |
|
1277 |
vncHideCursor(); |
1278 |
|
1279 |
if (s->serverFormat.bitsPerPixel == 8) |
1280 |
{ |
1281 |
//simple copy |
1282 |
int srcstep, dststep; |
1283 |
char *srcdata, *dstdata; |
1284 |
srcstep = s->paddedWidthInBytes * s->serverFormat.bitsPerPixel / 8; |
1285 |
dststep = w * s->serverFormat.bitsPerPixel / 8; |
1286 |
dstdata = b->data; |
1287 |
srcdata = s->frameBuffer + (y * srcstep + x * s->serverFormat.bitsPerPixel / 8); |
1288 |
for (yy = 0; yy < h; yy++) |
1289 |
{ |
1290 |
memcpy(dstdata, srcdata, dststep); |
1291 |
dstdata += dststep; |
1292 |
srcdata += srcstep; |
1293 |
} |
1294 |
} |
1295 |
else |
1296 |
{ |
1297 |
for (yy = y; yy < y + h; yy++) |
1298 |
{ |
1299 |
for (xx = x; xx < x + w; xx++) |
1300 |
{ |
1301 |
SETPIXEL(b, xx - x, yy - y, GETPIXEL(frameBuffer, xx, yy)); |
1302 |
} |
1303 |
} |
1304 |
} |
1305 |
|
1306 |
return b; |
1307 |
} |
1308 |
|
1309 |
/* colourmap */ |
1310 |
|
1311 |
rfbColourMap * |
1312 |
vncNewColourMap(rfbScreenInfoPtr s, int n) |
1313 |
{ |
1314 |
rfbColourMap *m = (rfbColourMap *) xmalloc(sizeof(rfbColourMap)); |
1315 |
m->is16 = FALSE; |
1316 |
m->count = n; |
1317 |
m->data.bytes = (uint8_t *) xmalloc(n * 3); |
1318 |
return m; |
1319 |
} |
1320 |
|
1321 |
void |
1322 |
vncSetColourMapEntry(rfbColourMap * m, int i, vncPixel r, vncPixel g, vncPixel b) |
1323 |
{ |
1324 |
if (i < m->count) |
1325 |
{ |
1326 |
m->data.bytes[3 * i + 0] = r; |
1327 |
m->data.bytes[3 * i + 1] = g; |
1328 |
m->data.bytes[3 * i + 2] = b; |
1329 |
} |
1330 |
} |
1331 |
|
1332 |
void |
1333 |
vncDeleteColourMap(rfbColourMap * m) |
1334 |
{ |
1335 |
if (m->data.bytes) |
1336 |
free(m->data.bytes); |
1337 |
m->count = 0; |
1338 |
} |
1339 |
|
1340 |
void |
1341 |
vncSetColourMap(rfbScreenInfoPtr s, rfbColourMap * m) |
1342 |
{ |
1343 |
vncDeleteColourMap(&s->colourMap); |
1344 |
s->colourMap = *m; |
1345 |
rfbSetClientColourMaps(s, 0, 0); |
1346 |
} |
1347 |
|
1348 |
void |
1349 |
ui_begin_update() |
1350 |
{ |
1351 |
} |
1352 |
|
1353 |
void |
1354 |
ui_end_update() |
1355 |
{ |
1356 |
} |
1357 |
|
1358 |
void |
1359 |
ui_resize_window() |
1360 |
{ |
1361 |
rfbClientIteratorPtr iter; |
1362 |
rfbClientPtr cl; |
1363 |
|
1364 |
server->width = g_width; |
1365 |
server->height = g_height; |
1366 |
server->frameBuffer = (char *) realloc(server->frameBuffer, g_width * g_height); |
1367 |
server->paddedWidthInBytes = g_width; |
1368 |
|
1369 |
iter = rfbGetClientIterator(server); |
1370 |
while ((cl = rfbClientIteratorNext(iter))) |
1371 |
if (cl->useNewFBSize) |
1372 |
cl->newFBSizePending = TRUE; |
1373 |
else |
1374 |
rfbLog("Warning: Client %s does not support NewFBSize!\n ", cl->host); |
1375 |
rfbReleaseClientIterator(iter); |
1376 |
} |