filename | src/gtkui/gtkui.c |
changeset | 537:d924be49e192 |
prev | 530:28bdc62e642a |
next | 543:361ec0a70cf2 |
author | nkeynes |
date | Tue Nov 20 10:27:58 2007 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Move gtk UI into gtkui subdir (prep for non-gtk builds), and protect with an automake conditional |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/gtkui/gtkui.c Tue Nov 20 10:27:58 2007 +00001.3 @@ -0,0 +1,468 @@1.4 +/**1.5 + * $Id: gtkui.c,v 1.12 2007-11-10 04:45:29 nkeynes Exp $1.6 + *1.7 + * Core GTK-based user interface1.8 + *1.9 + * Copyright (c) 2005 Nathan Keynes.1.10 + *1.11 + * This program is free software; you can redistribute it and/or modify1.12 + * it under the terms of the GNU General Public License as published by1.13 + * the Free Software Foundation; either version 2 of the License, or1.14 + * (at your option) any later version.1.15 + *1.16 + * This program is distributed in the hope that it will be useful,1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.19 + * GNU General Public License for more details.1.20 + */1.21 +1.22 +#include "lxdream.h"1.23 +#include <sys/time.h>1.24 +#include <time.h>1.25 +#include <glib/gi18n.h>1.26 +#include "dreamcast.h"1.27 +#include "display.h"1.28 +#include "gdrom/gdrom.h"1.29 +#include "gtkui/gtkui.h"1.30 +1.31 +1.32 +void gtk_gui_start( void );1.33 +void gtk_gui_stop( void );1.34 +void gtk_gui_alloc_resources ( void );1.35 +uint32_t gtk_gui_run_slice( uint32_t nanosecs );1.36 +1.37 +struct dreamcast_module gtk_gui_module = { "gui", NULL,1.38 + gtk_gui_update,1.39 + gtk_gui_start,1.40 + gtk_gui_run_slice,1.41 + gtk_gui_stop,1.42 + NULL, NULL };1.43 +1.44 +/**1.45 + * Single-instance windows (at most one)1.46 + */1.47 +static main_window_t main_win = NULL;1.48 +static debug_window_t debug_win = NULL;1.49 +static mmio_window_t mmio_win = NULL;1.50 +1.51 +/**1.52 + * UIManager and action helpers1.53 + */1.54 +static GtkUIManager *global_ui_manager;1.55 +static GtkActionGroup *global_action_group;1.56 +1.57 +/**1.58 + * Count of running nanoseconds - used to cut back on the GUI runtime1.59 + */1.60 +static uint32_t gtk_gui_nanos = 0;1.61 +static struct timeval gtk_gui_lasttv;1.62 +1.63 +static gboolean gtk_gui_init_ok = FALSE;1.64 +1.65 +#define ENABLE_ACTION(win,name) SET_ACTION_ENABLED(win,name,TRUE)1.66 +#define DISABLE_ACTION(win,name) SET_ACTION_ENABLED(win,name,FALSE)1.67 +1.68 +// UI Actions1.69 +static const GtkActionEntry ui_actions[] = {1.70 + { "FileMenu", NULL, N_("_File") },1.71 + { "SettingsMenu", NULL, N_("_Settings") },1.72 + { "HelpMenu", NULL, N_("_Help") },1.73 + { "Reset", GTK_STOCK_REFRESH, N_("_Reset"), "<control>R", N_("Reset dreamcast"), G_CALLBACK(reset_action_callback) },1.74 + { "Pause", GTK_STOCK_MEDIA_PAUSE, N_("_Pause"), NULL, N_("Pause dreamcast"), G_CALLBACK(pause_action_callback) },1.75 + { "Run", GTK_STOCK_MEDIA_PLAY, N_("Resume"), NULL, N_("Resume"), G_CALLBACK(resume_action_callback) },1.76 + { "LoadState", GTK_STOCK_REVERT_TO_SAVED, N_("_Load state..."), "F4", N_("Load an lxdream save state"), G_CALLBACK(load_state_action_callback) },1.77 + { "SaveState", GTK_STOCK_SAVE_AS, N_("_Save state..."), "F3", N_("Create an lxdream save state"), G_CALLBACK(save_state_action_callback) },1.78 + { "Exit", GTK_STOCK_QUIT, N_("E_xit"), NULL, N_("Exit lxdream"), G_CALLBACK(exit_action_callback) },1.79 + { "GdromSettings", NULL, N_("_GD-Rom...") },1.80 + { "GdromUnmount", NULL, N_("_Empty") },1.81 + { "GdromMount", GTK_STOCK_CDROM, N_("_Open Image..."), "<control>O", N_("Mount a cdrom disc"), G_CALLBACK(mount_action_callback) },1.82 + { "PathSettings", NULL, N_("_Paths..."), NULL, N_("Configure files and paths"), G_CALLBACK(path_settings_callback) },1.83 + { "AudioSettings", NULL, N_("_Audio..."), NULL, N_("Configure audio output"), G_CALLBACK(audio_settings_callback) },1.84 + { "ControllerSettings", NULL, N_("_Controllers..."), NULL, N_("Configure controllers"), G_CALLBACK(maple_settings_callback) },1.85 + { "NetworkSettings", NULL, N_("_Network..."), NULL, N_("Configure network settings"), G_CALLBACK(network_settings_callback) },1.86 + { "VideoSettings", NULL, N_("_Video..."), NULL,N_( "Configure video output"), G_CALLBACK(video_settings_callback) },1.87 + { "About", GTK_STOCK_ABOUT, N_("_About..."), NULL, N_("About lxdream"), G_CALLBACK(about_action_callback) },1.88 + { "DebugMenu", NULL, N_("_Debug") },1.89 + { "Debugger", NULL, N_("_Debugger"), NULL, N_("Open debugger window"), G_CALLBACK(debugger_action_callback) },1.90 + { "DebugMem", NULL, N_("View _Memory"), NULL, N_("View memory dump"), G_CALLBACK(debug_memory_action_callback) },1.91 + { "DebugMmio", NULL, N_("View IO _Registers"), NULL, N_("View MMIO Registers"), G_CALLBACK(debug_mmio_action_callback) },1.92 + { "SaveScene", NULL, N_("_Save Scene"), NULL, N_("Save next rendered scene"), G_CALLBACK(save_scene_action_callback) },1.93 + { "SingleStep", GTK_STOCK_REDO, N_("_Single Step"), NULL, N_("Single step"), G_CALLBACK(debug_step_action_callback) },1.94 + { "RunTo", GTK_STOCK_GOTO_LAST, N_("Run _To"), NULL, N_("Run to"), G_CALLBACK( debug_runto_action_callback) },1.95 + { "SetBreakpoint", GTK_STOCK_CLOSE, N_("_Breakpoint"), NULL, N_("Toggle breakpoint"), G_CALLBACK( debug_breakpoint_action_callback) }1.96 +};1.97 +static const GtkToggleActionEntry ui_toggle_actions[] = {1.98 + { "FullScreen", NULL, "_Full Screen", "<alt>Return", "Toggle full screen video", G_CALLBACK(fullscreen_toggle_callback), 0 },1.99 +};1.100 +1.101 +// Menus and toolbars1.102 +static const char *ui_description =1.103 + "<ui>"1.104 + " <menubar name='MainMenu'>"1.105 + " <menu action='FileMenu'>"1.106 + " <menuitem action='GdromSettings'/>"1.107 + " <separator/>"1.108 + " <menuitem action='Reset'/>"1.109 + " <menuitem action='Pause'/>"1.110 + " <menuitem action='Run'/>"1.111 + " <menuitem action='Debugger'/>"1.112 + " <separator/>"1.113 + " <menuitem action='LoadState'/>"1.114 + " <menuitem action='SaveState'/>"1.115 + " <separator/>"1.116 + " <menuitem action='Exit'/>"1.117 + " </menu>"1.118 + " <menu action='SettingsMenu'>"1.119 + " <menuitem action='PathSettings'/>"1.120 + " <menuitem action='AudioSettings'/>"1.121 + " <menuitem action='ControllerSettings'/>"1.122 + " <menuitem action='NetworkSettings'/>"1.123 + " <menuitem action='VideoSettings'/>"1.124 + " <separator/>"1.125 + " <menuitem action='FullScreen'/>"1.126 + " </menu>"1.127 + " <menu action='HelpMenu'>"1.128 + " <menuitem action='About'/>"1.129 + " </menu>"1.130 + " </menubar>"1.131 + " <toolbar name='MainToolbar'>"1.132 + " <toolitem action='GdromMount'/>"1.133 + " <toolitem action='Reset'/>"1.134 + " <toolitem action='Pause'/>"1.135 + " <toolitem action='Run'/>"1.136 + " <separator/>"1.137 + " <toolitem action='LoadState'/>"1.138 + " <toolitem action='SaveState'/>"1.139 + " </toolbar>"1.140 + " <menubar name='DebugMenu'>"1.141 + " <menu action='FileMenu'>"1.142 + " <menuitem action='GdromSettings'/>"1.143 + " <separator/>"1.144 + " <menuitem action='Reset'/>"1.145 + " <separator/>"1.146 + " <menuitem action='LoadState'/>"1.147 + " <menuitem action='SaveState'/>"1.148 + " <separator/>"1.149 + " <menuitem action='Exit'/>"1.150 + " </menu>"1.151 + " <menu action='DebugMenu'>"1.152 + " <menuitem action='DebugMem'/>"1.153 + " <menuitem action='DebugMmio'/>"1.154 + " <menuitem action='SaveScene'/>"1.155 + " <separator/>"1.156 + " <menuitem action='SetBreakpoint'/>"1.157 + " <menuitem action='Pause'/>"1.158 + " <menuitem action='SingleStep'/>"1.159 + " <menuitem action='RunTo'/>"1.160 + " <menuitem action='Run'/>"1.161 + " </menu>"1.162 + " <menu action='SettingsMenu'>"1.163 + " <menuitem action='PathSettings'/>"1.164 + " <menuitem action='AudioSettings'/>"1.165 + " <menuitem action='ControllerSettings'/>"1.166 + " <menuitem action='NetworkSettings'/>"1.167 + " <menuitem action='VideoSettings'/>"1.168 + " <separator/>"1.169 + " <menuitem action='FullScreen'/>"1.170 + " </menu>"1.171 + " <menu action='HelpMenu'>"1.172 + " <menuitem action='About'/>"1.173 + " </menu>"1.174 + " </menubar>"1.175 + " <toolbar name='DebugToolbar'>"1.176 + " <toolitem action='GdromMount'/>"1.177 + " <toolitem action='Reset'/>"1.178 + " <toolitem action='Pause'/>"1.179 + " <separator/>"1.180 + " <toolitem action='SingleStep'/>"1.181 + " <toolitem action='RunTo'/>"1.182 + " <toolitem action='Run'/>"1.183 + " <toolitem action='SetBreakpoint'/>"1.184 + " <separator/>"1.185 + " <toolitem action='LoadState'/>"1.186 + " <toolitem action='SaveState'/>"1.187 + " </toolbar>"1.188 + "</ui>";1.189 +1.190 +gboolean gui_parse_cmdline( int *argc, char **argv[] )1.191 +{1.192 + gtk_gui_init_ok = gtk_init_check( argc, argv );1.193 + return gtk_gui_init_ok;1.194 +}1.195 +1.196 +gboolean gui_init( gboolean withDebug )1.197 +{1.198 + if( gtk_gui_init_ok ) {1.199 + GError *error = NULL;1.200 + dreamcast_register_module( >k_gui_module );1.201 + gtk_gui_alloc_resources();1.202 +1.203 + global_action_group = gtk_action_group_new("MenuActions");1.204 + gtk_action_group_set_translation_domain( global_action_group, NULL );1.205 + gtk_action_group_add_actions( global_action_group, ui_actions, G_N_ELEMENTS(ui_actions), NULL );1.206 + gtk_action_group_add_toggle_actions( global_action_group, ui_toggle_actions, G_N_ELEMENTS(ui_toggle_actions), NULL );1.207 + gtk_gui_enable_action("AudioSettings", FALSE);1.208 + gtk_gui_enable_action("NetworkSettings", FALSE);1.209 + gtk_gui_enable_action("VideoSettings", FALSE);1.210 +1.211 + global_ui_manager = gtk_ui_manager_new();1.212 + gtk_ui_manager_set_add_tearoffs(global_ui_manager, TRUE);1.213 + gtk_ui_manager_insert_action_group( global_ui_manager, global_action_group, 0 );1.214 +1.215 + if (!gtk_ui_manager_add_ui_from_string (global_ui_manager, ui_description, -1, &error)) {1.216 + g_message ("building menus failed: %s", error->message);1.217 + g_error_free (error);1.218 + exit(1);1.219 + }1.220 + GtkAccelGroup *accel_group = gtk_ui_manager_get_accel_group (global_ui_manager);1.221 + GtkWidget *menubar = gtk_ui_manager_get_widget(global_ui_manager, "/MainMenu");1.222 + GtkWidget *toolbar = gtk_ui_manager_get_widget(global_ui_manager, "/MainToolbar");1.223 +1.224 + GtkWidget *gdrommenuitem = gtk_ui_manager_get_widget(global_ui_manager, "/MainMenu/FileMenu/GdromSettings");1.225 + gdrom_menu_init();1.226 + GtkWidget *gdrommenu = gdrom_menu_new();1.227 + gtk_menu_item_set_submenu( GTK_MENU_ITEM(gdrommenuitem), gdrommenu );1.228 + main_win = main_window_new( APP_NAME " " APP_VERSION, menubar, toolbar, accel_group );1.229 + if( withDebug ) {1.230 + gtk_gui_show_debugger();1.231 + }1.232 +1.233 + return TRUE;1.234 + } else {1.235 + return FALSE;1.236 + }1.237 +}1.238 +1.239 +void gui_main_loop(void)1.240 +{1.241 + gtk_main();1.242 +}1.243 +1.244 +void gui_update_state(void)1.245 +{1.246 + gtk_gui_update();1.247 +}1.248 +1.249 +gboolean gui_error_dialog( const char *msg, ... )1.250 +{1.251 + if( main_win != NULL ) {1.252 + va_list args;1.253 + GtkWidget *dialog =1.254 + gtk_message_dialog_new( main_window_get_frame(main_win), GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,1.255 + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, NULL );1.256 + va_start(args, msg);1.257 + gchar *markup = g_markup_vprintf_escaped( msg, args );1.258 + va_end( args );1.259 + gtk_message_dialog_set_markup( GTK_MESSAGE_DIALOG(dialog), markup );1.260 + g_free(markup);1.261 + gtk_dialog_run(GTK_DIALOG(dialog));1.262 + gtk_widget_destroy(dialog);1.263 + return TRUE;1.264 + }1.265 + return FALSE;1.266 +}1.267 +1.268 +void gui_update_io_activity( io_activity_type io, gboolean active )1.269 +{1.270 +1.271 +}1.272 +1.273 +void gtk_gui_show_debugger()1.274 +{1.275 + if( debug_win ) {1.276 + debug_window_show(debug_win, TRUE);1.277 + } else {1.278 + GtkAccelGroup *accel_group = gtk_ui_manager_get_accel_group (global_ui_manager);1.279 + GtkWidget *menubar = gtk_ui_manager_get_widget(global_ui_manager, "/DebugMenu");1.280 + GtkWidget *toolbar = gtk_ui_manager_get_widget(global_ui_manager, "/DebugToolbar");1.281 + GtkWidget *gdrommenuitem = gtk_ui_manager_get_widget(global_ui_manager, "/DebugMenu/FileMenu/GdromSettings");1.282 + GtkWidget *gdrommenu = gdrom_menu_new();1.283 + gtk_menu_item_set_submenu( GTK_MENU_ITEM(gdrommenuitem), gdrommenu );1.284 + gchar *title = g_strdup_printf( APP_NAME " " APP_VERSION " :: %s", _("Debugger"));1.285 + debug_win = debug_window_new( title, menubar, toolbar, accel_group );1.286 + g_free(title);1.287 + }1.288 +}1.289 +1.290 +void gtk_gui_show_mmio()1.291 +{1.292 + if( mmio_win ) {1.293 + mmio_window_show(mmio_win, TRUE);1.294 + } else {1.295 + gchar *title = g_strdup_printf( APP_NAME " " APP_VERSION " :: %s", _("MMIO Registers"));1.296 + mmio_win = mmio_window_new( title );1.297 + g_free(title);1.298 + }1.299 +}1.300 +1.301 +1.302 +main_window_t gtk_gui_get_main()1.303 +{1.304 + return main_win;1.305 +}1.306 +1.307 +debug_window_t gtk_gui_get_debugger()1.308 +{1.309 + return debug_win;1.310 +}1.311 +1.312 +mmio_window_t gtk_gui_get_mmio()1.313 +{1.314 + return mmio_win;1.315 +}1.316 +1.317 +GtkWidget *gtk_gui_get_renderarea()1.318 +{1.319 + if( main_win == NULL ) {1.320 + return NULL;1.321 + } else {1.322 + return main_window_get_renderarea(main_win);1.323 + }1.324 +}1.325 +1.326 +/**1.327 + * Hook called when DC starts running. Just disables the run/step buttons1.328 + * and enables the stop button.1.329 + */1.330 +void gtk_gui_start( void )1.331 +{1.332 + main_window_set_running( main_win, TRUE );1.333 + if( debug_win != NULL ) {1.334 + debug_window_set_running( debug_win, TRUE );1.335 + }1.336 + gtk_gui_nanos = 0;1.337 + gettimeofday(>k_gui_lasttv,NULL);1.338 +}1.339 +1.340 +/**1.341 + * Hook called when DC stops running. Enables the run/step buttons1.342 + * and disables the stop button.1.343 + */1.344 +void gtk_gui_stop( void )1.345 +{1.346 + main_window_set_running( main_win, FALSE );1.347 + gtk_gui_update();1.348 +}1.349 +1.350 +void gtk_gui_update( void )1.351 +{1.352 + if( debug_win ) {1.353 + debug_window_set_running( debug_win, FALSE );1.354 + debug_window_update(debug_win);1.355 + }1.356 + if( mmio_win ) {1.357 + mmio_window_update(mmio_win);1.358 + }1.359 + dump_window_update_all();1.360 +}1.361 +1.362 +/**1.363 + * Module run-slice. Because UI processing is fairly expensive, only1.364 + * run the processing about 10 times a second while we're emulating.1.365 + */1.366 +uint32_t gtk_gui_run_slice( uint32_t nanosecs )1.367 +{1.368 + gtk_gui_nanos += nanosecs;1.369 + if( gtk_gui_nanos > 100000000 ) {1.370 + struct timeval tv;1.371 + while( gtk_events_pending() )1.372 + gtk_main_iteration();1.373 +1.374 + gettimeofday(&tv,NULL);1.375 + double ns = ((tv.tv_sec - gtk_gui_lasttv.tv_sec) * 1000000000.0) +1.376 + ((tv.tv_usec - gtk_gui_lasttv.tv_usec)*1000.0);1.377 + double speed = (float)( (double)gtk_gui_nanos * 100.0 / ns );1.378 + gtk_gui_lasttv.tv_sec = tv.tv_sec;1.379 + gtk_gui_lasttv.tv_usec = tv.tv_usec;1.380 + main_window_set_speed( main_win, speed );1.381 + gtk_gui_nanos = 0;1.382 + }1.383 + return nanosecs;1.384 +}1.385 +1.386 +1.387 +PangoFontDescription *gui_fixed_font;1.388 +GdkColor gui_colour_normal, gui_colour_changed, gui_colour_error;1.389 +GdkColor gui_colour_warn, gui_colour_pc, gui_colour_debug;1.390 +GdkColor gui_colour_trace, gui_colour_break, gui_colour_temp_break;1.391 +GdkColor gui_colour_white;1.392 +1.393 +void gtk_gui_alloc_resources() {1.394 + GdkColormap *map;1.395 +1.396 + gui_colour_normal.red = gui_colour_normal.green = gui_colour_normal.blue = 0;1.397 + gui_colour_changed.red = gui_colour_changed.green = 64*256;1.398 + gui_colour_changed.blue = 154*256;1.399 + gui_colour_error.red = 65535;1.400 + gui_colour_error.green = gui_colour_error.blue = 64*256;1.401 + gui_colour_pc.red = 32*256;1.402 + gui_colour_pc.green = 170*256;1.403 + gui_colour_pc.blue = 52*256;1.404 + gui_colour_warn = gui_colour_changed;1.405 + gui_colour_trace.red = 156*256;1.406 + gui_colour_trace.green = 78*256;1.407 + gui_colour_trace.blue = 201*256;1.408 + gui_colour_debug = gui_colour_pc;1.409 + gui_colour_break.red = 65535;1.410 + gui_colour_break.green = gui_colour_break.blue = 192*256;1.411 + gui_colour_temp_break.red = gui_colour_temp_break.green = 128*256;1.412 + gui_colour_temp_break.blue = 32*256;1.413 + gui_colour_white.red = gui_colour_white.green = gui_colour_white.blue = 65535;1.414 +1.415 + map = gdk_colormap_new(gdk_visual_get_best(), TRUE);1.416 + gdk_colormap_alloc_color(map, &gui_colour_normal, TRUE, TRUE);1.417 + gdk_colormap_alloc_color(map, &gui_colour_changed, TRUE, TRUE);1.418 + gdk_colormap_alloc_color(map, &gui_colour_error, TRUE, TRUE);1.419 + gdk_colormap_alloc_color(map, &gui_colour_warn, TRUE, TRUE);1.420 + gdk_colormap_alloc_color(map, &gui_colour_pc, TRUE, TRUE);1.421 + gdk_colormap_alloc_color(map, &gui_colour_debug, TRUE, TRUE);1.422 + gdk_colormap_alloc_color(map, &gui_colour_trace, TRUE, TRUE);1.423 + gdk_colormap_alloc_color(map, &gui_colour_break, TRUE, TRUE);1.424 + gdk_colormap_alloc_color(map, &gui_colour_temp_break, TRUE, TRUE);1.425 + gdk_colormap_alloc_color(map, &gui_colour_white, TRUE, TRUE);1.426 + gui_fixed_font = pango_font_description_from_string("Courier 10");1.427 +}1.428 +1.429 +gint gtk_gui_run_property_dialog( const gchar *title, GtkWidget *panel, gtk_dialog_done_fn fn )1.430 +{1.431 + GtkWidget *dialog =1.432 + gtk_dialog_new_with_buttons(title, main_window_get_frame(main_win),1.433 + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,1.434 + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,1.435 + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,1.436 + NULL);1.437 + gint result;1.438 + gtk_widget_show_all(panel);1.439 + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), panel );1.440 + result = gtk_dialog_run( GTK_DIALOG(dialog) );1.441 + if( fn != NULL ) {1.442 + fn(panel, result == GTK_RESPONSE_ACCEPT);1.443 + }1.444 + gtk_widget_destroy( dialog );1.445 + return result;1.446 +}1.447 +1.448 +void gtk_gui_enable_action( const gchar *action, gboolean enable )1.449 +{1.450 + gtk_action_set_sensitive( gtk_action_group_get_action( global_action_group, action), enable);1.451 +}1.452 +1.453 +static void delete_frame_buffer( guchar *pixels, gpointer buffer )1.454 +{1.455 + if( buffer != NULL ) {1.456 + g_free(buffer);1.457 + }1.458 +}1.459 +1.460 +GdkPixbuf *gdk_pixbuf_new_from_frame_buffer( frame_buffer_t buffer )1.461 +{1.462 + return gdk_pixbuf_new_from_data( (unsigned char *)buffer->data,1.463 + GDK_COLORSPACE_RGB,1.464 + (buffer->colour_format == COLFMT_BGRA8888),1.465 + 8,1.466 + buffer->width,1.467 + buffer->height,1.468 + buffer->rowstride,1.469 + delete_frame_buffer,1.470 + buffer );1.471 +}
.