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