runtime: expose the resolved window-icon path for the launcher

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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0194TYJAqgyG9a9PJe9uUcgQ
This commit is contained in:
Alex Vanderveen
2026-08-29 11:04:30 -04:00
parent d14ca6917c
commit c481b6cd4e
3 changed files with 30 additions and 1 deletions
+8
View File
@@ -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
+8
View File
@@ -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. */
+14 -1
View File
@@ -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");