1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rfb.cc 14277 2021-06-11 14:46:38Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2000 Psyon.Org!
6 //
7 // Donald Becker
8 // http://www.psyon.org
9 //
10 // Copyright (C) 2001-2021 The Bochs Project
11 //
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2 of the License, or (at your option) any later version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26 // RFB still to do :
27 // - properly handle SetPixelFormat, including big/little-endian flag
28 // - depth > 8bpp support
29 // - optional compression support
30
31
32 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
33 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
34 // is used to know when we are exporting symbols and when we are importing.
35 #define BX_PLUGGABLE
36
37 #include "param_names.h"
38 #include "iodev.h"
39 #include "keymap.h"
40 #if BX_WITH_RFB
41
42 #include "icon_bochs.h"
43 #include "font/vga.bitmap.h"
44 #include "sdl.h" // 8x8 font for status text
45
46 #include "rfb.h"
47 #include "rfbkeys.h"
48
49 #include "bxthread.h"
50
51
52 class bx_rfb_gui_c : public bx_gui_c {
53 public:
bx_rfb_gui_c(void)54 bx_rfb_gui_c (void) {}
55 DECLARE_GUI_VIRTUAL_METHODS()
56 DECLARE_GUI_NEW_VIRTUAL_METHODS()
57 virtual void draw_char(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
58 Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
59 bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs);
60 virtual void set_display_mode(disp_mode_t newmode);
61 void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp);
62 void statusbar_setitem_specific(int element, bool active, bool w);
63 virtual void set_mouse_mode_absxy(bool mode);
64 #if BX_SHOW_IPS
65 void show_ips(Bit32u ips_count);
66 #endif
67 private:
68 void rfbMouseMove(int x, int y, int z, int bmask);
69 void rfbKeyPressed(Bit32u key, int press_release);
70 };
71
72 // declare one instance of the gui object and call macro to insert the
73 // plugin code
74 static bx_rfb_gui_c *theGui = NULL;
75 IMPLEMENT_GUI_PLUGIN_CODE(rfb)
76
77 #define LOG_THIS theGui->
78
79 #if defined(WIN32) && !defined(__CYGWIN__)
80
81 #include <winsock2.h>
82 #include <process.h>
83 #define BX_RFB_WIN32
84
85 #else
86
87 #include <sys/socket.h>
88 #include <netinet/tcp.h>
89 #include <netinet/in.h>
90 #include <unistd.h>
91 #ifndef __QNXNTO__
92 #include <sys/errno.h>
93 #else
94 #include <errno.h>
95 #endif
96
97 typedef int SOCKET;
98 #ifndef INVALID_SOCKET
99 #define INVALID_SOCKET -1
100 #endif
101
102 #endif
103
104 static bool keep_alive;
105 static bool client_connected;
106 static bool desktop_resizable;
107 #if BX_SHOW_IPS
108 static bool rfbHideIPS = 0;
109 static bool rfbIPSupdate = 0;
110 static char rfbIPStext[40];
111 #endif
112 static unsigned short rfbPort;
113
114 // Headerbar stuff
115 static unsigned rfbBitmapCount = 0;
116 static struct _rfbBitmaps {
117 char *bmap;
118 unsigned xdim;
119 unsigned ydim;
120 } rfbBitmaps[BX_MAX_PIXMAPS];
121
122 // Keyboard/Mouse stuff
123 #define KEYBOARD 1
124 #define MOUSE 0
125 #define MAX_KEY_EVENTS 512
126 static struct _rfbKeyboardEvent {
127 bool type;
128 int key;
129 int down;
130 int x;
131 int y;
132 int z;
133 } rfbKeyboardEvent[MAX_KEY_EVENTS];
134 static unsigned long rfbKeyboardEvents = 0;
135 static bool bKeyboardInUse = 0;
136
137 // Misc Stuff
138 static struct _rfbUpdateRegion {
139 unsigned int x;
140 unsigned int y;
141 unsigned int width;
142 unsigned int height;
143 bool updated;
144 } rfbUpdateRegion;
145
146 #define BX_RFB_MAX_XDIM 1280
147 #define BX_RFB_MAX_YDIM 1024
148 #define BX_RFB_DEF_XDIM 720
149 #define BX_RFB_DEF_YDIM 480
150
151 static Bit8u status_leds[3] = {0x38, 0x07, 0x3f};
152 static unsigned char status_gray_text = 0xa4;
153 const unsigned char headerbar_bg = 0xff;
154 const unsigned char headerbar_fg = 0x00;
155
156 static char *rfbScreen;
157 static char rfbPalette[256];
158 static bool rfbBGR233Format;
159
160 static unsigned rfbWindowX, rfbWindowY;
161 static unsigned rfbDimensionX, rfbDimensionY;
162 static Bit16u rfbHeaderbarY;
163 static unsigned rfbTileX = 0;
164 static unsigned rfbTileY = 0;
165 static unsigned long rfbOriginLeft = 0;
166 static unsigned long rfbOriginRight = 0;
167 static bool rfbMouseModeAbsXY = 0;
168 static unsigned rfbStatusbarY = 18;
169 static unsigned rfbStatusitemPos[12] = {
170 0, 170, 210, 250, 290, 330, 370, 410, 450, 490, 530, 570
171 };
172 static bool rfbStatusitemActive[12];
173
174 static SOCKET sGlobal;
175
176 static Bit32u clientEncodingsCount = 0;
177 static Bit32u *clientEncodings = NULL;
178
179 #ifdef BX_RFB_WIN32
180 bool StopWinsock();
181 #endif
182 void rfbStartThread();
183 void HandleRfbClient(SOCKET sClient);
184 int ReadExact(int sock, char *buf, int len);
185 int WriteExact(int sock, char *buf, int len);
186 void DrawBitmap(int x, int y, int width, int height, char *bmap, char fg,
187 char bg, bool update_client);
188 void DrawChar(int x, int y, int width, int height, int fontx, int fonty,
189 char *bmap, char fg, char bg, bool gfxchar);
190 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height,
191 bool update_client);
192 void SendUpdate(int x, int y, int width, int height, Bit32u encoding);
193 void rfbSetUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h);
194 void rfbAddUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h);
195 void rfbSetStatusText(int element, const char *text, bool active, Bit8u color = 0);
196 static Bit32u convertStringToRfbKey(const char *string);
197 #if BX_SHOW_IPS && defined(WIN32)
198 DWORD WINAPI rfbShowIPSthread(LPVOID);
199 #endif
200
201 static const rfbPixelFormat BGR233Format = {
202 8, 8, 1, 1, 7, 7, 3, 0, 3, 6
203 };
204 static const rfbPixelFormat RGB332Format = {
205 8, 8, 0, 1, 7, 7, 3, 5, 2, 0
206 };
207
208 // VNCViewer code to be replaced
209 #define PF_EQ(x,y) ((x.bitsPerPixel == y.bitsPerPixel) && (x.depth == y.depth) && (x.trueColourFlag == y.trueColourFlag) && ((x.bigEndianFlag == y.bigEndianFlag) || (x.bitsPerPixel == 8)) && (!x.trueColourFlag || ((x.redMax == y.redMax) && (x.greenMax == y.greenMax) && (x.blueMax == y.blueMax) && (x.redShift == y.redShift) && (x.greenShift == y.greenShift) && (x.blueShift == y.blueShift))))
210
211
212 // RFB implementation of the bx_gui_c methods (see nogui.cc for details)
213
specific_init(int argc,char ** argv,unsigned headerbar_y)214 void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned headerbar_y)
215 {
216 int i, timeout = 30;
217
218 put("RFB");
219 UNUSED(bochs_icon_bits);
220
221 rfbHeaderbarY = (Bit16u)headerbar_y;
222 rfbDimensionX = BX_RFB_DEF_XDIM;
223 rfbDimensionY = BX_RFB_DEF_YDIM;
224 rfbWindowX = rfbDimensionX;
225 rfbWindowY = rfbDimensionY + rfbHeaderbarY + rfbStatusbarY;
226 rfbTileX = x_tilesize;
227 rfbTileY = y_tilesize;
228
229 for (i = 0; i < 256; i++) {
230 for (int j = 0; j < 16; j++) {
231 vga_charmap[i * 32 + j] = reverse_bitorder(bx_vgafont[i].data[j]);
232 }
233 }
234
235 console.present = 1;
236
237 // parse rfb specific options
238 if (argc > 1) {
239 for (i = 1; i < argc; i++) {
240 if (!strncmp(argv[i], "timeout=", 8)) {
241 timeout = atoi(&argv[i][8]);
242 if (timeout < 0) {
243 BX_PANIC(("invalid timeout value: %d", timeout));
244 } else {
245 BX_INFO(("connection timeout set to %d", timeout));
246 }
247 #if BX_SHOW_IPS
248 } else if (!strcmp(argv[i], "hideIPS")) {
249 BX_INFO(("hide IPS display in status bar"));
250 rfbHideIPS = 1;
251 #endif
252 } else if (!strcmp(argv[i], "no_gui_console")) {
253 console.present = 0;
254 } else {
255 BX_PANIC(("Unknown rfb option '%s'", argv[i]));
256 }
257 }
258 }
259
260 if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {
261 BX_ERROR(("private_colormap option ignored."));
262 }
263
264 rfbScreen = new char[rfbWindowX * rfbWindowY];
265 memset(&rfbPalette, 0, sizeof(rfbPalette));
266
267 rfbSetUpdateRegion(rfbWindowX, rfbWindowY, 0, 0);
268
269 clientEncodingsCount=0;
270 clientEncodings=NULL;
271
272 keep_alive = 1;
273 client_connected = 0;
274 desktop_resizable = 0;
275 rfbStartThread();
276
277 #ifdef WIN32
278 Sleep(1000);
279 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
280 #endif
281
282 // load keymap for rfb
283 if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
284 bx_keymap.loadKeymap(convertStringToRfbKey);
285 }
286
287 // the ask menu doesn't work on the client side
288 io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
289
290 if (timeout > 0) {
291 while ((!client_connected) && (timeout--)) {
292 fprintf(stderr, "Bochs RFB server waiting for client: %2d\r", timeout+1);
293 #ifdef BX_RFB_WIN32
294 Sleep(1000);
295 #else
296 sleep(1);
297 #endif
298 }
299 if ((timeout < 0) && (!client_connected)) {
300 BX_PANIC(("timeout! no client present"));
301 } else {
302 fprintf(stderr, "RFB client connected \r");
303 }
304 }
305
306 #if BX_SHOW_IPS && defined(WIN32)
307 if (!rfbHideIPS) {
308 DWORD threadID;
309 CreateThread(NULL, 0, rfbShowIPSthread, NULL, 0, &threadID);
310 }
311 #endif
312
313 new_gfx_api = 1;
314 new_text_api = 1;
315 }
316
handle_events(void)317 void bx_rfb_gui_c::handle_events(void)
318 {
319 while (bKeyboardInUse) ;
320
321 bKeyboardInUse = 1;
322 if (rfbKeyboardEvents > 0) {
323 for (unsigned i = 0; i < rfbKeyboardEvents; i++) {
324 if (rfbKeyboardEvent[i].type == KEYBOARD) {
325 rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down);
326 } else { //type == MOUSE;
327 rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].z, rfbKeyboardEvent[i].down);
328 }
329 }
330 rfbKeyboardEvents = 0;
331 }
332 bKeyboardInUse = 0;
333
334 #if BX_SHOW_IPS
335 if (rfbIPSupdate) {
336 rfbIPSupdate = 0;
337 rfbSetStatusText(0, rfbIPStext, 1);
338 }
339 #endif
340 }
341
flush(void)342 void bx_rfb_gui_c::flush(void)
343 {
344 if (rfbUpdateRegion.updated) {
345 SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width,
346 rfbUpdateRegion.height, rfbEncodingRaw);
347 rfbSetUpdateRegion(rfbWindowX, rfbWindowY, 0, 0);
348 }
349 }
350
clear_screen(void)351 void bx_rfb_gui_c::clear_screen(void)
352 {
353 memset(&rfbScreen[rfbWindowX * rfbHeaderbarY], 0, rfbWindowX * rfbDimensionY);
354 rfbAddUpdateRegion(0, rfbHeaderbarY, rfbWindowX, rfbDimensionY);
355 }
356
draw_char(Bit8u ch,Bit8u fc,Bit8u bc,Bit16u xc,Bit16u yc,Bit8u fw,Bit8u fh,Bit8u fx,Bit8u fy,bool gfxcharw9,Bit8u cs,Bit8u ce,bool curs)357 void bx_rfb_gui_c::draw_char(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
358 Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
359 bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs)
360 {
361 Bit8u fgcol = rfbPalette[fc];
362 Bit8u bgcol = rfbPalette[bc];
363
364 yc += rfbHeaderbarY;
365 DrawChar(xc, yc, fw, fh, fx, fy, (char *)&vga_charmap[ch << 5], fgcol, bgcol,
366 gfxcharw9);
367 rfbAddUpdateRegion(xc, yc, fw, fh);
368 if (curs && (ce >= fy) && (cs < (fh + fy))) {
369 if (cs > fy) {
370 yc += (cs - fy);
371 fh -= (cs - fy);
372 }
373 if ((ce - cs + 1) < fh) {
374 fh = ce - cs + 1;
375 }
376 DrawChar(xc, yc, fw, fh, fx, cs, (char *)&vga_charmap[ch << 5], bgcol,
377 fgcol, gfxcharw9);
378 }
379 }
380
text_update(Bit8u * old_text,Bit8u * new_text,unsigned long cursor_x,unsigned long cursor_y,bx_vga_tminfo_t * tm_info)381 void bx_rfb_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t *tm_info)
382 {
383 // present for compatibilty
384 }
385
get_clipboard_text(Bit8u ** bytes,Bit32s * nbytes)386 int bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
387 {
388 return 0;
389 }
390
set_clipboard_text(char * text_snapshot,Bit32u len)391 int bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
392 {
393 return 0;
394 }
395
palette_change(Bit8u index,Bit8u red,Bit8u green,Bit8u blue)396 bool bx_rfb_gui_c::palette_change(Bit8u index, Bit8u red, Bit8u green, Bit8u blue)
397 {
398 if (rfbBGR233Format) {
399 rfbPalette[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6);
400 } else {
401 rfbPalette[index] = (((red * 7 + 127) / 255) << 5) | (((green * 7 + 127) / 255) << 2) | (((blue * 3 + 127) / 255) << 0);
402 }
403 return 1;
404 }
405
graphics_tile_update(Bit8u * tile,unsigned x0,unsigned y0)406 void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
407 {
408 unsigned c, i, h, y;
409
410 switch (guest_bpp) {
411 case 8: /* 8 bpp */
412 y = y0 + rfbHeaderbarY;
413 if ((y0 + rfbTileY) > rfbDimensionY) {
414 h = rfbDimensionY - y0;
415 } else {
416 h = rfbTileY;
417 }
418 for (i = 0; i < h; i++) {
419 for (c = 0; c < rfbTileX; c++) {
420 tile[(i * rfbTileX) + c] = rfbPalette[tile[(i * rfbTileX) + c]];
421 }
422 memcpy(&rfbScreen[y * rfbWindowX + x0], &tile[i * rfbTileX], rfbTileX);
423 y++;
424 }
425 break;
426 default:
427 BX_PANIC(("%u bpp modes handled by new graphics API", guest_bpp));
428 return;
429 }
430 rfbAddUpdateRegion(x0, y0 + rfbHeaderbarY, rfbTileX, h);
431 }
432
dimension_update(unsigned x,unsigned y,unsigned fheight,unsigned fwidth,unsigned bpp)433 void bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
434 {
435 if (bpp == 8) {
436 guest_bpp = bpp;
437 } else {
438 BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
439 }
440 guest_textmode = (fheight > 0);
441 guest_fwidth = fwidth;
442 guest_fheight = fheight;
443 guest_xres = x;
444 guest_yres = y;
445 if ((x != rfbDimensionX) || (y != rfbDimensionY)) {
446 if (desktop_resizable) {
447 if ((x > BX_RFB_MAX_XDIM) || (y > BX_RFB_MAX_YDIM)) {
448 BX_PANIC(("dimension_update(): RFB doesn't support graphics mode %dx%d", x, y));
449 }
450 rfbDimensionX = x;
451 rfbDimensionY = y;
452 rfbWindowX = rfbDimensionX;
453 rfbWindowY = rfbDimensionY + rfbHeaderbarY + rfbStatusbarY;
454 delete [] rfbScreen;
455 rfbScreen = new char[rfbWindowX * rfbWindowY];
456 SendUpdate(0, 0, rfbWindowX, rfbWindowY, rfbEncodingDesktopSize);
457 bx_gui->show_headerbar();
458 rfbSetUpdateRegion(0, 0, rfbWindowX, rfbWindowY);
459 } else {
460 if ((x > BX_RFB_DEF_XDIM) || (y > BX_RFB_DEF_YDIM)) {
461 BX_PANIC(("dimension_update(): RFB doesn't support graphics mode %dx%d", x, y));
462 }
463 clear_screen();
464 SendUpdate(0, rfbHeaderbarY, rfbDimensionX, rfbDimensionY, rfbEncodingRaw);
465 rfbDimensionX = x;
466 rfbDimensionY = y;
467 }
468 }
469 }
470
create_bitmap(const unsigned char * bmap,unsigned xdim,unsigned ydim)471 unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
472 {
473 if (rfbBitmapCount >= BX_MAX_PIXMAPS) {
474 BX_ERROR(("too many pixmaps."));
475 return 0;
476 }
477 rfbBitmaps[rfbBitmapCount].bmap = new char[(xdim * ydim) / 8];
478 rfbBitmaps[rfbBitmapCount].xdim = xdim;
479 rfbBitmaps[rfbBitmapCount].ydim = ydim;
480 memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8);
481
482 rfbBitmapCount++;
483 return (rfbBitmapCount - 1);
484 }
485
headerbar_bitmap(unsigned bmap_id,unsigned alignment,void (* f)(void))486 unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
487 {
488 int hb_index;
489
490 if ((bx_headerbar_entries + 1) > BX_MAX_HEADERBAR_ENTRIES) {
491 return 0;
492 }
493
494 hb_index = bx_headerbar_entries++;
495 bx_headerbar_entry[hb_index].bmap_id = bmap_id;
496 bx_headerbar_entry[hb_index].xdim = rfbBitmaps[bmap_id].xdim;
497 bx_headerbar_entry[hb_index].ydim = rfbBitmaps[bmap_id].ydim;
498 bx_headerbar_entry[hb_index].alignment = alignment;
499 bx_headerbar_entry[hb_index].f = f;
500 if (alignment == BX_GRAVITY_LEFT) {
501 bx_headerbar_entry[hb_index].xorigin = rfbOriginLeft;
502 rfbOriginLeft += rfbBitmaps[bmap_id].xdim;
503 } else { // BX_GRAVITY_RIGHT
504 rfbOriginRight += rfbBitmaps[bmap_id].xdim;
505 bx_headerbar_entry[hb_index].xorigin = rfbOriginRight;
506 }
507 return hb_index;
508 }
509
show_headerbar(void)510 void bx_rfb_gui_c::show_headerbar(void)
511 {
512 char *newBits, value;
513 unsigned int i, xorigin, addr, bmap_id;
514
515 newBits = new char[rfbWindowX * rfbHeaderbarY];
516 memset(newBits, 0, (rfbWindowX * rfbHeaderbarY));
517 DrawBitmap(0, 0, rfbWindowX, rfbHeaderbarY, newBits, headerbar_fg, headerbar_bg, 0);
518 for (i = 0; i < bx_headerbar_entries; i++) {
519 if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT) {
520 xorigin = bx_headerbar_entry[i].xorigin;
521 } else {
522 xorigin = rfbWindowX - bx_headerbar_entry[i].xorigin;
523 }
524 bmap_id = bx_headerbar_entry[i].bmap_id;
525 DrawBitmap(xorigin, 0, rfbBitmaps[bmap_id].xdim, rfbBitmaps[bmap_id].ydim,
526 rfbBitmaps[bmap_id].bmap, headerbar_fg, headerbar_bg, 0);
527 }
528 delete [] newBits;
529 newBits = new char[rfbWindowX * rfbStatusbarY / 8];
530 memset(newBits, 0, (rfbWindowX * rfbStatusbarY / 8));
531 for (i = 1; i < 12; i++) {
532 addr = rfbStatusitemPos[i] / 8;
533 value = 1 << (rfbStatusitemPos[i] % 8);
534 for (unsigned j = 1; j < rfbStatusbarY; j++) {
535 newBits[(rfbWindowX * j / 8) + addr] = value;
536 }
537 }
538 DrawBitmap(0, rfbWindowY - rfbStatusbarY, rfbWindowX, rfbStatusbarY, newBits,
539 headerbar_fg, headerbar_bg, 0);
540 delete [] newBits;
541 for (i = 1; i <= statusitem_count; i++) {
542 rfbSetStatusText(i, statusitem[i - 1].text, rfbStatusitemActive[i]);
543 }
544 }
545
replace_bitmap(unsigned hbar_id,unsigned bmap_id)546 void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
547 {
548 unsigned int xorigin;
549
550 if (bmap_id == bx_headerbar_entry[hbar_id].bmap_id)
551 return;
552 bx_headerbar_entry[hbar_id].bmap_id = bmap_id;
553 if (bx_headerbar_entry[hbar_id].alignment == BX_GRAVITY_LEFT) {
554 xorigin = bx_headerbar_entry[hbar_id].xorigin;
555 } else {
556 xorigin = rfbWindowX - bx_headerbar_entry[hbar_id].xorigin;
557 }
558 DrawBitmap(xorigin, 0, rfbBitmaps[bmap_id].xdim, rfbBitmaps[bmap_id].ydim,
559 rfbBitmaps[bmap_id].bmap, headerbar_fg, headerbar_bg, 1);
560 }
561
exit(void)562 void bx_rfb_gui_c::exit(void)
563 {
564 unsigned int i;
565 keep_alive = 0;
566 #ifdef BX_RFB_WIN32
567 StopWinsock();
568 #endif
569 delete [] rfbScreen;
570 for(i = 0; i < rfbBitmapCount; i++) {
571 free(rfbBitmaps[i].bmap);
572 }
573
574 // Clear supported encodings
575 if (clientEncodings != NULL) {
576 delete [] clientEncodings;
577 clientEncodingsCount = 0;
578 }
579
580 BX_DEBUG(("bx_rfb_gui_c::exit()"));
581 }
582
mouse_enabled_changed_specific(bool val)583 void bx_rfb_gui_c::mouse_enabled_changed_specific(bool val)
584 {
585 }
586
graphics_tile_info(bx_svga_tileinfo_t * info)587 bx_svga_tileinfo_t *bx_rfb_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info)
588 {
589 info->bpp = 8;
590 info->pitch = rfbWindowX;
591 info->red_shift = 3;
592 info->green_shift = 6;
593 info->blue_shift = 8;
594 info->red_mask = 0x07;
595 info->green_mask = 0x38;
596 info->blue_mask = 0xc0;
597 info->is_indexed = 0;
598 #ifdef BX_LITTLE_ENDIAN
599 info->is_little_endian = 1;
600 #else
601 info->is_little_endian = 0;
602 #endif
603
604 return info;
605 }
606
graphics_tile_get(unsigned x0,unsigned y0,unsigned * w,unsigned * h)607 Bit8u *bx_rfb_gui_c::graphics_tile_get(unsigned x0, unsigned y0,
608 unsigned *w, unsigned *h)
609 {
610 if (x0 + rfbTileX > rfbDimensionX) {
611 *w = rfbDimensionX - x0;
612 } else {
613 *w = rfbTileX;
614 }
615
616 if (y0 + rfbTileY > rfbDimensionY) {
617 *h = rfbDimensionY - y0;
618 } else {
619 *h = rfbTileY;
620 }
621
622 return (Bit8u *)rfbScreen + (rfbHeaderbarY + y0) * rfbWindowX + x0;
623 }
624
graphics_tile_update_in_place(unsigned x0,unsigned y0,unsigned w,unsigned h)625 void bx_rfb_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,
626 unsigned w, unsigned h)
627 {
628 rfbAddUpdateRegion(x0, y0 + rfbHeaderbarY, w, h);
629 }
630
631
get_capabilities(Bit16u * xres,Bit16u * yres,Bit16u * bpp)632 void bx_rfb_gui_c::get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp)
633 {
634 if (desktop_resizable) {
635 *xres = BX_RFB_MAX_XDIM;
636 *yres = BX_RFB_MAX_YDIM;
637 } else {
638 *xres = BX_RFB_DEF_XDIM;
639 *yres = BX_RFB_DEF_YDIM;
640 }
641 *bpp = 8;
642 }
643
statusbar_setitem_specific(int element,bool active,bool w)644 void bx_rfb_gui_c::statusbar_setitem_specific(int element, bool active, bool w)
645 {
646 Bit8u color = 0;
647 if (w) {
648 color = statusitem[element].auto_off ? 1 : 2;
649 }
650 rfbSetStatusText(element+1, statusitem[element].text, active, color);
651 }
652
set_mouse_mode_absxy(bool mode)653 void bx_rfb_gui_c::set_mouse_mode_absxy(bool mode)
654 {
655 rfbMouseModeAbsXY = mode;
656 }
657
658 #if BX_SHOW_IPS
show_ips(Bit32u ips_count)659 void bx_rfb_gui_c::show_ips(Bit32u ips_count)
660 {
661 if (!rfbIPSupdate && !rfbHideIPS) {
662 ips_count /= 1000;
663 sprintf(rfbIPStext, "IPS: %u.%3.3uM", ips_count / 1000, ips_count % 1000);
664 rfbIPSupdate = 1;
665 }
666 }
667 #endif
668
set_display_mode(disp_mode_t newmode)669 void bx_rfb_gui_c::set_display_mode(disp_mode_t newmode)
670 {
671 // if no mode change, do nothing.
672 if (disp_mode == newmode) return;
673 // remember the display mode for next time
674 disp_mode = newmode;
675 if ((newmode == DISP_MODE_SIM) && console_running()) {
676 console_cleanup();
677 }
678 }
679
rfbMouseMove(int x,int y,int z,int bmask)680 void bx_rfb_gui_c::rfbMouseMove(int x, int y, int z, int bmask)
681 {
682 static int oldx = -1;
683 static int oldy = -1;
684 int dx, dy;
685
686 if ((oldx == 1) && (oldy == -1)) {
687 oldx = x;
688 oldy = y;
689 return;
690 }
691 if (y > rfbHeaderbarY) {
692 if (console_running())
693 return;
694 if (rfbMouseModeAbsXY) {
695 if ((y >= rfbHeaderbarY) && (y < (int)(rfbDimensionY + rfbHeaderbarY))) {
696 dx = x * 0x7fff / rfbDimensionX;
697 dy = (y - rfbHeaderbarY) * 0x7fff / rfbDimensionY;
698 DEV_mouse_motion(dx, dy, z, bmask, 1);
699 }
700 } else {
701 DEV_mouse_motion(x - oldx, oldy - y, z, bmask, 0);
702 }
703 oldx = x;
704 oldy = y;
705 } else {
706 if (bmask == 1) {
707 bKeyboardInUse = 0;
708 rfbKeyboardEvents = 0;
709 headerbar_click(x);
710 }
711 }
712 }
713
714 // function to convert key names into rfb key values.
715 // This first try will be horribly inefficient, but it only has
716 // to be done while loading a keymap. Once the simulation starts,
717 // this function won't be called.
convertStringToRfbKey(const char * string)718 static Bit32u convertStringToRfbKey(const char *string)
719 {
720 rfbKeyTabEntry *ptr;
721 for (ptr = &rfb_keytable[0]; ptr->name != NULL; ptr++) {
722 if (!strcmp(string, ptr->name))
723 return ptr->value;
724 }
725 return BX_KEYMAP_UNKNOWN;
726 }
727
728 static Bit32u rfb_ascii_to_key_event[0x5f] = {
729 // !"#$%&'
730 BX_KEY_SPACE,
731 BX_KEY_1,
732 BX_KEY_SINGLE_QUOTE,
733 BX_KEY_3,
734 BX_KEY_4,
735 BX_KEY_5,
736 BX_KEY_7,
737 BX_KEY_SINGLE_QUOTE,
738
739 // ()*+,-./
740 BX_KEY_9,
741 BX_KEY_0,
742 BX_KEY_8,
743 BX_KEY_EQUALS,
744 BX_KEY_COMMA,
745 BX_KEY_MINUS,
746 BX_KEY_PERIOD,
747 BX_KEY_SLASH,
748
749 // 01234567
750 BX_KEY_0,
751 BX_KEY_1,
752 BX_KEY_2,
753 BX_KEY_3,
754 BX_KEY_4,
755 BX_KEY_5,
756 BX_KEY_6,
757 BX_KEY_7,
758
759 // 89:;<=>?
760 BX_KEY_8,
761 BX_KEY_9,
762 BX_KEY_SEMICOLON,
763 BX_KEY_SEMICOLON,
764 BX_KEY_COMMA,
765 BX_KEY_EQUALS,
766 BX_KEY_PERIOD,
767 BX_KEY_SLASH,
768
769 // @ABCDEFG
770 BX_KEY_2,
771 BX_KEY_A,
772 BX_KEY_B,
773 BX_KEY_C,
774 BX_KEY_D,
775 BX_KEY_E,
776 BX_KEY_F,
777 BX_KEY_G,
778
779
780 // HIJKLMNO
781 BX_KEY_H,
782 BX_KEY_I,
783 BX_KEY_J,
784 BX_KEY_K,
785 BX_KEY_L,
786 BX_KEY_M,
787 BX_KEY_N,
788 BX_KEY_O,
789
790
791 // PQRSTUVW
792 BX_KEY_P,
793 BX_KEY_Q,
794 BX_KEY_R,
795 BX_KEY_S,
796 BX_KEY_T,
797 BX_KEY_U,
798 BX_KEY_V,
799 BX_KEY_W,
800
801 // XYZ[\]^_
802 BX_KEY_X,
803 BX_KEY_Y,
804 BX_KEY_Z,
805 BX_KEY_LEFT_BRACKET,
806 BX_KEY_BACKSLASH,
807 BX_KEY_RIGHT_BRACKET,
808 BX_KEY_6,
809 BX_KEY_MINUS,
810
811 // `abcdefg
812 BX_KEY_GRAVE,
813 BX_KEY_A,
814 BX_KEY_B,
815 BX_KEY_C,
816 BX_KEY_D,
817 BX_KEY_E,
818 BX_KEY_F,
819 BX_KEY_G,
820
821 // hijklmno
822 BX_KEY_H,
823 BX_KEY_I,
824 BX_KEY_J,
825 BX_KEY_K,
826 BX_KEY_L,
827 BX_KEY_M,
828 BX_KEY_N,
829 BX_KEY_O,
830
831 // pqrstuvw
832 BX_KEY_P,
833 BX_KEY_Q,
834 BX_KEY_R,
835 BX_KEY_S,
836 BX_KEY_T,
837 BX_KEY_U,
838 BX_KEY_V,
839 BX_KEY_W,
840
841 // xyz{|}~
842 BX_KEY_X,
843 BX_KEY_Y,
844 BX_KEY_Z,
845 BX_KEY_LEFT_BRACKET,
846 BX_KEY_BACKSLASH,
847 BX_KEY_RIGHT_BRACKET,
848 BX_KEY_GRAVE
849 };
850
rfbKeyPressed(Bit32u key,int press_release)851 void bx_rfb_gui_c::rfbKeyPressed(Bit32u key, int press_release)
852 {
853 Bit32u key_event;
854
855 if (console_running() && press_release) {
856 if (((key >= XK_space) && (key <= XK_asciitilde)) ||
857 (key == XK_Return) || (key == XK_BackSpace)) {
858 console_key_enq((Bit8u)(key & 0xff));
859 }
860 return;
861 }
862 if (!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
863 if ((key >= XK_space) && (key <= XK_asciitilde)) {
864 key_event = rfb_ascii_to_key_event[key - XK_space];
865 } else {
866 switch (key) {
867 case XK_KP_1:
868 #ifdef XK_KP_End
869 case XK_KP_End:
870 #endif
871 key_event = BX_KEY_KP_END;
872 break;
873
874 case XK_KP_2:
875 #ifdef XK_KP_Down
876 case XK_KP_Down:
877 #endif
878 key_event = BX_KEY_KP_DOWN;
879 break;
880
881 case XK_KP_3:
882 #ifdef XK_KP_Page_Down
883 case XK_KP_Page_Down:
884 #endif
885 key_event = BX_KEY_KP_PAGE_DOWN;
886 break;
887
888 case XK_KP_4:
889 #ifdef XK_KP_Left
890 case XK_KP_Left:
891 #endif
892 key_event = BX_KEY_KP_LEFT;
893 break;
894
895 case XK_KP_5:
896 #ifdef XK_KP_Begin
897 case XK_KP_Begin:
898 #endif
899 key_event = BX_KEY_KP_5;
900 break;
901
902 case XK_KP_6:
903 #ifdef XK_KP_Right
904 case XK_KP_Right:
905 #endif
906 key_event = BX_KEY_KP_RIGHT;
907 break;
908
909 case XK_KP_7:
910 #ifdef XK_KP_Home
911 case XK_KP_Home:
912 #endif
913 key_event = BX_KEY_KP_HOME;
914 break;
915
916 case XK_KP_8:
917 #ifdef XK_KP_Up
918 case XK_KP_Up:
919 #endif
920 key_event = BX_KEY_KP_UP;
921 break;
922
923 case XK_KP_9:
924 #ifdef XK_KP_Page_Up
925 case XK_KP_Page_Up:
926 #endif
927 key_event = BX_KEY_KP_PAGE_UP;
928 break;
929
930 case XK_KP_0:
931 #ifdef XK_KP_Insert
932 case XK_KP_Insert:
933 #endif
934 key_event = BX_KEY_KP_INSERT;
935 break;
936
937 case XK_KP_Decimal:
938 #ifdef XK_KP_Delete
939 case XK_KP_Delete:
940 #endif
941 key_event = BX_KEY_KP_DELETE;
942 break;
943
944 #ifdef XK_KP_Enter
945 case XK_KP_Enter:
946 key_event = BX_KEY_KP_ENTER;
947 break;
948 #endif
949
950 case XK_KP_Subtract:
951 key_event = BX_KEY_KP_SUBTRACT;
952 break;
953 case XK_KP_Add:
954 key_event = BX_KEY_KP_ADD;
955 break;
956
957 case XK_KP_Multiply:
958 key_event = BX_KEY_KP_MULTIPLY;
959 break;
960 case XK_KP_Divide:
961 key_event = BX_KEY_KP_DIVIDE;
962 break;
963
964 case XK_Up:
965 key_event = BX_KEY_UP;
966 break;
967 case XK_Down:
968 key_event = BX_KEY_DOWN;
969 break;
970 case XK_Left:
971 key_event = BX_KEY_LEFT;
972 break;
973 case XK_Right:
974 key_event = BX_KEY_RIGHT;
975 break;
976
977 case XK_Delete:
978 key_event = BX_KEY_DELETE;
979 break;
980 case XK_BackSpace:
981 key_event = BX_KEY_BACKSPACE;
982 break;
983 case XK_Tab:
984 key_event = BX_KEY_TAB;
985 break;
986 #ifdef XK_ISO_Left_Tab
987 case XK_ISO_Left_Tab:
988 key_event = BX_KEY_TAB;
989 break;
990 #endif
991 case XK_Return:
992 key_event = BX_KEY_ENTER;
993 break;
994 case XK_Escape:
995 key_event = BX_KEY_ESC;
996 break;
997 case XK_F1:
998 key_event = BX_KEY_F1;
999 break;
1000 case XK_F2:
1001 key_event = BX_KEY_F2;
1002 break;
1003 case XK_F3:
1004 key_event = BX_KEY_F3;
1005 break;
1006 case XK_F4:
1007 key_event = BX_KEY_F4;
1008 break;
1009 case XK_F5:
1010 key_event = BX_KEY_F5;
1011 break;
1012 case XK_F6:
1013 key_event = BX_KEY_F6;
1014 break;
1015 case XK_F7:
1016 key_event = BX_KEY_F7;
1017 break;
1018 case XK_F8:
1019 key_event = BX_KEY_F8;
1020 break;
1021 case XK_F9:
1022 key_event = BX_KEY_F9;
1023 break;
1024 case XK_F10:
1025 key_event = BX_KEY_F10;
1026 break;
1027 case XK_F11:
1028 key_event = BX_KEY_F11;
1029 break;
1030 case XK_F12:
1031 key_event = BX_KEY_F12;
1032 break;
1033 case XK_Control_L:
1034 key_event = BX_KEY_CTRL_L;
1035 break;
1036 #ifdef XK_Control_R
1037 case XK_Control_R:
1038 key_event = BX_KEY_CTRL_R;
1039 break;
1040 #endif
1041 case XK_Shift_L:
1042 key_event = BX_KEY_SHIFT_L;
1043 break;
1044 case XK_Shift_R:
1045 key_event = BX_KEY_SHIFT_R;
1046 break;
1047 case XK_Alt_L:
1048 key_event = BX_KEY_ALT_L;
1049 break;
1050 #ifdef XK_Alt_R
1051 case XK_Alt_R:
1052 key_event = BX_KEY_ALT_R;
1053 break;
1054 #endif
1055 case XK_Caps_Lock:
1056 key_event = BX_KEY_CAPS_LOCK;
1057 break;
1058 case XK_Num_Lock:
1059 key_event = BX_KEY_NUM_LOCK;
1060 break;
1061 #ifdef XK_Scroll_Lock
1062 case XK_Scroll_Lock:
1063 key_event = BX_KEY_SCRL_LOCK;
1064 break;
1065 #endif
1066 #ifdef XK_Print
1067 case XK_Print:
1068 key_event = BX_KEY_PRINT;
1069 break;
1070 #endif
1071 #ifdef XK_Pause
1072 case XK_Pause:
1073 key_event = BX_KEY_PAUSE;
1074 break;
1075 #endif
1076
1077 case XK_Insert:
1078 key_event = BX_KEY_INSERT;
1079 break;
1080 case XK_Home:
1081 key_event = BX_KEY_HOME;
1082 break;
1083 case XK_End:
1084 key_event = BX_KEY_END;
1085 break;
1086 case XK_Page_Up:
1087 key_event = BX_KEY_PAGE_UP;
1088 break;
1089 case XK_Page_Down:
1090 key_event = BX_KEY_PAGE_DOWN;
1091 break;
1092
1093 default:
1094 BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key));
1095 return;
1096 }
1097 }
1098 } else {
1099 BXKeyEntry *entry = bx_keymap.findHostKey(key);
1100 if (!entry) {
1101 BX_ERROR(("rfbKeyPressed(): key %x unhandled!", (unsigned) key));
1102 return;
1103 }
1104 key_event = entry->baseKey;
1105 }
1106
1107 if (!press_release)
1108 key_event |= BX_KEY_RELEASED;
1109 DEV_kbd_gen_scancode(key_event);
1110 }
1111
1112 // RFB specific functions
1113
1114 #ifdef BX_RFB_WIN32
InitWinsock()1115 bool InitWinsock()
1116 {
1117 WSADATA wsaData;
1118 if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false;
1119 return true;
1120 }
1121
StopWinsock()1122 bool StopWinsock()
1123 {
1124 WSACleanup();
1125 return true;
1126 }
1127 #endif
1128
BX_THREAD_FUNC(rfbServerThreadInit,indata)1129 BX_THREAD_FUNC(rfbServerThreadInit, indata)
1130 {
1131 SOCKET sServer;
1132 SOCKET sClient;
1133 struct sockaddr_in sai;
1134 unsigned int sai_size;
1135 int port_ok = 0;
1136 int one=1;
1137
1138 #ifdef WIN32
1139 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
1140 #endif
1141 #ifdef BX_RFB_WIN32
1142 if(!InitWinsock()) {
1143 BX_PANIC(("could not initialize winsock."));
1144 goto end_of_thread;
1145 }
1146 #endif
1147
1148 sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1149 if(sServer == (SOCKET) -1) {
1150 BX_PANIC(("could not create socket."));
1151 goto end_of_thread;
1152 }
1153 if (setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(int)) == -1) {
1154 BX_PANIC(("could not set socket option."));
1155 goto end_of_thread;
1156 }
1157
1158 for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) {
1159 sai.sin_addr.s_addr = INADDR_ANY;
1160 sai.sin_family = AF_INET;
1161 sai.sin_port = htons(rfbPort);
1162 BX_INFO (("Trying port %d", rfbPort));
1163 if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) {
1164 BX_INFO(("Could not bind socket."));
1165 continue;
1166 }
1167 if(listen(sServer, SOMAXCONN) == -1) {
1168 BX_INFO(("Could not listen on socket."));
1169 continue;
1170 }
1171 // success
1172 port_ok = 1;
1173 break;
1174 }
1175 if (!port_ok) {
1176 BX_PANIC (("RFB could not bind any port between %d and %d",
1177 BX_RFB_PORT_MIN,
1178 BX_RFB_PORT_MAX));
1179 goto end_of_thread;
1180 }
1181 BX_INFO (("listening for connections on port %i", rfbPort));
1182 sai_size = sizeof(sai);
1183 while (keep_alive) {
1184 sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size);
1185 if(sClient != INVALID_SOCKET) {
1186 HandleRfbClient(sClient);
1187 sGlobal = INVALID_SOCKET;
1188 close(sClient);
1189 } else {
1190 close(sClient);
1191 }
1192 }
1193
1194 end_of_thread:
1195 #ifdef BX_RFB_WIN32
1196 StopWinsock();
1197 #endif
1198 BX_THREAD_EXIT;
1199 }
1200
rfbStartThread()1201 void rfbStartThread()
1202 {
1203 BX_THREAD_VAR(thread_var);
1204
1205 BX_THREAD_CREATE(rfbServerThreadInit, NULL, thread_var);
1206 UNUSED(thread_var);
1207 }
1208
HandleRfbClient(SOCKET sClient)1209 void HandleRfbClient(SOCKET sClient)
1210 {
1211 char rfbName[] = "Bochs-RFB";
1212 rfbProtocolVersionMessage pv;
1213 int one = 1;
1214 U32 auth;
1215 rfbClientInitMessage cim;
1216 rfbServerInitMessage sim;
1217 bool mouse_toggle = 0;
1218 static Bit8u wheel_status = 0;
1219
1220 setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
1221 BX_INFO(("accepted client connection."));
1222 snprintf(pv, rfbProtocolVersionMessageSize + 1,
1223 rfbProtocolVersionFormat,
1224 rfbServerProtocolMajorVersion,
1225 rfbServerProtocolMinorVersion);
1226
1227 if(WriteExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
1228 BX_ERROR(("could not send protocol version."));
1229 return;
1230 }
1231 if(ReadExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
1232 BX_ERROR(("could not receive client protocol version."));
1233 return;
1234 }
1235 pv[rfbProtocolVersionMessageSize-1]=0; // Drop last character
1236 BX_INFO(("Client protocol version is '%s'", pv));
1237 // FIXME should check for version number
1238
1239 auth = htonl(rfbSecurityNone);
1240
1241 if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) {
1242 BX_ERROR(("could not send authorization method."));
1243 return;
1244 }
1245
1246 if(ReadExact(sClient, (char *)&cim, rfbClientInitMessageSize) < 0) {
1247 BX_ERROR(("could not receive client initialization message."));
1248 return;
1249 }
1250
1251 sim.framebufferWidth = htons((short)rfbWindowX);
1252 sim.framebufferHeight = htons((short)rfbWindowY);
1253 sim.serverPixelFormat = BGR233Format;
1254 sim.serverPixelFormat.redMax = htons(sim.serverPixelFormat.redMax);
1255 sim.serverPixelFormat.greenMax = htons(sim.serverPixelFormat.greenMax);
1256 sim.serverPixelFormat.blueMax = htons(sim.serverPixelFormat.blueMax);
1257 sim.nameLength = strlen(rfbName);
1258 sim.nameLength = htonl(sim.nameLength);
1259 if(WriteExact(sClient, (char *)&sim, rfbServerInitMessageSize) < 0) {
1260 BX_ERROR(("could send server initialization message."));
1261 return;
1262 }
1263 if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) {
1264 BX_ERROR (("could not send server name."));
1265 return;
1266 }
1267
1268 client_connected = 1;
1269 sGlobal = sClient;
1270 while (keep_alive) {
1271 U8 msgType;
1272 int n;
1273
1274 if ((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) {
1275 if (n == 0) {
1276 // client closed connection
1277 client_connected = 0;
1278 } else {
1279 if (errno == EINTR)
1280 continue;
1281 BX_ERROR(("error receiving data."));
1282 }
1283 return;
1284 }
1285
1286 switch (msgType) {
1287 case rfbSetPixelFormat:
1288 {
1289 rfbSetPixelFormatMessage spf;
1290 ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMessage));
1291
1292 spf.pixelFormat.trueColourFlag = (spf.pixelFormat.trueColourFlag ? 1 : 0);
1293 spf.pixelFormat.bigEndianFlag = (spf.pixelFormat.bigEndianFlag ? 1 : 0);
1294 spf.pixelFormat.redMax = ntohs(spf.pixelFormat.redMax);
1295 spf.pixelFormat.greenMax = ntohs(spf.pixelFormat.greenMax);
1296 spf.pixelFormat.blueMax = ntohs(spf.pixelFormat.blueMax);
1297
1298 rfbBGR233Format = 1;
1299 if (PF_EQ(spf.pixelFormat, RGB332Format)) {
1300 rfbBGR233Format = 0;
1301 status_leds[0] = 0x1c;
1302 status_leds[1] = 0xe0;
1303 status_leds[2] = 0xfc;
1304 status_gray_text = 0x92;
1305 } else if (!PF_EQ(spf.pixelFormat, BGR233Format)) {
1306 BX_ERROR(("client has wrong pixel format (%d %d %d %d %d %d %d %d %d %d)",
1307 spf.pixelFormat.bitsPerPixel,spf.pixelFormat.depth,spf.pixelFormat.bigEndianFlag,
1308 spf.pixelFormat.trueColourFlag,spf.pixelFormat.redMax,spf.pixelFormat.greenMax,
1309 spf.pixelFormat.blueMax,spf.pixelFormat.redShift,spf.pixelFormat.greenShift,
1310 spf.pixelFormat.blueShift));
1311 //return;
1312 }
1313 break;
1314 }
1315 case rfbFixColourMapEntries:
1316 {
1317 rfbFixColourMapEntriesMessage fcme;
1318 ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMessage));
1319 break;
1320 }
1321 case rfbSetEncodings:
1322 {
1323 rfbSetEncodingsMessage se;
1324 Bit32u i;
1325 U32 enc;
1326
1327 // free previously registered encodings
1328 if (clientEncodings != NULL) {
1329 delete [] clientEncodings;
1330 clientEncodingsCount = 0;
1331 }
1332
1333 ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMessage));
1334
1335 // Alloc new clientEncodings
1336 clientEncodingsCount = ntohs(se.numberOfEncodings);
1337 clientEncodings = new Bit32u[clientEncodingsCount];
1338
1339 for (i = 0; i < clientEncodingsCount; i++) {
1340 if ((n = ReadExact(sClient, (char *)&enc, sizeof(U32))) <= 0) {
1341 if (n == 0) {
1342 // client closed connection
1343 client_connected = 0;
1344 } else {
1345 BX_ERROR(("error receiving data."));
1346 }
1347 return;
1348 }
1349 clientEncodings[i]=ntohl(enc);
1350 }
1351
1352 // print supported encodings
1353 BX_INFO(("rfbSetEncodings : client supported encodings:"));
1354 for (i = 0; i < clientEncodingsCount; i++) {
1355 Bit32u j;
1356 bool found = 0;
1357 for (j=0; j < rfbEncodingsCount; j ++) {
1358 if (clientEncodings[i] == rfbEncodings[j].id) {
1359 BX_INFO(("%08x %s", rfbEncodings[j].id, rfbEncodings[j].name));
1360 found=1;
1361 if (clientEncodings[i] == rfbEncodingDesktopSize) {
1362 desktop_resizable = 1;
1363 }
1364 break;
1365 }
1366 }
1367 if (!found) BX_INFO(("%08x Unknown", clientEncodings[i]));
1368 }
1369 break;
1370 }
1371 case rfbFramebufferUpdateRequest:
1372 {
1373 rfbFramebufferUpdateRequestMessage fur;
1374
1375 ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMessage));
1376 if(!fur.incremental) {
1377 rfbSetUpdateRegion(0, 0, rfbWindowX, rfbWindowY);
1378 } //else {
1379 // if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x;
1380 // if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y;
1381 // if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x);
1382 // if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y);
1383 //}
1384 //rfbUpdateRegion.updated = 1;
1385 break;
1386 }
1387 case rfbKeyEvent:
1388 {
1389 rfbKeyEventMessage ke;
1390 ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMessage));
1391 ke.key = ntohl(ke.key);
1392 while (bKeyboardInUse) ;
1393
1394 if ((ke.key == XK_Control_L) || (ke.key == XK_Control_R)) {
1395 mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_CTRL, ke.downFlag);
1396 } else if (ke.key == XK_Alt_L) {
1397 mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_ALT, ke.downFlag);
1398 } else if (ke.key == XK_F10) {
1399 mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F10, ke.downFlag);
1400 } else if (ke.key == XK_F12) {
1401 mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F12, ke.downFlag);
1402 }
1403 if (mouse_toggle) {
1404 bx_gui->toggle_mouse_enable();
1405 } else {
1406 bKeyboardInUse = 1;
1407 if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
1408 rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD;
1409 rfbKeyboardEvent[rfbKeyboardEvents].key = ke.key;
1410 rfbKeyboardEvent[rfbKeyboardEvents].down = ke.downFlag;
1411 rfbKeyboardEvents++;
1412 bKeyboardInUse = 0;
1413 }
1414 break;
1415 }
1416 case rfbPointerEvent:
1417 {
1418 rfbPointerEventMessage pe;
1419 ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMessage));
1420 while (bKeyboardInUse) ;
1421
1422 if (bx_gui->mouse_toggle_check(BX_MT_MBUTTON, (pe.buttonMask & 0x02) > 0)) {
1423 bx_gui->toggle_mouse_enable();
1424 } else {
1425 bKeyboardInUse = 1;
1426 if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
1427 rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE;
1428 rfbKeyboardEvent[rfbKeyboardEvents].x = ntohs(pe.xPosition);
1429 rfbKeyboardEvent[rfbKeyboardEvents].y = ntohs(pe.yPosition);
1430 rfbKeyboardEvent[rfbKeyboardEvents].z = 0;
1431 rfbKeyboardEvent[rfbKeyboardEvents].down = (pe.buttonMask & 0x01) |
1432 ((pe.buttonMask>>1) & 0x02) |
1433 ((pe.buttonMask<<1) & 0x04);
1434 if ((pe.buttonMask & 0x18) != wheel_status) {
1435 if (pe.buttonMask & 0x10) {
1436 rfbKeyboardEvent[rfbKeyboardEvents].z = -1;
1437 } else if (pe.buttonMask & 0x08) {
1438 rfbKeyboardEvent[rfbKeyboardEvents].z = 1;
1439 }
1440 wheel_status = pe.buttonMask & 0x18;
1441 }
1442 rfbKeyboardEvents++;
1443 bKeyboardInUse = 0;
1444 }
1445 break;
1446 }
1447 case rfbClientCutText:
1448 {
1449 rfbClientCutTextMessage cct;
1450 ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMessage));
1451 break;
1452 }
1453 }
1454 }
1455 }
1456
1457 /*
1458 * ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if
1459 * those bytes have been read, 0 if the other end has closed, or -1 if an error
1460 * occurred (errno is set to ETIMEDOUT if it timed out).
1461 */
1462
ReadExact(int sock,char * buf,int len)1463 int ReadExact(int sock, char *buf, int len)
1464 {
1465 while (len > 0) {
1466 int n = recv(sock, buf, len, 0);
1467 if (n > 0) {
1468 buf += n;
1469 len -= n;
1470 } else {
1471 return n;
1472 }
1473 }
1474 return 1;
1475 }
1476
1477 /*
1478 * WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if
1479 * those bytes have been written, or -1 if an error occurred (errno is set to
1480 * ETIMEDOUT if it timed out).
1481 */
1482
WriteExact(int sock,char * buf,int len)1483 int WriteExact(int sock, char *buf, int len)
1484 {
1485 while (len > 0) {
1486 int n = send(sock, buf, len,0);
1487
1488 if (n > 0) {
1489 buf += n;
1490 len -= n;
1491 } else {
1492 if (n == 0) BX_ERROR(("WriteExact: write returned 0?"));
1493 return n;
1494 }
1495 }
1496 return 1;
1497 }
1498
DrawBitmap(int x,int y,int width,int height,char * bmap,char fgcolor,char bgcolor,bool update_client)1499 void DrawBitmap(int x, int y, int width, int height, char *bmap,
1500 char fgcolor, char bgcolor, bool update_client)
1501 {
1502 unsigned char *newBits;
1503 newBits = new unsigned char[width * height];
1504 memset(newBits, 0, (width * height));
1505 for (int i = 0; i < (width * height) / 8; i++) {
1506 newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor;
1507 newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor;
1508 newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor;
1509 newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor;
1510 newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor;
1511 newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor;
1512 newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor;
1513 newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor;
1514 }
1515 UpdateScreen(newBits, x, y, width, height, update_client);
1516 delete [] newBits;
1517 }
1518
DrawChar(int x,int y,int width,int height,int fontx,int fonty,char * bmap,char fgcolor,char bgcolor,bool gfxchar)1519 void DrawChar(int x, int y, int width, int height, int fontx, int fonty,
1520 char *bmap, char fgcolor, char bgcolor, bool gfxchar)
1521 {
1522 static unsigned char newBits[18 * 32];
1523 unsigned char mask;
1524 int bytes = width * height;
1525 bool dwidth = (width > 9);
1526 for (int i = 0; i < bytes; i += width) {
1527 mask = 0x80 >> fontx;
1528 for (int j = 0; j < width; j++) {
1529 if (mask > 0) {
1530 newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
1531 } else {
1532 if (gfxchar) {
1533 newBits[i + j] = (bmap[fonty] & 0x01) ? fgcolor : bgcolor;
1534 } else {
1535 newBits[i + j] = bgcolor;
1536 }
1537 }
1538 if (!dwidth || (j & 1)) mask >>= 1;
1539 }
1540 fonty++;
1541 }
1542 UpdateScreen(newBits, x, y, width, height, 0);
1543 }
1544
UpdateScreen(unsigned char * newBits,int x,int y,int width,int height,bool update_client)1545 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height,
1546 bool update_client)
1547 {
1548 int i, x0, y0;
1549 x0 = x;
1550 y0 = y;
1551 if ((unsigned)(x + width - 1) >= rfbWindowX) {
1552 width = rfbWindowX - x + 1;
1553 }
1554 if ((unsigned)(y + height - 1) >= rfbWindowY) {
1555 height = rfbWindowY - y + 1;
1556 }
1557 for (i = 0; i < height; i++) {
1558 memcpy(&rfbScreen[y * rfbWindowX + x0], &newBits[i * width], width);
1559 y++;
1560 }
1561 if (update_client) {
1562 if(sGlobal == INVALID_SOCKET) return;
1563 rfbFramebufferUpdateMessage fum;
1564 rfbFramebufferUpdateRectHeader furh;
1565 fum.messageType = rfbFramebufferUpdate;
1566 fum.numberOfRectangles = htons(1);
1567 WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1568 furh.r.xPosition = htons(x0);
1569 furh.r.yPosition = htons(y0);
1570 furh.r.width = htons((short)width);
1571 furh.r.height = htons((short)height);
1572 furh.r.encodingType = htonl(rfbEncodingRaw);
1573 WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1574 WriteExact(sGlobal, (char *)newBits, width * height);
1575 }
1576 }
1577
SendUpdate(int x,int y,int width,int height,Bit32u encoding)1578 void SendUpdate(int x, int y, int width, int height, Bit32u encoding)
1579 {
1580 char *newBits;
1581
1582 if(x < 0 || y < 0 || (x + width) > (int)rfbWindowX || (y + height) > (int)rfbWindowY) {
1583 BX_ERROR(("Dimensions out of bounds. x=%i y=%i w=%i h=%i", x, y, width, height));
1584 }
1585 if(sGlobal != INVALID_SOCKET) {
1586 rfbFramebufferUpdateMessage fum;
1587 rfbFramebufferUpdateRectHeader furh;
1588
1589 fum.messageType = rfbFramebufferUpdate;
1590 fum.numberOfRectangles = htons(1);
1591
1592 furh.r.xPosition = htons(x);
1593 furh.r.yPosition = htons(y);
1594 furh.r.width = htons((short)width);
1595 furh.r.height = htons((short)height);
1596 furh.r.encodingType = htonl(encoding);
1597
1598 WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1599 WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1600
1601 if (encoding == rfbEncodingRaw) {
1602 newBits = new char[width * height];
1603 for(int i = 0; i < height; i++) {
1604 memcpy(&newBits[i * width], &rfbScreen[y * rfbWindowX + x], width);
1605 y++;
1606 }
1607 WriteExact(sGlobal, (char *)newBits, width * height);
1608 delete [] newBits;
1609 }
1610 }
1611 }
1612
rfbSetUpdateRegion(unsigned x0,unsigned y0,unsigned w,unsigned h)1613 void rfbSetUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h)
1614 {
1615 rfbUpdateRegion.x = x0;
1616 rfbUpdateRegion.y = y0;
1617 rfbUpdateRegion.width = w;
1618 rfbUpdateRegion.height = h;
1619 rfbUpdateRegion.updated = ((w > 0) && (h > 0));
1620 }
1621
rfbAddUpdateRegion(unsigned x0,unsigned y0,unsigned w,unsigned h)1622 void rfbAddUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h)
1623 {
1624 unsigned x1, y1;
1625
1626 if (!rfbUpdateRegion.updated) {
1627 rfbSetUpdateRegion(x0, y0, w, h);
1628 } else {
1629 x1 = rfbUpdateRegion.x + rfbUpdateRegion.width;
1630 y1 = rfbUpdateRegion.y + rfbUpdateRegion.height;
1631 if (x0 < rfbUpdateRegion.x) {
1632 rfbUpdateRegion.x = x0;
1633 }
1634 if (y0 < rfbUpdateRegion.y) {
1635 rfbUpdateRegion.y = y0;
1636 }
1637 if ((x0 + w) > x1) {
1638 rfbUpdateRegion.width = x0 + w - rfbUpdateRegion.x;
1639 } else {
1640 rfbUpdateRegion.width= x1 - rfbUpdateRegion.x;
1641 }
1642 if ((y0 + h) > y1) {
1643 rfbUpdateRegion.height = y0 + h - rfbUpdateRegion.y;
1644 } else {
1645 rfbUpdateRegion.height = y1 - rfbUpdateRegion.y;
1646 }
1647 if ((rfbUpdateRegion.x + rfbUpdateRegion.width) > rfbWindowX) {
1648 rfbUpdateRegion.width = rfbWindowX - rfbUpdateRegion.x;
1649 }
1650 if ((rfbUpdateRegion.y + rfbUpdateRegion.height) > rfbWindowY) {
1651 rfbUpdateRegion.height = rfbWindowY - rfbUpdateRegion.y;
1652 }
1653 rfbUpdateRegion.updated = 1;
1654 }
1655 }
1656
rfbSetStatusText(int element,const char * text,bool active,Bit8u color)1657 void rfbSetStatusText(int element, const char *text, bool active, Bit8u color)
1658 {
1659 char *newBits;
1660 unsigned xleft, xsize, i, len;
1661
1662 rfbStatusitemActive[element] = active;
1663 xleft = rfbStatusitemPos[element] + 2;
1664 xsize = rfbStatusitemPos[element + 1] - xleft - 1;
1665 newBits = new char[((xsize / 8) + 1) * (rfbStatusbarY - 2)];
1666 memset(newBits, 0, ((xsize / 8) + 1) * (rfbStatusbarY - 2));
1667 for (i = 0; i < (rfbStatusbarY - 2); i++) {
1668 newBits[((xsize / 8) + 1) * i] = 0;
1669 }
1670
1671 Bit8u fgcolor = active ? headerbar_fg : status_gray_text;
1672 Bit8u bgcolor = 0;
1673 if ((element > 0) && active) {
1674 bgcolor = status_leds[color];
1675 } else {
1676 bgcolor = headerbar_bg;
1677 }
1678 DrawBitmap(xleft, rfbWindowY - rfbStatusbarY + 1, xsize, rfbStatusbarY - 2,
1679 newBits, fgcolor, bgcolor, 0);
1680
1681 delete [] newBits;
1682 len = ((element > 0) && (strlen(text) > 4)) ? 4 : strlen(text);
1683 for (i = 0; i < len; i++) {
1684 DrawChar(xleft + i * 8 + 2, rfbWindowY - rfbStatusbarY + 5, 8, 8, 0, 0,
1685 (char *) &sdl_font8x8[(unsigned) text[i]][0], fgcolor, bgcolor, 0);
1686 }
1687
1688 rfbAddUpdateRegion(xleft, rfbWindowY - rfbStatusbarY + 1, xsize, rfbStatusbarY - 2);
1689 }
1690
1691 #if BX_SHOW_IPS && defined(WIN32)
IPSTimerProc(HWND hWnd,UINT nMsg,UINT_PTR nIDEvent,DWORD dwTime)1692 VOID CALLBACK IPSTimerProc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime)
1693 {
1694 if (keep_alive) {
1695 bx_show_ips_handler();
1696 }
1697 }
1698
rfbShowIPSthread(LPVOID)1699 DWORD WINAPI rfbShowIPSthread(LPVOID)
1700 {
1701 MSG msg;
1702
1703 UINT TimerId = SetTimer(NULL, 0, 1000, &IPSTimerProc);
1704 while (keep_alive && GetMessage(&msg, NULL, 0, 0)) {
1705 DispatchMessage(&msg);
1706 }
1707 KillTimer(NULL, TimerId);
1708 return 0;
1709 }
1710 #endif
1711
1712 #endif /* if BX_WITH_RFB */
1713