Bochs/bochs/gui/sdl.cc
instinc ee181da9d3 Added required space for the control bar
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
2002-02-06 02:12:45 +00:00

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;
}