- FM synthesizer now usable with MIDI output (simple piano only)
[bochs-mirror.git] / gui / rfb.cc
blobdb85ba66a067be151b523b5bf4d19ba593eeb44c
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rfb.cc,v 1.58 2008/04/07 20:20:04 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2000 Psyon.Org!
6 //
7 // Donald Becker
8 // http://www.psyon.org
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2 of the License, or (at your option) any later version.
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 // RFB still to do :
25 // - properly handle SetPixelFormat, including big/little-endian flag
26 // - depth > 8bpp support
27 // - full dimension update support (desktop size should be an option)
28 // - optional compression support
31 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
32 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
33 // is used to know when we are exporting symbols and when we are importing.
34 #define BX_PLUGGABLE
36 #include "bochs.h"
37 #include "iodev.h"
38 #if BX_WITH_RFB
40 #include "icon_bochs.h"
41 #include "font/vga.bitmap.h"
42 #if BX_WITH_SDL && !BX_PLUGINS
43 extern unsigned char sdl_font8x8[256][8];
44 #else
45 #include "sdl.h" // 8x8 font for status text
46 #endif
48 class bx_rfb_gui_c : public bx_gui_c {
49 public:
50 bx_rfb_gui_c (void) {}
51 DECLARE_GUI_VIRTUAL_METHODS()
52 DECLARE_GUI_NEW_VIRTUAL_METHODS()
53 void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp);
54 void statusbar_setitem(int element, bx_bool active);
55 #if BX_SHOW_IPS
56 void show_ips(Bit32u ips_count);
57 #endif
60 // declare one instance of the gui object and call macro to insert the
61 // plugin code
62 static bx_rfb_gui_c *theGui = NULL;
63 IMPLEMENT_GUI_PLUGIN_CODE(rfb)
65 #define LOG_THIS theGui->
67 #include "rfb.h"
69 #ifdef WIN32
71 #include <winsock.h>
72 #include <process.h>
74 #else
76 #include <sys/socket.h>
77 #include <netinet/tcp.h>
78 #include <netinet/in.h>
79 #include <unistd.h>
80 #ifndef __QNXNTO__
81 #include <sys/errno.h>
82 #else
83 #include <errno.h>
84 #endif
85 #include <pthread.h>
87 typedef int SOCKET;
88 #ifndef INVALID_SOCKET
89 #define INVALID_SOCKET -1
90 #endif
92 #endif
94 static bool keep_alive;
95 static bool client_connected;
97 #define BX_RFB_PORT_MIN 5900
98 #define BX_RFB_PORT_MAX 5949
99 static unsigned short rfbPort;
101 // Headerbar stuff
102 unsigned rfbBitmapCount = 0;
103 static struct {
104 char *bmap;
105 unsigned xdim;
106 unsigned ydim;
107 } rfbBitmaps[BX_MAX_PIXMAPS];
109 static unsigned rfbHeaderbarBitmapCount = 0;
110 struct _rfbHeaderbarBitmaps {
111 unsigned int index;
112 unsigned int xorigin;
113 unsigned int yorigin;
114 unsigned int alignment;
115 void (*f)(void);
116 } rfbHeaderbarBitmaps[BX_MAX_HEADERBAR_ENTRIES];
118 //Keyboard stuff
119 #define KEYBOARD true
120 #define MOUSE false
121 #define MAX_KEY_EVENTS 512
122 static struct {
123 bool type;
124 int key;
125 int down;
126 int x;
127 int y;
128 } rfbKeyboardEvent[MAX_KEY_EVENTS];
129 static unsigned long rfbKeyboardEvents = 0;
130 static bool bKeyboardInUse = false;
132 // Misc Stuff
133 static struct {
134 unsigned int x;
135 unsigned int y;
136 unsigned int width;
137 unsigned int height;
138 bool updated;
139 } rfbUpdateRegion;
141 #define BX_RFB_MAX_XDIM 720
142 #define BX_RFB_MAX_YDIM 480
144 static char *rfbScreen;
145 static char rfbPalette[256];
147 static unsigned rfbWindowX, rfbWindowY;
148 static unsigned rfbDimensionX, rfbDimensionY;
149 static long rfbHeaderbarY;
150 static long rfbTileX = 0;
151 static long rfbTileY = 0;
152 static unsigned long rfbCursorX = 0;
153 static unsigned long rfbCursorY = 0;
154 static unsigned long rfbOriginLeft = 0;
155 static unsigned long rfbOriginRight = 0;
156 static unsigned rfbStatusbarY = 18;
157 static unsigned rfbStatusitemPos[12] = {
158 0, 170, 210, 250, 290, 330, 370, 410, 450, 490, 530, 570
160 static bx_bool rfbStatusitemActive[12];
162 static unsigned int text_rows=25, text_cols=80;
163 static unsigned int font_height=16, font_width=8;
165 //static unsigned long ServerThread = 0;
166 //static unsigned long ServerThreadID = 0;
168 static SOCKET sGlobal;
170 static Bit32u clientEncodingsCount = 0;
171 static Bit32u *clientEncodings = NULL;
173 void CDECL ServerThreadInit(void *indata);
174 void HandleRfbClient(SOCKET sClient);
175 int ReadExact(int sock, char *buf, int len);
176 int WriteExact(int sock, char *buf, int len);
177 void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client);
178 void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color, bx_bool gfxchar);
179 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client);
180 void SendUpdate(int x, int y, int width, int height);
181 void StartThread();
182 void rfbKeyPressed(Bit32u key, int press_release);
183 void rfbMouseMove(int x, int y, int bmask);
184 void DrawColorPalette();
186 static const rfbPixelFormat BGR233Format = {
187 8, 8, 1, 1, 7, 7, 3, 0, 3, 6
190 // VNCViewer code to be replaced
191 #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))))
194 // ::SPECIFIC_INIT()
196 // Called from gui.cc, once upon program startup, to allow for the
197 // specific GUI code (X11, BeOS, ...) to be initialized.
199 // argc, argv: not used right now, but the intention is to pass native GUI
200 // specific options from the command line. (X11 options, BeOS options,...)
202 // tilewidth, tileheight: for optimization, graphics_tile_update() passes
203 // only updated regions of the screen to the gui code to be redrawn.
204 // These define the dimensions of a region (tile).
205 // headerbar_y: A headerbar (toolbar) is display on the top of the
206 // VGA window, showing floppy status, and other information. It
207 // always assumes the width of the current VGA mode width, but
208 // it's height is defined by this parameter.
210 void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y)
212 unsigned char fc, vc;
213 int i, timeout = 30;
215 put("RFB");
216 UNUSED(bochs_icon_bits);
218 // the ask menu doesn't work on the client side
219 io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
221 rfbHeaderbarY = headerbar_y;
222 rfbDimensionX = BX_RFB_MAX_XDIM;
223 rfbDimensionY = BX_RFB_MAX_YDIM;
224 rfbWindowX = rfbDimensionX;
225 rfbWindowY = rfbDimensionY + rfbHeaderbarY + rfbStatusbarY;
226 rfbTileX = tilewidth;
227 rfbTileY = tileheight;
229 for(i = 0; i < 256; i++) {
230 for(int j = 0; j < 16; j++) {
231 vc = bx_vgafont[i].data[j];
232 fc = 0;
233 for (int b = 0; b < 8; b++) {
234 fc |= (vc & 0x01) << (7 - b);
235 vc >>= 1;
237 vga_charmap[i*32+j] = fc;
241 rfbScreen = (char *)malloc(rfbWindowX * rfbWindowY);
242 memset(&rfbPalette, 0, sizeof(rfbPalette));
243 rfbPalette[7] = (char)0xAD;
244 rfbPalette[63] = (char)0xFF;
246 rfbUpdateRegion.x = rfbWindowX;
247 rfbUpdateRegion.y = rfbWindowY;
248 rfbUpdateRegion.width = 0;
249 rfbUpdateRegion.height = 0;
250 rfbUpdateRegion.updated = false;
252 clientEncodingsCount=0;
253 clientEncodings=NULL;
255 keep_alive = true;
256 client_connected = false;
257 StartThread();
259 #ifdef WIN32
260 Sleep(1000);
261 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
262 #endif
263 if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {
264 BX_ERROR(("private_colormap option ignored."));
267 // parse rfb specific options
268 if (argc > 1) {
269 for (i = 1; i < argc; i++) {
270 if (!strncmp(argv[i], "timeout=", 8)) {
271 timeout = atoi(&argv[i][8]);
272 } else {
273 BX_PANIC(("Unknown rfb option '%s'", argv[i]));
278 while ((!client_connected) && (timeout--)) {
279 #ifdef WIN32
280 Sleep(1000);
281 #else
282 sleep(1);
283 #endif
285 if (timeout < 0) BX_PANIC(("timeout! no client present"));
287 new_gfx_api = 1;
288 dialog_caps = 0;
291 void rfbSetStatusText(int element, const char *text, bx_bool active)
293 char *newBits;
294 unsigned xleft, xsize, color, i, len;
296 rfbStatusitemActive[element] = active;
297 xleft = rfbStatusitemPos[element] + 2;
298 xsize = rfbStatusitemPos[element+1] - xleft - 1;
299 newBits = (char *)malloc(((xsize / 8) + 1) * (rfbStatusbarY - 2));
300 memset(newBits, 0, ((xsize / 8) + 1) * (rfbStatusbarY - 2));
301 for (i=0; i<(rfbStatusbarY - 2); i++) {
302 newBits[((xsize / 8) + 1) * i] = 0;
304 if (element > 0) {
305 color = active?0xa0:0xf7;
306 } else {
307 color = 0xf0;
309 DrawBitmap(xleft, rfbWindowY - rfbStatusbarY + 1, xsize, rfbStatusbarY - 2, newBits, color, false);
310 free(newBits);
311 len = ((element > 0) && (strlen(text) > 4)) ? 4 : strlen(text);
312 for (i = 0; i < len; i++) {
313 DrawChar(xleft + i * 8 + 2, rfbWindowY - rfbStatusbarY + 5, 8, 8, 0,
314 (char *)&sdl_font8x8[(unsigned)text[i]][0], color, 0);
316 if (xleft < rfbUpdateRegion.x) rfbUpdateRegion.x = xleft;
317 if ((rfbWindowY - rfbStatusbarY + 1) < rfbUpdateRegion.y) rfbUpdateRegion.y = rfbWindowY - rfbStatusbarY + 1;
318 if (((xleft + xsize) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((xleft + xsize) - rfbUpdateRegion.x);
319 if (((rfbWindowY - 2) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((rfbWindowY - 2) - rfbUpdateRegion.y);
320 rfbUpdateRegion.updated = true;
323 void bx_rfb_gui_c::statusbar_setitem(int element, bx_bool active)
325 if (element < 0) {
326 for (unsigned i = 0; i < statusitem_count; i++) {
327 rfbSetStatusText(i+1, statusitem_text[i], active);
329 } else if ((unsigned)element < statusitem_count) {
330 rfbSetStatusText(element+1, statusitem_text[element], active);
334 #ifdef WIN32
335 bool InitWinsock()
337 WSADATA wsaData;
338 if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false;
339 return true;
341 #endif
343 #ifdef WIN32
344 bool StopWinsock()
346 WSACleanup();
347 return true;
349 #endif
351 void CDECL ServerThreadInit(void *indata)
353 SOCKET sServer;
354 SOCKET sClient;
355 struct sockaddr_in sai;
356 unsigned int sai_size;
357 int port_ok = 0;
358 int one=1;
360 #ifdef WIN32
361 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
362 if(!InitWinsock()) {
363 BX_PANIC(("could not initialize winsock."));
364 goto end_of_thread;
366 #endif
368 sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
369 if(sServer == -1) {
370 BX_PANIC(("could not create socket."));
371 goto end_of_thread;
373 if (setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(int)) == -1) {
374 BX_PANIC(("could not set socket option."));
375 goto end_of_thread;
378 for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) {
379 sai.sin_addr.s_addr = INADDR_ANY;
380 sai.sin_family = AF_INET;
381 sai.sin_port = htons(rfbPort);
382 BX_INFO (("Trying port %d", rfbPort));
383 if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) {
384 BX_INFO(("Could not bind socket."));
385 continue;
387 if(listen(sServer, SOMAXCONN) == -1) {
388 BX_INFO(("Could not listen on socket."));
389 continue;
391 // success
392 port_ok = 1;
393 break;
395 if (!port_ok) {
396 BX_PANIC (("RFB could not bind any port between %d and %d",
397 BX_RFB_PORT_MIN,
398 BX_RFB_PORT_MAX));
399 goto end_of_thread;
401 BX_INFO (("listening for connections on port %i", rfbPort));
402 sai_size = sizeof(sai);
403 while(keep_alive) {
404 sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size);
405 if(sClient != INVALID_SOCKET) {
406 HandleRfbClient(sClient);
407 sGlobal = INVALID_SOCKET;
408 close(sClient);
409 } else {
410 close(sClient);
414 end_of_thread:
415 #ifdef WIN32
416 StopWinsock();
417 #endif
418 return;
421 void HandleRfbClient(SOCKET sClient)
423 char rfbName[] = "Bochs-RFB";
424 rfbProtocolVersionMessage pv;
425 int one = 1;
426 U32 auth;
427 rfbClientInitMessage cim;
428 rfbServerInitMessage sim;
430 client_connected = true;
431 setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
432 BX_INFO(("accepted client connection."));
433 snprintf(pv , rfbProtocolVersionMessageSize,
434 rfbProtocolVersionFormat,
435 rfbServerProtocolMajorVersion,
436 rfbServerProtocolMinorVersion);
438 if(WriteExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
439 BX_ERROR(("could not send protocol version."));
440 return;
442 if(ReadExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
443 BX_ERROR(("could not receive client protocol version."));
444 return;
446 pv[rfbProtocolVersionMessageSize-1]=0; // Drop last character
447 BX_INFO(("Client protocol version is '%s'", pv));
448 // FIXME should check for version number
450 auth = htonl(rfbSecurityNone);
452 if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) {
453 BX_ERROR(("could not send authorization method."));
454 return;
457 if(ReadExact(sClient, (char *)&cim, rfbClientInitMessageSize) < 0) {
458 BX_ERROR(("could not receive client initialization message."));
459 return;
462 sim.framebufferWidth = htons((short)rfbWindowX);
463 sim.framebufferHeight = htons((short)rfbWindowY);
464 sim.serverPixelFormat = BGR233Format;
465 sim.serverPixelFormat.redMax = htons(sim.serverPixelFormat.redMax);
466 sim.serverPixelFormat.greenMax = htons(sim.serverPixelFormat.greenMax);
467 sim.serverPixelFormat.blueMax = htons(sim.serverPixelFormat.blueMax);
468 sim.nameLength = strlen(rfbName);
469 sim.nameLength = htonl(sim.nameLength);
470 if(WriteExact(sClient, (char *)&sim, rfbServerInitMessageSize) < 0) {
471 BX_ERROR(("could send server initialization message."));
472 return;
474 if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) {
475 BX_ERROR (("could not send server name."));
476 return;
479 sGlobal = sClient;
480 while(keep_alive) {
481 U8 msgType;
482 int n;
484 if((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) {
485 if(n == 0) {
486 BX_ERROR(("client closed connection."));
487 } else {
488 BX_ERROR(("error receiving data."));
490 return;
493 switch(msgType) {
494 case rfbSetPixelFormat:
496 rfbSetPixelFormatMessage spf;
497 ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMessage));
499 spf.pixelFormat.bitsPerPixel = spf.pixelFormat.bitsPerPixel;
500 spf.pixelFormat.depth = spf.pixelFormat.depth;
501 spf.pixelFormat.trueColourFlag = (spf.pixelFormat.trueColourFlag ? 1 : 0);
502 spf.pixelFormat.bigEndianFlag = (spf.pixelFormat.bigEndianFlag ? 1 : 0);
503 spf.pixelFormat.redMax = ntohs(spf.pixelFormat.redMax);
504 spf.pixelFormat.greenMax = ntohs(spf.pixelFormat.greenMax);
505 spf.pixelFormat.blueMax = ntohs(spf.pixelFormat.blueMax);
506 spf.pixelFormat.redShift = spf.pixelFormat.redShift;
507 spf.pixelFormat.greenShift = spf.pixelFormat.greenShift;
508 spf.pixelFormat.blueShift = spf.pixelFormat.blueShift;
510 if (!PF_EQ(spf.pixelFormat, BGR233Format)) {
511 BX_ERROR(("client has wrong pixel format (%d %d %d %d %d %d %d %d %d)",
512 spf.pixelFormat.bitsPerPixel,spf.pixelFormat.depth,spf.pixelFormat.trueColourFlag,
513 spf.pixelFormat.bigEndianFlag,spf.pixelFormat.redMax,spf.pixelFormat.greenMax,
514 spf.pixelFormat.blueMax,spf.pixelFormat.redShift,spf.pixelFormat.blueShift));
515 //return;
517 break;
519 case rfbFixColourMapEntries:
521 rfbFixColourMapEntriesMessage fcme;
522 ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMessage));
523 break;
525 case rfbSetEncodings:
527 rfbSetEncodingsMessage se;
528 Bit32u i;
529 U32 enc;
531 // free previously registered encodings
532 if (clientEncodings != NULL) {
533 delete [] clientEncodings;
534 clientEncodingsCount = 0;
537 ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMessage));
539 // Alloc new clientEncodings
540 clientEncodingsCount = ntohs(se.numberOfEncodings);
541 clientEncodings = new Bit32u[clientEncodingsCount];
543 for(i = 0; i < clientEncodingsCount; i++) {
544 if((n = ReadExact(sClient, (char *)&enc, sizeof(U32))) <= 0) {
545 if(n == 0) {
546 BX_ERROR(("client closed connection."));
547 } else {
548 BX_ERROR(("error receiving data."));
550 return;
552 clientEncodings[i]=ntohl(enc);
555 // print supported encodings
556 BX_INFO(("rfbSetEncodings : client supported encodings:"));
557 for(i = 0; i < clientEncodingsCount; i++) {
558 Bit32u j;
559 bx_bool found = 0;
560 for (j=0; j < rfbEncodingsCount; j ++) {
561 if (clientEncodings[i] == rfbEncodings[j].id) {
562 BX_INFO(("%08x %s", rfbEncodings[j].id, rfbEncodings[j].name));
563 found=1;
564 break;
567 if (!found) BX_INFO(("%08x Unknown", clientEncodings[i]));
569 break;
571 case rfbFramebufferUpdateRequest:
573 rfbFramebufferUpdateRequestMessage fur;
575 ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMessage));
576 if(!fur.incremental) {
577 rfbUpdateRegion.x = 0;
578 rfbUpdateRegion.y = 0;
579 rfbUpdateRegion.width = rfbWindowX;
580 rfbUpdateRegion.height = rfbWindowY;
581 rfbUpdateRegion.updated = true;
582 } //else {
583 // if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x;
584 // if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y;
585 // if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x);
586 // if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y);
588 //rfbUpdateRegion.updated = true;
589 break;
591 case rfbKeyEvent:
593 rfbKeyEventMessage ke;
594 ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMessage));
595 ke.key = ntohl(ke.key);
596 while(bKeyboardInUse);
597 bKeyboardInUse = true;
598 if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
599 rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD;
600 rfbKeyboardEvent[rfbKeyboardEvents].key = ke.key;
601 rfbKeyboardEvent[rfbKeyboardEvents].down = ke.downFlag;
602 rfbKeyboardEvents++;
603 bKeyboardInUse = false;
604 break;
606 case rfbPointerEvent:
608 rfbPointerEventMessage pe;
609 ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMessage));
610 while(bKeyboardInUse);
611 bKeyboardInUse = true;
612 if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
613 rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE;
614 rfbKeyboardEvent[rfbKeyboardEvents].x = ntohs(pe.xPosition);
615 rfbKeyboardEvent[rfbKeyboardEvents].y = ntohs(pe.yPosition);
616 rfbKeyboardEvent[rfbKeyboardEvents].down = (pe.buttonMask & 0x01)
617 | ((pe.buttonMask>>1) & 0x02)
618 | ((pe.buttonMask<<1) & 0x04);
619 rfbKeyboardEvents++;
620 bKeyboardInUse = false;
621 break;
623 case rfbClientCutText:
625 rfbClientCutTextMessage cct;
626 ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMessage));
627 break;
632 // ::HANDLE_EVENTS()
634 // Called periodically (vga_update_interval in .bochsrc) so the
635 // the gui code can poll for keyboard, mouse, and other
636 // relevant events.
638 void bx_rfb_gui_c::handle_events(void)
640 unsigned int i = 0;
641 while(bKeyboardInUse);
642 bKeyboardInUse = true;
643 if(rfbKeyboardEvents > 0) {
644 for(i = 0; i < rfbKeyboardEvents; i++) {
645 if(rfbKeyboardEvent[i].type == KEYBOARD) {
646 rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down);
647 } else { //type == MOUSE;
648 rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].down);
651 rfbKeyboardEvents = 0;
653 bKeyboardInUse = false;
655 if(rfbUpdateRegion.updated) {
656 SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width, rfbUpdateRegion.height);
657 rfbUpdateRegion.x = rfbWindowX;
658 rfbUpdateRegion.y = rfbWindowY;
659 rfbUpdateRegion.width = 0;
660 rfbUpdateRegion.height = 0;
662 rfbUpdateRegion.updated = false;
665 // ::FLUSH()
667 // Called periodically, requesting that the gui code flush all pending
668 // screen update requests.
670 void bx_rfb_gui_c::flush(void)
674 // ::CLEAR_SCREEN()
676 // Called to request that the VGA region is cleared. Don't
677 // clear the area that defines the headerbar.
678 void bx_rfb_gui_c::clear_screen(void)
680 memset(&rfbScreen[rfbWindowX * rfbHeaderbarY], 0, rfbWindowX * rfbDimensionY);
683 // ::TEXT_UPDATE()
685 // Called in a VGA text mode, to update the screen with
686 // new content.
688 // old_text: array of character/attributes making up the contents
689 // of the screen from the last call. See below
690 // new_text: array of character/attributes making up the current
691 // contents, which should now be displayed. See below
693 // format of old_text & new_text: each is tm_info.line_offset*text_rows
694 // bytes long. Each character consists of 2 bytes. The first by is
695 // the character value, the second is the attribute byte.
697 // cursor_x: new x location of cursor
698 // cursor_y: new y location of cursor
699 // tm_info: this structure contains information for additional
700 // features in text mode (cursor shape, line offset,...)
702 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)
704 Bit8u *old_line, *new_line;
705 Bit8u cAttr, cChar;
706 unsigned int curs, hchars, offset, rows, x, y, xc, yc;
707 bx_bool force_update=0, gfxchar, blink_state, blink_mode;
709 blink_mode = (tm_info.blink_flags & BX_TEXT_BLINK_MODE) > 0;
710 blink_state = (tm_info.blink_flags & BX_TEXT_BLINK_STATE) > 0;
711 if (blink_mode) {
712 if (tm_info.blink_flags & BX_TEXT_BLINK_TOGGLE)
713 force_update = 1;
715 if(charmap_updated) {
716 force_update = 1;
717 charmap_updated = 0;
720 // first invalidate character at previous and new cursor location
721 if ((rfbCursorY < text_rows) && (rfbCursorX < text_cols)) {
722 curs = rfbCursorY * tm_info.line_offset + rfbCursorX * 2;
723 old_text[curs] = ~new_text[curs];
725 if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
726 (cursor_y < text_rows) && (cursor_x < text_cols)) {
727 curs = cursor_y * tm_info.line_offset + cursor_x * 2;
728 old_text[curs] = ~new_text[curs];
729 } else {
730 curs = 0xffff;
733 rows = text_rows;
734 y = 0;
735 do {
736 hchars = text_cols;
737 new_line = new_text;
738 old_line = old_text;
739 offset = y * tm_info.line_offset;
740 yc = y * font_height + rfbHeaderbarY;
741 x = 0;
742 do {
743 if (force_update || (old_text[0] != new_text[0])
744 || (old_text[1] != new_text[1])) {
745 cChar = new_text[0];
746 if (blink_mode) {
747 cAttr = new_text[1] & 0x7F;
748 if (!blink_state && (new_text[1] & 0x80))
749 cAttr = (cAttr & 0x70) | (cAttr >> 4);
750 } else {
751 cAttr = new_text[1];
753 gfxchar = tm_info.line_graphics && ((cChar & 0xE0) == 0xC0);
754 xc = x * font_width;
755 DrawChar(xc, yc, font_width, font_height, 0, (char *)&vga_charmap[cChar<<5], cAttr, gfxchar);
756 if(yc < rfbUpdateRegion.y) rfbUpdateRegion.y = yc;
757 if((yc + font_height - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = (yc + font_height - rfbUpdateRegion.y);
758 if(xc < rfbUpdateRegion.x) rfbUpdateRegion.x = xc;
759 if((xc + font_width - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = (xc + font_width - rfbUpdateRegion.x);
760 rfbUpdateRegion.updated = true;
761 if (offset == curs) {
762 cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
763 DrawChar(xc, yc + tm_info.cs_start, font_width, tm_info.cs_end - tm_info.cs_start + 1,
764 tm_info.cs_start, (char *)&vga_charmap[cChar<<5], cAttr, gfxchar);
767 x++;
768 new_text+=2;
769 old_text+=2;
770 offset+=2;
771 } while (--hchars);
772 y++;
773 new_text = new_line + tm_info.line_offset;
774 old_text = old_line + tm_info.line_offset;
775 } while (--rows);
777 rfbCursorX = cursor_x;
778 rfbCursorY = cursor_y;
781 int bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
783 return 0;
786 int bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
788 return 0;
791 // ::PALETTE_CHANGE()
793 // Allocate a color in the native GUI, for this color, and put
794 // it in the colormap location 'index'.
795 // returns: 0=no screen update needed (color map change has direct effect)
796 // 1=screen updated needed (redraw using current colormap)
798 bx_bool bx_rfb_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
800 rfbPalette[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6);
801 return(1);
804 // ::GRAPHICS_TILE_UPDATE()
806 // Called to request that a tile of graphics be drawn to the
807 // screen, since info in this region has changed.
809 // tile: array of 8bit values representing a block of pixels with
810 // dimension equal to the 'tilewidth' & 'tileheight' parameters to
811 // ::specific_init(). Each value specifies an index into the
812 // array of colors you allocated for ::palette_change()
813 // x0: x origin of tile
814 // y0: y origin of tile
816 // note: origin of tile and of window based on (0,0) being in the upper
817 // left of the window.
818 void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
820 UpdateScreen(tile, x0, y0 + rfbHeaderbarY, rfbTileX, rfbTileY, false);
821 if(x0 < rfbUpdateRegion.x) rfbUpdateRegion.x = x0;
822 if((y0 + rfbHeaderbarY) < rfbUpdateRegion.y) rfbUpdateRegion.y = y0 + rfbHeaderbarY;
823 if(((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y);
824 if(((x0 + rfbTileX) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((x0 + rfbTileX) - rfbUpdateRegion.x);
825 rfbUpdateRegion.updated = true;
828 bx_svga_tileinfo_t *bx_rfb_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info)
830 if (!info) {
831 info = (bx_svga_tileinfo_t *)malloc(sizeof(bx_svga_tileinfo_t));
832 if (!info) {
833 return NULL;
837 info->bpp = 8;
838 info->pitch = rfbWindowX;
839 info->red_shift = 3;
840 info->green_shift = 6;
841 info->blue_shift = 8;
842 info->red_mask = 0x07;
843 info->green_mask = 0x38;
844 info->blue_mask = 0xc0;
845 info->is_indexed = 0;
846 info->is_little_endian = 1;
848 return info;
851 Bit8u *bx_rfb_gui_c::graphics_tile_get(unsigned x0, unsigned y0,
852 unsigned *w, unsigned *h)
854 if (x0+rfbTileX > rfbDimensionX) {
855 *w = rfbDimensionX - x0;
857 else {
858 *w = rfbTileX;
861 if (y0+rfbTileY > rfbDimensionY) {
862 *h = rfbDimensionY - y0;
864 else {
865 *h = rfbTileY;
868 return (Bit8u *)rfbScreen + (rfbHeaderbarY + y0) * rfbWindowX + x0;
871 void bx_rfb_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,
872 unsigned w, unsigned h)
874 if(x0 < rfbUpdateRegion.x) rfbUpdateRegion.x = x0;
875 if((y0 + rfbHeaderbarY) < rfbUpdateRegion.y) rfbUpdateRegion.y = y0 + rfbHeaderbarY;
876 if(((y0 + rfbHeaderbarY + h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((y0 + rfbHeaderbarY + h) - rfbUpdateRegion.y);
877 if(((x0 + w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((x0 + h) - rfbUpdateRegion.x);
878 rfbUpdateRegion.updated = true;
882 // ::DIMENSION_UPDATE()
884 // Called when the VGA mode changes it's X,Y dimensions.
885 // Resize the window to this size, but you need to add on
886 // the height of the headerbar to the Y value.
888 // x: new VGA x size
889 // y: new VGA y size (add headerbar_y parameter from ::specific_init().
890 // fheight: new VGA character height in text mode
891 // fwidth : new VGA character width in text mode
892 // bpp : bits per pixel in graphics mode
894 void bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
896 if (bpp > 8) {
897 BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
899 if (fheight > 0) {
900 font_height = fheight;
901 font_width = fwidth;
902 text_cols = x / fwidth;
903 text_rows = y / fheight;
905 if ((x > BX_RFB_MAX_XDIM) || (y > BX_RFB_MAX_YDIM)) {
906 BX_PANIC(("dimension_update(): RFB doesn't support graphics mode %dx%d", x, y));
907 } else if ((x != rfbDimensionX) || (x != rfbDimensionY)) {
908 clear_screen();
909 SendUpdate(0, rfbHeaderbarY, rfbDimensionX, rfbDimensionY);
910 rfbDimensionX = x;
911 rfbDimensionY = y;
916 // ::CREATE_BITMAP()
918 // Create a monochrome bitmap of size 'xdim' by 'ydim', which will
919 // be drawn in the headerbar. Return an integer ID to the bitmap,
920 // with which the bitmap can be referenced later.
922 // bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
923 // bit0 is the left most pixel, bit7 is the right most pixel.
924 // xdim: x dimension of bitmap
925 // ydim: y dimension of bitmap
927 unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
929 if(rfbBitmapCount >= BX_MAX_PIXMAPS) {
930 BX_ERROR(("too many pixmaps."));
931 return 0;
933 rfbBitmaps[rfbBitmapCount].bmap = (char *)malloc((xdim * ydim) / 8);
934 rfbBitmaps[rfbBitmapCount].xdim = xdim;
935 rfbBitmaps[rfbBitmapCount].ydim = ydim;
936 memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8);
938 rfbBitmapCount++;
939 return(rfbBitmapCount - 1);
943 // ::HEADERBAR_BITMAP()
945 // Called to install a bitmap in the bochs headerbar (toolbar).
947 // bmap_id: will correspond to an ID returned from
948 // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
949 // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
950 // available leftmost or rightmost space.
951 // alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
952 // meaning install the bitmap in the next
953 // available leftmost or rightmost space.
954 // f: a 'C' function pointer to callback when the mouse is clicked in
955 // the boundaries of this bitmap.
957 unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
959 int hb_index;
961 if((rfbHeaderbarBitmapCount + 1) > BX_MAX_HEADERBAR_ENTRIES) {
962 return 0;
965 rfbHeaderbarBitmapCount++;
966 hb_index = rfbHeaderbarBitmapCount - 1;
967 rfbHeaderbarBitmaps[hb_index].index = bmap_id;
968 rfbHeaderbarBitmaps[hb_index].alignment = alignment;
969 rfbHeaderbarBitmaps[hb_index].f = f;
970 if (alignment == BX_GRAVITY_LEFT) {
971 rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginLeft;
972 rfbHeaderbarBitmaps[hb_index].yorigin = 0;
973 rfbOriginLeft += rfbBitmaps[bmap_id].xdim;
974 } else { // BX_GRAVITY_RIGHT
975 rfbOriginRight += rfbBitmaps[bmap_id].xdim;
976 rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginRight;
977 rfbHeaderbarBitmaps[hb_index].yorigin = 0;
979 return hb_index;
983 // ::SHOW_HEADERBAR()
985 // Show (redraw) the current headerbar, which is composed of
986 // currently installed bitmaps.
988 void bx_rfb_gui_c::show_headerbar(void)
990 char *newBits, value;
991 unsigned int i, xorigin, addr;
993 newBits = (char *)malloc(rfbWindowX * rfbHeaderbarY);
994 memset(newBits, 0, (rfbWindowX * rfbHeaderbarY));
995 DrawBitmap(0, 0, rfbWindowX, rfbHeaderbarY, newBits, (char)0xf0, false);
996 for(i = 0; i < rfbHeaderbarBitmapCount; i++) {
997 if(rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT) {
998 xorigin = rfbHeaderbarBitmaps[i].xorigin;
999 } else {
1000 xorigin = rfbWindowX - rfbHeaderbarBitmaps[i].xorigin;
1002 DrawBitmap(xorigin, 0, rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].ydim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].bmap, (char)0xf0, false);
1004 free(newBits);
1005 newBits = (char *)malloc(rfbWindowX * rfbStatusbarY / 8);
1006 memset(newBits, 0, (rfbWindowX * rfbStatusbarY / 8));
1007 for (i = 1; i < 12; i++) {
1008 addr = rfbStatusitemPos[i] / 8;
1009 value = 1 << (rfbStatusitemPos[i] % 8);
1010 for (unsigned j=1; j<rfbStatusbarY; j++) {
1011 newBits[(rfbWindowX * j / 8) + addr] = value;
1014 DrawBitmap(0, rfbWindowY - rfbStatusbarY, rfbWindowX, rfbStatusbarY, newBits, (char)0xf0, false);
1015 free(newBits);
1016 for (i = 1; i <= statusitem_count; i++) {
1017 rfbSetStatusText(i, statusitem_text[i-1], rfbStatusitemActive[i]);
1022 // ::REPLACE_BITMAP()
1024 // Replace the bitmap installed in the headerbar ID slot 'hbar_id',
1025 // with the one specified by 'bmap_id'. 'bmap_id' will have
1026 // been generated by ::create_bitmap(). The old and new bitmap
1027 // must be of the same size. This allows the bitmap the user
1028 // sees to change, when some action occurs. For example when
1029 // the user presses on the floppy icon, it then displays
1030 // the ejected status.
1032 // hbar_id: headerbar slot ID
1033 // bmap_id: bitmap ID
1035 void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
1037 unsigned int xorigin;
1039 if (bmap_id == rfbHeaderbarBitmaps[hbar_id].index) return;
1040 rfbHeaderbarBitmaps[hbar_id].index = bmap_id;
1041 if (rfbHeaderbarBitmaps[hbar_id].alignment == BX_GRAVITY_LEFT) {
1042 xorigin = rfbHeaderbarBitmaps[hbar_id].xorigin;
1043 } else {
1044 xorigin = rfbWindowX - rfbHeaderbarBitmaps[hbar_id].xorigin;
1046 DrawBitmap(xorigin, 0, rfbBitmaps[rfbHeaderbarBitmaps[hbar_id].index].xdim,
1047 rfbBitmaps[rfbHeaderbarBitmaps[hbar_id].index].ydim,
1048 rfbBitmaps[rfbHeaderbarBitmaps[hbar_id].index].bmap, (char)0xf0, true);
1052 // ::EXIT()
1054 // Called before bochs terminates, to allow for a graceful
1055 // exit from the native GUI mechanism.
1056 void bx_rfb_gui_c::exit(void)
1058 unsigned int i;
1059 keep_alive = false;
1060 #ifdef WIN32
1061 StopWinsock();
1062 #endif
1063 free(rfbScreen);
1064 for(i = 0; i < rfbBitmapCount; i++) {
1065 free(rfbBitmaps[i].bmap);
1068 // Clear supported encodings
1069 if (clientEncodings != NULL) {
1070 delete [] clientEncodings;
1071 clientEncodingsCount = 0;
1074 BX_DEBUG(("bx_rfb_gui_c::exit()"));
1078 * ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if
1079 * those bytes have been read, 0 if the other end has closed, or -1 if an error
1080 * occurred (errno is set to ETIMEDOUT if it timed out).
1083 int ReadExact(int sock, char *buf, int len)
1085 int n;
1087 while (len > 0) {
1088 n = recv(sock, buf, len, 0);
1089 if (n > 0) {
1090 buf += n;
1091 len -= n;
1092 } else {
1093 return n;
1096 return 1;
1100 * WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if
1101 * those bytes have been written, or -1 if an error occurred (errno is set to
1102 * ETIMEDOUT if it timed out).
1105 int WriteExact(int sock, char *buf, int len)
1107 int n;
1109 while (len > 0) {
1110 n = send(sock, buf, len,0);
1112 if (n > 0) {
1113 buf += n;
1114 len -= n;
1115 } else if (n == 0) {
1116 BX_ERROR(("WriteExact: write returned 0?"));
1117 return n;
1118 } else {
1119 return n;
1122 return 1;
1125 void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client)
1127 int i;
1128 unsigned char *newBits;
1129 char fgcolor, bgcolor;
1130 char vgaPalette[] = {(char)0x00, //Black
1131 (char)0x01, //Dark Blue
1132 (char)0x02, //Dark Green
1133 (char)0x03, //Dark Cyan
1134 (char)0x04, //Dark Red
1135 (char)0x05, //Dark Magenta
1136 (char)0x06, //Brown
1137 (char)0x07, //Light Gray
1138 (char)0x38, //Dark Gray
1139 (char)0x09, //Light Blue
1140 (char)0x12, //Green
1141 (char)0x1B, //Cyan
1142 (char)0x24, //Light Red
1143 (char)0x2D, //Magenta
1144 (char)0x36, //Yellow
1145 (char)0x3F //White
1148 bgcolor = vgaPalette[(color >> 4) & 0xF];
1149 fgcolor = vgaPalette[color & 0xF];
1150 newBits = (unsigned char *)malloc(width * height);
1151 memset(newBits, 0, (width * height));
1152 for(i = 0; i < (width * height) / 8; i++) {
1153 newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor;
1154 newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor;
1155 newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor;
1156 newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor;
1157 newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor;
1158 newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor;
1159 newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor;
1160 newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor;
1162 UpdateScreen(newBits, x, y, width, height, update_client);
1163 //DrawColorPalette();
1164 free(newBits);
1167 void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color, bx_bool gfxchar)
1169 static unsigned char newBits[9 * 32];
1170 unsigned char mask;
1171 int bytes = width * height;
1172 char fgcolor, bgcolor;
1173 char vgaPalette[] = {(char)0x00, //Black
1174 (char)0x01, //Dark Blue
1175 (char)0x02, //Dark Green
1176 (char)0x03, //Dark Cyan
1177 (char)0x04, //Dark Red
1178 (char)0x05, //Dark Magenta
1179 (char)0x06, //Brown
1180 (char)0x07, //Light Gray
1181 (char)0x38, //Dark Gray
1182 (char)0x09, //Light Blue
1183 (char)0x12, //Green
1184 (char)0x1B, //Cyan
1185 (char)0x24, //Light Red
1186 (char)0x2D, //Magenta
1187 (char)0x36, //Yellow
1188 (char)0x3F //White
1191 bgcolor = vgaPalette[(color >> 4) & 0xF];
1192 fgcolor = vgaPalette[color & 0xF];
1194 for(int i = 0; i < bytes; i+=width) {
1195 mask = 0x80;
1196 for(int j = 0; j < width; j++) {
1197 if (mask > 0) {
1198 newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
1199 } else {
1200 if (gfxchar) {
1201 newBits[i + j] = (bmap[fonty] & 0x01) ? fgcolor : bgcolor;
1202 } else {
1203 newBits[i + j] = bgcolor;
1206 mask >>= 1;
1208 fonty++;
1210 UpdateScreen(newBits, x, y, width, height, false);
1211 //DrawColorPalette();
1214 void DrawColorPalette()
1216 unsigned char bits[100];
1217 int x = 0, y = 0, c;
1218 for(c = 0; c < 256; c++) {
1219 memset(&bits, rfbPalette[c], 100);
1220 UpdateScreen(bits, x, y, 10, 10, false);
1221 x += 10;
1222 if(x > 70) {
1223 y += 10;
1224 x = 0;
1229 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client)
1231 int i, c;
1232 for(i = 0; i < height; i++) {
1233 for(c = 0; c < width; c++) {
1234 newBits[(i * width) + c] = rfbPalette[newBits[(i * width) + c]];
1236 memcpy(&rfbScreen[y * rfbWindowX + x], &newBits[i * width], width);
1237 y++;
1239 if(update_client) {
1240 if(sGlobal == INVALID_SOCKET) return;
1241 rfbFramebufferUpdateMessage fum;
1242 rfbFramebufferUpdateRectHeader furh;
1243 fum.messageType = rfbFramebufferUpdate;
1244 fum.numberOfRectangles = htons(1);
1245 WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1246 furh.r.xPosition = htons(x);
1247 furh.r.yPosition = htons((y - i));
1248 furh.r.width = htons((short)width);
1249 furh.r.height = htons((short)height);
1250 furh.r.encodingType = htonl(rfbEncodingRaw);
1251 WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1252 WriteExact(sGlobal, (char *)newBits, width * height);
1256 void SendUpdate(int x, int y, int width, int height)
1258 char *newBits;
1259 int i;
1261 if(x < 0 || y < 0 || (x + width) > (int)rfbWindowX || (y + height) > (int)rfbWindowY) {
1262 BX_ERROR(("Dimensions out of bounds. x=%i y=%i w=%i h=%i", x, y, width, height));
1264 if(sGlobal != INVALID_SOCKET) {
1265 rfbFramebufferUpdateMessage fum;
1266 rfbFramebufferUpdateRectHeader furh;
1268 fum.messageType = rfbFramebufferUpdate;
1269 fum.numberOfRectangles = htons(1);
1271 furh.r.xPosition = htons(x);
1272 furh.r.yPosition = htons(y);
1273 furh.r.width = htons((short)width);
1274 furh.r.height = htons((short)height);
1275 furh.r.encodingType = htonl(rfbEncodingRaw);
1277 newBits = (char *)malloc(width * height);
1278 for(i = 0; i < height; i++) {
1279 memcpy(&newBits[i * width], &rfbScreen[y * rfbWindowX + x], width);
1280 y++;
1283 WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1284 WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1285 WriteExact(sGlobal, (char *)newBits, width * height);
1287 free(newBits);
1291 void StartThread()
1293 #ifdef WIN32
1294 _beginthread(ServerThreadInit, 0, NULL);
1295 #else
1296 pthread_t thread;
1297 pthread_create(&thread, NULL, (void *(*)(void *))&ServerThreadInit, NULL);
1298 #endif
1301 /***********************/
1302 /* Keyboard Definitons */
1303 /* And */
1304 /* Functions */
1305 /***********************/
1307 #define XK_space 0x020
1308 #define XK_asciitilde 0x07e
1310 #define XK_dead_grave 0xFE50
1311 #define XK_dead_acute 0xFE51
1312 #define XK_dead_circumflex 0xFE52
1313 #define XK_dead_tilde 0xFE53
1315 #define XK_BackSpace 0xFF08
1316 #define XK_Tab 0xFF09
1317 #define XK_Linefeed 0xFF0A
1318 #define XK_Clear 0xFF0B
1319 #define XK_Return 0xFF0D
1320 #define XK_Pause 0xFF13
1321 #define XK_Scroll_Lock 0xFF14
1322 #define XK_Sys_Req 0xFF15
1323 #define XK_Escape 0xFF1B
1325 #define XK_Delete 0xFFFF
1327 #define XK_Home 0xFF50
1328 #define XK_Left 0xFF51
1329 #define XK_Up 0xFF52
1330 #define XK_Right 0xFF53
1331 #define XK_Down 0xFF54
1332 #define XK_Page_Up 0xFF55
1333 #define XK_Page_Down 0xFF56
1334 #define XK_End 0xFF57
1335 #define XK_Begin 0xFF58
1337 #define XK_Select 0xFF60
1338 #define XK_Print 0xFF61
1339 #define XK_Execute 0xFF62
1340 #define XK_Insert 0xFF63
1342 #define XK_Cancel 0xFF69
1343 #define XK_Help 0xFF6A
1344 #define XK_Break 0xFF6B
1345 #define XK_Num_Lock 0xFF7F
1347 #define XK_KP_Space 0xFF80
1348 #define XK_KP_Tab 0xFF89
1349 #define XK_KP_Enter 0xFF8D
1351 #define XK_KP_Home 0xFF95
1352 #define XK_KP_Left 0xFF96
1353 #define XK_KP_Up 0xFF97
1354 #define XK_KP_Right 0xFF98
1355 #define XK_KP_Down 0xFF99
1356 #define XK_KP_Prior 0xFF9A
1357 #define XK_KP_Page_Up 0xFF9A
1358 #define XK_KP_Next 0xFF9B
1359 #define XK_KP_Page_Down 0xFF9B
1360 #define XK_KP_End 0xFF9C
1361 #define XK_KP_Begin 0xFF9D
1362 #define XK_KP_Insert 0xFF9E
1363 #define XK_KP_Delete 0xFF9F
1364 #define XK_KP_Equal 0xFFBD
1365 #define XK_KP_Multiply 0xFFAA
1366 #define XK_KP_Add 0xFFAB
1367 #define XK_KP_Separator 0xFFAC
1368 #define XK_KP_Subtract 0xFFAD
1369 #define XK_KP_Decimal 0xFFAE
1370 #define XK_KP_Divide 0xFFAF
1372 #define XK_KP_F1 0xFF91
1373 #define XK_KP_F2 0xFF92
1374 #define XK_KP_F3 0xFF93
1375 #define XK_KP_F4 0xFF94
1377 #define XK_KP_0 0xFFB0
1378 #define XK_KP_1 0xFFB1
1379 #define XK_KP_2 0xFFB2
1380 #define XK_KP_3 0xFFB3
1381 #define XK_KP_4 0xFFB4
1382 #define XK_KP_5 0xFFB5
1383 #define XK_KP_6 0xFFB6
1384 #define XK_KP_7 0xFFB7
1385 #define XK_KP_8 0xFFB8
1386 #define XK_KP_9 0xFFB9
1388 #define XK_F1 0xFFBE
1389 #define XK_F2 0xFFBF
1390 #define XK_F3 0xFFC0
1391 #define XK_F4 0xFFC1
1392 #define XK_F5 0xFFC2
1393 #define XK_F6 0xFFC3
1394 #define XK_F7 0xFFC4
1395 #define XK_F8 0xFFC5
1396 #define XK_F9 0xFFC6
1397 #define XK_F10 0xFFC7
1398 #define XK_F11 0xFFC8
1399 #define XK_F12 0xFFC9
1400 #define XK_F13 0xFFCA
1401 #define XK_F14 0xFFCB
1402 #define XK_F15 0xFFCC
1403 #define XK_F16 0xFFCD
1404 #define XK_F17 0xFFCE
1405 #define XK_F18 0xFFCF
1406 #define XK_F19 0xFFD0
1407 #define XK_F20 0xFFD1
1408 #define XK_F21 0xFFD2
1409 #define XK_F22 0xFFD3
1410 #define XK_F23 0xFFD4
1411 #define XK_F24 0xFFD5
1414 #define XK_Shift_L 0xFFE1
1415 #define XK_Shift_R 0xFFE2
1416 #define XK_Control_L 0xFFE3
1417 #define XK_Control_R 0xFFE4
1418 #define XK_Caps_Lock 0xFFE5
1419 #define XK_Shift_Lock 0xFFE6
1420 #define XK_Meta_L 0xFFE7
1421 #define XK_Meta_R 0xFFE8
1422 #define XK_Alt_L 0xFFE9
1423 #define XK_Alt_R 0xFFEA
1425 Bit32u rfb_ascii_to_key_event[0x5f] = {
1426 // !"#$%&'
1427 BX_KEY_SPACE,
1428 BX_KEY_1,
1429 BX_KEY_SINGLE_QUOTE,
1430 BX_KEY_3,
1431 BX_KEY_4,
1432 BX_KEY_5,
1433 BX_KEY_7,
1434 BX_KEY_SINGLE_QUOTE,
1436 // ()*+,-./
1437 BX_KEY_9,
1438 BX_KEY_0,
1439 BX_KEY_8,
1440 BX_KEY_EQUALS,
1441 BX_KEY_COMMA,
1442 BX_KEY_MINUS,
1443 BX_KEY_PERIOD,
1444 BX_KEY_SLASH,
1446 // 01234567
1447 BX_KEY_0,
1448 BX_KEY_1,
1449 BX_KEY_2,
1450 BX_KEY_3,
1451 BX_KEY_4,
1452 BX_KEY_5,
1453 BX_KEY_6,
1454 BX_KEY_7,
1456 // 89:;<=>?
1457 BX_KEY_8,
1458 BX_KEY_9,
1459 BX_KEY_SEMICOLON,
1460 BX_KEY_SEMICOLON,
1461 BX_KEY_COMMA,
1462 BX_KEY_EQUALS,
1463 BX_KEY_PERIOD,
1464 BX_KEY_SLASH,
1466 // @ABCDEFG
1467 BX_KEY_2,
1468 BX_KEY_A,
1469 BX_KEY_B,
1470 BX_KEY_C,
1471 BX_KEY_D,
1472 BX_KEY_E,
1473 BX_KEY_F,
1474 BX_KEY_G,
1477 // HIJKLMNO
1478 BX_KEY_H,
1479 BX_KEY_I,
1480 BX_KEY_J,
1481 BX_KEY_K,
1482 BX_KEY_L,
1483 BX_KEY_M,
1484 BX_KEY_N,
1485 BX_KEY_O,
1488 // PQRSTUVW
1489 BX_KEY_P,
1490 BX_KEY_Q,
1491 BX_KEY_R,
1492 BX_KEY_S,
1493 BX_KEY_T,
1494 BX_KEY_U,
1495 BX_KEY_V,
1496 BX_KEY_W,
1498 // XYZ[\]^_
1499 BX_KEY_X,
1500 BX_KEY_Y,
1501 BX_KEY_Z,
1502 BX_KEY_LEFT_BRACKET,
1503 BX_KEY_BACKSLASH,
1504 BX_KEY_RIGHT_BRACKET,
1505 BX_KEY_6,
1506 BX_KEY_MINUS,
1508 // `abcdefg
1509 BX_KEY_GRAVE,
1510 BX_KEY_A,
1511 BX_KEY_B,
1512 BX_KEY_C,
1513 BX_KEY_D,
1514 BX_KEY_E,
1515 BX_KEY_F,
1516 BX_KEY_G,
1518 // hijklmno
1519 BX_KEY_H,
1520 BX_KEY_I,
1521 BX_KEY_J,
1522 BX_KEY_K,
1523 BX_KEY_L,
1524 BX_KEY_M,
1525 BX_KEY_N,
1526 BX_KEY_O,
1528 // pqrstuvw
1529 BX_KEY_P,
1530 BX_KEY_Q,
1531 BX_KEY_R,
1532 BX_KEY_S,
1533 BX_KEY_T,
1534 BX_KEY_U,
1535 BX_KEY_V,
1536 BX_KEY_W,
1538 // xyz{|}~
1539 BX_KEY_X,
1540 BX_KEY_Y,
1541 BX_KEY_Z,
1542 BX_KEY_LEFT_BRACKET,
1543 BX_KEY_BACKSLASH,
1544 BX_KEY_RIGHT_BRACKET,
1545 BX_KEY_GRAVE
1548 void rfbKeyPressed(Bit32u key, int press_release)
1550 Bit32u key_event;
1552 if((key >= XK_space) && (key <= XK_asciitilde)) {
1553 key_event = rfb_ascii_to_key_event[key - XK_space];
1554 } else {
1555 switch (key) {
1556 case XK_KP_1:
1557 #ifdef XK_KP_End
1558 case XK_KP_End:
1559 #endif
1560 key_event = BX_KEY_KP_END; break;
1562 case XK_KP_2:
1563 #ifdef XK_KP_Down
1564 case XK_KP_Down:
1565 #endif
1566 key_event = BX_KEY_KP_DOWN; break;
1568 case XK_KP_3:
1569 #ifdef XK_KP_Page_Down
1570 case XK_KP_Page_Down:
1571 #endif
1572 key_event = BX_KEY_KP_PAGE_DOWN; break;
1574 case XK_KP_4:
1575 #ifdef XK_KP_Left
1576 case XK_KP_Left:
1577 #endif
1578 key_event = BX_KEY_KP_LEFT; break;
1580 case XK_KP_5:
1581 #ifdef XK_KP_Begin
1582 case XK_KP_Begin:
1583 #endif
1584 key_event = BX_KEY_KP_5; break;
1586 case XK_KP_6:
1587 #ifdef XK_KP_Right
1588 case XK_KP_Right:
1589 #endif
1590 key_event = BX_KEY_KP_RIGHT; break;
1592 case XK_KP_7:
1593 #ifdef XK_KP_Home
1594 case XK_KP_Home:
1595 #endif
1596 key_event = BX_KEY_KP_HOME; break;
1598 case XK_KP_8:
1599 #ifdef XK_KP_Up
1600 case XK_KP_Up:
1601 #endif
1602 key_event = BX_KEY_KP_UP; break;
1604 case XK_KP_9:
1605 #ifdef XK_KP_Page_Up
1606 case XK_KP_Page_Up:
1607 #endif
1608 key_event = BX_KEY_KP_PAGE_UP; break;
1610 case XK_KP_0:
1611 #ifdef XK_KP_Insert
1612 case XK_KP_Insert:
1613 #endif
1614 key_event = BX_KEY_KP_INSERT; break;
1616 case XK_KP_Decimal:
1617 #ifdef XK_KP_Delete
1618 case XK_KP_Delete:
1619 #endif
1620 key_event = BX_KEY_KP_DELETE; break;
1622 #ifdef XK_KP_Enter
1623 case XK_KP_Enter: key_event = BX_KEY_KP_ENTER; break;
1624 #endif
1626 case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
1627 case XK_KP_Add: key_event = BX_KEY_KP_ADD; break;
1629 case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
1630 case XK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break;
1633 case XK_Up: key_event = BX_KEY_UP; break;
1634 case XK_Down: key_event = BX_KEY_DOWN; break;
1635 case XK_Left: key_event = BX_KEY_LEFT; break;
1636 case XK_Right: key_event = BX_KEY_RIGHT; break;
1639 case XK_Delete: key_event = BX_KEY_DELETE; break;
1640 case XK_BackSpace: key_event = BX_KEY_BACKSPACE; break;
1641 case XK_Tab: key_event = BX_KEY_TAB; break;
1642 #ifdef XK_ISO_Left_Tab
1643 case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
1644 #endif
1645 case XK_Return: key_event = BX_KEY_ENTER; break;
1646 case XK_Escape: key_event = BX_KEY_ESC; break;
1647 case XK_F1: key_event = BX_KEY_F1; break;
1648 case XK_F2: key_event = BX_KEY_F2; break;
1649 case XK_F3: key_event = BX_KEY_F3; break;
1650 case XK_F4: key_event = BX_KEY_F4; break;
1651 case XK_F5: key_event = BX_KEY_F5; break;
1652 case XK_F6: key_event = BX_KEY_F6; break;
1653 case XK_F7: key_event = BX_KEY_F7; break;
1654 case XK_F8: key_event = BX_KEY_F8; break;
1655 case XK_F9: key_event = BX_KEY_F9; break;
1656 case XK_F10: key_event = BX_KEY_F10; break;
1657 case XK_F11: key_event = BX_KEY_F11; break;
1658 case XK_F12: key_event = BX_KEY_F12; break;
1659 case XK_Control_L: key_event = BX_KEY_CTRL_L; break;
1660 #ifdef XK_Control_R
1661 case XK_Control_R: key_event = BX_KEY_CTRL_R; break;
1662 #endif
1663 case XK_Shift_L: key_event = BX_KEY_SHIFT_L; break;
1664 case XK_Shift_R: key_event = BX_KEY_SHIFT_R; break;
1665 case XK_Alt_L: key_event = BX_KEY_ALT_L; break;
1666 #ifdef XK_Alt_R
1667 case XK_Alt_R: key_event = BX_KEY_ALT_R; break;
1668 #endif
1669 case XK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break;
1670 case XK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break;
1671 #ifdef XK_Scroll_Lock
1672 case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
1673 #endif
1674 #ifdef XK_Print
1675 case XK_Print: key_event = BX_KEY_PRINT; break;
1676 #endif
1677 #ifdef XK_Pause
1678 case XK_Pause: key_event = BX_KEY_PAUSE; break;
1679 #endif
1681 case XK_Insert: key_event = BX_KEY_INSERT; break;
1682 case XK_Home: key_event = BX_KEY_HOME; break;
1683 case XK_End: key_event = BX_KEY_END; break;
1684 case XK_Page_Up: key_event = BX_KEY_PAGE_UP; break;
1685 case XK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break;
1687 default:
1688 BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key));
1689 return;
1690 break;
1694 if (!press_release) key_event |= BX_KEY_RELEASED;
1695 DEV_kbd_gen_scancode(key_event);
1698 void rfbMouseMove(int x, int y, int bmask)
1700 static int oldx = -1;
1701 static int oldy = -1;
1702 int xorigin;
1704 if ((oldx == 1) && (oldy == -1)) {
1705 oldx = x;
1706 oldy = y;
1707 return;
1709 if(y > rfbHeaderbarY) {
1710 DEV_mouse_motion(x - oldx, oldy - y, bmask);
1711 oldx = x;
1712 oldy = y;
1713 } else {
1714 if (bmask == 1) {
1715 for (unsigned i=0; i<rfbHeaderbarBitmapCount; i++) {
1716 if (rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT)
1717 xorigin = rfbHeaderbarBitmaps[i].xorigin;
1718 else
1719 xorigin = rfbWindowX - rfbHeaderbarBitmaps[i].xorigin;
1720 if ((x>=xorigin) && (x<(xorigin+int(rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim)))) {
1721 rfbHeaderbarBitmaps[i].f();
1722 return;
1729 void bx_rfb_gui_c::mouse_enabled_changed_specific (bx_bool val)
1733 void bx_rfb_gui_c::get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp)
1735 *xres = BX_RFB_MAX_XDIM;
1736 *yres = BX_RFB_MAX_YDIM;
1737 *bpp = 8;
1740 #if BX_SHOW_IPS
1741 void bx_rfb_gui_c::show_ips(Bit32u ips_count)
1743 char ips_text[40];
1744 sprintf(ips_text, "IPS: %9u", ips_count);
1745 rfbSetStatusText(0, ips_text, 1);
1747 #endif
1749 #endif /* if BX_WITH_RFB */