From c481b6cd4e1c1b3d95a535b10fe1b22e711848e4 Mon Sep 17 00:00:00 2001 From: Alex Vanderveen Date: Sat, 29 Aug 2026 11:04:30 -0400 Subject: [PATCH] runtime: expose the resolved window-icon path for the launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit recomp-ui takes a host-supplied icon path (GameInfo.window_icon_path) so the launcher window carries the same art as the game window. Publish the path psx_apply_window_icon() already resolves, rather than letting the launcher repeat the search — repeating it is what would let the two drift apart the next time the candidate list changes. Resolved once and cached: both the game window and the launcher ask, and the answer cannot change within a run. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0194TYJAqgyG9a9PJe9uUcgQ --- runtime/include/psx_window_icon.h | 8 ++++++++ runtime/src/main.cpp | 8 ++++++++ runtime/src/psx_window_icon.cpp | 15 ++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/runtime/include/psx_window_icon.h b/runtime/include/psx_window_icon.h index 09eaea5b..d98d95e6 100644 --- a/runtime/include/psx_window_icon.h +++ b/runtime/include/psx_window_icon.h @@ -10,6 +10,14 @@ struct SDL_Window; * the window / taskbar icon. No-op when the PNG is missing. */ void psx_apply_window_icon(struct SDL_Window *window, const char *argv0); +/* The resolved path psx_apply_window_icon() would use, or "" when no icon PNG + * was found. Exists so the launcher can carry the SAME icon as the game + * window: recomp-ui takes a host-supplied path (GameInfo.window_icon_path) + * rather than repeating this search, which is what stops the two from + * drifting apart the next time the search order changes. The result is cached + * on first call and the returned pointer stays valid for the process. */ +const char *psx_window_icon_path(const char *argv0); + #ifdef __cplusplus } #endif diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index a7061f51..dab000df 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -10734,6 +10734,14 @@ namespace { gi->memcard_inspect = ae_memcard_inspect; gi->mods = PSXRecompV4::mod_runtime_launcher_provider(); gi->bios_verify = ae_bios_verify; + /* Launcher window icon: the SAME file psx_apply_window_icon() puts on + * the game window (assets/psxrecomp.png beside the exe, which + * runtime.cmake stages from APP_ICON's directory). Resolved through + * the shared helper rather than re-derived here, so the launcher and + * the game can never end up on different art. The pointer is process- + * lifetime; "" when the build shipped no PNG, which recomp-ui treats + * as "leave the toolkit default". */ + gi->window_icon_path = psx_window_icon_path(g_lnch_argv0); #if defined(PSX_HAS_RECOMP_NET) && defined(PSX_HAS_LOBBY_CLIENT) g_lnch_game_players = game_players_n; /* ae_disc_verify only fills netplay_ok/disc_fp when this is true. */ diff --git a/runtime/src/psx_window_icon.cpp b/runtime/src/psx_window_icon.cpp index 0a141a48..513cf0b9 100644 --- a/runtime/src/psx_window_icon.cpp +++ b/runtime/src/psx_window_icon.cpp @@ -69,10 +69,23 @@ static fs::path find_icon_png(const char *argv0) return {}; } +/* Resolve once and keep it: both the game window and the launcher ask, and + * the answer cannot change within a run. */ +extern "C" const char *psx_window_icon_path(const char *argv0) +{ + static std::string cached; + static bool resolved = false; + if (!resolved) { + cached = find_icon_png(argv0).string(); + resolved = true; + } + return cached.c_str(); +} + extern "C" void psx_apply_window_icon(SDL_Window *window, const char *argv0) { if (!window) return; - const fs::path png = find_icon_png(argv0); + const fs::path png(psx_window_icon_path(argv0)); if (png.empty()) return; FILE *f = std::fopen(png.string().c_str(), "rb");