mupen64plus-oldsvn/main/gui_gtk/main_gtk.c
Scott Knauert 8049d55592 Fix race conditions and gdk threading issues that cause crashes with Rice.
- Only update the GUI's state after fully initializing the core in the emulation thread. This stops a race condition when plugin loading takes a long time (mostly noticable with hi-res textures on Rice).
- Exit gdk when calling core functions (core start / stop / pause - likely others will need this) since they may turn around and call GUI functions. This prevents a double locked gdk which causes a freeze.
2008-11-02 08:43:15 +00:00

1246 lines
52 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - main_gtk.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008 Tillin9 *
* Copyright (C) 2002 Blight *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* main_gtk.c - Handles the main window and 'glues' it with other windows */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <SDL_thread.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "main_gtk.h"
#include "aboutdialog.h"
#include "cheatdialog.h"
#include "configdialog.h"
#include "rombrowser.h"
#include "romproperties.h"
#include "icontheme.h"
#include "../version.h"
#include "../main.h"
#include "../config.h"
#include "../util.h"
#include "../translate.h"
#include "../savestates.h"
#include "../plugin.h"
#include "../rom.h"
#ifdef DBG
#include "debugger/registers.h" //temporary includes for the debugger menu
#include "debugger/breakpoints.h" //these can be removed when the main gui
#include "debugger/regTLB.h" //window no longer needs to know if each
#include "debugger/memedit.h" //debugger window is open
#include "debugger/varlist.h"
#include "../../debugger/debugger.h"
#endif
/* Necessary function prototypes. */
static void callback_start_emulation(GtkWidget* widget, gpointer data);
static void callback_pause_emulation(GtkWidget* widget, gpointer data);
static void callback_stop_emulation(GtkWidget* widget, gpointer data);
static void callback_open_rom(GtkWidget* widget, gpointer data);
static void callback_theme_changed(GtkWidget* widget, gpointer data);
static void create_mainWindow(void);
/* Globals. */
SMainWindow g_MainWindow;
static Uint32 g_GuiThreadID = 0; /* Main gui thread. */
/*********************************************************************************************************
* GUI interfaces.
*/
/* Parse gui-specific arguments, remove them from argument list,
* and create gtk gui in thread-safe manner, but do not display.
*/
void gui_init(int* argc, char*** argv)
{
/* Initialize multi-threading support. */
g_thread_init(NULL);
gdk_threads_init();
/* Save main gui thread handle. */
g_GuiThreadID = SDL_ThreadID();
/* Call gtk to parse arguments. */
gtk_init(argc, argv);
/* Set application name. */
g_set_application_name(MUPEN_NAME);
/* Setup gtk theme. */
GtkIconTheme* icontheme = gtk_icon_theme_get_default();
g_signal_connect(icontheme, "changed", G_CALLBACK(callback_theme_changed), NULL);
g_MainWindow.dialogErrorImage = g_MainWindow.dialogQuestionImage = NULL;
create_mainWindow();
create_configDialog();
create_rom_properties();
callback_theme_changed(NULL, NULL);
gui_set_state(GUI_STATE_STOPPED);
gdk_threads_leave();
}
/* Display GUI components to the screen. */
void gui_display(void)
{
gtk_widget_show_all(g_MainWindow.toplevelVBox);
if(!(config_get_bool("ToolbarVisible",TRUE)))
gtk_widget_hide(g_MainWindow.toolBar);
if(!(config_get_bool("FilterVisible",TRUE)))
gtk_widget_hide(g_MainWindow.filterBar);
if(!(config_get_bool("StatusbarVisible",TRUE)))
gtk_widget_hide(g_MainWindow.statusBarHBox);
gtk_widget_show(g_MainWindow.window);
}
/* Save GUI window properties and destroy widgets. */
void gui_destroy(void)
{
gint width, height, xposition, yposition;
gtk_window_get_size(GTK_WINDOW(g_MainWindow.window), &width, &height);
gtk_window_get_position(GTK_WINDOW(g_MainWindow.window), &xposition, &yposition);
config_put_number("MainWindowWidth",width);
config_put_number("MainWindowHeight",height);
config_put_number("MainWindowXPosition",xposition);
config_put_number("MainWindowYPosition",yposition);
gtk_widget_destroy(g_MainWindow.window);
gtk_widget_destroy(g_ConfigDialog.dialog);
gtk_widget_destroy(g_RomPropDialog.dialog);
}
/* Give control of thread to gtk. */
void gui_main_loop(void)
{
gtk_main();
gui_destroy();
gdk_threads_leave();
}
/* gui_update_rombrowser() accesses g_romcahce.length and adds upto roms to the
* rombrowser. The clear flag tells the GUI to clear the rombrowser first.
*/
void gui_update_rombrowser(unsigned int roms, unsigned short clear)
{
Uint32 self = SDL_ThreadID();
/* If we're calling from a thread other than the main gtk thread, take gdk lock. */
if (self != g_GuiThreadID)
gdk_threads_enter();
rombrowser_refresh(roms, clear);
if (self != g_GuiThreadID)
gdk_threads_leave();
return;
}
/* Display either an informational message to the status bar, a yes / no confirmation
* dialog, or an error dialog.
*/
int gui_message(gui_message_t messagetype , const char* format, ...)
{
if(!gui_enabled()||messagetype>GUI_MESSAGE_ERROR)
return 0;
gint response = 0;
va_list ap;
char buffer[2048];
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
/* If we're calling from a thread other than the main gtk thread, take gdk lock. */
Uint32 self = SDL_ThreadID();
if(self!=g_GuiThreadID)
gdk_threads_enter();
if(messagetype==GUI_MESSAGE_INFO)
{
int counter;
for(counter = 0; counter < strlen(buffer); ++counter)
{
if(buffer[counter]=='\n')
{
buffer[counter]='\0';
break;
}
}
gtk_statusbar_pop(GTK_STATUSBAR(g_MainWindow.statusBar), gtk_statusbar_get_context_id(GTK_STATUSBAR(g_MainWindow.statusBar), "status"));
gtk_statusbar_push(GTK_STATUSBAR(g_MainWindow.statusBar), gtk_statusbar_get_context_id(GTK_STATUSBAR(g_MainWindow.statusBar), "status"), buffer);
}
else
{
GtkWidget *dialog, *hbox, *label, *icon;
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
icon = gtk_image_new();
if(messagetype==GUI_MESSAGE_ERROR)
{
dialog = gtk_dialog_new_with_buttons(tr("Error"), GTK_WINDOW(g_MainWindow.window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE,NULL);
icon = g_MainWindow.dialogErrorImage = gtk_image_new();
set_icon(g_MainWindow.dialogErrorImage, "dialog-error", 32, FALSE);
}
else if(messagetype==GUI_MESSAGE_CONFIRM)
{
dialog = gtk_dialog_new_with_buttons(tr("Confirm"), GTK_WINDOW(g_MainWindow.window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_YES, GTK_RESPONSE_ACCEPT, GTK_STOCK_NO, GTK_RESPONSE_REJECT, NULL);
icon = g_MainWindow.dialogErrorImage = gtk_image_new();
set_icon(g_MainWindow.dialogErrorImage, "dialog-question", 32, FALSE);
}
gtk_misc_set_alignment(GTK_MISC(icon), 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
label = gtk_label_new(buffer);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show_all(dialog);
if(messagetype==GUI_MESSAGE_ERROR)
g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
else if(messagetype==GUI_MESSAGE_CONFIRM)
{
response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
}
if (self != g_GuiThreadID)
gdk_threads_leave();
return response == GTK_RESPONSE_ACCEPT;
}
/* Depending on emulator state, disable undefined options in menus and on the toolbar. */
void gui_set_state(gui_state_t state)
{
Uint32 self = SDL_ThreadID();
gboolean enabled, paused;
if(!gui_enabled()||state>GUI_STATE_RUNNING)
return;
/* If we're calling from a thread other than the main gtk thread, take gdk lock. */
if(self!=g_GuiThreadID)
gdk_threads_enter();
if(state==GUI_STATE_STOPPED)
enabled = paused = FALSE;
if(state==GUI_STATE_RUNNING)
{
enabled = TRUE;
paused = FALSE;
}
if(state==GUI_STATE_PAUSED)
enabled = paused = TRUE;
g_signal_handlers_block_by_func(g_MainWindow.playButtonItem, callback_start_emulation, NULL);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(g_MainWindow.playButtonItem), enabled&&!paused);
g_signal_handlers_unblock_by_func(g_MainWindow.playButtonItem, callback_start_emulation, NULL);
g_signal_handlers_block_by_func(g_MainWindow.pauseButtonItem, callback_pause_emulation, NULL);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(g_MainWindow.pauseButtonItem), paused);
g_signal_handlers_unblock_by_func(g_MainWindow.pauseButtonItem, callback_pause_emulation, NULL);
g_signal_handlers_block_by_func(g_MainWindow.stopButtonItem, callback_stop_emulation, NULL);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(g_MainWindow.stopButtonItem), !enabled);
g_signal_handlers_unblock_by_func(g_MainWindow.stopButtonItem, callback_stop_emulation, NULL);
gtk_widget_set_sensitive(g_MainWindow.stopMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.saveStateMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.saveStateAsMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.loadStateMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.loadStateFromMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.fullscreenMenuItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.pauseButtonItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.stopButtonItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.saveStateButtonItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.loadStateButtonItem, enabled);
gtk_widget_set_sensitive(g_MainWindow.fullscreenButtonItem, enabled);
if(g_GfxPlugin||enabled)
gtk_widget_set_sensitive(g_ConfigDialog.graphicsCombo, FALSE);
else
gtk_widget_set_sensitive(g_ConfigDialog.graphicsCombo, TRUE);
if(g_AudioPlugin||enabled)
gtk_widget_set_sensitive(g_ConfigDialog.audioCombo, FALSE);
else
gtk_widget_set_sensitive(g_ConfigDialog.audioCombo, TRUE);
if(g_InputPlugin||enabled)
gtk_widget_set_sensitive(g_ConfigDialog.inputCombo, FALSE);
else
gtk_widget_set_sensitive(g_ConfigDialog.inputCombo, TRUE);
if(g_RspPlugin||enabled)
gtk_widget_set_sensitive(g_ConfigDialog.rspCombo, FALSE);
else
gtk_widget_set_sensitive(g_ConfigDialog.rspCombo, TRUE);
if (self != g_GuiThreadID)
gdk_threads_leave();
}
/*********************************************************************************************************
* Callbacks.
*/
static gint callback_mainWindowDeleteEvent(GtkWidget* widget, GdkEvent* event, gpointer data)
{
gtk_main_quit();
return TRUE; /* Don't delete main window here. */
}
/* If theme changes, update application with images from new theme, or fallbacks. */
static void callback_theme_changed(GtkWidget* widget, gpointer data)
{
gboolean usefallbacks = check_icon_theme();
short size = config_get_number("ToolbarSize", 22);
int counter;
set_icon(g_MainWindow.openButtonImage, "mupen64cart", size, TRUE);
set_icon(g_MainWindow.playButtonImage, "media-playback-start", size, FALSE);
set_icon(g_MainWindow.pauseButtonImage, "media-playback-pause", size, FALSE);
set_icon(g_MainWindow.stopButtonImage, "media-playback-stop", size, FALSE);
set_icon(g_MainWindow.saveStateButtonImage, "document-save", size, FALSE);
set_icon(g_MainWindow.loadStateButtonImage, "document-revert", size, FALSE);
set_icon(g_MainWindow.configureButtonImage, "preferences-system", size, FALSE);
set_icon(g_MainWindow.fullscreenButtonImage, "view-fullscreen", size, FALSE);
if(GTK_IS_IMAGE(g_MainWindow.dialogErrorImage))
set_icon(g_MainWindow.dialogErrorImage, "dialog-error", 32, FALSE);
if(GTK_IS_IMAGE(g_MainWindow.dialogQuestionImage))
set_icon(g_MainWindow.dialogQuestionImage, "dialog-question", 32, FALSE);
set_icon(g_ConfigDialog.graphicsImage, "video-display", 32, FALSE);
set_icon(g_ConfigDialog.audioImage, "audio-card", 32, FALSE);
set_icon(g_ConfigDialog.inputImage, "input-gaming", 32, FALSE);
set_icon(g_MainWindow.playMenuImage, "media-playback-start", 16, FALSE);
set_icon(g_MainWindow.pauseMenuImage, "media-playback-pause", 16, FALSE);
set_icon(g_MainWindow.stopMenuImage, "media-playback-stop", 16, FALSE);
set_icon(g_MainWindow.openRomMenuImage, "mupen64cart", 16, TRUE);
set_icon(g_MainWindow.closeRomMenuImage, "window-close", 16, FALSE);
set_icon(g_MainWindow.quitMenuImage, "application-exit", 16, FALSE);
set_icon(g_MainWindow.configureMenuImage, "preferences-system", 16, FALSE);
set_icon(g_MainWindow.graphicsMenuImage, "video-display", 16, FALSE);
set_icon(g_MainWindow.audioMenuImage, "audio-card", 16, FALSE);
set_icon(g_MainWindow.inputMenuImage, "input-gaming", 16, FALSE);
set_icon(g_MainWindow.rspMenuImage, "cpu", 16, TRUE);
set_icon(g_MainWindow.fullscreenMenuImage, "view-fullscreen", 16, FALSE);
set_icon(g_MainWindow.saveStateMenuImage, "document-save", 16, FALSE);
set_icon(g_MainWindow.saveStateAsMenuImage, "document-save-as", 16, FALSE);
set_icon(g_MainWindow.loadStateMenuImage, "document-revert", 16, FALSE);
set_icon(g_MainWindow.loadStateFromMenuImage, "document-open", 16, FALSE);
set_icon(g_MainWindow.aboutMenuImage, "gtk-about", 16, FALSE);
set_icon(g_MainWindow.playRombrowserImage, "media-playback-start", 16, FALSE);
set_icon(g_MainWindow.propertiesRombrowserImage, "document-properties", 16, FALSE);
set_icon(g_MainWindow.refreshRombrowserImage, "view-refresh", 16, FALSE);
if(usefallbacks)
{
GtkIconTheme* icontheme = gtk_icon_theme_get_default();
star = gtk_icon_theme_load_icon(icontheme, "gtk-about", 16, 0, NULL);
}
else
star = gdk_pixbuf_new_from_file(get_iconpath("16x16/gtk-about.png"), NULL);
staroff = gdk_pixbuf_copy(star);
gdk_pixbuf_saturate_and_pixelate(star, staroff, 0.1, FALSE);
if(g_RomPropDialog.entry)
{
for(counter = 0; counter < 5; ++counter)
{
if(g_RomPropDialog.entry->inientry->status>counter)
gtk_image_set_from_pixbuf(GTK_IMAGE(g_RomPropDialog.status[counter]), star);
else
gtk_image_set_from_pixbuf(GTK_IMAGE(g_RomPropDialog.status[counter]), staroff);
}
}
rombrowser_refresh(g_romcache.length, TRUE);
}
/* Ask user to load a rom. If emulation is running, give warning. */
static void callback_open_rom(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
{
if(!gui_message(GUI_MESSAGE_CONFIRM, tr("Emulation is running. Do you want to stop it?\n\nNote: in order to play another rom, you must first stop this one. ")))
return;
callback_stop_emulation(NULL, NULL);
}
/* Get rom file from user. */
GtkWidget* file_chooser = gtk_file_chooser_dialog_new(tr("Open Rom..."), GTK_WINDOW(g_MainWindow.window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
/* Add filter for rom file types. */
GtkFileFilter* file_filter = gtk_file_filter_new();
gtk_file_filter_set_name(file_filter, "N64 ROM (*.z64, *.v64, *.n64, *.gz, *.zip. *.bz2, *.lzma *.7z)");
gtk_file_filter_add_mime_type(file_filter, "application/x-gzip");
gtk_file_filter_add_mime_type(file_filter, "application/zip");
gtk_file_filter_add_mime_type(file_filter, "application/x-bzip2");
gtk_file_filter_add_mime_type(file_filter, "application/x-7z");
gtk_file_filter_add_pattern(file_filter, "*.[zZ]64");
gtk_file_filter_add_pattern(file_filter, "*.lzma");
gtk_file_filter_add_pattern(file_filter, "*.7z");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), file_filter);
/* Add filter for "all files." */
file_filter = gtk_file_filter_new();
gtk_file_filter_set_name(file_filter, "All files (*.*)");
gtk_file_filter_add_pattern(file_filter, "*");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), file_filter);
if(gtk_dialog_run(GTK_DIALOG(file_chooser))==GTK_RESPONSE_ACCEPT)
{
gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser));
gtk_widget_hide(file_chooser); /* Hide dialog while rom is loading. */
open_rom(filename, 0);
g_free(filename);
if(rom)
startEmulation();
}
gtk_widget_destroy(file_chooser);
}
static void callback_close_rom(GtkWidget* widget, gpointer data)
{
close_rom();
}
/* If a rom is loaded, start emulation. Else attempt to load rom, first from rombrowser
* then, if none selected, ask the user.
*/
static void callback_start_emulation(GtkWidget* widget, gpointer data)
{
if(!rom)
{
GList *list = NULL, *llist = NULL;
cache_entry* entry;
GtkTreeIter iter;
GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_MainWindow.romDisplay));
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_MainWindow.romDisplay));
list = gtk_tree_selection_get_selected_rows (selection, &model);
if(!list)
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("There is no Rom loaded. Do you want to load one?")))
callback_open_rom(NULL, NULL);
return;
}
else
{
llist = g_list_first(list);
gtk_tree_model_get_iter(model, &iter,(GtkTreePath*)llist->data);
gtk_tree_model_get(model, &iter, 22, &entry, -1);
g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
g_list_free(list);
if(open_rom(entry->filename, entry->archivefile)==0)
startEmulation();
else
return;
}
}
gdk_threads_leave();
startEmulation();
}
static void callback_pause_emulation(GtkWidget* widget, gpointer data)
{
gdk_threads_leave();
pauseContinueEmulation();
}
static void callback_stop_emulation(GtkWidget* widget, gpointer data)
{
gdk_threads_leave();
stopEmulation();
}
static void callback_save_state(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
savestates_job |= SAVESTATE;
else
error_message(tr("Emulation is not running."));
}
/* Save state as. Launch a file chooser so user can specify file. */
static void callback_save_state_as(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
{
GtkWidget* file_chooser;
file_chooser = gtk_file_chooser_dialog_new(tr("Save as..."), GTK_WINDOW(g_MainWindow.window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
/* Set default filename. */
char* filename = savestates_get_filename();
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), filename);
free(filename);
if(gtk_dialog_run(GTK_DIALOG(file_chooser))==GTK_RESPONSE_ACCEPT)
{
gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
savestates_select_filename(filename);
savestates_job |= SAVESTATE;
g_free(filename);
}
gtk_widget_destroy (file_chooser);
}
else
error_message(tr("Emulation is not running."));
}
static void callback_load_state(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
savestates_job |= LOADSTATE;
else
error_message(tr("Emulation is not running."));
}
/* Load state from. Open a file chooser so user can specify file. */
static void callback_load_state_from(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
{
GtkWidget* file_chooser;
file_chooser = gtk_file_chooser_dialog_new(tr("Load..."), GTK_WINDOW(g_MainWindow.window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
if(gtk_dialog_run(GTK_DIALOG(file_chooser))==GTK_RESPONSE_ACCEPT)
{
gchar* filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
savestates_select_filename(filename);
savestates_job |= LOADSTATE;
g_free(filename);
}
gtk_widget_destroy (file_chooser);
}
else
error_message(tr("Emulation is not running."));
}
/* User changed savestate slot. */
static void callback_change_slot(GtkMenuItem* item, int slot)
{
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)))
{
if(slot!=savestates_get_slot()) /* Only actually change slot when not a GUI update. */
savestates_select_slot(slot);
}
}
/* User opened save slot menu. Make sure current save slot is selected. */
static void callback_update_slot(GtkMenuItem* item, GSList* slots)
{
unsigned int i, slot;
GtkWidget* slotItem;
for(i = 0; i < g_slist_length(slots); i++)
{
slotItem = GTK_WIDGET(g_slist_nth_data(slots, i));
slot = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(slotItem), "slot_num"));
if(slot==savestates_get_slot())
{
if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(slotItem)))
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(slotItem), TRUE);
break;
}
}
}
static void callback_configure(GtkWidget* widget, gpointer data)
{
show_configure();
}
static void callback_configure_graphics(GtkWidget* widget, gpointer data)
{
char* name = plugin_name_by_filename(config_get_string("Gfx Plugin", ""));
if(name)
plugin_exec_config(name);
else
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("No graphics plugin selected! Do you\nwant to select one?")))
{
gtk_notebook_set_page(GTK_NOTEBOOK(g_ConfigDialog.notebook), gtk_notebook_page_num(GTK_NOTEBOOK(g_ConfigDialog.notebook), g_ConfigDialog.configPlugins));
gtk_widget_show_all(g_ConfigDialog.dialog);
}
}
}
static void callback_configure_audio(GtkWidget* widget, gpointer data)
{
char* name = plugin_name_by_filename(config_get_string("Audio Plugin", ""));
if(name)
plugin_exec_config(name);
else
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("No audio plugin selected! Do you\nwant to select one?")))
{
gtk_notebook_set_page(GTK_NOTEBOOK(g_ConfigDialog.notebook), gtk_notebook_page_num(GTK_NOTEBOOK(g_ConfigDialog.notebook), g_ConfigDialog.configPlugins));
gtk_widget_show_all(g_ConfigDialog.dialog);
}
}
}
static void callback_configure_input(GtkWidget* widget, gpointer data)
{
char* name = plugin_name_by_filename(config_get_string("Input Plugin", ""));
if(name)
plugin_exec_config(name);
else
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("No input plugin selected! Do you\nwant to select one?")))
{
gtk_notebook_set_page(GTK_NOTEBOOK(g_ConfigDialog.notebook), gtk_notebook_page_num(GTK_NOTEBOOK(g_ConfigDialog.notebook), g_ConfigDialog.configPlugins));
gtk_widget_show_all(g_ConfigDialog.dialog);
}
}
}
static void callback_configure_rsp(GtkWidget* widget, gpointer data)
{
char* name = plugin_name_by_filename(config_get_string("RSP Plugin", ""));
if(name)
plugin_exec_config(name);
else
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("No RSP plugin selected! Do you\nwant to select one?")))
{
gtk_notebook_set_page(GTK_NOTEBOOK(g_ConfigDialog.notebook), gtk_notebook_page_num(GTK_NOTEBOOK(g_ConfigDialog.notebook), g_ConfigDialog.configPlugins));
gtk_widget_show_all(g_ConfigDialog.dialog);
}
}
}
/* Enter full screen mode. */
static void callback_fullscreen(GtkWidget* widget, gpointer data)
{
if(g_EmulatorRunning)
changeWindow();
}
static void callback_toggle_view(GtkWidget* widget, gpointer data)
{
GtkWidget* toggle_object = NULL;
switch(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "toggle_object")))
{
case TOOLBAR:
toggle_object = g_MainWindow.toolBar;
config_put_bool("ToolbarVisible", !GTK_WIDGET_VISIBLE(g_MainWindow.toolBar));
break;
case FILTER:
toggle_object = g_MainWindow.filterBar;
gtk_entry_set_text(GTK_ENTRY(g_MainWindow.filter),"");
config_put_bool("FilterVisible", !GTK_WIDGET_VISIBLE(g_MainWindow.filterBar));
break;
case STATUSBAR:
toggle_object = g_MainWindow.statusBarHBox;
config_put_bool("StatusbarVisible", !GTK_WIDGET_VISIBLE(g_MainWindow.statusBarHBox));
break;
}
if(toggle_object==NULL)
return;
if(GTK_WIDGET_VISIBLE(toggle_object))
gtk_widget_hide(toggle_object);
else
gtk_widget_show(toggle_object);
}
static void callback_update_check_item(GtkWidget* widget, gpointer data)
{
GtkWidget* toggle_object = NULL;
switch(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "toggle_object")))
{
case TOOLBAR:
toggle_object = g_MainWindow.toolBar;
break;
case FILTER:
toggle_object = g_MainWindow.filterBar;
break;
case STATUSBAR:
toggle_object = g_MainWindow.statusBarHBox;
break;
}
if(toggle_object==NULL)
return;
g_signal_handlers_block_by_func(widget, callback_toggle_view, NULL);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), GTK_WIDGET_VISIBLE(toggle_object));
g_signal_handlers_unblock_by_func(widget, callback_toggle_view, NULL);
}
static void callback_update_view(GtkWidget* widget, gpointer data)
{
gtk_container_foreach(GTK_CONTAINER(widget), callback_update_check_item, NULL);
}
#ifdef DBG
static GtkWidget* debuggerRegistersShow;
static GtkWidget* debuggerBreakpointsShow;
static GtkWidget* debuggerTLBShow;
static GtkWidget* debuggerMemoryShow;
static GtkWidget* debuggerVariablesShow;
static void callback_debuggerEnableToggled(GtkWidget* widget, gpointer data)
{
int emuRestart = 0;
if(g_EmulatorRunning)
{
if(gui_message(GUI_MESSAGE_CONFIRM, tr("Emulation needs to be restarted in order\nto activate the debugger. Do you want\nthis to happen?")))
{
callback_stop_emulation(NULL, NULL);
emuRestart = 1;
}
}
g_DebuggerEnabled = gtk_check_menu_item_get_active((GtkCheckMenuItem*)widget);
gtk_widget_set_sensitive(debuggerRegistersShow, g_DebuggerEnabled);
gtk_widget_set_sensitive(debuggerBreakpointsShow, g_DebuggerEnabled);
gtk_widget_set_sensitive(debuggerTLBShow, g_DebuggerEnabled);
gtk_widget_set_sensitive(debuggerMemoryShow, g_DebuggerEnabled);
gtk_widget_set_sensitive(debuggerVariablesShow, g_DebuggerEnabled);
if(emuRestart==1)
callback_start_emulation(NULL, NULL);
}
static void callback_debuggerWindowShow(GtkWidget* widget, gpointer window)
{
switch(GPOINTER_TO_UINT(window))
{
case 1:
if(registers_opened==0)
init_registers();
break;
case 2:
if(breakpoints_opened==0)
init_breakpoints();
break;
case 3:
if(regTLB_opened==0)
init_TLBwindow();
break;
case 4:
if(memedit_opened==0)
init_memedit();
break;
case 5:
if(varlist_opened==0)
init_varlist();
break;
}
}
#endif
/*********************************************************************************************************
* GUI creation.
*/
static void create_menubar(void)
{
GtkWidget* menu;
GtkWidget* menuitem;
GtkWidget* item;
GtkWidget* submenu;
GtkWidget* submenuitem;
int i;
/* Create toggable accelerator groups. */
g_MainWindow.accelGroup = gtk_accel_group_new();
g_MainWindow.accelUnsafe = gtk_accel_group_new();
g_MainWindow.accelUnsafeActive = TRUE;
gtk_window_add_accel_group(GTK_WINDOW(g_MainWindow.window), g_MainWindow.accelGroup);
gtk_window_add_accel_group(GTK_WINDOW(g_MainWindow.window), g_MainWindow.accelUnsafe);
g_MainWindow.menuBar = gtk_menu_bar_new();
gtk_box_pack_start(GTK_BOX(g_MainWindow.toplevelVBox), g_MainWindow.menuBar, FALSE, FALSE, 0);
/* File menu. */
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_mnemonic(tr("_File"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(g_MainWindow.menuBar), menuitem);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Open Rom..."));
g_MainWindow.openRomMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.openRomMenuImage);
gtk_widget_add_accelerator(item, "activate", g_MainWindow.accelGroup, GDK_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(item, "activate", G_CALLBACK(callback_open_rom), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Close Rom"));
g_MainWindow.closeRomMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.closeRomMenuImage);
gtk_widget_add_accelerator(item, "activate", g_MainWindow.accelGroup, GDK_w, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(item, "activate", G_CALLBACK(callback_close_rom), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
item = gtk_image_menu_item_new_with_mnemonic(tr("_Quit"));
g_MainWindow.quitMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.quitMenuImage);
gtk_widget_add_accelerator(item, "activate", g_MainWindow.accelGroup, GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(item, "activate", G_CALLBACK(callback_mainWindowDeleteEvent), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* Emulation menu. */
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_mnemonic(tr("_Emulation"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(g_MainWindow.menuBar), menuitem);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Start"));
g_MainWindow.playMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.playMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_start_emulation), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
g_MainWindow.pauseMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("_Pause"));
g_MainWindow.pauseMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.pauseMenuItem), g_MainWindow.pauseMenuImage);
gtk_widget_add_accelerator(g_MainWindow.pauseMenuItem, "activate", g_MainWindow.accelGroup, GDK_Pause, 0, GTK_ACCEL_VISIBLE);
g_signal_connect(g_MainWindow.pauseMenuItem, "activate", G_CALLBACK(callback_pause_emulation), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.pauseMenuItem);
g_MainWindow.stopMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("S_top"));
g_MainWindow.stopMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.stopMenuItem), g_MainWindow.stopMenuImage);
gtk_widget_add_accelerator(g_MainWindow.stopMenuItem, "activate", g_MainWindow.accelGroup, GDK_Escape, 0, GTK_ACCEL_VISIBLE);
g_signal_connect(g_MainWindow.stopMenuItem, "activate", G_CALLBACK(callback_stop_emulation), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.stopMenuItem);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
g_MainWindow.saveStateMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("Sa_ve State"));
g_MainWindow.saveStateMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.saveStateMenuItem), g_MainWindow.saveStateMenuImage);
gtk_widget_add_accelerator(g_MainWindow.saveStateMenuItem, "activate", g_MainWindow.accelGroup, GDK_F5, 0, GTK_ACCEL_VISIBLE);
g_signal_connect(g_MainWindow.saveStateMenuItem, "activate", G_CALLBACK(callback_save_state), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.saveStateMenuItem);
g_MainWindow.saveStateAsMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("Save State _as..."));
g_MainWindow.saveStateAsMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.saveStateAsMenuItem), g_MainWindow.saveStateAsMenuImage);
g_signal_connect(g_MainWindow.saveStateAsMenuItem, "activate", G_CALLBACK(callback_save_state_as), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.saveStateAsMenuItem);
g_MainWindow.loadStateMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("_Load State"));
g_MainWindow.loadStateMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.loadStateMenuItem), g_MainWindow.loadStateMenuImage);
gtk_widget_add_accelerator(g_MainWindow.loadStateMenuItem, "activate", g_MainWindow.accelGroup, GDK_F7, 0, GTK_ACCEL_VISIBLE);
g_signal_connect(g_MainWindow.loadStateMenuItem, "activate", G_CALLBACK(callback_load_state), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.loadStateMenuItem);
g_MainWindow.loadStateFromMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("L_oad State from..."));
g_MainWindow.loadStateFromMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.loadStateFromMenuItem), g_MainWindow.loadStateFromMenuImage);
g_signal_connect(g_MainWindow.loadStateFromMenuItem, "activate", G_CALLBACK(callback_load_state_from), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.loadStateFromMenuItem);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
/* Slot submenu. */
submenuitem = gtk_menu_item_new_with_mnemonic(tr("_Current Save State Slot"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu), submenuitem);
submenu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), submenu);
item = gtk_radio_menu_item_new(NULL);
char buffer[128];
for(i = 0; i < 10; ++i)
{
snprintf(buffer, 128, tr(" Slot _%d"), i); /* Mnemonic needed even with accelerator. */
item = gtk_radio_menu_item_new_with_mnemonic_from_widget(GTK_RADIO_MENU_ITEM(item), buffer);
g_object_set_data(G_OBJECT(item), "slot_num", GUINT_TO_POINTER(i));
gtk_widget_add_accelerator(item, "activate", g_MainWindow.accelUnsafe, GDK_0+i, 0, GTK_ACCEL_VISIBLE);
g_signal_connect(item, "activate", G_CALLBACK(callback_change_slot), GUINT_TO_POINTER(i));
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
}
/* Set callback so save state slot menu is updated everytime it's opened. */
g_signal_connect(submenuitem, "activate", G_CALLBACK(callback_update_slot), gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)));
/* Options menu. */
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_mnemonic(tr("_Options"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(g_MainWindow.menuBar), menuitem);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Configure..."));
g_MainWindow.configureMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.configureMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_configure), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
item = gtk_image_menu_item_new_with_mnemonic(tr("_Graphics Settings..."));
g_MainWindow.graphicsMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.graphicsMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_configure_graphics), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Audio Settings..."));
g_MainWindow.audioMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.audioMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_configure_audio), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_image_menu_item_new_with_mnemonic(tr("_Input Settings..."));
g_MainWindow.inputMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.inputMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_configure_input), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_image_menu_item_new_with_mnemonic(tr("_RSP Settings..."));
g_MainWindow.rspMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.rspMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_configure_rsp), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
item = gtk_menu_item_new_with_mnemonic(tr("C_heats..."));
g_signal_connect(item, "activate", G_CALLBACK(cb_cheatDialog), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
g_MainWindow.fullscreenMenuItem = gtk_image_menu_item_new_with_mnemonic(tr("_Full Screen"));
g_MainWindow.fullscreenMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(g_MainWindow.fullscreenMenuItem), g_MainWindow.fullscreenMenuImage);
gtk_widget_add_accelerator(g_MainWindow.fullscreenMenuItem, "activate", g_MainWindow.accelGroup, GDK_Return, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(item, "activate", G_CALLBACK(callback_fullscreen), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_MainWindow.fullscreenMenuItem);
/* View menu. */
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_mnemonic(tr("_View"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
g_signal_connect_object(menuitem, "activate", G_CALLBACK(callback_update_view), menu, G_CONNECT_SWAPPED);
gtk_menu_shell_append(GTK_MENU_SHELL(g_MainWindow.menuBar), menuitem);
/* Note: we must use embedded data since g_callbacks don't reference pointers
and not all widgets have been created. */
item = gtk_check_menu_item_new_with_mnemonic(tr(" _Toolbar"));
g_object_set_data(G_OBJECT(item), "toggle_object", GUINT_TO_POINTER(TOOLBAR));
g_signal_connect(item, "toggled", G_CALLBACK(callback_toggle_view), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_check_menu_item_new_with_mnemonic(tr(" _Filter"));
g_object_set_data(G_OBJECT(item), "toggle_object", GUINT_TO_POINTER(FILTER));
g_signal_connect(item, "toggled", G_CALLBACK(callback_toggle_view), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
item = gtk_check_menu_item_new_with_mnemonic(tr(" _Statusbar"));
g_object_set_data(G_OBJECT(item), "toggle_object", GUINT_TO_POINTER(STATUSBAR));
g_signal_connect(item, "toggled", G_CALLBACK(callback_toggle_view), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* Debugger submenu. */
#ifdef DBG
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
GtkWidget* debuggerMenu;
GtkWidget* debuggerMenuItem;
debuggerMenu = gtk_menu_new();
debuggerMenuItem = gtk_menu_item_new_with_mnemonic(tr("_Debugger"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(debuggerMenuItem), debuggerMenu);
item = gtk_check_menu_item_new_with_mnemonic(tr(" _Enable"));
g_signal_connect(item, "toggled", G_CALLBACK(callback_debuggerEnableToggled), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), item);
debuggerRegistersShow = gtk_menu_item_new_with_mnemonic(tr("_Registers"));
g_signal_connect(debuggerRegistersShow, "activate", G_CALLBACK(callback_debuggerWindowShow), (gpointer)1);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), debuggerRegistersShow);
debuggerBreakpointsShow = gtk_menu_item_new_with_mnemonic(tr("_Breakpoints"));
g_signal_connect(debuggerBreakpointsShow, "activate", G_CALLBACK(callback_debuggerWindowShow), (gpointer)2);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), debuggerBreakpointsShow);
debuggerTLBShow = gtk_menu_item_new_with_mnemonic(tr("_TLB"));
g_signal_connect(debuggerTLBShow, "activate", G_CALLBACK(callback_debuggerWindowShow), (gpointer)3);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), debuggerTLBShow);
debuggerMemoryShow = gtk_menu_item_new_with_mnemonic(tr("_Memory"));
g_signal_connect(debuggerMemoryShow, "activate", G_CALLBACK(callback_debuggerWindowShow), (gpointer)4);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), debuggerMemoryShow);
debuggerVariablesShow = gtk_menu_item_new_with_mnemonic(tr("_Variables"));
g_signal_connect(debuggerVariablesShow, "activate", G_CALLBACK(callback_debuggerWindowShow), (gpointer)5);
gtk_menu_shell_append(GTK_MENU_SHELL(debuggerMenu), debuggerVariablesShow);
if(g_DebuggerEnabled)
gtk_check_menu_item_set_active((GtkCheckMenuItem*)item, TRUE);
else
{
gtk_widget_set_sensitive(GTK_WIDGET(debuggerRegistersShow), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(debuggerBreakpointsShow), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(debuggerTLBShow), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(debuggerMemoryShow), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(debuggerVariablesShow), FALSE);
}
gtk_menu_shell_append(GTK_MENU_SHELL(menu), debuggerMenuItem);
#endif
/* Help menu. */
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_mnemonic(tr("_Help"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(g_MainWindow.menuBar), menuitem);
item = gtk_image_menu_item_new_with_mnemonic(tr("_About..."));
g_MainWindow.aboutMenuImage = gtk_image_new();
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), g_MainWindow.aboutMenuImage);
g_signal_connect(item, "activate", G_CALLBACK(callback_about_mupen64plus), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
}
static void create_toolbar(void)
{
g_MainWindow.toolBar = gtk_toolbar_new();
gtk_toolbar_set_orientation(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_ORIENTATION_HORIZONTAL);
switch(config_get_number("ToolbarStyle", 0))
{
case 1:
gtk_toolbar_set_style(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOLBAR_TEXT);
break;
case 2:
gtk_toolbar_set_style(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOLBAR_BOTH);
break;
default:
gtk_toolbar_set_style(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOLBAR_ICONS);
}
gtk_toolbar_set_tooltips(GTK_TOOLBAR(g_MainWindow.toolBar), TRUE);
g_MainWindow.openButtonImage = gtk_image_new();
g_MainWindow.playButtonImage = gtk_image_new();
g_MainWindow.pauseButtonImage = gtk_image_new();
g_MainWindow.stopButtonImage = gtk_image_new();
g_MainWindow.saveStateButtonImage = gtk_image_new();
g_MainWindow.loadStateButtonImage = gtk_image_new();
g_MainWindow.fullscreenButtonImage = gtk_image_new();
g_MainWindow.configureButtonImage = gtk_image_new();
GtkToolItem* item;
/* Add icons to toolbar. */
item = gtk_tool_button_new(g_MainWindow.openButtonImage, tr("Open Rom"));
gtk_widget_set_tooltip_text(GTK_WIDGET(item), tr("Open Rom"));
g_signal_connect(item, "clicked", G_CALLBACK(callback_open_rom), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), item, 0);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), gtk_separator_tool_item_new(), 1);
g_MainWindow.playButtonItem = GTK_WIDGET(gtk_toggle_tool_button_new());
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(g_MainWindow.playButtonItem), g_MainWindow.playButtonImage);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(g_MainWindow.playButtonItem), tr("Start"));
gtk_widget_set_tooltip_text(g_MainWindow.playButtonItem, tr("Start Emulation"));
g_signal_connect(g_MainWindow.playButtonItem, "toggled", G_CALLBACK(callback_start_emulation), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.playButtonItem), 2);
g_MainWindow.pauseButtonItem = GTK_WIDGET(gtk_toggle_tool_button_new());
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(g_MainWindow.pauseButtonItem), g_MainWindow.pauseButtonImage);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(g_MainWindow.pauseButtonItem), tr("Pause"));
gtk_widget_set_tooltip_text(g_MainWindow.pauseButtonItem, tr("Pause/ Continue Emulation"));
g_signal_connect(g_MainWindow.pauseButtonItem, "toggled", G_CALLBACK(callback_pause_emulation), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.pauseButtonItem), 3);
g_MainWindow.stopButtonItem = GTK_WIDGET(gtk_toggle_tool_button_new());
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(g_MainWindow.stopButtonItem), g_MainWindow.stopButtonImage);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(g_MainWindow.pauseButtonItem), tr("Stop"));
gtk_widget_set_tooltip_text(g_MainWindow.stopButtonItem, tr("Stop Emulation"));
g_signal_connect(g_MainWindow.stopButtonItem, "toggled", G_CALLBACK(callback_stop_emulation), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.stopButtonItem), 4);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), gtk_separator_tool_item_new(), 5);
g_MainWindow.saveStateButtonItem = GTK_WIDGET(gtk_tool_button_new(g_MainWindow.saveStateButtonImage, tr("Save State")));
gtk_widget_set_tooltip_text(g_MainWindow.saveStateButtonItem, tr("Save State"));
g_signal_connect(g_MainWindow.saveStateButtonItem, "clicked", G_CALLBACK(callback_save_state), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.saveStateButtonItem), 6);
g_MainWindow.loadStateButtonItem = GTK_WIDGET(gtk_tool_button_new(g_MainWindow.loadStateButtonImage, tr("Load State")));
gtk_widget_set_tooltip_text(g_MainWindow.loadStateButtonItem, tr("Load State"));
g_signal_connect(g_MainWindow.loadStateButtonItem, "clicked", G_CALLBACK(callback_load_state), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.loadStateButtonItem), 7);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), gtk_separator_tool_item_new(), 8);
item = gtk_tool_button_new(g_MainWindow.configureButtonImage, tr("Configure"));
gtk_widget_set_tooltip_text(GTK_WIDGET(item), tr("Configure"));
g_signal_connect(item, "clicked", G_CALLBACK(callback_configure), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), item, 9);
g_MainWindow.fullscreenButtonItem = GTK_WIDGET(gtk_tool_button_new(g_MainWindow.fullscreenButtonImage, tr("Fullscreen")));
gtk_widget_set_tooltip_text(GTK_WIDGET(g_MainWindow.fullscreenButtonItem), tr("Fullscreen"));
g_signal_connect(g_MainWindow.fullscreenButtonItem, "clicked", G_CALLBACK(callback_fullscreen), NULL);
gtk_toolbar_insert(GTK_TOOLBAR(g_MainWindow.toolBar), GTK_TOOL_ITEM(g_MainWindow.fullscreenButtonItem), 10);
gtk_box_pack_start(GTK_BOX(g_MainWindow.toplevelVBox), g_MainWindow.toolBar, FALSE, FALSE, 0);
}
static void create_statusbar(void)
{
g_MainWindow.statusBarHBox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_end(GTK_BOX(g_MainWindow.toplevelVBox), g_MainWindow.statusBarHBox, FALSE, FALSE, 0);
g_MainWindow.statusBar = gtk_statusbar_new();
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(g_MainWindow.statusBar), FALSE);
gtk_box_pack_start(GTK_BOX(g_MainWindow.statusBarHBox), g_MainWindow.statusBar, TRUE , TRUE, 0);
}
static void create_mainWindow(void)
{
/* Setup main window. */
gint width, height, xposition, yposition;
width = config_get_number("MainWindowWidth", 600);
height = config_get_number("MainWindowHeight", 400);
xposition = config_get_number("MainWindowXPosition", 0);
yposition = config_get_number("MainWindowYPosition", 0);
GdkDisplay* display = gdk_display_get_default();
GdkScreen* screen = gdk_display_get_default_screen(display);
gint screenwidth = gdk_screen_get_width(screen);
gint screenheight = gdk_screen_get_height(screen);
if(xposition>screenwidth)
xposition = 0;
if(yposition>screenheight)
yposition = 0;
if(width>screenwidth)
width = 600;
if(height>screenheight)
height = 400;
if((xposition+width)>screenwidth)
xposition = screenwidth - width;
if((yposition+height)>screenheight)
yposition = screenheight - height;
g_MainWindow.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(g_MainWindow.window), MUPEN_NAME " v" MUPEN_VERSION);
gtk_window_set_default_size(GTK_WINDOW(g_MainWindow.window), width, height);
gtk_window_move(GTK_WINDOW(g_MainWindow.window), xposition, yposition);
GdkPixbuf *mupen64plus16, *mupen64plus32;
mupen64plus16 = gdk_pixbuf_new_from_file(get_iconpath("16x16/mupen64plus.png"), NULL);
mupen64plus32 = gdk_pixbuf_new_from_file(get_iconpath("32x32/mupen64plus.png"), NULL);
GList* iconlist = NULL;
iconlist = g_list_append(iconlist, mupen64plus16);
iconlist = g_list_append(iconlist, mupen64plus16);
gtk_window_set_icon_list(GTK_WINDOW(g_MainWindow.window), iconlist);
/* Edit gtk on quit. */
g_signal_connect(g_MainWindow.window, "delete_event", G_CALLBACK(callback_mainWindowDeleteEvent), NULL);
/* Toplevel vbox, parent to all GUI widgets. */
g_MainWindow.toplevelVBox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(g_MainWindow.window), g_MainWindow.toplevelVBox);
create_menubar();
create_toolbar();
create_filter();
/* Setup rombrowser. */
int value = config_get_number("RomSortType", 16);
if(value!=GTK_SORT_ASCENDING&&value!=GTK_SORT_DESCENDING)
{
g_MainWindow.romSortType = GTK_SORT_ASCENDING;
config_put_number("RomSortType",GTK_SORT_ASCENDING);
}
else
g_MainWindow.romSortType = value;
value = config_get_number("RomSortColumn", 17);
if(value<0||value>16)
{
g_MainWindow.romSortColumn = 1;
config_put_number("RomSortColumn", 1);
}
else
g_MainWindow.romSortColumn = value;
create_romBrowser();
create_statusbar();
}