diff --git a/gtk3/main.c b/gtk3/main.c
index 1b4a61d..bcd01a7 100644
--- a/gtk3/main.c
+++ b/gtk3/main.c
@@ -46,7 +46,6 @@ typedef struct GuiData {
struct CliOptionData {
gchar *config_path;
gchar *boot_rom_path;
- gchar *prefix;
gboolean fullscreen;
GB_model_t model;
gboolean force_software_renderer;
@@ -358,8 +357,6 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
// TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_str_has_prefix(model_name, "DMG")) {
- gui_data.cli_options.prefix = "DMG";
-
if (g_str_has_suffix(model_name, "-B") || g_strcmp0(model_name, "DMG") == 0) {
gui_data.cli_options.model = GB_MODEL_DMG_B;
}
@@ -369,8 +366,6 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
}
}
else if (g_str_has_prefix(model_name, "SGB")) {
- gui_data.cli_options.prefix = "SGB";
-
if (g_str_has_suffix(model_name, "-NTSC") || g_strcmp0(model_name, "SGB") == 0) {
gui_data.cli_options.model = GB_MODEL_SGB;
}
@@ -386,8 +381,6 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
}
}
else if (g_str_has_prefix(model_name, "CGB")) {
- gui_data.cli_options.prefix = "CGB";
-
if (g_str_has_suffix(model_name, "-C")) {
gui_data.cli_options.model = GB_MODEL_CGB_C;
}
@@ -400,13 +393,9 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
}
}
else if (g_str_has_prefix(model_name, "AGB")) {
- gui_data.cli_options.prefix = "AGB";
-
gui_data.cli_options.model = GB_MODEL_AGB;
}
else {
- gui_data.cli_options.prefix = NULL;
-
g_warning("Unknown model: %s", model_name);
exit(EXIT_FAILURE);
}
@@ -818,17 +807,87 @@ static char *async_console_input(GB_gameboy_t *gb) {
GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
GtkWidget *menu = gtk_menu_new();
- g_autoptr(GList) iter = gtk_container_get_children(GTK_CONTAINER (menubar));
+ g_autoptr(GList) iter = gtk_container_get_children(GTK_CONTAINER(menubar));
while (iter) {
GtkWidget *item = GTK_WIDGET(iter->data);
gtk_widget_reparent(item, menu);
- iter = g_list_next(iter);
+ iter = iter->next;
}
return menu;
}
+// Creating these items in the UI defintion files was buggy in some desktop
+// environments and the manual call of `g_signal_connect` was needed anyway
+// because the UI definition can’t define string arguments for signal handlers.
+static void create_model_menu_items() {
+ void on_change_model(GtkCheckMenuItem *check_menu_item, const gchar *model_str);
+
+ static const char *const model_names[] = {
+ "Game Boy",
+ "Super Game Boy",
+ "Game Boy Color",
+ "Game Boy Advance"
+ };
+
+ static const char *const model_codes[] = {
+ "DMG",
+ "SGB",
+ "CGB",
+ "GBA"
+ };
+
+ // Find the menu item index of the previous sibling of the new menu items
+ GtkWidget *before = builder_get(GTK_WIDGET, "before_model_changer");
+ GtkContainer *parent = GTK_CONTAINER(gtk_widget_get_parent(before));
+ g_autoptr(GList) list = gtk_container_get_children(parent);
+ gint position = g_list_index(list, before);
+
+ GSList *group = NULL;
+ for (int i = 0; i < sizeof(model_names) / sizeof(const char*); i++) {
+ // Create a new menu item
+ GtkWidget *item = gtk_radio_menu_item_new_with_label(group, model_names[i]);
+
+ // Add it to the existing menu
+ gtk_menu_shell_insert(GTK_MENU_SHELL(parent), item, ++position);
+ g_signal_connect(item, "toggled", G_CALLBACK(on_change_model), (gpointer) model_codes[i]);
+
+ if (g_strcmp0(config.emulation.model, model_codes[i]) == 0) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), true);
+ }
+
+ if (i == 0) group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
+ }
+
+ static const char *const peripheral_names[] = {
+ "None",
+ "Game Boy Printer",
+ };
+
+ static const char *const peripheral_codes[] = {
+ "NONE",
+ "PRINTER",
+ };
+
+ GtkMenuShell *link_menu = builder_get(GTK_MENU_SHELL, "link_menu");
+ group = NULL;
+ position = 0;
+ for (int i = 0; i < sizeof(peripheral_names) / sizeof(const char*); i++) {
+ // Create a new menu item
+ GtkWidget *item = gtk_radio_menu_item_new_with_label(group, peripheral_names[i]);
+
+ // Add it to the existing menu
+ gtk_menu_shell_insert(link_menu, item, position++);
+ // g_signal_connect(item, "toggled", G_CALLBACK(on_change_linked_device, (gpointer) peripheral_codes[i]);
+
+ if (i == 0) {
+ group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), true);
+ }
+ }
+}
+
// Create our application’s menu.
//
// This function tries to stick to the desktop environment’s conventions.
@@ -836,72 +895,10 @@ GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
// the desktop environment shell handle the menu if it signals support for it
// or uses a standard menubar inside the window.
static void setup_menu(GApplication *app) {
+ create_model_menu_items();
+
GtkMenuBar *menubar = builder_get(GTK_MENU_BAR, "main_menu");
- enum menubar_type_t menubar_type = get_show_menubar();
-
- // Try to use a sane default
- if (menubar_type == MENUBAR_AUTO) {
- GtkSettings *settings = gtk_settings_get_default();
- gboolean show_in_shell;
- g_object_get(settings, "gtk-shell-shows-menubar", &show_in_shell, NULL);
-
- const gchar *xdg_current_desktop = g_getenv("XDG_CURRENT_DESKTOP");
- const gchar *gdm_session = g_getenv("GDMSESSION");
- const gchar *desktop_session = g_getenv("DESKTOP_SESSION");
-
- gchar *desktop = (gchar *)xdg_current_desktop;
- if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)gdm_session;
- if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)desktop_session;
-
- g_debug("XDG_CURRENT_DESKTOP: %s\nGDMSESSION: %s\nDESKTOP_SESSION: %s\nChosen value: %s\nShow menu in shell: %d", xdg_current_desktop, gdm_session, desktop_session, desktop, show_in_shell);
-
- if (desktop != NULL && show_in_shell) {
- menubar_type = MENUBAR_SHOW_IN_SHELL;
- }
- else if (desktop != NULL && g_str_match_string("GNOME", desktop, false)) {
- if (g_str_match_string("GNOME-Flashback", desktop, false) || g_str_match_string("GNOME-Classic", desktop, false)) {
- menubar_type = MENUBAR_SHOW_IN_WINDOW;
- }
- else if (gdm_session != NULL && (g_str_match_string("gnome-classic", gdm_session, false) || g_str_match_string("gnome-flashback", gdm_session, false))) {
- menubar_type = MENUBAR_SHOW_IN_WINDOW;
- }
- else {
- menubar_type = MENUBAR_SHOW_HAMBURGER;
- }
- }
- else {
- menubar_type = MENUBAR_SHOW_IN_WINDOW;
- }
- }
-
- switch (menubar_type) {
- case MENUBAR_AUTO:
- g_warning("Unreachable");
- break;
-
- case MENUBAR_SHOW_IN_SHELL:
- case MENUBAR_SHOW_IN_WINDOW: {
- g_debug("Showing menu in the window");
- gtk_box_pack_start(GTK_BOX(gui_data.main_window_container), GTK_WIDGET(menubar), false, false, 0);
- break;
- }
-
- case MENUBAR_SHOW_HAMBURGER: {
- g_debug("Showing hamburger");
- // Attach a custom title bar
- GtkWidget *titlebar = builder_get(GTK_WIDGET, "main_header_bar");
- gtk_header_bar_set_title(GTK_HEADER_BAR(titlebar), gtk_window_get_title(GTK_WINDOW(gui_data.main_window)));
- gtk_window_set_titlebar(GTK_WINDOW(gui_data.main_window), titlebar);
-
- // Disable menubar
- gtk_application_set_menubar(GTK_APPLICATION(app), NULL);
-
- // Hook menubar up to the hamburger button
- GtkMenuButton *hamburger_button = GTK_MENU_BUTTON(get_object("hamburger_button"));
- gtk_menu_button_set_popup(hamburger_button, GTK_WIDGET(menubar_to_menu(menubar)));
- break;
- }
- }
+ gtk_box_pack_start(GTK_BOX(gui_data.main_window_container), GTK_WIDGET(menubar), false, false, 0);
}
// Determines if a ComboBox entry should be converted into a separator.
@@ -963,6 +960,42 @@ static void flip(void) {
gui_data.current_buffer = (gui_data.current_buffer + 1) % number_of_buffers();
}
+static void update_viewport(void) {
+ GtkWidget *w = gui_data.fallback_canvas ? GTK_WIDGET(gui_data.fallback_canvas) : GTK_WIDGET(gui_data.gl_area);
+
+ int win_width = gtk_widget_get_allocated_width(w);
+ int win_height = gtk_widget_get_allocated_height(w);
+
+ double x_factor = win_width / (double) GB_get_screen_width(&gb);
+ double y_factor = win_height / (double) GB_get_screen_height(&gb);
+
+ if (config.video.use_integer_scaling) {
+ x_factor = (int)(x_factor);
+ y_factor = (int)(y_factor);
+ }
+
+ if (config.video.keep_aspect_ratio) {
+ if (x_factor > y_factor) {
+ x_factor = y_factor;
+ }
+ else {
+ y_factor = x_factor;
+ }
+ }
+
+ unsigned new_width = x_factor * GB_get_screen_width(&gb);
+ unsigned new_height = y_factor * GB_get_screen_height(&gb);
+
+ gui_data.viewport = (Rect){
+ (win_width - new_width) / 2,
+ (win_height - new_height) / 2,
+ new_width,
+ new_height
+ };
+
+ if (!gui_data.fallback_canvas) glViewport(gui_data.viewport.x, gui_data.viewport.y, gui_data.viewport.w, gui_data.viewport.h);
+}
+
// WHY DO WE NEED SUCH AN UGLY METHOD, GTK?!
static void action_entries_set_enabled(const GActionEntry *entries, unsigned n_entries, bool value) {
// Assumes null-terminated if n_entries == -1
@@ -978,15 +1011,20 @@ static void update_window_geometry(void) {
g_debug("update_window_geometry: %u×%u → %u×%u", gui_data.last_screen_width, gui_data.last_screen_height, GB_get_screen_width(&gb), GB_get_screen_height(&gb));
GtkWidget *w = gui_data.fallback_canvas ? GTK_WIDGET(gui_data.fallback_canvas) : GTK_WIDGET(gui_data.gl_area);
- int win_width = gtk_widget_get_allocated_width(w);
- int win_height = gtk_widget_get_allocated_height(w);
- unsigned new_width = GB_get_screen_width(&gb) * 2;
- unsigned new_height = GB_get_screen_height(&gb) * 2;
+ signed win_width = gtk_widget_get_allocated_width(w);
+ signed win_height = gtk_widget_get_allocated_height(w);
+ signed menu_height = gtk_widget_get_allocated_height(builder_get(GTK_WIDGET, "main_menu"));
+
+ unsigned _factor = win_width > win_height ? win_width / GB_get_screen_width(&gb) : win_height / GB_get_screen_height(&gb);
+ unsigned factor = _factor < 2 ? 2 : _factor;
+
+ unsigned new_width = GB_get_screen_width(&gb) * factor;
+ unsigned new_height = GB_get_screen_height(&gb) * factor + menu_height;
// Set size hints
GdkGeometry hints;
hints.min_width = GB_get_screen_width(&gb);
- hints.min_height = GB_get_screen_height(&gb);
+ hints.min_height = GB_get_screen_height(&gb) + menu_height;
gtk_window_set_geometry_hints(
GTK_WINDOW(gui_data.main_window),
@@ -1016,6 +1054,8 @@ static void update_window_geometry(void) {
if (GB_is_inited(&gb)) {
GB_set_pixels_output(&gb, get_pixels());
}
+
+ update_viewport();
}
static void stop(void) {
@@ -1989,20 +2029,9 @@ static void startup(GApplication *app, gpointer null_ptr) {
create_action_groups(app);
- if (gui_data.cli_options.prefix != NULL) {
- // TODO
-
- //GAction *action = g_action_map_lookup_action(G_ACTION_MAP(gui_data.main_application), "change_model");
- //g_action_change_state(action, g_variant_new_string(gui_data.cli_options.prefix));
- }
-
#if NDEBUG
// Disable when not compiled in debug mode
action_set_enabled(app, "open_gtk_debugger", false);
-
- // Remove the menubar override
- gtk_widget_destroy(builder_get(GTK_WIDGET, "menubar_override_selector_label"));
- gtk_widget_destroy(builder_get(GTK_WIDGET, "menubar_override_selector"));
#endif
gui_data.preferences = GTK_WINDOW(get_object("preferences"));
@@ -2138,48 +2167,6 @@ static void connect_signal_handlers(GApplication *app) {
g_signal_connect(get_object("vram_viewer_tilemap_canvas"), "motion_notify_event", G_CALLBACK(on_motion_vram_viewer_tilemap), NULL);
g_signal_connect(get_object("vram_viewer_stack"), "notify::visible-child", G_CALLBACK(on_vram_tab_change), NULL);
-
- // We can’t set these values in the UI definition file
- g_signal_connect(get_object("change_model_dmg"), "toggled", G_CALLBACK(on_change_model), (gpointer) "DMG");
- g_signal_connect(get_object("change_model_sgb"), "toggled", G_CALLBACK(on_change_model), (gpointer) "SGB");
- g_signal_connect(get_object("change_model_cgb"), "toggled", G_CALLBACK(on_change_model), (gpointer) "CGB");
- g_signal_connect(get_object("change_model_agb"), "toggled", G_CALLBACK(on_change_model), (gpointer) "AGB");
-}
-
-static void update_viewport(void) {
- GtkWidget *w = gui_data.fallback_canvas ? GTK_WIDGET(gui_data.fallback_canvas) : GTK_WIDGET(gui_data.gl_area);
-
- int win_width = gtk_widget_get_allocated_width(w);
- int win_height = gtk_widget_get_allocated_height(w);
-
- double x_factor = win_width / (double) GB_get_screen_width(&gb);
- double y_factor = win_height / (double) GB_get_screen_height(&gb);
-
- if (config.video.use_integer_scaling) {
- x_factor = (int)(x_factor);
- y_factor = (int)(y_factor);
- }
-
- if (config.video.keep_aspect_ratio) {
- if (x_factor > y_factor) {
- x_factor = y_factor;
- }
- else {
- y_factor = x_factor;
- }
- }
-
- unsigned new_width = x_factor * GB_get_screen_width(&gb);
- unsigned new_height = y_factor * GB_get_screen_height(&gb);
-
- gui_data.viewport = (Rect){
- (win_width - new_width) / 2,
- (win_height - new_height) / 2,
- new_width,
- new_height
- };
-
- if (!gui_data.fallback_canvas) glViewport(gui_data.viewport.x, gui_data.viewport.y, gui_data.viewport.w, gui_data.viewport.h);
}
// TODO: Comment
@@ -2362,6 +2349,8 @@ static void activate(GApplication *app, gpointer null_ptr) {
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(gui_data.main_window));
gtk_widget_show_all(GTK_WIDGET(gui_data.main_window));
+ update_window_geometry();
+
// Start the emulation thread
run();
}
@@ -2623,10 +2612,6 @@ G_MODULE_EXPORT void on_monochrome_palette_changed(GtkWidget *w, gpointer user_d
GB_set_palette(&gb, get_monochrome_palette());
}
-G_MODULE_EXPORT void on_color_menubar_override_changed(GtkWidget *w, gpointer user_data_ptr) {
- config.window.menubar_override = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
-}
-
G_MODULE_EXPORT void on_dmg_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.dmg_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui
index 645ed51..b275a65 100644
--- a/gtk3/resources/ui/window.ui
+++ b/gtk3/resources/ui/window.ui
@@ -1206,26 +1206,6 @@ Maximilian Mader https://github.com/max-m
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gtk3/settings.c b/gtk3/settings.c
index c399b45..639a1cc 100644
--- a/gtk3/settings.c
+++ b/gtk3/settings.c
@@ -146,15 +146,6 @@ void on_preferences_realize(GtkWidget *w, gpointer builder_ptr) {
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "analog_speed_controls_toggle"), config.controls.analog_speed_controls);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rumble_mode_selector"), config.controls.rumble_mode);
-
- #if ! NDEBUG
- gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "menubar_override_selector"), config.window.menubar_override);
- #else
- if (builder_get(GTK_COMBO_BOX, "menubar_override_selector") != NULL) {
- gtk_widget_destroy(GTK_WIDGET(builder_get(GTK_COMBO_BOX, "menubar_override_selector")));
- gtk_widget_destroy(GTK_WIDGET(builder_get(GTK_COMBO_BOX, "menubar_override_selector_label")));
- }
- #endif
}
void init_settings(GApplication *app, gchar *path, GDateTime **modification_date, GtkWindow *preferences) {
@@ -259,44 +250,6 @@ void update_boot_rom_selector(GtkBuilder *builder) {
gtk_combo_box_text_append(combo_box, "other", "Other");
}
-enum menubar_type_t get_show_menubar(void) {
- if (config.window.menubar_override == NULL) goto default_value;
-
- if (g_strcmp0(config.window.menubar_override, "auto") == 0) {
- return MENUBAR_AUTO;
- }
- else if (g_strcmp0(config.window.menubar_override, "show_in_shell") == 0) {
- return MENUBAR_SHOW_IN_SHELL;
- }
- else if (g_strcmp0(config.window.menubar_override, "show_in_window") == 0) {
- return MENUBAR_SHOW_IN_WINDOW;
- }
- else if (g_strcmp0(config.window.menubar_override, "show_hamburger") == 0) {
- return MENUBAR_SHOW_HAMBURGER;
- }
-
- // This should not happen
- g_warning("Unknown menubar setting: %s\nFalling back to “Auto”", config.window.menubar_override);
- default_value: return MENUBAR_AUTO;
-}
-
-void set_show_menubar(enum menubar_type_t value) {
- switch (value) {
- case MENUBAR_AUTO:
- config.window.menubar_override = "auto";
- break;
- case MENUBAR_SHOW_IN_SHELL:
- config.window.menubar_override = "show_in_shell";
- break;
- case MENUBAR_SHOW_IN_WINDOW:
- config.window.menubar_override = "show_in_window";
- break;
- case MENUBAR_SHOW_HAMBURGER:
- config.window.menubar_override = "show_hamburger";
- break;
- }
-}
-
GB_color_correction_mode_t get_color_correction_mode(void) {
if (config.video.color_correction_id == NULL) goto default_value;
diff --git a/gtk3/settings.h b/gtk3/settings.h
index 0caf1a4..dcea76c 100644
--- a/gtk3/settings.h
+++ b/gtk3/settings.h
@@ -54,7 +54,7 @@
EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \
) \
EXPAND_GROUP(window, \
- EXPAND_GROUP_MEMBER(menubar_override, string, "auto") \
+ \
)
typedef struct config_t {
@@ -69,13 +69,6 @@ typedef struct config_t {
#undef EXPAND_GROUP_MEMBER
} config_t;
-enum menubar_type_t {
- MENUBAR_AUTO,
- MENUBAR_SHOW_IN_SHELL,
- MENUBAR_SHOW_IN_WINDOW,
- MENUBAR_SHOW_HAMBURGER
-};
-
config_t config;
void on_preferences_realize(GtkWidget *w, gpointer builder_ptr);
@@ -90,9 +83,6 @@ void free_settings(void);
void update_boot_rom_selector(GtkBuilder *builder);
-enum menubar_type_t get_show_menubar(void);
-void set_show_menubar(enum menubar_type_t);
-
GB_color_correction_mode_t get_color_correction_mode(void);
void set_color_correction_mode(GB_color_correction_mode_t);