- Update address of Free Software Foundation.
[reactos.git] / reactos / base / applications / tsclient / rdesktop / vnc / vnc.c
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 along
20 with this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 }