diff --git a/gtk3/main.c b/gtk3/main.c index 613ee25..4a4d1b3 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -15,7 +15,7 @@ typedef struct UserData { bool fullscreen; GFile *file; - gchar *bootrom_path; + gchar *boot_rom_path; gchar *config_path; GB_model_t model; } UserData; @@ -25,7 +25,7 @@ typedef struct{ uint16_t w, h; } Rect; -static void run(UserData *user_data); +static void run(GApplication *app, UserData *user_data); static GtkApplication *main_application; static GtkBuilder *builder; @@ -209,7 +209,8 @@ static GMenuModel *get_menu_model(GApplication *app, const char *id) { } static void quit(GApplication *app) { - g_application_quit(app); + // Tell our own main loop to quit. + // This will allow our run() and therefore our activate() methods to end. running = false; } @@ -414,7 +415,6 @@ G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_da g_print("New value: %s\n", gtk_combo_box_get_active_id(box)); } - // This functions gets called immediately after registration of the GApplication static void startup(GApplication *app, gpointer user_data_gptr) { UserData *user_data = user_data_gptr; @@ -533,7 +533,7 @@ static void activate(GApplication *app, gpointer user_data_gptr) { // Start the emulation loop. // This loop takes care of the GTK main loop. - run(user_data); + run(app, user_data); } // This function gets called when there are files to open. @@ -552,6 +552,7 @@ static void open(GApplication *app, GFile **files, gint n_files, const gchar *hi activate(app, user_data_gptr); } +// This function gets called when the application is closed. static void shutdown(GApplication *app, GFile **files, gint n_files, const gchar *hint, gpointer user_data_gptr) { g_print("SHUTDOWN\n"); @@ -671,7 +672,7 @@ static void update_window_geometry() { image_buffers[2] = malloc(buffer_size); } -static void run(UserData *user_data) { +static void run(GApplication *app, UserData *user_data) { GB_model_t prev_model = GB_get_model(&gb); GB_model_t model = user_data->model? user_data->model : GB_MODEL_CGB_E; // TODO: Model from config @@ -704,54 +705,67 @@ static void run(UserData *user_data) { GError *error; char *boot_rom_path; + char *boot_rom_name; GBytes *boot_rom_f; const guchar *boot_rom_data; gsize boot_rom_size; - if (user_data->bootrom_path) { - g_print("Trying to load boot ROM from %s\n", user_data->bootrom_path); - if (GB_load_boot_rom(&gb, user_data->bootrom_path)) { - g_printerr("Falling back to internal boot ROM\n"); - goto internal_bootrom; + if (user_data->boot_rom_path) { + g_print("Trying to load boot ROM from %s\n", user_data->boot_rom_path); + if (GB_load_boot_rom(&gb, user_data->boot_rom_path)) { + g_printerr("Falling back to boot ROM from config\n"); + goto config_boot_rom; } } - else { internal_bootrom: + else { config_boot_rom: switch (model) { case GB_MODEL_DMG_B: - boot_rom_path = RESOURCE_PREFIX "bootroms/dmg_boot.bin"; + boot_rom_name = "dmg_boot.bin"; break; case GB_MODEL_SGB: case GB_MODEL_SGB_PAL: case GB_MODEL_SGB_NO_SFC: - boot_rom_path = RESOURCE_PREFIX "bootroms/sgb_boot.bin"; + boot_rom_name = "sgb_boot.bin"; break; case GB_MODEL_SGB2: case GB_MODEL_SGB2_NO_SFC: - boot_rom_path = RESOURCE_PREFIX "bootroms/sgb2_boot.bin"; + boot_rom_name = "sgb2_boot.bin"; break; case GB_MODEL_CGB_C: case GB_MODEL_CGB_E: - boot_rom_path = RESOURCE_PREFIX "bootroms/cgb_boot.bin"; + boot_rom_name = "cgb_boot.bin"; break; case GB_MODEL_AGB: - boot_rom_path = RESOURCE_PREFIX "bootroms/agb_boot.bin"; + boot_rom_name = "agb_boot.bin"; break; } - boot_rom_f = g_resources_lookup_data(boot_rom_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &error); - - if (boot_rom_f == NULL) { - g_printerr("Failed to load internal boot ROM: %s\n", boot_rom_path); - g_error_free(error); - exit(EXIT_FAILURE); + if (config.boot_rom_path != NULL) { + boot_rom_path = g_build_filename(config.boot_rom_path, boot_rom_name, NULL); + g_print("Trying to load boot ROM from %s\n", boot_rom_path); + + if (GB_load_boot_rom(&gb, boot_rom_path)) { + g_printerr("Falling back to internal boot ROM\n"); + goto internal_boot_rom; + } } + else { internal_boot_rom: + boot_rom_path = g_build_filename(RESOURCE_PREFIX "bootroms/", boot_rom_name, NULL); + boot_rom_f = g_resources_lookup_data(boot_rom_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &error); - boot_rom_data = g_bytes_get_data(boot_rom_f, &boot_rom_size); - GB_load_boot_rom_from_buffer(&gb, boot_rom_data, boot_rom_size); + if (boot_rom_f == NULL) { + g_printerr("Failed to load internal boot ROM: %s\n", boot_rom_path); + g_error_free(error); + exit(EXIT_FAILURE); + } + + boot_rom_data = g_bytes_get_data(boot_rom_f, &boot_rom_size); + GB_load_boot_rom_from_buffer(&gb, boot_rom_data, boot_rom_size); + } } if (user_data->file != NULL) { @@ -779,6 +793,10 @@ static void run(UserData *user_data) { GB_run(&gb); } } + + // Quit our application properly. + // This fires the “shutdown” signal. + g_application_quit(app); } int main(int argc, char *argv[]) { @@ -791,7 +809,7 @@ int main(int argc, char *argv[]) { GOptionEntry entries[] = { { "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL }, { "fullscreen", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Start in fullscreen mode", NULL }, - { "bootrom", 'b', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &user_data.bootrom_path, "Path to the boot ROM to use", "" }, + { "bootrom", 'b', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &user_data.boot_rom_path, "Path to the boot ROM to use", "" }, { "model", 'm', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "Override the model type to emulate", "" }, { "config", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &user_data.config_path, "Override the path of the configuration file", "" }, { NULL }