2001-10-03 17:10:38 +04:00
/////////////////////////////////////////////////////////////////////////
2006-11-12 13:07:18 +03:00
// $Id: win32.cc,v 1.110 2006-11-12 10:07:18 vruppert Exp $
2001-10-03 17:10:38 +04:00
/////////////////////////////////////////////////////////////////////////
//
2002-03-21 21:40:20 +03:00
// Copyright (C) 2002 MandrakeSoft S.A.
2001-04-10 05:04:59 +04:00
//
// MandrakeSoft S.A.
// 43, rue d'Aboukir
// 75002 Paris - France
// http://www.linux-mandrake.com/
// http://www.mandrakesoft.com/
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Much of this file was written by:
// David Ross
// dross@pobox.com
2002-10-25 01:07:56 +04:00
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
# define BX_PLUGGABLE
2001-04-10 05:04:59 +04:00
# include "bochs.h"
2004-12-05 23:23:39 +03:00
# include "iodev/iodev.h"
2002-11-19 08:47:45 +03:00
# if BX_WITH_WIN32
2004-12-05 23:23:39 +03:00
# include "zmouse.h"
2005-10-22 15:00:00 +04:00
# include "win32dialog.h"
2002-12-26 21:24:41 +03:00
# include "win32res.h"
2001-04-10 05:04:59 +04:00
# include "font/vga.bitmap.h"
2002-10-04 01:07:04 +04:00
// windows.h is included by bochs.h
2002-08-10 19:23:30 +04:00
# include <commctrl.h>
2001-04-10 05:04:59 +04:00
# include <process.h>
2002-10-25 01:07:56 +04:00
class bx_win32_gui_c : public bx_gui_c {
public :
bx_win32_gui_c ( void ) { }
2006-01-22 21:15:48 +03:00
DECLARE_GUI_VIRTUAL_METHODS ( ) ;
2004-02-07 17:34:35 +03:00
virtual void statusbar_setitem ( int element , bx_bool active ) ;
2006-01-25 20:37:22 +03:00
virtual void set_tooltip ( unsigned hbar_id , const char * tip ) ;
2006-01-22 21:15:48 +03:00
# if BX_SHOW_IPS
2006-01-22 15:31:16 +03:00
virtual void show_ips ( Bit32u ips_count ) ;
2006-01-22 21:15:48 +03:00
# endif
2002-10-25 01:07:56 +04:00
} ;
// declare one instance of the gui object and call macro to insert the
// plugin code
static bx_win32_gui_c * theGui = NULL ;
IMPLEMENT_GUI_PLUGIN_CODE ( win32 )
# define LOG_THIS theGui->
2001-04-10 05:04:59 +04:00
# define EXIT_GUI_SHUTDOWN 1
# define EXIT_GMH_FAILURE 2
# define EXIT_FONT_BITMAP_ERROR 3
# define EXIT_NORMAL 4
# define EXIT_HEADER_BITMAP_ERROR 5
2005-05-08 23:10:21 +04:00
# ifndef TBSTYLE_FLAT
# define TBSTYLE_FLAT 0x0800
# endif
2003-06-20 14:36:46 +04:00
/* FIXME: Should we add a bochsrc option to control the font usage? */
# define BX_USE_WINDOWS_FONTS 0
2001-04-10 05:04:59 +04:00
// Keyboard/mouse stuff
# define SCANCODE_BUFSIZE 20
# define MOUSE_PRESSED 0x20000000
# define HEADERBAR_CLICKED 0x08000000
# define MOUSE_MOTION 0x22000000
void enq_key_event ( Bit32u , Bit32u ) ;
void enq_mouse_event ( void ) ;
struct QueueEvent {
Bit32u key_event ;
int mouse_x ;
int mouse_y ;
2004-12-05 23:23:39 +03:00
int mouse_z ;
2001-04-10 05:04:59 +04:00
int mouse_button_state ;
} ;
QueueEvent * deq_key_event ( void ) ;
static QueueEvent keyevents [ SCANCODE_BUFSIZE ] ;
static unsigned head = 0 , tail = 0 ;
2002-10-25 01:07:56 +04:00
static int mouse_button_state = 0 ;
2004-12-05 23:23:39 +03:00
static int ms_xdelta = 0 , ms_ydelta = 0 , ms_zdelta = 0 ;
2004-12-07 00:12:11 +03:00
static int ms_lastx = 0 , ms_lasty = 0 ;
static int ms_savedx = 0 , ms_savedy = 0 ;
2004-02-17 00:47:08 +03:00
static BOOL mouseCaptureMode , mouseCaptureNew , mouseToggleReq ;
2002-10-25 01:07:56 +04:00
static unsigned long workerThread = 0 ;
2001-04-10 05:04:59 +04:00
static DWORD workerThreadID = 0 ;
2004-08-18 13:03:48 +04:00
static int mouse_buttons = 3 ;
2001-04-10 05:04:59 +04:00
// Graphics screen stuff
static unsigned x_tilesize = 0 , y_tilesize = 0 ;
static BITMAPINFO * bitmap_info = ( BITMAPINFO * ) 0 ;
static RGBQUAD * cmap_index ; // indeces into system colormap
static HBITMAP MemoryBitmap = NULL ;
static HDC MemoryDC = NULL ;
static RECT updated_area ;
static BOOL updated_area_valid = FALSE ;
2006-10-15 20:23:42 +04:00
// Text mode screen stuff
static unsigned prev_cursor_x = 0 ;
static unsigned prev_cursor_y = 0 ;
static HBITMAP vgafont [ 256 ] ;
static int xChar = 8 , yChar = 16 ;
static unsigned int text_rows = 25 , text_cols = 80 ;
static Bit8u text_pal_idx [ 16 ] ;
# if !BX_USE_WINDOWS_FONTS
static Bit8u h_panning = 0 , v_panning = 0 ;
static Bit16u line_compare = 1023 ;
# else
static HFONT hFont [ 3 ] ;
static int FontId = 2 ;
# endif
2001-04-10 05:04:59 +04:00
// Headerbar stuff
2003-10-19 12:24:12 +04:00
HWND hwndTB , hwndSB ;
2002-08-10 19:23:30 +04:00
unsigned bx_bitmap_entries ;
2001-04-10 05:04:59 +04:00
struct {
HBITMAP bmap ;
unsigned xdim ;
unsigned ydim ;
} bx_bitmaps [ BX_MAX_PIXMAPS ] ;
static struct {
2002-08-10 19:23:30 +04:00
unsigned bmap_id ;
2001-04-10 05:04:59 +04:00
void ( * f ) ( void ) ;
2006-01-25 20:37:22 +03:00
const char * tooltip ;
2001-04-10 05:04:59 +04:00
} bx_headerbar_entry [ BX_MAX_HEADERBAR_ENTRIES ] ;
2002-10-25 01:07:56 +04:00
static int bx_headerbar_entries ;
2002-08-10 19:23:30 +04:00
static unsigned bx_hb_separator ;
2001-04-10 05:04:59 +04:00
2004-02-07 17:34:35 +03:00
// Status Bar stuff
2006-01-24 00:53:57 +03:00
# if BX_SHOW_IPS
static BOOL ipsUpdate = FALSE ;
static char ipsText [ 20 ] ;
2006-01-27 21:04:49 +03:00
# define BX_SB_TEXT_ELEMENTS 2
# else
# define BX_SB_TEXT_ELEMENTS 1
2006-01-24 00:53:57 +03:00
# endif
2006-01-27 21:04:49 +03:00
# define SIZE_OF_SB_ELEMENT 40
# define SIZE_OF_SB_MOUSE_MESSAGE 170
# define SIZE_OF_SB_IPS_MESSAGE 90
long SB_Edges [ BX_MAX_STATUSITEMS + BX_SB_TEXT_ELEMENTS + 1 ] ;
char SB_Text [ BX_MAX_STATUSITEMS ] [ 10 ] ;
bx_bool SB_Active [ BX_MAX_STATUSITEMS ] ;
2004-02-07 17:34:35 +03:00
2001-04-10 05:04:59 +04:00
// Misc stuff
2003-11-05 20:25:29 +03:00
static unsigned dimension_x , dimension_y , current_bpp ;
2001-04-10 05:04:59 +04:00
static unsigned stretched_x , stretched_y ;
static unsigned stretch_factor = 1 ;
2003-12-14 12:51:58 +03:00
static BOOL BxTextMode = TRUE ;
2004-02-23 19:33:52 +03:00
static BOOL legacyF12 = FALSE ;
2005-05-08 23:10:21 +04:00
static BOOL fix_size = FALSE ;
2001-04-10 05:04:59 +04:00
2004-08-18 13:03:48 +04:00
static char * szMouseEnable = " CTRL + 3rd button enables mouse " ;
static char * szMouseDisable = " CTRL + 3rd button disables mouse " ;
2006-01-25 20:37:22 +03:00
static char * szMouseTooltip = " Enable mouse capture \n Use CTRL + 3rd button to release " ;
2004-08-18 13:03:48 +04:00
2001-04-10 05:04:59 +04:00
static char szAppName [ ] = " Bochs for Windows " ;
static char szWindowName [ ] = " Bochs for Windows - Display " ;
typedef struct {
HINSTANCE hInstance ;
CRITICAL_SECTION drawCS ;
CRITICAL_SECTION keyCS ;
CRITICAL_SECTION mouseCS ;
int kill ; // reason for terminateEmul(int)
BOOL UIinited ;
2002-08-10 19:23:30 +04:00
HWND mainWnd ;
HWND simWnd ;
2001-04-10 05:04:59 +04:00
} sharedThreadInfo ;
sharedThreadInfo stInfo ;
2002-08-10 19:23:30 +04:00
LRESULT CALLBACK mainWndProc ( HWND , UINT , WPARAM , LPARAM ) ;
LRESULT CALLBACK simWndProc ( HWND , UINT , WPARAM , LPARAM ) ;
2001-04-10 05:04:59 +04:00
VOID UIThread ( PVOID ) ;
2004-08-18 13:03:48 +04:00
void SetStatusText ( int Num , const char * Text , bx_bool active ) ;
2001-04-10 05:04:59 +04:00
void terminateEmul ( int ) ;
void create_vga_font ( void ) ;
static unsigned char reverse_bitorder ( unsigned char ) ;
2003-06-22 16:37:03 +04:00
void DrawBitmap ( HDC , HBITMAP , int , int , int , int , int , int , DWORD , unsigned char ) ;
2002-03-21 21:40:20 +03:00
void DrawChar ( HDC , unsigned char , int , int , unsigned char cColor , int , int ) ;
2001-04-10 05:04:59 +04:00
void updateUpdated ( int , int , int , int ) ;
static void headerbar_click ( int x ) ;
2003-06-20 14:36:46 +04:00
# if BX_USE_WINDOWS_FONTS
2002-03-21 21:40:20 +03:00
void InitFont ( void ) ;
void DestroyFont ( void ) ;
2003-06-20 14:36:46 +04:00
# endif
2001-04-10 05:04:59 +04:00
2003-10-25 21:37:58 +04:00
Bit32u win32_to_bx_key [ 2 ] [ 0x100 ] =
{
{ /* normal-keys */
/* 0x00 - 0x0f */
0 ,
BX_KEY_ESC ,
BX_KEY_1 ,
BX_KEY_2 ,
BX_KEY_3 ,
BX_KEY_4 ,
BX_KEY_5 ,
BX_KEY_6 ,
BX_KEY_7 ,
BX_KEY_8 ,
BX_KEY_9 ,
BX_KEY_0 ,
BX_KEY_MINUS ,
BX_KEY_EQUALS ,
BX_KEY_BACKSPACE ,
BX_KEY_TAB ,
/* 0x10 - 0x1f */
BX_KEY_Q ,
BX_KEY_W ,
BX_KEY_E ,
BX_KEY_R ,
BX_KEY_T ,
BX_KEY_Y ,
BX_KEY_U ,
BX_KEY_I ,
BX_KEY_O ,
BX_KEY_P ,
BX_KEY_LEFT_BRACKET ,
BX_KEY_RIGHT_BRACKET ,
BX_KEY_ENTER ,
BX_KEY_CTRL_L ,
BX_KEY_A ,
BX_KEY_S ,
/* 0x20 - 0x2f */
BX_KEY_D ,
BX_KEY_F ,
BX_KEY_G ,
BX_KEY_H ,
BX_KEY_J ,
BX_KEY_K ,
BX_KEY_L ,
BX_KEY_SEMICOLON ,
BX_KEY_SINGLE_QUOTE ,
BX_KEY_GRAVE ,
BX_KEY_SHIFT_L ,
BX_KEY_BACKSLASH ,
BX_KEY_Z ,
BX_KEY_X ,
BX_KEY_C ,
BX_KEY_V ,
/* 0x30 - 0x3f */
BX_KEY_B ,
BX_KEY_N ,
BX_KEY_M ,
BX_KEY_COMMA ,
BX_KEY_PERIOD ,
BX_KEY_SLASH ,
BX_KEY_SHIFT_R ,
BX_KEY_KP_MULTIPLY ,
BX_KEY_ALT_L ,
BX_KEY_SPACE ,
BX_KEY_CAPS_LOCK ,
BX_KEY_F1 ,
BX_KEY_F2 ,
BX_KEY_F3 ,
BX_KEY_F4 ,
BX_KEY_F5 ,
/* 0x40 - 0x4f */
BX_KEY_F6 ,
BX_KEY_F7 ,
BX_KEY_F8 ,
BX_KEY_F9 ,
BX_KEY_F10 ,
BX_KEY_PAUSE ,
BX_KEY_SCRL_LOCK ,
BX_KEY_KP_HOME ,
BX_KEY_KP_UP ,
BX_KEY_KP_PAGE_UP ,
BX_KEY_KP_SUBTRACT ,
BX_KEY_KP_LEFT ,
BX_KEY_KP_5 ,
BX_KEY_KP_RIGHT ,
BX_KEY_KP_ADD ,
BX_KEY_KP_END ,
/* 0x50 - 0x5f */
BX_KEY_KP_DOWN ,
BX_KEY_KP_PAGE_DOWN ,
BX_KEY_KP_INSERT ,
BX_KEY_KP_DELETE ,
0 ,
0 ,
BX_KEY_LEFT_BACKSLASH ,
BX_KEY_F11 ,
BX_KEY_F12 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
/* 0x60 - 0x6f */
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
/* 0x70 - 0x7f */
0 , /* Todo: "Katakana" key ( ibm 133 ) for Japanese 106 keyboard */
0 ,
0 ,
0 , /* Todo: "Ro" key ( ibm 56 ) for Japanese 106 keyboard */
0 ,
0 ,
0 ,
0 ,
0 ,
0 , /* Todo: "convert" key ( ibm 132 ) for Japanese 106 keyboard */
0 ,
0 , /* Todo: "non-convert" key ( ibm 131 ) for Japanese 106 keyboard */
0 ,
0 , /* Todo: "Yen" key ( ibm 14 ) for Japanese 106 keyboard */
0 ,
0 ,
} ,
{ /* extended-keys */
/* 0x00 - 0x0f */
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
/* 0x10 - 0x1f */
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
BX_KEY_KP_ENTER ,
BX_KEY_CTRL_R ,
0 ,
0 ,
/* 0x20 - 0x2f */
0 ,
BX_KEY_POWER_CALC ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
/* 0x30 - 0x3f */
0 ,
0 ,
BX_KEY_INT_HOME ,
0 ,
0 ,
BX_KEY_KP_DIVIDE ,
0 ,
0 , /* ?? BX_KEY_PRINT ( ibm 124 ) ?? */
BX_KEY_ALT_R ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
/* 0x40 - 0x4f */
0 ,
0 ,
0 ,
0 ,
0 ,
BX_KEY_NUM_LOCK ,
0 ,
BX_KEY_HOME ,
BX_KEY_UP ,
BX_KEY_PAGE_UP ,
0 ,
BX_KEY_LEFT ,
0 ,
BX_KEY_RIGHT ,
0 ,
BX_KEY_END ,
/* 0x50 - 0x5f */
BX_KEY_DOWN ,
BX_KEY_PAGE_DOWN ,
BX_KEY_INSERT ,
BX_KEY_DELETE ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
BX_KEY_WIN_L ,
BX_KEY_WIN_R ,
BX_KEY_MENU ,
BX_KEY_POWER_POWER ,
BX_KEY_POWER_SLEEP ,
/* 0x60 - 0x6f */
0 ,
0 ,
0 ,
BX_KEY_POWER_WAKE ,
0 ,
BX_KEY_INT_SEARCH ,
BX_KEY_INT_FAV ,
0 ,
BX_KEY_INT_STOP ,
BX_KEY_INT_FORWARD ,
BX_KEY_INT_BACK ,
BX_KEY_POWER_MYCOMP ,
BX_KEY_INT_MAIL ,
0 ,
0 ,
0 ,
}
2003-02-17 22:08:12 +03:00
} ;
2001-04-10 05:04:59 +04:00
/* Macro to convert WM_ button state to BX button state */
2006-01-22 15:31:16 +03:00
# if defined(__MINGW32__) || defined(_MSC_VER)
2001-04-10 05:04:59 +04:00
VOID CALLBACK MyTimer ( HWND , UINT , UINT , DWORD ) ;
void alarm ( int ) ;
void bx_signal_handler ( int ) ;
# endif
2004-12-05 23:23:39 +03:00
static void processMouseXY ( int x , int y , int z , int windows_state , int implied_state_change )
2001-04-10 05:04:59 +04:00
{
int bx_state ;
int old_bx_state ;
EnterCriticalSection ( & stInfo . mouseCS ) ;
2004-02-15 03:03:16 +03:00
bx_state = ( ( windows_state & MK_LBUTTON ) ? 1 : 0 ) + ( ( windows_state & MK_RBUTTON ) ? 2 : 0 ) +
( ( windows_state & MK_MBUTTON ) ? 4 : 0 ) ;
2001-04-10 05:04:59 +04:00
old_bx_state = bx_state ^ implied_state_change ;
if ( old_bx_state ! = mouse_button_state )
{
/* Make up for missing message */
2001-05-30 22:56:02 +04:00
BX_INFO ( ( " &&&missing mouse state change " ) ) ;
2001-04-10 05:04:59 +04:00
EnterCriticalSection ( & stInfo . keyCS ) ;
enq_mouse_event ( ) ;
mouse_button_state = old_bx_state ;
enq_key_event ( mouse_button_state , MOUSE_PRESSED ) ;
LeaveCriticalSection ( & stInfo . keyCS ) ;
}
ms_ydelta = ms_savedy - y ;
ms_xdelta = x - ms_savedx ;
2004-12-07 00:12:11 +03:00
ms_zdelta = z ;
2001-04-10 05:04:59 +04:00
ms_lastx = x ;
ms_lasty = y ;
if ( bx_state ! = mouse_button_state )
{
EnterCriticalSection ( & stInfo . keyCS ) ;
enq_mouse_event ( ) ;
mouse_button_state = bx_state ;
enq_key_event ( mouse_button_state , MOUSE_PRESSED ) ;
LeaveCriticalSection ( & stInfo . keyCS ) ;
}
LeaveCriticalSection ( & stInfo . mouseCS ) ;
}
static void resetDelta ( )
{
EnterCriticalSection ( & stInfo . mouseCS ) ;
ms_savedx = ms_lastx ;
ms_savedy = ms_lasty ;
2004-12-05 23:23:39 +03:00
ms_ydelta = ms_xdelta = ms_zdelta = 0 ;
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . mouseCS ) ;
}
static void cursorWarped ( )
{
EnterCriticalSection ( & stInfo . mouseCS ) ;
EnterCriticalSection ( & stInfo . keyCS ) ;
enq_mouse_event ( ) ;
LeaveCriticalSection ( & stInfo . keyCS ) ;
ms_lastx = stretched_x / 2 ;
ms_lasty = stretched_y / 2 ;
ms_savedx = ms_lastx ;
ms_savedy = ms_lasty ;
LeaveCriticalSection ( & stInfo . mouseCS ) ;
}
// GUI thread must be dead/done in order to call terminateEmul
void terminateEmul ( int reason ) {
// We know that Critical Sections were inited when x_tilesize has been set
2002-10-25 01:07:56 +04:00
// See bx_win32_gui_c::specific_init
2001-04-10 05:04:59 +04:00
if ( x_tilesize ! = 0 ) {
DeleteCriticalSection ( & stInfo . drawCS ) ;
DeleteCriticalSection ( & stInfo . keyCS ) ;
DeleteCriticalSection ( & stInfo . mouseCS ) ;
}
2002-08-10 19:23:30 +04:00
x_tilesize = 0 ;
2001-04-10 05:04:59 +04:00
if ( MemoryDC ) DeleteDC ( MemoryDC ) ;
if ( MemoryBitmap ) DeleteObject ( MemoryBitmap ) ;
if ( bitmap_info ) delete [ ] ( char * ) bitmap_info ;
2002-08-10 00:25:02 +04:00
for ( unsigned b = 0 ; b < bx_bitmap_entries ; b + + )
if ( bx_bitmaps [ b ] . bmap ) DeleteObject ( bx_bitmaps [ b ] . bmap ) ;
2001-04-10 05:04:59 +04:00
for ( unsigned c = 0 ; c < 256 ; c + + )
if ( vgafont [ c ] ) DeleteObject ( vgafont [ c ] ) ;
2002-08-10 00:25:02 +04:00
LOG_THIS setonoff ( LOGLEV_PANIC , ACT_FATAL ) ;
2001-04-10 05:04:59 +04:00
switch ( reason ) {
case EXIT_GUI_SHUTDOWN :
2001-05-30 22:56:02 +04:00
BX_PANIC ( ( " Window closed, exiting! " ) ) ;
2001-04-10 05:04:59 +04:00
break ;
case EXIT_GMH_FAILURE :
2001-05-30 22:56:02 +04:00
BX_PANIC ( ( " GetModuleHandle failure! " ) ) ;
2001-04-10 05:04:59 +04:00
break ;
case EXIT_FONT_BITMAP_ERROR :
2001-05-30 22:56:02 +04:00
BX_PANIC ( ( " Font bitmap creation failure! " ) ) ;
2001-04-10 05:04:59 +04:00
break ;
case EXIT_HEADER_BITMAP_ERROR :
2001-05-30 22:56:02 +04:00
BX_PANIC ( ( " Header bitmap creation failure! " ) ) ;
2001-04-10 05:04:59 +04:00
break ;
case EXIT_NORMAL :
break ;
}
}
// ::SPECIFIC_INIT()
//
// Called from gui.cc, once upon program startup, to allow for the
// specific GUI code (X11, BeOS, ...) to be initialized.
//
// argc, argv: not used right now, but the intention is to pass native GUI
// specific options from the command line. (X11 options, BeOS options,...)
//
// tilewidth, tileheight: for optimization, graphics_tile_update() passes
// only updated regions of the screen to the gui code to be redrawn.
// These define the dimensions of a region (tile).
// headerbar_y: A headerbar (toolbar) is display on the top of the
// VGA window, showing floppy status, and other information. It
// always assumes the width of the current VGA mode width, but
// it's height is defined by this parameter.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : specific_init ( int argc , char * * argv , unsigned
2004-02-23 19:33:52 +03:00
tilewidth , unsigned tileheight ,
2004-02-24 22:21:48 +03:00
unsigned headerbar_y )
{
2005-02-03 21:43:23 +03:00
int i ;
2004-02-23 19:33:52 +03:00
2002-10-25 01:07:56 +04:00
put ( " WGUI " ) ;
2001-04-10 05:04:59 +04:00
static RGBQUAD black_quad = { 0 , 0 , 0 , 0 } ;
stInfo . kill = 0 ;
stInfo . UIinited = FALSE ;
InitializeCriticalSection ( & stInfo . drawCS ) ;
InitializeCriticalSection ( & stInfo . keyCS ) ;
InitializeCriticalSection ( & stInfo . mouseCS ) ;
x_tilesize = tilewidth ;
y_tilesize = tileheight ;
2002-08-10 19:23:30 +04:00
bx_bitmap_entries = 0 ;
bx_headerbar_entries = 0 ;
bx_hb_separator = 0 ;
mouseCaptureMode = FALSE ;
2004-02-17 00:47:08 +03:00
mouseCaptureNew = FALSE ;
mouseToggleReq = FALSE ;
2004-08-18 13:03:48 +04:00
mouse_buttons = GetSystemMetrics ( SM_CMOUSEBUTTONS ) ;
BX_INFO ( ( " Number of Mouse Buttons = %d " , mouse_buttons ) ) ;
if ( mouse_buttons = = 2 ) {
szMouseEnable = " CTRL + Lbutton + Rbutton enables mouse " ;
szMouseDisable = " CTRL + Lbutton + Rbutton disables mouse " ;
2006-01-25 20:37:22 +03:00
szMouseTooltip = " Enable mouse capture \n Use CTRL + Lbutton + Rbutton to release " ;
2004-08-18 13:03:48 +04:00
}
// parse win32 specific options
if ( argc > 1 ) {
for ( i = 1 ; i < argc ; i + + ) {
2004-08-22 20:22:09 +04:00
BX_INFO ( ( " option %d: %s " , i , argv [ i ] ) ) ;
2004-08-18 13:03:48 +04:00
if ( ! strcmp ( argv [ i ] , " legacyF12 " ) ) {
legacyF12 = TRUE ;
2006-11-12 13:07:18 +03:00
# if BX_DEBUGGER
} else if ( ! strcmp ( argv [ i ] , " windebug " ) ) {
SIM - > set_debug_gui ( 1 ) ;
# endif
2004-08-18 13:03:48 +04:00
} else {
BX_PANIC ( ( " Unknown win32 option '%s' " , argv [ i ] ) ) ;
}
}
}
if ( legacyF12 ) {
szMouseEnable = " Press F12 to enable mouse " ;
szMouseDisable = " Press F12 to disable mouse " ;
2006-01-25 20:37:22 +03:00
szMouseTooltip = " Enable mouse capture \n Use F12 to release " ;
2004-08-18 13:03:48 +04:00
}
2001-04-10 05:04:59 +04:00
stInfo . hInstance = GetModuleHandle ( NULL ) ;
2002-08-10 19:23:30 +04:00
UNUSED ( headerbar_y ) ;
2001-04-10 05:04:59 +04:00
dimension_x = 640 ;
2002-08-10 19:23:30 +04:00
dimension_y = 480 ;
2003-11-05 20:25:29 +03:00
current_bpp = 8 ;
2001-04-10 05:04:59 +04:00
stretched_x = dimension_x ;
stretched_y = dimension_y ;
stretch_factor = 1 ;
for ( unsigned c = 0 ; c < 256 ; c + + ) vgafont [ c ] = NULL ;
create_vga_font ( ) ;
bitmap_info = ( BITMAPINFO * ) new char [ sizeof ( BITMAPINFOHEADER ) +
2005-03-23 23:46:52 +03:00
259 * sizeof ( RGBQUAD ) ] ; // 256 + 3 entries for 16 bpp mode
2001-04-10 05:04:59 +04:00
bitmap_info - > bmiHeader . biSize = sizeof ( BITMAPINFOHEADER ) ;
bitmap_info - > bmiHeader . biWidth = x_tilesize ;
// Height is negative for top-down bitmap
2006-10-15 20:23:42 +04:00
bitmap_info - > bmiHeader . biHeight = - ( LONG ) y_tilesize ;
2001-04-10 05:04:59 +04:00
bitmap_info - > bmiHeader . biPlanes = 1 ;
bitmap_info - > bmiHeader . biBitCount = 8 ;
bitmap_info - > bmiHeader . biCompression = BI_RGB ;
2003-06-28 12:04:31 +04:00
bitmap_info - > bmiHeader . biSizeImage = x_tilesize * y_tilesize * 4 ;
2001-04-10 05:04:59 +04:00
// I think these next two figures don't matter; saying 45 pixels/centimeter
bitmap_info - > bmiHeader . biXPelsPerMeter = 4500 ;
bitmap_info - > bmiHeader . biYPelsPerMeter = 4500 ;
bitmap_info - > bmiHeader . biClrUsed = 256 ;
bitmap_info - > bmiHeader . biClrImportant = 0 ;
cmap_index = bitmap_info - > bmiColors ;
// start out with all color map indeces pointing to Black
cmap_index [ 0 ] = black_quad ;
2005-03-23 23:46:52 +03:00
for ( i = 1 ; i < 259 ; i + + ) {
2001-04-10 05:04:59 +04:00
cmap_index [ i ] = cmap_index [ 0 ] ;
}
if ( stInfo . hInstance )
workerThread = _beginthread ( UIThread , 0 , NULL ) ;
else
terminateEmul ( EXIT_GMH_FAILURE ) ;
// Wait for a window before continuing
if ( ( stInfo . kill = = 0 ) & & ( FindWindow ( szAppName , NULL ) = = NULL ) )
Sleep ( 500 ) ;
// Now set this thread's priority to below normal because this is where
// the emulated CPU runs, and it hogs the real CPU
SetThreadPriority ( GetCurrentThread ( ) , THREAD_PRIORITY_BELOW_NORMAL ) ;
2006-02-22 00:35:09 +03:00
if ( SIM - > get_param_bool ( BXPN_PRIVATE_COLORMAP ) - > get ( ) )
BX_INFO ( ( " private_colormap option ignored. " ) ) ;
2002-03-16 14:30:06 +03:00
// load keymap tables
2006-02-22 22:18:29 +03:00
if ( SIM - > get_param_bool ( BXPN_KBD_USEMAPPING ) - > get ( ) ) {
2002-03-16 14:30:06 +03:00
bx_keymap . loadKeymap ( NULL ) ; // I have no function to convert X windows symbols
2005-10-21 22:00:17 +04:00
}
2004-02-23 19:33:52 +03:00
2005-10-22 15:00:00 +04:00
win32_init_notify_callback ( ) ;
2005-11-12 19:09:55 +03:00
dialog_caps = BX_GUI_DLG_ALL ;
2001-04-10 05:04:59 +04:00
}
2005-05-08 23:10:21 +04:00
void resize_main_window ( )
{
RECT R ;
int toolbar_y = 0 ;
int statusbar_y = 0 ;
if ( IsWindowVisible ( hwndTB ) ) {
GetWindowRect ( hwndTB , & R ) ;
toolbar_y = R . bottom - R . top ;
}
if ( IsWindowVisible ( hwndSB ) ) {
GetWindowRect ( hwndSB , & R ) ;
statusbar_y = R . bottom - R . top ;
}
SetRect ( & R , 0 , 0 , stretched_x , stretched_y ) ;
DWORD style = GetWindowLong ( stInfo . simWnd , GWL_STYLE ) ;
DWORD exstyle = GetWindowLong ( stInfo . simWnd , GWL_EXSTYLE ) ;
AdjustWindowRectEx ( & R , style , FALSE , exstyle ) ;
style = GetWindowLong ( stInfo . mainWnd , GWL_STYLE ) ;
AdjustWindowRect ( & R , style , FALSE ) ;
SetWindowPos ( stInfo . mainWnd , HWND_TOP , 0 , 0 , R . right - R . left ,
R . bottom - R . top + toolbar_y + statusbar_y ,
SWP_NOMOVE | SWP_NOZORDER ) ;
fix_size = FALSE ;
}
2001-04-10 05:04:59 +04:00
// This thread controls the GUI window.
VOID UIThread ( PVOID pvoid ) {
MSG msg ;
HDC hdc ;
2002-12-29 21:39:21 +03:00
WNDCLASS wndclass ;
2005-05-08 23:10:21 +04:00
RECT wndRect ;
2001-04-10 05:04:59 +04:00
workerThreadID = GetCurrentThreadId ( ) ;
2005-05-08 23:10:21 +04:00
GetClassInfo ( NULL , WC_DIALOG , & wndclass ) ;
2001-04-10 05:04:59 +04:00
wndclass . style = CS_HREDRAW | CS_VREDRAW ;
2002-08-10 19:23:30 +04:00
wndclass . lpfnWndProc = mainWndProc ;
2001-04-10 05:04:59 +04:00
wndclass . cbClsExtra = 0 ;
wndclass . cbWndExtra = 0 ;
wndclass . hInstance = stInfo . hInstance ;
2002-12-26 21:24:41 +03:00
wndclass . hIcon = LoadIcon ( stInfo . hInstance , MAKEINTRESOURCE ( ICON_BOCHS ) ) ;
2001-04-10 05:04:59 +04:00
wndclass . lpszMenuName = NULL ;
wndclass . lpszClassName = szAppName ;
2002-12-29 21:39:21 +03:00
RegisterClass ( & wndclass ) ;
2001-04-10 05:04:59 +04:00
2002-08-10 19:23:30 +04:00
wndclass . style = CS_HREDRAW | CS_VREDRAW ;
wndclass . lpfnWndProc = simWndProc ;
wndclass . cbClsExtra = 0 ;
wndclass . cbWndExtra = 0 ;
wndclass . hInstance = stInfo . hInstance ;
2002-12-26 21:24:41 +03:00
wndclass . hIcon = NULL ;
2002-08-10 19:23:30 +04:00
wndclass . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wndclass . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
wndclass . lpszMenuName = NULL ;
wndclass . lpszClassName = " SIMWINDOW " ;
2002-12-29 21:39:21 +03:00
RegisterClass ( & wndclass ) ;
2002-08-10 19:23:30 +04:00
2005-05-08 23:10:21 +04:00
SetRect ( & wndRect , 0 , 0 , stretched_x , stretched_y ) ;
DWORD sim_style = WS_CHILD ;
DWORD sim_exstyle = WS_EX_CLIENTEDGE ;
AdjustWindowRectEx ( & wndRect , sim_style , FALSE , sim_exstyle ) ;
DWORD main_style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX ;
AdjustWindowRect ( & wndRect , main_style , FALSE ) ;
2002-08-10 19:23:30 +04:00
stInfo . mainWnd = CreateWindow ( szAppName ,
szWindowName ,
2005-05-08 23:10:21 +04:00
main_style ,
2002-08-10 19:23:30 +04:00
CW_USEDEFAULT ,
CW_USEDEFAULT ,
2005-05-08 23:10:21 +04:00
wndRect . right - wndRect . left ,
wndRect . bottom - wndRect . top ,
2002-08-10 19:23:30 +04:00
NULL ,
NULL ,
stInfo . hInstance ,
NULL ) ;
if ( stInfo . mainWnd ) {
2002-08-11 17:01:49 +04:00
InitCommonControls ( ) ;
2002-08-10 19:23:30 +04:00
hwndTB = CreateWindowEx ( 0 , TOOLBARCLASSNAME , ( LPSTR ) NULL ,
2006-01-25 20:37:22 +03:00
WS_CHILD | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT , 0 , 0 , 0 , 0 , stInfo . mainWnd ,
2002-08-10 19:23:30 +04:00
( HMENU ) 100 , stInfo . hInstance , NULL ) ;
SendMessage ( hwndTB , TB_BUTTONSTRUCTSIZE , ( WPARAM ) sizeof ( TBBUTTON ) , 0 ) ;
SendMessage ( hwndTB , TB_SETBITMAPSIZE , 0 , ( LPARAM ) MAKELONG ( 32 , 32 ) ) ;
2005-05-08 23:10:21 +04:00
2004-08-18 13:03:48 +04:00
hwndSB = CreateStatusWindow ( WS_CHILD | WS_VISIBLE , " " ,
2003-10-19 12:24:12 +04:00
stInfo . mainWnd , 0x7712 ) ;
if ( hwndSB ) {
2004-02-07 17:34:35 +03:00
int elements ;
2006-01-27 21:04:49 +03:00
SB_Edges [ 0 ] = SIZE_OF_SB_MOUSE_MESSAGE + SIZE_OF_SB_ELEMENT ;
# if BX_SHOW_IPS
SB_Edges [ 1 ] = SB_Edges [ 0 ] + SIZE_OF_SB_IPS_MESSAGE ;
# endif
for ( elements = BX_SB_TEXT_ELEMENTS ; elements < ( BX_MAX_STATUSITEMS + BX_SB_TEXT_ELEMENTS ) ; elements + + )
2004-02-07 17:34:35 +03:00
SB_Edges [ elements ] = SB_Edges [ elements - 1 ] + SIZE_OF_SB_ELEMENT ;
SB_Edges [ elements ] = - 1 ;
2006-01-27 21:04:49 +03:00
SendMessage ( hwndSB , SB_SETPARTS , BX_MAX_STATUSITEMS + BX_SB_TEXT_ELEMENTS + 1 , ( long ) & SB_Edges ) ;
2003-10-19 12:24:12 +04:00
}
2004-08-18 13:03:48 +04:00
SetStatusText ( 0 , szMouseEnable , TRUE ) ;
2005-05-08 23:10:21 +04:00
stInfo . simWnd = CreateWindowEx ( sim_exstyle ,
" SIMWINDOW " ,
2002-08-10 19:23:30 +04:00
" " ,
2005-05-08 23:10:21 +04:00
sim_style ,
0 ,
0 ,
0 ,
2002-08-10 19:23:30 +04:00
0 ,
stInfo . mainWnd ,
NULL ,
stInfo . hInstance ,
NULL ) ;
2003-05-04 20:03:23 +04:00
/* needed for the Japanese versions of Windows */
if ( stInfo . simWnd ) {
HMODULE hm ;
hm = GetModuleHandle ( " USER32 " ) ;
if ( hm ) {
BOOL ( WINAPI * enableime ) ( HWND , BOOL ) ;
enableime = ( BOOL ( WINAPI * ) ( HWND , BOOL ) ) GetProcAddress ( hm , " WINNLSEnableIME " ) ;
if ( enableime ) {
enableime ( stInfo . simWnd , FALSE ) ;
BX_INFO ( ( " IME disabled " ) ) ;
}
}
}
2002-08-10 19:23:30 +04:00
ShowWindow ( stInfo . simWnd , SW_SHOW ) ;
SetFocus ( stInfo . simWnd ) ;
2001-04-10 05:04:59 +04:00
2001-06-04 06:45:28 +04:00
ShowCursor ( ! mouseCaptureMode ) ;
2005-05-08 23:10:21 +04:00
POINT pt = { 0 , 0 } ;
ClientToScreen ( stInfo . simWnd , & pt ) ;
SetCursorPos ( pt . x + stretched_x / 2 , pt . y + stretched_y / 2 ) ;
2001-04-10 05:04:59 +04:00
cursorWarped ( ) ;
2002-03-28 04:12:26 +03:00
2002-08-10 19:23:30 +04:00
hdc = GetDC ( stInfo . simWnd ) ;
2002-03-28 04:12:26 +03:00
MemoryBitmap = CreateCompatibleBitmap ( hdc , BX_MAX_XRES , BX_MAX_YRES ) ;
MemoryDC = CreateCompatibleDC ( hdc ) ;
2002-08-10 19:23:30 +04:00
ReleaseDC ( stInfo . simWnd , hdc ) ;
2002-03-28 04:12:26 +03:00
2001-04-10 05:04:59 +04:00
if ( MemoryBitmap & & MemoryDC ) {
2005-05-08 23:10:21 +04:00
resize_main_window ( ) ;
ShowWindow ( stInfo . mainWnd , SW_SHOW ) ;
2001-04-10 05:04:59 +04:00
stInfo . UIinited = TRUE ;
2003-09-17 23:47:41 +04:00
bx_gui - > clear_screen ( ) ;
2001-04-10 05:04:59 +04:00
while ( GetMessage ( & msg , NULL , 0 , 0 ) ) {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
}
stInfo . kill = EXIT_GUI_SHUTDOWN ;
_endthread ( ) ;
}
2004-02-08 13:25:50 +03:00
void SetStatusText ( int Num , const char * Text , bx_bool active )
2003-10-19 12:24:12 +04:00
{
char StatText [ MAX_PATH ] ;
2006-01-27 21:04:49 +03:00
if ( ( Num < BX_SB_TEXT_ELEMENTS ) | | ( Num > ( BX_MAX_STATUSITEMS + BX_SB_TEXT_ELEMENTS ) ) ) {
StatText [ 0 ] = ' ' ; // Add space to text in 1st and last items
lstrcpy ( StatText + 1 , Text ) ;
2004-02-08 13:25:50 +03:00
SendMessage ( hwndSB , SB_SETTEXT , Num , ( long ) StatText ) ;
2004-02-08 21:38:26 +03:00
} else {
2006-01-27 21:04:49 +03:00
StatText [ 0 ] = 9 ; // Center the rest
lstrcpy ( StatText + 1 , Text ) ;
lstrcpy ( SB_Text [ Num - BX_SB_TEXT_ELEMENTS ] , StatText ) ;
SB_Active [ Num - BX_SB_TEXT_ELEMENTS ] = active ;
SendMessage ( hwndSB , SB_SETTEXT , Num | SBT_OWNERDRAW , ( long ) SB_Text [ Num - BX_SB_TEXT_ELEMENTS ] ) ;
2004-02-08 13:25:50 +03:00
}
2004-02-07 17:34:35 +03:00
UpdateWindow ( hwndSB ) ;
}
void
bx_win32_gui_c : : statusbar_setitem ( int element , bx_bool active )
{
2004-02-08 13:25:50 +03:00
if ( element < 0 ) {
2005-06-07 00:14:50 +04:00
for ( int i = 0 ; i < ( int ) statusitem_count ; i + + ) {
2006-01-27 21:04:49 +03:00
SetStatusText ( i + BX_SB_TEXT_ELEMENTS , statusitem_text [ i ] , active ) ;
2004-02-08 13:25:50 +03:00
}
2005-06-07 00:14:50 +04:00
} else if ( element < ( int ) statusitem_count ) {
2006-01-27 21:04:49 +03:00
SetStatusText ( element + BX_SB_TEXT_ELEMENTS , statusitem_text [ element ] , active ) ;
2004-02-07 17:34:35 +03:00
}
2003-10-19 12:24:12 +04:00
}
2004-02-08 13:25:50 +03:00
LRESULT CALLBACK mainWndProc ( HWND hwnd , UINT iMsg , WPARAM wParam , LPARAM lParam )
{
DRAWITEMSTRUCT * lpdis ;
char * sbtext ;
2006-01-25 20:37:22 +03:00
NMHDR * lpnmh ;
TOOLTIPTEXT * lpttt ;
int idTT , hbar_id ;
2003-10-25 15:57:42 +04:00
2002-08-10 19:23:30 +04:00
switch ( iMsg ) {
case WM_CREATE :
2004-12-28 17:38:30 +03:00
SetStatusText ( 0 , szMouseEnable , TRUE ) ;
2002-08-10 19:23:30 +04:00
return 0 ;
case WM_COMMAND :
if ( LOWORD ( wParam ) > = 101 ) {
EnterCriticalSection ( & stInfo . keyCS ) ;
enq_key_event ( LOWORD ( wParam ) - 101 , HEADERBAR_CLICKED ) ;
LeaveCriticalSection ( & stInfo . keyCS ) ;
}
break ;
case WM_SETFOCUS :
SetFocus ( stInfo . simWnd ) ;
return 0 ;
case WM_CLOSE :
SendMessage ( stInfo . simWnd , WM_CLOSE , 0 , 0 ) ;
break ;
case WM_DESTROY :
PostQuitMessage ( 0 ) ;
return 0 ;
2003-11-14 18:43:12 +03:00
case WM_SIZE :
2005-05-08 23:10:21 +04:00
{
SendMessage ( hwndTB , TB_AUTOSIZE , 0 , 0 ) ;
SendMessage ( hwndSB , WM_SIZE , 0 , 0 ) ;
int rect_data [ ] = { 1 , 0 , IsWindowVisible ( hwndTB ) , 100 , IsWindowVisible ( hwndSB ) , 0x7712 , 0 , 0 } ;
RECT R ;
GetEffectiveClientRect ( hwnd , & R , rect_data ) ;
MoveWindow ( stInfo . simWnd , R . left , R . top , R . right - R . left , R . bottom - R . top , TRUE ) ;
GetClientRect ( stInfo . simWnd , & R ) ;
2006-10-15 20:23:42 +04:00
if ( ( ( R . right - R . left ) ! = ( int ) stretched_x ) | | ( ( R . bottom - R . top ) ! = ( int ) stretched_y ) ) {
2005-05-08 23:10:21 +04:00
BX_ERROR ( ( " Sim window's client size(%d, %d) was different from the stretched size(%d, %d) !! " , ( R . right - R . left ) , ( R . bottom - R . top ) , stretched_x , stretched_y ) ) ;
fix_size = TRUE ;
}
}
2003-11-14 18:43:12 +03:00
break ;
2004-02-08 13:25:50 +03:00
case WM_DRAWITEM :
lpdis = ( DRAWITEMSTRUCT * ) lParam ;
if ( lpdis - > hwndItem = = hwndSB ) {
sbtext = ( char * ) lpdis - > itemData ;
2006-01-27 21:04:49 +03:00
if ( SB_Active [ lpdis - > itemID - BX_SB_TEXT_ELEMENTS ] ) {
2004-02-08 21:38:26 +03:00
SetBkColor ( lpdis - > hDC , 0x0000FF00 ) ;
} else {
SetBkMode ( lpdis - > hDC , TRANSPARENT ) ;
SetTextColor ( lpdis - > hDC , 0x00808080 ) ;
}
2004-02-08 13:25:50 +03:00
DrawText ( lpdis - > hDC , sbtext + 1 , lstrlen ( sbtext ) - 1 , & lpdis - > rcItem , DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
return TRUE ;
}
break ;
2006-01-25 20:37:22 +03:00
case WM_NOTIFY :
lpnmh = ( LPNMHDR ) lParam ;
if ( ( int ) lpnmh - > code = = TTN_NEEDTEXT ) {
lpttt = ( LPTOOLTIPTEXT ) lParam ;
idTT = ( int ) wParam ;
hbar_id = idTT - 101 ;
if ( ( SendMessage ( hwndTB , TB_GETSTATE , idTT , 0 ) ) & &
( bx_headerbar_entry [ hbar_id ] . tooltip ! = NULL ) ) {
lstrcpy ( lpttt - > szText , bx_headerbar_entry [ hbar_id ] . tooltip ) ;
}
}
return FALSE ;
break ;
2002-08-10 19:23:30 +04:00
}
return DefWindowProc ( hwnd , iMsg , wParam , lParam ) ;
}
2004-02-17 00:47:08 +03:00
void SetMouseCapture ( )
{
2005-05-08 23:10:21 +04:00
POINT pt = { 0 , 0 } ;
2004-02-17 00:47:08 +03:00
2004-12-28 17:38:30 +03:00
if ( mouseToggleReq ) {
mouseCaptureMode = mouseCaptureNew ;
mouseToggleReq = FALSE ;
} else {
2006-02-22 22:18:29 +03:00
SIM - > get_param_bool ( BXPN_MOUSE_ENABLED ) - > set ( mouseCaptureMode ) ;
2004-12-28 17:38:30 +03:00
}
2004-02-17 00:47:08 +03:00
ShowCursor ( ! mouseCaptureMode ) ;
ShowCursor ( ! mouseCaptureMode ) ; // somehow one didn't do the trick (win98)
2005-05-08 23:10:21 +04:00
ClientToScreen ( stInfo . simWnd , & pt ) ;
SetCursorPos ( pt . x + stretched_x / 2 , pt . y + stretched_y / 2 ) ;
2004-02-17 00:47:08 +03:00
cursorWarped ( ) ;
if ( mouseCaptureMode )
2004-08-18 13:03:48 +04:00
SetStatusText ( 0 , szMouseDisable , TRUE ) ;
2004-02-17 00:47:08 +03:00
else
2004-08-18 13:03:48 +04:00
SetStatusText ( 0 , szMouseEnable , TRUE ) ;
2004-02-17 00:47:08 +03:00
}
2002-08-10 19:23:30 +04:00
2004-02-15 14:30:28 +03:00
LRESULT CALLBACK simWndProc ( HWND hwnd , UINT iMsg , WPARAM wParam , LPARAM lParam )
{
2001-04-10 05:04:59 +04:00
HDC hdc , hdcMem ;
PAINTSTRUCT ps ;
2005-05-08 23:10:21 +04:00
POINT pt ;
2004-02-15 14:30:28 +03:00
static BOOL mouseModeChange = FALSE ;
2001-04-10 05:04:59 +04:00
switch ( iMsg ) {
case WM_CREATE :
2003-06-20 14:36:46 +04:00
# if BX_USE_WINDOWS_FONTS
2002-03-21 21:40:20 +03:00
InitFont ( ) ;
2003-06-20 14:36:46 +04:00
# endif
2001-04-10 05:04:59 +04:00
SetTimer ( hwnd , 1 , 330 , NULL ) ;
return 0 ;
case WM_TIMER :
2004-02-17 00:47:08 +03:00
if ( mouseToggleReq & & ( GetActiveWindow ( ) = = stInfo . mainWnd ) ) {
SetMouseCapture ( ) ;
}
2001-04-10 05:04:59 +04:00
// If mouse escaped, bring it back
if ( mouseCaptureMode )
{
2005-05-08 23:10:21 +04:00
pt . x = 0 ;
pt . y = 0 ;
ClientToScreen ( hwnd , & pt ) ;
SetCursorPos ( pt . x + stretched_x / 2 , pt . y + stretched_y / 2 ) ;
2001-10-08 04:42:52 +04:00
cursorWarped ( ) ;
2001-04-10 05:04:59 +04:00
}
2005-05-08 23:10:21 +04:00
if ( fix_size ) {
resize_main_window ( ) ;
}
2001-04-10 05:04:59 +04:00
return 0 ;
case WM_PAINT :
EnterCriticalSection ( & stInfo . drawCS ) ;
hdc = BeginPaint ( hwnd , & ps ) ;
hdcMem = CreateCompatibleDC ( hdc ) ;
SelectObject ( hdcMem , MemoryBitmap ) ;
2003-09-17 23:47:41 +04:00
if ( stretch_factor = = 1 ) {
BitBlt ( hdc , ps . rcPaint . left , ps . rcPaint . top ,
ps . rcPaint . right - ps . rcPaint . left + 1 ,
ps . rcPaint . bottom - ps . rcPaint . top + 1 , hdcMem ,
ps . rcPaint . left , ps . rcPaint . top , SRCCOPY ) ;
} else {
StretchBlt ( hdc , ps . rcPaint . left , ps . rcPaint . top ,
ps . rcPaint . right - ps . rcPaint . left + 1 ,
ps . rcPaint . bottom - ps . rcPaint . top + 1 , hdcMem ,
ps . rcPaint . left / stretch_factor , ps . rcPaint . top ,
( ps . rcPaint . right - ps . rcPaint . left + 1 ) / stretch_factor ,
( ps . rcPaint . bottom - ps . rcPaint . top + 1 ) , SRCCOPY ) ;
}
2001-04-10 05:04:59 +04:00
DeleteDC ( hdcMem ) ;
EndPaint ( hwnd , & ps ) ;
LeaveCriticalSection ( & stInfo . drawCS ) ;
return 0 ;
case WM_MOUSEMOVE :
2004-02-15 14:30:28 +03:00
if ( ! mouseModeChange ) {
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 0 ) ;
}
return 0 ;
case WM_MOUSEWHEEL :
if ( ! mouseModeChange ) {
2004-12-07 00:12:11 +03:00
// WM_MOUSEWHEEL returns x and y relative to the main screen.
// WM_MOUSEMOVE below returns x and y relative to the current view.
2005-05-11 22:00:02 +04:00
POINT pt ;
pt . x = LOWORD ( lParam ) ;
pt . y = HIWORD ( lParam ) ;
ScreenToClient ( stInfo . simWnd , & pt ) ;
processMouseXY ( pt . x , pt . y , ( Bit16s ) HIWORD ( wParam ) / 120 , LOWORD ( wParam ) , 0 ) ;
2004-02-15 14:30:28 +03:00
}
2001-04-10 05:04:59 +04:00
return 0 ;
case WM_LBUTTONDOWN :
case WM_LBUTTONDBLCLK :
case WM_LBUTTONUP :
2004-08-18 13:03:48 +04:00
if ( mouse_buttons = = 2 ) {
if ( wParam = = ( MK_CONTROL | MK_LBUTTON | MK_RBUTTON ) ) {
mouseCaptureMode = ! mouseCaptureMode ;
SetMouseCapture ( ) ;
mouseModeChange = TRUE ;
} else if ( mouseModeChange & & ( iMsg = = WM_LBUTTONUP ) ) {
mouseModeChange = FALSE ;
} else {
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 1 ) ;
2004-08-18 13:03:48 +04:00
}
return 0 ;
}
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 1 ) ;
2001-04-10 05:04:59 +04:00
return 0 ;
2004-02-15 03:03:16 +03:00
case WM_MBUTTONDOWN :
case WM_MBUTTONDBLCLK :
case WM_MBUTTONUP :
2004-02-15 14:30:28 +03:00
if ( wParam = = ( MK_CONTROL | MK_MBUTTON ) ) {
mouseCaptureMode = ! mouseCaptureMode ;
2004-02-17 00:47:08 +03:00
SetMouseCapture ( ) ;
2004-02-15 14:30:28 +03:00
mouseModeChange = TRUE ;
} else if ( mouseModeChange & & ( iMsg = = WM_MBUTTONUP ) ) {
mouseModeChange = FALSE ;
} else {
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 4 ) ;
2004-02-15 14:30:28 +03:00
}
2004-02-15 03:03:16 +03:00
return 0 ;
2001-04-10 05:04:59 +04:00
case WM_RBUTTONDOWN :
case WM_RBUTTONDBLCLK :
case WM_RBUTTONUP :
2004-08-18 13:03:48 +04:00
if ( mouse_buttons = = 2 ) {
if ( wParam = = ( MK_CONTROL | MK_LBUTTON | MK_RBUTTON ) ) {
mouseCaptureMode = ! mouseCaptureMode ;
SetMouseCapture ( ) ;
mouseModeChange = TRUE ;
} else if ( mouseModeChange & & ( iMsg = = WM_RBUTTONUP ) ) {
mouseModeChange = FALSE ;
} else {
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 2 ) ;
2004-08-18 13:03:48 +04:00
}
return 0 ;
}
2004-12-05 23:23:39 +03:00
processMouseXY ( LOWORD ( lParam ) , HIWORD ( lParam ) , 0 , wParam , 2 ) ;
2004-02-15 03:03:16 +03:00
return 0 ;
2001-04-10 05:04:59 +04:00
case WM_CLOSE :
return DefWindowProc ( hwnd , iMsg , wParam , lParam ) ;
case WM_DESTROY :
KillTimer ( hwnd , 1 ) ;
stInfo . UIinited = FALSE ;
2003-06-20 14:36:46 +04:00
# if BX_USE_WINDOWS_FONTS
2002-03-21 21:40:20 +03:00
DestroyFont ( ) ;
2003-06-20 14:36:46 +04:00
# endif
2001-04-10 05:04:59 +04:00
return 0 ;
case WM_KEYDOWN :
case WM_SYSKEYDOWN :
2004-02-23 19:33:52 +03:00
if ( legacyF12 & & ( wParam = = VK_F12 ) ) {
mouseCaptureMode = ! mouseCaptureMode ;
SetMouseCapture ( ) ;
return 0 ;
}
2004-02-15 14:30:28 +03:00
EnterCriticalSection ( & stInfo . keyCS ) ;
enq_key_event ( HIWORD ( lParam ) & 0x01FF , BX_KEY_PRESSED ) ;
LeaveCriticalSection ( & stInfo . keyCS ) ;
2001-04-10 05:04:59 +04:00
return 0 ;
case WM_KEYUP :
case WM_SYSKEYUP :
EnterCriticalSection ( & stInfo . keyCS ) ;
2001-11-23 21:03:23 +03:00
enq_key_event ( HIWORD ( lParam ) & 0x01FF , BX_KEY_RELEASED ) ;
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . keyCS ) ;
return 0 ;
case WM_CHAR :
case WM_DEADCHAR :
case WM_SYSCHAR :
case WM_SYSDEADCHAR :
return 0 ;
}
return DefWindowProc ( hwnd , iMsg , wParam , lParam ) ;
}
2004-02-15 14:30:28 +03:00
void enq_key_event ( Bit32u key , Bit32u press_release )
{
2005-10-02 21:37:56 +04:00
static BOOL alt_pressed_l = FALSE ;
static BOOL alt_pressed_r = FALSE ;
static BOOL ctrl_pressed_l = FALSE ;
static BOOL ctrl_pressed_r = FALSE ;
static BOOL shift_pressed_l = FALSE ;
static BOOL shift_pressed_r = FALSE ;
// Windows generates multiple keypresses when holding down these keys
2004-02-15 14:30:28 +03:00
if ( press_release = = BX_KEY_PRESSED ) {
switch ( key ) {
case 0x1d :
2005-10-02 21:37:56 +04:00
if ( ctrl_pressed_l )
2004-02-15 14:30:28 +03:00
return ;
2005-10-02 21:37:56 +04:00
ctrl_pressed_l = TRUE ;
2004-02-15 14:30:28 +03:00
break ;
case 0x2a :
2005-10-02 21:37:56 +04:00
if ( shift_pressed_l )
return ;
shift_pressed_l = TRUE ;
break ;
case 0x36 :
if ( shift_pressed_r )
2004-02-15 14:30:28 +03:00
return ;
2005-10-02 21:37:56 +04:00
shift_pressed_r = TRUE ;
2004-02-15 14:30:28 +03:00
break ;
case 0x38 :
2005-10-02 21:37:56 +04:00
if ( alt_pressed_l )
return ;
alt_pressed_l = TRUE ;
break ;
case 0x011d :
if ( ctrl_pressed_r )
return ;
ctrl_pressed_r = TRUE ;
break ;
case 0x0138 :
if ( alt_pressed_r )
2004-02-15 14:30:28 +03:00
return ;
2006-07-23 15:09:15 +04:00
// This makes the "AltGr" key on European keyboards work
if ( ctrl_pressed_l ) {
enq_key_event ( 0x1d , BX_KEY_RELEASED ) ;
}
2005-10-02 21:37:56 +04:00
alt_pressed_r = TRUE ;
2004-02-15 14:30:28 +03:00
break ;
}
2005-10-02 21:37:56 +04:00
} else {
2004-02-15 14:30:28 +03:00
switch ( key ) {
case 0x1d :
2006-07-23 15:09:15 +04:00
if ( ! ctrl_pressed_l )
return ;
2005-10-02 21:37:56 +04:00
ctrl_pressed_l = FALSE ;
2004-02-15 14:30:28 +03:00
break ;
case 0x2a :
2005-10-02 21:37:56 +04:00
shift_pressed_l = FALSE ;
break ;
case 0x36 :
shift_pressed_r = FALSE ;
2004-02-15 14:30:28 +03:00
break ;
case 0x38 :
2005-10-02 21:37:56 +04:00
alt_pressed_l = FALSE ;
break ;
case 0x011d :
ctrl_pressed_r = FALSE ;
break ;
case 0x0138 :
alt_pressed_r = FALSE ;
2004-02-15 14:30:28 +03:00
break ;
}
}
2001-04-10 05:04:59 +04:00
if ( ( ( tail + 1 ) % SCANCODE_BUFSIZE ) = = head ) {
2001-05-30 22:56:02 +04:00
BX_ERROR ( ( " enq_scancode: buffer full " ) ) ;
2001-04-10 05:04:59 +04:00
return ;
}
keyevents [ tail ] . key_event = key | press_release ;
tail = ( tail + 1 ) % SCANCODE_BUFSIZE ;
}
void enq_mouse_event ( void )
{
EnterCriticalSection ( & stInfo . mouseCS ) ;
2004-12-05 23:23:39 +03:00
if ( ms_xdelta | | ms_ydelta | | ms_zdelta )
2001-04-10 05:04:59 +04:00
{
if ( ( ( tail + 1 ) % SCANCODE_BUFSIZE ) = = head ) {
2001-05-30 22:56:02 +04:00
BX_ERROR ( ( " enq_scancode: buffer full " ) ) ;
2001-04-10 05:04:59 +04:00
return ;
}
QueueEvent & current = keyevents [ tail ] ;
current . key_event = MOUSE_MOTION ;
current . mouse_x = ms_xdelta ;
current . mouse_y = ms_ydelta ;
2004-12-05 23:23:39 +03:00
current . mouse_z = ms_zdelta ;
2001-04-10 05:04:59 +04:00
current . mouse_button_state = mouse_button_state ;
resetDelta ( ) ;
tail = ( tail + 1 ) % SCANCODE_BUFSIZE ;
}
LeaveCriticalSection ( & stInfo . mouseCS ) ;
}
QueueEvent * deq_key_event ( void ) {
QueueEvent * key ;
if ( head = = tail ) {
2001-05-30 22:56:02 +04:00
BX_ERROR ( ( " deq_scancode: buffer empty " ) ) ;
2001-04-10 05:04:59 +04:00
return ( ( QueueEvent * ) 0 ) ;
}
key = & keyevents [ head ] ;
head = ( head + 1 ) % SCANCODE_BUFSIZE ;
return ( key ) ;
}
// ::HANDLE_EVENTS()
//
// Called periodically (vga_update_interval in .bochsrc) so the
// the gui code can poll for keyboard, mouse, and other
// relevant events.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : handle_events ( void ) {
2001-04-10 05:04:59 +04:00
Bit32u key ;
2003-02-17 22:08:12 +03:00
Bit32u key_event ;
2001-04-10 05:04:59 +04:00
if ( stInfo . kill ) terminateEmul ( stInfo . kill ) ;
// Handle mouse moves
enq_mouse_event ( ) ;
// Handle keyboard and mouse clicks
EnterCriticalSection ( & stInfo . keyCS ) ;
while ( head ! = tail ) {
QueueEvent * queue_event = deq_key_event ( ) ;
if ( ! queue_event )
break ;
key = queue_event - > key_event ;
if ( key = = MOUSE_MOTION )
{
2004-12-05 23:23:39 +03:00
DEV_mouse_motion_ext ( queue_event - > mouse_x ,
queue_event - > mouse_y , queue_event - > mouse_z , queue_event - > mouse_button_state ) ;
2001-04-10 05:04:59 +04:00
}
// Check for mouse buttons first
else if ( key & MOUSE_PRESSED ) {
2004-12-05 23:23:39 +03:00
DEV_mouse_motion_ext ( 0 , 0 , 0 , LOWORD ( key ) ) ;
2001-04-10 05:04:59 +04:00
}
else if ( key & HEADERBAR_CLICKED ) {
headerbar_click ( LOWORD ( key ) ) ;
}
else {
2003-10-25 21:37:58 +04:00
key_event = win32_to_bx_key [ ( key & 0x100 ) ? 1 : 0 ] [ key & 0xff ] ;
2003-02-17 22:08:12 +03:00
if ( key & BX_KEY_RELEASED ) key_event | = BX_KEY_RELEASED ;
DEV_kbd_gen_scancode ( key_event ) ;
2001-04-10 05:04:59 +04:00
}
}
2006-01-24 00:53:57 +03:00
# if BX_SHOW_IPS
if ( ipsUpdate ) {
2006-01-27 21:04:49 +03:00
SetStatusText ( 1 , ipsText , 1 ) ;
2006-01-24 00:53:57 +03:00
ipsUpdate = FALSE ;
}
# endif
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . keyCS ) ;
}
// ::FLUSH()
//
// Called periodically, requesting that the gui code flush all pending
// screen update requests.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : flush ( void ) {
2001-04-10 05:04:59 +04:00
EnterCriticalSection ( & stInfo . drawCS ) ;
if ( updated_area_valid ) {
// slight bugfix
updated_area . right + + ;
updated_area . bottom + + ;
2002-08-10 19:23:30 +04:00
InvalidateRect ( stInfo . simWnd , & updated_area , FALSE ) ;
2001-04-10 05:04:59 +04:00
updated_area_valid = FALSE ;
}
LeaveCriticalSection ( & stInfo . drawCS ) ;
}
// ::CLEAR_SCREEN()
//
// Called to request that the VGA region is cleared. Don't
// clear the area that defines the headerbar.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : clear_screen ( void ) {
2001-04-10 05:04:59 +04:00
HGDIOBJ oldObj ;
if ( ! stInfo . UIinited ) return ;
EnterCriticalSection ( & stInfo . drawCS ) ;
oldObj = SelectObject ( MemoryDC , MemoryBitmap ) ;
2002-08-10 19:23:30 +04:00
PatBlt ( MemoryDC , 0 , 0 , stretched_x , stretched_y , BLACKNESS ) ;
2001-04-10 05:04:59 +04:00
SelectObject ( MemoryDC , oldObj ) ;
2002-08-10 19:23:30 +04:00
updateUpdated ( 0 , 0 , dimension_x - 1 , dimension_y - 1 ) ;
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . drawCS ) ;
}
// ::TEXT_UPDATE()
//
// Called in a VGA text mode, to update the screen with
// new content.
//
// old_text: array of character/attributes making up the contents
// of the screen from the last call. See below
// new_text: array of character/attributes making up the current
// contents, which should now be displayed. See below
//
2003-05-28 23:08:32 +04:00
// format of old_text & new_text: each is tm_info.line_offset*text_rows
// bytes long. Each character consists of 2 bytes. The first by is
// the character value, the second is the attribute byte.
2001-04-10 05:04:59 +04:00
//
// cursor_x: new x location of cursor
// cursor_y: new y location of cursor
2003-05-28 23:08:32 +04:00
// tm_info: this structure contains information for additional
// features in text mode (cursor shape, line offset,...)
// nrows: number of text rows (unused here)
2001-04-10 05:04:59 +04:00
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : text_update ( Bit8u * old_text , Bit8u * new_text ,
2001-04-10 05:04:59 +04:00
unsigned long cursor_x , unsigned long cursor_y ,
2003-05-12 23:53:22 +04:00
bx_vga_tminfo_t tm_info , unsigned nrows )
{
2001-04-10 05:04:59 +04:00
HDC hdc ;
2002-09-08 20:41:19 +04:00
unsigned char data [ 64 ] ;
2006-10-15 20:23:42 +04:00
Bit8u * old_line , * new_line ;
2004-04-11 12:01:22 +04:00
Bit8u cAttr , cChar ;
2006-10-15 20:23:42 +04:00
unsigned int curs , hchars , i , offset , rows , x , y , xc , yc ;
BOOL forceUpdate = FALSE ;
# if !BX_USE_WINDOWS_FONTS
Bit8u * text_base ;
2003-06-22 16:37:03 +04:00
Bit8u cfwidth , cfheight , cfheight2 , font_col , font_row , font_row2 ;
2004-04-11 12:01:22 +04:00
Bit8u split_textrow , split_fontrows ;
2006-10-15 20:23:42 +04:00
unsigned int yc2 , cs_y ;
BOOL split_screen ;
# endif
2002-09-08 20:41:19 +04:00
2003-05-12 23:53:22 +04:00
if ( ! stInfo . UIinited ) return ;
EnterCriticalSection ( & stInfo . drawCS ) ;
2003-05-28 23:08:32 +04:00
UNUSED ( nrows ) ;
2002-10-25 01:07:56 +04:00
if ( charmap_updated ) {
2002-09-21 23:38:47 +04:00
for ( unsigned c = 0 ; c < 256 ; c + + ) {
2002-10-25 01:07:56 +04:00
if ( char_changed [ c ] ) {
2002-09-21 23:38:47 +04:00
memset ( data , 0 , sizeof ( data ) ) ;
2003-05-14 00:38:35 +04:00
BOOL gfxchar = tm_info . line_graphics & & ( ( c & 0xE0 ) = = 0xC0 ) ;
2006-10-15 20:23:42 +04:00
for ( i = 0 ; i < ( unsigned ) yChar ; i + + ) {
2002-10-25 01:07:56 +04:00
data [ i * 2 ] = vga_charmap [ c * 32 + i ] ;
2003-05-14 00:38:35 +04:00
if ( gfxchar ) {
2003-05-13 22:44:23 +04:00
data [ i * 2 + 1 ] = ( data [ i * 2 ] < < 7 ) ;
}
}
2002-09-21 23:38:47 +04:00
SetBitmapBits ( vgafont [ c ] , 64 , data ) ;
2002-10-25 01:07:56 +04:00
char_changed [ c ] = 0 ;
2002-09-21 23:38:47 +04:00
}
2002-09-08 20:41:19 +04:00
}
2002-10-04 14:52:44 +04:00
forceUpdate = TRUE ;
2002-10-25 01:07:56 +04:00
charmap_updated = 0 ;
2002-09-08 20:41:19 +04:00
}
2006-10-15 20:23:42 +04:00
for ( i = 0 ; i < 16 ; i + + ) {
text_pal_idx [ i ] = DEV_vga_get_actl_pal_idx ( i ) ;
}
2001-04-10 05:04:59 +04:00
2002-08-10 19:23:30 +04:00
hdc = GetDC ( stInfo . simWnd ) ;
2001-04-10 05:04:59 +04:00
2003-06-22 16:37:03 +04:00
# if !BX_USE_WINDOWS_FONTS
if ( ( tm_info . h_panning ! = h_panning ) | | ( tm_info . v_panning ! = v_panning ) ) {
forceUpdate = 1 ;
h_panning = tm_info . h_panning ;
v_panning = tm_info . v_panning ;
}
2004-04-11 12:01:22 +04:00
if ( tm_info . line_compare ! = line_compare ) {
forceUpdate = 1 ;
line_compare = tm_info . line_compare ;
}
2003-06-22 16:37:03 +04:00
# endif
2003-06-20 14:36:46 +04:00
// first invalidate character at previous and new cursor location
if ( ( prev_cursor_y < text_rows ) & & ( prev_cursor_x < text_cols ) ) {
curs = prev_cursor_y * tm_info . line_offset + prev_cursor_x * 2 ;
old_text [ curs ] = ~ new_text [ curs ] ;
}
if ( ( tm_info . cs_start < = tm_info . cs_end ) & & ( tm_info . cs_start < yChar ) & &
( cursor_y < text_rows ) & & ( cursor_x < text_cols ) ) {
curs = cursor_y * tm_info . line_offset + cursor_x * 2 ;
old_text [ curs ] = ~ new_text [ curs ] ;
} else {
curs = 0xffff ;
2001-04-10 05:04:59 +04:00
}
2003-06-22 16:37:03 +04:00
# if !BX_USE_WINDOWS_FONTS
rows = text_rows ;
if ( v_panning ) rows + + ;
y = 0 ;
2004-04-11 12:01:22 +04:00
cs_y = 0 ;
text_base = new_text - tm_info . start_address ;
split_textrow = ( line_compare + v_panning ) / yChar ;
split_fontrows = ( ( line_compare + v_panning ) % yChar ) + 1 ;
split_screen = 0 ;
2003-06-22 16:37:03 +04:00
do {
hchars = text_cols ;
if ( h_panning ) hchars + + ;
2004-04-11 12:01:22 +04:00
if ( split_screen ) {
yc = line_compare + cs_y * yChar + 1 ;
font_row = 0 ;
if ( rows = = 1 ) {
cfheight = ( dimension_y - line_compare - 1 ) % yChar ;
if ( cfheight = = 0 ) cfheight = yChar ;
} else {
cfheight = yChar ;
}
} else if ( v_panning ) {
2003-06-22 16:37:03 +04:00
if ( y = = 0 ) {
yc = 0 ;
font_row = v_panning ;
cfheight = yChar - v_panning ;
} else {
yc = y * yChar - v_panning ;
font_row = 0 ;
if ( rows = = 1 ) {
cfheight = v_panning ;
} else {
cfheight = yChar ;
}
}
} else {
yc = y * yChar ;
font_row = 0 ;
cfheight = yChar ;
}
2004-04-11 12:01:22 +04:00
if ( ! split_screen & & ( y = = split_textrow ) ) {
if ( split_fontrows < cfheight ) cfheight = split_fontrows ;
}
2003-06-22 16:37:03 +04:00
new_line = new_text ;
old_line = old_text ;
x = 0 ;
2004-04-11 12:01:22 +04:00
offset = cs_y * tm_info . line_offset ;
2003-06-22 16:37:03 +04:00
do {
if ( h_panning ) {
if ( hchars > text_cols ) {
xc = 0 ;
font_col = h_panning ;
cfwidth = xChar - h_panning ;
} else {
xc = x * xChar - h_panning ;
font_col = 0 ;
if ( hchars = = 1 ) {
cfwidth = h_panning ;
} else {
cfwidth = xChar ;
}
}
} else {
xc = x * xChar ;
font_col = 0 ;
cfwidth = xChar ;
}
if ( forceUpdate | | ( old_text [ 0 ] ! = new_text [ 0 ] )
| | ( old_text [ 1 ] ! = new_text [ 1 ] ) ) {
cChar = new_text [ 0 ] ;
cAttr = new_text [ 1 ] ;
DrawBitmap ( hdc , vgafont [ cChar ] , xc , yc , cfwidth , cfheight , font_col ,
font_row , SRCCOPY , cAttr ) ;
if ( offset = = curs ) {
if ( font_row = = 0 ) {
yc2 = yc + tm_info . cs_start ;
font_row2 = tm_info . cs_start ;
cfheight2 = tm_info . cs_end - tm_info . cs_start + 1 ;
} else {
if ( v_panning > tm_info . cs_start ) {
yc2 = yc ;
font_row2 = font_row ;
cfheight2 = tm_info . cs_end - v_panning + 1 ;
} else {
yc2 = yc + tm_info . cs_start - v_panning ;
font_row2 = tm_info . cs_start ;
cfheight2 = tm_info . cs_end - tm_info . cs_start + 1 ;
}
}
cAttr = ( ( cAttr > > 4 ) & 0xF ) + ( ( cAttr & 0xF ) < < 4 ) ;
DrawBitmap ( hdc , vgafont [ cChar ] , xc , yc2 , cfwidth , cfheight2 , font_col ,
font_row2 , SRCCOPY , cAttr ) ;
}
}
x + + ;
new_text + = 2 ;
old_text + = 2 ;
offset + = 2 ;
} while ( - - hchars ) ;
2004-04-11 12:01:22 +04:00
if ( ! split_screen & & ( y = = split_textrow ) ) {
new_text = text_base ;
forceUpdate = 1 ;
cs_y = 0 ;
if ( tm_info . split_hpanning ) h_panning = 0 ;
rows = ( ( dimension_y - line_compare + yChar - 2 ) / yChar ) + 1 ;
split_screen = 1 ;
} else {
y + + ;
cs_y + + ;
new_text = new_line + tm_info . line_offset ;
old_text = old_line + tm_info . line_offset ;
}
2003-06-22 16:37:03 +04:00
} while ( - - rows ) ;
2004-04-11 12:01:22 +04:00
h_panning = tm_info . h_panning ;
2003-06-22 16:37:03 +04:00
# else
2003-05-28 23:08:32 +04:00
rows = text_rows ;
2003-05-12 23:53:22 +04:00
y = 0 ;
do {
2003-05-28 23:08:32 +04:00
hchars = text_cols ;
2003-06-20 14:36:46 +04:00
yc = y * yChar ;
2003-05-12 23:53:22 +04:00
new_line = new_text ;
old_line = old_text ;
x = 0 ;
2003-06-20 14:36:46 +04:00
offset = y * tm_info . line_offset ;
2003-05-12 23:53:22 +04:00
do {
2003-06-20 14:36:46 +04:00
xc = x * xChar ;
2003-05-12 23:53:22 +04:00
if ( forceUpdate | | ( old_text [ 0 ] ! = new_text [ 0 ] )
| | ( old_text [ 1 ] ! = new_text [ 1 ] ) ) {
cChar = new_text [ 0 ] ;
cAttr = new_text [ 1 ] ;
2003-06-20 14:36:46 +04:00
DrawChar ( hdc , cChar , xc , yc , cAttr , 1 , 0 ) ;
if ( offset = = curs ) {
DrawChar ( hdc , cChar , xc , yc , cAttr , tm_info . cs_start , tm_info . cs_end ) ;
2003-05-12 23:53:22 +04:00
}
2002-03-21 21:40:20 +03:00
}
2003-05-12 23:53:22 +04:00
x + + ;
new_text + = 2 ;
old_text + = 2 ;
2003-06-20 14:36:46 +04:00
offset + = 2 ;
2003-05-12 23:53:22 +04:00
} while ( - - hchars ) ;
y + + ;
new_text = new_line + tm_info . line_offset ;
old_text = old_line + tm_info . line_offset ;
} while ( - - rows ) ;
2003-06-22 16:37:03 +04:00
# endif
2001-04-10 05:04:59 +04:00
2003-06-20 14:36:46 +04:00
prev_cursor_x = cursor_x ;
prev_cursor_y = cursor_y ;
2001-04-10 05:04:59 +04:00
2002-08-10 19:23:30 +04:00
ReleaseDC ( stInfo . simWnd , hdc ) ;
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . drawCS ) ;
}
2002-03-16 14:30:06 +03:00
int
2002-10-25 01:07:56 +04:00
bx_win32_gui_c : : get_clipboard_text ( Bit8u * * bytes , Bit32s * nbytes )
2002-03-16 14:30:06 +03:00
{
2002-08-10 19:23:30 +04:00
if ( OpenClipboard ( stInfo . simWnd ) ) {
2002-03-16 14:30:06 +03:00
HGLOBAL hg = GetClipboardData ( CF_TEXT ) ;
char * data = ( char * ) GlobalLock ( hg ) ;
* nbytes = strlen ( data ) ;
2002-09-05 19:57:37 +04:00
* bytes = new Bit8u [ 1 + * nbytes ] ;
2002-03-16 14:30:06 +03:00
BX_INFO ( ( " found %d bytes on the clipboard " , * nbytes ) ) ;
memcpy ( * bytes , data , * nbytes + 1 ) ;
BX_INFO ( ( " first byte is 0x%02x " , * bytes [ 0 ] ) ) ;
GlobalUnlock ( hg ) ;
CloseClipboard ( ) ;
return 1 ;
2002-09-05 19:57:37 +04:00
// *bytes will be freed in bx_keyb_c::paste_bytes or
// bx_keyb_c::service_paste_buf, using delete [].
2002-03-16 14:30:06 +03:00
} else {
BX_ERROR ( ( " paste: could not open clipboard " ) ) ;
return 0 ;
}
}
int
2002-10-25 01:07:56 +04:00
bx_win32_gui_c : : set_clipboard_text ( char * text_snapshot , Bit32u len )
2002-03-15 19:45:10 +03:00
{
2002-08-10 19:23:30 +04:00
if ( OpenClipboard ( stInfo . simWnd ) ) {
2002-03-16 14:30:06 +03:00
HANDLE hMem = GlobalAlloc ( GMEM_ZEROINIT , len ) ;
EmptyClipboard ( ) ;
lstrcpy ( ( char * ) hMem , text_snapshot ) ;
SetClipboardData ( CF_TEXT , hMem ) ;
CloseClipboard ( ) ;
GlobalFree ( hMem ) ;
return 1 ;
} else {
BX_ERROR ( ( " copy: could not open clipboard " ) ) ;
return 0 ;
}
2002-03-15 19:45:10 +03:00
}
2001-04-10 05:04:59 +04:00
// ::PALETTE_CHANGE()
//
// Allocate a color in the native GUI, for this color, and put
// it in the colormap location 'index'.
// returns: 0=no screen update needed (color map change has direct effect)
// 1=screen updated needed (redraw using current colormap)
2002-10-25 15:44:41 +04:00
bx_bool bx_win32_gui_c : : palette_change ( unsigned index , unsigned red ,
2001-04-10 05:04:59 +04:00
unsigned green , unsigned blue ) {
2005-03-23 23:46:52 +03:00
if ( ( current_bpp = = 16 ) & & ( index < 3 ) ) {
cmap_index [ 256 + index ] . rgbRed = red ;
cmap_index [ 256 + index ] . rgbBlue = blue ;
cmap_index [ 256 + index ] . rgbGreen = green ;
return 0 ;
} else {
cmap_index [ index ] . rgbRed = red ;
cmap_index [ index ] . rgbBlue = blue ;
cmap_index [ index ] . rgbGreen = green ;
}
2001-04-10 05:04:59 +04:00
return ( 1 ) ;
}
// ::GRAPHICS_TILE_UPDATE()
//
// Called to request that a tile of graphics be drawn to the
// screen, since info in this region has changed.
//
// tile: array of 8bit values representing a block of pixels with
// dimension equal to the 'tilewidth' & 'tileheight' parameters to
// ::specific_init(). Each value specifies an index into the
// array of colors you allocated for ::palette_change()
// x0: x origin of tile
// y0: y origin of tile
//
// note: origin of tile and of window based on (0,0) being in the upper
// left of the window.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : graphics_tile_update ( Bit8u * tile , unsigned x0 , unsigned y0 ) {
2001-04-10 05:04:59 +04:00
HDC hdc ;
HGDIOBJ oldObj ;
EnterCriticalSection ( & stInfo . drawCS ) ;
2002-08-10 19:23:30 +04:00
hdc = GetDC ( stInfo . simWnd ) ;
2001-04-10 05:04:59 +04:00
oldObj = SelectObject ( MemoryDC , MemoryBitmap ) ;
2002-08-10 19:23:30 +04:00
StretchDIBits ( MemoryDC , x0 , y0 , x_tilesize , y_tilesize , 0 , 0 ,
2001-04-10 05:04:59 +04:00
x_tilesize , y_tilesize , tile , bitmap_info , DIB_RGB_COLORS , SRCCOPY ) ;
SelectObject ( MemoryDC , oldObj ) ;
2002-08-10 19:23:30 +04:00
updateUpdated ( x0 , y0 , x0 + x_tilesize - 1 , y0 + y_tilesize - 1 ) ;
2001-04-10 05:04:59 +04:00
2002-08-10 19:23:30 +04:00
ReleaseDC ( stInfo . simWnd , hdc ) ;
2001-04-10 05:04:59 +04:00
LeaveCriticalSection ( & stInfo . drawCS ) ;
}
// ::DIMENSION_UPDATE()
//
// Called when the VGA mode changes it's X,Y dimensions.
// Resize the window to this size, but you need to add on
// the height of the headerbar to the Y value.
//
// x: new VGA x size
// y: new VGA y size (add headerbar_y parameter from ::specific_init().
2003-05-28 23:08:32 +04:00
// fheight: new VGA character height in text mode
// fwidth : new VGA character width in text mode
2003-06-28 12:04:31 +04:00
// bpp : bits per pixel in graphics mode
2001-04-10 05:04:59 +04:00
2003-06-28 12:04:31 +04:00
void bx_win32_gui_c : : dimension_update ( unsigned x , unsigned y , unsigned fheight , unsigned fwidth , unsigned bpp )
2002-04-20 11:19:35 +04:00
{
2003-12-14 12:51:58 +03:00
BxTextMode = ( fheight > 0 ) ;
if ( BxTextMode ) {
2003-05-28 23:08:32 +04:00
text_cols = x / fwidth ;
text_rows = y / fheight ;
2003-06-20 14:36:46 +04:00
# if BX_USE_WINDOWS_FONTS
2002-09-08 20:41:19 +04:00
if ( fheight > = 14 ) {
2002-04-20 11:19:35 +04:00
FontId = 2 ;
2003-06-20 14:36:46 +04:00
xChar = 8 ;
yChar = 16 ;
} else if ( fheight > = 12 ) {
2002-04-20 11:19:35 +04:00
FontId = 1 ;
2003-05-13 22:44:23 +04:00
xChar = 8 ;
2002-04-20 11:19:35 +04:00
yChar = 14 ;
} else {
FontId = 0 ;
2003-05-13 22:44:23 +04:00
xChar = 8 ;
2002-04-20 11:19:35 +04:00
yChar = 12 ;
}
2003-06-20 14:36:46 +04:00
if ( fwidth ! = xChar ) {
x = x * 8 / fwidth ;
}
if ( fheight ! = yChar ) {
y = y * yChar / fheight ;
}
# else
xChar = fwidth ;
yChar = fheight ;
# endif
2002-04-20 11:19:35 +04:00
}
2003-11-05 20:25:29 +03:00
if ( x = = dimension_x & & y = = dimension_y & & bpp = = current_bpp )
2001-04-10 05:04:59 +04:00
return ;
dimension_x = x ;
2002-08-10 19:23:30 +04:00
dimension_y = y ;
2001-04-10 05:04:59 +04:00
stretched_x = dimension_x ;
stretched_y = dimension_y ;
stretch_factor = 1 ;
2003-12-14 12:51:58 +03:00
if ( BxTextMode & & ( stretched_x < 400 ) ) {
2001-04-10 05:04:59 +04:00
stretched_x * = 2 ;
stretch_factor * = 2 ;
}
2003-06-28 12:04:31 +04:00
bitmap_info - > bmiHeader . biBitCount = bpp ;
2003-07-01 01:24:09 +04:00
if ( bpp = = 16 )
{
bitmap_info - > bmiHeader . biCompression = BI_BITFIELDS ;
static RGBQUAD red_mask = { 0x00 , 0xF8 , 0x00 , 0x00 } ;
static RGBQUAD green_mask = { 0xE0 , 0x07 , 0x00 , 0x00 } ;
static RGBQUAD blue_mask = { 0x1F , 0x00 , 0x00 , 0x00 } ;
2005-03-23 23:46:52 +03:00
bitmap_info - > bmiColors [ 256 ] = bitmap_info - > bmiColors [ 0 ] ;
bitmap_info - > bmiColors [ 257 ] = bitmap_info - > bmiColors [ 1 ] ;
bitmap_info - > bmiColors [ 258 ] = bitmap_info - > bmiColors [ 2 ] ;
2003-07-01 01:24:09 +04:00
bitmap_info - > bmiColors [ 0 ] = red_mask ;
bitmap_info - > bmiColors [ 1 ] = green_mask ;
bitmap_info - > bmiColors [ 2 ] = blue_mask ;
}
else
{
2005-03-23 23:46:52 +03:00
if ( current_bpp = = 16 )
{
bitmap_info - > bmiColors [ 0 ] = bitmap_info - > bmiColors [ 256 ] ;
bitmap_info - > bmiColors [ 1 ] = bitmap_info - > bmiColors [ 257 ] ;
bitmap_info - > bmiColors [ 2 ] = bitmap_info - > bmiColors [ 258 ] ;
}
2003-07-01 01:24:09 +04:00
bitmap_info - > bmiHeader . biCompression = BI_RGB ;
2003-07-11 19:11:24 +04:00
if ( bpp = = 15 )
{
bitmap_info - > bmiHeader . biBitCount = 16 ;
}
2003-07-01 01:24:09 +04:00
}
2005-03-23 23:46:52 +03:00
current_bpp = bpp ;
2002-03-21 21:40:20 +03:00
2005-05-08 23:10:21 +04:00
resize_main_window ( ) ;
2003-10-25 15:57:42 +04:00
2003-06-28 12:04:31 +04:00
BX_INFO ( ( " dimension update x=%d y=%d fontheight=%d fontwidth=%d bpp=%d " , x , y , fheight , fwidth , bpp ) ) ;
2004-08-15 23:27:15 +04:00
host_xres = x ;
host_yres = y ;
host_bpp = bpp ;
2001-04-10 05:04:59 +04:00
}
// ::CREATE_BITMAP()
//
// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
// be drawn in the headerbar. Return an integer ID to the bitmap,
// with which the bitmap can be referenced later.
//
// bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
// bit0 is the left most pixel, bit7 is the right most pixel.
// xdim: x dimension of bitmap
// ydim: y dimension of bitmap
2002-10-25 01:07:56 +04:00
unsigned bx_win32_gui_c : : create_bitmap ( const unsigned char * bmap , unsigned xdim ,
2001-04-10 05:04:59 +04:00
unsigned ydim ) {
unsigned char * data ;
2002-08-10 19:23:30 +04:00
TBADDBITMAP tbab ;
2001-04-10 05:04:59 +04:00
if ( bx_bitmap_entries > = BX_MAX_PIXMAPS )
terminateEmul ( EXIT_HEADER_BITMAP_ERROR ) ;
bx_bitmaps [ bx_bitmap_entries ] . bmap = CreateBitmap ( xdim , ydim , 1 , 1 , NULL ) ;
if ( ! bx_bitmaps [ bx_bitmap_entries ] . bmap )
terminateEmul ( EXIT_HEADER_BITMAP_ERROR ) ;
data = new unsigned char [ ydim * xdim / 8 ] ;
for ( unsigned i = 0 ; i < ydim * xdim / 8 ; i + + )
2002-08-10 19:23:30 +04:00
data [ i ] = 255 - reverse_bitorder ( bmap [ i ] ) ;
2001-04-10 05:04:59 +04:00
SetBitmapBits ( bx_bitmaps [ bx_bitmap_entries ] . bmap , ydim * xdim / 8 , data ) ;
2001-12-21 22:33:18 +03:00
delete [ ] data ;
data = NULL ;
2001-04-10 05:04:59 +04:00
bx_bitmaps [ bx_bitmap_entries ] . xdim = xdim ;
bx_bitmaps [ bx_bitmap_entries ] . ydim = ydim ;
2002-08-10 19:23:30 +04:00
tbab . hInst = NULL ;
tbab . nID = ( UINT ) bx_bitmaps [ bx_bitmap_entries ] . bmap ;
SendMessage ( hwndTB , TB_ADDBITMAP , 1 , ( LPARAM ) & tbab ) ;
2001-04-10 05:04:59 +04:00
bx_bitmap_entries + + ;
return ( bx_bitmap_entries - 1 ) ; // return index as handle
}
// ::HEADERBAR_BITMAP()
//
// Called to install a bitmap in the bochs headerbar (toolbar).
//
// bmap_id: will correspond to an ID returned from
// ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
// or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
// available leftmost or rightmost space.
// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
// meaning install the bitmap in the next
// available leftmost or rightmost space.
// f: a 'C' function pointer to callback when the mouse is clicked in
// the boundaries of this bitmap.
2002-10-25 01:07:56 +04:00
unsigned bx_win32_gui_c : : headerbar_bitmap ( unsigned bmap_id , unsigned alignment ,
2001-04-10 05:04:59 +04:00
void ( * f ) ( void ) ) {
unsigned hb_index ;
2002-08-10 19:23:30 +04:00
TBBUTTON tbb [ 1 ] ;
2001-04-10 05:04:59 +04:00
if ( ( bx_headerbar_entries + 1 ) > BX_MAX_HEADERBAR_ENTRIES )
terminateEmul ( EXIT_HEADER_BITMAP_ERROR ) ;
bx_headerbar_entries + + ;
hb_index = bx_headerbar_entries - 1 ;
2002-08-10 19:23:30 +04:00
memset ( tbb , 0 , sizeof ( tbb ) ) ;
if ( bx_hb_separator = = 0 ) {
tbb [ 0 ] . iBitmap = 0 ;
tbb [ 0 ] . idCommand = 0 ;
tbb [ 0 ] . fsState = 0 ;
tbb [ 0 ] . fsStyle = TBSTYLE_SEP ;
SendMessage ( hwndTB , TB_ADDBUTTONS , 1 , ( LPARAM ) ( LPTBBUTTON ) & tbb ) ;
}
tbb [ 0 ] . iBitmap = bmap_id ;
tbb [ 0 ] . idCommand = hb_index + 101 ;
tbb [ 0 ] . fsState = TBSTATE_ENABLED ;
tbb [ 0 ] . fsStyle = TBSTYLE_BUTTON ;
2001-04-10 05:04:59 +04:00
if ( alignment = = BX_GRAVITY_LEFT ) {
2002-08-10 19:23:30 +04:00
SendMessage ( hwndTB , TB_INSERTBUTTON , bx_hb_separator , ( LPARAM ) ( LPTBBUTTON ) & tbb ) ;
bx_hb_separator + + ;
2001-04-10 05:04:59 +04:00
} else { // BX_GRAVITY_RIGHT
2002-08-10 19:23:30 +04:00
SendMessage ( hwndTB , TB_INSERTBUTTON , bx_hb_separator + 1 , ( LPARAM ) ( LPTBBUTTON ) & tbb ) ;
}
2001-04-10 05:04:59 +04:00
2002-08-10 19:23:30 +04:00
bx_headerbar_entry [ hb_index ] . bmap_id = bmap_id ;
bx_headerbar_entry [ hb_index ] . f = f ;
2006-01-25 20:37:22 +03:00
bx_headerbar_entry [ hb_index ] . tooltip = NULL ;
2001-04-10 05:04:59 +04:00
return ( hb_index ) ;
}
// ::SHOW_HEADERBAR()
//
// Show (redraw) the current headerbar, which is composed of
// currently installed bitmaps.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : show_headerbar ( void )
2002-08-10 19:23:30 +04:00
{
2005-05-08 23:10:21 +04:00
if ( ! IsWindowVisible ( hwndTB ) ) {
SendMessage ( hwndTB , TB_AUTOSIZE , 0 , 0 ) ;
ShowWindow ( hwndTB , SW_SHOW ) ;
resize_main_window ( ) ;
2006-01-25 20:37:22 +03:00
bx_gui - > set_tooltip ( bx_gui - > get_mouse_headerbar_id ( ) , szMouseTooltip ) ;
2003-09-17 23:47:41 +04:00
}
2001-04-10 05:04:59 +04:00
}
// ::REPLACE_BITMAP()
//
// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
// with the one specified by 'bmap_id'. 'bmap_id' will have
// been generated by ::create_bitmap(). The old and new bitmap
// must be of the same size. This allows the bitmap the user
// sees to change, when some action occurs. For example when
// the user presses on the floppy icon, it then displays
// the ejected status.
//
// hbar_id: headerbar slot ID
// bmap_id: bitmap ID
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : replace_bitmap ( unsigned hbar_id , unsigned bmap_id )
2002-08-10 19:23:30 +04:00
{
if ( bmap_id ! = bx_headerbar_entry [ hbar_id ] . bmap_id ) {
bx_headerbar_entry [ hbar_id ] . bmap_id = bmap_id ;
2005-05-08 23:10:21 +04:00
bx_bool is_visible = IsWindowVisible ( hwndTB ) ;
if ( is_visible ) {
ShowWindow ( hwndTB , SW_HIDE ) ;
}
2002-08-10 19:23:30 +04:00
SendMessage ( hwndTB , TB_CHANGEBITMAP , ( WPARAM ) hbar_id + 101 , ( LPARAM )
MAKELPARAM ( bmap_id , 0 ) ) ;
2005-05-08 23:10:21 +04:00
SendMessage ( hwndTB , TB_AUTOSIZE , 0 , 0 ) ;
if ( is_visible ) {
ShowWindow ( hwndTB , SW_SHOW ) ;
}
2002-08-10 19:23:30 +04:00
}
2001-04-10 05:04:59 +04:00
}
// ::EXIT()
//
// Called before bochs terminates, to allow for a graceful
// exit from the native GUI mechanism.
2002-10-25 01:07:56 +04:00
void bx_win32_gui_c : : exit ( void ) {
printf ( " # In bx_win32_gui_c::exit(void)! \n " ) ;
2001-04-10 05:04:59 +04:00
// kill thread first...
2002-08-10 19:23:30 +04:00
PostMessage ( stInfo . mainWnd , WM_CLOSE , 0 , 0 ) ;
2001-04-10 05:04:59 +04:00
// Wait until it dies
while ( ( stInfo . kill = = 0 ) & & ( workerThreadID ! = 0 ) ) Sleep ( 500 ) ;
if ( ! stInfo . kill ) terminateEmul ( EXIT_NORMAL ) ;
}
void create_vga_font ( void ) {
2002-09-08 20:41:19 +04:00
unsigned char data [ 64 ] ;
2001-04-10 05:04:59 +04:00
2003-05-13 22:44:23 +04:00
// VGA font is 8 or 9 wide and up to 32 high
2001-04-10 05:04:59 +04:00
for ( unsigned c = 0 ; c < 256 ; c + + ) {
2003-05-13 22:44:23 +04:00
vgafont [ c ] = CreateBitmap ( 9 , 32 , 1 , 1 , NULL ) ;
2001-04-10 05:04:59 +04:00
if ( ! vgafont [ c ] ) terminateEmul ( EXIT_FONT_BITMAP_ERROR ) ;
2002-09-08 20:41:19 +04:00
memset ( data , 0 , sizeof ( data ) ) ;
2001-04-10 05:04:59 +04:00
for ( unsigned i = 0 ; i < 16 ; i + + )
data [ i * 2 ] = reverse_bitorder ( bx_vgafont [ c ] . data [ i ] ) ;
2002-09-08 20:41:19 +04:00
SetBitmapBits ( vgafont [ c ] , 64 , data ) ;
2001-04-10 05:04:59 +04:00
}
}
unsigned char reverse_bitorder ( unsigned char b ) {
unsigned char ret = 0 ;
2002-03-15 19:45:10 +03:00
2001-04-10 05:04:59 +04:00
for ( unsigned i = 0 ; i < 8 ; i + + ) {
ret | = ( b & 0x01 ) < < ( 7 - i ) ;
b > > = 1 ;
}
2002-03-15 19:45:10 +03:00
2001-04-10 05:04:59 +04:00
return ( ret ) ;
}
2002-08-12 18:41:42 +04:00
COLORREF GetColorRef ( unsigned char attr )
{
2006-10-15 20:23:42 +04:00
Bit8u pal_idx = text_pal_idx [ attr ] ;
return RGB ( cmap_index [ pal_idx ] . rgbRed , cmap_index [ pal_idx ] . rgbGreen ,
cmap_index [ pal_idx ] . rgbBlue ) ;
2002-08-12 18:41:42 +04:00
}
2006-10-15 20:23:42 +04:00
void DrawBitmap ( HDC hdc , HBITMAP hBitmap , int xStart , int yStart , int width ,
int height , int fcol , int frow , DWORD dwRop , unsigned char cColor ) {
2001-04-10 05:04:59 +04:00
BITMAP bm ;
HDC hdcMem ;
POINT ptSize , ptOrg ;
HGDIOBJ oldObj ;
hdcMem = CreateCompatibleDC ( hdc ) ;
SelectObject ( hdcMem , hBitmap ) ;
SetMapMode ( hdcMem , GetMapMode ( hdc ) ) ;
GetObject ( hBitmap , sizeof ( BITMAP ) , ( LPVOID ) & bm ) ;
2003-06-22 16:37:03 +04:00
ptSize . x = width ;
ptSize . y = height ;
2001-04-10 05:04:59 +04:00
DPtoLP ( hdc , & ptSize , 1 ) ;
2003-06-22 16:37:03 +04:00
ptOrg . x = fcol ;
ptOrg . y = frow ;
2001-04-10 05:04:59 +04:00
DPtoLP ( hdcMem , & ptOrg , 1 ) ;
oldObj = SelectObject ( MemoryDC , MemoryBitmap ) ;
2003-05-13 22:44:23 +04:00
2006-10-15 20:23:42 +04:00
// The highest background bit usually means blinking characters. No idea
// how to implement that so for now it's just implemented as color.
// Note: it is also possible to program the VGA controller to have the
// high bit for the foreground color enable blinking characters.
2001-10-01 22:36:13 +04:00
2006-10-15 20:23:42 +04:00
COLORREF crFore = SetTextColor ( MemoryDC , GetColorRef ( ( cColor > > 4 ) & 0xf ) ) ;
COLORREF crBack = SetBkColor ( MemoryDC , GetColorRef ( cColor & 0xf ) ) ;
BitBlt ( MemoryDC , xStart , yStart , ptSize . x , ptSize . y , hdcMem , ptOrg . x ,
ptOrg . y , dwRop ) ;
SetBkColor ( MemoryDC , crBack ) ;
SetTextColor ( MemoryDC , crFore ) ;
2001-04-10 05:04:59 +04:00
SelectObject ( MemoryDC , oldObj ) ;
updateUpdated ( xStart , yStart , ptSize . x + xStart - 1 , ptSize . y + yStart - 1 ) ;
DeleteDC ( hdcMem ) ;
}
void updateUpdated ( int x1 , int y1 , int x2 , int y2 ) {
x1 * = stretch_factor ;
x2 * = stretch_factor ;
if ( ! updated_area_valid ) {
updated_area . left = x1 ;
updated_area . top = y1 ;
updated_area . right = x2 ;
updated_area . bottom = y2 ;
} else {
if ( x1 < updated_area . left ) updated_area . left = x1 ;
if ( y1 < updated_area . top ) updated_area . top = y1 ;
if ( x2 > updated_area . right ) updated_area . right = x2 ;
if ( y2 > updated_area . bottom ) updated_area . bottom = y2 ;
}
updated_area_valid = TRUE ;
}
2002-08-10 19:23:30 +04:00
void headerbar_click ( int x )
{
if ( x < bx_headerbar_entries ) {
bx_headerbar_entry [ x ] . f ( ) ;
2001-04-10 05:04:59 +04:00
}
}
2006-01-22 15:31:16 +03:00
# if defined(__MINGW32__) || defined(_MSC_VER)
2001-04-10 05:04:59 +04:00
# if BX_SHOW_IPS
VOID CALLBACK MyTimer ( HWND hwnd , UINT uMsg , UINT idEvent , DWORD dwTime )
{
bx_signal_handler ( SIGALRM ) ;
}
2006-01-22 15:31:16 +03:00
void alarm ( int time )
2001-04-10 05:04:59 +04:00
{
2006-01-22 15:31:16 +03:00
UINT idTimer = 2 ;
2002-08-10 19:23:30 +04:00
SetTimer ( stInfo . simWnd , idTimer , time * 1000 , MyTimer ) ;
2001-04-10 05:04:59 +04:00
}
# endif
# endif
2001-06-23 07:18:14 +04:00
2006-10-15 20:23:42 +04:00
void bx_win32_gui_c : : mouse_enabled_changed_specific ( bx_bool val )
2001-06-23 07:18:14 +04:00
{
2006-10-15 20:23:42 +04:00
if ( ( val ! = ( bx_bool ) mouseCaptureMode ) & & ! mouseToggleReq ) {
2004-02-17 00:47:08 +03:00
mouseToggleReq = TRUE ;
mouseCaptureNew = val ;
}
2001-06-23 07:18:14 +04:00
}
2002-03-21 21:40:20 +03:00
2006-01-25 20:37:22 +03:00
void bx_win32_gui_c : : set_tooltip ( unsigned hbar_id , const char * tip )
{
bx_headerbar_entry [ hbar_id ] . tooltip = tip ;
}
2006-01-22 21:15:48 +03:00
# if BX_SHOW_IPS
2006-01-22 15:31:16 +03:00
void bx_win32_gui_c : : show_ips ( Bit32u ips_count )
{
2006-01-27 21:04:49 +03:00
if ( ! ipsUpdate ) {
sprintf ( ipsText , " IPS: %9u " , ips_count ) ;
ipsUpdate = TRUE ;
2006-01-24 00:53:57 +03:00
}
2006-01-22 15:31:16 +03:00
}
2006-01-22 21:15:48 +03:00
# endif
2006-01-22 15:31:16 +03:00
2003-06-20 14:36:46 +04:00
# if BX_USE_WINDOWS_FONTS
2002-03-21 21:40:20 +03:00
void DrawChar ( HDC hdc , unsigned char c , int xStart , int yStart ,
unsigned char cColor , int cs_start , int cs_end ) {
HDC hdcMem ;
POINT ptSize , ptOrg ;
HGDIOBJ oldObj ;
char str [ 2 ] ;
HFONT hFontOld ;
hdcMem = CreateCompatibleDC ( hdc ) ;
SetMapMode ( hdcMem , GetMapMode ( hdc ) ) ;
2003-05-13 22:44:23 +04:00
ptSize . x = xChar ;
2002-03-21 21:40:20 +03:00
ptSize . y = yChar ;
DPtoLP ( hdc , & ptSize , 1 ) ;
ptOrg . x = 0 ;
ptOrg . y = 0 ;
DPtoLP ( hdcMem , & ptOrg , 1 ) ;
oldObj = SelectObject ( MemoryDC , MemoryBitmap ) ;
hFontOld = ( HFONT ) SelectObject ( MemoryDC , hFont [ FontId ] ) ;
2006-10-15 20:23:42 +04:00
// The highest background bit usually means blinking characters. No idea
// how to implement that so for now it's just implemented as color.
// Note: it is also possible to program the VGA controller to have the
// high bit for the foreground color enable blinking characters.
2002-03-21 21:40:20 +03:00
2006-10-15 20:23:42 +04:00
COLORREF crFore = SetTextColor ( MemoryDC , GetColorRef ( cColor & 0xf ) ) ;
COLORREF crBack = SetBkColor ( MemoryDC , GetColorRef ( ( cColor > > 4 ) & 0xf ) ) ;
2002-03-21 21:40:20 +03:00
str [ 0 ] = c ;
str [ 1 ] = 0 ;
int y = FontId = = 2 ? 16 : 8 ;
TextOut ( MemoryDC , xStart , yStart , str , 1 ) ;
if ( cs_start < = cs_end & & cs_start < y )
{
RECT rc ;
2002-08-12 18:41:42 +04:00
SetBkColor ( MemoryDC , GetColorRef ( cColor & 0xf ) ) ;
SetTextColor ( MemoryDC , GetColorRef ( ( cColor > > 4 ) & 0xf ) ) ;
2002-03-21 21:40:20 +03:00
rc . left = xStart + 0 ;
2003-05-13 22:44:23 +04:00
rc . right = xStart + xChar ;
2002-03-21 21:40:20 +03:00
if ( cs_end > = y )
cs_end = y - 1 ;
rc . top = yStart + cs_start * yChar / y ;
rc . bottom = yStart + ( cs_end + 1 ) * yChar / y ;
ExtTextOut ( MemoryDC , xStart , yStart , ETO_CLIPPED | ETO_OPAQUE , & rc , str , 1 , NULL ) ;
}
SetBkColor ( MemoryDC , crBack ) ;
SetTextColor ( MemoryDC , crFore ) ;
SelectObject ( MemoryDC , hFontOld ) ;
SelectObject ( MemoryDC , oldObj ) ;
updateUpdated ( xStart , yStart , ptSize . x + xStart - 1 , ptSize . y + yStart - 1 ) ;
DeleteDC ( hdcMem ) ;
}
void InitFont ( void )
{
LOGFONT lf ;
lf . lfWidth = 8 ;
lf . lfEscapement = 0 ;
lf . lfOrientation = 0 ;
lf . lfWeight = FW_MEDIUM ;
lf . lfItalic = FALSE ;
lf . lfUnderline = FALSE ;
lf . lfStrikeOut = FALSE ;
lf . lfCharSet = OEM_CHARSET ;
lf . lfOutPrecision = OUT_DEFAULT_PRECIS ;
lf . lfClipPrecision = CLIP_DEFAULT_PRECIS ;
lf . lfQuality = DEFAULT_QUALITY ;
lf . lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE ;
wsprintf ( lf . lfFaceName , " Lucida Console " ) ;
2006-01-22 21:15:48 +03:00
for ( int i = 0 ; i < 3 ; i + + )
2002-03-21 21:40:20 +03:00
{
lf . lfHeight = 12 + i * 2 ;
hFont [ i ] = CreateFontIndirect ( & lf ) ;
}
}
void DestroyFont ( void )
{
2006-01-22 21:15:48 +03:00
for ( int i = 0 ; i < 3 ; i + + )
2002-03-21 21:40:20 +03:00
{
DeleteObject ( hFont [ i ] ) ;
}
}
2003-06-20 14:36:46 +04:00
# endif /* if BX_USE_WINDOWS_FONTS */
2002-11-19 08:47:45 +03:00
# endif /* if BX_WITH_WIN32 */