/[rdesktop]/sourceforge.net/trunk/rdesktop/vnc/vnc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/vnc/vnc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 651 - (show annotations)
Thu Apr 15 20:12:42 2004 UTC (20 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 29332 byte(s)
Indent fixes

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 }

  ViewVC Help
Powered by ViewVC 1.1.26