- added instructions how to update the online documentation
[bochs-mirror.git] / gui / win32.cc
blobd9d563eb411bf8a3071d01e13f5681f10fe7526c
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: win32.cc,v 1.121 2008/10/06 22:00:11 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 // Much of this file was written by:
29 // David Ross
30 // dross@pobox.com
32 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
33 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
34 // is used to know when we are exporting symbols and when we are importing.
35 #define BX_PLUGGABLE
37 #include "bochs.h"
38 #include "iodev/iodev.h"
39 #if BX_WITH_WIN32
41 #include "zmouse.h"
42 #include "win32dialog.h"
43 #include "win32res.h"
44 #include "font/vga.bitmap.h"
45 // windows.h is included by bochs.h
46 #include <commctrl.h>
47 #include <process.h>
49 class bx_win32_gui_c : public bx_gui_c {
50 public:
51 bx_win32_gui_c (void) {}
52 DECLARE_GUI_VIRTUAL_METHODS();
53 virtual void statusbar_setitem(int element, bx_bool active, bx_bool w=0);
54 virtual void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp);
55 virtual void set_tooltip(unsigned hbar_id, const char *tip);
56 #if BX_SHOW_IPS
57 virtual void show_ips(Bit32u ips_count);
58 #endif
61 // declare one instance of the gui object and call macro to insert the
62 // plugin code
63 static bx_win32_gui_c *theGui = NULL;
64 IMPLEMENT_GUI_PLUGIN_CODE(win32)
66 #define LOG_THIS theGui->
68 #define EXIT_GUI_SHUTDOWN 1
69 #define EXIT_GMH_FAILURE 2
70 #define EXIT_FONT_BITMAP_ERROR 3
71 #define EXIT_NORMAL 4
72 #define EXIT_HEADER_BITMAP_ERROR 5
74 #ifndef TBSTYLE_FLAT
75 #define TBSTYLE_FLAT 0x0800
76 #endif
78 /* FIXME: Should we add a bochsrc option to control the font usage? */
79 #define BX_USE_WINDOWS_FONTS 0
81 // Keyboard/mouse stuff
82 #define SCANCODE_BUFSIZE 20
83 #define MOUSE_PRESSED 0x20000000
84 #define HEADERBAR_CLICKED 0x08000000
85 #define MOUSE_MOTION 0x22000000
86 #define BX_SYSKEY (KF_UP|KF_REPEAT|KF_ALTDOWN)
87 void enq_key_event(Bit32u, Bit32u);
88 void enq_mouse_event(void);
90 struct QueueEvent {
91 Bit32u key_event;
92 int mouse_x;
93 int mouse_y;
94 int mouse_z;
95 int mouse_button_state;
97 QueueEvent* deq_key_event(void);
99 static QueueEvent keyevents[SCANCODE_BUFSIZE];
100 static unsigned head=0, tail=0;
101 static int mouse_button_state = 0;
102 static int ms_xdelta=0, ms_ydelta=0, ms_zdelta=0;
103 static int ms_lastx=0, ms_lasty=0;
104 static int ms_savedx=0, ms_savedy=0;
105 static BOOL mouseCaptureMode, mouseCaptureNew, mouseToggleReq;
106 static unsigned long workerThread = 0;
107 static DWORD workerThreadID = 0;
108 static int mouse_buttons = 3;
110 // Graphics screen stuff
111 static unsigned x_tilesize = 0, y_tilesize = 0;
112 static BITMAPINFO* bitmap_info=(BITMAPINFO*)0;
113 static RGBQUAD* cmap_index; // indeces into system colormap
114 static HBITMAP MemoryBitmap = NULL;
115 static HDC MemoryDC = NULL;
116 static RECT updated_area;
117 static BOOL updated_area_valid = FALSE;
118 static HWND desktopWindow;
119 static RECT desktop;
120 static BOOL queryFullScreen = FALSE;
121 static int desktop_x, desktop_y;
122 static BOOL toolbarVisible, statusVisible;
124 // Text mode screen stuff
125 static unsigned prev_cursor_x = 0;
126 static unsigned prev_cursor_y = 0;
127 static HBITMAP vgafont[256];
128 static int xChar = 8, yChar = 16;
129 static unsigned int text_rows=25, text_cols=80;
130 static Bit8u text_pal_idx[16];
131 #if !BX_USE_WINDOWS_FONTS
132 static Bit8u h_panning = 0, v_panning = 0;
133 static Bit16u line_compare = 1023;
134 #else
135 static HFONT hFont[3];
136 static int FontId = 2;
137 #endif
139 // Headerbar stuff
140 HWND hwndTB, hwndSB;
141 unsigned bx_bitmap_entries;
142 struct {
143 HBITMAP bmap;
144 unsigned xdim;
145 unsigned ydim;
146 } bx_bitmaps[BX_MAX_PIXMAPS];
148 static struct {
149 unsigned bmap_id;
150 void (*f)(void);
151 const char *tooltip;
152 } bx_headerbar_entry[BX_MAX_HEADERBAR_ENTRIES];
154 static int bx_headerbar_entries;
155 static unsigned bx_hb_separator;
157 // Status Bar stuff
158 #if BX_SHOW_IPS
159 static BOOL ipsUpdate = FALSE;
160 static char ipsText[20];
161 #define BX_SB_TEXT_ELEMENTS 2
162 #else
163 #define BX_SB_TEXT_ELEMENTS 1
164 #endif
165 #define SIZE_OF_SB_ELEMENT 40
166 #define SIZE_OF_SB_MOUSE_MESSAGE 170
167 #define SIZE_OF_SB_IPS_MESSAGE 90
168 long SB_Edges[BX_MAX_STATUSITEMS+BX_SB_TEXT_ELEMENTS+1];
169 char SB_Text[BX_MAX_STATUSITEMS][10];
170 bx_bool SB_Active[BX_MAX_STATUSITEMS];
171 bx_bool SB_ActiveW[BX_MAX_STATUSITEMS];
173 // Misc stuff
174 static unsigned dimension_x, dimension_y, current_bpp;
175 static unsigned stretched_x, stretched_y;
176 static unsigned stretch_factor=1;
177 static BOOL BxTextMode = TRUE;
178 static BOOL legacyF12 = FALSE;
179 static BOOL fix_size = FALSE;
180 #if BX_DEBUGGER
181 static BOOL windebug = FALSE;
182 #endif
183 static HWND hotKeyReceiver = NULL;
184 static HWND saveParent = NULL;
186 static char *szMouseEnable = "CTRL + 3rd button enables mouse ";
187 static char *szMouseDisable = "CTRL + 3rd button disables mouse";
188 static char *szMouseTooltip = "Enable mouse capture\nUse CTRL + 3rd button to release";
190 static char szAppName[] = "Bochs for Windows";
191 static char szWindowName[] = "Bochs for Windows - Display";
193 typedef struct {
194 HINSTANCE hInstance;
196 CRITICAL_SECTION drawCS;
197 CRITICAL_SECTION keyCS;
198 CRITICAL_SECTION mouseCS;
200 int kill; // reason for terminateEmul(int)
201 BOOL UIinited;
202 HWND mainWnd;
203 HWND simWnd;
204 } sharedThreadInfo;
206 sharedThreadInfo stInfo;
208 LRESULT CALLBACK mainWndProc (HWND, UINT, WPARAM, LPARAM);
209 LRESULT CALLBACK simWndProc (HWND, UINT, WPARAM, LPARAM);
210 VOID CDECL UIThread(PVOID);
211 void SetStatusText(int Num, const char *Text, bx_bool active, bx_bool w=0);
212 void terminateEmul(int);
213 void create_vga_font(void);
214 static unsigned char reverse_bitorder(unsigned char);
215 void DrawBitmap (HDC, HBITMAP, int, int, int, int, int, int, DWORD, unsigned char);
216 void DrawChar (HDC, unsigned char, int, int, unsigned char cColor, int, int);
217 void updateUpdated(int,int,int,int);
218 static void headerbar_click(int x);
219 #if BX_USE_WINDOWS_FONTS
220 void InitFont(void);
221 void DestroyFont(void);
222 #endif
225 Bit32u win32_to_bx_key[2][0x100] =
227 { /* normal-keys */
228 /* 0x00 - 0x0f */
230 BX_KEY_ESC,
231 BX_KEY_1,
232 BX_KEY_2,
233 BX_KEY_3,
234 BX_KEY_4,
235 BX_KEY_5,
236 BX_KEY_6,
237 BX_KEY_7,
238 BX_KEY_8,
239 BX_KEY_9,
240 BX_KEY_0,
241 BX_KEY_MINUS,
242 BX_KEY_EQUALS,
243 BX_KEY_BACKSPACE,
244 BX_KEY_TAB,
245 /* 0x10 - 0x1f */
246 BX_KEY_Q,
247 BX_KEY_W,
248 BX_KEY_E,
249 BX_KEY_R,
250 BX_KEY_T,
251 BX_KEY_Y,
252 BX_KEY_U,
253 BX_KEY_I,
254 BX_KEY_O,
255 BX_KEY_P,
256 BX_KEY_LEFT_BRACKET,
257 BX_KEY_RIGHT_BRACKET,
258 BX_KEY_ENTER,
259 BX_KEY_CTRL_L,
260 BX_KEY_A,
261 BX_KEY_S,
262 /* 0x20 - 0x2f */
263 BX_KEY_D,
264 BX_KEY_F,
265 BX_KEY_G,
266 BX_KEY_H,
267 BX_KEY_J,
268 BX_KEY_K,
269 BX_KEY_L,
270 BX_KEY_SEMICOLON,
271 BX_KEY_SINGLE_QUOTE,
272 BX_KEY_GRAVE,
273 BX_KEY_SHIFT_L,
274 BX_KEY_BACKSLASH,
275 BX_KEY_Z,
276 BX_KEY_X,
277 BX_KEY_C,
278 BX_KEY_V,
279 /* 0x30 - 0x3f */
280 BX_KEY_B,
281 BX_KEY_N,
282 BX_KEY_M,
283 BX_KEY_COMMA,
284 BX_KEY_PERIOD,
285 BX_KEY_SLASH,
286 BX_KEY_SHIFT_R,
287 BX_KEY_KP_MULTIPLY,
288 BX_KEY_ALT_L,
289 BX_KEY_SPACE,
290 BX_KEY_CAPS_LOCK,
291 BX_KEY_F1,
292 BX_KEY_F2,
293 BX_KEY_F3,
294 BX_KEY_F4,
295 BX_KEY_F5,
296 /* 0x40 - 0x4f */
297 BX_KEY_F6,
298 BX_KEY_F7,
299 BX_KEY_F8,
300 BX_KEY_F9,
301 BX_KEY_F10,
302 BX_KEY_PAUSE,
303 BX_KEY_SCRL_LOCK,
304 BX_KEY_KP_HOME,
305 BX_KEY_KP_UP,
306 BX_KEY_KP_PAGE_UP,
307 BX_KEY_KP_SUBTRACT,
308 BX_KEY_KP_LEFT,
309 BX_KEY_KP_5,
310 BX_KEY_KP_RIGHT,
311 BX_KEY_KP_ADD,
312 BX_KEY_KP_END,
313 /* 0x50 - 0x5f */
314 BX_KEY_KP_DOWN,
315 BX_KEY_KP_PAGE_DOWN,
316 BX_KEY_KP_INSERT,
317 BX_KEY_KP_DELETE,
320 BX_KEY_LEFT_BACKSLASH,
321 BX_KEY_F11,
322 BX_KEY_F12,
330 /* 0x60 - 0x6f */
347 /* 0x70 - 0x7f */
348 0, /* Todo: "Katakana" key (ibm 133) for Japanese 106 keyboard */
351 0, /* Todo: "Ro" key (ibm 56) for Japanese 106 keyboard */
357 0, /* Todo: "convert" key (ibm 132) for Japanese 106 keyboard */
359 0, /* Todo: "non-convert" key (ibm 131) for Japanese 106 keyboard */
361 0, /* Todo: "Yen" key (ibm 14) for Japanese 106 keyboard */
365 { /* extended-keys */
366 /* 0x00 - 0x0f */
383 /* 0x10 - 0x1f */
396 BX_KEY_KP_ENTER,
397 BX_KEY_CTRL_R,
400 /* 0x20 - 0x2f */
402 BX_KEY_POWER_CALC,
417 /* 0x30 - 0x3f */
420 BX_KEY_INT_HOME,
423 BX_KEY_KP_DIVIDE,
425 BX_KEY_PRINT,
426 BX_KEY_ALT_R,
434 /* 0x40 - 0x4f */
440 BX_KEY_NUM_LOCK,
442 BX_KEY_HOME,
443 BX_KEY_UP,
444 BX_KEY_PAGE_UP,
446 BX_KEY_LEFT,
448 BX_KEY_RIGHT,
450 BX_KEY_END,
451 /* 0x50 - 0x5f */
452 BX_KEY_DOWN,
453 BX_KEY_PAGE_DOWN,
454 BX_KEY_INSERT,
455 BX_KEY_DELETE,
463 BX_KEY_WIN_L,
464 BX_KEY_WIN_R,
465 BX_KEY_MENU,
466 BX_KEY_POWER_POWER,
467 BX_KEY_POWER_SLEEP,
468 /* 0x60 - 0x6f */
472 BX_KEY_POWER_WAKE,
474 BX_KEY_INT_SEARCH,
475 BX_KEY_INT_FAV,
477 BX_KEY_INT_STOP,
478 BX_KEY_INT_FORWARD,
479 BX_KEY_INT_BACK,
480 BX_KEY_POWER_MYCOMP,
481 BX_KEY_INT_MAIL,
488 /* Macro to convert WM_ button state to BX button state */
490 #if defined(__MINGW32__) || defined(_MSC_VER)
491 VOID CALLBACK MyTimer(HWND,UINT,UINT,DWORD);
492 void alarm(int);
493 #endif
495 static void processMouseXY(int x, int y, int z, int windows_state, int implied_state_change)
497 int bx_state;
498 int old_bx_state;
499 EnterCriticalSection(&stInfo.mouseCS);
500 bx_state=((windows_state & MK_LBUTTON) ? 1 : 0) + ((windows_state & MK_RBUTTON) ? 2 : 0) +
501 ((windows_state & MK_MBUTTON) ? 4 : 0);
502 old_bx_state=bx_state ^ implied_state_change;
503 if (old_bx_state!=mouse_button_state)
505 /* Make up for missing message */
506 BX_INFO(("&&&missing mouse state change"));
507 EnterCriticalSection(&stInfo.keyCS);
508 enq_mouse_event();
509 mouse_button_state=old_bx_state;
510 enq_key_event(mouse_button_state, MOUSE_PRESSED);
511 LeaveCriticalSection(&stInfo.keyCS);
513 ms_ydelta=ms_savedy-y;
514 ms_xdelta=x-ms_savedx;
515 ms_zdelta=z;
516 ms_lastx=x;
517 ms_lasty=y;
518 if (bx_state!=mouse_button_state)
520 EnterCriticalSection(&stInfo.keyCS);
521 enq_mouse_event();
522 mouse_button_state=bx_state;
523 enq_key_event(mouse_button_state, MOUSE_PRESSED);
524 LeaveCriticalSection(&stInfo.keyCS);
526 LeaveCriticalSection(&stInfo.mouseCS);
529 static void resetDelta()
531 EnterCriticalSection(&stInfo.mouseCS);
532 ms_savedx=ms_lastx;
533 ms_savedy=ms_lasty;
534 ms_ydelta=ms_xdelta=ms_zdelta=0;
535 LeaveCriticalSection(&stInfo.mouseCS);
538 static void cursorWarped()
540 EnterCriticalSection(&stInfo.mouseCS);
541 EnterCriticalSection(&stInfo.keyCS);
542 enq_mouse_event();
543 LeaveCriticalSection(&stInfo.keyCS);
544 ms_lastx=stretched_x/2;
545 ms_lasty=stretched_y/2;
546 ms_savedx=ms_lastx;
547 ms_savedy=ms_lasty;
548 LeaveCriticalSection(&stInfo.mouseCS);
551 // GUI thread must be dead/done in order to call terminateEmul
552 void terminateEmul(int reason)
554 // We know that Critical Sections were inited when x_tilesize has been set
555 // See bx_win32_gui_c::specific_init
556 if (x_tilesize != 0) {
557 DeleteCriticalSection (&stInfo.drawCS);
558 DeleteCriticalSection (&stInfo.keyCS);
559 DeleteCriticalSection (&stInfo.mouseCS);
561 x_tilesize = 0;
563 if (MemoryDC) DeleteDC (MemoryDC);
564 if (MemoryBitmap) DeleteObject (MemoryBitmap);
566 if (bitmap_info) delete[] (char*)bitmap_info;
568 for (unsigned b=0; b<bx_bitmap_entries; b++)
569 if (bx_bitmaps[b].bmap) DeleteObject(bx_bitmaps[b].bmap);
570 for (unsigned c=0; c<256; c++)
571 if (vgafont[c]) DeleteObject(vgafont[c]);
573 LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
575 switch (reason) {
576 case EXIT_GUI_SHUTDOWN:
577 BX_PANIC(("Window closed, exiting!"));
578 break;
579 case EXIT_GMH_FAILURE:
580 BX_PANIC(("GetModuleHandle failure!"));
581 break;
582 case EXIT_FONT_BITMAP_ERROR:
583 BX_PANIC(("Font bitmap creation failure!"));
584 break;
585 case EXIT_HEADER_BITMAP_ERROR:
586 BX_PANIC(("Header bitmap creation failure!"));
587 break;
588 case EXIT_NORMAL:
589 break;
594 // ::SPECIFIC_INIT()
596 // Called from gui.cc, once upon program startup, to allow for the
597 // specific GUI code (X11, BeOS, ...) to be initialized.
599 // argc, argv: not used right now, but the intention is to pass native GUI
600 // specific options from the command line. (X11 options, BeOS options,...)
602 // tilewidth, tileheight: for optimization, graphics_tile_update() passes
603 // only updated regions of the screen to the gui code to be redrawn.
604 // These define the dimensions of a region (tile).
605 // headerbar_y: A headerbar (toolbar) is display on the top of the
606 // VGA window, showing floppy status, and other information. It
607 // always assumes the width of the current VGA mode width, but
608 // it's height is defined by this parameter.
610 void bx_win32_gui_c::specific_init(int argc, char **argv, unsigned
611 tilewidth, unsigned tileheight,
612 unsigned headerbar_y)
614 int i;
616 put("WGUI");
618 // prepare for possible fullscreen mode
619 desktopWindow = GetDesktopWindow();
620 GetWindowRect(desktopWindow, &desktop);
621 desktop_x = desktop.right - desktop.left;
622 desktop_y = desktop.bottom - desktop.top;
623 hotKeyReceiver = stInfo.simWnd;
624 BX_INFO(("Desktop Window dimensions: %d x %d", desktop_x, desktop_y));
626 static RGBQUAD black_quad={ 0, 0, 0, 0};
627 stInfo.kill = 0;
628 stInfo.UIinited = FALSE;
629 InitializeCriticalSection(&stInfo.drawCS);
630 InitializeCriticalSection(&stInfo.keyCS);
631 InitializeCriticalSection(&stInfo.mouseCS);
633 x_tilesize = tilewidth;
634 y_tilesize = tileheight;
636 bx_bitmap_entries = 0;
637 bx_headerbar_entries = 0;
638 bx_hb_separator = 0;
639 mouseCaptureMode = FALSE;
640 mouseCaptureNew = FALSE;
641 mouseToggleReq = FALSE;
643 mouse_buttons = GetSystemMetrics(SM_CMOUSEBUTTONS);
644 BX_INFO(("Number of Mouse Buttons = %d", mouse_buttons));
645 if (mouse_buttons == 2) {
646 szMouseEnable = "CTRL + Lbutton + Rbutton enables mouse ";
647 szMouseDisable = "CTRL + Lbutton + Rbutton disables mouse";
648 szMouseTooltip = "Enable mouse capture\nUse CTRL + Lbutton + Rbutton to release";
651 // parse win32 specific options
652 if (argc > 1) {
653 for (i = 1; i < argc; i++) {
654 BX_INFO(("option %d: %s", i, argv[i]));
655 if (!strcmp(argv[i], "legacyF12")) {
656 legacyF12 = TRUE;
657 #if BX_DEBUGGER
658 } else if (!strcmp(argv[i], "windebug")) {
659 windebug = TRUE;
660 SIM->set_debug_gui(1);
661 #endif
662 } else {
663 BX_PANIC(("Unknown win32 option '%s'", argv[i]));
668 if (legacyF12) {
669 szMouseEnable = "Press F12 to enable mouse ";
670 szMouseDisable = "Press F12 to disable mouse";
671 szMouseTooltip = "Enable mouse capture\nUse F12 to release";
674 stInfo.hInstance = GetModuleHandle(NULL);
676 UNUSED(headerbar_y);
677 dimension_x = 640;
678 dimension_y = 480;
679 current_bpp = 8;
680 stretched_x = dimension_x;
681 stretched_y = dimension_y;
682 stretch_factor = 1;
684 for(unsigned c=0; c<256; c++) vgafont[c] = NULL;
685 create_vga_font();
687 bitmap_info=(BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER)+
688 259*sizeof(RGBQUAD)]; // 256 + 3 entries for 16 bpp mode
689 bitmap_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
690 bitmap_info->bmiHeader.biWidth=x_tilesize;
691 // Height is negative for top-down bitmap
692 bitmap_info->bmiHeader.biHeight= -(LONG)y_tilesize;
693 bitmap_info->bmiHeader.biPlanes=1;
694 bitmap_info->bmiHeader.biBitCount=8;
695 bitmap_info->bmiHeader.biCompression=BI_RGB;
696 bitmap_info->bmiHeader.biSizeImage=x_tilesize*y_tilesize*4;
697 // I think these next two figures don't matter; saying 45 pixels/centimeter
698 bitmap_info->bmiHeader.biXPelsPerMeter=4500;
699 bitmap_info->bmiHeader.biYPelsPerMeter=4500;
700 bitmap_info->bmiHeader.biClrUsed=256;
701 bitmap_info->bmiHeader.biClrImportant=0;
702 cmap_index=bitmap_info->bmiColors;
703 // start out with all color map indeces pointing to Black
704 cmap_index[0] = black_quad;
705 for (i=1; i<259; i++) {
706 cmap_index[i] = cmap_index[0];
709 if (stInfo.hInstance)
710 workerThread = _beginthread (UIThread, 0, NULL);
711 else
712 terminateEmul(EXIT_GMH_FAILURE);
714 // Wait for a window before continuing
715 if ((stInfo.kill == 0) && (FindWindow(szAppName, NULL) == NULL))
716 Sleep(500);
718 // Now set this thread's priority to below normal because this is where
719 // the emulated CPU runs, and it hogs the real CPU
720 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
722 if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get())
723 BX_INFO(("private_colormap option ignored."));
725 // load keymap tables
726 if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
727 bx_keymap.loadKeymap(NULL); // I have no function to convert X windows symbols
730 win32_init_notify_callback();
731 dialog_caps = BX_GUI_DLG_ALL;
734 void resize_main_window()
736 RECT R;
737 int toolbar_y = 0;
738 int statusbar_y = 0;
739 unsigned long mainStyle;
741 if (IsWindowVisible(hwndTB)) {
742 toolbarVisible = TRUE;
743 GetWindowRect(hwndTB, &R);
744 toolbar_y = R.bottom - R.top;
747 if (IsWindowVisible(hwndSB)) {
748 statusVisible = TRUE;
749 GetWindowRect(hwndSB, &R);
750 statusbar_y = R.bottom - R.top;
753 // stretched_x and stretched_y were set in dimension_update()
754 // if we need to do any additional resizing, do it now
755 if ((desktop_y > 0) && (stretched_y >= (unsigned)desktop_y)) {
756 if (!queryFullScreen) {
757 MessageBox(NULL,
758 "Going into fullscreen mode -- Alt-Enter to revert",
759 "Going fullscreen",
760 MB_APPLMODAL);
761 queryFullScreen = TRUE;
763 // hide toolbar and status bars to get some additional space
764 ShowWindow(hwndTB, SW_HIDE);
765 ShowWindow(hwndSB, SW_HIDE);
766 // hide title bar
767 mainStyle = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
768 mainStyle &= ~(WS_CAPTION | WS_BORDER);
769 SetWindowLong(stInfo.mainWnd, GWL_STYLE, mainStyle);
770 // maybe need to adjust stInfo.simWnd here also?
771 if (saveParent = SetParent(stInfo.mainWnd, desktopWindow)) {
772 BX_DEBUG(("Saved parent window"));
773 SetWindowPos(stInfo.mainWnd, HWND_TOPMOST, desktop.left, desktop.top,
774 desktop.right, desktop.bottom, SWP_SHOWWINDOW);
776 } else {
777 if (saveParent) {
778 BX_DEBUG(("Restoring parent window"));
779 SetParent(stInfo.mainWnd, saveParent);
780 saveParent = NULL;
782 // put back the title bar, border, etc...
783 mainStyle = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
784 mainStyle |= WS_CAPTION | WS_BORDER;
785 SetWindowLong(stInfo.mainWnd, GWL_STYLE, mainStyle);
786 if (toolbarVisible) ShowWindow(hwndTB, SW_SHOW);
787 if (statusVisible) ShowWindow(hwndSB, SW_SHOW);
788 SetRect(&R, 0, 0, stretched_x, stretched_y);
789 DWORD style = GetWindowLong(stInfo.simWnd, GWL_STYLE);
790 DWORD exstyle = GetWindowLong(stInfo.simWnd, GWL_EXSTYLE);
791 AdjustWindowRectEx(&R, style, FALSE, exstyle);
792 style = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
793 AdjustWindowRect(&R, style, FALSE);
794 SetWindowPos(stInfo.mainWnd, HWND_TOP, 0, 0, R.right - R.left,
795 R.bottom - R.top + toolbar_y + statusbar_y,
796 SWP_NOMOVE | SWP_NOZORDER);
798 fix_size = FALSE;
801 // This thread controls the GUI window.
802 VOID CDECL UIThread(PVOID pvoid)
804 MSG msg;
805 HDC hdc;
806 WNDCLASS wndclass;
807 RECT wndRect;
809 workerThreadID = GetCurrentThreadId();
811 GetClassInfo(NULL, WC_DIALOG, &wndclass);
812 wndclass.style = CS_HREDRAW | CS_VREDRAW;
813 wndclass.lpfnWndProc = mainWndProc;
814 wndclass.cbClsExtra = 0;
815 wndclass.cbWndExtra = 0;
816 wndclass.hInstance = stInfo.hInstance;
817 wndclass.hIcon = LoadIcon (stInfo.hInstance, MAKEINTRESOURCE(ICON_BOCHS));
818 wndclass.lpszMenuName = NULL;
819 wndclass.lpszClassName = szAppName;
821 RegisterClass (&wndclass);
823 wndclass.style = CS_HREDRAW | CS_VREDRAW;
824 wndclass.lpfnWndProc = simWndProc;
825 wndclass.cbClsExtra = 0;
826 wndclass.cbWndExtra = 0;
827 wndclass.hInstance = stInfo.hInstance;
828 wndclass.hIcon = NULL;
829 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
830 wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
831 wndclass.lpszMenuName = NULL;
832 wndclass.lpszClassName = "SIMWINDOW";
834 RegisterClass (&wndclass);
836 SetRect(&wndRect, 0, 0, stretched_x, stretched_y);
837 DWORD sim_style = WS_CHILD;
838 DWORD sim_exstyle = WS_EX_CLIENTEDGE;
839 AdjustWindowRectEx(&wndRect, sim_style, FALSE, sim_exstyle);
840 DWORD main_style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
841 AdjustWindowRect(&wndRect, main_style, FALSE);
842 stInfo.mainWnd = CreateWindow (szAppName,
843 szWindowName,
844 main_style,
845 CW_USEDEFAULT,
846 CW_USEDEFAULT,
847 wndRect.right - wndRect.left,
848 wndRect.bottom - wndRect.top,
849 NULL,
850 NULL,
851 stInfo.hInstance,
852 NULL);
854 if (stInfo.mainWnd) {
856 InitCommonControls();
857 hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL,
858 WS_CHILD | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0, 0, 0, 0, stInfo.mainWnd,
859 (HMENU) 100, stInfo.hInstance, NULL);
860 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
861 SendMessage(hwndTB, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(32, 32));
863 hwndSB = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "",
864 stInfo.mainWnd, 0x7712);
865 if (hwndSB) {
866 int elements;
867 SB_Edges[0] = SIZE_OF_SB_MOUSE_MESSAGE + SIZE_OF_SB_ELEMENT;
868 #if BX_SHOW_IPS
869 SB_Edges[1] = SB_Edges[0] + SIZE_OF_SB_IPS_MESSAGE;
870 #endif
871 for (elements = BX_SB_TEXT_ELEMENTS; elements < (BX_MAX_STATUSITEMS+BX_SB_TEXT_ELEMENTS); elements++)
872 SB_Edges[elements] = SB_Edges[elements-1] + SIZE_OF_SB_ELEMENT;
873 SB_Edges[elements] = -1;
874 SendMessage(hwndSB, SB_SETPARTS, BX_MAX_STATUSITEMS+BX_SB_TEXT_ELEMENTS+1, (long)&SB_Edges);
876 SetStatusText(0, szMouseEnable, TRUE);
878 stInfo.simWnd = CreateWindowEx(sim_exstyle,
879 "SIMWINDOW",
881 sim_style,
886 stInfo.mainWnd,
887 NULL,
888 stInfo.hInstance,
889 NULL);
891 /* needed for the Japanese versions of Windows */
892 if (stInfo.simWnd) {
893 HMODULE hm;
894 hm = GetModuleHandle("USER32");
895 if (hm) {
896 BOOL (WINAPI *enableime)(HWND, BOOL);
897 enableime = (BOOL (WINAPI *)(HWND, BOOL))GetProcAddress(hm, "WINNLSEnableIME");
898 if (enableime) {
899 enableime(stInfo.simWnd, FALSE);
900 BX_INFO(("IME disabled"));
905 ShowWindow(stInfo.simWnd, SW_SHOW);
906 SetFocus(stInfo.simWnd);
908 ShowCursor(!mouseCaptureMode);
909 POINT pt = { 0, 0 };
910 ClientToScreen(stInfo.simWnd, &pt);
911 SetCursorPos(pt.x + stretched_x/2, pt.y + stretched_y/2);
912 cursorWarped();
914 hdc = GetDC(stInfo.simWnd);
915 MemoryBitmap = CreateCompatibleBitmap(hdc, BX_MAX_XRES, BX_MAX_YRES);
916 MemoryDC = CreateCompatibleDC(hdc);
917 ReleaseDC(stInfo.simWnd, hdc);
919 if (MemoryBitmap && MemoryDC) {
920 resize_main_window();
921 ShowWindow(stInfo.mainWnd, SW_SHOW);
922 #if BX_DEBUGGER
923 if (windebug) {
924 InitDebugDialog(stInfo.mainWnd);
926 #endif
927 stInfo.UIinited = TRUE;
929 bx_gui->clear_screen();
931 while (GetMessage (&msg, NULL, 0, 0)) {
932 TranslateMessage (&msg);
933 DispatchMessage (&msg);
938 stInfo.kill = EXIT_GUI_SHUTDOWN;
940 _endthread();
943 void SetStatusText(int Num, const char *Text, bx_bool active, bx_bool w)
945 char StatText[MAX_PATH];
947 if ((Num < BX_SB_TEXT_ELEMENTS) || (Num > (BX_MAX_STATUSITEMS+BX_SB_TEXT_ELEMENTS))) {
948 StatText[0] = ' '; // Add space to text in 1st and last items
949 lstrcpy(StatText+1, Text);
950 SendMessage(hwndSB, SB_SETTEXT, Num, (long)StatText);
951 } else {
952 StatText[0] = 9; // Center the rest
953 lstrcpy(StatText+1, Text);
954 lstrcpy(SB_Text[Num-BX_SB_TEXT_ELEMENTS], StatText);
955 SB_Active[Num-BX_SB_TEXT_ELEMENTS] = active;
956 SB_ActiveW[Num-BX_SB_TEXT_ELEMENTS] = w;
957 SendMessage(hwndSB, SB_SETTEXT, Num | SBT_OWNERDRAW, (long)SB_Text[Num-BX_SB_TEXT_ELEMENTS]);
959 UpdateWindow(hwndSB);
962 void bx_win32_gui_c::statusbar_setitem(int element, bx_bool active, bx_bool w)
964 if (element < 0) {
965 for (int i = 0; i < (int)statusitem_count; i++) {
966 SetStatusText(i+BX_SB_TEXT_ELEMENTS, statusitem_text[i], active, w);
968 } else if (element < (int)statusitem_count) {
969 SetStatusText(element+BX_SB_TEXT_ELEMENTS, statusitem_text[element], active, w);
973 LRESULT CALLBACK mainWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
975 DRAWITEMSTRUCT *lpdis;
976 char *sbtext;
977 NMHDR *lpnmh;
978 TOOLTIPTEXT *lpttt;
979 int idTT, hbar_id;
981 switch (iMsg) {
982 case WM_CREATE:
983 SetStatusText(0, szMouseEnable, TRUE);
984 return 0;
986 case WM_COMMAND:
987 if (LOWORD(wParam) >= 101) {
988 EnterCriticalSection(&stInfo.keyCS);
989 enq_key_event(LOWORD(wParam)-101, HEADERBAR_CLICKED);
990 LeaveCriticalSection(&stInfo.keyCS);
992 break;
994 case WM_SETFOCUS:
995 SetFocus(stInfo.simWnd);
996 return 0;
998 case WM_CLOSE:
999 SendMessage(stInfo.simWnd, WM_CLOSE, 0, 0);
1000 break;
1002 case WM_DESTROY:
1003 PostQuitMessage (0);
1004 return 0;
1006 case WM_SIZE:
1008 int x, y;
1009 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
1010 SendMessage(hwndSB, WM_SIZE, 0, 0);
1011 // now fit simWindow to mainWindow
1012 int rect_data[] = { 1, 0, IsWindowVisible(hwndTB),
1013 100, IsWindowVisible(hwndSB), 0x7712, 0, 0 };
1014 RECT R;
1015 GetEffectiveClientRect(hwnd, &R, rect_data);
1016 x = R.right - R.left;
1017 y = R.bottom - R.top;
1018 MoveWindow(stInfo.simWnd, R.left, R.top, x, y, TRUE);
1019 GetClientRect(stInfo.simWnd, &R);
1020 x = R.right - R.left;
1021 y = R.bottom - R.top;
1022 if ((x != (int)stretched_x) || (y != (int)stretched_y)) {
1023 BX_ERROR(("Sim client size(%d, %d) != stretched size(%d, %d)!",
1024 x, y, stretched_x, stretched_y));
1025 if (!saveParent) fix_size = TRUE; // no fixing if fullscreen
1028 break;
1030 case WM_DRAWITEM:
1031 lpdis = (DRAWITEMSTRUCT *)lParam;
1032 if (lpdis->hwndItem == hwndSB) {
1033 sbtext = (char *)lpdis->itemData;
1034 if (SB_Active[lpdis->itemID-BX_SB_TEXT_ELEMENTS]) {
1035 if (SB_ActiveW[lpdis->itemID-BX_SB_TEXT_ELEMENTS])
1036 SetBkColor(lpdis->hDC, 0x000040FF);
1037 else
1038 SetBkColor(lpdis->hDC, 0x0000FF00);
1039 } else {
1040 SetBkMode(lpdis->hDC, TRANSPARENT);
1041 SetTextColor(lpdis->hDC, 0x00808080);
1043 DrawText(lpdis->hDC, sbtext+1, lstrlen(sbtext)-1, &lpdis->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
1044 return TRUE;
1046 break;
1048 case WM_NOTIFY:
1049 lpnmh = (LPNMHDR)lParam;
1050 if (lpnmh->code == TTN_NEEDTEXT) {
1051 lpttt = (LPTOOLTIPTEXT)lParam;
1052 idTT = (int)wParam;
1053 hbar_id = idTT - 101;
1054 if (SendMessage(hwndTB, TB_GETSTATE, idTT, 0) && bx_headerbar_entry[hbar_id].tooltip != NULL) {
1055 lstrcpy(lpttt->szText, bx_headerbar_entry[hbar_id].tooltip);
1058 return FALSE;
1059 break;
1062 return DefWindowProc(hwnd, iMsg, wParam, lParam);
1065 void SetMouseCapture()
1067 POINT pt = {0, 0};
1069 if (mouseToggleReq) {
1070 mouseCaptureMode = mouseCaptureNew;
1071 mouseToggleReq = FALSE;
1072 } else {
1073 SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set(mouseCaptureMode);
1075 ShowCursor(!mouseCaptureMode);
1076 ShowCursor(!mouseCaptureMode); // somehow one didn't do the trick (win98)
1077 ClientToScreen(stInfo.simWnd, &pt);
1078 SetCursorPos(pt.x + stretched_x/2, pt.y + stretched_y/2);
1079 cursorWarped();
1080 if (mouseCaptureMode)
1081 SetStatusText(0, szMouseDisable, TRUE);
1082 else
1083 SetStatusText(0, szMouseEnable, TRUE);
1086 LRESULT CALLBACK simWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
1088 HDC hdc, hdcMem;
1089 PAINTSTRUCT ps;
1090 POINT pt;
1091 static BOOL mouseModeChange = FALSE;
1093 switch (iMsg) {
1095 case WM_CREATE:
1096 #if BX_USE_WINDOWS_FONTS
1097 InitFont();
1098 #endif
1099 SetTimer (hwnd, 1, 330, NULL);
1100 return 0;
1102 case WM_TIMER:
1103 if (mouseToggleReq && (GetActiveWindow() == stInfo.mainWnd)) {
1104 SetMouseCapture();
1106 // If mouse escaped, bring it back
1107 if (mouseCaptureMode)
1109 pt.x = 0;
1110 pt.y = 0;
1111 ClientToScreen(hwnd, &pt);
1112 SetCursorPos(pt.x + stretched_x/2, pt.y + stretched_y/2);
1113 cursorWarped();
1115 if (fix_size) {
1116 resize_main_window();
1118 return 0;
1120 case WM_PAINT:
1121 EnterCriticalSection(&stInfo.drawCS);
1122 hdc = BeginPaint (hwnd, &ps);
1124 hdcMem = CreateCompatibleDC (hdc);
1125 SelectObject (hdcMem, MemoryBitmap);
1127 if (stretch_factor == 1) {
1128 BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top,
1129 ps.rcPaint.right - ps.rcPaint.left + 1,
1130 ps.rcPaint.bottom - ps.rcPaint.top + 1, hdcMem,
1131 ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
1132 } else {
1133 StretchBlt(hdc, ps.rcPaint.left, ps.rcPaint.top,
1134 ps.rcPaint.right - ps.rcPaint.left + 1,
1135 ps.rcPaint.bottom - ps.rcPaint.top + 1, hdcMem,
1136 ps.rcPaint.left/stretch_factor, ps.rcPaint.top,
1137 (ps.rcPaint.right - ps.rcPaint.left+1)/stretch_factor,
1138 (ps.rcPaint.bottom - ps.rcPaint.top+1), SRCCOPY);
1140 DeleteDC (hdcMem);
1141 EndPaint (hwnd, &ps);
1142 LeaveCriticalSection(&stInfo.drawCS);
1143 return 0;
1145 case WM_MOUSEMOVE:
1146 if (!mouseModeChange) {
1147 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 0);
1149 return 0;
1151 case WM_MOUSEWHEEL:
1152 if (!mouseModeChange) {
1153 // WM_MOUSEWHEEL returns x and y relative to the main screen.
1154 // WM_MOUSEMOVE below returns x and y relative to the current view.
1155 POINT pt;
1156 pt.x = LOWORD(lParam);
1157 pt.y = HIWORD(lParam);
1158 ScreenToClient(stInfo.simWnd, &pt);
1159 processMouseXY(pt.x, pt.y, (Bit16s) HIWORD(wParam) / 120, LOWORD(wParam), 0);
1161 return 0;
1163 case WM_LBUTTONDOWN:
1164 case WM_LBUTTONDBLCLK:
1165 case WM_LBUTTONUP:
1166 if (mouse_buttons == 2) {
1167 if (wParam == (MK_CONTROL | MK_LBUTTON | MK_RBUTTON)) {
1168 mouseCaptureMode = !mouseCaptureMode;
1169 SetMouseCapture();
1170 mouseModeChange = TRUE;
1171 } else if (mouseModeChange && (iMsg == WM_LBUTTONUP)) {
1172 mouseModeChange = FALSE;
1173 } else {
1174 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 1);
1176 return 0;
1178 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 1);
1179 return 0;
1181 case WM_MBUTTONDOWN:
1182 case WM_MBUTTONDBLCLK:
1183 case WM_MBUTTONUP:
1184 if (wParam == (MK_CONTROL | MK_MBUTTON)) {
1185 mouseCaptureMode = !mouseCaptureMode;
1186 SetMouseCapture();
1187 mouseModeChange = TRUE;
1188 } else if (mouseModeChange && (iMsg == WM_MBUTTONUP)) {
1189 mouseModeChange = FALSE;
1190 } else {
1191 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 4);
1193 return 0;
1195 case WM_RBUTTONDOWN:
1196 case WM_RBUTTONDBLCLK:
1197 case WM_RBUTTONUP:
1198 if (mouse_buttons == 2) {
1199 if (wParam == (MK_CONTROL | MK_LBUTTON | MK_RBUTTON)) {
1200 mouseCaptureMode = !mouseCaptureMode;
1201 SetMouseCapture();
1202 mouseModeChange = TRUE;
1203 } else if (mouseModeChange && (iMsg == WM_RBUTTONUP)) {
1204 mouseModeChange = FALSE;
1205 } else {
1206 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 2);
1208 return 0;
1210 processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 2);
1211 return 0;
1213 case WM_CLOSE:
1214 return DefWindowProc (hwnd, iMsg, wParam, lParam);
1216 case WM_DESTROY:
1217 KillTimer (hwnd, 1);
1218 stInfo.UIinited = FALSE;
1219 #if BX_USE_WINDOWS_FONTS
1220 DestroyFont();
1221 #endif
1222 return 0;
1224 case WM_KEYDOWN:
1225 case WM_SYSKEYDOWN:
1226 if (legacyF12 && (wParam == VK_F12)) {
1227 mouseCaptureMode = !mouseCaptureMode;
1228 SetMouseCapture();
1229 return 0;
1231 EnterCriticalSection(&stInfo.keyCS);
1232 enq_key_event(HIWORD (lParam) & 0x01FF, BX_KEY_PRESSED);
1233 LeaveCriticalSection(&stInfo.keyCS);
1234 return 0;
1236 case WM_KEYUP:
1237 case WM_SYSKEYUP:
1238 // check if it's keyup, alt key, non-repeat
1239 // see http://msdn2.microsoft.com/en-us/library/ms646267.aspx
1240 if ((wParam == VK_RETURN) &&
1241 ((HIWORD(lParam) & BX_SYSKEY) == (KF_ALTDOWN | KF_UP))) {
1242 if (!saveParent) {
1243 BX_INFO(("entering fullscreen mode"));
1244 theGui->dimension_update(desktop_x, desktop_y,
1245 0, 0, current_bpp);
1246 } else {
1247 BX_INFO(("leaving fullscreen mode"));
1248 theGui->dimension_update(dimension_x, desktop_y - 1,
1249 0, 0, current_bpp);
1251 } else {
1252 EnterCriticalSection(&stInfo.keyCS);
1253 enq_key_event(HIWORD (lParam) & 0x01FF, BX_KEY_RELEASED);
1254 LeaveCriticalSection(&stInfo.keyCS);
1256 return 0;
1258 case WM_SYSCHAR:
1259 // check if it's keydown, alt key, non-repeat
1260 // see http://msdn2.microsoft.com/en-us/library/ms646267.aspx
1261 if (wParam == VK_RETURN) {
1262 if ((HIWORD(lParam) & BX_SYSKEY) == KF_ALTDOWN) {
1263 if (!saveParent) {
1264 BX_INFO(("entering fullscreen mode"));
1265 theGui->dimension_update(desktop_x, desktop_y,
1266 0, 0, current_bpp);
1267 } else {
1268 BX_INFO(("leaving fullscreen mode"));
1269 theGui->dimension_update(dimension_x, desktop_y - 1,
1270 0, 0, current_bpp);
1274 case WM_CHAR:
1275 case WM_DEADCHAR:
1276 case WM_SYSDEADCHAR:
1277 return 0;
1279 return DefWindowProc (hwnd, iMsg, wParam, lParam);
1283 void enq_key_event(Bit32u key, Bit32u press_release)
1285 static BOOL alt_pressed_l = FALSE;
1286 static BOOL alt_pressed_r = FALSE;
1287 static BOOL ctrl_pressed_l = FALSE;
1288 static BOOL ctrl_pressed_r = FALSE;
1289 static BOOL shift_pressed_l = FALSE;
1290 static BOOL shift_pressed_r = FALSE;
1292 // Windows generates multiple keypresses when holding down these keys
1293 if (press_release == BX_KEY_PRESSED) {
1294 switch (key) {
1295 case 0x1d:
1296 if (ctrl_pressed_l)
1297 return;
1298 ctrl_pressed_l = TRUE;
1299 break;
1300 case 0x2a:
1301 if (shift_pressed_l)
1302 return;
1303 shift_pressed_l = TRUE;
1304 break;
1305 case 0x36:
1306 if (shift_pressed_r)
1307 return;
1308 shift_pressed_r = TRUE;
1309 break;
1310 case 0x38:
1311 if (alt_pressed_l)
1312 return;
1313 alt_pressed_l = TRUE;
1314 break;
1315 case 0x011d:
1316 if (ctrl_pressed_r)
1317 return;
1318 ctrl_pressed_r = TRUE;
1319 break;
1320 case 0x0138:
1321 if (alt_pressed_r)
1322 return;
1323 // This makes the "AltGr" key on European keyboards work
1324 if (ctrl_pressed_l) {
1325 enq_key_event(0x1d, BX_KEY_RELEASED);
1327 alt_pressed_r = TRUE;
1328 break;
1330 } else {
1331 switch (key) {
1332 case 0x1d:
1333 if (!ctrl_pressed_l)
1334 return;
1335 ctrl_pressed_l = FALSE;
1336 break;
1337 case 0x2a:
1338 shift_pressed_l = FALSE;
1339 break;
1340 case 0x36:
1341 shift_pressed_r = FALSE;
1342 break;
1343 case 0x38:
1344 alt_pressed_l = FALSE;
1345 break;
1346 case 0x011d:
1347 ctrl_pressed_r = FALSE;
1348 break;
1349 case 0x0138:
1350 alt_pressed_r = FALSE;
1351 break;
1354 if (((tail+1) % SCANCODE_BUFSIZE) == head) {
1355 BX_ERROR(("enq_scancode: buffer full"));
1356 return;
1358 keyevents[tail].key_event = key | press_release;
1359 tail = (tail + 1) % SCANCODE_BUFSIZE;
1362 void enq_mouse_event(void)
1364 EnterCriticalSection(&stInfo.mouseCS);
1365 if (ms_xdelta || ms_ydelta || ms_zdelta)
1367 if (((tail+1) % SCANCODE_BUFSIZE) == head) {
1368 BX_ERROR(("enq_scancode: buffer full"));
1369 return;
1371 QueueEvent& current=keyevents[tail];
1372 current.key_event=MOUSE_MOTION;
1373 current.mouse_x=ms_xdelta;
1374 current.mouse_y=ms_ydelta;
1375 current.mouse_z=ms_zdelta;
1376 current.mouse_button_state=mouse_button_state;
1377 resetDelta();
1378 tail = (tail + 1) % SCANCODE_BUFSIZE;
1380 LeaveCriticalSection(&stInfo.mouseCS);
1383 QueueEvent* deq_key_event(void)
1385 QueueEvent* key;
1387 if (head == tail) {
1388 BX_ERROR(("deq_scancode: buffer empty"));
1389 return((QueueEvent*)0);
1391 key = &keyevents[head];
1392 head = (head + 1) % SCANCODE_BUFSIZE;
1394 return(key);
1398 // ::HANDLE_EVENTS()
1400 // Called periodically (vga_update_interval in .bochsrc) so the
1401 // the gui code can poll for keyboard, mouse, and other
1402 // relevant events.
1404 void bx_win32_gui_c::handle_events(void)
1406 Bit32u key;
1407 Bit32u key_event;
1409 if (stInfo.kill) terminateEmul(stInfo.kill);
1411 // Handle mouse moves
1412 enq_mouse_event();
1414 // Handle keyboard and mouse clicks
1415 EnterCriticalSection(&stInfo.keyCS);
1416 while (head != tail) {
1417 QueueEvent* queue_event=deq_key_event();
1418 if (! queue_event)
1419 break;
1420 key = queue_event->key_event;
1421 if (key==MOUSE_MOTION)
1423 DEV_mouse_motion_ext(queue_event->mouse_x,
1424 queue_event->mouse_y, queue_event->mouse_z, queue_event->mouse_button_state);
1426 // Check for mouse buttons first
1427 else if (key & MOUSE_PRESSED) {
1428 DEV_mouse_motion_ext(0, 0, 0, LOWORD(key));
1430 else if (key & HEADERBAR_CLICKED) {
1431 headerbar_click(LOWORD(key));
1433 else {
1434 key_event = win32_to_bx_key[(key & 0x100) ? 1 : 0][key & 0xff];
1435 if (key & BX_KEY_RELEASED) key_event |= BX_KEY_RELEASED;
1436 DEV_kbd_gen_scancode(key_event);
1439 #if BX_SHOW_IPS
1440 if (ipsUpdate) {
1441 SetStatusText(1, ipsText, 1);
1442 ipsUpdate = FALSE;
1444 #endif
1445 LeaveCriticalSection(&stInfo.keyCS);
1449 // ::FLUSH()
1451 // Called periodically, requesting that the gui code flush all pending
1452 // screen update requests.
1454 void bx_win32_gui_c::flush(void)
1456 EnterCriticalSection(&stInfo.drawCS);
1457 if (updated_area_valid) {
1458 // slight bugfix
1459 updated_area.right++;
1460 updated_area.bottom++;
1461 InvalidateRect(stInfo.simWnd, &updated_area, FALSE);
1462 updated_area_valid = FALSE;
1464 LeaveCriticalSection(&stInfo.drawCS);
1467 // ::CLEAR_SCREEN()
1469 // Called to request that the VGA region is cleared. Don't
1470 // clear the area that defines the headerbar.
1472 void bx_win32_gui_c::clear_screen(void)
1474 HGDIOBJ oldObj;
1476 if (!stInfo.UIinited) return;
1478 EnterCriticalSection(&stInfo.drawCS);
1480 oldObj = SelectObject(MemoryDC, MemoryBitmap);
1481 PatBlt(MemoryDC, 0, 0, stretched_x, stretched_y, BLACKNESS);
1482 SelectObject(MemoryDC, oldObj);
1484 updateUpdated(0, 0, dimension_x-1, dimension_y-1);
1486 LeaveCriticalSection(&stInfo.drawCS);
1490 // ::TEXT_UPDATE()
1492 // Called in a VGA text mode, to update the screen with
1493 // new content.
1495 // old_text: array of character/attributes making up the contents
1496 // of the screen from the last call. See below
1497 // new_text: array of character/attributes making up the current
1498 // contents, which should now be displayed. See below
1500 // format of old_text & new_text: each is tm_info.line_offset*text_rows
1501 // bytes long. Each character consists of 2 bytes. The first by is
1502 // the character value, the second is the attribute byte.
1504 // cursor_x: new x location of cursor
1505 // cursor_y: new y location of cursor
1506 // tm_info: this structure contains information for additional
1507 // features in text mode (cursor shape, line offset,...)
1509 void bx_win32_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
1510 unsigned long cursor_x, unsigned long cursor_y,
1511 bx_vga_tminfo_t tm_info)
1513 HDC hdc;
1514 unsigned char data[64];
1515 Bit8u *old_line, *new_line;
1516 Bit8u cAttr, cChar;
1517 unsigned int curs, hchars, i, offset, rows, x, y, xc, yc;
1518 BOOL forceUpdate = FALSE, blink_state, blink_mode;
1519 #if !BX_USE_WINDOWS_FONTS
1520 Bit8u *text_base;
1521 Bit8u cfwidth, cfheight, cfheight2, font_col, font_row, font_row2;
1522 Bit8u split_textrow, split_fontrows;
1523 unsigned int yc2, cs_y;
1524 BOOL split_screen;
1525 #endif
1527 if (!stInfo.UIinited) return;
1529 EnterCriticalSection(&stInfo.drawCS);
1531 blink_mode = (tm_info.blink_flags & BX_TEXT_BLINK_MODE) > 0;
1532 blink_state = (tm_info.blink_flags & BX_TEXT_BLINK_STATE) > 0;
1533 if (blink_mode) {
1534 if (tm_info.blink_flags & BX_TEXT_BLINK_TOGGLE)
1535 forceUpdate = 1;
1537 if (charmap_updated) {
1538 for (unsigned c = 0; c<256; c++) {
1539 if (char_changed[c]) {
1540 memset(data, 0, sizeof(data));
1541 BOOL gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);
1542 for (i=0; i<(unsigned)yChar; i++) {
1543 data[i*2] = vga_charmap[c*32+i];
1544 if (gfxchar) {
1545 data[i*2+1] = (data[i*2] << 7);
1548 SetBitmapBits(vgafont[c], 64, data);
1549 char_changed[c] = 0;
1552 forceUpdate = TRUE;
1553 charmap_updated = 0;
1555 for (i=0; i<16; i++) {
1556 text_pal_idx[i] = DEV_vga_get_actl_pal_idx(i);
1559 hdc = GetDC(stInfo.simWnd);
1561 #if !BX_USE_WINDOWS_FONTS
1562 if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {
1563 forceUpdate = 1;
1564 h_panning = tm_info.h_panning;
1565 v_panning = tm_info.v_panning;
1567 if(tm_info.line_compare != line_compare) {
1568 forceUpdate = 1;
1569 line_compare = tm_info.line_compare;
1571 #endif
1573 // first invalidate character at previous and new cursor location
1574 if((prev_cursor_y < text_rows) && (prev_cursor_x < text_cols)) {
1575 curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;
1576 old_text[curs] = ~new_text[curs];
1578 if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < yChar) &&
1579 (cursor_y < text_rows) && (cursor_x < text_cols)) {
1580 curs = cursor_y * tm_info.line_offset + cursor_x * 2;
1581 old_text[curs] = ~new_text[curs];
1582 } else {
1583 curs = 0xffff;
1586 #if !BX_USE_WINDOWS_FONTS
1587 rows = text_rows;
1588 if (v_panning) rows++;
1589 y = 0;
1590 cs_y = 0;
1591 text_base = new_text - tm_info.start_address;
1592 split_textrow = (line_compare + v_panning) / yChar;
1593 split_fontrows = ((line_compare + v_panning) % yChar) + 1;
1594 split_screen = 0;
1595 do {
1596 hchars = text_cols;
1597 if (h_panning) hchars++;
1598 if (split_screen) {
1599 yc = line_compare + cs_y * yChar + 1;
1600 font_row = 0;
1601 if (rows == 1) {
1602 cfheight = (dimension_y - line_compare - 1) % yChar;
1603 if (cfheight == 0) cfheight = yChar;
1604 } else {
1605 cfheight = yChar;
1607 } else if (v_panning) {
1608 if (y == 0) {
1609 yc = 0;
1610 font_row = v_panning;
1611 cfheight = yChar - v_panning;
1612 } else {
1613 yc = y * yChar - v_panning;
1614 font_row = 0;
1615 if (rows == 1) {
1616 cfheight = v_panning;
1617 } else {
1618 cfheight = yChar;
1621 } else {
1622 yc = y * yChar;
1623 font_row = 0;
1624 cfheight = yChar;
1626 if (!split_screen && (y == split_textrow)) {
1627 if (split_fontrows < cfheight) cfheight = split_fontrows;
1629 new_line = new_text;
1630 old_line = old_text;
1631 x = 0;
1632 offset = cs_y * tm_info.line_offset;
1633 do {
1634 if (h_panning) {
1635 if (hchars > text_cols) {
1636 xc = 0;
1637 font_col = h_panning;
1638 cfwidth = xChar - h_panning;
1639 } else {
1640 xc = x * xChar - h_panning;
1641 font_col = 0;
1642 if (hchars == 1) {
1643 cfwidth = h_panning;
1644 } else {
1645 cfwidth = xChar;
1648 } else {
1649 xc = x * xChar;
1650 font_col = 0;
1651 cfwidth = xChar;
1653 if (forceUpdate || (old_text[0] != new_text[0])
1654 || (old_text[1] != new_text[1])) {
1655 cChar = new_text[0];
1656 if (blink_mode) {
1657 cAttr = new_text[1] & 0x7F;
1658 if (!blink_state && (new_text[1] & 0x80))
1659 cAttr = (cAttr & 0x70) | (cAttr >> 4);
1660 } else {
1661 cAttr = new_text[1];
1663 DrawBitmap(hdc, vgafont[cChar], xc, yc, cfwidth, cfheight, font_col,
1664 font_row, SRCCOPY, cAttr);
1665 if (offset == curs) {
1666 if (font_row == 0) {
1667 yc2 = yc + tm_info.cs_start;
1668 font_row2 = tm_info.cs_start;
1669 cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
1670 } else {
1671 if (v_panning > tm_info.cs_start) {
1672 yc2 = yc;
1673 font_row2 = font_row;
1674 cfheight2 = tm_info.cs_end - v_panning + 1;
1675 } else {
1676 yc2 = yc + tm_info.cs_start - v_panning;
1677 font_row2 = tm_info.cs_start;
1678 cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
1681 cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
1682 DrawBitmap(hdc, vgafont[cChar], xc, yc2, cfwidth, cfheight2, font_col,
1683 font_row2, SRCCOPY, cAttr);
1686 x++;
1687 new_text+=2;
1688 old_text+=2;
1689 offset+=2;
1690 } while (--hchars);
1691 if (!split_screen && (y == split_textrow)) {
1692 new_text = text_base;
1693 forceUpdate = 1;
1694 cs_y = 0;
1695 if (tm_info.split_hpanning) h_panning = 0;
1696 rows = ((dimension_y - line_compare + yChar - 2) / yChar) + 1;
1697 split_screen = 1;
1698 } else {
1699 y++;
1700 cs_y++;
1701 new_text = new_line + tm_info.line_offset;
1702 old_text = old_line + tm_info.line_offset;
1704 } while (--rows);
1706 h_panning = tm_info.h_panning;
1707 #else
1708 rows = text_rows;
1709 y = 0;
1710 do {
1711 hchars = text_cols;
1712 yc = y * yChar;
1713 new_line = new_text;
1714 old_line = old_text;
1715 x = 0;
1716 offset = y * tm_info.line_offset;
1717 do {
1718 xc = x * xChar;
1719 if (forceUpdate || (old_text[0] != new_text[0])
1720 || (old_text[1] != new_text[1])) {
1721 cChar = new_text[0];
1722 if (blink_mode) {
1723 cAttr = new_text[1] & 0x7F;
1724 if (!blink_state && (new_text[1] & 0x80))
1725 cAttr = (cAttr & 0x70) | (cAttr >> 4);
1726 } else {
1727 cAttr = new_text[1];
1729 DrawChar(hdc, cChar, xc, yc, cAttr, 1, 0);
1730 if (offset == curs) {
1731 DrawChar(hdc, cChar, xc, yc, cAttr, tm_info.cs_start, tm_info.cs_end);
1734 x++;
1735 new_text+=2;
1736 old_text+=2;
1737 offset+=2;
1738 } while (--hchars);
1739 y++;
1740 new_text = new_line + tm_info.line_offset;
1741 old_text = old_line + tm_info.line_offset;
1742 } while (--rows);
1743 #endif
1745 prev_cursor_x = cursor_x;
1746 prev_cursor_y = cursor_y;
1748 ReleaseDC(stInfo.simWnd, hdc);
1750 LeaveCriticalSection(&stInfo.drawCS);
1753 int bx_win32_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
1755 if (OpenClipboard(stInfo.simWnd)) {
1756 HGLOBAL hg = GetClipboardData(CF_TEXT);
1757 char *data = (char *)GlobalLock(hg);
1758 *nbytes = strlen(data);
1759 *bytes = new Bit8u[1 + *nbytes];
1760 BX_INFO (("found %d bytes on the clipboard", *nbytes));
1761 memcpy (*bytes, data, *nbytes+1);
1762 BX_INFO (("first byte is 0x%02x", *bytes[0]));
1763 GlobalUnlock(hg);
1764 CloseClipboard();
1765 return 1;
1766 // *bytes will be freed in bx_keyb_c::paste_bytes or
1767 // bx_keyb_c::service_paste_buf, using delete [].
1768 } else {
1769 BX_ERROR (("paste: could not open clipboard"));
1770 return 0;
1774 int bx_win32_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
1776 if (OpenClipboard(stInfo.simWnd)) {
1777 HANDLE hMem = GlobalAlloc(GMEM_ZEROINIT, len);
1778 EmptyClipboard();
1779 lstrcpy((char *)hMem, text_snapshot);
1780 SetClipboardData(CF_TEXT, hMem);
1781 CloseClipboard();
1782 GlobalFree(hMem);
1783 return 1;
1784 } else {
1785 BX_ERROR (("copy: could not open clipboard"));
1786 return 0;
1791 // ::PALETTE_CHANGE()
1793 // Allocate a color in the native GUI, for this color, and put
1794 // it in the colormap location 'index'.
1795 // returns: 0=no screen update needed (color map change has direct effect)
1796 // 1=screen updated needed (redraw using current colormap)
1798 bx_bool bx_win32_gui_c::palette_change(unsigned index, unsigned red,
1799 unsigned green, unsigned blue) {
1800 if ((current_bpp == 16) && (index < 3)) {
1801 cmap_index[256+index].rgbRed = red;
1802 cmap_index[256+index].rgbBlue = blue;
1803 cmap_index[256+index].rgbGreen = green;
1804 return 0;
1805 } else {
1806 cmap_index[index].rgbRed = red;
1807 cmap_index[index].rgbBlue = blue;
1808 cmap_index[index].rgbGreen = green;
1810 return(1);
1814 // ::GRAPHICS_TILE_UPDATE()
1816 // Called to request that a tile of graphics be drawn to the
1817 // screen, since info in this region has changed.
1819 // tile: array of 8bit values representing a block of pixels with
1820 // dimension equal to the 'tilewidth' & 'tileheight' parameters to
1821 // ::specific_init(). Each value specifies an index into the
1822 // array of colors you allocated for ::palette_change()
1823 // x0: x origin of tile
1824 // y0: y origin of tile
1826 // note: origin of tile and of window based on (0,0) being in the upper
1827 // left of the window.
1829 void bx_win32_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
1831 HDC hdc;
1832 HGDIOBJ oldObj;
1834 EnterCriticalSection(&stInfo.drawCS);
1835 hdc = GetDC(stInfo.simWnd);
1837 oldObj = SelectObject(MemoryDC, MemoryBitmap);
1839 StretchDIBits(MemoryDC, x0, y0, x_tilesize, y_tilesize, 0, 0,
1840 x_tilesize, y_tilesize, tile, bitmap_info, DIB_RGB_COLORS, SRCCOPY);
1842 SelectObject(MemoryDC, oldObj);
1844 updateUpdated(x0, y0, x0 + x_tilesize - 1, y0 + y_tilesize - 1);
1846 ReleaseDC(stInfo.simWnd, hdc);
1847 LeaveCriticalSection(&stInfo.drawCS);
1852 // ::DIMENSION_UPDATE()
1854 // Called when the VGA mode changes it's X,Y dimensions.
1855 // Resize the window to this size, but you need to add on
1856 // the height of the headerbar to the Y value.
1858 // x: new VGA x size
1859 // y: new VGA y size (add headerbar_y parameter from ::specific_init().
1860 // fheight: new VGA character height in text mode
1861 // fwidth : new VGA character width in text mode
1862 // bpp : bits per pixel in graphics mode
1864 void bx_win32_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
1866 BxTextMode = (fheight > 0);
1867 if (BxTextMode) {
1868 text_cols = x / fwidth;
1869 text_rows = y / fheight;
1870 #if BX_USE_WINDOWS_FONTS
1871 if (fheight >= 14) {
1872 FontId = 2;
1873 xChar = 8;
1874 yChar = 16;
1875 } else if (fheight >= 12) {
1876 FontId = 1;
1877 xChar = 8;
1878 yChar = 14;
1879 } else {
1880 FontId = 0;
1881 xChar = 8;
1882 yChar = 12;
1884 if (fwidth != xChar) {
1885 x = x * 8 / fwidth;
1887 if (fheight != yChar) {
1888 y = y * yChar / fheight;
1890 #else
1891 xChar = fwidth;
1892 yChar = fheight;
1893 #endif
1896 if (x==dimension_x && y==dimension_y && bpp==current_bpp)
1897 return;
1898 dimension_x = x;
1899 dimension_y = y;
1900 stretched_x = dimension_x;
1901 stretched_y = dimension_y;
1902 stretch_factor = 1;
1903 if (BxTextMode && (stretched_x<400)) {
1904 stretched_x *= 2;
1905 stretch_factor *= 2;
1908 bitmap_info->bmiHeader.biBitCount = bpp;
1909 if (bpp == 16)
1911 bitmap_info->bmiHeader.biCompression = BI_BITFIELDS;
1912 static RGBQUAD red_mask = {0x00, 0xF8, 0x00, 0x00};
1913 static RGBQUAD green_mask = {0xE0, 0x07, 0x00, 0x00};
1914 static RGBQUAD blue_mask = {0x1F, 0x00, 0x00, 0x00};
1915 bitmap_info->bmiColors[256] = bitmap_info->bmiColors[0];
1916 bitmap_info->bmiColors[257] = bitmap_info->bmiColors[1];
1917 bitmap_info->bmiColors[258] = bitmap_info->bmiColors[2];
1918 bitmap_info->bmiColors[0] = red_mask;
1919 bitmap_info->bmiColors[1] = green_mask;
1920 bitmap_info->bmiColors[2] = blue_mask;
1922 else
1924 if (current_bpp == 16)
1926 bitmap_info->bmiColors[0] = bitmap_info->bmiColors[256];
1927 bitmap_info->bmiColors[1] = bitmap_info->bmiColors[257];
1928 bitmap_info->bmiColors[2] = bitmap_info->bmiColors[258];
1930 bitmap_info->bmiHeader.biCompression = BI_RGB;
1931 if (bpp == 15)
1933 bitmap_info->bmiHeader.biBitCount = 16;
1936 current_bpp = bpp;
1938 resize_main_window();
1940 BX_INFO(("dimension update x=%d y=%d fontheight=%d fontwidth=%d bpp=%d", x, y, fheight, fwidth, bpp));
1942 host_xres = x;
1943 host_yres = y;
1944 host_bpp = bpp;
1948 // ::CREATE_BITMAP()
1950 // Create a monochrome bitmap of size 'xdim' by 'ydim', which will
1951 // be drawn in the headerbar. Return an integer ID to the bitmap,
1952 // with which the bitmap can be referenced later.
1954 // bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
1955 // bit0 is the left most pixel, bit7 is the right most pixel.
1956 // xdim: x dimension of bitmap
1957 // ydim: y dimension of bitmap
1959 unsigned bx_win32_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim,
1960 unsigned ydim)
1962 unsigned char *data;
1963 TBADDBITMAP tbab;
1965 if (bx_bitmap_entries >= BX_MAX_PIXMAPS)
1966 terminateEmul(EXIT_HEADER_BITMAP_ERROR);
1968 bx_bitmaps[bx_bitmap_entries].bmap = CreateBitmap(xdim,ydim,1,1,NULL);
1969 if (!bx_bitmaps[bx_bitmap_entries].bmap)
1970 terminateEmul(EXIT_HEADER_BITMAP_ERROR);
1972 data = new unsigned char[ydim * xdim/8];
1973 for (unsigned i=0; i<ydim * xdim/8; i++)
1974 data[i] = 255 - reverse_bitorder(bmap[i]);
1975 SetBitmapBits(bx_bitmaps[bx_bitmap_entries].bmap, ydim * xdim/8, data);
1976 delete [] data;
1977 data = NULL;
1979 bx_bitmaps[bx_bitmap_entries].xdim = xdim;
1980 bx_bitmaps[bx_bitmap_entries].ydim = ydim;
1982 tbab.hInst = NULL;
1983 tbab.nID = (UINT)bx_bitmaps[bx_bitmap_entries].bmap;
1984 SendMessage(hwndTB, TB_ADDBITMAP, 1, (LPARAM)&tbab);
1986 bx_bitmap_entries++;
1987 return(bx_bitmap_entries-1); // return index as handle
1991 // ::HEADERBAR_BITMAP()
1993 // Called to install a bitmap in the bochs headerbar (toolbar).
1995 // bmap_id: will correspond to an ID returned from
1996 // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
1997 // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
1998 // available leftmost or rightmost space.
1999 // alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
2000 // meaning install the bitmap in the next
2001 // available leftmost or rightmost space.
2002 // f: a 'C' function pointer to callback when the mouse is clicked in
2003 // the boundaries of this bitmap.
2005 unsigned bx_win32_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment,
2006 void (*f)(void))
2008 unsigned hb_index;
2009 TBBUTTON tbb[1];
2011 if ((bx_headerbar_entries+1) > BX_MAX_HEADERBAR_ENTRIES)
2012 terminateEmul(EXIT_HEADER_BITMAP_ERROR);
2014 bx_headerbar_entries++;
2015 hb_index = bx_headerbar_entries - 1;
2017 memset(tbb,0,sizeof(tbb));
2018 if (bx_hb_separator==0) {
2019 tbb[0].iBitmap = 0;
2020 tbb[0].idCommand = 0;
2021 tbb[0].fsState = 0;
2022 tbb[0].fsStyle = TBSTYLE_SEP;
2023 SendMessage(hwndTB, TB_ADDBUTTONS, 1,(LPARAM)(LPTBBUTTON)&tbb);
2025 tbb[0].iBitmap = bmap_id;
2026 tbb[0].idCommand = hb_index + 101;
2027 tbb[0].fsState = TBSTATE_ENABLED;
2028 tbb[0].fsStyle = TBSTYLE_BUTTON;
2029 if (alignment == BX_GRAVITY_LEFT) {
2030 SendMessage(hwndTB, TB_INSERTBUTTON, bx_hb_separator,(LPARAM)(LPTBBUTTON)&tbb);
2031 bx_hb_separator++;
2032 } else { // BX_GRAVITY_RIGHT
2033 SendMessage(hwndTB, TB_INSERTBUTTON, bx_hb_separator+1, (LPARAM)(LPTBBUTTON)&tbb);
2036 bx_headerbar_entry[hb_index].bmap_id = bmap_id;
2037 bx_headerbar_entry[hb_index].f = f;
2038 bx_headerbar_entry[hb_index].tooltip = NULL;
2040 return(hb_index);
2044 // ::SHOW_HEADERBAR()
2046 // Show (redraw) the current headerbar, which is composed of
2047 // currently installed bitmaps.
2049 void bx_win32_gui_c::show_headerbar(void)
2051 if (!IsWindowVisible(hwndTB)) {
2052 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
2053 ShowWindow(hwndTB, SW_SHOW);
2054 resize_main_window();
2055 bx_gui->set_tooltip(bx_gui->get_mouse_headerbar_id(), szMouseTooltip);
2060 // ::REPLACE_BITMAP()
2062 // Replace the bitmap installed in the headerbar ID slot 'hbar_id',
2063 // with the one specified by 'bmap_id'. 'bmap_id' will have
2064 // been generated by ::create_bitmap(). The old and new bitmap
2065 // must be of the same size. This allows the bitmap the user
2066 // sees to change, when some action occurs. For example when
2067 // the user presses on the floppy icon, it then displays
2068 // the ejected status.
2070 // hbar_id: headerbar slot ID
2071 // bmap_id: bitmap ID
2073 void bx_win32_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
2075 if (bmap_id != bx_headerbar_entry[hbar_id].bmap_id) {
2076 bx_headerbar_entry[hbar_id].bmap_id = bmap_id;
2077 bx_bool is_visible = IsWindowVisible(hwndTB);
2078 if (is_visible) {
2079 ShowWindow(hwndTB, SW_HIDE);
2081 SendMessage(hwndTB, TB_CHANGEBITMAP, (WPARAM)hbar_id+101, (LPARAM)
2082 MAKELPARAM(bmap_id, 0));
2083 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
2084 if (is_visible) {
2085 ShowWindow(hwndTB, SW_SHOW);
2091 // ::EXIT()
2093 // Called before bochs terminates, to allow for a graceful
2094 // exit from the native GUI mechanism.
2095 void bx_win32_gui_c::exit(void)
2097 printf("# In bx_win32_gui_c::exit(void)!\n");
2099 // kill thread first...
2100 PostMessage(stInfo.mainWnd, WM_CLOSE, 0, 0);
2102 // Wait until it dies
2103 while ((stInfo.kill == 0) && (workerThreadID != 0)) Sleep(500);
2105 if (!stInfo.kill) terminateEmul(EXIT_NORMAL);
2109 void create_vga_font(void)
2111 unsigned char data[64];
2113 // VGA font is 8 or 9 wide and up to 32 high
2114 for (unsigned c = 0; c<256; c++) {
2115 vgafont[c] = CreateBitmap(9,32,1,1,NULL);
2116 if (!vgafont[c]) terminateEmul(EXIT_FONT_BITMAP_ERROR);
2117 memset(data, 0, sizeof(data));
2118 for (unsigned i=0; i<16; i++)
2119 data[i*2] = reverse_bitorder(bx_vgafont[c].data[i]);
2120 SetBitmapBits(vgafont[c], 64, data);
2125 unsigned char reverse_bitorder(unsigned char b)
2127 unsigned char ret=0;
2129 for (unsigned i=0; i<8; i++) {
2130 ret |= (b & 0x01) << (7-i);
2131 b >>= 1;
2134 return(ret);
2138 COLORREF GetColorRef(unsigned char attr)
2140 Bit8u pal_idx = text_pal_idx[attr];
2141 return RGB(cmap_index[pal_idx].rgbRed, cmap_index[pal_idx].rgbGreen,
2142 cmap_index[pal_idx].rgbBlue);
2146 void DrawBitmap(HDC hdc, HBITMAP hBitmap, int xStart, int yStart, int width,
2147 int height, int fcol, int frow, DWORD dwRop, unsigned char cColor)
2149 BITMAP bm;
2150 HDC hdcMem;
2151 POINT ptSize, ptOrg;
2152 HGDIOBJ oldObj;
2154 hdcMem = CreateCompatibleDC (hdc);
2155 SelectObject (hdcMem, hBitmap);
2156 SetMapMode (hdcMem, GetMapMode (hdc));
2158 GetObject (hBitmap, sizeof (BITMAP), (LPVOID) &bm);
2160 ptSize.x = width;
2161 ptSize.y = height;
2163 DPtoLP (hdc, &ptSize, 1);
2165 ptOrg.x = fcol;
2166 ptOrg.y = frow;
2167 DPtoLP (hdcMem, &ptOrg, 1);
2169 oldObj = SelectObject(MemoryDC, MemoryBitmap);
2171 COLORREF crFore = SetTextColor(MemoryDC, GetColorRef((cColor>>4)&0xf));
2172 COLORREF crBack = SetBkColor(MemoryDC, GetColorRef(cColor&0xf));
2173 BitBlt(MemoryDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x,
2174 ptOrg.y, dwRop);
2175 SetBkColor(MemoryDC, crBack);
2176 SetTextColor(MemoryDC, crFore);
2178 SelectObject(MemoryDC, oldObj);
2180 updateUpdated(xStart, yStart, ptSize.x + xStart - 1, ptSize.y + yStart - 1);
2182 DeleteDC (hdcMem);
2186 void updateUpdated(int x1, int y1, int x2, int y2)
2188 x1*=stretch_factor;
2189 x2*=stretch_factor;
2190 if (!updated_area_valid) {
2191 updated_area.left = x1 ;
2192 updated_area.top = y1 ;
2193 updated_area.right = x2 ;
2194 updated_area.bottom = y2 ;
2195 } else {
2196 if (x1 < updated_area.left) updated_area.left = x1 ;
2197 if (y1 < updated_area.top) updated_area.top = y1 ;
2198 if (x2 > updated_area.right) updated_area.right = x2 ;
2199 if (y2 > updated_area.bottom) updated_area.bottom = y2;
2202 updated_area_valid = TRUE;
2206 void headerbar_click(int x)
2208 if (x < bx_headerbar_entries) {
2209 bx_headerbar_entry[x].f();
2213 #if defined(__MINGW32__) || defined(_MSC_VER)
2214 #if BX_SHOW_IPS
2215 VOID CALLBACK MyTimer(HWND hwnd,UINT uMsg, UINT idEvent, DWORD dwTime)
2217 bx_signal_handler(SIGALRM);
2220 void alarm(int time)
2222 UINT idTimer = 2;
2223 SetTimer(stInfo.simWnd,idTimer,time*1000,MyTimer);
2225 #endif
2226 #endif
2228 void bx_win32_gui_c::mouse_enabled_changed_specific(bx_bool val)
2230 if ((val != (bx_bool)mouseCaptureMode) && !mouseToggleReq) {
2231 mouseToggleReq = TRUE;
2232 mouseCaptureNew = val;
2236 void bx_win32_gui_c::get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp)
2238 if (desktop_y > 0) {
2239 *xres = desktop_x;
2240 *yres = desktop_y;
2241 *bpp = 32;
2242 } else {
2243 *xres = 1024;
2244 *yres = 768;
2245 *bpp = 32;
2249 void bx_win32_gui_c::set_tooltip(unsigned hbar_id, const char *tip)
2251 bx_headerbar_entry[hbar_id].tooltip = tip;
2254 #if BX_SHOW_IPS
2255 void bx_win32_gui_c::show_ips(Bit32u ips_count)
2257 if (!ipsUpdate) {
2258 sprintf(ipsText, "IPS: %9u", ips_count);
2259 ipsUpdate = TRUE;
2262 #endif
2264 #if BX_USE_WINDOWS_FONTS
2266 void DrawChar (HDC hdc, unsigned char c, int xStart, int yStart,
2267 unsigned char cColor, int cs_start, int cs_end)
2269 HDC hdcMem;
2270 POINT ptSize, ptOrg;
2271 HGDIOBJ oldObj;
2272 char str[2];
2273 HFONT hFontOld;
2275 hdcMem = CreateCompatibleDC (hdc);
2276 SetMapMode (hdcMem, GetMapMode (hdc));
2277 ptSize.x = xChar;
2278 ptSize.y = yChar;
2280 DPtoLP (hdc, &ptSize, 1);
2282 ptOrg.x = 0;
2283 ptOrg.y = 0;
2285 DPtoLP (hdcMem, &ptOrg, 1);
2287 oldObj = SelectObject(MemoryDC, MemoryBitmap);
2288 hFontOld=(HFONT)SelectObject(MemoryDC, hFont[FontId]);
2290 COLORREF crFore = SetTextColor(MemoryDC, GetColorRef(cColor&0xf));
2291 COLORREF crBack = SetBkColor(MemoryDC, GetColorRef((cColor>>4)&0xf));
2292 str[0]=c;
2293 str[1]=0;
2295 int y = FontId == 2 ? 16 : 8;
2297 TextOut(MemoryDC, xStart, yStart, str, 1);
2298 if (cs_start <= cs_end && cs_start < y)
2300 RECT rc;
2301 SetBkColor(MemoryDC, GetColorRef(cColor&0xf));
2302 SetTextColor(MemoryDC, GetColorRef((cColor>>4)&0xf));
2303 rc.left = xStart+0;
2304 rc.right = xStart+xChar;
2305 if (cs_end >= y)
2306 cs_end = y-1;
2307 rc.top = yStart+cs_start*yChar/y;
2308 rc.bottom = yStart+(cs_end+1)*yChar/y;
2309 ExtTextOut(MemoryDC, xStart, yStart, ETO_CLIPPED|ETO_OPAQUE, &rc, str, 1, NULL);
2312 SetBkColor(MemoryDC, crBack);
2313 SetTextColor(MemoryDC, crFore);
2315 SelectObject(MemoryDC, hFontOld);
2316 SelectObject(MemoryDC, oldObj);
2318 updateUpdated(xStart, yStart, ptSize.x + xStart - 1, ptSize.y + yStart - 1);
2320 DeleteDC (hdcMem);
2323 void InitFont(void)
2325 LOGFONT lf;
2327 lf.lfWidth = 8;
2328 lf.lfEscapement = 0;
2329 lf.lfOrientation = 0;
2330 lf.lfWeight = FW_MEDIUM;
2331 lf.lfItalic = FALSE;
2332 lf.lfUnderline=FALSE;
2333 lf.lfStrikeOut=FALSE;
2334 lf.lfCharSet=OEM_CHARSET;
2335 lf.lfOutPrecision=OUT_DEFAULT_PRECIS;
2336 lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;
2337 lf.lfQuality=DEFAULT_QUALITY;
2338 lf.lfPitchAndFamily=FIXED_PITCH | FF_DONTCARE;
2339 wsprintf(lf.lfFaceName, "Lucida Console");
2341 for (int i=0; i < 3; i++)
2343 lf.lfHeight = 12 + i * 2;
2344 hFont[i]=CreateFontIndirect(&lf);
2348 void DestroyFont(void)
2350 for(int i = 0; i < 3; i++)
2352 DeleteObject(hFont[i]);
2356 #endif /* if BX_USE_WINDOWS_FONTS */
2358 #endif /* if BX_WITH_WIN32 */