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