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
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.
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.
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.
29 #define close closesocket
30 #define strcasecmp _strcmpi
33 #include <sys/time.h> /* timeval */
34 #include <sys/socket.h>
37 #include "../rdesktop.h"
41 #define HBITMAP R_HBITMAP
42 #define HCURSOR R_HCURSOR
53 #include <sys/socket.h>
54 extern int ListenOnTCPPort(int port
);
55 extern int rfbClientSocket
;
57 #include <rfb/rfbregion.h>
59 #define BITSPERBYTES 8
60 #define TOBYTES(bits) ((bits)/BITSPERBYTES)
65 extern BOOL sendmotion
;
67 extern int client_counter
;
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
;
81 BOOL owncolmap
= False
;
82 BOOL enable_compose
= False
;
87 if (server
->clientHead
)
88 rfbUndrawCursor(server
);
92 * Table converting mouse button number (0-2) to flag
95 int mouseLookup
[3] = {
96 MOUSE_FLAG_BUTTON1
, MOUSE_FLAG_BUTTON3
, MOUSE_FLAG_BUTTON2
99 int clipX
, clipY
, clipW
, clipH
;
102 vncwinClipRect(int *x
, int *y
, int *cx
, int *cy
)
104 if (*x
+ *cx
> clipX
+ clipW
)
105 *cx
= clipX
+ clipW
- *x
;
106 if (*y
+ *cy
> clipY
+ clipH
)
107 *cy
= clipY
+ clipH
- *y
;
118 if (*cx
< 0 || *cy
< 0)
120 return (*cx
> 0 && *cy
> 0 && *x
< server
->width
&& *y
< server
->height
);
124 xwin_toggle_fullscreen(void)
128 static int lastbuttons
= 0;
130 #define FIRST_MODIFIER XK_Shift_L
131 #define LAST_MODIFIER XK_Hyper_R
133 static BOOL keystate
[LAST_MODIFIER
- FIRST_MODIFIER
];
139 for (i
= 0; i
< LAST_MODIFIER
- FIRST_MODIFIER
; i
++)
146 get_key_state(unsigned int state
, uint32 keysym
)
148 if (keysym
>= FIRST_MODIFIER
&& keysym
<= LAST_MODIFIER
)
149 return keystate
[keysym
- FIRST_MODIFIER
];
154 vncKey(rfbBool down
, rfbKeySym keysym
, struct _rfbClientRec
*cl
)
156 uint32 ev_time
= time(NULL
);
157 key_translation tr
= { 0, 0 };
159 if (keysym
>= FIRST_MODIFIER
&& keysym
<= LAST_MODIFIER
)
161 /* TODO: fake local state */
162 keystate
[keysym
- FIRST_MODIFIER
] = down
;
167 /* TODO: fake local state */
168 if (handle_special_keys(keysym
, 0, ev_time
, True
))
171 /* TODO: fake local state */
172 tr
= xkeymap_translate_key(keysym
, 0, 0);
174 if (tr
.scancode
== 0)
177 ensure_remote_modifiers(ev_time
, tr
);
179 rdp_send_scancode(ev_time
, RDP_KEYPRESS
, tr
.scancode
);
183 /* todO: fake local state */
184 if (handle_special_keys(keysym
, 0, ev_time
, False
))
187 /* todO: fake local state */
188 tr
= xkeymap_translate_key(keysym
, 0, 0);
190 if (tr
.scancode
== 0)
193 rdp_send_scancode(ev_time
, RDP_KEYRELEASE
, tr
.scancode
);
198 vncMouse(int buttonMask
, int x
, int y
, struct _rfbClientRec
*cl
)
201 uint32 ev_time
= time(NULL
);
203 rdp_send_input(ev_time
, RDP_INPUT_MOUSE
, MOUSE_FLAG_MOVE
, x
, y
);
205 for (b
= 0; b
< 3; b
++)
208 if (!(lastbuttons
& bb
) && (buttonMask
& bb
))
210 rdp_send_input(ev_time
, RDP_INPUT_MOUSE
,
211 (mouseLookup
[b
]) | MOUSE_FLAG_DOWN
, x
, y
);
213 else if ((lastbuttons
& bb
) && !(buttonMask
& bb
))
215 rdp_send_input(ev_time
, RDP_INPUT_MOUSE
, (mouseLookup
[b
]), x
, y
);
218 lastbuttons
= buttonMask
;
221 rfbDefaultPtrAddEvent(buttonMask
, x
, y
, cl
);
226 rdp2vnc_connect(char *server
, uint32 flags
, char *domain
, char *password
,
227 char *shell
, char *directory
)
229 struct sockaddr addr
;
232 int rfbListenSock
, addrlen
= sizeof(addr
);
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
);
242 FD_SET(rfbListenSock
, &fdset
);
245 if (select(rfbListenSock
+ 1, &fdset
, NULL
, NULL
, &tv
) > 0)
247 rfbClientSocket
= accept(rfbListenSock
, &addr
, &addrlen
);
248 if (rfbClientSocket
< 0)
250 error("Error accepting client (%d: %s.\n",
251 errno
, strerror(errno
));
255 if (!rdp_connect(server
, flags
, domain
, password
, shell
, directory
))
257 error("Error connecting to RDP server.\n");
263 uint32_t ext_disc_reason
;
264 printf("Connection successful.\n");
265 rdp_main_loop(&deactivated
, &ext_disc_reason
);
266 printf("Disconnecting...\n");
279 extern char g_title
[];
285 for (i
= 0; i
< 0x100; 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);
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
;
297 server
->httpPort
= 6124 + client_counter
;
298 server
->port
= 5924 + client_counter
;
299 rfbInitSockets(server
);
300 server
->alwaysShared
= TRUE
;
301 server
->neverShared
= FALSE
;
304 server
->alwaysShared
= FALSE
;
305 server
->neverShared
= FALSE
;
307 server
->inetdSock
= rfbClientSocket
;
308 server
->serverFormat
.trueColour
= FALSE
; /* activate colour maps */
309 server
->deferUpdateTime
= defer_time
;
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
;
319 ui_set_clip(0, 0, g_width
, g_height
);
321 rfbInitServer(server
);
322 #ifndef ENABLE_SHADOW
323 server
->port
= rfb_port
;
325 fprintf(stderr
, "server listening on port %d (socket %d)\n", server
->port
,
331 return (server
!= NULL
);
337 rfbCloseClient(server
->clientHead
);
342 ui_select(int rdpSocket
)
346 int n
, m
= server
->maxFd
;
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
)
361 if (FD_ISSET(rdpSocket
, &fds
))
368 ui_move_pointer(int x
, int y
)
370 // TODO: Is there a way to send x,y even if cursor encoding is active?
371 rfbUndrawCursor(server
);
377 ui_create_bitmap(int width
, int height
, uint8
* data
)
381 buf
= vncNewBuffer(width
, height
, 8);
382 memcpy(buf
->data
, data
, width
* height
);
384 return (HBITMAP
) buf
;
388 ui_paint_bitmap(int x
, int y
, int cx
, int cy
, int width
, int height
, uint8
* data
)
391 buf
= ui_create_bitmap(width
, height
, data
);
392 vncCopyBlitFrom(server
, x
, y
, cx
, cy
, buf
, 0, 0);
393 vncDeleteBuffer(buf
);
397 ui_destroy_bitmap(HBITMAP bmp
)
399 vncDeleteBuffer((vncBuffer
*) bmp
);
403 vncLookupColour(rfbColourMap
* colourMap
, uint8_t * p
)
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
++)
410 m
= abs(cm
[i
* 3] - p
[0]) + abs(cm
[i
* 3 + 1] - p
[1]) + abs(cm
[i
* 3 + 2] - p
[2]);
421 ui_create_cursor(unsigned int x
, unsigned int y
, int width
, int height
, uint8
* mask
, uint8
* data
)
426 uint8_t white
[3] = { 0xff, 0xff, 0xff };
427 uint8_t black
[3] = { 0, 0, 0 };
430 rfbColourMap
*colourMap
= &server
->colourMap
;
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
++)
438 d0
[j
* width
/ 8 + i
] = d1
[(height
- 1 - j
) * width
/ 8 + i
] ^ 0xffffffff;
440 for (j
= 0; j
< height
; j
++)
442 for (i
= 0; i
< width
; i
++)
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)
449 if (!(d0
[(j
* width
+ i
) / 8] & (0x80 >> (i
& 7))))
452 cdata
[j
* width
+ i
] = vncLookupColour(colourMap
, black
);
453 d0
[(j
* width
+ i
) / 8] |= 0x80 >> (i
& 7);
456 cdata
[j
* width
+ i
] = vncLookupColour(colourMap
, white
);
459 cdata
[j
* width
+ i
] = vncLookupColour(colourMap
, cur
);
462 cursor
= (rfbCursorPtr
) xmalloc(sizeof(rfbCursor
));
463 cursor
->width
= width
;
464 cursor
->height
= height
;
467 cursor
->mask
= (char *) d0
;
469 cursor
->richSource
= cdata
;
470 cursor
->cleanup
= 0; // workaround: this produces a memleak
472 cursor
->backRed
= cursor
->backGreen
= cursor
->backBlue
= 0xffff;
473 cursor
->foreRed
= cursor
->foreGreen
= cursor
->foreBlue
= 0;
475 return (HCURSOR
) cursor
;
479 ui_set_cursor(HCURSOR cursor
)
481 /* FALSE means: don't delete old cursor */
482 rfbSetCursor(server
, (rfbCursorPtr
) cursor
, FALSE
);
486 ui_destroy_cursor(HCURSOR cursor
)
489 rfbFreeCursor((rfbCursorPtr
) cursor
);
493 ui_set_null_cursor(void)
495 rfbSetCursor(server
, 0, FALSE
);
499 ui_create_glyph(int width
, int height
, uint8
* data
)
504 buf
= vncNewBuffer(width
, height
, 8);
506 //data is padded to multiple of 16bit line lengths
507 for (y
= 0; y
< height
; y
++)
509 for (x
= 0; x
< width
; x
++)
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);
522 ui_destroy_glyph(HGLYPH glyph
)
524 ui_destroy_bitmap((HBITMAP
) glyph
);
528 ui_create_colourmap(COLOURMAP
* colours
)
531 rfbColourMap
*map
= vncNewColourMap(server
, colours
->ncolours
);
532 for (i
= 0; i
< colours
->ncolours
; i
++)
534 vncSetColourMapEntry(map
, i
, colours
->colours
[i
].red
,
535 colours
->colours
[i
].green
, colours
->colours
[i
].blue
);
541 ui_destroy_colourmap(HCOLOURMAP map
)
543 vncDeleteColourMap(map
);
547 ui_set_colourmap(HCOLOURMAP map
)
549 vncSetColourMap(server
, map
);
553 ui_set_clip(int x
, int y
, int cx
, int cy
)
577 ui_destblt(uint8 opcode
,
578 /* dest */ int x
, int y
, int cx
, int cy
)
587 ui_rect(x
, y
, cx
, cy
, 0xff);
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
];
595 unimpl("ui_destblt: opcode=%d %d,%d %dx%d\n", opcode
, x
, y
, cx
, cy
);
600 ui_patblt(uint8 opcode
,
601 /* dest */ int x
, int y
, int cx
, int cy
,
602 /* brush */ BRUSH
* brush
, int bgcolour
, int fgcolour
)
604 switch (brush
->style
)
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
,
623 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
624 vncSetRect(server
, x
, y
, cx
, cy
, fgcolour
);
628 case 3: /* Pattern */
632 fill
= (vncBuffer
*) ui_create_glyph(8, 8, brush
->pattern
);
634 for (yy
= 0; yy
< 8; yy
++)
636 for (xx
= 0; xx
< 8; xx
++)
638 vncSetPixel(fill
, xx
, yy
,
639 vncGetPixel(fill
, xx
,
640 yy
) ? fgcolour
: bgcolour
);
644 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
649 vncCopyBlitFrom(server
, x
, y
, cx
, cy
, fill
,
653 vncXorBlitFrom(server
, x
, y
, cx
, cy
, fill
,
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
,
664 ui_destroy_glyph((HGLYPH
) fill
);
669 unimpl("brush %d\n", brush
->style
);
674 ui_screenblt(uint8 opcode
,
675 /* dest */ int x
, int y
, int cx
, int cy
,
676 /* src */ int srcx
, int srcy
)
682 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
684 //if we clipped top or left, we have to adjust srcx,srcy;
687 vncCopyBlit(server
, x
, y
, cx
, cy
, srcx
, srcy
);
692 ui_memblt(uint8 opcode
,
693 /* dest */ int x
, int y
, int cx
, int cy
,
694 /* src */ HBITMAP src
, int srcx
, int srcy
)
700 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
702 //if we clipped top or left, we have to adjust srcx,srcy;
705 switch (ROP2_S(opcode
))
708 vncTransBlitFrom(server
, x
, y
, cx
, cy
, (vncBuffer
*) src
, srcx
,
712 vncXorBlitFrom(server
, x
, y
, cx
, cy
, (vncBuffer
*) src
, srcx
, srcy
);
715 vncAndBlitFrom(server
, x
, y
, cx
, cy
, (vncBuffer
*) src
, srcx
, srcy
);
718 vncCopyBlitFrom(server
, x
, y
, cx
, cy
, (vncBuffer
*) src
, srcx
,
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
,
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
)
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. */
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
);
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
);
753 unimpl("ui_triblt 1x%x\n", opcode
);
754 ui_memblt(ROP2_COPY
, x
, y
, cx
, cy
, src
, srcx
, srcy
);
760 ui_line(uint8 opcode
,
761 /* dest */ int startx
, int starty
, int endx
, int endy
,
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
);
772 /* dest */ int x
, int y
, int cx
, int cy
,
773 /* brush */ int colour
)
775 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
777 vncSetRect(server
, x
, y
, cx
, cy
, colour
);
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
)
789 vncBuffer
*buf
= vncDupBuffer(glyph
);
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;
802 for (yy
= srcy
; yy
< srcy
+ cy
; yy
++)
804 for (xx
= srcx
; xx
< srcx
+ cx
; xx
++)
806 vncSetPixel(buf
, xx
, yy
, vncGetPixel(buf
, xx
, yy
) ? fgcolour
: bgcolour
);
812 case MIX_TRANSPARENT
:
813 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
815 //if we clipped top or left, we have to adjust srcx,srcy;
818 vncTransBlitFrom(server
, x
, y
, cx
, cy
, buf
, srcx
, srcy
, bgcolour
);
822 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
824 //if we clipped top or left, we have to adjust srcx,srcy;
827 vncCopyBlitFrom(server
, x
, y
, cx
, cy
, buf
, srcx
, srcy
);
832 unimpl("mix %d\n", mixmode
);
834 vncDeleteBuffer(buf
);
837 #define DO_GLYPH(ttext,idx) \
839 glyph = cache_get_font (font, ttext[idx]);\
840 if (!(flags & TEXT2_IMPLICIT_X))\
842 offset = ttext[++idx];\
843 if ((offset & 0x80))\
844 offset = ((offset & 0x7f) << 8) | ttext[++idx];\
845 if (flags & TEXT2_VERTICAL)\
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)\
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
)
874 ui_rect(boxx
, boxy
, boxcx
, boxcy
, bgcolour
);
876 else if (mixmode
== MIX_OPAQUE
)
878 ui_rect(clipx
, clipy
, clipcx
, clipcy
, bgcolour
);
881 /* Paint text, character by character */
882 for (i
= 0; i
< length
;)
888 cache_put_text(text
[i
+ 1], &(text
[i
- text
[i
+ 2]]),
892 error("this shouldn't be happening\n");
895 /* this will move pointer from start to first character after FF command */
897 text
= &(text
[i
+ 3]);
902 entry
= cache_get_text(text
[i
+ 1]);
905 if ((((uint8
*) (entry
->data
))[1] == 0)
906 && (!(flags
& TEXT2_IMPLICIT_X
)))
908 if (flags
& 0x04) /* vertical text */
918 /* this will move pointer from start to first character after FE command */
921 for (j
= 0; j
< entry
->size
; j
++)
922 DO_GLYPH(((uint8
*) (entry
->data
)), j
);
934 ui_desktop_save(uint32 offset
, int x
, int y
, int cx
, int cy
)
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
),
945 ui_desktop_restore(uint32 offset
, int x
, int y
, int cx
, int cy
)
949 int ox
, oy
, srcx
, srcy
;
955 offset
*= TOBYTES(server
->serverFormat
.bitsPerPixel
);
956 data
= cache_get_desktop(offset
, cx
, cy
, TOBYTES(server
->serverFormat
.bitsPerPixel
));
960 buf
= vncNewBuffer(cx
, cy
, 8);
961 memcpy(buf
->data
, data
, cx
* cy
* 1);
963 if (vncwinClipRect(&x
, &y
, &cx
, &cy
))
967 vncCopyBlitFrom(server
, x
, y
, cx
, cy
, buf
, srcx
, srcy
);
969 vncDeleteBuffer(buf
);
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}
976 {16, 16, 1, 1, 31, 63, 31, 0, 5, 10}
978 {32, 24, 1, 1, 255, 255, 255, 0, 8, 16}
980 {32, 32, 1, 1, 2047, 2047, 1023, 0, 11, 22}
984 vncNewFormat(int depth
)
986 return &(vnc_formats
[(depth
+ 1) / 8 - 1]);
990 vncNewBuffer(int w
, int h
, int depth
)
992 vncBuffer
*b
= (vncBuffer
*) xmalloc(sizeof(vncBuffer
));
993 b
->format
= vncNewFormat(depth
);
994 b
->data
= (void *) xmalloc(w
* h
* (b
->format
->bitsPerPixel
/ 8));
1003 vncDupBuffer(vncBuffer
* b
)
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);
1013 if (server
&& server
->clientHead
)
1014 rfbPrintStats(server
->clientHead
);
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)
1025 vncCopyBlitFromNoEncode(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
,
1026 vncBuffer
* src
, int srcx
, int srcy
)
1032 if (s
->serverFormat
.bitsPerPixel
== src
->format
->bitsPerPixel
1033 && srcx
+ w
<= src
->w
&& srcy
+ h
<= src
->h
)
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
++)
1041 memcpy(dstdata
, srcdata
, w
);
1042 dstdata
+= s
->paddedWidthInBytes
;
1043 srcdata
+= src
->linew
;
1048 // xsrc,ysrc provide tiling copy support.
1049 for (yy
= y
; yy
< y
+ h
; yy
++)
1051 int ysrc
= srcy
+ yy
- y
;
1052 while (ysrc
>= src
->h
)
1054 for (xx
= x
; xx
< x
+ w
; xx
++)
1057 int xsrc
= srcx
+ xx
- x
;
1058 while (xsrc
>= src
->linew
)
1060 p
= GETPIXEL(src
, xsrc
, ysrc
);
1061 SETPIXEL(frameBuffer
, xx
, yy
, p
);
1068 vncCopyBlit(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
, int srcx
, int srcy
)
1070 /* LibVNCServer already knows how to copy the data. */
1071 rfbDoCopyRect(s
, x
, y
, x
+ w
, y
+ h
, x
- srcx
, y
- srcy
);
1075 vncCopyBlitFrom(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
, vncBuffer
* src
, int srcx
, int srcy
)
1077 vncCopyBlitFromNoEncode(s
, x
, y
, w
, h
, src
, srcx
, srcy
);
1078 rfbMarkRectAsModified(s
, x
, y
, x
+ w
, y
+ h
);
1082 vncTransBlitFrom(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
,
1083 vncBuffer
* src
, int srcx
, int srcy
, int bg
)
1089 // xsrc,ysrc provide tiling copy support.
1090 for (yy
= y
; yy
< y
+ h
; yy
++)
1092 int ysrc
= srcy
+ yy
- y
;
1093 while (ysrc
>= src
->h
)
1095 for (xx
= x
; xx
< x
+ w
; xx
++)
1098 int xsrc
= srcx
+ xx
- x
;
1099 while (xsrc
>= src
->linew
)
1101 p
= GETPIXEL(src
, xsrc
, ysrc
);
1102 // transparent blit!
1104 SETPIXEL(frameBuffer
, xx
, yy
, p
);
1108 rfbMarkRectAsModified(s
, x
, y
, x
+ w
, y
+ h
);
1112 vncXorBlitFrom(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
, vncBuffer
* src
, int srcx
, int srcy
)
1118 // xsrc,ysrc provide tiling copy support.
1119 for (yy
= y
; yy
< y
+ h
; yy
++)
1121 int ysrc
= srcy
+ yy
- y
;
1122 while (ysrc
>= src
->h
)
1124 for (xx
= x
; xx
< x
+ w
; xx
++)
1127 int xsrc
= srcx
+ xx
- x
;
1128 while (xsrc
>= src
->linew
)
1130 p
= GETPIXEL(src
, xsrc
, ysrc
);
1131 pp
= GETPIXEL(frameBuffer
, xx
, yy
);
1133 SETPIXEL(frameBuffer
, xx
, yy
, p
^ pp
);
1137 rfbMarkRectAsModified(s
, x
, y
, x
+ w
, y
+ h
);
1141 vncAndBlitFrom(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
, vncBuffer
* src
, int srcx
, int srcy
)
1147 // xsrc,ysrc provide tiling copy support.
1148 for (yy
= y
; yy
< y
+ h
; yy
++)
1150 int ysrc
= srcy
+ yy
- y
;
1151 while (ysrc
>= src
->h
)
1153 for (xx
= x
; xx
< x
+ w
; xx
++)
1156 int xsrc
= srcx
+ xx
- x
;
1157 while (xsrc
>= src
->linew
)
1159 p
= GETPIXEL(src
, xsrc
, ysrc
);
1160 pp
= GETPIXEL(frameBuffer
, xx
, yy
);
1162 SETPIXEL(frameBuffer
, xx
, yy
, p
& pp
);
1166 rfbMarkRectAsModified(s
, x
, y
, x
+ w
, y
+ h
);
1170 vncDeleteBuffer(vncBuffer
* b
)
1179 vncNewCursor(vncBuffer
* mask
, vncBuffer
* pointer
, int hotx
, int hoty
)
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
));
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
);
1192 c
->height
= mask
->h
;
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
);
1202 c
->richSource
= (char *) xmalloc(pointer_size
);
1203 memcpy(c
->richSource
, pointer
->data
, pointer_size
);
1204 vncDeleteBuffer(pointer
);
1209 /* No FreeCursor, because the cursors are buffered. We only get a "HANDLE" */
1211 vncSetCursor(rfbScreenInfoPtr s
, rfbCursorPtr c
)
1213 rfbSetCursor(s
, c
, FALSE
);
1216 /* these functions work even if vncBuffer's pixel format is not 1 byte/pixel */
1218 vncGetPixel(vncBuffer
* b
, int x
, int y
)
1220 unsigned long offset
= (x
+ (y
* (b
->linew
))) * (b
->format
->bitsPerPixel
>> 3);
1221 return ((uint8_t *) (b
->data
))[offset
];
1225 vncSetPixel(vncBuffer
* b
, int x
, int y
, vncPixel c
)
1227 unsigned long offset
= (x
+ (y
* (b
->linew
))) * (b
->format
->bitsPerPixel
>> 3);
1228 ((uint8_t *) (b
->data
))[offset
] = c
;
1232 vncSetRect(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
, vncPixel c
)
1236 if (x
+ w
> s
->width
)
1238 if (y
+ h
> s
->height
)
1240 if (w
<= 0 || h
<= 0)
1245 // - Fill the rect in the local framebuffer
1246 if (s
->serverFormat
.bitsPerPixel
== 8)
1248 // - Simple 8-bit fill
1250 dstdata
= s
->frameBuffer
+ (y
* s
->paddedWidthInBytes
+ x
);
1251 for (yy
= 0; yy
< h
; yy
++)
1253 memset(dstdata
, c
, w
);
1254 dstdata
+= s
->paddedWidthInBytes
;
1259 for (yy
= y
; yy
< y
+ h
; yy
++)
1261 for (xx
= x
; xx
< x
+ w
; xx
++)
1263 SETPIXEL(frameBuffer
, xx
, yy
, c
);
1268 rfbMarkRectAsModified(s
, x
, y
, x
+ w
, y
+ h
);
1272 vncGetRect(rfbScreenInfoPtr s
, int x
, int y
, int w
, int h
)
1275 vncBuffer
*b
= vncNewBuffer(w
, h
, s
->serverFormat
.depth
);
1279 if (s
->serverFormat
.bitsPerPixel
== 8)
1282 int srcstep
, dststep
;
1283 char *srcdata
, *dstdata
;
1284 srcstep
= s
->paddedWidthInBytes
* s
->serverFormat
.bitsPerPixel
/ 8;
1285 dststep
= w
* s
->serverFormat
.bitsPerPixel
/ 8;
1287 srcdata
= s
->frameBuffer
+ (y
* srcstep
+ x
* s
->serverFormat
.bitsPerPixel
/ 8);
1288 for (yy
= 0; yy
< h
; yy
++)
1290 memcpy(dstdata
, srcdata
, dststep
);
1297 for (yy
= y
; yy
< y
+ h
; yy
++)
1299 for (xx
= x
; xx
< x
+ w
; xx
++)
1301 SETPIXEL(b
, xx
- x
, yy
- y
, GETPIXEL(frameBuffer
, xx
, yy
));
1312 vncNewColourMap(rfbScreenInfoPtr s
, int n
)
1314 rfbColourMap
*m
= (rfbColourMap
*) xmalloc(sizeof(rfbColourMap
));
1317 m
->data
.bytes
= (uint8_t *) xmalloc(n
* 3);
1322 vncSetColourMapEntry(rfbColourMap
* m
, int i
, vncPixel r
, vncPixel g
, vncPixel b
)
1326 m
->data
.bytes
[3 * i
+ 0] = r
;
1327 m
->data
.bytes
[3 * i
+ 1] = g
;
1328 m
->data
.bytes
[3 * i
+ 2] = b
;
1333 vncDeleteColourMap(rfbColourMap
* m
)
1336 free(m
->data
.bytes
);
1341 vncSetColourMap(rfbScreenInfoPtr s
, rfbColourMap
* m
)
1343 vncDeleteColourMap(&s
->colourMap
);
1345 rfbSetClientColourMaps(s
, 0, 0);
1361 rfbClientIteratorPtr iter
;
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
;
1369 iter
= rfbGetClientIterator(server
);
1370 while ((cl
= rfbClientIteratorNext(iter
)))
1371 if (cl
->useNewFBSize
)
1372 cl
->newFBSizePending
= TRUE
;
1374 rfbLog("Warning: Client %s does not support NewFBSize!\n ", cl
->host
);
1375 rfbReleaseClientIterator(iter
);