- added instructions how to update the online documentation
[bochs-mirror.git] / gui / wx.cc
blobcce878a03174464ed32516fe22aed17d1233cf53
1 /////////////////////////////////////////////////////////////////
2 // $Id: wx.cc,v 1.96 2008/11/16 21:01:09 vruppert Exp $
3 /////////////////////////////////////////////////////////////////
4 //
5 // wxWidgets VGA display for Bochs. wx.cc implements a custom
6 // wxPanel called a MyPanel, which has methods to display
7 // text and VGA graphics on the panel. Normally, a MyPanel
8 // is instantiated within a MyFrame created by wxmain.cc, but
9 // this is not a requirement.
11 // The separation between wxmain.cc and wx.cc is as follows:
12 // - wxmain.cc implements a Bochs configuration interface (CI),
13 // which is the wxWidgets equivalent of textconfig.cc. wxmain creates
14 // a frame with several menus and a toolbar, and allows the user to
15 // choose the machine configuration and start the simulation. Note
16 // that wxmain.cc does NOT include bochs.h. All interactions
17 // between the CI and the simulator are through the siminterface
18 // object.
19 // - wx.cc implements a VGA display screen using wxWidgets. It is
20 // is the wxWidgets equivalent of x.cc, win32.cc, macos.cc, etc.
21 // wx.cc includes bochs.h and has access to all Bochs devices.
22 // The VGA panel accepts only paint, key, and mouse events. As it
23 // receives events, it builds BxEvents and places them into a
24 // thread-safe BxEvent queue. The simulation thread periodically
25 // processes events from the BxEvent queue (bx_wx_gui_c::handle_events)
26 // and notifies the appropriate emulated I/O device.
28 /////////////////////////////////////////////////////////////////
30 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
31 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
32 // is used to know when we are exporting symbols and when we are importing.
33 #define BX_PLUGGABLE
35 #include "bochs.h"
36 #include "iodev.h"
37 #if BX_WITH_WX
39 // For compilers that support precompilation, includes <wx/wx.h>.
40 #include <wx/wxprec.h>
41 #ifdef __BORLANDC__
42 #pragma hdrstop
43 #endif
44 #ifndef WX_PRECOMP
45 #include <wx/wx.h>
46 #endif
47 #include <wx/image.h>
48 #include <wx/clipbrd.h>
50 //#include "gui/icon_bochs.h"
51 #include "osdep.h"
52 #include "font/vga.bitmap.h"
54 // shared elements between wxmain.cc and this file
55 #include "wxmain.h"
58 //////////////////////////////////////////////////////////////
59 // plugin support
60 //////////////////////////////////////////////////////////////
61 class bx_wx_gui_c : public bx_gui_c {
62 public:
63 bx_wx_gui_c (void) {}
64 DECLARE_GUI_VIRTUAL_METHODS()
65 DECLARE_GUI_NEW_VIRTUAL_METHODS()
66 void statusbar_setitem(int element, bx_bool active, bx_bool w=0);
67 #if BX_SHOW_IPS
68 void show_ips(Bit32u ips_count);
69 #endif
72 // declare one instance of the gui object and call macro to insert the
73 // plugin code
74 static bx_wx_gui_c *theGui = NULL;
76 void MyPanel::OnPluginInit () {
77 theGui = new bx_wx_gui_c ();
78 bx_gui = theGui;
81 #define LOG_THIS theGui->
83 //////////////////////////////////////////////////////////////
84 // data for wx gui
85 //////////////////////////////////////////////////////////////
86 // The bits to be displayed on the VGA screen are stored in wxScreen.
87 // wxScreen is an array (size=width*height*3) of RGB values. Each
88 // pixel is represented by three bytes, one for red, green, and blue.
89 static char *wxScreen = NULL;
90 wxCriticalSection wxScreen_lock;
91 static long wxScreenX = 0;
92 static long wxScreenY = 0;
93 static bx_bool wxScreenCheckSize = 0;
94 static unsigned wxTileX = 0;
95 static unsigned wxTileY = 0;
96 static unsigned long wxCursorX = 0;
97 static unsigned long wxCursorY = 0;
98 static unsigned long wxFontX = 0;
99 static unsigned long wxFontY = 0;
100 static unsigned int text_rows=25, text_cols=80;
101 static Bit8u h_panning = 0, v_panning = 0;
102 static Bit16u line_compare = 1023;
103 static unsigned vga_bpp=8;
104 static struct {
105 unsigned char red;
106 unsigned char green;
107 unsigned char blue;
108 } wxBochsPalette[256];
109 wxCriticalSection event_thread_lock;
110 BxEvent event_queue[MAX_EVENTS];
111 unsigned long num_events = 0;
112 static bx_bool mouse_captured = 0;
113 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
114 static Bit32u convertStringToGDKKey (const char *string);
115 #endif
118 //////////////////////////////////////////////////////////////
119 // and now, the code
120 //////////////////////////////////////////////////////////////
122 //////////////////////////////////////////////////////////////
123 // define the MyPanel which implements the VGA screen
124 //////////////////////////////////////////////////////////////
126 BEGIN_EVENT_TABLE(MyPanel, wxPanel)
127 EVT_KEY_DOWN(MyPanel::OnKeyDown)
128 EVT_KEY_UP(MyPanel::OnKeyUp)
129 EVT_TIMER(-1, MyPanel::OnTimer)
130 EVT_PAINT(MyPanel::OnPaint)
131 EVT_MOUSE_EVENTS(MyPanel::OnMouse)
132 END_EVENT_TABLE()
134 MyPanel::MyPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
135 : wxPanel (parent, id, pos, size, style, name)
137 wxLogDebug (wxT ("MyPanel constructor"));
138 refreshTimer.SetOwner (this);
139 refreshTimer.Start (100);
140 needRefresh = true;
141 const char bits[1] = { 0 };
142 blankCursor = new wxCursor (bits, 1, 1, -1, -1, bits);
143 thePanel = this;
146 MyPanel::~MyPanel ()
148 delete blankCursor;
149 thePanel = NULL;
152 void MyPanel::OnTimer(wxTimerEvent& WXUNUSED(event))
154 int cx, cy;
156 if (wxScreenCheckSize) {
157 theFrame->GetClientSize(&cx, &cy);
158 if ((cx != wxScreenX) || (cy != wxScreenY)) {
159 theFrame->SetClientSize(wxScreenX, wxScreenY);
161 wxScreenCheckSize = 0;
163 IFDBG_VGA(wxLogDebug(wxT("timer")));
164 if (needRefresh) {
165 IFDBG_VGA(wxLogDebug(wxT("calling refresh")));
166 Refresh(FALSE);
170 void MyPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
172 wxPaintDC dc(this);
173 IFDBG_VGA (wxLogDebug (wxT ("OnPaint")));
174 //PrepareDC(dc);
176 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::OnPaint trying to get lock. wxScreen=%p", wxScreen)));
177 wxCriticalSectionLocker lock(wxScreen_lock);
178 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::OnPaint got lock. wxScreen=%p", wxScreen)));
179 if(wxScreen != NULL) {
180 wxPoint pt = GetClientAreaOrigin();
181 wxImage screenImage(wxScreenX, wxScreenY, (unsigned char *)wxScreen, TRUE);
182 IFDBG_VGA(wxLogDebug (wxT ("drawBitmap")));
183 dc.DrawBitmap(wxBitmap(screenImage), pt.x, pt.y, FALSE);
185 needRefresh = false;
188 void MyPanel::ToggleMouse (bool fromToolbar)
190 static bool first_enable = true;
191 bx_param_bool_c *enable = SIM->get_param_bool(BXPN_MOUSE_ENABLED);
192 bool en = ! enable->get();
193 bool is_main_thread = wxThread::IsMain ();
194 bool needmutex = !is_main_thread && SIM->is_sim_thread ();
195 if (needmutex) wxMutexGuiEnter();
196 if (fromToolbar && first_enable && en) {
197 // only show this help if you click on the toolbar. If they already
198 // know the shortcut, don't annoy them with the message.
199 wxString msg = wxT(
200 "You have enabled the mouse in Bochs, so now your mouse actions will\n"
201 "be sent into the simulator. The usual mouse cursor will be trapped\n"
202 "inside the Bochs window until you press a CTRL key + the middle button\n"
203 "to turn mouse capture off.");
204 wxMessageBox(msg, wxT("Mouse Capture Enabled"), wxOK | wxICON_INFORMATION);
205 first_enable = false;
207 enable->set (en);
208 IFDBG_MOUSE (wxLogDebug (wxT ("now mouse is %sabled", en ? "en" : "dis")));
209 if (en) {
210 mouseSavedX = wxScreenX / 2;
211 mouseSavedY = wxScreenY / 2;
212 WarpPointer (mouseSavedX, mouseSavedY);
213 SetCursor (*blankCursor);
214 } else {
215 SetCursor (wxNullCursor);
217 if (needmutex) wxMutexGuiLeave();
220 void MyPanel::OnMouse(wxMouseEvent& event)
222 long x,y;
223 event.GetPosition (&x, &y);
224 IFDBG_MOUSE (
225 if (event.IsButton ()) {
226 wxLogDebug (wxT ("mouse button event at %d,%d", x, y));
227 } else if (event.Entering ()) {
228 wxLogDebug (wxT ("mouse entering at %d,%d", x, y));
229 } else if (event.Leaving ()) {
230 wxLogDebug (wxT ("mouse leaving at %d,%d", x, y));
231 } else if (event.Moving() || event.Dragging ()) {
232 wxLogDebug (wxT ("mouse moved to %d,%d", x, y));
233 } else {
234 wxLogDebug (wxT ("other mouse event at %d,%d", x, y));
238 if (event.MiddleDown() && event.ControlDown()) {
239 ToggleMouse (false);
240 return;
243 if (!mouse_captured)
244 return; // mouse disabled, ignore the event
246 // process buttons and motion together
247 Bit32u buttons;
248 buttons = event.LeftIsDown() ? 1 : 0;
249 buttons |= event.RightIsDown() ? 2 : 0;
250 buttons |= event.MiddleIsDown() ? 4 : 0;
251 if (x==mouseSavedX && y==mouseSavedY && !event.IsButton ()) {
252 // nothing happened. This could have been generated by the WarpPointer.
253 return;
254 } else {
255 if(num_events < MAX_EVENTS) {
256 wxCriticalSectionLocker lock(event_thread_lock);
257 Bit16s dx = x - mouseSavedX;
258 Bit16s dy = y - mouseSavedY;
259 IFDBG_MOUSE (wxLogDebug (wxT ("mouse moved by delta %d,%d", dx, dy)));
260 event_queue[num_events].type = BX_ASYNC_EVT_MOUSE;
261 event_queue[num_events].u.mouse.dx = dx;
262 event_queue[num_events].u.mouse.dy = -dy;
263 event_queue[num_events].u.mouse.buttons = buttons;
264 num_events++;
265 mouseSavedX = x;
266 mouseSavedY = y;
267 } else {
268 wxLogDebug (wxT ("mouse event skipped because event queue full"));
272 mouseSavedX = wxScreenX / 2;
273 mouseSavedY = wxScreenY / 2;
274 WarpPointer (mouseSavedX, mouseSavedY);
275 // The WarpPointer moves the pointer back to the middle of the
276 // screen. This WILL produce another mouse motion event, which needs
277 // to be ignored. It will be ignored because the new motion event
278 // will move the cursor to (mouseSavedX, mouseSavedY).
281 void MyPanel::MyRefresh ()
283 IFDBG_VGA (wxLogDebug (wxT ("set needRefresh=true")));
284 needRefresh = true;
287 void MyPanel::OnKeyDown(wxKeyEvent& event)
289 wxCriticalSectionLocker lock(event_thread_lock);
290 if(num_events < MAX_EVENTS) {
291 event_queue[num_events].type = BX_ASYNC_EVT_KEY;
292 fillBxKeyEvent (event, event_queue[num_events].u.key, false);
293 num_events++;
298 void MyPanel::OnKeyUp(wxKeyEvent& event)
300 wxCriticalSectionLocker lock(event_thread_lock);
301 if(num_events < MAX_EVENTS) {
302 event_queue[num_events].type = BX_ASYNC_EVT_KEY;
303 fillBxKeyEvent (event, event_queue[num_events].u.key, true);
304 num_events++;
308 /// copied right out of gui/x.cc
309 static char wxAsciiKey[0x5f] = {
310 // !"#$%&'
311 BX_KEY_SPACE,
312 BX_KEY_1,
313 BX_KEY_SINGLE_QUOTE,
314 BX_KEY_3,
315 BX_KEY_4,
316 BX_KEY_5,
317 BX_KEY_7,
318 BX_KEY_SINGLE_QUOTE,
320 // ()*+,-./
321 BX_KEY_9,
322 BX_KEY_0,
323 BX_KEY_8,
324 BX_KEY_EQUALS,
325 BX_KEY_COMMA,
326 BX_KEY_MINUS,
327 BX_KEY_PERIOD,
328 BX_KEY_SLASH,
330 // 01234567
331 BX_KEY_0,
332 BX_KEY_1,
333 BX_KEY_2,
334 BX_KEY_3,
335 BX_KEY_4,
336 BX_KEY_5,
337 BX_KEY_6,
338 BX_KEY_7,
340 // 89:;<=>?
341 BX_KEY_8,
342 BX_KEY_9,
343 BX_KEY_SEMICOLON,
344 BX_KEY_SEMICOLON,
345 BX_KEY_COMMA,
346 BX_KEY_EQUALS,
347 BX_KEY_PERIOD,
348 BX_KEY_SLASH,
350 // @ABCDEFG
351 BX_KEY_2,
352 BX_KEY_A,
353 BX_KEY_B,
354 BX_KEY_C,
355 BX_KEY_D,
356 BX_KEY_E,
357 BX_KEY_F,
358 BX_KEY_G,
361 // HIJKLMNO
362 BX_KEY_H,
363 BX_KEY_I,
364 BX_KEY_J,
365 BX_KEY_K,
366 BX_KEY_L,
367 BX_KEY_M,
368 BX_KEY_N,
369 BX_KEY_O,
372 // PQRSTUVW
373 BX_KEY_P,
374 BX_KEY_Q,
375 BX_KEY_R,
376 BX_KEY_S,
377 BX_KEY_T,
378 BX_KEY_U,
379 BX_KEY_V,
380 BX_KEY_W,
382 // XYZ[\]^_
383 BX_KEY_X,
384 BX_KEY_Y,
385 BX_KEY_Z,
386 BX_KEY_LEFT_BRACKET,
387 BX_KEY_BACKSLASH,
388 BX_KEY_RIGHT_BRACKET,
389 BX_KEY_6,
390 BX_KEY_MINUS,
392 // `abcdefg
393 BX_KEY_GRAVE,
394 BX_KEY_A,
395 BX_KEY_B,
396 BX_KEY_C,
397 BX_KEY_D,
398 BX_KEY_E,
399 BX_KEY_F,
400 BX_KEY_G,
402 // hijklmno
403 BX_KEY_H,
404 BX_KEY_I,
405 BX_KEY_J,
406 BX_KEY_K,
407 BX_KEY_L,
408 BX_KEY_M,
409 BX_KEY_N,
410 BX_KEY_O,
412 // pqrstuvw
413 BX_KEY_P,
414 BX_KEY_Q,
415 BX_KEY_R,
416 BX_KEY_S,
417 BX_KEY_T,
418 BX_KEY_U,
419 BX_KEY_V,
420 BX_KEY_W,
422 // xyz{|}~
423 BX_KEY_X,
424 BX_KEY_Y,
425 BX_KEY_Z,
426 BX_KEY_LEFT_BRACKET,
427 BX_KEY_BACKSLASH,
428 BX_KEY_RIGHT_BRACKET,
429 BX_KEY_GRAVE
432 // copied from gui/win32.cc
433 Bit32u wxMSW_to_bx_key[0x59] = {
434 /* 0x00 - 0x0f */
436 BX_KEY_ESC,
437 BX_KEY_1,
438 BX_KEY_2,
439 BX_KEY_3,
440 BX_KEY_4,
441 BX_KEY_5,
442 BX_KEY_6,
443 BX_KEY_7,
444 BX_KEY_8,
445 BX_KEY_9,
446 BX_KEY_0,
447 BX_KEY_MINUS,
448 BX_KEY_EQUALS,
449 BX_KEY_BACKSPACE,
450 BX_KEY_TAB,
451 /* 0x10 - 0x1f */
452 BX_KEY_Q,
453 BX_KEY_W,
454 BX_KEY_E,
455 BX_KEY_R,
456 BX_KEY_T,
457 BX_KEY_Y,
458 BX_KEY_U,
459 BX_KEY_I,
460 BX_KEY_O,
461 BX_KEY_P,
462 BX_KEY_LEFT_BRACKET,
463 BX_KEY_RIGHT_BRACKET,
464 BX_KEY_ENTER,
465 BX_KEY_CTRL_L,
466 BX_KEY_A,
467 BX_KEY_S,
468 /* 0x20 - 0x2f */
469 BX_KEY_D,
470 BX_KEY_F,
471 BX_KEY_G,
472 BX_KEY_H,
473 BX_KEY_J,
474 BX_KEY_K,
475 BX_KEY_L,
476 BX_KEY_SEMICOLON,
477 BX_KEY_SINGLE_QUOTE,
478 BX_KEY_GRAVE,
479 BX_KEY_SHIFT_L,
480 BX_KEY_BACKSLASH,
481 BX_KEY_Z,
482 BX_KEY_X,
483 BX_KEY_C,
484 BX_KEY_V,
485 /* 0x30 - 0x3f */
486 BX_KEY_B,
487 BX_KEY_N,
488 BX_KEY_M,
489 BX_KEY_COMMA,
490 BX_KEY_PERIOD,
491 BX_KEY_SLASH,
492 BX_KEY_SHIFT_R,
493 BX_KEY_KP_MULTIPLY,
494 BX_KEY_ALT_L,
495 BX_KEY_SPACE,
496 BX_KEY_CAPS_LOCK,
497 BX_KEY_F1,
498 BX_KEY_F2,
499 BX_KEY_F3,
500 BX_KEY_F4,
501 BX_KEY_F5,
502 /* 0x40 - 0x4f */
503 BX_KEY_F6,
504 BX_KEY_F7,
505 BX_KEY_F8,
506 BX_KEY_F9,
507 BX_KEY_F10,
508 BX_KEY_PAUSE,
509 BX_KEY_SCRL_LOCK,
510 BX_KEY_KP_HOME,
511 BX_KEY_KP_UP,
512 BX_KEY_KP_PAGE_UP,
513 BX_KEY_KP_SUBTRACT,
514 BX_KEY_KP_LEFT,
515 BX_KEY_KP_5,
516 BX_KEY_KP_RIGHT,
517 BX_KEY_KP_ADD,
518 BX_KEY_KP_END,
519 /* 0x50 - 0x58 */
520 BX_KEY_KP_DOWN,
521 BX_KEY_KP_PAGE_DOWN,
522 BX_KEY_KP_INSERT,
523 BX_KEY_KP_DELETE,
526 BX_KEY_LEFT_BACKSLASH,
527 BX_KEY_F11,
528 BX_KEY_F12
531 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXMSW__)
532 // get windows specific definitions. At present the only thing needed
533 // is the definition of HIWORD.
535 // windows.h included by bochs.h, so nothing extra is required here.
536 #endif
538 // MS Windows specific key mapping, which uses wxKeyEvent::m_rawCode & 2.
539 bx_bool MyPanel::fillBxKeyEvent_MSW (wxKeyEvent& wxev, BxKeyEvent& bxev, bx_bool release)
541 #if defined(wxHAS_RAW_KEY_CODES) && defined(__WXMSW__)
542 IFDBG_KEY(wxLogDebug (wxT ("fillBxKeyEvent_MSW. key code %d, raw codes %d %d", wxev.m_keyCode, wxev.m_rawCode, wxev.m_rawFlags)));
543 // this code was grabbed from gui/win32.cpp
544 Bit32u lParam = wxev.m_rawFlags;
545 Bit32u key = HIWORD (lParam) & 0x01FF;
546 bxev.bx_key = 0x0000;
547 if (key & 0x0100) {
548 // Its an extended key
549 bxev.bx_key = 0xE000;
551 // Its a key
552 bxev.bx_key |= (key & 0x00FF) | (release? 0x80 : 0x00);
553 bxev.raw_scancode = true;
554 return true;
555 #else
556 return false;
557 #endif
560 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
561 // get those keysym definitions
562 #include <gdk/gdkkeysyms.h>
563 #endif
565 // GTK specific key mapping, which uses wxKeyEvent::m_rawCode.
566 bx_bool MyPanel::fillBxKeyEvent_GTK (wxKeyEvent& wxev, BxKeyEvent& bxev, bx_bool release)
568 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
569 IFDBG_KEY(wxLogDebug (wxT ("fillBxKeyEvent_GTK. key code %ld, raw codes %d %d", wxev.m_keyCode, wxev.m_rawCode, wxev.m_rawFlags)));
570 // GTK has only 16bit key codes
571 Bit16u keysym = (Bit32u) wxev.m_rawCode;
572 Bit32u key_event = 0;
573 // since the GDK_* symbols are very much like the X11 symbols (possibly
574 // identical), I'm using code that is copied from gui/x.cc.
575 if(!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
576 if (keysym >= GDK_space && keysym < GDK_asciitilde) {
577 // use nice ASCII conversion table, based on x.cc
578 key_event = wxAsciiKey[keysym - GDK_space];
579 } else switch (keysym) {
580 case GDK_KP_1:
581 #ifdef GDK_KP_End
582 case GDK_KP_End:
583 #endif
584 key_event = BX_KEY_KP_END; break;
586 case GDK_KP_2:
587 #ifdef GDK_KP_Down
588 case GDK_KP_Down:
589 #endif
590 key_event = BX_KEY_KP_DOWN; break;
592 case GDK_KP_3:
593 #ifdef GDK_KP_Page_Down
594 case GDK_KP_Page_Down:
595 #endif
596 key_event = BX_KEY_KP_PAGE_DOWN; break;
598 case GDK_KP_4:
599 #ifdef GDK_KP_Left
600 case GDK_KP_Left:
601 #endif
602 key_event = BX_KEY_KP_LEFT; break;
604 case GDK_KP_5:
605 #ifdef GDK_KP_Begin
606 case GDK_KP_Begin:
607 #endif
608 key_event = BX_KEY_KP_5; break;
610 case GDK_KP_6:
611 #ifdef GDK_KP_Right
612 case GDK_KP_Right:
613 #endif
614 key_event = BX_KEY_KP_RIGHT; break;
616 case GDK_KP_7:
617 #ifdef GDK_KP_Home
618 case GDK_KP_Home:
619 #endif
620 key_event = BX_KEY_KP_HOME; break;
622 case GDK_KP_8:
623 #ifdef GDK_KP_Up
624 case GDK_KP_Up:
625 #endif
626 key_event = BX_KEY_KP_UP; break;
628 case GDK_KP_9:
629 #ifdef GDK_KP_Page_Up
630 case GDK_KP_Page_Up:
631 #endif
632 key_event = BX_KEY_KP_PAGE_UP; break;
634 case GDK_KP_0:
635 #ifdef GDK_KP_Insert
636 case GDK_KP_Insert:
637 #endif
638 key_event = BX_KEY_KP_INSERT; break;
640 case GDK_KP_Decimal:
641 #ifdef GDK_KP_Delete
642 case GDK_KP_Delete:
643 #endif
644 key_event = BX_KEY_KP_DELETE; break;
646 #ifdef GDK_KP_Enter
647 case GDK_KP_Enter: key_event = BX_KEY_KP_ENTER; break;
648 #endif
650 case GDK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
651 case GDK_KP_Add: key_event = BX_KEY_KP_ADD; break;
653 case GDK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
654 case GDK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break;
657 case GDK_Up: key_event = BX_KEY_UP; break;
658 case GDK_Down: key_event = BX_KEY_DOWN; break;
659 case GDK_Left: key_event = BX_KEY_LEFT; break;
660 case GDK_Right: key_event = BX_KEY_RIGHT; break;
663 case GDK_Delete: key_event = BX_KEY_DELETE; break;
664 case GDK_BackSpace: key_event = BX_KEY_BACKSPACE; break;
665 case GDK_Tab: key_event = BX_KEY_TAB; break;
666 #ifdef GDK_ISO_Left_Tab
667 case GDK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
668 #endif
669 case GDK_Return: key_event = BX_KEY_ENTER; break;
670 case GDK_Escape: key_event = BX_KEY_ESC; break;
671 case GDK_F1: key_event = BX_KEY_F1; break;
672 case GDK_F2: key_event = BX_KEY_F2; break;
673 case GDK_F3: key_event = BX_KEY_F3; break;
674 case GDK_F4: key_event = BX_KEY_F4; break;
675 case GDK_F5: key_event = BX_KEY_F5; break;
676 case GDK_F6: key_event = BX_KEY_F6; break;
677 case GDK_F7: key_event = BX_KEY_F7; break;
678 case GDK_F8: key_event = BX_KEY_F8; break;
679 case GDK_F9: key_event = BX_KEY_F9; break;
680 case GDK_F10: key_event = BX_KEY_F10; break;
681 case GDK_F11: key_event = BX_KEY_F11; break;
682 case GDK_F12: key_event = BX_KEY_F12; break;
683 case GDK_Control_L: key_event = BX_KEY_CTRL_L; break;
684 #ifdef GDK_Control_R
685 case GDK_Control_R: key_event = BX_KEY_CTRL_R; break;
686 #endif
687 case GDK_Shift_L: key_event = BX_KEY_SHIFT_L; break;
688 case GDK_Shift_R: key_event = BX_KEY_SHIFT_R; break;
689 case GDK_Alt_L: key_event = BX_KEY_ALT_L; break;
690 #ifdef GDK_Alt_R
691 case GDK_Alt_R: key_event = BX_KEY_ALT_R; break;
692 #endif
693 case GDK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break;
694 case GDK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break;
695 #ifdef GDK_Scroll_Lock
696 case GDK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
697 #endif
698 #ifdef GDK_Print
699 case GDK_Print: key_event = BX_KEY_PRINT; break;
700 #endif
701 #ifdef GDK_Pause
702 case GDK_Pause: key_event = BX_KEY_PAUSE; break;
703 #endif
705 case GDK_Insert: key_event = BX_KEY_INSERT; break;
706 case GDK_Home: key_event = BX_KEY_HOME; break;
707 case GDK_End: key_event = BX_KEY_END; break;
708 case GDK_Page_Up: key_event = BX_KEY_PAGE_UP; break;
709 case GDK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break;
711 #ifdef GDK_Menu
712 case GDK_Menu: key_event = BX_KEY_MENU; break;
713 #endif
714 #ifdef GDK_Super_L
715 case GDK_Super_L: key_event = BX_KEY_WIN_L; break;
716 #endif
717 #ifdef GDK_Super_R
718 case GDK_Super_R: key_event = BX_KEY_WIN_R; break;
719 #endif
721 default:
722 wxLogError(wxT("fillBxKeyEvent_GTK(): keysym %x unhandled!"), (unsigned) keysym);
723 return BX_KEY_UNHANDLED;
725 } else {
726 /* use mapping */
727 BXKeyEntry *entry = bx_keymap.findHostKey (keysym);
728 if (!entry) {
729 BX_ERROR(("fillBxKeyEvent_GTK(): keysym %x unhandled!", (unsigned) keysym));
730 return BX_KEY_UNHANDLED;
732 key_event = entry->baseKey;
734 bxev.bx_key = key_event | (release? BX_KEY_RELEASED : BX_KEY_PRESSED);
735 bxev.raw_scancode = false;
736 return true;
737 #else // if GTK toolkit
738 return false;
739 #endif
742 bx_bool MyPanel::fillBxKeyEvent (wxKeyEvent& wxev, BxKeyEvent& bxev, bx_bool release)
744 // Use raw codes if they are available. Raw codes are a nonstandard addition
745 // to the wxWidgets library. At present, the only way to use the "RAW_CODES"
746 // mode is to apply Bryce's "patch.wx-raw-keycodes" patch to the wxWidgets
747 // sources and recompile. This patch, or something like it, should appear in
748 // future wxWidgets versions.
750 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXMSW__)
751 return fillBxKeyEvent_MSW (wxev, bxev, release);
752 #endif
754 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
755 return fillBxKeyEvent_GTK (wxev, bxev, release);
756 #endif
758 // otherwise fall back to using portable WXK_* keycodes. Not all keys
759 // can be mapped correctly using WXK_* codes but it should be usable.
760 IFDBG_KEY (wxLogDebug (wxT ("fillBxKeyEvent. key code %ld", wxev.m_keyCode)));
761 Bit32u key = wxev.m_keyCode;
762 Bit32u bx_key;
764 if(key >= WXK_SPACE && key < WXK_DELETE) {
765 bx_key = wxAsciiKey[key - WXK_SPACE];
766 } else {
767 // handle extended keys here
768 switch(key) {
769 case WXK_BACK: bx_key = BX_KEY_BACKSPACE; break;
770 case WXK_TAB: bx_key = BX_KEY_TAB; break;
771 case WXK_RETURN: bx_key = BX_KEY_ENTER; break;
772 case WXK_ESCAPE: bx_key = BX_KEY_ESC; break;
773 case WXK_DELETE: bx_key = BX_KEY_DELETE; break;
774 case WXK_SHIFT: bx_key = BX_KEY_SHIFT_L; break;
775 case WXK_CONTROL: bx_key = BX_KEY_CTRL_L; break;
776 case WXK_ALT: bx_key = BX_KEY_ALT_L; break;
777 case WXK_MENU: bx_key = BX_KEY_MENU; break;
778 case WXK_PAUSE: bx_key = BX_KEY_PAUSE; break;
779 case WXK_PRIOR: bx_key = BX_KEY_PAGE_UP; break;
780 case WXK_NEXT: bx_key = BX_KEY_PAGE_DOWN; break;
781 case WXK_END: bx_key = BX_KEY_END; break;
782 case WXK_HOME: bx_key = BX_KEY_HOME; break;
783 case WXK_LEFT: bx_key = BX_KEY_LEFT; break;
784 case WXK_UP: bx_key = BX_KEY_UP; break;
785 case WXK_RIGHT: bx_key = BX_KEY_RIGHT; break;
786 case WXK_DOWN: bx_key = BX_KEY_DOWN; break;
787 case WXK_INSERT: bx_key = BX_KEY_INSERT; break;
788 case WXK_NUMPAD0: bx_key = BX_KEY_KP_INSERT; break;
789 case WXK_NUMPAD1: bx_key = BX_KEY_KP_END; break;
790 case WXK_NUMPAD2: bx_key = BX_KEY_KP_DOWN; break;
791 case WXK_NUMPAD3: bx_key = BX_KEY_KP_PAGE_DOWN; break;
792 case WXK_NUMPAD4: bx_key = BX_KEY_KP_LEFT; break;
793 case WXK_NUMPAD5: bx_key = BX_KEY_KP_5; break;
794 case WXK_NUMPAD6: bx_key = BX_KEY_KP_RIGHT; break;
795 case WXK_NUMPAD7: bx_key = BX_KEY_KP_HOME; break;
796 case WXK_NUMPAD8: bx_key = BX_KEY_KP_UP; break;
797 case WXK_NUMPAD9: bx_key = BX_KEY_KP_PAGE_UP; break;
798 case WXK_F1: bx_key = BX_KEY_F1; break;
799 case WXK_F2: bx_key = BX_KEY_F2; break;
800 case WXK_F3: bx_key = BX_KEY_F3; break;
801 case WXK_F4: bx_key = BX_KEY_F4; break;
802 case WXK_F5: bx_key = BX_KEY_F5; break;
803 case WXK_F6: bx_key = BX_KEY_F6; break;
804 case WXK_F7: bx_key = BX_KEY_F7; break;
805 case WXK_F8: bx_key = BX_KEY_F8; break;
806 case WXK_F9: bx_key = BX_KEY_F9; break;
807 case WXK_F10: bx_key = BX_KEY_F10; break;
808 case WXK_F11: bx_key = BX_KEY_F11; break;
809 case WXK_F12: bx_key = BX_KEY_F12; break;
810 case WXK_NUMLOCK: bx_key = BX_KEY_NUM_LOCK; break;
811 case WXK_SCROLL: bx_key = BX_KEY_SCRL_LOCK; break;
812 case WXK_DECIMAL: bx_key = BX_KEY_PERIOD; break;
813 case WXK_SUBTRACT: bx_key = BX_KEY_MINUS; break;
814 case WXK_ADD: bx_key = BX_KEY_EQUALS; break;
815 case WXK_MULTIPLY: bx_key = BX_KEY_KP_MULTIPLY; break;
816 case WXK_DIVIDE: bx_key = BX_KEY_KP_DIVIDE; break;
818 case WXK_NUMPAD_ENTER: bx_key = BX_KEY_KP_ENTER; break;
819 case WXK_NUMPAD_HOME: bx_key = BX_KEY_KP_HOME; break;
820 case WXK_NUMPAD_LEFT: bx_key = BX_KEY_KP_LEFT; break;
821 case WXK_NUMPAD_UP: bx_key = BX_KEY_KP_UP; break;
822 case WXK_NUMPAD_RIGHT: bx_key = BX_KEY_KP_RIGHT; break;
823 case WXK_NUMPAD_DOWN: bx_key = BX_KEY_KP_DOWN; break;
824 case WXK_NUMPAD_PRIOR: bx_key = BX_KEY_KP_PAGE_UP; break;
825 case WXK_NUMPAD_PAGEUP: bx_key = BX_KEY_KP_PAGE_UP; break;
826 case WXK_NUMPAD_NEXT: bx_key = BX_KEY_KP_PAGE_DOWN; break;
827 case WXK_NUMPAD_PAGEDOWN: bx_key = BX_KEY_KP_PAGE_DOWN; break;
828 case WXK_NUMPAD_END: bx_key = BX_KEY_KP_END; break;
829 case WXK_NUMPAD_BEGIN: bx_key = BX_KEY_KP_HOME; break;
830 case WXK_NUMPAD_INSERT: bx_key = BX_KEY_KP_INSERT; break;
831 case WXK_NUMPAD_DELETE: bx_key = BX_KEY_KP_DELETE; break;
832 case WXK_NUMPAD_EQUAL: bx_key = BX_KEY_KP_ENTER; break;
833 case WXK_NUMPAD_MULTIPLY: bx_key = BX_KEY_KP_MULTIPLY; break;
834 case WXK_NUMPAD_SUBTRACT: bx_key = BX_KEY_KP_SUBTRACT; break;
835 case WXK_NUMPAD_DECIMAL: bx_key = BX_KEY_KP_DELETE; break;
836 case WXK_NUMPAD_DIVIDE: bx_key = BX_KEY_KP_DIVIDE; break;
838 // Keys not handled by wxMSW
839 case 20: bx_key = BX_KEY_CAPS_LOCK; break; // =+
840 case 186: bx_key = BX_KEY_SEMICOLON; break; // ;:
841 case 187: bx_key = BX_KEY_EQUALS; break; // =+
842 case 188: bx_key = BX_KEY_COMMA; break; // ,<
843 case 189: bx_key = BX_KEY_MINUS; break; // -_
844 case 190: bx_key = BX_KEY_PERIOD; break; // .>
845 case 191: bx_key = BX_KEY_SLASH; break; // /?
846 case 192: bx_key = BX_KEY_GRAVE; break; // `~
847 case 219: bx_key = BX_KEY_LEFT_BRACKET; break; // [{
848 case 221: bx_key = BX_KEY_RIGHT_BRACKET; break; // ]}
849 case 220: bx_key = BX_KEY_BACKSLASH; break; // \|
850 case 222: bx_key = BX_KEY_SINGLE_QUOTE; break; // '"
851 case 305: bx_key = BX_KEY_KP_5; break; // keypad 5
852 case 392: bx_key = BX_KEY_KP_ADD; break; // keypad plus
854 default:
855 wxLogMessage(wxT ("Unhandled key event: %i (0x%x)"), key, key);
856 return 0;
859 IFDBG_KEY (wxLogDebug (wxT ("fillBxKeyEvent: after remapping, key=%d"), bx_key));
860 bxev.bx_key = bx_key | (release? BX_KEY_RELEASED : BX_KEY_PRESSED);
861 bxev.raw_scancode = false;
862 return true;
865 //////////////////////////////////////////////////////////////
866 // fill in methods of bx_gui
867 //////////////////////////////////////////////////////////////
869 void bx_wx_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
870 unsigned headerbar_y)
872 int b,i,j;
873 unsigned char fc, vc;
875 put("WX ");
876 if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {
877 BX_INFO(("private_colormap option ignored."));
880 for(i = 0; i < 256; i++) {
881 wxBochsPalette[i].red = 0;
882 wxBochsPalette[i].green = 0;
883 wxBochsPalette[i].blue = 0;
886 for(i = 0; i < 256; i++) {
887 for(j = 0; j < 16; j++) {
888 vc = bx_vgafont[i].data[j];
889 fc = 0;
890 for (b = 0; b < 8; b++) {
891 fc |= (vc & 0x01) << (7 - b);
892 vc >>= 1;
894 vga_charmap[i*32+j] = fc;
898 wxScreenX = 640;
899 wxScreenY = 480;
900 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::specific_init trying to get lock. wxScreen=%p", wxScreen)));
901 wxCriticalSectionLocker lock(wxScreen_lock);
902 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::specific_init got lock. wxScreen=%p", wxScreen)));
903 if (wxScreen == NULL) {
904 wxScreen = (char *)malloc(wxScreenX * wxScreenY * 3);
905 } else {
906 wxScreen = (char *)realloc(wxScreen, wxScreenX * wxScreenY * 3);
908 memset(wxScreen, 0, wxScreenX * wxScreenY * 3);
910 wxTileX = tilewidth;
911 wxTileY = tileheight;
913 // load keymap tables
914 if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get())
915 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
916 bx_keymap.loadKeymap(convertStringToGDKKey);
917 #else
918 bx_keymap.loadKeymap(NULL);
919 #endif
921 new_gfx_api = 1;
922 dialog_caps = BX_GUI_DLG_USER | BX_GUI_DLG_SNAPSHOT | BX_GUI_DLG_SAVE_RESTORE;
925 // ::HANDLE_EVENTS()
927 // Called periodically (vga_update_interval in .bochsrc) so the
928 // the gui code can poll for keyboard, mouse, and other
929 // relevant events.
931 void bx_wx_gui_c::handle_events(void)
933 wxCriticalSectionLocker lock(event_thread_lock);
934 Bit32u bx_key = 0;
935 for(unsigned int i = 0; i < num_events; i++) {
936 switch(event_queue[i].type) {
937 case BX_ASYNC_EVT_TOOLBAR:
938 switch (event_queue[i].u.toolbar.button) {
939 case BX_TOOLBAR_FLOPPYA: floppyA_handler(); break;
940 case BX_TOOLBAR_FLOPPYB: floppyB_handler(); break;
941 case BX_TOOLBAR_CDROMD: cdromD_handler(); break;
942 case BX_TOOLBAR_RESET: reset_handler(); break;
943 case BX_TOOLBAR_POWER: power_handler(); break;
944 case BX_TOOLBAR_SAVE_RESTORE: save_restore_handler(); break;
945 case BX_TOOLBAR_COPY: copy_handler(); break;
946 case BX_TOOLBAR_PASTE: paste_handler(); break;
947 case BX_TOOLBAR_SNAPSHOT: snapshot_handler(); break;
948 case BX_TOOLBAR_CONFIG: config_handler(); break;
949 case BX_TOOLBAR_MOUSE_EN: thePanel->ToggleMouse(true); break;
950 case BX_TOOLBAR_USER: userbutton_handler(); break;
951 default:
952 wxLogDebug (wxT ("unknown toolbar id %d"), event_queue[i].u.toolbar.button);
954 break;
955 case BX_ASYNC_EVT_KEY:
956 bx_key = event_queue[i].u.key.bx_key;
957 if (event_queue[i].u.key.raw_scancode) {
958 // event contains raw scancodes: convert to BX_KEY values first
959 bx_bool released = ((bx_key & 0x80) > 0);
960 if (bx_key & 0xFF00) { // for extended keys
961 switch (bx_key & 0x7f) {
962 case 0x1C:
963 bx_key = BX_KEY_KP_ENTER;
964 break;
965 case 0x1D:
966 bx_key = BX_KEY_CTRL_R;
967 break;
968 case 0x35:
969 bx_key = BX_KEY_KP_DIVIDE;
970 break;
971 case 0x38:
972 // This makes the "AltGr" key on European keyboards work
973 DEV_kbd_gen_scancode(BX_KEY_CTRL_L | BX_KEY_RELEASED);
974 bx_key = BX_KEY_ALT_R;
975 break;
976 case 0x45:
977 bx_key = BX_KEY_NUM_LOCK;
978 break;
979 case 0x47:
980 bx_key = BX_KEY_HOME;
981 break;
982 case 0x48:
983 bx_key = BX_KEY_UP;
984 break;
985 case 0x49:
986 bx_key = BX_KEY_PAGE_UP;
987 break;
988 case 0x4B:
989 bx_key = BX_KEY_LEFT;
990 break;
991 case 0x4D:
992 bx_key = BX_KEY_RIGHT;
993 break;
994 case 0x4F:
995 bx_key = BX_KEY_END;
996 break;
997 case 0x50:
998 bx_key = BX_KEY_DOWN;
999 break;
1000 case 0x51:
1001 bx_key = BX_KEY_PAGE_DOWN;
1002 break;
1003 case 0x52:
1004 bx_key = BX_KEY_INSERT;
1005 break;
1006 case 0x53:
1007 bx_key = BX_KEY_DELETE;
1008 break;
1009 case 0x5B:
1010 bx_key = BX_KEY_WIN_L;
1011 break;
1012 case 0x5C:
1013 bx_key = BX_KEY_WIN_R;
1014 break;
1015 case 0x5D:
1016 bx_key = BX_KEY_MENU;
1017 break;
1019 } else {
1020 bx_key = wxMSW_to_bx_key[bx_key & 0x7f];
1022 if (released) bx_key |= BX_KEY_RELEASED;
1024 // event contains BX_KEY_* codes: use gen_scancode
1025 IFDBG_KEY (wxLogDebug (wxT ("sending key event 0x%02x", bx_key)));
1026 DEV_kbd_gen_scancode(bx_key);
1027 break;
1028 case BX_ASYNC_EVT_MOUSE:
1029 DEV_mouse_motion(
1030 event_queue[i].u.mouse.dx,
1031 event_queue[i].u.mouse.dy,
1032 event_queue[i].u.mouse.buttons);
1033 break;
1034 default:
1035 wxLogError (wxT ("handle_events received unhandled event type %d in queue"), (int)event_queue[i].type);
1038 num_events = 0;
1041 void bx_wx_gui_c::statusbar_setitem(int element, bx_bool active, bx_bool w)
1043 #if defined(__WXMSW__)
1044 char status_text[10];
1045 #endif
1047 wxMutexGuiEnter();
1048 if (element < 0) {
1049 for (unsigned i = 0; i < statusitem_count; i++) {
1050 if (active) {
1051 #if defined(__WXMSW__)
1052 status_text[0] = 9;
1053 strcpy(status_text+1, statusitem_text[i]);
1054 theFrame->SetStatusText(status_text, i+1);
1055 #else
1056 theFrame->SetStatusText(wxString(statusitem_text[i], wxConvUTF8), i+1);
1057 #endif
1058 } else {
1059 theFrame->SetStatusText(wxT(""), i+1);
1062 } else if ((unsigned)element < statusitem_count) {
1063 if (active) {
1064 #if defined(__WXMSW__)
1065 status_text[0] = 9;
1066 strcpy(status_text+1, statusitem_text[element]);
1067 theFrame->SetStatusText(status_text, element+1);
1068 #else
1069 theFrame->SetStatusText(wxString(statusitem_text[element], wxConvUTF8),
1070 element+1);
1071 #endif
1072 } else {
1073 theFrame->SetStatusText(wxT(""), element+1);
1076 wxMutexGuiLeave();
1079 // ::FLUSH()
1081 // Called periodically, requesting that the gui code flush all pending
1082 // screen update requests.
1084 void bx_wx_gui_c::flush(void)
1088 // ::CLEAR_SCREEN()
1090 // Called to request that the VGA region is cleared. Don't
1091 // clear the area that defines the headerbar.
1093 void bx_wx_gui_c::clear_screen(void)
1095 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::clear_screen trying to get lock. wxScreen=%p", wxScreen)));
1096 wxCriticalSectionLocker lock(wxScreen_lock);
1097 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::clear_screen got lock. wxScreen=%p", wxScreen)));
1098 memset(wxScreen, 0, wxScreenX * wxScreenY * 3);
1099 thePanel->MyRefresh ();
1102 static void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height)
1104 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::UpdateScreen trying to get lock. wxScreen=%p", wxScreen)));
1105 wxCriticalSectionLocker lock(wxScreen_lock);
1106 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::UpdateScreen got lock. wxScreen=%p", wxScreen)));
1107 if(wxScreen != NULL) {
1108 switch (vga_bpp) {
1109 case 8: /* 8 bpp */
1110 for(int i = 0; i < height; i++) {
1111 char *pwxScreen = &wxScreen[(y * wxScreenX * 3) + (x * 3)];
1112 for(int c = 0; c < width; c++) {
1113 unsigned pixel = (i * width) + c;
1114 pwxScreen[0] = wxBochsPalette[newBits[pixel]].red;
1115 pwxScreen[1] = wxBochsPalette[newBits[pixel]].green;
1116 pwxScreen[2] = wxBochsPalette[newBits[pixel]].blue;
1117 pwxScreen += 3;
1119 y++;
1120 if(y >= wxScreenY) break;
1122 break;
1123 default:
1124 BX_PANIC(("%u bpp modes handled by new graphics API", vga_bpp));
1125 return;
1127 } else {
1128 IFDBG_VGA (wxLogDebug (wxT ("UpdateScreen with null wxScreen")));
1132 static void DrawBochsBitmap(int x, int y, int width, int height, char *bmap, char color, int fontx, int fonty, bx_bool gfxchar)
1134 static unsigned char newBits[9 * 32];
1135 unsigned char mask;
1136 int bytes = width * height;
1137 char bgcolor = DEV_vga_get_actl_pal_idx((color >> 4) & 0xF);
1138 char fgcolor = DEV_vga_get_actl_pal_idx(color & 0xF);
1140 if (y > wxScreenY) return;
1142 for(int i = 0; i < bytes; i+=width) {
1143 mask = 0x80 >> fontx;
1144 for(int j = 0; j < width; j++) {
1145 if (mask > 0) {
1146 newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
1147 } else {
1148 if (gfxchar) {
1149 newBits[i + j] = (bmap[fonty] & 0x01) ? fgcolor : bgcolor;
1150 } else {
1151 newBits[i + j] = bgcolor;
1154 mask >>= 1;
1156 fonty++;
1158 UpdateScreen(newBits, x, y, width, height);
1162 // ::TEXT_UPDATE()
1164 // Called in a VGA text mode, to update the screen with
1165 // new content.
1167 // old_text: array of character/attributes making up the contents
1168 // of the screen from the last call. See below
1169 // new_text: array of character/attributes making up the current
1170 // contents, which should now be displayed. See below
1172 // format of old_text & new_text: each is tm_info.line_offset*text_rows
1173 // bytes long. Each character consists of 2 bytes. The first by is
1174 // the character value, the second is the attribute byte.
1176 // cursor_x: new x location of cursor
1177 // cursor_y: new y location of cursor
1178 // tm_info: this structure contains information for additional
1179 // features in text mode (cursor shape, line offset,...)
1181 void bx_wx_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
1182 unsigned long cursor_x, unsigned long cursor_y,
1183 bx_vga_tminfo_t tm_info)
1185 IFDBG_VGA(wxLogDebug (wxT ("text_update")));
1187 Bit8u *old_line, *new_line, *text_base;
1188 Bit8u cAttr, cChar;
1189 unsigned int curs, hchars, offset, rows, x, y, xc, yc, yc2, cs_y;
1190 Bit8u cfwidth, cfheight, cfheight2, font_col, font_row, font_row2;
1191 Bit8u split_textrow, split_fontrows;
1192 bx_bool forceUpdate = 0, gfxchar, split_screen, blink_state, blink_mode;
1194 // first check if the screen needs to be redrawn completely
1195 blink_mode = (tm_info.blink_flags & BX_TEXT_BLINK_MODE) > 0;
1196 blink_state = (tm_info.blink_flags & BX_TEXT_BLINK_STATE) > 0;
1197 if (blink_mode) {
1198 if (tm_info.blink_flags & BX_TEXT_BLINK_TOGGLE)
1199 forceUpdate = 1;
1201 if(charmap_updated) {
1202 forceUpdate = 1;
1203 charmap_updated = 0;
1205 if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {
1206 forceUpdate = 1;
1207 h_panning = tm_info.h_panning;
1208 v_panning = tm_info.v_panning;
1210 if(tm_info.line_compare != line_compare) {
1211 forceUpdate = 1;
1212 line_compare = tm_info.line_compare;
1215 // invalidate character at previous and new cursor location
1216 if((wxCursorY < text_rows) && (wxCursorX < text_cols)) {
1217 curs = wxCursorY * tm_info.line_offset + wxCursorX * 2;
1218 old_text[curs] = ~new_text[curs];
1220 if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < wxFontY) &&
1221 (cursor_y < text_rows) && (cursor_x < text_cols)) {
1222 curs = cursor_y * tm_info.line_offset + cursor_x * 2;
1223 old_text[curs] = ~new_text[curs];
1224 } else {
1225 curs = 0xffff;
1228 rows = text_rows;
1229 if (v_panning) rows++;
1230 y = 0;
1231 cs_y = 0;
1232 text_base = new_text - tm_info.start_address;
1233 split_textrow = (line_compare + v_panning) / wxFontY;
1234 split_fontrows = ((line_compare + v_panning) % wxFontY) + 1;
1235 split_screen = 0;
1236 do {
1237 hchars = text_cols;
1238 if (h_panning) hchars++;
1239 if (split_screen) {
1240 yc = line_compare + cs_y * wxFontY + 1;
1241 font_row = 0;
1242 if (rows == 1) {
1243 cfheight = (wxScreenY - line_compare - 1) % wxFontY;
1244 if (cfheight == 0) cfheight = wxFontY;
1245 } else {
1246 cfheight = wxFontY;
1248 } else if (v_panning) {
1249 if (y == 0) {
1250 yc = 0;
1251 font_row = v_panning;
1252 cfheight = wxFontY - v_panning;
1253 } else {
1254 yc = y * wxFontY - v_panning;
1255 font_row = 0;
1256 if (rows == 1) {
1257 cfheight = v_panning;
1258 } else {
1259 cfheight = wxFontY;
1262 } else {
1263 yc = y * wxFontY;
1264 font_row = 0;
1265 cfheight = wxFontY;
1267 if (!split_screen && (y == split_textrow)) {
1268 if (split_fontrows < cfheight) cfheight = split_fontrows;
1270 new_line = new_text;
1271 old_line = old_text;
1272 x = 0;
1273 offset = cs_y * tm_info.line_offset;
1274 do {
1275 if (h_panning) {
1276 if (hchars > text_cols) {
1277 xc = 0;
1278 font_col = h_panning;
1279 cfwidth = wxFontX - h_panning;
1280 } else {
1281 xc = x * wxFontX - h_panning;
1282 font_col = 0;
1283 if (hchars == 1) {
1284 cfwidth = h_panning;
1285 } else {
1286 cfwidth = wxFontX;
1289 } else {
1290 xc = x * wxFontX;
1291 font_col = 0;
1292 cfwidth = wxFontX;
1294 if(forceUpdate || (old_text[0] != new_text[0])
1295 || (old_text[1] != new_text[1])) {
1296 cChar = new_text[0];
1297 if (blink_mode) {
1298 cAttr = new_text[1] & 0x7F;
1299 if (!blink_state && (new_text[1] & 0x80))
1300 cAttr = (cAttr & 0x70) | (cAttr >> 4);
1301 } else {
1302 cAttr = new_text[1];
1304 gfxchar = tm_info.line_graphics && ((cChar & 0xE0) == 0xC0);
1305 DrawBochsBitmap(xc, yc, cfwidth, cfheight, (char *)&vga_charmap[cChar<<5],
1306 cAttr, font_col, font_row, gfxchar);
1307 if (offset == curs) {
1308 if (font_row == 0) {
1309 yc2 = yc + tm_info.cs_start;
1310 font_row2 = tm_info.cs_start;
1311 cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
1312 } else {
1313 if (v_panning > tm_info.cs_start) {
1314 yc2 = yc;
1315 font_row2 = font_row;
1316 cfheight2 = tm_info.cs_end - v_panning + 1;
1317 } else {
1318 yc2 = yc + tm_info.cs_start - v_panning;
1319 font_row2 = tm_info.cs_start;
1320 cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
1323 cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
1324 DrawBochsBitmap(xc, yc2, cfwidth, cfheight2, (char *)&vga_charmap[cChar<<5],
1325 cAttr, font_col, font_row2, gfxchar);
1328 x++;
1329 new_text+=2;
1330 old_text+=2;
1331 offset+=2;
1332 } while (--hchars);
1333 if (!split_screen && (y == split_textrow)) {
1334 new_text = text_base;
1335 forceUpdate = 1;
1336 cs_y = 0;
1337 if (tm_info.split_hpanning) h_panning = 0;
1338 rows = ((wxScreenY - line_compare + wxFontY - 2) / wxFontY) + 1;
1339 split_screen = 1;
1340 } else {
1341 y++;
1342 cs_y++;
1343 new_text = new_line + tm_info.line_offset;
1344 old_text = old_line + tm_info.line_offset;
1346 } while (--rows);
1348 h_panning = tm_info.h_panning;
1349 wxCursorX = cursor_x;
1350 wxCursorY = cursor_y;
1352 thePanel->MyRefresh();
1355 // ::PALETTE_CHANGE()
1357 // Allocate a color in the native GUI, for this color, and put
1358 // it in the colormap location 'index'.
1359 // returns: 0=no screen update needed (color map change has direct effect)
1360 // 1=screen update needed (redraw using current colormap)
1362 bx_bool bx_wx_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
1364 IFDBG_VGA(wxLogDebug (wxT ("palette_change")));
1365 wxBochsPalette[index].red = red;
1366 wxBochsPalette[index].green = green;
1367 wxBochsPalette[index].blue = blue;
1368 return(1); // screen update needed
1372 // ::GRAPHICS_TILE_UPDATE()
1374 // Called to request that a tile of graphics be drawn to the
1375 // screen, since info in this region has changed.
1377 // tile: array of 8bit values representing a block of pixels with
1378 // dimension equal to the 'tilewidth' & 'tileheight' parameters to
1379 // ::specific_init(). Each value specifies an index into the
1380 // array of colors you allocated for ::palette_change()
1381 // x0: x origin of tile
1382 // y0: y origin of tile
1384 // note: origin of tile and of window based on (0,0) being in the upper
1385 // left of the window.
1387 void bx_wx_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
1389 IFDBG_VGA (wxLogDebug (wxT ("graphics_tile_update")));
1390 UpdateScreen(tile, x0, y0, wxTileX, wxTileY);
1391 thePanel->MyRefresh();
1394 bx_svga_tileinfo_t *bx_wx_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info)
1396 if (!info) {
1397 info = (bx_svga_tileinfo_t *)malloc(sizeof(bx_svga_tileinfo_t));
1398 if (!info) {
1399 return NULL;
1403 info->bpp = 24;
1404 info->pitch = wxScreenX * 3;
1405 info->red_shift = 8;
1406 info->green_shift = 16;
1407 info->blue_shift = 24;
1408 info->red_mask = 0x0000ff;
1409 info->green_mask = 0x00ff00;
1410 info->blue_mask = 0xff0000;
1411 info->is_indexed = 0;
1412 #ifdef BX_LITTLE_ENDIAN
1413 info->is_little_endian = 1;
1414 #else
1415 info->is_little_endian = 0;
1416 #endif
1418 return info;
1421 Bit8u *bx_wx_gui_c::graphics_tile_get(unsigned x0, unsigned y0,
1422 unsigned *w, unsigned *h)
1424 if (x0+wxTileX > (unsigned)wxScreenX) {
1425 *w = wxScreenX - x0;
1427 else {
1428 *w = wxTileX;
1431 if (y0+wxTileY > (unsigned)wxScreenY) {
1432 *h = wxScreenY - y0;
1434 else {
1435 *h = wxTileY;
1438 return (Bit8u *)wxScreen + y0 * wxScreenX * 3 + x0 * 3;
1441 void bx_wx_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,
1442 unsigned w, unsigned h)
1444 thePanel->MyRefresh();
1447 // ::DIMENSION_UPDATE()
1449 // Called from the simulator when the VGA mode changes it's X,Y dimensions.
1450 // Resize the window to this size, but you need to add on
1451 // the height of the headerbar to the Y value.
1453 // x: new VGA x size
1454 // y: new VGA y size
1455 // fheight: new VGA character height in text mode
1456 // fwidth : new VGA character width in text mode
1457 // bpp : bits per pixel in graphics mode
1459 void bx_wx_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
1461 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::dimension_update trying to get lock. wxScreen=%p", wxScreen)));
1462 wxScreen_lock.Enter ();
1463 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::dimension_update got lock. wxScreen=%p", wxScreen)));
1464 BX_INFO (("dimension update x=%d y=%d fontheight=%d fontwidth=%d bpp=%d", x, y, fheight, fwidth, bpp));
1465 if ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32)) {
1466 if (bpp == 32) BX_INFO(("wxWidgets ignores bit 24..31 in 32bpp mode"));
1467 vga_bpp = bpp;
1469 else
1471 BX_PANIC(("%d bpp graphics mode not supported", bpp));
1473 if (fheight > 0) {
1474 wxFontX = fwidth;
1475 wxFontY = fheight;
1476 text_cols = x / wxFontX;
1477 text_rows = y / wxFontY;
1479 wxScreenX = x;
1480 wxScreenY = y;
1481 wxScreen = (char *)realloc(wxScreen, wxScreenX * wxScreenY * 3);
1482 wxASSERT (wxScreen != NULL);
1483 wxScreen_lock.Leave ();
1484 IFDBG_VGA(wxLogDebug (wxT ("MyPanel::dimension_update gave up lock. wxScreen=%p", wxScreen)));
1485 // Note: give up wxScreen_lock before calling SetClientSize. I did
1486 // this because I was sometimes seeing thread deadlock in win32, apparantly
1487 // related to wxStreen_lock. The wxWidgets GUI thread was sitting in OnPaint
1488 // trying to get the wxScreen_lock, and the simulation thread was stuck in some
1489 // native win32 function called by SetClientSize (below). As with many
1490 // thread problems, it happened sporadically so it's hard to prove that this
1491 // really fixed it. -bbd
1493 // this method is called from the simulation thread, so we must get the GUI
1494 // thread mutex first to be safe.
1495 wxMutexGuiEnter();
1496 theFrame->SetClientSize(wxScreenX, wxScreenY);
1497 theFrame->Layout();
1498 wxMutexGuiLeave();
1499 thePanel->MyRefresh();
1500 wxScreenCheckSize = 1;
1504 // ::CREATE_BITMAP()
1506 // Create a monochrome bitmap of size 'xdim' by 'ydim', which will
1507 // be drawn in the headerbar. Return an integer ID to the bitmap,
1508 // with which the bitmap can be referenced later.
1510 // bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
1511 // bit0 is the left most pixel, bit7 is the right most pixel.
1512 // xdim: x dimension of bitmap
1513 // ydim: y dimension of bitmap
1515 unsigned bx_wx_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
1517 UNUSED(bmap);
1518 UNUSED(xdim);
1519 UNUSED(ydim);
1520 return(0);
1524 // ::HEADERBAR_BITMAP()
1526 // Called to install a bitmap in the bochs headerbar (toolbar).
1528 // bmap_id: will correspond to an ID returned from
1529 // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
1530 // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
1531 // available leftmost or rightmost space.
1532 // alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
1533 // meaning install the bitmap in the next
1534 // available leftmost or rightmost space.
1535 // f: a 'C' function pointer to callback when the mouse is clicked in
1536 // the boundaries of this bitmap.
1538 unsigned bx_wx_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
1540 UNUSED(bmap_id);
1541 UNUSED(alignment);
1542 UNUSED(f);
1543 return(0);
1546 // ::SHOW_HEADERBAR()
1548 // Show (redraw) the current headerbar, which is composed of
1549 // currently installed bitmaps.
1551 void bx_wx_gui_c::show_headerbar(void)
1555 // ::REPLACE_BITMAP()
1557 // Replace the bitmap installed in the headerbar ID slot 'hbar_id',
1558 // with the one specified by 'bmap_id'. 'bmap_id' will have
1559 // been generated by ::create_bitmap(). The old and new bitmap
1560 // must be of the same size. This allows the bitmap the user
1561 // sees to change, when some action occurs. For example when
1562 // the user presses on the floppy icon, it then displays
1563 // the ejected status.
1565 // hbar_id: headerbar slot ID
1566 // bmap_id: bitmap ID
1568 void
1569 bx_wx_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
1571 UNUSED(hbar_id);
1572 UNUSED(bmap_id);
1576 // ::EXIT()
1578 // Called before bochs terminates, to allow for a graceful
1579 // exit from the native GUI mechanism.
1581 void bx_wx_gui_c::exit(void)
1583 clear_screen();
1586 void bx_wx_gui_c::mouse_enabled_changed_specific(bx_bool val)
1588 mouse_captured = val;
1591 int bx_wx_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
1593 int ret = 0;
1594 wxMutexGuiEnter();
1595 if (wxTheClipboard->Open()) {
1596 if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
1597 wxTextDataObject data;
1598 wxTheClipboard->GetData(data);
1599 wxString str = data.GetText();
1600 int len = str.Len();
1601 Bit8u *buf = new Bit8u[len];
1602 memcpy(buf, str.mb_str(wxConvUTF8), len);
1603 *bytes = buf;
1604 *nbytes = len;
1605 ret = 1;
1606 // buf will be freed in bx_keyb_c::paste_bytes or
1607 // bx_keyb_c::service_paste_buf, using delete [].
1608 } else {
1609 BX_ERROR (("paste: could not open wxWidgets clipboard"));
1611 wxTheClipboard->Close();
1613 wxMutexGuiLeave();
1614 return ret;
1617 int bx_wx_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
1619 wxMutexGuiEnter();
1620 int ret = 0;
1621 if (wxTheClipboard->Open()) {
1622 wxString string(text_snapshot, wxConvUTF8, len);
1623 wxTheClipboard->SetData(new wxTextDataObject (string));
1624 wxTheClipboard->Close();
1625 ret = 1;
1627 wxMutexGuiLeave();
1628 return ret;
1631 #if BX_SHOW_IPS
1632 void bx_wx_gui_c::show_ips(Bit32u ips_count)
1634 char ips_text[40];
1635 wxMutexGuiEnter();
1636 sprintf(ips_text, "IPS: %9u", ips_count);
1637 theFrame->SetStatusText(wxString(ips_text, wxConvUTF8), 0);
1638 wxMutexGuiLeave();
1640 #endif
1642 #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__)
1643 /* we can use the X keysyms for GTK too */
1644 #include <X11/Xlib.h>
1645 #include <X11/keysym.h>
1646 /* convertStringToGDKKey is a keymap callback
1647 * used when reading the keymap file.
1648 * It converts a Symblic String to a GUI Constant
1650 * It returns a Bit32u constant or BX_KEYMAP_UNKNOWN if it fails
1652 static Bit32u convertStringToGDKKey (const char *string)
1654 if (strncmp ("XK_", string, 3) != 0)
1655 return BX_KEYMAP_UNKNOWN;
1656 KeySym keysym=XStringToKeysym(string+3);
1658 // failure, return unknown
1659 if(keysym==NoSymbol) return BX_KEYMAP_UNKNOWN;
1661 return((Bit32u)keysym);
1663 #endif
1665 #endif /* if BX_WITH_WX */