ee181da9d3
Added control for 80x50 fonts Added mouse input Added mouse grabbing Added automatic mouse grabbing when entering full screen Added autoremoval of header when going fullscreen Simplified a couple of graphic routines
666 lines
14 KiB
C++
666 lines
14 KiB
C++
#define _MULTI_THREAD
|
|
|
|
#include <iostream>
|
|
|
|
#include <stdlib.h>
|
|
#include <SDL/SDL.h>
|
|
#include <SDL/SDL_endian.h>
|
|
#include <SDL/SDL_thread.h>
|
|
|
|
#include "bochs.h"
|
|
#include "icon_bochs.h"
|
|
#include "sdl.h"
|
|
|
|
#define LOG_THIS bx_gui.
|
|
|
|
|
|
|
|
SDL_Thread *sdl_thread;
|
|
SDL_Surface *sdl_screen, *sdl_fullscreen;
|
|
SDL_Event sdl_event;
|
|
int sdl_fullscreen_toggle;
|
|
int sdl_grab;
|
|
int res_x, res_y;
|
|
int headerbar_height;
|
|
int textres_x, textres_y;
|
|
int fontwidth = 8, fontheight = 16;
|
|
unsigned tilewidth, tileheight;
|
|
unsigned char *font = &sdl_font8x16[0][0];
|
|
unsigned char menufont[256][8];
|
|
Uint32 palette[256];
|
|
Uint32 headerbar_fg, headerbar_bg;
|
|
Bit8u old_mousebuttons=0, new_mousebuttons=0;
|
|
int old_mousex=0, new_mousex=0;
|
|
int old_mousey=0, new_mousey=0;
|
|
|
|
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
|
#define SWAP16(X) (X)
|
|
#define SWAP32(X) (X)
|
|
#else
|
|
#define SWAP16(X) SDL_Swap16(X)
|
|
#define SWAP32(X) SDL_Swap32(X)
|
|
#endif
|
|
|
|
|
|
|
|
void switch_to_windowed(void)
|
|
{
|
|
SDL_Surface *tmp;
|
|
SDL_Rect src, dst;
|
|
src.x = 0; src.y = 0;
|
|
src.w = res_x; src.h = res_y;
|
|
dst.x = 0; dst.y = 0;
|
|
|
|
tmp = SDL_CreateRGBSurface(
|
|
SDL_SWSURFACE,
|
|
res_x,
|
|
res_y,
|
|
32,
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
0xff000000,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff
|
|
#else
|
|
0x000000ff,
|
|
0x0000ff00,
|
|
0x00ff0000,
|
|
0xff000000
|
|
#endif
|
|
);
|
|
|
|
SDL_BlitSurface(sdl_fullscreen,&src,tmp,&dst);
|
|
SDL_UpdateRect(tmp,0,0,res_x,res_y);
|
|
SDL_FreeSurface(sdl_fullscreen);
|
|
sdl_fullscreen = NULL;
|
|
|
|
sdl_screen = SDL_SetVideoMode(res_x,res_y+headerbar_height,32, SDL_SWSURFACE);
|
|
dst.y = headerbar_height;
|
|
SDL_BlitSurface(tmp,&src,sdl_screen,&dst);
|
|
SDL_UpdateRect(tmp,0,0,res_x,res_y+headerbar_height);
|
|
SDL_FreeSurface(tmp);
|
|
|
|
SDL_ShowCursor(1);
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
bx_gui.show_headerbar();
|
|
sdl_grab = 0;
|
|
}
|
|
|
|
void switch_to_fullscreen(void)
|
|
{
|
|
SDL_Surface *tmp;
|
|
SDL_Rect src, dst;
|
|
src.x = 0; src.y = headerbar_height;
|
|
src.w = res_x; src.h = res_y;
|
|
dst.x = 0; dst.y = 0;
|
|
|
|
tmp = SDL_CreateRGBSurface(
|
|
SDL_SWSURFACE,
|
|
res_x,
|
|
res_y,
|
|
32,
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
0xff000000,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff
|
|
#else
|
|
0x000000ff,
|
|
0x0000ff00,
|
|
0x00ff0000,
|
|
0xff000000
|
|
#endif
|
|
);
|
|
SDL_BlitSurface(sdl_screen,&src,tmp,&dst);
|
|
SDL_UpdateRect(tmp,0,0,res_x,res_y);
|
|
SDL_FreeSurface(sdl_screen);
|
|
sdl_screen = NULL;
|
|
|
|
sdl_fullscreen = SDL_SetVideoMode(res_x,res_y,32, SDL_HWSURFACE|SDL_FULLSCREEN);
|
|
src.y = 0;
|
|
SDL_BlitSurface(tmp,&src,sdl_fullscreen,&dst);
|
|
SDL_UpdateRect(tmp,0,0,res_x,res_y);
|
|
SDL_FreeSurface(tmp);
|
|
|
|
SDL_ShowCursor(0);
|
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
sdl_grab = 1;
|
|
}
|
|
|
|
|
|
void bx_gui_c::specific_init(
|
|
bx_gui_c *th,
|
|
int argc,
|
|
char **argv,
|
|
unsigned x_tilesize,
|
|
unsigned y_tilesize,
|
|
unsigned header_bar_y)
|
|
{
|
|
int i,j;
|
|
Uint32 color, *buf;
|
|
|
|
tilewidth = x_tilesize;
|
|
tileheight = y_tilesize;
|
|
headerbar_height = header_bar_y;
|
|
|
|
for(i=0;i<256;i++)
|
|
for(j=0;j<8;j++)
|
|
menufont[i][j] = sdl_font8x8[i][j];
|
|
|
|
if( SDL_Init(SDL_INIT_VIDEO) < 0 )
|
|
{
|
|
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
|
|
BX_PANIC (("Unable to initialize SDL libraries"));
|
|
return;
|
|
}
|
|
atexit(SDL_Quit);
|
|
|
|
sdl_screen = NULL;
|
|
th->dimension_update(640,480);
|
|
|
|
|
|
sdl_fullscreen_toggle = 0;
|
|
SDL_EnableKeyRepeat(250,50);
|
|
SDL_WM_SetCaption(
|
|
#if BX_CPU_LEVEL < 2
|
|
"Bochs 8086 emulator, http://bochs.sourceforge.net/",
|
|
#elif BX_CPU_LEVEL == 2
|
|
"Bochs 80286 emulator, http://bochs.sourceforge.net/",
|
|
#elif BX_CPU_LEVEL == 3
|
|
"Bochs 80386 emulator, http://bochs.sourceforge.net/",
|
|
#elif BX_CPU_LEVEL == 4
|
|
"Bochs 80486 emulator, http://bochs.sourceforge.net/",
|
|
#else
|
|
"Bochs Pentium emulator, http://bochs.sourceforge.net/",
|
|
#endif
|
|
"Bochs" );
|
|
SDL_WarpMouse(res_x/2, res_y/2);
|
|
}
|
|
|
|
void bx_gui_c::text_update(
|
|
Bit8u *old_text,
|
|
Bit8u *new_text,
|
|
unsigned long cursor_x,
|
|
unsigned long cursor_y,
|
|
Bit16u cursor_state,
|
|
unsigned rows)
|
|
{
|
|
char *oldText = (char *)old_text;
|
|
char *newText = (char *)new_text;
|
|
unsigned char font_row, *pfont_row;
|
|
int hchars,fontrows,fontpixels,x,y;
|
|
int fgcolor_ndx;
|
|
int bgcolor_ndx;
|
|
Uint32 fgcolor;
|
|
Uint32 bgcolor;
|
|
Uint32 *buf, *buf_row, *buf_char;
|
|
Uint32 disp;
|
|
|
|
if( sdl_screen )
|
|
{
|
|
disp = sdl_screen->pitch/4;
|
|
buf_row = (Uint32 *)sdl_screen->pixels + headerbar_height*disp;
|
|
}
|
|
else
|
|
{
|
|
disp = sdl_fullscreen->pitch/4;
|
|
buf_row = (Uint32 *)sdl_fullscreen->pixels;
|
|
}
|
|
|
|
do
|
|
{
|
|
buf = buf_row;
|
|
hchars = textres_x;
|
|
do
|
|
{
|
|
// check if char needs to be updated
|
|
if( (old_text[0] != new_text[0])
|
|
|| (old_text[1] != new_text[1]) )
|
|
{
|
|
|
|
// Get Foreground/Background pixel colors
|
|
fgcolor_ndx = new_text[1] & 0x0F;
|
|
bgcolor_ndx = (new_text[1] >> 4) & 0x07;
|
|
fgcolor = palette[fgcolor_ndx];
|
|
bgcolor = palette[bgcolor_ndx];
|
|
|
|
// Display this one char
|
|
fontrows = fontheight;
|
|
pfont_row = &font[(new_text[0]*fontheight)];
|
|
buf_char = buf;
|
|
do
|
|
{
|
|
font_row = *pfont_row++;
|
|
fontpixels = fontwidth;
|
|
do
|
|
{
|
|
if( (font_row & 0x80) == 0 )
|
|
*buf = bgcolor;
|
|
else
|
|
*buf = fgcolor;
|
|
buf++;
|
|
font_row = font_row << 1;
|
|
} while( --fontpixels );
|
|
buf -= fontwidth;
|
|
buf += disp;
|
|
} while( --fontrows );
|
|
|
|
// restore output buffer ptr to start of this char
|
|
buf = buf_char;
|
|
}
|
|
// move to next char location on screen
|
|
buf += fontwidth;
|
|
|
|
// select next char in old/new text
|
|
new_text+=2;
|
|
old_text+=2;
|
|
|
|
// process one entire horizontal row
|
|
} while( --hchars );
|
|
|
|
// go to next character row location
|
|
buf_row += disp * fontheight;
|
|
} while( --rows );
|
|
}
|
|
|
|
|
|
void bx_gui_c::graphics_tile_update(
|
|
Bit8u *snapshot,
|
|
unsigned x,
|
|
unsigned y)
|
|
{
|
|
Uint32 *buf, disp;
|
|
Uint32 *buf_row;
|
|
int i,j;
|
|
|
|
if( sdl_screen )
|
|
{
|
|
disp = sdl_screen->pitch/4;
|
|
buf = (Uint32 *)sdl_screen->pixels + (headerbar_height+y)*disp + x;
|
|
}
|
|
else
|
|
{
|
|
disp = sdl_fullscreen->pitch/4;
|
|
buf = (Uint32 *)sdl_fullscreen->pixels + y*disp + x;
|
|
}
|
|
|
|
i = tileheight;
|
|
if( i + y > res_y ) i = res_y - y;
|
|
|
|
do
|
|
{
|
|
buf_row = buf;
|
|
j = tilewidth;
|
|
do
|
|
{
|
|
*buf++ = palette[*snapshot++];
|
|
} while( --j );
|
|
buf = buf_row + disp;
|
|
} while( --i);
|
|
}
|
|
|
|
|
|
void bx_gui_c::handle_events(void)
|
|
{
|
|
Bit32u key_event;
|
|
|
|
while( SDL_PollEvent(&sdl_event) )
|
|
{
|
|
switch( sdl_event.type )
|
|
{
|
|
case SDL_VIDEOEXPOSE:
|
|
if( sdl_fullscreen_toggle == 0 )
|
|
SDL_UpdateRect( sdl_screen, 0,0, res_x, res_y+headerbar_height );
|
|
else
|
|
SDL_UpdateRect( sdl_screen, 0,headerbar_height, res_x, res_y );
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
new_mousebuttons = ((sdl_event.motion.state & 0x01)|((sdl_event.motion.state>>1)&0x02));
|
|
bx_devices.keyboard->mouse_motion(
|
|
sdl_event.motion.xrel,
|
|
sdl_event.motion.yrel,
|
|
new_mousebuttons );
|
|
old_mousebuttons = new_mousebuttons;
|
|
old_mousex = (int)(sdl_event.motion.x);
|
|
old_mousey = (int)(sdl_event.motion.y);
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
if( (sdl_event.button.button == SDL_BUTTON(2))
|
|
&& (sdl_fullscreen_toggle == 0) )
|
|
{
|
|
if( sdl_grab == 0 )
|
|
{
|
|
SDL_ShowCursor(0);
|
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
}
|
|
else
|
|
{
|
|
SDL_ShowCursor(1);
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
}
|
|
sdl_grab = ~sdl_grab;
|
|
break;
|
|
}
|
|
case SDL_MOUSEBUTTONUP:
|
|
// figure out mouse state
|
|
new_mousex = (int)(sdl_event.button.x);
|
|
new_mousey = (int)(sdl_event.button.y);
|
|
new_mousebuttons =
|
|
(sdl_event.button.state & 0x01) |
|
|
((sdl_event.button.state>>1)&0x02) |
|
|
((sdl_event.button.state<<1)&0x04) ;
|
|
// filter out middle button if not fullscreen
|
|
if( sdl_fullscreen_toggle == 0 )
|
|
new_mousebuttons &= 0x03;
|
|
// send motion information
|
|
bx_devices.keyboard->mouse_motion(
|
|
new_mousex - old_mousex,
|
|
new_mousey - old_mousey,
|
|
new_mousebuttons );
|
|
// mark current state to diff with next packet
|
|
old_mousebuttons = new_mousebuttons;
|
|
old_mousex = new_mousex;
|
|
old_mousey = new_mousey;
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
|
|
// Windows/Fullscreen toggle-check
|
|
if( sdl_event.key.keysym.sym == SDLK_SCROLLOCK )
|
|
{
|
|
Uint32 *buf, *buf_row;
|
|
Uint32 *buf2, *buf_row2;
|
|
Uint32 disp, disp2;
|
|
int rows, cols;
|
|
// SDL_WM_ToggleFullScreen( sdl_screen );
|
|
sdl_fullscreen_toggle = ~sdl_fullscreen_toggle;
|
|
if( sdl_fullscreen_toggle == 0 )
|
|
switch_to_windowed();
|
|
else
|
|
switch_to_fullscreen();
|
|
bx_gui.show_headerbar();
|
|
bx_gui.flush();
|
|
break;
|
|
}
|
|
|
|
// convert scancode->bochs code
|
|
if( sdl_event.key.keysym.scancode > _SCN2BX_LAST_ ) break;
|
|
key_event = scancodes2bx[ sdl_event.key.keysym.scancode-8 ][1];
|
|
if( key_event == 0 ) break;
|
|
bx_devices.keyboard->gen_scancode( key_event );
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
|
|
// filter out release of Windows/Fullscreen toggle and unsupported keys
|
|
if( (sdl_event.key.keysym.sym != SDLK_SCROLLOCK)
|
|
&& (sdl_event.key.keysym.scancode < _SCN2BX_LAST_ ))
|
|
{
|
|
// convert scancode->bochs code
|
|
key_event = scancodes2bx[ sdl_event.key.keysym.scancode-8 ][1];
|
|
if( key_event == 0 ) break;
|
|
bx_devices.keyboard->gen_scancode( key_event | BX_KEY_RELEASED );
|
|
}
|
|
break;
|
|
|
|
case SDL_QUIT:
|
|
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
|
|
BX_PANIC (("User requested shutdown."));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void bx_gui_c::flush(void)
|
|
{
|
|
if( sdl_screen )
|
|
SDL_UpdateRect( sdl_screen,0,0,res_x,res_y+headerbar_height );
|
|
else
|
|
SDL_UpdateRect( sdl_fullscreen,0,0,res_x,res_y);
|
|
}
|
|
|
|
|
|
void bx_gui_c::clear_screen(void)
|
|
{
|
|
int i = res_y, j;
|
|
Uint32 color;
|
|
Uint32 *buf, *buf_row;
|
|
Uint32 disp;
|
|
|
|
if( sdl_screen )
|
|
{
|
|
color = SDL_MapRGB( sdl_screen->format, 0,0,0 );
|
|
disp = sdl_screen->pitch/4;
|
|
buf = (Uint32 *)sdl_screen->pixels + headerbar_height*disp;
|
|
}
|
|
else if( sdl_fullscreen )
|
|
{
|
|
color = SDL_MapRGB( sdl_fullscreen->format, 0,0,0 );
|
|
disp = sdl_fullscreen->pitch/4;
|
|
buf = (Uint32 *)sdl_fullscreen->pixels;
|
|
}
|
|
else return;
|
|
|
|
do
|
|
{
|
|
buf_row = buf;
|
|
j = res_x;
|
|
while( j-- ) *buf++ = color;
|
|
buf = buf_row + disp;
|
|
} while( --i );
|
|
|
|
if( sdl_screen )
|
|
SDL_UpdateRect(sdl_screen,0,0,res_x,res_y+headerbar_height);
|
|
else
|
|
SDL_UpdateRect(sdl_fullscreen,0,0,res_x,res_y);
|
|
}
|
|
|
|
|
|
|
|
Boolean bx_gui_c::palette_change(
|
|
unsigned index,
|
|
unsigned red,
|
|
unsigned green,
|
|
unsigned blue)
|
|
{
|
|
unsigned char palred = red & 0xFF;
|
|
unsigned char palgreen = green & 0xFF;
|
|
unsigned char palblue = blue & 0xFF;
|
|
|
|
if( index > 255 ) return 0;
|
|
|
|
if( sdl_screen )
|
|
palette[index] = SDL_MapRGB( sdl_screen->format, palred, palgreen, palblue );
|
|
else if( sdl_fullscreen )
|
|
palette[index] = SDL_MapRGB( sdl_fullscreen->format, palred, palgreen, palblue );
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
void bx_gui_c::dimension_update(
|
|
unsigned x,
|
|
unsigned y)
|
|
{
|
|
int i=headerbar_height;
|
|
|
|
// TODO: remove this stupid check whenever the vga driver is fixed
|
|
if( y == 208 ) y = 200;
|
|
// TODO: remove this stupid check whenever 80x50 font is properly handled
|
|
if( y > x )
|
|
{
|
|
y = y>>1;
|
|
font = &sdl_font8x8[0][0];
|
|
fontheight = 8;
|
|
fontwidth = 8;
|
|
}
|
|
else
|
|
{
|
|
font = &sdl_font8x16[0][0];
|
|
fontheight = 16;
|
|
fontwidth = 8;
|
|
}
|
|
|
|
if( (x == res_x) && (y == res_y )) return;
|
|
|
|
if( sdl_screen )
|
|
{
|
|
SDL_FreeSurface( sdl_screen );
|
|
sdl_screen = NULL;
|
|
}
|
|
if( sdl_fullscreen )
|
|
{
|
|
SDL_FreeSurface( sdl_fullscreen );
|
|
sdl_fullscreen = NULL;
|
|
}
|
|
|
|
if( sdl_fullscreen_toggle == 0 )
|
|
{
|
|
sdl_screen = SDL_SetVideoMode( x, y+headerbar_height, 32, SDL_SWSURFACE );
|
|
if( !sdl_screen )
|
|
{
|
|
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
|
|
BX_PANIC (("Unable to set requested videomode: %ix%i: %s",x,y,SDL_GetError()));
|
|
}
|
|
headerbar_fg = SDL_MapRGB(
|
|
sdl_screen->format,
|
|
BX_HEADERBAR_FG_RED,
|
|
BX_HEADERBAR_FG_GREEN,
|
|
BX_HEADERBAR_FG_BLUE );
|
|
headerbar_bg = SDL_MapRGB(
|
|
sdl_screen->format,
|
|
BX_HEADERBAR_BG_RED,
|
|
BX_HEADERBAR_BG_GREEN,
|
|
BX_HEADERBAR_BG_BLUE );
|
|
}
|
|
else
|
|
{
|
|
sdl_fullscreen = SDL_SetVideoMode( x, y, 32, SDL_HWSURFACE|SDL_FULLSCREEN );
|
|
if( !sdl_fullscreen )
|
|
{
|
|
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
|
|
BX_PANIC (("Unable to set requested videomode: %ix%i: %s",x,y,SDL_GetError()));
|
|
}
|
|
}
|
|
res_x = x;
|
|
res_y = y;
|
|
textres_x = x / fontwidth;
|
|
textres_y = y / fontheight;
|
|
bx_gui.show_headerbar();
|
|
}
|
|
|
|
|
|
unsigned bx_gui_c::create_bitmap(
|
|
const unsigned char *bmap,
|
|
unsigned xdim,
|
|
unsigned ydim)
|
|
{
|
|
cout << "sdl: create bitmap" <<endl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
unsigned bx_gui_c::headerbar_bitmap(
|
|
unsigned bmap_id,
|
|
unsigned alignment,
|
|
void (*f)(void))
|
|
{
|
|
cout << "sdl: headerbar bitmap" <<endl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void bx_gui_c::replace_bitmap(
|
|
unsigned hbar_id,
|
|
unsigned bmap_id)
|
|
{
|
|
cout << "sdl: replace bitmap" << endl;
|
|
}
|
|
|
|
|
|
void bx_gui_c::show_headerbar(void)
|
|
{
|
|
Uint32 *buf;
|
|
Uint32 *buf_row;
|
|
int rowsleft = headerbar_height;
|
|
int colsleft;
|
|
|
|
if( !sdl_screen ) return;
|
|
buf = (Uint32 *)sdl_screen->pixels;
|
|
|
|
do
|
|
{
|
|
colsleft = res_x;
|
|
buf_row = buf;
|
|
do
|
|
{
|
|
*buf++ = headerbar_bg;
|
|
} while( --colsleft );
|
|
buf = buf_row + sdl_screen->pitch/4;
|
|
} while( --rowsleft );
|
|
SDL_UpdateRect(sdl_screen,0,0,res_x,headerbar_height);
|
|
}
|
|
|
|
|
|
void update_floppy_status_buttons (void)
|
|
{
|
|
cout << "sdl: update floppy status buttons" <<endl;
|
|
}
|
|
|
|
|
|
void bx_gui_c::mouse_enabled_changed_specific (Boolean val)
|
|
{
|
|
cout << "sdl: mouse enabled changed specific" <<endl;
|
|
}
|
|
|
|
|
|
void bx_gui_c::exit(void)
|
|
{
|
|
if( sdl_screen )
|
|
SDL_FreeSurface(sdl_screen);
|
|
}
|
|
|
|
|
|
void init_signal_handlers ()
|
|
{
|
|
cout << "sdl: init signal handlers" <<endl;
|
|
}
|
|
|
|
|
|
void key_event(Bit32u key)
|
|
{
|
|
cout << "sdl: key event" << endl;
|
|
}
|
|
|
|
|
|
void init(
|
|
int argc,
|
|
char **argv,
|
|
unsigned x_tilesize,
|
|
unsigned y_tilesize)
|
|
{
|
|
cout << "sdl: init" <<endl;
|
|
}
|
|
|
|
|
|
void sim_is_idle(void)
|
|
{
|
|
cout << "sdl: sim is idle" <<endl;
|
|
}
|
|
|
|
|
|
Bit32u get_sighandler_mask ()
|
|
{
|
|
cout << "sdl: get sighandler mask" <<endl;
|
|
}
|
|
|
|
|
|
void sighandler (int sig)
|
|
{
|
|
cout << "sdl: sighandler" <<endl;
|
|
}
|
|
|