Files
2026-10-14 12:17:30 -07:00

126 lines
5.9 KiB
C

/* psx_menu_host.h -- the runtime's contract with an in-game menu provider.
*
* psxrecomp owns this header. A frontend (recomp-ui, recomp-launcher, or any
* other) implements PsxMenuProvider; the runtime implements PsxMenuHost. The
* runtime keeps every policy (pause, live settings, mod changes, disc/tray,
* netplay session start/exit) on its side, so all providers get the same
* behaviour. Nothing here is specific to one frontend.
*
* Selection: no provider is registered by default, so a title's existing UI
* (recomp-ui) and its pin are unchanged. A title that wants a provider
* registers it with psx_menu_set_provider() before the game window opens
* (for example from a static initializer in the title's own code).
*
* Threads: attach/event/is_open/set_open run on the main thread; draw runs on
* the thread that owns the GL context (host_overlay.h P2) with the window
* framebuffer bound. PsxMenuHost calls may come from either; the runtime
* applies them on the main thread at the next frame. */
#ifndef PSX_MENU_HOST_H
#define PSX_MENU_HOST_H
#include "host_overlay.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSX_MENU_ABI_VERSION 1
/* PsxMenuHost.default_selection is present (appended, ABI-compatible). */
#define PSX_MENU_HOST_HAS_DEFAULT_SELECTION 1
/* request_exit */
enum {
PSX_MENU_EXIT_QUIT = 0, /* leave the game (netplay: back to the lobby) */
PSX_MENU_EXIT_TO_FRONTEND = 1, /* end the session, re-enter the frontend loop in-process */
PSX_MENU_EXIT_RELAUNCH = 2 /* restart this process with its original arguments */
};
/* video_apply returns PSX_VIDEO_RESTART_* bits (host_overlay.h) plus this one:
* during a netplay match only presentation applies; the rest waits. */
#define PSX_MENU_RESTART_AFTER_MATCH (1u << 31)
/* The shared launcher C ABI (recomp_launcher.h) that recomp-ui and
* recomp-launcher both speak for the pre-game launcher. Optional: a provider
* that uses it gets the same game info, mod catalogue and lobby objects the
* pre-game launcher gets; one that does not ignores these entries. */
struct RecompLauncherCGameInfo;
struct RecompLauncherCSettings;
typedef struct PsxMenuHost {
int abi_version; /* PSX_MENU_ABI_VERSION */
/* Pause the guest and audio (host_overlay.h P1). Returns 0 when refused
* (netplay): the menu then stays open without pausing. */
int (*set_paused)(int paused);
int (*netplay_active)(void);
/* Video settings: current values, and a live apply (P4) that also saves
* settings.toml. Returns the restart bits of the fields that wait. */
void (*video_get)(PsxHostVideoSettings *out);
unsigned (*video_apply)(const PsxHostVideoSettings *next);
/* Mod feature switch (option == NULL, value "true"/"false") or option.
* Saved to mods/state.toml; returns 1 when it applied live (P5), 0 when it
* waits for the next start. Refused (0, unsaved) during netplay. */
int (*mod_set)(const char *package_id, const char *feature_id,
const char *option_id, const char *value);
/* Reload keybinds.ini / input.ini / config.ini after the menu wrote them. */
void (*reload_bindings)(void);
/* PSX_MENU_EXIT_*. Applied on the main thread; the menu is closed and its
* pause dropped before the session ends. */
void (*request_exit)(int how);
/* Disc/tray: the runtime's production tray policy (psx_disc_tray.h),
* shared with its own disc menu and hotkeys; count is 0 without a
* multi-disc roster or a policy. insert queues the lid cycle for the main
* thread: 0 = queued, -1 = no such disc, 3 = refused (netplay). */
int (*disc_count)(void);
int (*disc_mounted)(void); /* 1-based, 0 = none */
const char *(*disc_path)(int disc_1based);
int (*disc_insert)(int disc_1based);
/* Shared launcher ABI helpers (see above); NULL in builds without it. */
void (*launcher_game_info)(struct RecompLauncherCGameInfo *out);
void (*launcher_settings_get)(struct RecompLauncherCSettings *out);
unsigned (*launcher_settings_apply)(const struct RecompLauncherCSettings *next);
const char *assets_dir; /* the title's assets folder */
/* 1 when the runtime chose this provider because the title chose none
* (the UI library's default provider, recomp_ui_psx_menu.h). Such a
* provider keeps the title's default presentation: it may decline to
* attach when it would only add a menu the title did not have. */
int default_selection;
} PsxMenuHost;
typedef struct PsxMenuProvider {
int abi_version; /* PSX_MENU_ABI_VERSION */
const char *name;
void *ctx;
/* Once per GL context, with it current. Returns 0 to decline. */
int (*attach)(void *ctx, void *sdl_window, void *gl_context, const PsxMenuHost *host);
/* Every SDL event first; 1 = consumed (the game does not see it). The
* provider opens itself (its own key/pad binding) from here. */
int (*event)(void *ctx, const void *sdl_event);
int (*is_open)(void *ctx);
void (*set_open)(void *ctx, int open);
/* Draw over the presented frame (P2). */
void (*draw)(void *ctx, int framebuffer_w, int framebuffer_h);
/* Before its GL context goes away (session end, rematch), with it current;
* attach follows for the next context. */
void (*detach)(void *ctx);
} PsxMenuProvider;
/* Register (or clear, NULL) the in-game menu provider. Main thread, before
* the game window opens; a provider with another ABI version is refused. */
int psx_menu_set_provider(const PsxMenuProvider *provider);
const PsxMenuProvider *psx_menu_provider(void);
/* The disc/tray policy publishes itself here (PsxMenuHost disc_* entries). */
typedef struct PsxMenuDiscOps {
int (*count)(void);
int (*mounted)(void);
const char *(*path)(int disc_1based);
int (*insert)(int disc_1based);
} PsxMenuDiscOps;
void psx_menu_set_disc_ops(const PsxMenuDiscOps *ops);
const PsxMenuDiscOps *psx_menu_disc_ops(void);
#ifdef __cplusplus
}
#endif
#endif