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