From 27899685166c3c32ef1b6d6202511fa8048b3cda Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:32:17 -0500 Subject: [PATCH 1/8] ui/xui: Add "Recent" under Machine to keep track of recently loaded disc images --- config_spec.yml | 6 +++++ ui/xui/actions.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++++ ui/xui/actions.hh | 2 ++ 3 files changed, 71 insertions(+) diff --git a/config_spec.yml b/config_spec.yml index a18db650315..d24e23aca77 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -19,6 +19,12 @@ general: f7: string f8: string filter_current_game: bool + history: + discs: + type: array + items: + type: string + max_items: 10 input: bindings: diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index e76e6144292..b2b1cbea82f 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -57,6 +57,41 @@ void ActionLoadDiscFile(const char *file_path) if (err) { xemu_queue_error_message(error_get_pretty(err)); error_free(err); + } else { + if (file_path && file_path[0]) { + if (!g_config.general.history.discs) { + g_config.general.history.discs = g_new0(const char *, 1); + g_config.general.history.discs_count = 0; + } + + int i; + for (i = 0; i < g_config.general.history.discs_count; i++) { + if (g_strcmp0(g_config.general.history.discs[i], file_path) == 0) { + for (int j = i; j > 0; j--) { + g_config.general.history.discs[j] = g_config.general.history.discs[j-1]; + } + g_config.general.history.discs[0] = g_strdup(file_path); + break; + } + } + + if (i == g_config.general.history.discs_count) { + if (g_config.general.history.discs_count >= 10) { + g_free((void*)g_config.general.history.discs[9]); + } else { + const char **new_discs = g_renew(const char *, g_config.general.history.discs, + g_config.general.history.discs_count + 1); + g_config.general.history.discs = new_discs; + g_config.general.history.discs_count++; + } + + for (int i = g_config.general.history.discs_count - 1; i > 0; i--) { + g_config.general.history.discs[i] = g_config.general.history.discs[i-1]; + } + g_config.general.history.discs[0] = g_strdup(file_path); + } + } + xemu_settings_save(); } } @@ -112,3 +147,31 @@ void ActionLoadSnapshotChecked(const char *name) { g_snapshot_mgr.LoadSnapshotChecked(name); } + +void ActionLoadDiscFromHistory(int index) +{ + if (index < 0 || index >= g_config.general.history.discs_count) { + return; + } + + const char *file_path = g_config.general.history.discs[index]; + if (!file_path || !file_path[0]) { + return; + } + + if (qemu_access(file_path, F_OK) == -1) { + return; + } + + ActionLoadDiscFile(file_path); +} + +void ActionClearDiscHistory(void) +{ + for (int i = 0; i < g_config.general.history.discs_count; i++) { + g_free((void*)g_config.general.history.discs[i]); + } + g_free(g_config.general.history.discs); + g_config.general.history.discs = NULL; + g_config.general.history.discs_count = 0; +} diff --git a/ui/xui/actions.hh b/ui/xui/actions.hh index d0aff3fd230..a34faac44b1 100644 --- a/ui/xui/actions.hh +++ b/ui/xui/actions.hh @@ -27,3 +27,5 @@ void ActionShutdown(); void ActionScreenshot(); void ActionActivateBoundSnapshot(int slot, bool save); void ActionLoadSnapshotChecked(const char *name); +void ActionLoadDiscFromHistory(int index); +void ActionClearDiscHistory(void); From ff4b1270d79aa7457cebbfc13d423118f12530f9 Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Sun, 16 Nov 2025 22:31:53 -0500 Subject: [PATCH 2/8] Remove hard coded number in yml to prevent desyncs between the code and config file --- config_spec.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config_spec.yml b/config_spec.yml index d24e23aca77..602360b6590 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -24,7 +24,6 @@ general: type: array items: type: string - max_items: 10 input: bindings: From 304cb106c27e02f9712781d34bcc483b9ea628cd Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Sun, 16 Nov 2025 22:38:36 -0500 Subject: [PATCH 3/8] Address code review - Use symbolic constant for entry count - Remove explicit save - Add early return - Add an assert for invalid index - Remove invalid entries --- ui/xui/actions.cc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index b2b1cbea82f..a33a2b0efff 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -24,6 +24,8 @@ #include "../xemu-notifications.h" #include "snapshot-manager.hh" +#define MAX_RECENT_DISCS 10 + void ActionEjectDisc(void) { Error *err = NULL; @@ -71,13 +73,16 @@ void ActionLoadDiscFile(const char *file_path) g_config.general.history.discs[j] = g_config.general.history.discs[j-1]; } g_config.general.history.discs[0] = g_strdup(file_path); - break; + return; } } if (i == g_config.general.history.discs_count) { - if (g_config.general.history.discs_count >= 10) { - g_free((void*)g_config.general.history.discs[9]); + if (g_config.general.history.discs_count >= MAX_RECENT_DISCS) { + for (int j = MAX_RECENT_DISCS; j < g_config.general.history.discs_count; j++) { + g_free((void*)g_config.general.history.discs[j]); + } + g_config.general.history.discs_count = MAX_RECENT_DISCS; } else { const char **new_discs = g_renew(const char *, g_config.general.history.discs, g_config.general.history.discs_count + 1); @@ -91,7 +96,6 @@ void ActionLoadDiscFile(const char *file_path) g_config.general.history.discs[0] = g_strdup(file_path); } } - xemu_settings_save(); } } @@ -150,6 +154,8 @@ void ActionLoadSnapshotChecked(const char *name) void ActionLoadDiscFromHistory(int index) { + g_assert(index >= 0 && index < g_config.general.history.discs_count); + if (index < 0 || index >= g_config.general.history.discs_count) { return; } @@ -160,6 +166,15 @@ void ActionLoadDiscFromHistory(int index) } if (qemu_access(file_path, F_OK) == -1) { + g_free((void*)g_config.general.history.discs[index]); + for (int j = index; j < g_config.general.history.discs_count - 1; j++) { + g_config.general.history.discs[j] = g_config.general.history.discs[j + 1]; + } + g_config.general.history.discs_count--; + if (g_config.general.history.discs_count == 0) { + g_free(g_config.general.history.discs); + g_config.general.history.discs = NULL; + } return; } From 2e93a5ddb89e7170e0154ccf17ade8114282ca3e Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Tue, 18 Nov 2025 18:08:52 -0500 Subject: [PATCH 4/8] ui/xui: Actually add the entry in the menubar (I forgot to upload it) --- ui/xui/menubar.cc | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index 83a0b08ae2c..b13f09ff91c 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -138,6 +138,39 @@ void ShowMainMenu() if (ImGui::MenuItem("Eject Disc", SHORTCUT_MENU_TEXT(E))) ActionEjectDisc(); if (ImGui::MenuItem("Load Disc...", SHORTCUT_MENU_TEXT(O))) ActionLoadDisc(); + if (ImGui::BeginMenu("Recent")) { + bool has_recent = g_config.general.history.discs && g_config.general.history.discs_count > 0; + + if (has_recent) { + for (int i = 0; i < g_config.general.history.discs_count; i++) { + const char *disc_path = g_config.general.history.discs[i]; + if (!disc_path) continue; + + const char *filename = g_path_get_basename(disc_path); + bool file_exists = qemu_access(disc_path, F_OK) != -1; + + if (file_exists) { + if (ImGui::MenuItem(filename)) { + ActionLoadDiscFromHistory(i); + } + } else { + ImGui::MenuItem(filename, NULL, false, false); + } + + g_free((void *)filename); + } + + ImGui::Separator(); + } + + if (ImGui::MenuItem("Clear History")) { + ActionClearDiscHistory(); + xemu_settings_save(); + } + + ImGui::EndMenu(); + } + ImGui::Separator(); if (ImGui::MenuItem("Settings...")) g_main_menu.ShowSettings(); From d03b50fd503244e69daa7b7400cbe2ee9de9b41c Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Fri, 5 Dec 2025 03:24:34 -0500 Subject: [PATCH 5/8] Various cleanups and additions - Renamed History to Recent for consistency - Added a red X so that each entry can be manually deleted - Made it so the "Recent Discs" becomes grey and unclickable if no discs are in the list - Bumped the max disc in the list from 10 to 15 - Added something to clear just the missing discs from the list --- config_spec.yml | 1 - ui/xui/actions.cc | 129 ++++++++++++++++++++++++++++++---------------- ui/xui/actions.hh | 6 ++- ui/xui/menubar.cc | 80 +++++++++++++++++++++------- 4 files changed, 151 insertions(+), 65 deletions(-) diff --git a/config_spec.yml b/config_spec.yml index bc1b2193984..602360b6590 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -151,7 +151,6 @@ display: validation_layers: bool debug_shaders: bool assert_on_validation_msg: bool - preferred_physical_device: string quality: surface_scale: type: integer diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index a33a2b0efff..383822f8217 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -24,7 +24,7 @@ #include "../xemu-notifications.h" #include "snapshot-manager.hh" -#define MAX_RECENT_DISCS 10 +#define MAX_RECENT_DISCS 15 void ActionEjectDisc(void) { @@ -61,39 +61,39 @@ void ActionLoadDiscFile(const char *file_path) error_free(err); } else { if (file_path && file_path[0]) { - if (!g_config.general.history.discs) { - g_config.general.history.discs = g_new0(const char *, 1); - g_config.general.history.discs_count = 0; + if (!g_config.general.recent.discs) { + g_config.general.recent.discs = g_new0(const char *, 1); + g_config.general.recent.discs_count = 0; } int i; - for (i = 0; i < g_config.general.history.discs_count; i++) { - if (g_strcmp0(g_config.general.history.discs[i], file_path) == 0) { + for (i = 0; i < g_config.general.recent.discs_count; i++) { + if (g_strcmp0(g_config.general.recent.discs[i], file_path) == 0) { for (int j = i; j > 0; j--) { - g_config.general.history.discs[j] = g_config.general.history.discs[j-1]; + g_config.general.recent.discs[j] = g_config.general.recent.discs[j-1]; } - g_config.general.history.discs[0] = g_strdup(file_path); + g_config.general.recent.discs[0] = g_strdup(file_path); return; } } - if (i == g_config.general.history.discs_count) { - if (g_config.general.history.discs_count >= MAX_RECENT_DISCS) { - for (int j = MAX_RECENT_DISCS; j < g_config.general.history.discs_count; j++) { - g_free((void*)g_config.general.history.discs[j]); + if (i == g_config.general.recent.discs_count) { + if (g_config.general.recent.discs_count >= MAX_RECENT_DISCS) { + for (int j = MAX_RECENT_DISCS; j < g_config.general.recent.discs_count; j++) { + g_free((void*)g_config.general.recent.discs[j]); } - g_config.general.history.discs_count = MAX_RECENT_DISCS; + g_config.general.recent.discs_count = MAX_RECENT_DISCS; } else { - const char **new_discs = g_renew(const char *, g_config.general.history.discs, - g_config.general.history.discs_count + 1); - g_config.general.history.discs = new_discs; - g_config.general.history.discs_count++; + const char **new_discs = g_renew(const char *, g_config.general.recent.discs, + g_config.general.recent.discs_count + 1); + g_config.general.recent.discs = new_discs; + g_config.general.recent.discs_count++; } - for (int i = g_config.general.history.discs_count - 1; i > 0; i--) { - g_config.general.history.discs[i] = g_config.general.history.discs[i-1]; + for (int i = g_config.general.recent.discs_count - 1; i > 0; i--) { + g_config.general.recent.discs[i] = g_config.general.recent.discs[i-1]; } - g_config.general.history.discs[0] = g_strdup(file_path); + g_config.general.recent.discs[0] = g_strdup(file_path); } } } @@ -152,28 +152,23 @@ void ActionLoadSnapshotChecked(const char *name) g_snapshot_mgr.LoadSnapshotChecked(name); } -void ActionLoadDiscFromHistory(int index) +void ActionLoadDiscFromRecent(unsigned int index) { - g_assert(index >= 0 && index < g_config.general.history.discs_count); + g_assert(index < g_config.general.recent.discs_count); + if (index >= g_config.general.recent.discs_count) return; - if (index < 0 || index >= g_config.general.history.discs_count) { - return; - } - - const char *file_path = g_config.general.history.discs[index]; - if (!file_path || !file_path[0]) { - return; - } + const char *file_path = g_config.general.recent.discs[index]; + if (!file_path || !file_path[0]) return; if (qemu_access(file_path, F_OK) == -1) { - g_free((void*)g_config.general.history.discs[index]); - for (int j = index; j < g_config.general.history.discs_count - 1; j++) { - g_config.general.history.discs[j] = g_config.general.history.discs[j + 1]; + g_free((void*)g_config.general.recent.discs[index]); + for (int j = index; j < g_config.general.recent.discs_count - 1; j++) { + g_config.general.recent.discs[j] = g_config.general.recent.discs[j + 1]; } - g_config.general.history.discs_count--; - if (g_config.general.history.discs_count == 0) { - g_free(g_config.general.history.discs); - g_config.general.history.discs = NULL; + g_config.general.recent.discs_count--; + if (g_config.general.recent.discs_count == 0) { + g_free(g_config.general.recent.discs); + g_config.general.recent.discs = NULL; } return; } @@ -181,12 +176,60 @@ void ActionLoadDiscFromHistory(int index) ActionLoadDiscFile(file_path); } -void ActionClearDiscHistory(void) +void ActionRemoveDiscFromRecent(unsigned int index) { - for (int i = 0; i < g_config.general.history.discs_count; i++) { - g_free((void*)g_config.general.history.discs[i]); + g_assert(index < g_config.general.recent.discs_count); + if (index >= g_config.general.recent.discs_count) return; + + g_free((void*)g_config.general.recent.discs[index]); + for (int j = index; j < g_config.general.recent.discs_count - 1; j++) { + g_config.general.recent.discs[j] = g_config.general.recent.discs[j + 1]; + } + g_config.general.recent.discs_count--; + if (g_config.general.recent.discs_count == 0) { + g_free(g_config.general.recent.discs); + g_config.general.recent.discs = NULL; + } +} + +void ActionClearDiscRecent(void) +{ + for (int i = 0; i < g_config.general.recent.discs_count; i++) { + g_free((void*)g_config.general.recent.discs[i]); + } + g_free(g_config.general.recent.discs); + g_config.general.recent.discs = NULL; + g_config.general.recent.discs_count = 0; +} + +void ActionClearMissingRecentDiscs(void) +{ + int valid_count = 0; + for (int i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; + if (!disc_path) continue; + if (qemu_access(disc_path, F_OK) != -1) { + valid_count++; + } + } + + const char **valid_discs = NULL; + if (valid_count > 0) { + valid_discs = (const char **)g_new0(const char *, valid_count); + + int valid_index = 0; + for (int i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; + if (!disc_path) continue; + if (qemu_access(disc_path, F_OK) != -1) { + valid_discs[valid_index++] = disc_path; + } else { + g_free((void*)disc_path); + } + } } - g_free(g_config.general.history.discs); - g_config.general.history.discs = NULL; - g_config.general.history.discs_count = 0; + + g_free(g_config.general.recent.discs); + g_config.general.recent.discs = valid_discs; + g_config.general.recent.discs_count = valid_count; } diff --git a/ui/xui/actions.hh b/ui/xui/actions.hh index a34faac44b1..133c721e12b 100644 --- a/ui/xui/actions.hh +++ b/ui/xui/actions.hh @@ -27,5 +27,7 @@ void ActionShutdown(); void ActionScreenshot(); void ActionActivateBoundSnapshot(int slot, bool save); void ActionLoadSnapshotChecked(const char *name); -void ActionLoadDiscFromHistory(int index); -void ActionClearDiscHistory(void); +void ActionLoadDiscFromRecent(unsigned int index); +void ActionRemoveDiscFromRecent(unsigned int index); +void ActionClearDiscRecent(void); +void ActionClearMissingRecentDiscs(void); diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index b13f09ff91c..b72f65bf5a6 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -138,34 +138,76 @@ void ShowMainMenu() if (ImGui::MenuItem("Eject Disc", SHORTCUT_MENU_TEXT(E))) ActionEjectDisc(); if (ImGui::MenuItem("Load Disc...", SHORTCUT_MENU_TEXT(O))) ActionLoadDisc(); - if (ImGui::BeginMenu("Recent")) { - bool has_recent = g_config.general.history.discs && g_config.general.history.discs_count > 0; + int valid_count = 0; + for (int i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; + if (!disc_path) continue; - if (has_recent) { - for (int i = 0; i < g_config.general.history.discs_count; i++) { - const char *disc_path = g_config.general.history.discs[i]; - if (!disc_path) continue; + const char *filename = g_path_get_basename(disc_path); + bool file_exists = qemu_access(disc_path, F_OK) != -1; + g_free((void *)filename); + + if (file_exists) { + valid_count++; + } + } + + bool has_valid_entries = (valid_count > 0); + if (ImGui::BeginMenu("Recent Discs", has_valid_entries)) { + for (int i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; + if (!disc_path) continue; + + const char *filename = g_path_get_basename(disc_path); + bool file_exists = qemu_access(disc_path, F_OK) != -1; + + if (file_exists) { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); + ImGui::PushID(i + 1000); + if (ImGui::Button("X", ImVec2(20.0f, 0))) { + ActionRemoveDiscFromRecent(i); + } + ImGui::PopID(); + ImGui::PopStyleColor(); - const char *filename = g_path_get_basename(disc_path); - bool file_exists = qemu_access(disc_path, F_OK) != -1; + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 255)); + if (ImGui::MenuItem(filename)) { + ActionLoadDiscFromRecent(i); + } + ImGui::PopStyleColor(); + } else { + char *missing_filename = g_strconcat(filename, " (missing)", nullptr); - if (file_exists) { - if (ImGui::MenuItem(filename)) { - ActionLoadDiscFromHistory(i); - } - } else { - ImGui::MenuItem(filename, NULL, false, false); + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); + ImGui::PushID(i + 1000); + if (ImGui::Button("X", ImVec2(20.0f, 0))) { + ActionRemoveDiscFromRecent(i); } + ImGui::PopID(); + ImGui::PopStyleColor(); - g_free((void *)filename); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(128, 128, 128, 255)); + ImGui::Text("%s", missing_filename); + ImGui::PopStyleColor(); + + g_free(missing_filename); } - ImGui::Separator(); + g_free((void *)filename); } - if (ImGui::MenuItem("Clear History")) { - ActionClearDiscHistory(); - xemu_settings_save(); + if (g_config.general.recent.discs_count > 0) { + ImGui::Separator(); + + if (ImGui::MenuItem("Clear Recent Discs")) { + ActionClearDiscRecent(); + } + + if (ImGui::MenuItem("Clear Missing Recent Discs")) { + ActionClearMissingRecentDiscs(); + } } ImGui::EndMenu(); From afd16a5165e2e282c8267075bfb9bb5a7430d8de Mon Sep 17 00:00:00 2001 From: ehw <885618+ehw@users.noreply.github.com> Date: Fri, 5 Dec 2025 03:31:09 -0500 Subject: [PATCH 6/8] Forgot to upload config_spec.yml --- config_spec.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config_spec.yml b/config_spec.yml index 602360b6590..de60513356d 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -19,7 +19,7 @@ general: f7: string f8: string filter_current_game: bool - history: + recent: discs: type: array items: @@ -151,6 +151,7 @@ display: validation_layers: bool debug_shaders: bool assert_on_validation_msg: bool + preferred_physical_device: string quality: surface_scale: type: integer From 4eb643eb9542628dae58c2242fe96e0c7596b458 Mon Sep 17 00:00:00 2001 From: jyetcv <125610127+jyetcv@users.noreply.github.com> Date: Sun, 11 Jan 2026 18:49:28 -0500 Subject: [PATCH 7/8] Modification of the Recent History PR. --- ui/xui/actions.cc | 146 +++++++++++++--------------------------------- ui/xui/actions.hh | 3 - ui/xui/menubar.cc | 67 +++------------------ 3 files changed, 47 insertions(+), 169 deletions(-) diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index 383822f8217..7f0ac7a7a91 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -24,7 +24,7 @@ #include "../xemu-notifications.h" #include "snapshot-manager.hh" -#define MAX_RECENT_DISCS 15 +#define MAX_RECENT_DISCS 11 void ActionEjectDisc(void) { @@ -60,42 +60,48 @@ void ActionLoadDiscFile(const char *file_path) xemu_queue_error_message(error_get_pretty(err)); error_free(err); } else { - if (file_path && file_path[0]) { - if (!g_config.general.recent.discs) { - g_config.general.recent.discs = g_new0(const char *, 1); - g_config.general.recent.discs_count = 0; - } + if (!g_config.general.recent.discs) { + g_config.general.recent.discs = g_new0(const char *, 1); + g_config.general.recent.discs_count = 0; + } - int i; - for (i = 0; i < g_config.general.recent.discs_count; i++) { - if (g_strcmp0(g_config.general.recent.discs[i], file_path) == 0) { - for (int j = i; j > 0; j--) { - g_config.general.recent.discs[j] = g_config.general.recent.discs[j-1]; - } - g_config.general.recent.discs[0] = g_strdup(file_path); - return; + // If current game is already in history, + // move other game entries down, + // then move the current game to the most recent slot. + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + if (g_strcmp0(g_config.general.recent.discs[i], file_path) == 0) { + const char *current_path = g_config.general.recent.discs[i]; + for (unsigned int j = i; j > 0; j--) { + g_config.general.recent.discs[j] = + g_config.general.recent.discs[j - 1]; } + g_config.general.recent.discs[0] = current_path; + return; + } + } + // Free a slot for our entry. + if (g_config.general.recent.discs_count >= MAX_RECENT_DISCS) { + for (unsigned i = MAX_RECENT_DISCS; + i < g_config.general.recent.discs_count; i++) { + g_free((void *)g_config.general.recent.discs[i]); } - if (i == g_config.general.recent.discs_count) { - if (g_config.general.recent.discs_count >= MAX_RECENT_DISCS) { - for (int j = MAX_RECENT_DISCS; j < g_config.general.recent.discs_count; j++) { - g_free((void*)g_config.general.recent.discs[j]); - } - g_config.general.recent.discs_count = MAX_RECENT_DISCS; - } else { - const char **new_discs = g_renew(const char *, g_config.general.recent.discs, - g_config.general.recent.discs_count + 1); - g_config.general.recent.discs = new_discs; - g_config.general.recent.discs_count++; - } + g_free((void *)g_config.general.recent.discs[MAX_RECENT_DISCS - 1]); + g_config.general.recent.discs_count = MAX_RECENT_DISCS; + } else { + // Allocate new space. + const char **new_discs = + g_renew(const char *, g_config.general.recent.discs, + g_config.general.recent.discs_count + 1); + g_config.general.recent.discs = new_discs; + g_config.general.recent.discs_count++; + } - for (int i = g_config.general.recent.discs_count - 1; i > 0; i--) { - g_config.general.recent.discs[i] = g_config.general.recent.discs[i-1]; - } - g_config.general.recent.discs[0] = g_strdup(file_path); - } + for (unsigned i = g_config.general.recent.discs_count - 1; i > 0; i--) { + g_config.general.recent.discs[i] = + g_config.general.recent.discs[i - 1]; } + g_config.general.recent.discs[0] = g_strdup(file_path); } } @@ -120,7 +126,7 @@ void ActionShutdown(void) void ActionScreenshot(void) { - g_screenshot_pending = true; + g_screenshot_pending = true; } void ActionActivateBoundSnapshot(int slot, bool save) @@ -152,84 +158,12 @@ void ActionLoadSnapshotChecked(const char *name) g_snapshot_mgr.LoadSnapshotChecked(name); } -void ActionLoadDiscFromRecent(unsigned int index) -{ - g_assert(index < g_config.general.recent.discs_count); - if (index >= g_config.general.recent.discs_count) return; - - const char *file_path = g_config.general.recent.discs[index]; - if (!file_path || !file_path[0]) return; - - if (qemu_access(file_path, F_OK) == -1) { - g_free((void*)g_config.general.recent.discs[index]); - for (int j = index; j < g_config.general.recent.discs_count - 1; j++) { - g_config.general.recent.discs[j] = g_config.general.recent.discs[j + 1]; - } - g_config.general.recent.discs_count--; - if (g_config.general.recent.discs_count == 0) { - g_free(g_config.general.recent.discs); - g_config.general.recent.discs = NULL; - } - return; - } - - ActionLoadDiscFile(file_path); -} - -void ActionRemoveDiscFromRecent(unsigned int index) -{ - g_assert(index < g_config.general.recent.discs_count); - if (index >= g_config.general.recent.discs_count) return; - - g_free((void*)g_config.general.recent.discs[index]); - for (int j = index; j < g_config.general.recent.discs_count - 1; j++) { - g_config.general.recent.discs[j] = g_config.general.recent.discs[j + 1]; - } - g_config.general.recent.discs_count--; - if (g_config.general.recent.discs_count == 0) { - g_free(g_config.general.recent.discs); - g_config.general.recent.discs = NULL; - } -} - void ActionClearDiscRecent(void) { - for (int i = 0; i < g_config.general.recent.discs_count; i++) { - g_free((void*)g_config.general.recent.discs[i]); + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + g_free((void *)g_config.general.recent.discs[i]); } g_free(g_config.general.recent.discs); g_config.general.recent.discs = NULL; g_config.general.recent.discs_count = 0; } - -void ActionClearMissingRecentDiscs(void) -{ - int valid_count = 0; - for (int i = 0; i < g_config.general.recent.discs_count; i++) { - const char *disc_path = g_config.general.recent.discs[i]; - if (!disc_path) continue; - if (qemu_access(disc_path, F_OK) != -1) { - valid_count++; - } - } - - const char **valid_discs = NULL; - if (valid_count > 0) { - valid_discs = (const char **)g_new0(const char *, valid_count); - - int valid_index = 0; - for (int i = 0; i < g_config.general.recent.discs_count; i++) { - const char *disc_path = g_config.general.recent.discs[i]; - if (!disc_path) continue; - if (qemu_access(disc_path, F_OK) != -1) { - valid_discs[valid_index++] = disc_path; - } else { - g_free((void*)disc_path); - } - } - } - - g_free(g_config.general.recent.discs); - g_config.general.recent.discs = valid_discs; - g_config.general.recent.discs_count = valid_count; -} diff --git a/ui/xui/actions.hh b/ui/xui/actions.hh index 133c721e12b..d4619b476e5 100644 --- a/ui/xui/actions.hh +++ b/ui/xui/actions.hh @@ -27,7 +27,4 @@ void ActionShutdown(); void ActionScreenshot(); void ActionActivateBoundSnapshot(int slot, bool save); void ActionLoadSnapshotChecked(const char *name); -void ActionLoadDiscFromRecent(unsigned int index); -void ActionRemoveDiscFromRecent(unsigned int index); void ActionClearDiscRecent(void); -void ActionClearMissingRecentDiscs(void); diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index d74a3bbf689..3931e5831f6 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -142,79 +142,26 @@ void ShowMainMenu() if (ImGui::MenuItem("Eject Disc", SHORTCUT_MENU_TEXT(E))) ActionEjectDisc(); if (ImGui::MenuItem("Load Disc...", SHORTCUT_MENU_TEXT(O))) ActionLoadDisc(); - int valid_count = 0; - for (int i = 0; i < g_config.general.recent.discs_count; i++) { - const char *disc_path = g_config.general.recent.discs[i]; - if (!disc_path) continue; - - const char *filename = g_path_get_basename(disc_path); - bool file_exists = qemu_access(disc_path, F_OK) != -1; - g_free((void *)filename); - - if (file_exists) { - valid_count++; - } - } - - bool has_valid_entries = (valid_count > 0); - if (ImGui::BeginMenu("Recent Discs", has_valid_entries)) { + bool has_any_entries = (g_config.general.recent.discs_count > 0); + if (ImGui::BeginMenu("Recent Discs", has_any_entries)) { for (int i = 0; i < g_config.general.recent.discs_count; i++) { const char *disc_path = g_config.general.recent.discs[i]; - if (!disc_path) continue; - + const char *filename = g_path_get_basename(disc_path); - bool file_exists = qemu_access(disc_path, F_OK) != -1; - - if (file_exists) { - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); - ImGui::PushID(i + 1000); - if (ImGui::Button("X", ImVec2(20.0f, 0))) { - ActionRemoveDiscFromRecent(i); - } - ImGui::PopID(); - ImGui::PopStyleColor(); - - ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 255)); + if (ImGui::MenuItem(filename)) { - ActionLoadDiscFromRecent(i); - } - ImGui::PopStyleColor(); - } else { - char *missing_filename = g_strconcat(filename, " (missing)", nullptr); - - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); - ImGui::PushID(i + 1000); - if (ImGui::Button("X", ImVec2(20.0f, 0))) { - ActionRemoveDiscFromRecent(i); + ActionLoadDiscFile(disc_path); } - ImGui::PopID(); - ImGui::PopStyleColor(); - - ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(128, 128, 128, 255)); - ImGui::Text("%s", missing_filename); - ImGui::PopStyleColor(); - - g_free(missing_filename); - } - + g_free((void *)filename); } - if (g_config.general.recent.discs_count > 0) { ImGui::Separator(); - if (ImGui::MenuItem("Clear Recent Discs")) { ActionClearDiscRecent(); } - - if (ImGui::MenuItem("Clear Missing Recent Discs")) { - ActionClearMissingRecentDiscs(); - } - } - ImGui::EndMenu(); + } } ImGui::Separator(); From c11bcaf99d3c9a9410184a647d2947ed49e15220 Mon Sep 17 00:00:00 2001 From: jyetcv <125610127+jyetcv@users.noreply.github.com> Date: Mon, 12 Jan 2026 09:16:31 -0500 Subject: [PATCH 8/8] Modifying code as suggested. --- ui/xui/actions.cc | 8 ++++---- ui/xui/menubar.cc | 24 +++++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index 7f0ac7a7a91..4f6e5c0b05a 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -24,7 +24,7 @@ #include "../xemu-notifications.h" #include "snapshot-manager.hh" -#define MAX_RECENT_DISCS 11 +static const unsigned int MAX_RECENT_DISCS = 10; void ActionEjectDisc(void) { @@ -65,9 +65,9 @@ void ActionLoadDiscFile(const char *file_path) g_config.general.recent.discs_count = 0; } - // If current game is already in history, - // move other game entries down, - // then move the current game to the most recent slot. + // If current disc entry is already in history, + // collapse other entries down, + // then move the current entry to the slot at the top. for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { if (g_strcmp0(g_config.general.recent.discs[i], file_path) == 0) { const char *current_path = g_config.general.recent.discs[i]; diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index 3931e5831f6..7091fd99bf9 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -142,26 +142,28 @@ void ShowMainMenu() if (ImGui::MenuItem("Eject Disc", SHORTCUT_MENU_TEXT(E))) ActionEjectDisc(); if (ImGui::MenuItem("Load Disc...", SHORTCUT_MENU_TEXT(O))) ActionLoadDisc(); - bool has_any_entries = (g_config.general.recent.discs_count > 0); + bool has_any_entries = (g_config.general.recent.discs_count > 0); if (ImGui::BeginMenu("Recent Discs", has_any_entries)) { - for (int i = 0; i < g_config.general.recent.discs_count; i++) { - const char *disc_path = g_config.general.recent.discs[i]; + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; const char *filename = g_path_get_basename(disc_path); - if (ImGui::MenuItem(filename)) { + if (ImGui::MenuItem(filename)) + { ActionLoadDiscFile(disc_path); } - g_free((void *)filename); + g_free((void *)filename); } - if (g_config.general.recent.discs_count > 0) { - ImGui::Separator(); - if (ImGui::MenuItem("Clear Recent Discs")) { - ActionClearDiscRecent(); - } - ImGui::EndMenu(); + + ImGui::Separator(); + if (ImGui::MenuItem("Clear Recent Discs")) + { + ActionClearDiscRecent(); } + + ImGui::EndMenu(); } ImGui::Separator();