/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 771 - (hide annotations)
Sat Sep 11 17:08:49 2004 UTC (19 years, 9 months ago) by stargo
File MIME type: text/plain
File size: 29950 byte(s)
VNC fixes from Johannes Schindelin <Johannes.Schindelin@gmx.de>

1 astrand 333 /*
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 astrand 335 #include <rfb/rfbregion.h>
58 astrand 333
59     #define BITSPERBYTES 8
60     #define TOBYTES(bits) ((bits)/BITSPERBYTES)
61    
62 stargo 648 extern int g_width;
63     extern int g_height;
64 astrand 333 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 stargo 648 BOOL g_enable_compose = False;
78 astrand 651 int g_display = 0;
79 astrand 333
80     /* ignored */
81     BOOL owncolmap = False;
82     BOOL enable_compose = False;
83    
84     void
85     vncHideCursor()
86     {
87 stargo 771 if (server->clientHead)
88 astrand 333 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 stargo 648 vncKey(rfbBool down, rfbKeySym keysym, struct _rfbClientRec *cl)
155 astrand 333 {
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 stargo 771 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
222 astrand 333 }
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 stargo 771 rfbListenSock = rfbListenOnTCPPort(rfb_port);
235 astrand 333 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 stargo 771 BOOL deactivated;
263     uint32_t ext_disc_reason;
264 astrand 333 printf("Connection successful.\n");
265 stargo 771 rdp_main_loop(&deactivated,&ext_disc_reason);
266 astrand 333 printf("Disconnecting...\n");
267     rdp_disconnect();
268     ui_destroy_window();
269     exit(0);
270     }
271     }
272     }
273     }
274    
275    
276    
277    
278    
279 stargo 648 extern char g_title[];
280 astrand 333 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 stargo 648 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 astrand 333 server->ptrAddEvent = vncMouse;
295     server->kbdAddEvent = vncKey;
296     #ifdef ENABLE_SHADOW
297     server->httpPort = 6124 + client_counter;
298 stargo 771 server->port = 5924 + client_counter;
299 astrand 333 rfbInitSockets(server);
300 stargo 771 server->alwaysShared = TRUE;
301     server->neverShared = FALSE;
302 astrand 333 #else
303 stargo 771 server->port = -1;
304     server->alwaysShared = FALSE;
305     server->neverShared = FALSE;
306 astrand 333 #endif
307     server->inetdSock = rfbClientSocket;
308 stargo 771 server->serverFormat.trueColour = FALSE; /* activate colour maps */
309     server->deferUpdateTime = defer_time;
310 astrand 333
311     frameBuffer = (vncBuffer *) malloc(sizeof(vncBuffer));
312 stargo 648 frameBuffer->w = g_width;
313     frameBuffer->h = g_height;
314     frameBuffer->linew = g_width;
315 astrand 333 frameBuffer->data = server->frameBuffer;
316     frameBuffer->owner = FALSE;
317 stargo 771 frameBuffer->format = &server->serverFormat;
318 astrand 333
319 stargo 648 ui_set_clip(0, 0, g_width, g_height);
320 astrand 333
321     rfbInitServer(server);
322     #ifndef ENABLE_SHADOW
323 stargo 771 server->port = rfb_port;
324 astrand 333 #else
325 stargo 771 fprintf(stderr, "server listening on port %d (socket %d)\n", server->port,
326     server->listenSock);
327 astrand 333 #endif
328    
329     init_keyboard();
330    
331     return (server != NULL);
332     }
333    
334     void
335     ui_destroy_window()
336     {
337 stargo 771 rfbCloseClient(server->clientHead);
338 astrand 333 }
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 stargo 771 if (!server->clientHead)
360 astrand 333 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 stargo 771 cursor->cleanup = 0; // workaround: this produces a memleak
471 astrand 333
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 astrand 651 void
493     ui_set_null_cursor(void)
494 stargo 648 {
495     rfbSetCursor(server, 0, FALSE);
496     }
497    
498 astrand 333 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 stargo 771 offset *= TOBYTES(server->serverFormat.bitsPerPixel);
940     cache_put_desktop(offset, cx, cy, cx, TOBYTES(server->serverFormat.bitsPerPixel),
941 astrand 333 (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 stargo 771 offset *= TOBYTES(server->serverFormat.bitsPerPixel);
956     data = cache_get_desktop(offset, cx, cy, TOBYTES(server->serverFormat.bitsPerPixel));
957 astrand 333 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 stargo 771 if (server && server->clientHead)
1014     rfbPrintStats(server->clientHead);
1015 astrand 333 }
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 stargo 771 if (s->serverFormat.bitsPerPixel == src->format->bitsPerPixel
1033 astrand 333 && 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 stargo 771 if (s->serverFormat.bitsPerPixel == 8)
1247 astrand 333 {
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 stargo 771 vncBuffer *b = vncNewBuffer(w, h, s->serverFormat.depth);
1276 astrand 333
1277     vncHideCursor();
1278    
1279 stargo 771 if (s->serverFormat.bitsPerPixel == 8)
1280 astrand 333 {
1281     //simple copy
1282     int srcstep, dststep;
1283     char *srcdata, *dstdata;
1284 stargo 771 srcstep = s->paddedWidthInBytes * s->serverFormat.bitsPerPixel / 8;
1285     dststep = w * s->serverFormat.bitsPerPixel / 8;
1286 astrand 333 dstdata = b->data;
1287 stargo 771 srcdata = s->frameBuffer + (y * srcstep + x * s->serverFormat.bitsPerPixel / 8);
1288 astrand 333 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 stargo 771
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     }
1377    

  ViewVC Help
Powered by ViewVC 1.1.26