gui_win32.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  *  This file is based upon Bochs.
00008  *
00009  *  Copyright (C) 2002  MandrakeSoft S.A.
00010  *
00011  *    MandrakeSoft S.A.
00012  *    43, rue d'Aboukir
00013  *    75002 Paris - France
00014  *    http://www.linux-mandrake.com/
00015  *    http://www.mandrakesoft.com/
00016  *
00017  *  This library is free software; you can redistribute it and/or
00018  *  modify it under the terms of the GNU Lesser General Public
00019  *  License as published by the Free Software Foundation; either
00020  *  version 2 of the License, or (at your option) any later version.
00021  *
00022  *  This library is distributed in the hope that it will be useful,
00023  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00024  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  *  Lesser General Public License for more details.
00026  *
00027  *  You should have received a copy of the GNU Lesser General Public
00028  *  License along with this library; if not, write to the Free Software
00029  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00030  *
00031  *  Much of this file was written by:
00032  *  David Ross
00033  *  dross@pobox.com
00034  */
00035 
00059 #include "../StdAfx.h"
00060 
00061 #if defined(_WIN32)
00062 #include <process.h>
00063 
00064 #include "gui_win32_font.h"
00065 #include "keymap.h"
00066 #include "../Configurator.h"
00067 #include "../VGA.h"
00068 #include "../Keyboard.h"
00069 
00070 #include "gui.h"
00071 
00072 class bx_win32_gui_c : public bx_gui_c
00073 {
00074   public:
00075     bx_win32_gui_c(CConfigurator* cfg)
00076     {
00077       myCfg = cfg;
00078       bx_keymap = new bx_keymap_c(cfg);
00079     };
00080 
00081     virtual void  specific_init(unsigned x_tilesize, unsigned y_tilesize);
00082     virtual void  text_update(u8*  old_text, u8*  new_text,
00083                               unsigned long cursor_x, unsigned long cursor_y,
00084                               bx_vga_tminfo_t tm_info, unsigned rows);
00085     virtual void  graphics_tile_update(u8* snapshot, unsigned x, unsigned y);
00086     virtual void  handle_events(void);
00087     virtual void  flush(void);
00088     virtual void  clear_screen(void);
00089     virtual bool  palette_change(unsigned index, unsigned red, unsigned green,
00090                                  unsigned blue);
00091     virtual void  dimension_update(unsigned x, unsigned y, unsigned fheight = 0,
00092                                    unsigned fwidth = 0, unsigned bpp = 8);
00093     virtual void  mouse_enabled_changed_specific(bool val);
00094     virtual void  exit(void);
00095 
00096     virtual void  get_capabilities(u16* xres, u16* yres, u16* bpp);
00097   private:
00098     CConfigurator*  myCfg;
00099 };
00100 
00101 // declare one instance of the gui object and call macro to insert the
00102 // plugin code
00103 static bx_win32_gui_c*  theGui = NULL;
00104 IMPLEMENT_GUI_PLUGIN_CODE(win32)
00105 #define EXIT_GUI_SHUTDOWN         1
00106 #define EXIT_GMH_FAILURE          2
00107 #define EXIT_FONT_BITMAP_ERROR    3
00108 #define EXIT_NORMAL               4
00109 #define EXIT_HEADER_BITMAP_ERROR  5
00110 
00111 // Keyboard/mouse stuff
00112 #define SCANCODE_BUFSIZE  20
00113 #define MOUSE_PRESSED     0x20000000
00114 #define MOUSE_MOTION      0x22000000
00115 #define BX_SYSKEY         (KF_UP | KF_REPEAT | KF_ALTDOWN)
00116 void  enq_key_event(u32, u32);
00117 void  enq_mouse_event(void);
00118 
00119 struct QueueEvent
00120 {
00121   u32 key_event;
00122   int mouse_x;
00123   int mouse_y;
00124   int mouse_z;
00125   int mouse_button_state;
00126 };
00127 QueueEvent*           deq_key_event(void);
00128 
00129 static QueueEvent     keyevents[SCANCODE_BUFSIZE];
00130 static unsigned       head = 0, tail = 0;
00131 static int            mouse_button_state = 0;
00132 static int            ms_xdelta = 0, ms_ydelta = 0, ms_zdelta = 0;
00133 static int            ms_lastx = 0, ms_lasty = 0;
00134 static int            ms_savedx = 0, ms_savedy = 0;
00135 static BOOL           mouseCaptureMode, mouseCaptureNew, mouseToggleReq;
00136 static unsigned long  workerThread = 0;
00137 static DWORD          workerThreadID = 0;
00138 static int            mouse_buttons = 3;
00139 
00140 // Graphics screen stuff
00141 static unsigned       x_tilesize = 0, y_tilesize = 0;
00142 static BITMAPINFO*    bitmap_info = (BITMAPINFO*) 0;
00143 static RGBQUAD*       cmap_index; // indeces into system colormap
00144 static HBITMAP        MemoryBitmap = NULL;
00145 static HDC            MemoryDC = NULL;
00146 static RECT           updated_area;
00147 static BOOL           updated_area_valid = false;
00148 static HWND           desktopWindow;
00149 static RECT           desktop;
00150 static BOOL           queryFullScreen = false;
00151 static int            desktop_x, desktop_y;
00152 
00153 // Text mode screen stuff
00154 static unsigned       prev_cursor_x = 0;
00155 static unsigned       prev_cursor_y = 0;
00156 static HBITMAP        vgafont[256];
00157 static int            xChar = 8, yChar = 16;
00158 static unsigned int   text_rows = 25, text_cols = 80;
00159 static u8             text_pal_idx[16];
00160 
00161 static u8             h_panning = 0, v_panning = 0;
00162 static u16            line_compare = 1023;
00163 
00164 // Misc stuff
00165 static unsigned       dimension_x, dimension_y, current_bpp;
00166 static unsigned       stretched_x, stretched_y;
00167 static unsigned       stretch_factor = 1;
00168 static BOOL           BxTextMode = true;
00169 static BOOL           fix_size = false;
00170 static HWND           hotKeyReceiver = NULL;
00171 static HWND           saveParent = NULL;
00172 
00173 static char           szAppName[] = "ES40 Emulator";
00174 static char           szWindowName[] = "ES40 Emulator";
00175 
00176 typedef struct
00177 {
00178   HINSTANCE         hInstance;
00179 
00180   CRITICAL_SECTION  drawCS;
00181   CRITICAL_SECTION  keyCS;
00182   CRITICAL_SECTION  mouseCS;
00183 
00184   int               kill;         // reason for terminateEmul(int)
00185   BOOL              UIinited;
00186   HWND              mainWnd;
00187   HWND              simWnd;
00188 } sharedThreadInfo;
00189 
00190 sharedThreadInfo      stInfo;
00191 
00192 LRESULT CALLBACK      mainWndProc(HWND, UINT, WPARAM, LPARAM);
00193 LRESULT CALLBACK      simWndProc(HWND, UINT, WPARAM, LPARAM);
00194 VOID                  UIThread(PVOID);
00195 void                  terminateEmul(int);
00196 void                  create_vga_font(void);
00197 static unsigned char  reverse_bitorder(unsigned char);
00198 void                  DrawBitmap(HDC, HBITMAP, int, int, int, int, int, int,
00199                                  DWORD, unsigned char);
00200 void                  DrawChar(HDC, unsigned char, int, int, unsigned char cColor,
00201                                int, int);
00202 void                  updateUpdated(int, int, int, int);
00203 
00204 u32                   win32_to_bx_key[2][0x100] =
00205 {
00206   {     /* normal-keys */
00207     /* 0x00 - 0x0f */
00208     0,
00209     BX_KEY_ESC,
00210     BX_KEY_1,
00211     BX_KEY_2,
00212     BX_KEY_3,
00213     BX_KEY_4,
00214     BX_KEY_5,
00215     BX_KEY_6,
00216       BX_KEY_7,
00217       BX_KEY_8,
00218       BX_KEY_9,
00219       BX_KEY_0,
00220       BX_KEY_MINUS,
00221       BX_KEY_EQUALS,
00222         BX_KEY_BACKSPACE,
00223         BX_KEY_TAB,
00224 
00225     /* 0x10 - 0x1f */
00226     BX_KEY_Q,
00227     BX_KEY_W,
00228     BX_KEY_E,
00229     BX_KEY_R,
00230     BX_KEY_T,
00231     BX_KEY_Y,
00232     BX_KEY_U,
00233       BX_KEY_I,
00234       BX_KEY_O,
00235       BX_KEY_P,
00236       BX_KEY_LEFT_BRACKET,
00237       BX_KEY_RIGHT_BRACKET,
00238         BX_KEY_ENTER,
00239         BX_KEY_CTRL_L,
00240         BX_KEY_A,
00241         BX_KEY_S,
00242 
00243     /* 0x20 - 0x2f */
00244     BX_KEY_D,
00245     BX_KEY_F,
00246     BX_KEY_G,
00247     BX_KEY_H,
00248     BX_KEY_J,
00249     BX_KEY_K,
00250     BX_KEY_L,
00251       BX_KEY_SEMICOLON,
00252       BX_KEY_SINGLE_QUOTE,
00253       BX_KEY_GRAVE,
00254       BX_KEY_SHIFT_L,
00255         BX_KEY_BACKSLASH,
00256         BX_KEY_Z,
00257         BX_KEY_X,
00258         BX_KEY_C,
00259         BX_KEY_V,
00260 
00261     /* 0x30 - 0x3f */
00262     BX_KEY_B,
00263     BX_KEY_N,
00264     BX_KEY_M,
00265     BX_KEY_COMMA,
00266     BX_KEY_PERIOD,
00267     BX_KEY_SLASH,
00268       BX_KEY_SHIFT_R,
00269       BX_KEY_KP_MULTIPLY,
00270       BX_KEY_ALT_L,
00271       BX_KEY_SPACE,
00272         BX_KEY_CAPS_LOCK,
00273         BX_KEY_F1,
00274         BX_KEY_F2,
00275         BX_KEY_F3,
00276         BX_KEY_F4,
00277         BX_KEY_F5,
00278 
00279     /* 0x40 - 0x4f */
00280     BX_KEY_F6,
00281     BX_KEY_F7,
00282     BX_KEY_F8,
00283     BX_KEY_F9,
00284     BX_KEY_F10,
00285     BX_KEY_PAUSE,
00286       BX_KEY_SCRL_LOCK,
00287       BX_KEY_KP_HOME,
00288       BX_KEY_KP_UP,
00289       BX_KEY_KP_PAGE_UP,
00290         BX_KEY_KP_SUBTRACT,
00291         BX_KEY_KP_LEFT,
00292         BX_KEY_KP_5,
00293         BX_KEY_KP_RIGHT,
00294           BX_KEY_KP_ADD,
00295           BX_KEY_KP_END,
00296 
00297     /* 0x50 - 0x5f */
00298     BX_KEY_KP_DOWN,
00299     BX_KEY_KP_PAGE_DOWN,
00300     BX_KEY_KP_INSERT,
00301       BX_KEY_KP_DELETE,
00302       0,
00303       0,
00304       BX_KEY_LEFT_BACKSLASH,
00305       BX_KEY_F11,
00306         BX_KEY_F12,
00307         0,
00308         0,
00309         0,
00310         0,
00311         0,
00312         0,
00313         0,
00314 
00315     /* 0x60 - 0x6f */
00316     0,
00317     0,
00318     0,
00319     0,
00320     0,
00321     0,
00322     0,
00323     0,
00324     0,
00325     0,
00326     0,
00327     0,
00328     0,
00329     0,
00330     0,
00331     0,
00332 
00333     /* 0x70 - 0x7f */
00334     0,  /* Todo: "Katakana" key ( ibm 133 ) for Japanese 106 keyboard */
00335     0,
00336     0,
00337     0,  /* Todo: "Ro" key ( ibm 56 ) for Japanese 106 keyboard */
00338     0,
00339     0,
00340     0,
00341     0,
00342     0,
00343     0,  /* Todo: "convert" key ( ibm 132 ) for Japanese 106 keyboard */
00344     0,
00345     0,  /* Todo: "non-convert" key ( ibm 131 ) for Japanese 106 keyboard */
00346     0,
00347     0,  /* Todo: "Yen" key ( ibm 14 ) for Japanese 106 keyboard */
00348     0,
00349     0,
00350   },
00351   {     /* extended-keys */
00352     /* 0x00 - 0x0f */
00353     0,
00354     0,
00355     0,
00356     0,
00357     0,
00358     0,
00359     0,
00360     0,
00361     0,
00362     0,
00363     0,
00364     0,
00365     0,
00366     0,
00367     0,
00368     0,
00369 
00370     /* 0x10 - 0x1f */
00371     0,
00372     0,
00373     0,
00374     0,
00375     0,
00376     0,
00377     0,
00378     0,
00379     0,
00380     0,
00381     0,
00382     0,
00383     BX_KEY_KP_ENTER,
00384     BX_KEY_CTRL_R,
00385     0,
00386     0,
00387 
00388     /* 0x20 - 0x2f */
00389     0,
00390     BX_KEY_POWER_CALC,
00391     0,
00392     0,
00393     0,
00394     0,
00395     0,
00396     0,
00397     0,
00398     0,
00399     0,
00400     0,
00401     0,
00402     0,
00403     0,
00404     0,
00405 
00406     /* 0x30 - 0x3f */
00407     0,
00408     0,
00409     BX_KEY_INT_HOME,
00410     0,
00411     0,
00412     BX_KEY_KP_DIVIDE,
00413     0,
00414     BX_KEY_PRINT,
00415       BX_KEY_ALT_R,
00416       0,
00417       0,
00418       0,
00419       0,
00420       0,
00421       0,
00422       0,
00423 
00424     /* 0x40 - 0x4f */
00425     0,
00426     0,
00427     0,
00428     0,
00429     0,
00430     BX_KEY_NUM_LOCK,
00431     0,
00432     BX_KEY_HOME,
00433     BX_KEY_UP,
00434       BX_KEY_PAGE_UP,
00435       0,
00436       BX_KEY_LEFT,
00437       0,
00438       BX_KEY_RIGHT,
00439       0,
00440       BX_KEY_END,
00441 
00442     /* 0x50 - 0x5f */
00443     BX_KEY_DOWN,
00444     BX_KEY_PAGE_DOWN,
00445     BX_KEY_INSERT,
00446       BX_KEY_DELETE,
00447       0,
00448       0,
00449       0,
00450       0,
00451       0,
00452       0,
00453       0,
00454       BX_KEY_WIN_L,
00455       BX_KEY_WIN_R,
00456         BX_KEY_MENU,
00457         BX_KEY_POWER_POWER,
00458         BX_KEY_POWER_SLEEP,
00459 
00460     /* 0x60 - 0x6f */
00461     0,
00462     0,
00463     0,
00464     BX_KEY_POWER_WAKE,
00465     0,
00466     BX_KEY_INT_SEARCH,
00467     BX_KEY_INT_FAV,
00468     0,
00469       BX_KEY_INT_STOP,
00470       BX_KEY_INT_FORWARD,
00471       BX_KEY_INT_BACK,
00472       BX_KEY_POWER_MYCOMP,
00473         BX_KEY_INT_MAIL,
00474         0,
00475         0,
00476         0,
00477       }
00478 };
00479 
00480 /* Macro to convert WM_ button state to BX button state */
00481 #if defined(__MINGW32__) || defined(_MSC_VER)
00482 VOID CALLBACK         MyTimer(HWND, UINT, UINT, DWORD);
00483 void                  alarm(int);
00484 void                  bx_signal_handler(int);
00485 #endif
00486 static void processMouseXY(int x, int y, int z, int windows_state,
00487                            int implied_state_change)
00488 {
00489   int bx_state;
00490   int old_bx_state;
00491   EnterCriticalSection(&stInfo.mouseCS);
00492   bx_state = ((windows_state & MK_LBUTTON) ? 1 : 0) +
00493     ((windows_state & MK_RBUTTON) ? 2 : 0) +
00494       ((windows_state & MK_MBUTTON) ? 4 : 0);
00495   old_bx_state = bx_state ^ implied_state_change;
00496   if(old_bx_state != mouse_button_state)
00497   {
00498 
00499     /* Make up for missing message */
00500     BX_INFO(("&&&missing mouse state change"));
00501     EnterCriticalSection(&stInfo.keyCS);
00502     enq_mouse_event();
00503     mouse_button_state = old_bx_state;
00504     enq_key_event(mouse_button_state, MOUSE_PRESSED);
00505     LeaveCriticalSection(&stInfo.keyCS);
00506   }
00507 
00508   ms_ydelta = ms_savedy - y;
00509   ms_xdelta = x - ms_savedx;
00510   ms_zdelta = z;
00511   ms_lastx = x;
00512   ms_lasty = y;
00513   if(bx_state != mouse_button_state)
00514   {
00515     EnterCriticalSection(&stInfo.keyCS);
00516     enq_mouse_event();
00517     mouse_button_state = bx_state;
00518     enq_key_event(mouse_button_state, MOUSE_PRESSED);
00519     LeaveCriticalSection(&stInfo.keyCS);
00520   }
00521 
00522   LeaveCriticalSection(&stInfo.mouseCS);
00523 }
00524 
00525 static void resetDelta()
00526 {
00527   EnterCriticalSection(&stInfo.mouseCS);
00528   ms_savedx = ms_lastx;
00529   ms_savedy = ms_lasty;
00530   ms_ydelta = ms_xdelta = ms_zdelta = 0;
00531   LeaveCriticalSection(&stInfo.mouseCS);
00532 }
00533 
00534 static void cursorWarped()
00535 {
00536   EnterCriticalSection(&stInfo.mouseCS);
00537   EnterCriticalSection(&stInfo.keyCS);
00538   enq_mouse_event();
00539   LeaveCriticalSection(&stInfo.keyCS);
00540   ms_lastx = stretched_x / 2;
00541   ms_lasty = stretched_y / 2;
00542   ms_savedx = ms_lastx;
00543   ms_savedy = ms_lasty;
00544   LeaveCriticalSection(&stInfo.mouseCS);
00545 }
00546 
00547 // GUI thread must be dead/done in order to call terminateEmul
00548 void terminateEmul(int reason)
00549 {
00550 
00551   // We know that Critical Sections were inited when x_tilesize has been set
00552   // See bx_win32_gui_c::specific_init
00553   if(x_tilesize != 0)
00554   {
00555     DeleteCriticalSection(&stInfo.drawCS);
00556     DeleteCriticalSection(&stInfo.keyCS);
00557     DeleteCriticalSection(&stInfo.mouseCS);
00558   }
00559 
00560   x_tilesize = 0;
00561 
00562   if(MemoryDC)
00563     DeleteDC(MemoryDC);
00564   if(MemoryBitmap)
00565     DeleteObject(MemoryBitmap);
00566 
00567   if(bitmap_info)
00568     delete[] (char*) bitmap_info;
00569 
00570   for(unsigned c = 0; c < 256; c++)
00571     if(vgafont[c])
00572       DeleteObject(vgafont[c]);
00573 
00574   switch(reason)
00575   {
00576   case EXIT_GUI_SHUTDOWN:
00577     FAILURE(Graceful, "Window closed, exiting!");
00578     break;
00579 
00580   case EXIT_GMH_FAILURE:
00581     FAILURE(Win32, "GetModuleHandle failure!");
00582     break;
00583 
00584   case EXIT_FONT_BITMAP_ERROR:
00585     FAILURE(Win32, "Font bitmap creation failure!");
00586     break;
00587 
00588   case EXIT_NORMAL:
00589     break;
00590   }
00591 }
00592 
00593 // ::SPECIFIC_INIT()
00594 //
00595 // Called from gui.cc, once upon program startup, to allow for the
00596 // specific GUI code (X11, BeOS, ...) to be initialized.
00597 //
00598 // tilewidth, tileheight: for optimization, graphics_tile_update() passes
00599 //     only updated regions of the screen to the gui code to be redrawn.
00600 
00601 //     These define the dimensions of a region (tile).
00602 void bx_win32_gui_c::specific_init(unsigned tilewidth, unsigned tileheight)
00603 {
00604   int i;
00605 
00606   // prepare for possible fullscreen mode
00607   desktopWindow = GetDesktopWindow();
00608   GetWindowRect(desktopWindow, &desktop);
00609   desktop_x = desktop.right - desktop.left;
00610   desktop_y = desktop.bottom - desktop.top;
00611   hotKeyReceiver = stInfo.simWnd;
00612   BX_INFO(("Desktop Window dimensions: %d x %d", desktop_x, desktop_y));
00613 
00614   static RGBQUAD  black_quad ={ 0, 0, 0, 0};
00615   stInfo.kill = 0;
00616   stInfo.UIinited = false;
00617   InitializeCriticalSection(&stInfo.drawCS);
00618   InitializeCriticalSection(&stInfo.keyCS);
00619   InitializeCriticalSection(&stInfo.mouseCS);
00620 
00621   x_tilesize = tilewidth;
00622   y_tilesize = tileheight;
00623 
00624   mouseCaptureMode = false;
00625   mouseCaptureNew = false;
00626   mouseToggleReq = false;
00627 
00628   mouse_buttons = GetSystemMetrics(SM_CMOUSEBUTTONS);
00629   BX_INFO(("Number of Mouse Buttons = %d", mouse_buttons));
00630 
00631   stInfo.hInstance = GetModuleHandle(NULL);
00632 
00633   dimension_x = 640;
00634   dimension_y = 480;
00635   current_bpp = 8;
00636   stretched_x = dimension_x;
00637   stretched_y = dimension_y;
00638   stretch_factor = 1;
00639 
00640   for(unsigned c = 0; c < 256; c++)
00641     vgafont[c] = NULL;
00642   create_vga_font();
00643 
00644   bitmap_info = (BITMAPINFO*) new char[sizeof(BITMAPINFOHEADER) + 259 * sizeof(RGBQUAD)]; // 256 + 3 entries for 16 bpp mode
00645   bitmap_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00646   bitmap_info->bmiHeader.biWidth = x_tilesize;
00647 
00648   // Height is negative for top-down bitmap
00649   bitmap_info->bmiHeader.biHeight = -(LONG) y_tilesize;
00650   bitmap_info->bmiHeader.biPlanes = 1;
00651   bitmap_info->bmiHeader.biBitCount = 8;
00652   bitmap_info->bmiHeader.biCompression = BI_RGB;
00653   bitmap_info->bmiHeader.biSizeImage = x_tilesize * y_tilesize * 4;
00654 
00655   // I think these next two figures don't matter; saying 45 pixels/centimeter
00656   bitmap_info->bmiHeader.biXPelsPerMeter = 4500;
00657   bitmap_info->bmiHeader.biYPelsPerMeter = 4500;
00658   bitmap_info->bmiHeader.biClrUsed = 256;
00659   bitmap_info->bmiHeader.biClrImportant = 0;
00660   cmap_index = bitmap_info->bmiColors;
00661 
00662   // start out with all color map indeces pointing to Black
00663   cmap_index[0] = black_quad;
00664   for(i = 1; i < 259; i++)
00665   {
00666     cmap_index[i] = cmap_index[0];
00667   }
00668 
00669   if(stInfo.hInstance)
00670     workerThread = _beginthread(UIThread, 0, NULL);
00671   else
00672     terminateEmul(EXIT_GMH_FAILURE);
00673 
00674   // Wait for a window before continuing
00675   if((stInfo.kill == 0) && (FindWindow(szAppName, NULL) == NULL))
00676     Sleep(500);
00677 
00678   // Now set this thread's priority to below normal because this is where
00679   //  the emulated CPU runs, and it hogs the real CPU
00680   // SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
00681   // load keymap tables
00682   if(myCfg->get_bool_value("keyboard.use_mapping"))
00683   {
00684     bx_keymap->loadKeymap(NULL);  // I have no function to convert X windows symbols
00685   }
00686 }
00687 
00688 void resize_main_window()
00689 {
00690   RECT          R;
00691   unsigned long mainStyle;
00692 
00693   // stretched_x and stretched_y were set in dimension_update()
00694   // if we need to do any additional resizing, do it now
00695   if((desktop_y > 0) && (stretched_y >= (unsigned) desktop_y))
00696   {
00697     if(!queryFullScreen)
00698     {
00699       MessageBox(NULL, "Going into fullscreen mode -- Alt-Enter to revert",
00700                  "Going fullscreen", MB_APPLMODAL);
00701       queryFullScreen = true;
00702     }
00703 
00704     // hide title bar
00705     mainStyle = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
00706     mainStyle &= ~(WS_CAPTION | WS_BORDER);
00707     SetWindowLong(stInfo.mainWnd, GWL_STYLE, mainStyle);
00708 
00709     // maybe need to adjust stInfo.simWnd here also?
00710     if(saveParent = SetParent(stInfo.mainWnd, desktopWindow))
00711     {
00712       BX_DEBUG(("Saved parent window"));
00713       SetWindowPos(stInfo.mainWnd, HWND_TOPMOST, desktop.left, desktop.top,
00714                    desktop.right, desktop.bottom, SWP_SHOWWINDOW);
00715     }
00716   }
00717   else
00718   {
00719     if(saveParent)
00720     {
00721       BX_DEBUG(("Restoring parent window"));
00722       SetParent(stInfo.mainWnd, saveParent);
00723       saveParent = NULL;
00724     }
00725 
00726     // put back the title bar, border, etc...
00727     mainStyle = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
00728     mainStyle |= WS_CAPTION | WS_BORDER;
00729     SetWindowLong(stInfo.mainWnd, GWL_STYLE, mainStyle);
00730     SetRect(&R, 0, 0, stretched_x, stretched_y);
00731 
00732     DWORD style = GetWindowLong(stInfo.simWnd, GWL_STYLE);
00733     DWORD exstyle = GetWindowLong(stInfo.simWnd, GWL_EXSTYLE);
00734     AdjustWindowRectEx(&R, style, false, exstyle);
00735     style = GetWindowLong(stInfo.mainWnd, GWL_STYLE);
00736     AdjustWindowRect(&R, style, false);
00737     SetWindowPos(stInfo.mainWnd, HWND_TOP, 0, 0, R.right - R.left,
00738                  R.bottom - R.top, SWP_NOMOVE | SWP_NOZORDER);
00739   }
00740 
00741   fix_size = false;
00742 }
00743 
00744 // This thread controls the GUI window.
00745 VOID UIThread(PVOID pvoid)
00746 {
00747   MSG       msg;
00748   HDC       hdc;
00749   WNDCLASS  wndclass;
00750   RECT      wndRect;
00751 
00752   workerThreadID = GetCurrentThreadId();
00753 
00754   GetClassInfo(NULL, WC_DIALOG, &wndclass);
00755   wndclass.style = CS_HREDRAW | CS_VREDRAW;
00756   wndclass.lpfnWndProc = mainWndProc;
00757   wndclass.cbClsExtra = 0;
00758   wndclass.cbWndExtra = 0;
00759   wndclass.hInstance = stInfo.hInstance;
00760   wndclass.lpszMenuName = NULL;
00761   wndclass.lpszClassName = szAppName;
00762 
00763   RegisterClass(&wndclass);
00764 
00765   wndclass.style = CS_HREDRAW | CS_VREDRAW;
00766   wndclass.lpfnWndProc = simWndProc;
00767   wndclass.cbClsExtra = 0;
00768   wndclass.cbWndExtra = 0;
00769   wndclass.hInstance = stInfo.hInstance;
00770   wndclass.hIcon = NULL;
00771   wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
00772   wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
00773   wndclass.lpszMenuName = NULL;
00774   wndclass.lpszClassName = "SIMWINDOW";
00775 
00776   RegisterClass(&wndclass);
00777 
00778   SetRect(&wndRect, 0, 0, stretched_x, stretched_y);
00779 
00780   DWORD sim_style = WS_CHILD;
00781   DWORD sim_exstyle = WS_EX_CLIENTEDGE;
00782   AdjustWindowRectEx(&wndRect, sim_style, false, sim_exstyle);
00783 
00784   DWORD main_style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
00785   AdjustWindowRect(&wndRect, main_style, false);
00786   stInfo.mainWnd = CreateWindow(szAppName, szWindowName, main_style,
00787                                 CW_USEDEFAULT, CW_USEDEFAULT,
00788                                 wndRect.right - wndRect.left,
00789                                 wndRect.bottom - wndRect.top, NULL, NULL,
00790                                 stInfo.hInstance, NULL);
00791 
00792   if(stInfo.mainWnd)
00793   {
00794 
00795     //    InitCommonControls();
00796     stInfo.simWnd = CreateWindowEx(sim_exstyle, "SIMWINDOW", "", sim_style, 0,
00797                                    0, 0, 0, stInfo.mainWnd, NULL,
00798                                    stInfo.hInstance, NULL);
00799 
00800     /* needed for the Japanese versions of Windows */
00801     if(stInfo.simWnd)
00802     {
00803       HMODULE hm;
00804       hm = GetModuleHandle("USER32");
00805       if(hm)
00806       {
00807         BOOL (WINAPI *enableime) (HWND, BOOL);
00808         enableime = (BOOL(WINAPI *) (HWND, BOOL)) GetProcAddress(hm,
00809                                                                  "WINNLSEnableIME");
00810         if(enableime)
00811         {
00812           enableime(stInfo.simWnd, false);
00813           BX_INFO(("IME disabled"));
00814         }
00815       }
00816     }
00817 
00818     ShowWindow(stInfo.simWnd, SW_SHOW);
00819     SetFocus(stInfo.simWnd);
00820 
00821     ShowCursor(!mouseCaptureMode);
00822 
00823     POINT pt = { 0, 0};
00824     ClientToScreen(stInfo.simWnd, &pt);
00825     SetCursorPos(pt.x + stretched_x / 2, pt.y + stretched_y / 2);
00826     cursorWarped();
00827 
00828     hdc = GetDC(stInfo.simWnd);
00829     MemoryBitmap = CreateCompatibleBitmap(hdc, BX_MAX_XRES, BX_MAX_YRES);
00830     MemoryDC = CreateCompatibleDC(hdc);
00831     ReleaseDC(stInfo.simWnd, hdc);
00832 
00833     if(MemoryBitmap && MemoryDC)
00834     {
00835       resize_main_window();
00836       ShowWindow(stInfo.mainWnd, SW_SHOW);
00837 #if BX_DEBUGGER
00838       if(windebug)
00839       {
00840         InitDebugDialog(stInfo.mainWnd);
00841       }
00842 #endif
00843       stInfo.UIinited = true;
00844 
00845       bx_gui->clear_screen();
00846 
00847       while(GetMessage(&msg, NULL, 0, 0))
00848       {
00849         TranslateMessage(&msg);
00850         DispatchMessage(&msg);
00851       }
00852     }
00853   }
00854 
00855   stInfo.kill = EXIT_GUI_SHUTDOWN;
00856 
00857   _endthread();
00858 }
00859 
00860 LRESULT CALLBACK mainWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
00861 {
00862   switch(iMsg)
00863   {
00864   case WM_SETFOCUS:
00865     SetFocus(stInfo.simWnd);
00866     return 0;
00867 
00868   case WM_CLOSE:
00869     SendMessage(stInfo.simWnd, WM_CLOSE, 0, 0);
00870     break;
00871 
00872   case WM_DESTROY:
00873     PostQuitMessage(0);
00874     return 0;
00875 
00876   case WM_SIZE:
00877     {
00878       int   x;
00879 
00880       int   y;
00881 
00882       // now fit simWindow to mainWindow
00883       //      int rect_data[] = { 1, 0, 0, 0 };
00884       RECT  R;
00885 
00886       //GetEffectiveClientRect( hwnd, &R, rect_data );
00887       GetClientRect(hwnd, &R);
00888       x = R.right - R.left;
00889       y = R.bottom - R.top;
00890       MoveWindow(stInfo.simWnd, R.left, R.top, x, y, true);
00891       GetClientRect(stInfo.simWnd, &R);
00892       x = R.right - R.left;
00893       y = R.bottom - R.top;
00894       if((x != (int) stretched_x) || (y != (int) stretched_y))
00895       {
00896         BX_ERROR(("Sim client size(%d, %d) != stretched size(%d, %d)!", x, y,
00897                    stretched_x, stretched_y));
00898         if(!saveParent)
00899           fix_size = true;        // no fixing if fullscreen
00900       }
00901     }
00902     break;
00903   }
00904 
00905   return DefWindowProc(hwnd, iMsg, wParam, lParam);
00906 }
00907 
00908 void SetMouseCapture()
00909 {
00910   POINT pt = {0, 0};
00911 
00912   if(mouseToggleReq)
00913   {
00914     mouseCaptureMode = mouseCaptureNew;
00915     mouseToggleReq = false;
00916   }
00917   else
00918   {
00919 
00920     //  SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set(mouseCaptureMode);
00921   }
00922 
00923   ShowCursor(!mouseCaptureMode);
00924   ShowCursor(!mouseCaptureMode);  // somehow one didn't do the trick (win98)
00925   ClientToScreen(stInfo.simWnd, &pt);
00926   SetCursorPos(pt.x + stretched_x / 2, pt.y + stretched_y / 2);
00927   cursorWarped();
00928 }
00929 
00930 LRESULT CALLBACK simWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
00931 {
00932   HDC         hdc;
00933 
00934   HDC         hdcMem;
00935   PAINTSTRUCT ps;
00936   POINT       pt;
00937   static BOOL mouseModeChange = false;
00938 
00939   switch(iMsg)
00940   {
00941   case WM_CREATE:
00942 #if BX_USE_WINDOWS_FONTS
00943     InitFont();
00944 #endif
00945     SetTimer(hwnd, 1, 330, NULL);
00946     return 0;
00947 
00948   case WM_TIMER:
00949     if(mouseToggleReq && (GetActiveWindow() == stInfo.mainWnd))
00950     {
00951       SetMouseCapture();
00952     }
00953 
00954     // If mouse escaped, bring it back
00955     if(mouseCaptureMode)
00956     {
00957       pt.x = 0;
00958       pt.y = 0;
00959       ClientToScreen(hwnd, &pt);
00960       SetCursorPos(pt.x + stretched_x / 2, pt.y + stretched_y / 2);
00961       cursorWarped();
00962     }
00963 
00964     if(fix_size)
00965     {
00966       resize_main_window();
00967     }
00968 
00969     return 0;
00970 
00971   case WM_PAINT:
00972     EnterCriticalSection(&stInfo.drawCS);
00973     hdc = BeginPaint(hwnd, &ps);
00974 
00975     hdcMem = CreateCompatibleDC(hdc);
00976     SelectObject(hdcMem, MemoryBitmap);
00977 
00978     if(stretch_factor == 1)
00979     {
00980       BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top,
00981              ps.rcPaint.right - ps.rcPaint.left + 1,
00982              ps.rcPaint.bottom - ps.rcPaint.top + 1, hdcMem, ps.rcPaint.left,
00983              ps.rcPaint.top, SRCCOPY);
00984     }
00985     else
00986     {
00987       StretchBlt(hdc, ps.rcPaint.left, ps.rcPaint.top,
00988                  ps.rcPaint.right - ps.rcPaint.left + 1,
00989                  ps.rcPaint.bottom - ps.rcPaint.top + 1, hdcMem,
00990                  ps.rcPaint.left / stretch_factor, ps.rcPaint.top,
00991                  (ps.rcPaint.right - ps.rcPaint.left + 1) / stretch_factor,
00992                  (ps.rcPaint.bottom - ps.rcPaint.top + 1), SRCCOPY);
00993     }
00994 
00995     DeleteDC(hdcMem);
00996     EndPaint(hwnd, &ps);
00997     LeaveCriticalSection(&stInfo.drawCS);
00998     return 0;
00999 
01000   case WM_MOUSEMOVE:
01001     if(!mouseModeChange)
01002     {
01003       processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 0);
01004     }
01005 
01006     return 0;
01007 
01008   //case WM_MOUSEWHEEL:
01009   //  if (!mouseModeChange) {
01010   //    // WM_MOUSEWHEEL returns x and y relative to the main screen.
01011   //    // WM_MOUSEMOVE below returns x and y relative to the current view.
01012   //    POINT pt;
01013   //    pt.x = LOWORD(lParam);
01014   //    pt.y = HIWORD(lParam);
01015   //    ScreenToClient(stInfo.simWnd, &pt);
01016   //    processMouseXY( pt.x, pt.y, (s16) HIWORD(wParam) / 120, LOWORD(wParam), 0);
01017   //  }
01018   //  return 0;
01019   case WM_LBUTTONDOWN:
01020   case WM_LBUTTONDBLCLK:
01021   case WM_LBUTTONUP:
01022     if(mouse_buttons == 2)
01023     {
01024       if(wParam == (MK_CONTROL | MK_LBUTTON | MK_RBUTTON))
01025       {
01026         mouseCaptureMode = !mouseCaptureMode;
01027         SetMouseCapture();
01028         mouseModeChange = true;
01029       }
01030       else if(mouseModeChange && (iMsg == WM_LBUTTONUP))
01031       {
01032         mouseModeChange = false;
01033       }
01034       else
01035       {
01036         processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 1);
01037       }
01038 
01039       return 0;
01040     }
01041 
01042     processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 1);
01043     return 0;
01044 
01045   case WM_MBUTTONDOWN:
01046   case WM_MBUTTONDBLCLK:
01047   case WM_MBUTTONUP:
01048     if(wParam == (MK_CONTROL | MK_MBUTTON))
01049     {
01050       mouseCaptureMode = !mouseCaptureMode;
01051       SetMouseCapture();
01052       mouseModeChange = true;
01053     }
01054     else if(mouseModeChange && (iMsg == WM_MBUTTONUP))
01055     {
01056       mouseModeChange = false;
01057     }
01058     else
01059     {
01060       processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 4);
01061     }
01062 
01063     return 0;
01064 
01065   case WM_RBUTTONDOWN:
01066   case WM_RBUTTONDBLCLK:
01067   case WM_RBUTTONUP:
01068     if(mouse_buttons == 2)
01069     {
01070       if(wParam == (MK_CONTROL | MK_LBUTTON | MK_RBUTTON))
01071       {
01072         mouseCaptureMode = !mouseCaptureMode;
01073         SetMouseCapture();
01074         mouseModeChange = true;
01075       }
01076       else if(mouseModeChange && (iMsg == WM_RBUTTONUP))
01077       {
01078         mouseModeChange = false;
01079       }
01080       else
01081       {
01082         processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 2);
01083       }
01084 
01085       return 0;
01086     }
01087 
01088     processMouseXY(LOWORD(lParam), HIWORD(lParam), 0, wParam, 2);
01089     return 0;
01090 
01091   case WM_CLOSE:
01092     return DefWindowProc(hwnd, iMsg, wParam, lParam);
01093 
01094   case WM_DESTROY:
01095     KillTimer(hwnd, 1);
01096     stInfo.UIinited = false;
01097 #if BX_USE_WINDOWS_FONTS
01098     DestroyFont();
01099 #endif
01100     return 0;
01101 
01102   case WM_KEYDOWN:
01103   case WM_SYSKEYDOWN:
01104     EnterCriticalSection(&stInfo.keyCS);
01105     enq_key_event(HIWORD(lParam) & 0x01FF, BX_KEY_PRESSED);
01106     LeaveCriticalSection(&stInfo.keyCS);
01107     return 0;
01108 
01109   case WM_KEYUP:
01110   case WM_SYSKEYUP:
01111 
01112     // check if it's keyup, alt key, non-repeat
01113     // see http://msdn2.microsoft.com/en-us/library/ms646267.aspx
01114     if(wParam == VK_RETURN)
01115     {
01116       if((HIWORD(lParam) & BX_SYSKEY) == (KF_ALTDOWN | KF_UP))
01117       {
01118         if(!saveParent)
01119         {
01120           BX_INFO(("entering fullscreen mode"));
01121           theGui->dimension_update(desktop_x, desktop_y, 0, 0, current_bpp);
01122         }
01123         else
01124         {
01125           BX_INFO(("leaving fullscreen mode"));
01126           theGui->dimension_update(dimension_x, desktop_y - 1, 0, 0, current_bpp);
01127         }
01128       }
01129     }
01130     else
01131     {
01132       EnterCriticalSection(&stInfo.keyCS);
01133       enq_key_event(HIWORD(lParam) & 0x01FF, BX_KEY_RELEASED);
01134       LeaveCriticalSection(&stInfo.keyCS);
01135     }
01136 
01137     return 0;
01138 
01139   case WM_SYSCHAR:
01140 
01141     // check if it's keydown, alt key, non-repeat
01142     // see http://msdn2.microsoft.com/en-us/library/ms646267.aspx
01143     if(wParam == VK_RETURN)
01144     {
01145       if((HIWORD(lParam) & BX_SYSKEY) == KF_ALTDOWN)
01146       {
01147         if(!saveParent)
01148         {
01149           BX_INFO(("entering fullscreen mode"));
01150           theGui->dimension_update(desktop_x, desktop_y, 0, 0, current_bpp);
01151         }
01152         else
01153         {
01154           BX_INFO(("leaving fullscreen mode"));
01155           theGui->dimension_update(dimension_x, desktop_y - 1, 0, 0, current_bpp);
01156         }
01157       }
01158     }
01159 
01160   case WM_CHAR:
01161   case WM_DEADCHAR:
01162   case WM_SYSDEADCHAR:
01163     return 0;
01164   }
01165 
01166   return DefWindowProc(hwnd, iMsg, wParam, lParam);
01167 }
01168 
01169 void enq_key_event(u32 key, u32 press_release)
01170 {
01171   static BOOL alt_pressed_l = false;
01172   static BOOL alt_pressed_r = false;
01173   static BOOL ctrl_pressed_l = false;
01174   static BOOL ctrl_pressed_r = false;
01175   static BOOL shift_pressed_l = false;
01176   static BOOL shift_pressed_r = false;
01177 
01178   // Windows generates multiple keypresses when holding down these keys
01179   if(press_release == BX_KEY_PRESSED)
01180   {
01181     switch(key)
01182     {
01183     case 0x1d:
01184       if(ctrl_pressed_l)
01185         return;
01186       ctrl_pressed_l = true;
01187       break;
01188 
01189     case 0x2a:
01190       if(shift_pressed_l)
01191         return;
01192       shift_pressed_l = true;
01193       break;
01194 
01195     case 0x36:
01196       if(shift_pressed_r)
01197         return;
01198       shift_pressed_r = true;
01199       break;
01200 
01201     case 0x38:
01202       if(alt_pressed_l)
01203         return;
01204       alt_pressed_l = true;
01205       break;
01206 
01207     case 0x011d:
01208       if(ctrl_pressed_r)
01209         return;
01210       ctrl_pressed_r = true;
01211       break;
01212 
01213     case 0x0138:
01214       if(alt_pressed_r)
01215         return;
01216 
01217       // This makes the "AltGr" key on European keyboards work
01218       if(ctrl_pressed_l)
01219       {
01220         enq_key_event(0x1d, BX_KEY_RELEASED);
01221       }
01222 
01223       alt_pressed_r = true;
01224       break;
01225     }
01226   }
01227   else
01228   {
01229     switch(key)
01230     {
01231     case 0x1d:    if(!ctrl_pressed_l) return; ctrl_pressed_l = false; break;
01232     case 0x2a:    shift_pressed_l = false; break;
01233     case 0x36:    shift_pressed_r = false; break;
01234     case 0x38:    alt_pressed_l = false; break;
01235     case 0x011d:  ctrl_pressed_r = false; break;
01236     case 0x0138:  alt_pressed_r = false; break;
01237     }
01238   }
01239 
01240   if(((tail + 1) % SCANCODE_BUFSIZE) == head)
01241   {
01242     BX_ERROR(("enq_scancode: buffer full"));
01243     return;
01244   }
01245 
01246   keyevents[tail].key_event = key | press_release;
01247   tail = (tail + 1) % SCANCODE_BUFSIZE;
01248 }
01249 
01250 void enq_mouse_event(void)
01251 {
01252   EnterCriticalSection(&stInfo.mouseCS);
01253   if(ms_xdelta || ms_ydelta || ms_zdelta)
01254   {
01255     if(((tail + 1) % SCANCODE_BUFSIZE) == head)
01256     {
01257       BX_ERROR(("enq_scancode: buffer full"));
01258       return;
01259     }
01260 
01261     QueueEvent&   current = keyevents[tail];
01262     current.key_event = MOUSE_MOTION;
01263     current.mouse_x = ms_xdelta;
01264     current.mouse_y = ms_ydelta;
01265     current.mouse_z = ms_zdelta;
01266     current.mouse_button_state = mouse_button_state;
01267     resetDelta();
01268     tail = (tail + 1) % SCANCODE_BUFSIZE;
01269   }
01270 
01271   LeaveCriticalSection(&stInfo.mouseCS);
01272 }
01273 
01274 QueueEvent* deq_key_event(void)
01275 {
01276   QueueEvent*   key;
01277 
01278   if(head == tail)
01279   {
01280     BX_ERROR(("deq_scancode: buffer empty"));
01281     return((QueueEvent*) 0);
01282   }
01283 
01284   key = &keyevents[head];
01285   head = (head + 1) % SCANCODE_BUFSIZE;
01286 
01287   return(key);
01288 }
01289 
01290 // ::HANDLE_EVENTS()
01291 //
01292 // Called periodically (vga_update_interval in .bochsrc) so the
01293 // the gui code can poll for keyboard, mouse, and other
01294 
01295 // relevant events.
01296 void bx_win32_gui_c::handle_events(void)
01297 {
01298   u32 key;
01299   u32 key_event;
01300 
01301   if(stInfo.kill)
01302     terminateEmul(stInfo.kill);
01303 
01304   // Handle mouse moves
01305   enq_mouse_event();
01306 
01307   // Handle keyboard and mouse clicks
01308   EnterCriticalSection(&stInfo.keyCS);
01309   while(head != tail)
01310   {
01311     QueueEvent*   queue_event = deq_key_event();
01312     if(!queue_event)
01313       break;
01314     key = queue_event->key_event;
01315     if(key == MOUSE_MOTION)
01316     {
01317 
01318       //      DEV_mouse_motion_ext( queue_event->mouse_x,
01319       //        queue_event->mouse_y, queue_event->mouse_z, queue_event->mouse_button_state);
01320     }
01321 
01322     // Check for mouse buttons first
01323     else if(key & MOUSE_PRESSED)
01324     {
01325 
01326       //      DEV_mouse_motion_ext( 0, 0, 0, LOWORD(key));
01327     }
01328     else
01329     {
01330       key_event = win32_to_bx_key[(key & 0x100) ? 1 : 0][key & 0xff];
01331       if(key & BX_KEY_RELEASED)
01332         key_event |= BX_KEY_RELEASED;
01333 
01334       //DEV_kbd_gen_scancode(key_event);
01335       theKeyboard->gen_scancode(key_event);
01336     }
01337   }
01338 
01339   LeaveCriticalSection(&stInfo.keyCS);
01340 }
01341 
01342 // ::FLUSH()
01343 //
01344 // Called periodically, requesting that the gui code flush all pending
01345 
01346 // screen update requests.
01347 void bx_win32_gui_c::flush(void)
01348 {
01349   EnterCriticalSection(&stInfo.drawCS);
01350   if(updated_area_valid)
01351   {
01352 
01353     // slight bugfix
01354     updated_area.right++;
01355     updated_area.bottom++;
01356     InvalidateRect(stInfo.simWnd, &updated_area, false);
01357     updated_area_valid = false;
01358   }
01359 
01360   LeaveCriticalSection(&stInfo.drawCS);
01361 }
01362 
01363 // ::CLEAR_SCREEN()
01364 //
01365 
01366 // Called to request that the VGA region is cleared.
01367 void bx_win32_gui_c::clear_screen(void)
01368 {
01369   HGDIOBJ oldObj;
01370 
01371   if(!stInfo.UIinited)
01372     return;
01373 
01374   EnterCriticalSection(&stInfo.drawCS);
01375 
01376   oldObj = SelectObject(MemoryDC, MemoryBitmap);
01377   PatBlt(MemoryDC, 0, 0, stretched_x, stretched_y, BLACKNESS);
01378   SelectObject(MemoryDC, oldObj);
01379 
01380   updateUpdated(0, 0, dimension_x - 1, dimension_y - 1);
01381 
01382   LeaveCriticalSection(&stInfo.drawCS);
01383 }
01384 
01385 // ::TEXT_UPDATE()
01386 //
01387 // Called in a VGA text mode, to update the screen with
01388 // new content.
01389 //
01390 // old_text: array of character/attributes making up the contents
01391 //           of the screen from the last call.  See below
01392 // new_text: array of character/attributes making up the current
01393 //           contents, which should now be displayed.  See below
01394 //
01395 // format of old_text & new_text: each is tm_info.line_offset*text_rows
01396 //     bytes long. Each character consists of 2 bytes.  The first by is
01397 //     the character value, the second is the attribute byte.
01398 //
01399 // cursor_x: new x location of cursor
01400 // cursor_y: new y location of cursor
01401 // tm_info:  this structure contains information for additional
01402 //           features in text mode (cursor shape, line offset,...)
01403 
01404 // nrows:    number of text rows (unused here)
01405 void bx_win32_gui_c::text_update(u8*  old_text, u8*  new_text,
01406                                  unsigned long cursor_x, unsigned long cursor_y,
01407                                  bx_vga_tminfo_t tm_info, unsigned nrows)
01408 {
01409   HDC           hdc;
01410   unsigned char data[64];
01411   u8*           old_line;
01412   u8 *new_line;
01413   u8            cAttr;
01414   u8            cChar;
01415   unsigned int  curs;
01416   unsigned int  hchars;
01417   unsigned int  i;
01418   unsigned int  offset;
01419   unsigned int  rows;
01420   unsigned int  x;
01421   unsigned int  y;
01422   unsigned int  xc;
01423   unsigned int  yc;
01424   BOOL          forceUpdate = false;
01425 #if !BX_USE_WINDOWS_FONTS
01426   u8*           text_base;
01427   u8            cfwidth;
01428   u8            cfheight;
01429   u8            cfheight2;
01430   u8            font_col;
01431   u8            font_row;
01432   u8            font_row2;
01433   u8            split_textrow;
01434   u8            split_fontrows;
01435   unsigned int  yc2;
01436   unsigned int  cs_y;
01437   BOOL          split_screen;
01438 #endif
01439   if(!stInfo.UIinited)
01440     return;
01441 
01442   EnterCriticalSection(&stInfo.drawCS);
01443 
01444   if(charmap_updated)
01445   {
01446     for(unsigned c = 0; c < 256; c++)
01447     {
01448       if(char_changed[c])
01449       {
01450         memset(data, 0, sizeof(data));
01451 
01452         BOOL  gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);
01453         for(i = 0; i < (unsigned) yChar; i++)
01454         {
01455           data[i * 2] = vga_charmap[c * 32 + i];
01456           if(gfxchar)
01457           {
01458             data[i * 2 + 1] = (data[i * 2] << 7);
01459           }
01460         }
01461 
01462         SetBitmapBits(vgafont[c], 64, data);
01463         char_changed[c] = 0;
01464       }
01465     }
01466 
01467     forceUpdate = true;
01468     charmap_updated = 0;
01469   }
01470 
01471   for(i = 0; i < 16; i++)
01472   {
01473     text_pal_idx[i] = theVGA->get_actl_palette_idx(i);  // DEV_vga_get_actl_pal_idx(i);
01474   }
01475 
01476   hdc = GetDC(stInfo.simWnd);
01477 
01478 #if !BX_USE_WINDOWS_FONTS
01479   if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning))
01480   {
01481     forceUpdate = 1;
01482     h_panning = tm_info.h_panning;
01483     v_panning = tm_info.v_panning;
01484   }
01485 
01486   if(tm_info.line_compare != line_compare)
01487   {
01488     forceUpdate = 1;
01489     line_compare = tm_info.line_compare;
01490   }
01491 #endif
01492 
01493   // first invalidate character at previous and new cursor location
01494   if((prev_cursor_y < text_rows) && (prev_cursor_x < text_cols))
01495   {
01496     curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;
01497     old_text[curs] = ~new_text[curs];
01498   }
01499 
01500   if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < yChar)
01501    && (cursor_y < text_rows) && (cursor_x < text_cols))
01502   {
01503     curs = cursor_y * tm_info.line_offset + cursor_x * 2;
01504     old_text[curs] = ~new_text[curs];
01505   }
01506   else
01507   {
01508     curs = 0xffff;
01509   }
01510 
01511 #if !BX_USE_WINDOWS_FONTS
01512   rows = text_rows;
01513   if(v_panning)
01514     rows++;
01515   y = 0;
01516   cs_y = 0;
01517   text_base = new_text - tm_info.start_address;
01518   split_textrow = (line_compare + v_panning) / yChar;
01519   split_fontrows = ((line_compare + v_panning) % yChar) + 1;
01520   split_screen = 0;
01521   do
01522   {
01523     hchars = text_cols;
01524     if(h_panning)
01525       hchars++;
01526     if(split_screen)
01527     {
01528       yc = line_compare + cs_y * yChar + 1;
01529       font_row = 0;
01530       if(rows == 1)
01531       {
01532         cfheight = (dimension_y - line_compare - 1) % yChar;
01533         if(cfheight == 0)
01534           cfheight = yChar;
01535       }
01536       else
01537       {
01538         cfheight = yChar;
01539       }
01540     }
01541     else if(v_panning)
01542     {
01543       if(y == 0)
01544       {
01545         yc = 0;
01546         font_row = v_panning;
01547         cfheight = yChar - v_panning;
01548       }
01549       else
01550       {
01551         yc = y * yChar - v_panning;
01552         font_row = 0;
01553         if(rows == 1)
01554         {
01555           cfheight = v_panning;
01556         }
01557         else
01558         {
01559           cfheight = yChar;
01560         }
01561       }
01562     }
01563     else
01564     {
01565       yc = y * yChar;
01566       font_row = 0;
01567       cfheight = yChar;
01568     }
01569 
01570     if(!split_screen && (y == split_textrow))
01571     {
01572       if(split_fontrows < cfheight)
01573         cfheight = split_fontrows;
01574     }
01575 
01576     new_line = new_text;
01577     old_line = old_text;
01578     x = 0;
01579     offset = cs_y * tm_info.line_offset;
01580     do
01581     {
01582       if(h_panning)
01583       {
01584         if(hchars > text_cols)
01585         {
01586           xc = 0;
01587           font_col = h_panning;
01588           cfwidth = xChar - h_panning;
01589         }
01590         else
01591         {
01592           xc = x * xChar - h_panning;
01593           font_col = 0;
01594           if(hchars == 1)
01595           {
01596             cfwidth = h_panning;
01597           }
01598           else
01599           {
01600             cfwidth = xChar;
01601           }
01602         }
01603       }
01604       else
01605       {
01606         xc = x * xChar;
01607         font_col = 0;
01608         cfwidth = xChar;
01609       }
01610 
01611       if(forceUpdate || (old_text[0] != new_text[0])
01612        || (old_text[1] != new_text[1]))
01613       {
01614         cChar = new_text[0];
01615         cAttr = new_text[1];
01616         DrawBitmap(hdc, vgafont[cChar], xc, yc, cfwidth, cfheight, font_col,
01617                    font_row, SRCCOPY, cAttr);
01618         if(offset == curs)
01619         {
01620           if(font_row == 0)
01621           {
01622             yc2 = yc + tm_info.cs_start;
01623             font_row2 = tm_info.cs_start;
01624             cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
01625           }
01626           else
01627           {
01628             if(v_panning > tm_info.cs_start)
01629             {
01630               yc2 = yc;
01631               font_row2 = font_row;
01632               cfheight2 = tm_info.cs_end - v_panning + 1;
01633             }
01634             else
01635             {
01636               yc2 = yc + tm_info.cs_start - v_panning;
01637               font_row2 = tm_info.cs_start;
01638               cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
01639             }
01640           }
01641 
01642           cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
01643           DrawBitmap(hdc, vgafont[cChar], xc, yc2, cfwidth, cfheight2, font_col,
01644                      font_row2, SRCCOPY, cAttr);
01645         }
01646       }
01647 
01648       x++;
01649       new_text += 2;
01650       old_text += 2;
01651       offset += 2;
01652     } while(--hchars);
01653     if(!split_screen && (y == split_textrow))
01654     {
01655       new_text = text_base;
01656       forceUpdate = 1;
01657       cs_y = 0;
01658       if(tm_info.split_hpanning)
01659         h_panning = 0;
01660       rows = ((dimension_y - line_compare + yChar - 2) / yChar) + 1;
01661       split_screen = 1;
01662     }
01663     else
01664     {
01665       y++;
01666       cs_y++;
01667       new_text = new_line + tm_info.line_offset;
01668       old_text = old_line + tm_info.line_offset;
01669     }
01670   } while(--rows);
01671 
01672   h_panning = tm_info.h_panning;
01673 #else
01674   rows = text_rows;
01675   y = 0;
01676   do
01677   {
01678     hchars = text_cols;
01679     yc = y * yChar;
01680     new_line = new_text;
01681     old_line = old_text;
01682     x = 0;
01683     offset = y * tm_info.line_offset;
01684     do
01685     {
01686       xc = x * xChar;
01687       if(forceUpdate || (old_text[0] != new_text[0])
01688        || (old_text[1] != new_text[1]))
01689       {
01690         cChar = new_text[0];
01691         cAttr = new_text[1];
01692         DrawChar(hdc, cChar, xc, yc, cAttr, 1, 0);
01693         if(offset == curs)
01694         {
01695           DrawChar(hdc, cChar, xc, yc, cAttr, tm_info.cs_start, tm_info.cs_end);
01696         }
01697       }
01698 
01699       x++;
01700       new_text += 2;
01701       old_text += 2;
01702       offset += 2;
01703     } while(--hchars);
01704     y++;
01705     new_text = new_line + tm_info.line_offset;
01706     old_text = old_line + tm_info.line_offset;
01707   } while(--rows);
01708 #endif
01709   prev_cursor_x = cursor_x;
01710   prev_cursor_y = cursor_y;
01711 
01712   ReleaseDC(stInfo.simWnd, hdc);
01713 
01714   LeaveCriticalSection(&stInfo.drawCS);
01715 }
01716 
01717 // ::PALETTE_CHANGE()
01718 //
01719 // Allocate a color in the native GUI, for this color, and put
01720 // it in the colormap location 'index'.
01721 // returns: 0=no screen update needed (color map change has direct effect)
01722 
01723 //          1=screen updated needed (redraw using current colormap)
01724 bool bx_win32_gui_c::palette_change(unsigned index, unsigned red, unsigned green,
01725                                     unsigned blue)
01726 {
01727   if((current_bpp == 16) && (index < 3))
01728   {
01729     cmap_index[256 + index].rgbRed = red;
01730     cmap_index[256 + index].rgbBlue = blue;
01731     cmap_index[256 + index].rgbGreen = green;
01732     return 0;
01733   }
01734   else
01735   {
01736     cmap_index[index].rgbRed = red;
01737     cmap_index[index].rgbBlue = blue;
01738     cmap_index[index].rgbGreen = green;
01739   }
01740 
01741   return(1);
01742 }
01743 
01744 // ::GRAPHICS_TILE_UPDATE()
01745 //
01746 // Called to request that a tile of graphics be drawn to the
01747 // screen, since info in this region has changed.
01748 //
01749 // tile: array of 8bit values representing a block of pixels with
01750 //       dimension equal to the 'tilewidth' & 'tileheight' parameters to
01751 //       ::specific_init().  Each value specifies an index into the
01752 //       array of colors you allocated for ::palette_change()
01753 // x0: x origin of tile
01754 // y0: y origin of tile
01755 //
01756 // note: origin of tile and of window based on (0,0) being in the upper
01757 
01758 //       left of the window.
01759 void bx_win32_gui_c::graphics_tile_update(u8* tile, unsigned x0, unsigned y0)
01760 {
01761   HDC     hdc;
01762   HGDIOBJ oldObj;
01763 
01764   EnterCriticalSection(&stInfo.drawCS);
01765   hdc = GetDC(stInfo.simWnd);
01766 
01767   oldObj = SelectObject(MemoryDC, MemoryBitmap);
01768 
01769   StretchDIBits(MemoryDC, x0, y0, x_tilesize, y_tilesize, 0, 0, x_tilesize,
01770                 y_tilesize, tile, bitmap_info, DIB_RGB_COLORS, SRCCOPY);
01771 
01772   SelectObject(MemoryDC, oldObj);
01773 
01774   updateUpdated(x0, y0, x0 + x_tilesize - 1, y0 + y_tilesize - 1);
01775 
01776   ReleaseDC(stInfo.simWnd, hdc);
01777   LeaveCriticalSection(&stInfo.drawCS);
01778 }
01779 
01780 // ::DIMENSION_UPDATE()
01781 //
01782 // Called when the VGA mode changes it's X,Y dimensions.
01783 // Resize the window to this size.
01784 //
01785 // x: new VGA x size
01786 // y: new VGA y size
01787 // fheight: new VGA character height in text mode
01788 // fwidth : new VGA character width in text mode
01789 
01790 // bpp : bits per pixel in graphics mode
01791 void bx_win32_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight,
01792                                       unsigned fwidth, unsigned bpp)
01793 {
01794   BxTextMode = (fheight > 0);
01795   if(BxTextMode)
01796   {
01797     text_cols = x / fwidth;
01798     text_rows = y / fheight;
01799     xChar = fwidth;
01800     yChar = fheight;
01801   }
01802 
01803   if(x == dimension_x && y == dimension_y && bpp == current_bpp)
01804     return;
01805   dimension_x = x;
01806   dimension_y = y;
01807   stretched_x = dimension_x;
01808   stretched_y = dimension_y;
01809   stretch_factor = 1;
01810   if(BxTextMode && (stretched_x < 400))
01811   {
01812     stretched_x *= 2;
01813     stretch_factor *= 2;
01814   }
01815 
01816   bitmap_info->bmiHeader.biBitCount = bpp;
01817   if(bpp == 16)
01818   {
01819     bitmap_info->bmiHeader.biCompression = BI_BITFIELDS;
01820 
01821     static RGBQUAD  red_mask = {0x00, 0xF8, 0x00, 0x00};
01822     static RGBQUAD  green_mask = {0xE0, 0x07, 0x00, 0x00};
01823     static RGBQUAD  blue_mask = {0x1F, 0x00, 0x00, 0x00};
01824     bitmap_info->bmiColors[256] = bitmap_info->bmiColors[0];
01825     bitmap_info->bmiColors[257] = bitmap_info->bmiColors[1];
01826     bitmap_info->bmiColors[258] = bitmap_info->bmiColors[2];
01827     bitmap_info->bmiColors[0] = red_mask;
01828     bitmap_info->bmiColors[1] = green_mask;
01829     bitmap_info->bmiColors[2] = blue_mask;
01830   }
01831   else
01832   {
01833     if(current_bpp == 16)
01834     {
01835       bitmap_info->bmiColors[0] = bitmap_info->bmiColors[256];
01836       bitmap_info->bmiColors[1] = bitmap_info->bmiColors[257];
01837       bitmap_info->bmiColors[2] = bitmap_info->bmiColors[258];
01838     }
01839 
01840     bitmap_info->bmiHeader.biCompression = BI_RGB;
01841     if(bpp == 15)
01842     {
01843       bitmap_info->bmiHeader.biBitCount = 16;
01844     }
01845   }
01846 
01847   current_bpp = bpp;
01848 
01849   resize_main_window();
01850 
01851   BX_INFO(("dimension update x=%d y=%d fontheight=%d fontwidth=%d bpp=%d", x, y,
01852             fheight, fwidth, bpp));
01853 
01854   host_xres = x;
01855   host_yres = y;
01856   host_bpp = bpp;
01857 }
01858 
01859 // ::EXIT()
01860 //
01861 // Called before bochs terminates, to allow for a graceful
01862 
01863 // exit from the native GUI mechanism.
01864 void bx_win32_gui_c::exit(void)
01865 {
01866   printf("# In bx_win32_gui_c::exit(void)!\n");
01867 
01868   // kill thread first...
01869   PostMessage(stInfo.mainWnd, WM_CLOSE, 0, 0);
01870 
01871   // Wait until it dies
01872   while((stInfo.kill == 0) && (workerThreadID != 0))
01873     Sleep(500);
01874 
01875   if(!stInfo.kill)
01876     terminateEmul(EXIT_NORMAL);
01877 }
01878 
01879 void create_vga_font(void)
01880 {
01881   unsigned char data[64];
01882 
01883   // VGA font is 8 or 9 wide and up to 32 high
01884   for(unsigned c = 0; c < 256; c++)
01885   {
01886     vgafont[c] = CreateBitmap(9, 32, 1, 1, NULL);
01887     if(!vgafont[c])
01888       terminateEmul(EXIT_FONT_BITMAP_ERROR);
01889     memset(data, 0, sizeof(data));
01890     for(unsigned i = 0; i < 16; i++)
01891       data[i * 2] = reverse_bitorder(bx_vgafont[c].data[i]);
01892     SetBitmapBits(vgafont[c], 64, data);
01893   }
01894 }
01895 
01896 unsigned char reverse_bitorder(unsigned char b)
01897 {
01898   unsigned char ret = 0;
01899 
01900   for(unsigned i = 0; i < 8; i++)
01901   {
01902     ret |= (b & 0x01) << (7 - i);
01903     b >>= 1;
01904   }
01905 
01906   return(ret);
01907 }
01908 
01909 COLORREF GetColorRef(unsigned char attr)
01910 {
01911   u8  pal_idx = text_pal_idx[attr];
01912   return RGB(cmap_index[pal_idx].rgbRed, cmap_index[pal_idx].rgbGreen,
01913              cmap_index[pal_idx].rgbBlue);
01914 }
01915 
01916 void DrawBitmap(HDC hdc, HBITMAP hBitmap, int xStart, int yStart, int width,
01917                 int height, int fcol, int frow, DWORD dwRop, unsigned char cColor)
01918 {
01919   BITMAP  bm;
01920   HDC     hdcMem;
01921   POINT   ptSize;
01922   POINT   ptOrg;
01923   HGDIOBJ oldObj;
01924 
01925   hdcMem = CreateCompatibleDC(hdc);
01926   SelectObject(hdcMem, hBitmap);
01927   SetMapMode(hdcMem, GetMapMode(hdc));
01928 
01929   GetObject(hBitmap, sizeof(BITMAP), (LPVOID) & bm);
01930 
01931   ptSize.x = width;
01932   ptSize.y = height;
01933 
01934   DPtoLP(hdc, &ptSize, 1);
01935 
01936   ptOrg.x = fcol;
01937   ptOrg.y = frow;
01938   DPtoLP(hdcMem, &ptOrg, 1);
01939 
01940   oldObj = SelectObject(MemoryDC, MemoryBitmap);
01941 
01942   // The highest background bit usually means blinking characters. No idea
01943   // how to implement that so for now it's just implemented as color.
01944   // Note: it is also possible to program the VGA controller to have the
01945   // high bit for the foreground color enable blinking characters.
01946   COLORREF  crFore = SetTextColor(MemoryDC, GetColorRef((cColor >> 4) & 0xf));
01947   COLORREF  crBack = SetBkColor(MemoryDC, GetColorRef(cColor & 0xf));
01948   BitBlt(MemoryDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y,
01949          dwRop);
01950   SetBkColor(MemoryDC, crBack);
01951   SetTextColor(MemoryDC, crFore);
01952 
01953   SelectObject(MemoryDC, oldObj);
01954 
01955   updateUpdated(xStart, yStart, ptSize.x + xStart - 1, ptSize.y + yStart - 1);
01956 
01957   DeleteDC(hdcMem);
01958 }
01959 
01960 void updateUpdated(int x1, int y1, int x2, int y2)
01961 {
01962   x1 *= stretch_factor;
01963   x2 *= stretch_factor;
01964   if(!updated_area_valid)
01965   {
01966     updated_area.left = x1;
01967     updated_area.top = y1;
01968     updated_area.right = x2;
01969     updated_area.bottom = y2;
01970   }
01971   else
01972   {
01973     if(x1 < updated_area.left)
01974       updated_area.left = x1;
01975     if(y1 < updated_area.top)
01976       updated_area.top = y1;
01977     if(x2 > updated_area.right)
01978       updated_area.right = x2;
01979     if(y2 > updated_area.bottom)
01980       updated_area.bottom = y2;
01981   }
01982 
01983   updated_area_valid = true;
01984 }
01985 
01986 void bx_win32_gui_c::mouse_enabled_changed_specific(bool val)
01987 {
01988   if((val != (bool) mouseCaptureMode) && !mouseToggleReq)
01989   {
01990     mouseToggleReq = true;
01991     mouseCaptureNew = val;
01992   }
01993 }
01994 
01995 void bx_win32_gui_c::get_capabilities(u16* xres, u16* yres, u16* bpp)
01996 {
01997   if(desktop_y > 0)
01998   {
01999     *xres = desktop_x;
02000     *yres = desktop_y;
02001     *bpp = 32;
02002   }
02003   else
02004   {
02005     *xres = 1024;
02006     *yres = 768;
02007     *bpp = 32;
02008   }
02009 }
02010 #endif /* if BX_WITH_WIN32 */

SourceForge.net Logo
Project space on SourceForge.net