1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rfb.cc,v 1.58 2008/04/07 20:20:04 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2000 Psyon.Org!
8 // http://www.psyon.org
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
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.
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];
45 #include "sdl.h" // 8x8 font for status text
48 class bx_rfb_gui_c
: public bx_gui_c
{
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
);
56 void show_ips(Bit32u ips_count
);
60 // declare one instance of the gui object and call macro to insert the
62 static bx_rfb_gui_c
*theGui
= NULL
;
63 IMPLEMENT_GUI_PLUGIN_CODE(rfb
)
65 #define LOG_THIS theGui->
76 #include <sys/socket.h>
77 #include <netinet/tcp.h>
78 #include <netinet/in.h>
81 #include <sys/errno.h>
88 #ifndef INVALID_SOCKET
89 #define INVALID_SOCKET -1
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
;
102 unsigned rfbBitmapCount
= 0;
107 } rfbBitmaps
[BX_MAX_PIXMAPS
];
109 static unsigned rfbHeaderbarBitmapCount
= 0;
110 struct _rfbHeaderbarBitmaps
{
112 unsigned int xorigin
;
113 unsigned int yorigin
;
114 unsigned int alignment
;
116 } rfbHeaderbarBitmaps
[BX_MAX_HEADERBAR_ENTRIES
];
119 #define KEYBOARD true
121 #define MAX_KEY_EVENTS 512
128 } rfbKeyboardEvent
[MAX_KEY_EVENTS
];
129 static unsigned long rfbKeyboardEvents
= 0;
130 static bool bKeyboardInUse
= false;
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
);
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))))
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
;
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
];
233 for (int b
= 0; b
< 8; b
++) {
234 fc
|= (vc
& 0x01) << (7 - b
);
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
;
256 client_connected
= false;
261 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL
);
263 if (SIM
->get_param_bool(BXPN_PRIVATE_COLORMAP
)->get()) {
264 BX_ERROR(("private_colormap option ignored."));
267 // parse rfb specific options
269 for (i
= 1; i
< argc
; i
++) {
270 if (!strncmp(argv
[i
], "timeout=", 8)) {
271 timeout
= atoi(&argv
[i
][8]);
273 BX_PANIC(("Unknown rfb option '%s'", argv
[i
]));
278 while ((!client_connected
) && (timeout
--)) {
285 if (timeout
< 0) BX_PANIC(("timeout! no client present"));
291 void rfbSetStatusText(int element
, const char *text
, bx_bool active
)
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;
305 color
= active
?0xa0:0xf7;
309 DrawBitmap(xleft
, rfbWindowY
- rfbStatusbarY
+ 1, xsize
, rfbStatusbarY
- 2, newBits
, color
, false);
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
)
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
);
338 if(WSAStartup(MAKEWORD(1,1), &wsaData
) != 0) return false;
351 void CDECL
ServerThreadInit(void *indata
)
355 struct sockaddr_in sai
;
356 unsigned int sai_size
;
361 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE
);
363 BX_PANIC(("could not initialize winsock."));
368 sServer
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
370 BX_PANIC(("could not create socket."));
373 if (setsockopt(sServer
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&one
, sizeof(int)) == -1) {
374 BX_PANIC(("could not set socket option."));
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."));
387 if(listen(sServer
, SOMAXCONN
) == -1) {
388 BX_INFO(("Could not listen on socket."));
396 BX_PANIC (("RFB could not bind any port between %d and %d",
401 BX_INFO (("listening for connections on port %i", rfbPort
));
402 sai_size
= sizeof(sai
);
404 sClient
= accept(sServer
, (struct sockaddr
*)&sai
, (socklen_t
*)&sai_size
);
405 if(sClient
!= INVALID_SOCKET
) {
406 HandleRfbClient(sClient
);
407 sGlobal
= INVALID_SOCKET
;
421 void HandleRfbClient(SOCKET sClient
)
423 char rfbName
[] = "Bochs-RFB";
424 rfbProtocolVersionMessage pv
;
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."));
442 if(ReadExact(sClient
, pv
, rfbProtocolVersionMessageSize
) < 0) {
443 BX_ERROR(("could not receive client protocol version."));
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."));
457 if(ReadExact(sClient
, (char *)&cim
, rfbClientInitMessageSize
) < 0) {
458 BX_ERROR(("could not receive client initialization message."));
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."));
474 if(WriteExact(sClient
, rfbName
, strlen(rfbName
)) < 0) {
475 BX_ERROR (("could not send server name."));
484 if((n
= recv(sClient
, (char *)&msgType
, 1, MSG_PEEK
)) <= 0) {
486 BX_ERROR(("client closed connection."));
488 BX_ERROR(("error receiving data."));
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
));
519 case rfbFixColourMapEntries
:
521 rfbFixColourMapEntriesMessage fcme
;
522 ReadExact(sClient
, (char *)&fcme
, sizeof(rfbFixColourMapEntriesMessage
));
525 case rfbSetEncodings
:
527 rfbSetEncodingsMessage se
;
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) {
546 BX_ERROR(("client closed connection."));
548 BX_ERROR(("error receiving data."));
552 clientEncodings
[i
]=ntohl(enc
);
555 // print supported encodings
556 BX_INFO(("rfbSetEncodings : client supported encodings:"));
557 for(i
= 0; i
< clientEncodingsCount
; i
++) {
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
));
567 if (!found
) BX_INFO(("%08x Unknown", clientEncodings
[i
]));
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;
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;
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
;
603 bKeyboardInUse
= false;
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);
620 bKeyboardInUse
= false;
623 case rfbClientCutText
:
625 rfbClientCutTextMessage cct
;
626 ReadExact(sClient
, (char *)&cct
, sizeof(rfbClientCutTextMessage
));
634 // Called periodically (vga_update_interval in .bochsrc) so the
635 // the gui code can poll for keyboard, mouse, and other
638 void bx_rfb_gui_c::handle_events(void)
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;
667 // Called periodically, requesting that the gui code flush all pending
668 // screen update requests.
670 void bx_rfb_gui_c::flush(void)
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
);
685 // Called in a VGA text mode, to update the screen with
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
;
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;
712 if (tm_info
.blink_flags
& BX_TEXT_BLINK_TOGGLE
)
715 if(charmap_updated
) {
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
];
739 offset
= y
* tm_info
.line_offset
;
740 yc
= y
* font_height
+ rfbHeaderbarY
;
743 if (force_update
|| (old_text
[0] != new_text
[0])
744 || (old_text
[1] != new_text
[1])) {
747 cAttr
= new_text
[1] & 0x7F;
748 if (!blink_state
&& (new_text
[1] & 0x80))
749 cAttr
= (cAttr
& 0x70) | (cAttr
>> 4);
753 gfxchar
= tm_info
.line_graphics
&& ((cChar
& 0xE0) == 0xC0);
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
);
773 new_text
= new_line
+ tm_info
.line_offset
;
774 old_text
= old_line
+ tm_info
.line_offset
;
777 rfbCursorX
= cursor_x
;
778 rfbCursorY
= cursor_y
;
781 int bx_rfb_gui_c::get_clipboard_text(Bit8u
**bytes
, Bit32s
*nbytes
)
786 int bx_rfb_gui_c::set_clipboard_text(char *text_snapshot
, Bit32u len
)
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);
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
)
831 info
= (bx_svga_tileinfo_t
*)malloc(sizeof(bx_svga_tileinfo_t
));
838 info
->pitch
= rfbWindowX
;
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;
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
;
861 if (y0
+rfbTileY
> rfbDimensionY
) {
862 *h
= rfbDimensionY
- y0
;
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.
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
)
897 BX_PANIC(("%d bpp graphics mode not supported yet", bpp
));
900 font_height
= fheight
;
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
)) {
909 SendUpdate(0, rfbHeaderbarY
, rfbDimensionX
, rfbDimensionY
);
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."));
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);
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))
961 if((rfbHeaderbarBitmapCount
+ 1) > BX_MAX_HEADERBAR_ENTRIES
) {
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;
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
;
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);
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);
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
;
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);
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)
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
)
1088 n
= recv(sock
, buf
, len
, 0);
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
)
1110 n
= send(sock
, buf
, len
,0);
1115 } else if (n
== 0) {
1116 BX_ERROR(("WriteExact: write returned 0?"));
1125 void DrawBitmap(int x
, int y
, int width
, int height
, char *bmap
, char color
, bool update_client
)
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
1137 (char)0x07, //Light Gray
1138 (char)0x38, //Dark Gray
1139 (char)0x09, //Light Blue
1142 (char)0x24, //Light Red
1143 (char)0x2D, //Magenta
1144 (char)0x36, //Yellow
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();
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];
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
1180 (char)0x07, //Light Gray
1181 (char)0x38, //Dark Gray
1182 (char)0x09, //Light Blue
1185 (char)0x24, //Light Red
1186 (char)0x2D, //Magenta
1187 (char)0x36, //Yellow
1191 bgcolor
= vgaPalette
[(color
>> 4) & 0xF];
1192 fgcolor
= vgaPalette
[color
& 0xF];
1194 for(int i
= 0; i
< bytes
; i
+=width
) {
1196 for(int j
= 0; j
< width
; j
++) {
1198 newBits
[i
+ j
] = (bmap
[fonty
] & mask
) ? fgcolor
: bgcolor
;
1201 newBits
[i
+ j
] = (bmap
[fonty
] & 0x01) ? fgcolor
: bgcolor
;
1203 newBits
[i
+ j
] = bgcolor
;
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);
1229 void UpdateScreen(unsigned char *newBits
, int x
, int y
, int width
, int height
, bool update_client
)
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
);
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
)
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
);
1283 WriteExact(sGlobal
, (char *)&fum
, rfbFramebufferUpdateMessageSize
);
1284 WriteExact(sGlobal
, (char *)&furh
, rfbFramebufferUpdateRectHeaderSize
);
1285 WriteExact(sGlobal
, (char *)newBits
, width
* height
);
1294 _beginthread(ServerThreadInit
, 0, NULL
);
1297 pthread_create(&thread
, NULL
, (void *(*)(void *))&ServerThreadInit
, NULL
);
1301 /***********************/
1302 /* Keyboard Definitons */
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] = {
1429 BX_KEY_SINGLE_QUOTE
,
1434 BX_KEY_SINGLE_QUOTE
,
1502 BX_KEY_LEFT_BRACKET
,
1504 BX_KEY_RIGHT_BRACKET
,
1542 BX_KEY_LEFT_BRACKET
,
1544 BX_KEY_RIGHT_BRACKET
,
1548 void rfbKeyPressed(Bit32u key
, int press_release
)
1552 if((key
>= XK_space
) && (key
<= XK_asciitilde
)) {
1553 key_event
= rfb_ascii_to_key_event
[key
- XK_space
];
1560 key_event
= BX_KEY_KP_END
; break;
1566 key_event
= BX_KEY_KP_DOWN
; break;
1569 #ifdef XK_KP_Page_Down
1570 case XK_KP_Page_Down
:
1572 key_event
= BX_KEY_KP_PAGE_DOWN
; break;
1578 key_event
= BX_KEY_KP_LEFT
; break;
1584 key_event
= BX_KEY_KP_5
; break;
1590 key_event
= BX_KEY_KP_RIGHT
; break;
1596 key_event
= BX_KEY_KP_HOME
; break;
1602 key_event
= BX_KEY_KP_UP
; break;
1605 #ifdef XK_KP_Page_Up
1608 key_event
= BX_KEY_KP_PAGE_UP
; break;
1614 key_event
= BX_KEY_KP_INSERT
; break;
1620 key_event
= BX_KEY_KP_DELETE
; break;
1623 case XK_KP_Enter
: key_event
= BX_KEY_KP_ENTER
; break;
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;
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;
1661 case XK_Control_R
: key_event
= BX_KEY_CTRL_R
; break;
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;
1667 case XK_Alt_R
: key_event
= BX_KEY_ALT_R
; break;
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;
1675 case XK_Print
: key_event
= BX_KEY_PRINT
; break;
1678 case XK_Pause
: key_event
= BX_KEY_PAUSE
; break;
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;
1688 BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key
));
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;
1704 if ((oldx
== 1) && (oldy
== -1)) {
1709 if(y
> rfbHeaderbarY
) {
1710 DEV_mouse_motion(x
- oldx
, oldy
- y
, bmask
);
1715 for (unsigned i
=0; i
<rfbHeaderbarBitmapCount
; i
++) {
1716 if (rfbHeaderbarBitmaps
[i
].alignment
== BX_GRAVITY_LEFT
)
1717 xorigin
= rfbHeaderbarBitmaps
[i
].xorigin
;
1719 xorigin
= rfbWindowX
- rfbHeaderbarBitmaps
[i
].xorigin
;
1720 if ((x
>=xorigin
) && (x
<(xorigin
+int(rfbBitmaps
[rfbHeaderbarBitmaps
[i
].index
].xdim
)))) {
1721 rfbHeaderbarBitmaps
[i
].f();
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
;
1741 void bx_rfb_gui_c::show_ips(Bit32u ips_count
)
1744 sprintf(ips_text
, "IPS: %9u", ips_count
);
1745 rfbSetStatusText(0, ips_text
, 1);
1749 #endif /* if BX_WITH_RFB */