2018-11-16 00:42:29 +01:00
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System ( TM ) emulator .
This file is licensed under the Snes9x License .
For further information , consult the LICENSE file in the root directory .
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-07-05 00:53:38 +02:00
# include "gtk_compat.h"
2018-05-09 23:25:09 +02:00
# ifdef GDK_WINDOWING_X11
2018-11-07 01:04:10 +01:00
# include <X11/Xatom.h>
2018-05-09 23:25:09 +02:00
# endif
2010-09-25 17:46:12 +02:00
# ifdef USE_XV
# include <X11/extensions/XShm.h>
# include <X11/extensions/Xv.h>
# include <X11/extensions/Xvlib.h>
# endif
2018-05-24 19:18:59 +02:00
# ifdef USE_OPENGL
# include "gtk_shader_parameters.h"
# endif
2010-09-25 17:46:12 +02:00
# include "gtk_s9x.h"
# include "gtk_preferences.h"
# include "gtk_icon.h"
# include "gtk_display.h"
# include "gtk_file.h"
# include "gtk_sound.h"
# include "gtk_control.h"
# include "gtk_cheat.h"
# include "gtk_netplay.h"
2020-07-05 00:53:38 +02:00
# include "gtk_s9xwindow.h"
# include "snes9x.h"
# include "controls.h"
# include "movie.h"
# include "display.h"
# include "apu/apu.h"
# include "memmap.h"
# include "cpuexec.h"
# include "snapshot.h"
# include "netplay.h"
static Glib : : RefPtr < Gtk : : FileFilter > get_save_states_file_filter ( )
{
const char * exts [ ] = { " *.sst " , " *.000 " , " *.001 " , " *.002 " , " *.003 " , " *.004 " ,
" *.005 " , " *.006 " , " *.007 " , " *.008 " , " *.009 " , nullptr } ;
auto filter = Gtk : : FileFilter : : create ( ) ;
filter - > set_name ( _ ( " Save States " ) ) ;
for ( int i = 0 ; exts [ i ] ; i + + )
filter - > add_pattern ( exts [ i ] ) ;
return filter ;
}
static Glib : : RefPtr < Gtk : : FileFilter > get_all_files_filter ( )
{
auto filter = Gtk : : FileFilter : : create ( ) ;
filter - > set_name ( _ ( " All Files " ) ) ;
filter - > add_pattern ( " *.* " ) ;
filter - > add_pattern ( " * " ) ;
return filter ;
}
Snes9xWindow : : Snes9xWindow ( Snes9xConfig * config )
: GtkBuilderWindow ( " main_window " )
{
user_pause = 0 ;
sys_pause = 0 ;
last_width = - 1 ;
last_height = - 1 ;
this - > config = config ;
recent_menu = nullptr ;
fullscreen_state = 0 ;
maximized_state = 0 ;
focused = true ;
paused_from_focus_loss = false ;
cr = nullptr ;
cairo_owned = false ;
mouse_grabbed = false ;
2010-09-25 17:46:12 +02:00
2020-08-23 23:28:01 +02:00
snes9x_preferences_create ( config ) ;
2020-07-05 00:53:38 +02:00
if ( Gtk : : IconTheme : : get_default ( ) - > has_icon ( " snes9x " ) )
{
window - > set_default_icon_name ( " snes9x " ) ;
}
else
{
2020-08-24 00:17:55 +02:00
auto pixbuf = Gdk : : Pixbuf : : create_from_inline ( sizeof ( app_icon ) , app_icon , false ) ;
window - > set_default_icon ( pixbuf ) ;
2020-07-05 00:53:38 +02:00
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
drawing_area = get_object < Gtk : : DrawingArea > ( " drawingarea " ) . get ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
gtk_widget_realize ( GTK_WIDGET ( window - > gobj ( ) ) ) ;
gtk_widget_realize ( GTK_WIDGET ( drawing_area - > gobj ( ) ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
# ifndef USE_OPENGL
get_object < Gtk : : Widget > ( " shader_parameters_separator " ) - > hide ( ) ;
get_object < Gtk : : Widget > ( " shader_parameters_item " ) - > hide ( ) ;
# else
enable_widget ( " shader_parameters_item " , false ) ;
# endif
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
connect_signals ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( config - > window_width < 100 | | config - > window_height < 100 )
{
config - > window_width = 256 ;
config - > window_height = 224 ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
window - > get_window ( ) - > set_cursor ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
resize ( config - > window_width , config - > window_height ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : connect_signals ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
drawing_area - > signal_draw ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : draw ) ) ;
window - > signal_delete_event ( ) . connect ( [ ] ( GdkEventAny * event ) - > bool {
S9xExit ( ) ;
return false ;
} ) ;
get_object < Gtk : : MenuItem > ( " exit_item " ) - > signal_activate ( ) . connect ( [ ] {
S9xExit ( ) ;
} ) ;
window - > signal_window_state_event ( ) . connect ( [ & ] ( GdkEventWindowState * state ) - > bool {
fullscreen_state = state - > new_window_state & GDK_WINDOW_STATE_FULLSCREEN ;
maximized_state = state - > new_window_state & GDK_WINDOW_STATE_MAXIMIZED ;
return false ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
window - > signal_focus_in_event ( ) . connect ( [ & ] ( GdkEventFocus * event ) - > bool {
focus_notify ( true ) ;
return false ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
window - > signal_focus_out_event ( ) . connect ( [ & ] ( GdkEventFocus * event ) - > bool {
focus_notify ( false ) ;
return false ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
last_key_pressed_keyval = 0 ;
last_key_pressed_type = GDK_NOTHING ;
window - > signal_key_press_event ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : event_key ) , false ) ;
window - > signal_key_release_event ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : event_key ) , false ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
drawing_area - > signal_button_press_event ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : button_press ) ) ;
drawing_area - > signal_button_release_event ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : button_release ) ) ;
drawing_area - > signal_motion_notify_event ( ) . connect ( sigc : : mem_fun ( * this , & Snes9xWindow : : motion_notify ) ) ;
2018-12-02 02:58:13 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " continue_item " ) - > signal_activate ( ) . connect ( [ & ] {
unpause_from_user ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " pause_item " ) - > signal_activate ( ) . connect ( [ & ] {
pause_from_user ( ) ;
} ) ;
2018-10-29 22:02:45 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " fullscreen_item " ) - > signal_activate ( ) . connect ( [ & ] {
toggle_fullscreen_mode ( ) ;
} ) ;
2011-02-06 02:42:26 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " open_rom_item " ) - > signal_activate ( ) . connect ( [ & ] {
open_rom_dialog ( ) ;
} ) ;
2011-02-06 02:42:26 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " reset_item " ) - > signal_activate ( ) . connect ( [ & ] {
S9xSoftReset ( ) ;
} ) ;
2018-04-28 18:59:17 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " hard_reset_item " ) - > signal_activate ( ) . connect ( [ & ] {
S9xReset ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
# ifdef USE_OPENGL
get_object < Gtk : : MenuItem > ( " shader_parameters_item " ) - > signal_activate ( ) . connect ( [ & ] {
gtk_shader_parameters_dialog ( get_window ( ) ) ;
} ) ;
2011-02-06 02:42:26 +01:00
# endif
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
const std : : vector < const char * > port_items = { " joypad1 " , " mouse1 " , " superscope1 " , " joypad2 " , " mouse2 " , " multitap2 " , " superscope2 " , " nothingpluggedin2 " } ;
for ( auto & name : port_items )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( name ) - > signal_activate ( ) . connect ( sigc : : bind < const char * > ( sigc : : mem_fun ( * this , & Snes9xWindow : : port_activate ) , name ) ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
for ( int i = 0 ; i < = 9 ; i + + )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
std : : string name = " load_state_ " + std : : to_string ( i ) ;
get_object < Gtk : : MenuItem > ( name . c_str ( ) ) - > signal_activate ( ) . connect ( [ i ] {
S9xQuickLoadSlot ( i ) ;
} ) ;
name = " save_state_ " + std : : to_string ( i ) ;
get_object < Gtk : : MenuItem > ( name . c_str ( ) ) - > signal_activate ( ) . connect ( [ i ] {
S9xQuickSaveSlot ( i ) ;
} ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " from_file1 " ) - > signal_activate ( ) . connect ( [ & ] {
load_state_dialog ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " to_file1 " ) - > signal_activate ( ) . connect ( [ & ] {
save_state_dialog ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " load_state_undo " ) - > signal_activate ( ) . connect ( [ & ] {
S9xUnfreezeGame ( S9xGetFilename ( " .undo " , SNAPSHOT_DIR ) ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " save_spc_item " ) - > signal_activate ( ) . connect ( [ & ] {
save_spc_dialog ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " open_movie_item " ) - > signal_activate ( ) . connect ( [ & ] {
if ( S9xMovieActive ( ) )
S9xMovieStop ( false ) ;
2010-09-25 17:46:12 +02:00
2020-08-06 23:51:52 +02:00
S9xMovieOpen ( open_movie_dialog ( true ) . c_str ( ) , false ) ;
2020-07-05 00:53:38 +02:00
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " stop_recording_item " ) - > signal_activate ( ) . connect ( [ & ] {
if ( S9xMovieActive ( ) )
S9xMovieStop ( false ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " jump_to_frame_item " ) - > signal_activate ( ) . connect ( [ & ] {
movie_seek_dialog ( ) ;
} ) ;
2018-11-08 21:23:37 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " record_movie_item " ) - > signal_activate ( ) . connect ( [ & ] {
if ( S9xMovieActive ( ) )
S9xMovieStop ( false ) ;
2018-11-08 21:23:37 +01:00
2020-08-06 23:51:52 +02:00
S9xMovieCreate ( open_movie_dialog ( false ) . c_str ( ) , 0xFF , MOVIE_OPT_FROM_RESET , nullptr , 0 ) ;
2020-07-05 00:53:38 +02:00
} ) ;
2018-11-08 21:23:37 +01:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " cheats_item " ) - > signal_activate ( ) . connect ( [ & ] {
open_snes9x_cheats_dialog ( ) ;
} ) ;
get_object < Gtk : : MenuItem > ( " preferences_item " ) - > signal_activate ( ) . connect ( [ & ] {
2020-08-23 23:28:01 +02:00
snes9x_preferences_open ( this ) ;
2020-07-05 00:53:38 +02:00
} ) ;
get_object < Gtk : : MenuItem > ( " open_netplay_item " ) - > signal_activate ( ) . connect ( [ & ] {
S9xNetplayDialogOpen ( ) ;
} ) ;
2018-05-23 22:50:57 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " rom_info_item " ) - > signal_activate ( ) . connect ( [ & ] {
show_rom_info ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " sync_clients_item " ) - > signal_activate ( ) . connect ( [ & ] {
S9xNetplaySyncClients ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " hide_ui " ) - > signal_activate ( ) . connect ( [ & ] {
toggle_ui ( ) ;
} ) ;
for ( int i = 1 ; i < = 5 ; i + + )
2010-09-26 11:19:15 +02:00
{
2020-07-05 00:53:38 +02:00
std : : string name = " exact_pixels_ " + std : : to_string ( i ) + " x_item " ;
get_object < Gtk : : MenuItem > ( name . c_str ( ) ) - > signal_activate ( ) . connect ( [ i , this ] {
resize_to_multiple ( i ) ;
} ) ;
2010-09-26 11:19:15 +02:00
}
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( " open_multicart_item " ) - > signal_activate ( ) . connect ( [ & ] {
open_multicart_dialog ( ) ;
} ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : button_press ( GdkEventButton * event )
2010-09-25 17:46:12 +02:00
{
2019-03-22 22:51:48 +01:00
if ( S9xIsMousePluggedIn ( ) )
2010-09-25 17:46:12 +02:00
{
2019-03-22 22:51:48 +01:00
switch ( event - > button )
{
2010-09-25 17:46:12 +02:00
case 1 :
2019-03-22 22:51:48 +01:00
S9xReportButton ( BINDING_MOUSE_BUTTON0 , 1 ) ;
2010-09-25 17:46:12 +02:00
break ;
case 2 :
2019-03-22 22:51:48 +01:00
S9xReportButton ( BINDING_MOUSE_BUTTON2 , 1 ) ;
2010-09-25 17:46:12 +02:00
break ;
case 3 :
2019-03-22 22:51:48 +01:00
S9xReportButton ( BINDING_MOUSE_BUTTON1 , 1 ) ;
2010-09-25 17:46:12 +02:00
break ;
2019-03-22 22:51:48 +01:00
}
}
else if ( event - > button = = 3 )
{
2020-07-05 00:53:38 +02:00
get_object < Gtk : : Menu > ( " view_menu_menu " ) - > popup_at_pointer ( nullptr ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
2018-12-28 23:32:32 +01:00
return false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : button_release ( GdkEventButton * event )
2010-09-25 17:46:12 +02:00
{
switch ( event - > button )
{
case 1 :
2020-07-05 00:53:38 +02:00
S9xReportButton ( BINDING_MOUSE_BUTTON0 , 0 ) ;
2010-09-25 17:46:12 +02:00
break ;
case 2 :
2020-07-05 00:53:38 +02:00
S9xReportButton ( BINDING_MOUSE_BUTTON1 , 0 ) ;
2010-09-25 17:46:12 +02:00
break ;
case 3 :
2020-07-05 00:53:38 +02:00
S9xReportButton ( BINDING_MOUSE_BUTTON2 , 0 ) ;
2010-09-25 17:46:12 +02:00
break ;
}
2018-12-28 23:32:32 +01:00
return false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : motion_notify ( GdkEventMotion * event )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
if ( ! config - > rom_loaded | | last_width < = 0 | | last_height < = 0 )
return false ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( mouse_grabbed )
{
if ( event - > x_root = = gdk_mouse_x & & event - > y_root = = gdk_mouse_y )
return false ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
snes_mouse_x + = ( event - > x_root - gdk_mouse_x ) ;
snes_mouse_y + = ( event - > y_root - gdk_mouse_y ) ;
center_mouse ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
return false ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
int scale_factor = window - > get_scale_factor ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
snes_mouse_x = ( uint16 ) ( ( int ) ( event - > x * scale_factor ) - mouse_region_x ) * 256 /
( mouse_region_width < = 0 ? 1 : mouse_region_width ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
snes_mouse_y = ( uint16 ) ( ( int ) ( event - > y * scale_factor ) - mouse_region_y ) * ( gui_config - > overscan ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT ) /
( mouse_region_height < = 0 ? 1 : mouse_region_height ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( ! config - > pointer_is_visible )
{
if ( ! S9xIsMousePluggedIn ( ) )
show_mouse_cursor ( ) ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
config - > pointer_timestamp = g_get_monotonic_time ( ) ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
return false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : port_activate ( const char * name )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
auto item = get_object < Gtk : : CheckMenuItem > ( name ) ;
if ( ! item - > get_active ( ) )
2010-09-25 17:46:12 +02:00
return ;
2020-07-05 00:53:38 +02:00
if ( ! strcasecmp ( name , " joypad1 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 0 , CTL_JOYPAD , 0 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " joypad2 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 1 , CTL_JOYPAD , 1 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " mouse1 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 0 , CTL_MOUSE , 0 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " mouse2 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 1 , CTL_MOUSE , 0 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " superscope1 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 0 , CTL_SUPERSCOPE , 0 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " superscope2 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 1 , CTL_SUPERSCOPE , 0 , 0 , 0 , 0 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " multitap1 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 0 , CTL_MP5 , 0 , 1 , 2 , 3 ) ;
2018-10-03 23:58:40 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " multitap2 " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 1 , CTL_MP5 , 1 , 2 , 3 , 4 ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
else if ( ! strcasecmp ( name , " nothingpluggedin2 " ) )
2018-12-12 23:40:31 +01:00
{
2020-07-05 00:53:38 +02:00
S9xSetController ( 1 , CTL_NONE , 0 , 0 , 0 , 0 ) ;
2018-12-12 23:40:31 +01:00
}
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : event_key ( GdkEventKey * event )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
Binding b ;
s9xcommand_t cmd ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
// Ignore multiple identical keypresses to discard repeating keys
if ( event - > keyval = = last_key_pressed_keyval & & event - > type = = last_key_pressed_type )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
return true ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
// Provide escape key to get out of fullscreen
if ( event - > keyval = = GDK_Escape )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
if ( event - > type = = GDK_KEY_RELEASE )
2017-09-12 02:32:10 +02:00
{
2020-07-05 00:53:38 +02:00
if ( config - > default_esc_behavior = = ESC_EXIT_FULLSCREEN )
leave_fullscreen_mode ( ) ;
else if ( config - > default_esc_behavior = = ESC_EXIT_SNES9X )
S9xExit ( ) ;
else
toggle_ui ( ) ;
2017-09-12 02:32:10 +02:00
}
2018-11-07 01:04:10 +01:00
2020-07-05 00:53:38 +02:00
return true ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
last_key_pressed_keyval = event - > keyval ;
last_key_pressed_type = event - > type ;
2018-05-24 19:18:59 +02:00
2020-07-05 00:53:38 +02:00
b = Binding ( event ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
// If no mapping for modifier version exists, try non-modifier
cmd = S9xGetMapping ( b . hex ( ) ) ;
if ( cmd . type = = S9xNoMapping )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
b = Binding ( event - > keyval , false , false , false ) ;
cmd = S9xGetMapping ( b . hex ( ) ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
if ( cmd . type ! = S9xNoMapping )
{
S9xReportButton ( b . hex ( ) , ( event - > type = = GDK_KEY_PRESS ) ) ;
return true ;
}
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
return false ; // Pass the key to GTK
2010-09-25 17:46:12 +02:00
}
2019-03-21 22:37:00 +01:00
extern int gtk_splash_smtpe_size ;
extern unsigned char gtk_splash_smtpe [ ] ;
2019-03-25 22:16:08 +01:00
extern int gtk_splash_combo_size ;
extern unsigned char gtk_splash_combo [ ] ;
2019-03-21 22:37:00 +01:00
extern int gtk_splash_pattern_size ;
extern unsigned char gtk_splash_pattern [ ] ;
void Snes9xWindow : : setup_splash ( )
{
uint16 * screen_ptr = GFX . Screen ;
2020-07-05 00:53:38 +02:00
// Load splash image (RGB24) into Snes9x buffer (RGB15)
2019-03-21 22:37:00 +01:00
last_width = 256 ;
last_height = 224 ;
if ( config - > splash_image = = SPLASH_IMAGE_PATTERN | |
2019-03-25 22:16:08 +01:00
config - > splash_image = = SPLASH_IMAGE_SMTPE | |
config - > splash_image = = SPLASH_IMAGE_COMBO ) {
2020-07-05 00:53:38 +02:00
unsigned char * pattern = nullptr ;
2019-03-21 22:37:00 +01:00
int pattern_size = 0 ;
if ( config - > splash_image = = SPLASH_IMAGE_PATTERN ) {
pattern = gtk_splash_pattern ;
pattern_size = gtk_splash_pattern_size ;
2019-03-25 22:16:08 +01:00
} else if ( config - > splash_image = = SPLASH_IMAGE_SMTPE ) {
2019-03-21 22:37:00 +01:00
pattern = gtk_splash_smtpe ;
pattern_size = gtk_splash_smtpe_size ;
2019-03-25 22:16:08 +01:00
} else {
pattern = gtk_splash_combo ;
pattern_size = gtk_splash_combo_size ;
2019-03-21 22:37:00 +01:00
}
2015-08-16 12:36:56 +02:00
2020-07-05 00:53:38 +02:00
auto pixbuf_loader = gdk_pixbuf_loader_new_with_type ( " png " , nullptr ) ;
gdk_pixbuf_loader_write ( pixbuf_loader , pattern , pattern_size , nullptr ) ;
gdk_pixbuf_loader_close ( pixbuf_loader , nullptr ) ;
2019-03-21 22:37:00 +01:00
auto pixbuf = gdk_pixbuf_loader_get_pixbuf ( pixbuf_loader ) ;
const unsigned char * splash_ptr = gdk_pixbuf_get_pixels ( pixbuf ) ;
const int channels = gdk_pixbuf_get_n_channels ( pixbuf ) ;
for ( int y = 0 ; y < 224 ; y + + , screen_ptr + = ( GFX . Pitch / 2 ) ) {
for ( int x = 0 ; x < 256 ; x + + ) {
unsigned int red = splash_ptr [ 0 ] ;
unsigned int green = splash_ptr [ 1 ] ;
unsigned int blue = splash_ptr [ 2 ] ;
screen_ptr [ x ] = ( ( red & 0xF8 ) < < 8 ) +
( ( green & 0xF8 ) < < 3 ) +
( ( green & 0x80 ) > > 2 ) +
( ( blue & 0xF8 ) > > 3 ) ;
splash_ptr + = channels ;
}
2010-09-26 11:19:15 +02:00
}
2019-03-21 22:37:00 +01:00
g_object_unref ( pixbuf_loader ) ;
2015-08-16 12:36:56 +02:00
2019-03-21 22:37:00 +01:00
return ;
}
2015-08-16 12:36:56 +02:00
2019-03-21 22:37:00 +01:00
if ( config - > splash_image = = SPLASH_IMAGE_BLUE ) {
for ( int y = 0 ; y < 224 ; y + + , screen_ptr + = ( GFX . Pitch / 2 ) ) {
uint16 colora = ( uint16 ) y / 7 ;
uint16 colorb = ( ( uint16 ) y - 3 ) / 7 ;
if ( colorb > 32 )
colorb = 0 ;
2015-08-16 12:36:56 +02:00
2019-03-21 22:37:00 +01:00
for ( int x = 0 ; x < 256 ; x + + ) {
screen_ptr [ x ] = ( ( x ^ y ) & 1 ) ? colorb : colora ;
2015-08-16 12:36:56 +02:00
}
}
2019-03-21 22:37:00 +01:00
return ;
}
for ( int y = 0 ; y < 224 ; y + + , screen_ptr + = ( GFX . Pitch / 2 ) ) {
memset ( screen_ptr , 0 , 256 * sizeof ( uint16 ) ) ;
}
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : draw ( const Cairo : : RefPtr < Cairo : : Context > & cr )
2019-03-21 22:37:00 +01:00
{
2020-07-05 00:53:38 +02:00
this - > cr = cr - > cobj ( ) ;
cairo_owned = false ;
2019-03-22 22:51:48 +01:00
if ( ! ( config - > fullscreen ) & & ! ( maximized_state ) )
2019-03-21 22:37:00 +01:00
{
config - > window_width = get_width ( ) ;
config - > window_height = get_height ( ) ;
}
if ( last_width < 0 )
{
setup_splash ( ) ;
}
2015-08-16 12:36:56 +02:00
2020-07-05 00:53:38 +02:00
S9xDisplayRefresh ( last_width , last_height ) ;
2010-09-26 11:19:15 +02:00
2016-10-02 02:23:21 +02:00
if ( ! ( config - > fullscreen ) )
{
2020-07-05 00:53:38 +02:00
config - > window_width = get_width ( ) ;
config - > window_height = get_height ( ) ;
2016-10-02 02:23:21 +02:00
}
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
if ( ( is_paused ( ) | | NetPlay . Paused ) & & ( gui_config - > splash_image < SPLASH_IMAGE_STARFIELD | | gui_config - > rom_loaded ) )
2018-10-29 22:02:45 +01:00
{
2020-07-05 00:53:38 +02:00
S9xDeinitUpdate ( last_width , last_height ) ;
2018-10-29 22:02:45 +01:00
}
2020-07-05 00:53:38 +02:00
this - > cr = nullptr ;
return true ;
2010-09-26 11:19:15 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : focus_notify ( bool state )
2010-09-25 17:46:12 +02:00
{
2018-12-28 23:32:32 +01:00
focused = state ;
2010-09-25 17:46:12 +02:00
if ( ! state & & config - > pause_emulation_on_switch )
{
sys_pause + + ;
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2018-12-28 23:32:32 +01:00
paused_from_focus_loss = true ;
2010-09-25 17:46:12 +02:00
}
if ( state & & paused_from_focus_loss )
{
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
2018-12-28 23:32:32 +01:00
paused_from_focus_loss = false ;
2010-09-25 17:46:12 +02:00
}
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : open_multicart_dialog ( )
2010-09-25 17:46:12 +02:00
{
int result ;
2020-07-05 00:53:38 +02:00
GtkBuilderWindow dialog_builder ( " multicart_dialog " ) ;
auto dialog = Glib : : RefPtr < Gtk : : Dialog > : : cast_static ( dialog_builder . window ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
dialog - > set_transient_for ( * window . get ( ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto slota = get_object < Gtk : : FileChooserDialog > ( " multicart_slota " ) ;
auto slotb = get_object < Gtk : : FileChooserDialog > ( " multicart_slotb " ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
slota - > set_current_folder ( config - > last_directory ) ;
slotb - > set_current_folder ( config - > last_directory ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
result = dialog - > run ( ) ;
dialog - > hide ( ) ;
2010-09-25 17:46:12 +02:00
if ( result = = GTK_RESPONSE_OK )
{
2020-07-05 00:53:38 +02:00
auto filename = slota - > get_filename ( ) ;
if ( ! filename . empty ( ) )
strncpy ( Settings . CartAName , filename . c_str ( ) , PATH_MAX ) ;
2010-09-25 17:46:12 +02:00
else
Settings . CartAName [ 0 ] = ' \0 ' ;
2020-07-05 00:53:38 +02:00
filename = slotb - > get_filename ( ) ;
if ( ! filename . empty ( ) )
strncpy ( Settings . CartBName , filename . c_str ( ) , PATH_MAX ) ;
2010-09-25 17:46:12 +02:00
else
Settings . CartBName [ 0 ] = ' \0 ' ;
2018-12-28 23:32:32 +01:00
Settings . Multi = true ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( S9xOpenROM ( nullptr ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
auto msg = Gtk : : MessageDialog ( * window . get ( ) ,
_ ( " Couldn't load files. " ) ,
false ,
Gtk : : MESSAGE_ERROR ,
Gtk : : BUTTONS_CLOSE ,
true ) ;
msg . run ( ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
std : : string Snes9xWindow : : open_movie_dialog ( bool readonly )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
this - > pause_from_focus_change ( ) ;
std : : string title ;
Gtk : : FileChooserAction action ;
2010-09-25 17:46:12 +02:00
if ( readonly )
{
2020-07-05 00:53:38 +02:00
title = _ ( " Open SNES Movie " ) ;
action = Gtk : : FILE_CHOOSER_ACTION_OPEN ;
2010-09-25 17:46:12 +02:00
}
else
{
2020-07-05 00:53:38 +02:00
title = _ ( " New SNES Movie " ) ;
action = Gtk : : FILE_CHOOSER_ACTION_SAVE ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
Gtk : : FileChooserDialog dialog ( * window . get ( ) , title , action ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-cancel " ) , Gtk : : RESPONSE_CANCEL ) ;
if ( readonly )
dialog . add_button ( Gtk : : StockID ( " gtk-open " ) , Gtk : : RESPONSE_ACCEPT ) ;
else
dialog . add_button ( Gtk : : StockID ( " gtk-save " ) , Gtk : : RESPONSE_ACCEPT ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( ! readonly )
{
const char * default_name = S9xGetFilename ( " .smv " , s9x_getdirtype : : ROM_DIR ) ;
dialog . set_current_name ( default_name ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
auto filter = Gtk : : FileFilter : : create ( ) ;
filter - > set_name ( _ ( " SNES Movies " ) ) ;
filter - > add_pattern ( " *.smv " ) ;
filter - > add_pattern ( " *.SMV " ) ;
dialog . add_filter ( filter ) ;
dialog . add_filter ( get_all_files_filter ( ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
dialog . set_current_folder ( S9xGetDirectory ( SRAM_DIR ) ) ;
auto result = dialog . run ( ) ;
dialog . hide ( ) ;
this - > unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( result = = Gtk : : RESPONSE_ACCEPT )
return dialog . get_filename ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
return std : : string { } ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
std : : string Snes9xWindow : : open_rom_dialog ( bool run )
{
const char * extensions [ ] = {
" *.smc " , " *.SMC " , " *.fig " , " *.FIG " , " *.sfc " , " *.SFC " ,
" *.jma " , " *.JMA " , " *.zip " , " *.ZIP " , " *.gd3 " , " *.GD3 " ,
" *.swc " , " *.SWC " , " *.gz " , " *.GZ " , " *.bs " , " *.BS " ,
NULL
} ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto dialog = Gtk : : FileChooserDialog ( * top_level - > window . get ( ) ,
_ ( " Open SNES ROM Image " ) ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-cancel " ) , Gtk : : RESPONSE_CANCEL ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-open " ) , Gtk : : RESPONSE_ACCEPT ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto filter = Gtk : : FileFilter : : create ( ) ;
filter - > set_name ( _ ( " SNES ROM Images " ) ) ;
for ( int i = 0 ; extensions [ i ] ; i + + )
filter - > add_pattern ( extensions [ i ] ) ;
dialog . add_filter ( filter ) ;
dialog . add_filter ( get_all_files_filter ( ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( ! gui_config - > last_directory . empty ( ) )
dialog . set_current_folder ( config - > last_directory ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto result = dialog . run ( ) ;
dialog . hide ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
std : : string filename ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( result = = Gtk : : RESPONSE_ACCEPT )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
std : : string directory = dialog . get_current_folder ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( ! directory . empty ( ) )
gui_config - > last_directory = directory ;
filename = dialog . get_filename ( ) ;
if ( ! filename . empty ( ) )
{
if ( run )
{
Settings . Multi = false ;
try_open_rom ( filename ) ;
}
}
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
return filename ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
bool Snes9xWindow : : try_open_rom ( std : : string filename )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
Settings . Multi = false ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( S9xOpenROM ( filename . c_str ( ) ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
std : : string message = _ ( " Couldn't load file: " ) + filename ;
Gtk : : MessageDialog msg ( * window . get ( ) , message , false , Gtk : : MESSAGE_ERROR , Gtk : : BUTTONS_CLOSE , true ) ;
msg . run ( ) ;
unpause_from_focus_change ( ) ;
2018-12-28 23:32:32 +01:00
return false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
Gtk : : RecentManager : : Data data ;
data . description = " SNES ROM " ;
data . mime_type = " application/x-snes-rom " ;
data . app_name = " Snes9x " ;
data . groups = { " cartridge " } ;
data . is_private = false ;
data . app_exec = Glib : : get_prgname ( ) + " %f " ;
2020-07-31 01:24:54 +02:00
auto uri = Glib : : filename_to_uri ( filename ) ;
Gtk : : RecentManager : : get_default ( ) - > add_item ( uri , data ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
unpause_from_user ( ) ;
unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
return true ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : load_state_dialog ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
this - > pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
Gtk : : FileChooserDialog dialog ( * window . get ( ) , _ ( " Load Saved State " ) ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-cancel " ) , Gtk : : RESPONSE_CANCEL ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-open " ) , Gtk : : RESPONSE_ACCEPT ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
dialog . add_filter ( get_save_states_file_filter ( ) ) ;
dialog . add_filter ( get_all_files_filter ( ) ) ;
dialog . set_current_folder ( S9xGetDirectory ( SNAPSHOT_DIR ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto result = dialog . run ( ) ;
dialog . hide ( ) ;
if ( result = = Gtk : : RESPONSE_ACCEPT )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xLoadState ( dialog . get_filename ( ) . c_str ( ) ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : movie_seek_dialog ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
char str [ 1024 ] ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( ! S9xMovieActive ( ) )
2010-09-25 17:46:12 +02:00
return ;
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
GtkBuilderWindow seek_dialog ( " frame_advance_dialog " ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
snprintf ( str , 1024 , _ ( " The current frame in the movie is <b>%d</b>. " ) , S9xMovieGetFrameCounter ( ) ) ;
seek_dialog . get_object < Gtk : : Label > ( " current_frame_label " ) - > set_label ( str ) ;
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
snprintf ( str , 1024 , " %d " , S9xMovieGetFrameCounter ( ) ) ;
seek_dialog . set_entry_text ( " frame_entry " , str ) ;
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
auto dialog = Glib : : RefPtr < Gtk : : Dialog > : : cast_static ( seek_dialog . window ) ;
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
dialog - > set_transient_for ( * window . get ( ) ) ;
auto result = dialog - > run ( ) ;
2010-09-26 11:19:15 +02:00
2020-07-05 00:53:38 +02:00
int entry_value = seek_dialog . get_entry_value ( " frame_entry " ) ;
2010-09-25 17:46:12 +02:00
switch ( result )
{
2020-07-05 00:53:38 +02:00
case Gtk : : RESPONSE_OK :
if ( entry_value > 0 & &
entry_value > ( int ) S9xMovieGetFrameCounter ( ) )
{
Settings . HighSpeedSeek =
entry_value - S9xMovieGetFrameCounter ( ) ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
break ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : save_state_dialog ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto dialog = Gtk : : FileChooserDialog ( * window . get ( ) , _ ( " Save State " ) , Gtk : : FILE_CHOOSER_ACTION_SAVE ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-cancel " ) , Gtk : : RESPONSE_CANCEL ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-save " ) , Gtk : : RESPONSE_ACCEPT ) ;
dialog . set_current_folder ( S9xGetDirectory ( SNAPSHOT_DIR ) ) ;
dialog . set_current_name ( S9xGetFilename ( " .sst " , SNAPSHOT_DIR ) ) ;
dialog . add_filter ( get_save_states_file_filter ( ) ) ;
dialog . add_filter ( get_all_files_filter ( ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto result = dialog . run ( ) ;
dialog . hide ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( result = = GTK_RESPONSE_ACCEPT )
S9xSaveState ( dialog . get_filename ( ) . c_str ( ) ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : save_spc_dialog ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
pause_from_focus_change ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto dialog = Gtk : : FileChooserDialog ( * window . get ( ) , _ ( " Save SPC file... " ) , Gtk : : FILE_CHOOSER_ACTION_SAVE ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-cancel " ) , Gtk : : RESPONSE_CANCEL ) ;
dialog . add_button ( Gtk : : StockID ( " gtk-save " ) , Gtk : : RESPONSE_ACCEPT ) ;
dialog . set_current_folder ( S9xGetDirectory ( SNAPSHOT_DIR ) ) ;
dialog . set_current_name ( S9xGetFilename ( " .spc " , SNAPSHOT_DIR ) ) ;
auto filter = Gtk : : FileFilter : : create ( ) ;
filter - > add_pattern ( " *.spc " ) ;
filter - > add_pattern ( " *.SPC " ) ;
dialog . add_filter ( filter ) ;
dialog . add_filter ( get_all_files_filter ( ) ) ;
auto result = dialog . run ( ) ;
dialog . hide ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
if ( result = = Gtk : : RESPONSE_ACCEPT )
{
if ( S9xSPCDump ( dialog . get_filename ( ) . c_str ( ) ) )
2010-09-25 17:46:12 +02:00
{
/* Success ? */
}
else
{
2020-07-05 00:53:38 +02:00
std : : string message = _ ( " Couldn't save SPC file: " ) ;
message + = " " + dialog . get_filename ( ) ;
Gtk : : MessageDialog ( * window . get ( ) , message , false , Gtk : : MESSAGE_ERROR , Gtk : : BUTTONS_CLOSE , true ) . run ( ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-07-05 00:53:38 +02:00
unpause_from_focus_change ( ) ;
}
void Snes9xWindow : : set_menu_item_selected ( const char * name )
{
get_object < Gtk : : CheckMenuItem > ( name ) - > set_active ( true ) ;
}
void Snes9xWindow : : show_rom_info ( )
{
const char * markup = _ ( R " (<b>Information for %s</b>
< i > Name : < / i > % s
< i > Speed : < / i > % 02 X / % s
< i > Map : < / i > % s
< i > Type : < / i > % 02 x
< i > Contents : < / i > % s
< i > ROM Size : < / i > % s
< i > Calculated Size : < / i > % d
< i > SRAM Size : < / i > % s
< i > Header Checksum : < / i > % 04 X
< i > Checksum Compliment : < / i > % 04 X
< i > Actual Checksum : < / i > % 04 X
< i > Video : < / i > % s
< i > CRC32 : < / i > % 08 X
< i > Revision : < / i > % s
< b > < i > % s % s < / i > < / b > ) " );
char output [ 2048 ] ;
snprintf ( output , 2048 , markup ,
Memory . ROMFilename ,
Memory . ROMName ,
Memory . ROMSpeed ,
( ( Memory . ROMSpeed & 0x10 ) ! = 0 ) ? " FastROM " : " SlowROM " ,
( Memory . HiROM ) ? " HiROM " : " LoROM " ,
Memory . ROMType ,
Memory . KartContents ( ) ,
Memory . Size ( ) ,
Memory . CalculatedSize / 0x20000 ,
Memory . StaticRAMSize ( ) ,
Memory . ROMChecksum ,
Memory . ROMComplementChecksum ,
Memory . CalculatedChecksum ,
( Memory . ROMRegion > 12 | | Memory . ROMRegion < 2 ) ? " NTSC 60Hz " : " PAL 50Hz " ,
Memory . ROMCRC32 ,
Memory . Revision ( ) ,
( Settings . IsPatched ) ? _ ( " \n \n This ROM has been auto-patched with " ) : ( Memory . ROMChecksum ! = Memory . CalculatedChecksum ) ? _ ( " \n \n This ROM has been modified or damaged " ) : " " ,
Settings . IsPatched = = 1 ? " IPS " : Settings . IsPatched = = 2 ? " BPS " : Settings . IsPatched = = 3 ? " UPS " : " " ) ;
pause_from_focus_change ( ) ;
auto dialog = Gtk : : MessageDialog ( * window . get ( ) , output , true , Gtk : : MESSAGE_OTHER , Gtk : : BUTTONS_CLOSE , true ) ;
dialog . set_title ( _ ( " File Information " ) ) ;
dialog . run ( ) ;
unpause_from_focus_change ( ) ;
}
void Snes9xWindow : : configure_widgets ( )
{
enable_widget ( " continue_item " , config - > rom_loaded ) ;
enable_widget ( " pause_item " , config - > rom_loaded ) ;
enable_widget ( " reset_item " , config - > rom_loaded ) ;
enable_widget ( " load_state_item " , config - > rom_loaded ) ;
enable_widget ( " save_state_item " , config - > rom_loaded ) ;
enable_widget ( " save_spc_item " , config - > rom_loaded ) ;
enable_widget ( " hard_reset_item " , config - > rom_loaded ) ;
enable_widget ( " record_movie_item " , config - > rom_loaded ) ;
enable_widget ( " stop_recording_item " , config - > rom_loaded ) ;
enable_widget ( " open_movie_item " , config - > rom_loaded ) ;
enable_widget ( " jump_to_frame_item " , config - > rom_loaded ) ;
enable_widget ( " cheats_item " , config - > rom_loaded ) ;
enable_widget ( " rom_info_item " , config - > rom_loaded ) ;
enable_widget ( " sync_clients_item " ,
config - > rom_loaded & &
Settings . NetPlay & &
Settings . NetPlayServer ) ;
2010-09-25 17:46:12 +02:00
if ( config - > default_esc_behavior ! = ESC_TOGGLE_MENUBAR )
{
2020-07-05 00:53:38 +02:00
enable_widget ( " fullscreen_item " , config - > rom_loaded ) ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
config - > ui_visible = true ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
show_widget ( " menubar " , ! config - > fullscreen ) ;
show_widget ( " hide_ui " , false ) ;
show_widget ( " hide_ui_separator " , false ) ;
2010-09-25 17:46:12 +02:00
}
else
{
2020-07-05 00:53:38 +02:00
enable_widget ( " fullscreen_item " , true ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
show_widget ( " hide_ui " , true ) ;
show_widget ( " hide_ui_separator " , true ) ;
show_widget ( " menubar " , config - > ui_visible ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2010-09-26 11:19:15 +02:00
if ( config - > rom_loaded & & ! Settings . Paused )
2020-07-05 00:53:38 +02:00
hide_mouse_cursor ( ) ;
2010-09-25 17:46:12 +02:00
else
2020-07-05 00:53:38 +02:00
show_mouse_cursor ( ) ;
2020-07-31 01:24:54 +02:00
if ( config - > rom_loaded )
{
std : : string title = S9xBasenameNoExt ( Memory . ROMFilename ) ;
title + = " - Snes9x " ;
window - > set_title ( title ) ;
}
else
{
window - > set_title ( " Snes9x " ) ;
}
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : set_mouseable_area ( int x , int y , int width , int height )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
mouse_region_x = x ;
mouse_region_y = y ;
mouse_region_width = width ;
2010-09-25 17:46:12 +02:00
mouse_region_height = height ;
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : reset_screensaver ( )
2010-09-25 17:46:12 +02:00
{
if ( ! focused )
return ;
2020-07-05 00:53:38 +02:00
GdkWindow * gdk_window = window - > get_window ( ) - > gobj ( ) ;
GdkDisplay * gdk_display = window - > get_display ( ) - > gobj ( ) ;
2018-05-09 23:43:10 +02:00
# ifdef GDK_WINDOWING_X11
2020-07-05 00:53:38 +02:00
if ( GDK_IS_X11_WINDOW ( gdk_window ) )
2018-05-09 23:43:10 +02:00
{
2020-07-05 00:53:38 +02:00
XResetScreenSaver ( GDK_DISPLAY_XDISPLAY ( gdk_display ) ) ;
2018-05-09 23:43:10 +02:00
}
# endif
# ifdef GDK_WINDOWING_WAYLAND
2020-07-05 00:53:38 +02:00
if ( GDK_IS_WAYLAND_WINDOW ( gdk_window ) )
2018-05-09 23:43:10 +02:00
{
2020-07-05 00:53:38 +02:00
// TODO screensaver for wayland
2018-05-09 23:43:10 +02:00
}
# endif
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
config - > screensaver_needs_reset = false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : toggle_fullscreen_mode ( )
2010-09-25 17:46:12 +02:00
{
if ( config - > fullscreen )
2020-07-05 00:53:38 +02:00
leave_fullscreen_mode ( ) ;
2010-09-25 17:46:12 +02:00
else
2020-07-05 00:53:38 +02:00
enter_fullscreen_mode ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
static double XRRGetExactRefreshRate ( Display * dpy , Window window )
2018-05-03 00:43:32 +02:00
{
2020-07-05 00:53:38 +02:00
XRRScreenResources * resources = nullptr ;
XRRCrtcInfo * crtc_info = nullptr ;
2018-05-03 00:43:32 +02:00
int event_base ;
int error_base ;
int version_major ;
int version_minor ;
double refresh_rate = 0.0 ;
int i ;
2020-07-05 00:53:38 +02:00
if ( ! XRRQueryExtension ( dpy , & event_base , & error_base ) | |
! XRRQueryVersion ( dpy , & version_major , & version_minor ) )
2018-05-03 00:43:32 +02:00
{
return refresh_rate ;
}
2018-05-05 00:52:29 +02:00
if ( version_minor < 3 )
return refresh_rate ;
2020-07-05 00:53:38 +02:00
resources = XRRGetScreenResourcesCurrent ( dpy , window ) ;
crtc_info = XRRGetCrtcInfo ( dpy , resources , resources - > crtcs [ 0 ] ) ;
2018-05-03 00:43:32 +02:00
for ( i = 0 ; i < resources - > nmode ; i + + )
{
if ( resources - > modes [ i ] . id = = crtc_info - > mode )
{
XRRModeInfo * m = & resources - > modes [ i ] ;
2020-07-05 00:53:38 +02:00
refresh_rate = ( double ) m - > dotClock / m - > hTotal / m - > vTotal ;
refresh_rate / = m - > modeFlags & RR_DoubleScan ? 2 : 1 ;
2018-05-03 00:43:32 +02:00
refresh_rate / = m - > modeFlags & RR_ClockDivideBy2 ? 2 : 1 ;
2020-07-05 00:53:38 +02:00
refresh_rate * = m - > modeFlags & RR_DoubleClock ? 2 : 1 ;
2018-05-03 00:43:32 +02:00
break ;
}
}
2020-07-05 00:53:38 +02:00
XRRFreeCrtcInfo ( crtc_info ) ;
XRRFreeScreenResources ( resources ) ;
2018-05-03 00:43:32 +02:00
return refresh_rate ;
}
double
2020-07-05 00:53:38 +02:00
Snes9xWindow : : get_refresh_rate ( )
2018-05-03 00:43:32 +02:00
{
2018-05-09 23:29:59 +02:00
double refresh_rate = 0.0 ;
2019-11-14 17:26:30 +01:00
# if defined GDK_WINDOWING_X11 || defined GDK_WINDOWING_WAYLAND
2020-07-05 00:53:38 +02:00
GdkDisplay * gdk_display = window - > get_display ( ) - > gobj ( ) ;
GdkWindow * gdk_window = window - > get_window ( ) - > gobj ( ) ;
2019-11-14 17:26:30 +01:00
# endif
2018-10-15 21:18:21 +02:00
2018-05-09 23:29:59 +02:00
# ifdef GDK_WINDOWING_X11
2020-07-05 00:53:38 +02:00
if ( GDK_IS_X11_DISPLAY ( gdk_display ) )
2018-05-09 23:29:59 +02:00
{
2020-07-05 00:53:38 +02:00
Window xid = gdk_x11_window_get_xid ( gdk_window ) ;
Display * dpy = gdk_x11_display_get_xdisplay ( gdk_display ) ;
refresh_rate = XRRGetExactRefreshRate ( dpy , xid ) ;
2018-10-15 21:18:21 +02:00
}
2018-05-09 23:29:59 +02:00
# endif
2018-10-15 21:18:21 +02:00
2018-05-09 23:29:59 +02:00
# ifdef GDK_WINDOWING_WAYLAND
2020-07-05 00:53:38 +02:00
if ( GDK_IS_WAYLAND_DISPLAY ( gdk_display ) )
2018-05-09 23:29:59 +02:00
{
2020-07-05 00:53:38 +02:00
GdkMonitor * monitor = gdk_display_get_monitor_at_window ( gdk_display , gdk_window ) ;
refresh_rate = ( double ) gdk_monitor_get_refresh_rate ( monitor ) / 1000.0 ;
2018-05-09 23:29:59 +02:00
}
# endif
2018-10-15 21:18:21 +02:00
2018-05-03 00:43:32 +02:00
if ( refresh_rate < 10.0 )
{
2020-07-05 00:53:38 +02:00
printf ( " Warning: Couldn't read refresh rate. \n " ) ;
2018-05-03 00:43:32 +02:00
refresh_rate = 60.0 ;
}
return refresh_rate ;
}
2020-07-05 00:53:38 +02:00
int Snes9xWindow : : get_auto_input_rate ( )
2018-05-03 00:43:32 +02:00
{
2020-07-05 00:53:38 +02:00
double refresh_rate = get_refresh_rate ( ) ;
2018-06-07 16:42:25 +02:00
2018-06-07 22:49:41 +02:00
if ( refresh_rate = = 0.0 )
return 0 ;
// Try for a close multiple of 60hz
if ( refresh_rate > 119.0 & & refresh_rate < 121.0 )
refresh_rate / = 2.0 ;
if ( refresh_rate > 179.0 & & refresh_rate < 181.0 )
refresh_rate / = 3.0 ;
if ( refresh_rate > 239.0 & & refresh_rate < 241.0 )
refresh_rate / = 4.0 ;
2019-04-12 19:10:51 +02:00
double new_input_rate = refresh_rate * 32040.0 / 60.09881389744051 + 0.5 ;
2018-06-07 22:49:41 +02:00
2019-04-12 19:10:51 +02:00
if ( new_input_rate > 32040.0 * 1.05 | | new_input_rate < 32040.0 * 0.95 )
2018-06-07 22:49:41 +02:00
new_input_rate = 0.0 ;
2018-06-07 16:42:25 +02:00
return new_input_rate ;
2018-05-03 00:43:32 +02:00
}
2018-10-15 21:31:42 +02:00
# ifdef GDK_WINDOWING_X11
2020-07-05 00:53:38 +02:00
static void set_bypass_compositor ( Display * dpy , Window window , unsigned char bypass )
2018-04-28 19:49:36 +02:00
{
2018-05-05 01:31:25 +02:00
uint32 value = bypass ;
2020-07-05 00:53:38 +02:00
Atom net_wm_bypass_compositor = XInternAtom ( dpy , " _NET_WM_BYPASS_COMPOSITOR " , False ) ;
XChangeProperty ( dpy , window , net_wm_bypass_compositor , XA_CARDINAL , 32 , PropModeReplace , ( const unsigned char * ) & value , 1 ) ;
2018-04-28 19:49:36 +02:00
}
2018-10-15 21:31:42 +02:00
# endif
2018-04-28 19:49:36 +02:00
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : enter_fullscreen_mode ( )
2010-09-25 17:46:12 +02:00
{
int rom_loaded = config - > rom_loaded ;
if ( config - > fullscreen )
return ;
2020-07-05 00:53:38 +02:00
GdkDisplay * gdk_display = window - > get_display ( ) - > gobj ( ) ;
GdkWindow * gdk_window = window - > get_window ( ) - > gobj ( ) ;
2010-09-25 17:46:12 +02:00
config - > rom_loaded = 0 ;
nfs_width = config - > window_width ;
nfs_height = config - > window_height ;
2020-07-05 00:53:38 +02:00
int nfs_x ;
int nfs_y ;
window - > get_position ( nfs_x , nfs_y ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
# ifdef GDK_WINDOWING_X11
if ( config - > change_display_resolution & & GDK_IS_X11_WINDOW ( gdk_window ) )
{
Display * dpy = gdk_x11_display_get_xdisplay ( gdk_display ) ;
gdk_display_sync ( gdk_display ) ;
if ( XRRSetCrtcConfig ( dpy ,
config - > xrr_screen_resources ,
config - > xrr_screen_resources - > crtcs [ 0 ] ,
CurrentTime ,
config - > xrr_crtc_info - > x ,
config - > xrr_crtc_info - > y ,
config - > xrr_screen_resources - > modes [ config - > xrr_index ] . id ,
config - > xrr_crtc_info - > rotation ,
& config - > xrr_crtc_info - > outputs [ 0 ] ,
1 ) ! = 0 )
2010-09-25 17:46:12 +02:00
{
config - > change_display_resolution = 0 ;
}
2018-05-03 00:43:32 +02:00
if ( gui_config - > auto_input_rate )
{
2020-07-05 00:53:38 +02:00
Settings . SoundInputRate = top_level - > get_auto_input_rate ( ) ;
S9xUpdateDynamicRate ( 1 , 2 ) ;
2018-05-03 00:43:32 +02:00
}
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
# endif
2010-09-25 17:46:12 +02:00
2018-04-29 01:36:40 +02:00
/* Make sure everything is done synchronously */
2020-07-05 00:53:38 +02:00
gdk_display_sync ( gdk_display ) ;
window - > fullscreen ( ) ;
gdk_display_sync ( gdk_display ) ;
window - > present ( ) ;
2018-04-28 19:49:36 +02:00
2018-05-10 18:36:54 +02:00
# ifdef GDK_WINDOWING_X11
2020-07-05 00:53:38 +02:00
if ( GDK_IS_X11_WINDOW ( window - > get_window ( ) - > gobj ( ) ) & &
2019-03-24 18:25:29 +01:00
config - > default_esc_behavior ! = ESC_TOGGLE_MENUBAR )
2018-05-10 18:36:54 +02:00
{
2020-07-05 00:53:38 +02:00
set_bypass_compositor ( gdk_x11_display_get_xdisplay ( gdk_display ) ,
gdk_x11_window_get_xid ( gdk_window ) ,
1 ) ;
2018-05-10 18:36:54 +02:00
}
# endif
2010-09-25 17:46:12 +02:00
config - > fullscreen = 1 ;
config - > rom_loaded = rom_loaded ;
/* If we're running a game, disable ui when entering fullscreen */
if ( ! Settings . Paused & & config - > rom_loaded )
2018-12-28 23:32:32 +01:00
config - > ui_visible = false ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
configure_widgets ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : leave_fullscreen_mode ( )
2010-09-25 17:46:12 +02:00
{
int rom_loaded = config - > rom_loaded ;
if ( ! config - > fullscreen )
return ;
2020-07-05 00:53:38 +02:00
GdkDisplay * gdk_display = window - > get_display ( ) - > gobj ( ) ;
GdkWindow * gdk_window = window - > get_window ( ) - > gobj ( ) ;
2010-09-25 17:46:12 +02:00
config - > rom_loaded = 0 ;
2020-07-05 00:53:38 +02:00
# ifdef GDK_WINDOWING_X11
if ( config - > change_display_resolution & & GDK_IS_X11_WINDOW ( gdk_window ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
Display * dpy = gdk_x11_display_get_xdisplay ( gdk_display ) ;
2018-04-29 01:36:40 +02:00
2018-05-05 00:52:29 +02:00
if ( config - > xrr_index > config - > xrr_screen_resources - > nmode )
2018-04-29 01:36:40 +02:00
config - > xrr_index = 0 ;
2020-07-05 00:53:38 +02:00
gdk_display_sync ( gdk_display ) ;
XRRSetCrtcConfig ( dpy ,
config - > xrr_screen_resources ,
config - > xrr_screen_resources - > crtcs [ 0 ] ,
CurrentTime ,
config - > xrr_crtc_info - > x ,
config - > xrr_crtc_info - > y ,
config - > xrr_crtc_info - > mode ,
config - > xrr_crtc_info - > rotation ,
& config - > xrr_crtc_info - > outputs [ 0 ] ,
1 ) ;
2018-05-03 00:43:32 +02:00
if ( gui_config - > auto_input_rate )
{
2020-07-05 00:53:38 +02:00
Settings . SoundInputRate = top_level - > get_auto_input_rate ( ) ;
S9xUpdateDynamicRate ( 1 , 2 ) ;
2018-05-03 00:43:32 +02:00
}
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
# endif
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
window - > unfullscreen ( ) ;
2010-09-25 17:46:12 +02:00
2018-05-10 18:36:54 +02:00
# ifdef GDK_WINDOWING_X11
2020-07-05 00:53:38 +02:00
if ( GDK_IS_X11_WINDOW ( gdk_window ) )
2018-05-10 18:36:54 +02:00
{
2020-07-05 00:53:38 +02:00
set_bypass_compositor ( gdk_x11_display_get_xdisplay ( gdk_display ) ,
gdk_x11_window_get_xid ( gdk_window ) ,
0 ) ;
2018-05-10 18:36:54 +02:00
}
# endif
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
resize ( nfs_width , nfs_height ) ;
window - > move ( nfs_x , nfs_y ) ;
2010-09-25 17:46:12 +02:00
config - > rom_loaded = rom_loaded ;
config - > fullscreen = 0 ;
2020-07-05 00:53:38 +02:00
configure_widgets ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : resize_viewport ( int width , int height )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
auto menubar = get_object < Gtk : : MenuBar > ( " menubar " ) ;
if ( menubar - > get_visible ( ) )
height + = menubar - > get_height ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
resize ( width , height ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : hide_mouse_cursor ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
auto blank = Gdk : : Cursor : : create ( Gdk : : BLANK_CURSOR ) ;
drawing_area - > get_window ( ) - > set_cursor ( blank ) ;
2018-12-28 23:32:32 +01:00
config - > pointer_is_visible = false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : show_mouse_cursor ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
auto left_ptr = Gdk : : Cursor : : create ( Gdk : : LEFT_PTR ) ;
drawing_area - > get_window ( ) - > set_cursor ( left_ptr ) ;
2018-12-28 23:32:32 +01:00
config - > pointer_is_visible = true ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : center_mouse ( )
2018-11-08 21:23:37 +01:00
{
2020-07-05 00:53:38 +02:00
int x ;
int y ;
2018-11-08 21:23:37 +01:00
2020-07-05 00:53:38 +02:00
window - > get_window ( ) - > get_origin ( x , y ) ;
int w = window - > get_width ( ) ;
int h = window - > get_height ( ) ;
2018-11-08 21:23:37 +01:00
2019-03-02 23:10:00 +01:00
gdk_mouse_x = x + w / 2 ;
gdk_mouse_y = y + h / 2 ;
2018-11-08 21:23:37 +01:00
2020-07-05 00:53:38 +02:00
window - > get_display ( ) - > get_default_seat ( ) - > get_pointer ( ) - > warp ( window - > get_screen ( ) , gdk_mouse_x , gdk_mouse_y ) ;
2018-11-08 21:23:37 +01:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : toggle_grab_mouse ( )
2018-11-08 21:23:37 +01:00
{
2020-07-05 00:53:38 +02:00
if ( ( ! mouse_grabbed & & ! S9xIsMousePluggedIn ( ) ) | | ! config - > rom_loaded )
2018-11-08 21:23:37 +01:00
return ;
2020-07-05 00:53:38 +02:00
auto seat = window - > get_display ( ) - > get_default_seat ( ) ;
2018-11-08 21:23:37 +01:00
if ( ! mouse_grabbed )
2020-07-05 00:53:38 +02:00
seat - > grab ( window - > get_window ( ) , Gdk : : SEAT_CAPABILITY_ALL_POINTING , true , Gdk : : Cursor : : create ( Gdk : : BLANK_CURSOR ) ) ;
2018-11-08 21:23:37 +01:00
else
2020-07-05 00:53:38 +02:00
seat - > ungrab ( ) ;
2018-11-08 21:23:37 +01:00
2020-07-05 00:53:38 +02:00
S9xReportPointer ( BINDING_MOUSE_POINTER , 0 , 0 ) ;
snes_mouse_x = 0.0 ;
snes_mouse_y = 0.0 ;
2018-12-28 23:32:32 +01:00
mouse_grabbed = ! mouse_grabbed ;
2018-11-08 21:23:37 +01:00
if ( mouse_grabbed )
2020-07-05 00:53:38 +02:00
center_mouse ( ) ;
2018-11-08 21:23:37 +01:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : show ( )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
window - > show ( ) ;
configure_widgets ( ) ;
2010-09-25 17:46:12 +02:00
if ( ! recent_menu )
{
2020-07-05 00:53:38 +02:00
auto manager = Gtk : : RecentManager : : get_default ( ) ;
recent_menu = new Gtk : : RecentChooserMenu ( manager ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
auto filter = Gtk : : RecentFilter : : create ( ) ;
filter - > add_group ( " cartridge " ) ;
recent_menu - > add_filter ( filter ) ;
recent_menu - > set_local_only ( ) ;
recent_menu - > set_show_icons ( false ) ;
recent_menu - > set_sort_type ( Gtk : : RECENT_SORT_MRU ) ;
get_object < Gtk : : MenuItem > ( " open_recent_item " ) - > set_submenu ( * recent_menu ) ;
recent_menu - > signal_item_activated ( ) . connect ( [ & ] {
try_open_rom ( Glib : : filename_from_uri ( recent_menu - > get_current_uri ( ) ) . c_str ( ) ) ;
} ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
recent_menu - > show ( ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : propagate_pause_state ( )
2010-09-25 17:46:12 +02:00
{
int oldpause = Settings . Paused ;
Settings . Paused = ( sys_pause | | user_pause | | ! ( config - > rom_loaded ) ) ;
if ( Settings . Paused ! = oldpause )
{
2020-07-05 00:53:38 +02:00
if ( ! is_paused ( ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
S9xSoundStart ( ) ;
2010-09-25 17:46:12 +02:00
if ( config - > rom_loaded )
2020-07-05 00:53:38 +02:00
enable_widget ( " pause_item " , true ) ;
2010-09-25 17:46:12 +02:00
}
else
{
2020-07-05 00:53:38 +02:00
S9xSoundStop ( ) ;
enable_widget ( " pause_item " , false ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
configure_widgets ( ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : toggle_ui ( )
2010-09-25 17:46:12 +02:00
{
config - > ui_visible = ! config - > ui_visible ;
2020-07-05 00:53:38 +02:00
configure_widgets ( ) ;
2010-09-25 17:46:12 +02:00
}
/* gui_[un]pause Handles when system needs to pause the emulator */
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : pause_from_focus_change ( )
2010-09-25 17:46:12 +02:00
{
2010-10-30 16:21:26 +02:00
sys_pause + = config - > modal_dialogs ;
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : unpause_from_focus_change ( )
2010-09-25 17:46:12 +02:00
{
2010-10-30 16:21:26 +02:00
if ( - - sys_pause < 0 )
sys_pause = 0 ;
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2010-09-25 17:46:12 +02:00
}
/* client_[un]pause Handles when user manually chooses to pause */
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : pause_from_user ( )
2010-09-25 17:46:12 +02:00
{
2018-12-28 23:32:32 +01:00
user_pause = true ;
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : unpause_from_user ( )
2010-09-25 17:46:12 +02:00
{
2018-12-28 23:32:32 +01:00
user_pause = false ;
2020-07-05 00:53:38 +02:00
propagate_pause_state ( ) ;
2010-09-25 17:46:12 +02:00
}
2018-12-28 23:32:32 +01:00
bool Snes9xWindow : : is_paused ( )
2010-09-25 17:46:12 +02:00
{
if ( user_pause | | sys_pause | | Settings . Paused | | ! ( config - > rom_loaded ) )
2018-12-28 23:32:32 +01:00
return true ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
return false ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : set_accelerator_to_binding ( const char * name , const char * binding )
2010-09-25 17:46:12 +02:00
{
Binding bin ;
2020-07-05 00:53:38 +02:00
if ( ! strcmp ( binding , " Escape Key " ) )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
bin = Binding ( GDK_Escape , false , false , false ) ;
2010-09-25 17:46:12 +02:00
}
else
{
2020-07-05 00:53:38 +02:00
bin = S9xGetBindingByName ( binding ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
if ( ! ( bin . is_key ( ) ) )
2010-09-25 17:46:12 +02:00
return ;
2020-07-05 00:53:38 +02:00
AcceleratorEntry entry { } ;
entry . name = name ;
entry . key = bin . get_key ( ) ;
entry . modifiers = bin . get_gdk_modifiers ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( name ) - > add_accelerator ( " activate " , accel_group , entry . key , entry . modifiers , Gtk : : ACCEL_VISIBLE ) ;
accelerators . push_back ( entry ) ;
}
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : update_accelerators ( )
{
if ( ! accel_group )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
accel_group = Gtk : : AccelGroup : : create ( ) ;
window - > add_accel_group ( accel_group ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
for ( auto & entry : accelerators )
2010-09-25 17:46:12 +02:00
{
2020-07-05 00:53:38 +02:00
get_object < Gtk : : MenuItem > ( entry . name . c_str ( ) ) - > remove_accelerator ( accel_group , entry . key , entry . modifiers ) ;
2010-09-25 17:46:12 +02:00
}
2020-07-05 00:53:38 +02:00
accelerators . clear ( ) ;
2010-09-25 17:46:12 +02:00
2020-07-05 00:53:38 +02:00
set_accelerator_to_binding ( " fullscreen_item " , " GTK_fullscreen " ) ;
set_accelerator_to_binding ( " reset_item " , " SoftReset " ) ;
set_accelerator_to_binding ( " save_state_0 " , " QuickSave000 " ) ;
set_accelerator_to_binding ( " save_state_1 " , " QuickSave001 " ) ;
set_accelerator_to_binding ( " save_state_2 " , " QuickSave002 " ) ;
set_accelerator_to_binding ( " save_state_3 " , " QuickSave003 " ) ;
set_accelerator_to_binding ( " save_state_4 " , " QuickSave004 " ) ;
set_accelerator_to_binding ( " save_state_5 " , " QuickSave005 " ) ;
set_accelerator_to_binding ( " save_state_6 " , " QuickSave006 " ) ;
set_accelerator_to_binding ( " save_state_7 " , " QuickSave007 " ) ;
set_accelerator_to_binding ( " save_state_8 " , " QuickSave008 " ) ;
set_accelerator_to_binding ( " save_state_9 " , " QuickSave009 " ) ;
set_accelerator_to_binding ( " load_state_0 " , " QuickLoad000 " ) ;
set_accelerator_to_binding ( " load_state_1 " , " QuickLoad001 " ) ;
set_accelerator_to_binding ( " load_state_2 " , " QuickLoad002 " ) ;
set_accelerator_to_binding ( " load_state_3 " , " QuickLoad003 " ) ;
set_accelerator_to_binding ( " load_state_4 " , " QuickLoad004 " ) ;
set_accelerator_to_binding ( " load_state_5 " , " QuickLoad005 " ) ;
set_accelerator_to_binding ( " load_state_6 " , " QuickLoad006 " ) ;
set_accelerator_to_binding ( " load_state_7 " , " QuickLoad007 " ) ;
set_accelerator_to_binding ( " load_state_8 " , " QuickLoad008 " ) ;
set_accelerator_to_binding ( " load_state_9 " , " QuickLoad009 " ) ;
set_accelerator_to_binding ( " pause_item " , " GTK_pause " ) ;
set_accelerator_to_binding ( " save_spc_item " , " GTK_save_spc " ) ;
set_accelerator_to_binding ( " open_rom_item " , " GTK_open_rom " ) ;
set_accelerator_to_binding ( " record_movie_item " , " BeginRecordingMovie " ) ;
set_accelerator_to_binding ( " open_movie_item " , " LoadMovie " ) ;
set_accelerator_to_binding ( " stop_recording_item " , " EndRecordingMovie " ) ;
set_accelerator_to_binding ( " jump_to_frame_item " , " GTK_seek_to_frame " ) ;
set_accelerator_to_binding ( " reset_item " , " SoftReset " ) ;
set_accelerator_to_binding ( " hard_reset_item " , " Reset " ) ;
set_accelerator_to_binding ( " exit_item " , " GTK_quit " ) ;
// Special UI assignment
set_accelerator_to_binding ( " hide_ui " , " Escape Key " ) ;
2010-09-25 17:46:12 +02:00
}
2014-03-29 11:48:35 +01:00
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : resize_to_multiple ( int factor )
2014-03-29 11:48:35 +01:00
{
2014-03-30 05:15:04 +02:00
int h = ( config - > overscan ? 239 : 224 ) * factor ;
2020-07-05 00:53:38 +02:00
int w = h * S9xGetAspect ( ) + 0.5 ;
2014-03-29 11:48:35 +01:00
2020-07-05 00:53:38 +02:00
resize_viewport ( w , h ) ;
2014-03-29 11:48:35 +01:00
}
2017-12-07 19:24:29 +01:00
2020-07-05 00:53:38 +02:00
cairo_t * Snes9xWindow : : get_cairo ( )
2017-12-07 19:24:29 +01:00
{
if ( cr )
return cr ;
2020-07-05 00:53:38 +02:00
auto allocation = drawing_area - > get_allocation ( ) ;
2017-12-07 19:24:29 +01:00
2020-07-05 00:53:38 +02:00
Cairo : : RectangleInt rect = { 0 , 0 , allocation . get_width ( ) , allocation . get_height ( ) } ;
gdk_drawing_context = drawing_area - > get_window ( ) - > begin_draw_frame ( Cairo : : Region : : create ( rect ) ) ;
cr = gdk_drawing_context - > get_cairo_context ( ) - > cobj ( ) ;
2017-12-07 19:24:29 +01:00
2018-12-28 23:32:32 +01:00
cairo_owned = true ;
2017-12-07 19:24:29 +01:00
return cr ;
}
2020-07-05 00:53:38 +02:00
void Snes9xWindow : : release_cairo ( )
2017-12-07 19:24:29 +01:00
{
if ( cairo_owned )
{
2020-07-05 00:53:38 +02:00
drawing_area - > get_window ( ) - > end_draw_frame ( gdk_drawing_context ) ;
gdk_drawing_context . clear ( ) ;
2018-12-28 23:32:32 +01:00
cairo_owned = false ;
2020-07-05 00:53:38 +02:00
cr = nullptr ;
2017-12-07 19:24:29 +01:00
}
}