From 0cea191e627449d0b3fb7b8f10b9ebd14b0d2ae2 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:00:53 +0200 Subject: [PATCH 01/24] feat(zaparoo): F2 toggle to switch the launcher between HDMI and CRT modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `alt_launcher_toggle_crt()` which kills the current launcher (if any) and re-spawns it with the opposite mode flag — when toggling on, the bash wrapper sets `ALT_LAUNCHER_CRT=1` and the launcher restarts with `--crt` so it adapts to the 320x240 native resolution and starts the DDR3 writer. On toggle-off the launcher restarts without the flag and returns to the HDMI HPS-framebuffer path. Bound to KEY_F2 in HandleUI, gated on `alt_launcher_configured()` and on being in the menu core or the dedicated Zaparoo Launcher core. F2 was previously unmapped. Implementation reuses the existing shutdown/init lifecycle: - alt_launcher_shutdown() drops status[9], clears the launcher fb_mode, waits SIGTERM/SIGKILL, and resets s_native_crt + s_gave_up so init succeeds afterwards regardless of whether the launcher was running. - alt_launcher_init(target_crt) schedules a respawn picked up by the next alt_launcher_poll() tick — same path the auto-init for the Zaparoo Launcher core uses. The FPGA-side (Menu_MiSTer feat/dual-mode-native-fb) consumes status[9] as the runtime gate selecting between the cosine pattern (default) and the native DDR reader. This hotkey is the user-facing way to flip it. --- menu.cpp | 7 +++++++ support/zaparoo/alt_launcher.cpp | 14 ++++++++++++++ support/zaparoo/alt_launcher.h | 1 + 3 files changed, 22 insertions(+) diff --git a/menu.cpp b/menu.cpp index d5197652e..fe6d6b776 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1297,6 +1297,13 @@ void HandleUI(void) } break; + case KEY_F2: + if (alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) + { + alt_launcher_toggle_crt(); + } + break; + case KEY_F11: if (user_io_osd_is_visible() && (menustate != MENU_SCRIPTS1 || script_finished)) { diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 0c5554541..c82a2c50f 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -269,6 +269,20 @@ bool alt_launcher_active(void) return s_pid != 0; } +void alt_launcher_toggle_crt(void) +{ + bool current_crt = alt_launcher_active() && s_native_crt; + bool target_crt = !current_crt; + + printf("alt_launcher: toggle CRT path %d -> %d\n", current_crt, target_crt); + + // Shutdown drops status[9], releases the FB mode and restores HPS framebuffer + // state regardless of whether the launcher was running. After it returns we + // always have a clean slate to spawn the next launcher invocation. + alt_launcher_shutdown(); + alt_launcher_init(target_crt); +} + void alt_launcher_init(bool native_crt) { if (!cfg.alt_launcher[0] || !cfg.fb_terminal || s_pid || s_gave_up) diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 3ce4ba959..28e45df31 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -7,6 +7,7 @@ void alt_launcher_init(bool native_crt = false); void alt_launcher_poll(void); void alt_launcher_shutdown(void); +void alt_launcher_toggle_crt(void); bool alt_launcher_active(void); bool alt_launcher_configured(void); From 6d2690b51b94bc5036ea9d67df30cd0e7c5ca5ca Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:32:24 +0200 Subject: [PATCH 02/24] fix(zaparoo): handle F2 toggle in user_io_kbd, not HandleUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit put the F2 toggle handler in menu.cpp's HandleUI, but keys reach HandleUI only via menu_key_set(), and that queue is only fed when the OSD is visible (or for the special is_menu_event keys F12/MENU). While the launcher is running the OSD is hidden, so HandleUI never sees the F2 press and the toggle silently did nothing. Move the toggle into user_io_kbd as a sibling case of the existing rbf_hide_datecode F2 handler. Order is important — the rbf_hide_datecode case stays first so it still wins when OSD is visible (a niche menu setting unrelated to the CRT path); our case fires when OSD is hidden, which is the actual usage scenario for toggling the launcher mode. Also remove the now-dead F2 case from menu.cpp HandleUI. --- menu.cpp | 7 ------- user_io.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/menu.cpp b/menu.cpp index fe6d6b776..d5197652e 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1297,13 +1297,6 @@ void HandleUI(void) } break; - case KEY_F2: - if (alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) - { - alt_launcher_toggle_crt(); - } - break; - case KEY_F11: if (user_io_osd_is_visible() && (menustate != MENU_SCRIPTS1 || script_finished)) { diff --git a/user_io.cpp b/user_io.cpp index 3c136bf5f..3f872171e 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -4153,6 +4153,15 @@ void user_io_kbd(uint16_t key, int press) PrintDirectory(); } else + if (key == KEY_F2 && press == 1 && alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) + { + // Toggle the Zaparoo launcher between HDMI and native-CRT modes. + // Handled here (not in HandleUI) so it works while the launcher is + // running and the OSD is hidden — keys outside OSD never reach the + // menu_key queue, only the FPGA core path. + alt_launcher_toggle_crt(); + } + else { if (key) { From 390c141ca3b8231d91bd5ad56f3a4e2b20451247 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:33:57 +0200 Subject: [PATCH 03/24] Revert "fix(zaparoo): handle F2 toggle in user_io_kbd, not HandleUI" This reverts commit 6d2690b51b94bc5036ea9d67df30cd0e7c5ca5ca. --- menu.cpp | 7 +++++++ user_io.cpp | 9 --------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/menu.cpp b/menu.cpp index d5197652e..fe6d6b776 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1297,6 +1297,13 @@ void HandleUI(void) } break; + case KEY_F2: + if (alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) + { + alt_launcher_toggle_crt(); + } + break; + case KEY_F11: if (user_io_osd_is_visible() && (menustate != MENU_SCRIPTS1 || script_finished)) { diff --git a/user_io.cpp b/user_io.cpp index 3f872171e..3c136bf5f 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -4153,15 +4153,6 @@ void user_io_kbd(uint16_t key, int press) PrintDirectory(); } else - if (key == KEY_F2 && press == 1 && alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) - { - // Toggle the Zaparoo launcher between HDMI and native-CRT modes. - // Handled here (not in HandleUI) so it works while the launcher is - // running and the OSD is hidden — keys outside OSD never reach the - // menu_key queue, only the FPGA core path. - alt_launcher_toggle_crt(); - } - else { if (key) { From 4220a82485c18c2bc623dd55109039aa19bc547a Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:33:57 +0200 Subject: [PATCH 04/24] Revert "feat(zaparoo): F2 toggle to switch the launcher between HDMI and CRT modes" This reverts commit 0cea191e627449d0b3fb7b8f10b9ebd14b0d2ae2. --- menu.cpp | 7 ------- support/zaparoo/alt_launcher.cpp | 14 -------------- support/zaparoo/alt_launcher.h | 1 - 3 files changed, 22 deletions(-) diff --git a/menu.cpp b/menu.cpp index fe6d6b776..d5197652e 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1297,13 +1297,6 @@ void HandleUI(void) } break; - case KEY_F2: - if (alt_launcher_configured() && (is_menu() || zaparoo_is_native_core())) - { - alt_launcher_toggle_crt(); - } - break; - case KEY_F11: if (user_io_osd_is_visible() && (menustate != MENU_SCRIPTS1 || script_finished)) { diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index c82a2c50f..0c5554541 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -269,20 +269,6 @@ bool alt_launcher_active(void) return s_pid != 0; } -void alt_launcher_toggle_crt(void) -{ - bool current_crt = alt_launcher_active() && s_native_crt; - bool target_crt = !current_crt; - - printf("alt_launcher: toggle CRT path %d -> %d\n", current_crt, target_crt); - - // Shutdown drops status[9], releases the FB mode and restores HPS framebuffer - // state regardless of whether the launcher was running. After it returns we - // always have a clean slate to spawn the next launcher invocation. - alt_launcher_shutdown(); - alt_launcher_init(target_crt); -} - void alt_launcher_init(bool native_crt) { if (!cfg.alt_launcher[0] || !cfg.fb_terminal || s_pid || s_gave_up) diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 28e45df31..3ce4ba959 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -7,7 +7,6 @@ void alt_launcher_init(bool native_crt = false); void alt_launcher_poll(void); void alt_launcher_shutdown(void); -void alt_launcher_toggle_crt(void); bool alt_launcher_active(void); bool alt_launcher_configured(void); From 7d0f6a408b0133cf0326b4469a75209f1f15d434 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:39:23 +0200 Subject: [PATCH 05/24] feat(zaparoo): OSD menu entry to toggle CRT path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a "CRT mode: On/Off" item to the System OSD (MENU_COMMON1) right below the existing "Launcher" entry. Activating it kills the running launcher and respawns it with the opposite mode flag — same behaviour the previous F2 hotkey aimed for, now navigable from the OSD so it works without a keyboard. Implementation: - New slot ALT_LAUNCHER_CRT_MENUSUB = 30 next to ALT_LAUNCHER_MENUSUB. - alt_launcher_native_crt() exposes the current mode for the label. - alt_launcher_toggle_crt() wraps shutdown + init(target) so the menu handler stays a one-liner; same lifecycle the auto-init path uses. - Activation re-enters MENU_COMMON1 so the label refreshes after the launcher state settles. Gated identically to the existing Launcher entry — only shown when alt_launcher_configured() is true. --- menu.cpp | 9 +++++++++ support/zaparoo/alt_launcher.cpp | 19 +++++++++++++++++++ support/zaparoo/alt_launcher.h | 5 ++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/menu.cpp b/menu.cpp index d5197652e..42698e0b6 100644 --- a/menu.cpp +++ b/menu.cpp @@ -2811,6 +2811,10 @@ void HandleUI(void) { menumask |= (1ULL << ALT_LAUNCHER_MENUSUB); MenuWrite(n++, " Launcher", menusub == ALT_LAUNCHER_MENUSUB, 0); + + menumask |= (1ULL << ALT_LAUNCHER_CRT_MENUSUB); + sprintf(s, " CRT mode: %s", alt_launcher_native_crt() ? "On" : "Off"); + MenuWrite(n++, s, menusub == ALT_LAUNCHER_CRT_MENUSUB, 0); } MenuWrite(n++, " Core \x16", menusub == 0, 0); @@ -3059,6 +3063,11 @@ void HandleUI(void) reboot_req = 1; break; + case ALT_LAUNCHER_CRT_MENUSUB: + alt_launcher_toggle_crt(); + menustate = MENU_COMMON1; + break; + default: menustate = MENU_NONE1; break; diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 0c5554541..2e9d1c465 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -269,6 +269,25 @@ bool alt_launcher_active(void) return s_pid != 0; } +bool alt_launcher_native_crt(void) +{ + return s_native_crt && s_pid != 0; +} + +void alt_launcher_toggle_crt(void) +{ + bool current_crt = alt_launcher_native_crt(); + bool target_crt = !current_crt; + + printf("alt_launcher: toggle CRT path %d -> %d\n", current_crt, target_crt); + + // Shutdown drops status[9], releases the FB mode and restores HPS framebuffer + // state regardless of whether the launcher was running. After it returns we + // always have a clean slate to spawn the next launcher invocation. + alt_launcher_shutdown(); + alt_launcher_init(target_crt); +} + void alt_launcher_init(bool native_crt) { if (!cfg.alt_launcher[0] || !cfg.fb_terminal || s_pid || s_gave_up) diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 3ce4ba959..f74f00a60 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -2,11 +2,14 @@ #include -#define ALT_LAUNCHER_MENUSUB 31 +#define ALT_LAUNCHER_MENUSUB 31 +#define ALT_LAUNCHER_CRT_MENUSUB 30 void alt_launcher_init(bool native_crt = false); void alt_launcher_poll(void); void alt_launcher_shutdown(void); +void alt_launcher_toggle_crt(void); +bool alt_launcher_native_crt(void); bool alt_launcher_active(void); bool alt_launcher_configured(void); From 4afaa675157c8a8dd27dd8b5026958d5a80d36ac Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:49:47 +0200 Subject: [PATCH 06/24] feat(zaparoo): also surface CRT mode toggle in System Settings (MENU_SYSTEM1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit only added the entry to MENU_COMMON1 ("System" submenu), which is reached by F12 on a non-menu core (or Win+F12 on the menu core). On the regular menu core, plain F12 opens the core picker; backing out lands you in MENU_SYSTEM1 ("System Settings") instead — that menu didn't have the toggle, hence the option appeared invisible. Add the same "CRT mode: On/Off" entry to MENU_SYSTEM1, gated identically on alt_launcher_configured(). The MENU_COMMON1 entry stays so the option is reachable from the game-core path too. --- menu.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/menu.cpp b/menu.cpp index 42698e0b6..0927523e0 100644 --- a/menu.cpp +++ b/menu.cpp @@ -6707,6 +6707,7 @@ void HandleUI(void) m = 0; OsdSetTitle("System Settings", OSD_ARROW_LEFT); menumask = 0x7F; + if (alt_launcher_configured()) menumask |= (1ULL << 7); OsdWrite(m++); sprintf(s, " MiSTer v%s", version + 5); @@ -6759,6 +6760,11 @@ void HandleUI(void) OsdWrite(m++, " Define joystick buttons \x16", menusub == 2); OsdWrite(m++, " Scripts \x16", menusub == 3); OsdWrite(m++, " Help \x16", menusub == 4); + if (alt_launcher_configured()) + { + sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); + OsdWrite(m++, s, menusub == 7); + } OsdWrite(m++, ""); cr = m; OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 5); @@ -6844,6 +6850,14 @@ void HandleUI(void) case 6: menustate = MENU_NONE1; break; + + case 7: + if (alt_launcher_configured()) + { + alt_launcher_toggle_crt(); + menustate = MENU_SYSTEM1; + } + break; } } else if (left) From 99f9829636b021181430216493e55edd097592dd Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 00:58:42 +0200 Subject: [PATCH 07/24] feat(zaparoo): let F12 open the OSD on top of a running launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously F12 and KEY_MENU were both early-returned in user_io_kbd whenever the launcher was active, so the only way to reach the MiSTer OSD was to first kill the launcher app. That made the new "CRT mode" toggle entry unreachable in practice — the menu was always one step behind the user's actual workflow. Drop F12 from the early return; keep KEY_MENU dropped because that one is the joypad OSD button remapped by alt_launcher_fb_terminal_key for the launcher app's own UI. F12 now falls through to is_menu_event -> menu_key_set(KEY_F12) and the OSD overlays normally. Input grabbing handles itself: the OSD open path already calls user_io_osd_key_enable(1) which triggers input_switch(-1), and that re-evaluates EVIOCGRAB as (grabbed | osd_is_visible). So while the OSD is up the launcher stops receiving inputs (MiSTer holds the exclusive grab); when the OSD closes user_io_osd_key_enable(0) drops the grab and the launcher resumes reading /dev/input. Net behavior: F12 toggles the OSD on top of the running launcher, no exit/respawn dance needed to access System Settings or the new CRT mode toggle. --- user_io.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/user_io.cpp b/user_io.cpp index 3c136bf5f..0cb46e31a 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -4157,7 +4157,13 @@ void user_io_kbd(uint16_t key, int press) if (key) { uint32_t code = get_ps2_code(key); - if (alt_launcher_active() && (key == KEY_MENU || key == KEY_F12)) + // While the launcher is running the joypad MENU button (KEY_MENU, + // remapped via alt_launcher_fb_terminal_key) belongs to the launcher + // app's own UI. F12 stays with MiSTer so the user can overlay the + // native OSD on top of the launcher and toggle CRT mode without + // exiting their app — input grabbing flips automatically when the + // OSD opens (user_io_osd_key_enable -> input_switch). + if (alt_launcher_active() && key == KEY_MENU) return; bool is_menu_event = ((has_menu() || osd_is_visible || (get_key_mod() & (LALT | RALT | RGUI | LGUI))) && (((key == KEY_F12) && (!is_f12_mod_needed() || (get_key_mod() & (RGUI | LGUI)))) || key == KEY_MENU)); if (!press) From 155254ec7cda4c40955cc4d8cedc1485acc65522 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 01:00:50 +0200 Subject: [PATCH 08/24] feat(zaparoo): F12 on menu core opens System Settings directly, F12 closes it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When alt_launcher is configured, the file picker is not the user's natural entry point on the menu core — they want a quick overlay to flip CRT mode or change a setting and get back to their launcher app. Make F12 behave that way: - F12 on the menu core (alt_launcher configured): jumps directly into MENU_SYSTEM1 (System Settings) instead of opening the core picker. - F12 again while in System Settings: closes the OSD (back to MENU_NONE1) instead of opening the core picker. Behavior on non-menu cores and on the menu core without alt_launcher configured is unchanged. The picker is still reachable from inside System Settings via the existing "Switch to ..." entries — we just stop forcing it as the only entry point. Combined with the previous commit (F12 falls through user_io_kbd while the launcher runs) the user can press F12 to overlay the OSD on top of their running launcher, toggle CRT mode in one step, then F12 again to hand inputs back to the launcher. --- menu.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/menu.cpp b/menu.cpp index 0927523e0..0b09d25d4 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1577,8 +1577,19 @@ void HandleUI(void) } else if (is_menu()) { - menusub = 6; - SelectFile("", 0, SCANO_CORES, MENU_CORE_FILE_SELECTED1, MENU_SYSTEM1); + if (alt_launcher_configured()) + { + // With an alt launcher, the file picker is not the user's + // natural entry point — they want the OSD overlay (System + // Settings) directly so they can flip CRT mode etc. + menustate = MENU_SYSTEM1; + menusub = 0; + } + else + { + menusub = 6; + SelectFile("", 0, SCANO_CORES, MENU_CORE_FILE_SELECTED1, MENU_SYSTEM1); + } } else if (is_minimig()) { @@ -6780,6 +6791,13 @@ void HandleUI(void) case MENU_SYSTEM2: if (menu) { + if (alt_launcher_configured()) + { + // F12 toggles: the OSD opened directly into System Settings, + // pressing F12 again closes it instead of opening the core picker. + menustate = MENU_NONE1; + break; + } SelectFile("", 0, SCANO_CORES, MENU_CORE_FILE_SELECTED1, MENU_SYSTEM1); break; } From 9c831d0d53be76ee39d09b9462d2bd59db73c551 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 01:08:23 +0200 Subject: [PATCH 09/24] fix(zaparoo): suppress fb_terminal nag and let System Settings render over launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two video_fb_state() gates were unconditionally getting in the way when the alt launcher is configured: 1. vga_nag() was painting the "fb_terminal=0 / vga_scaler=1" warning on VGA every time the OSD closed (MENU_NONE1 -> vga_nag), because video_fb_state() is permanently true while the launcher runs in HDMI mode. The user has fb_terminal on by design — the warning is wrong for this configuration. 2. MENU_SYSTEM1 was bailing immediately to MENU_NONE1 when video_fb_state() was true, so F12 in HDMI launcher mode appeared to do nothing — it really opened MENU_SYSTEM1 and instantly closed it, flashing the vga_nag warning on the way out. Both gates now opt out when alt_launcher_configured(): the warning is suppressed (CRT just shows the menu core's snow pattern with no overlay when the OSD is closed), and System Settings is allowed to render as the OSD overlay on top of the running launcher. The OSD shows on both CRT and HDMI as before. Combined with the prior commits, the full flow the user asked for now works: launcher running -> CRT shows clean snow / HDMI shows the launcher app -> F12 -> OSD overlay opens directly into System Settings on both screens, inputs grab automatically -> F12 again -> OSD closes, inputs return to the launcher. --- menu.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/menu.cpp b/menu.cpp index 0b09d25d4..b0db347df 100644 --- a/menu.cpp +++ b/menu.cpp @@ -829,7 +829,11 @@ const char* get_rbf_name_bootcore(char *str) static void vga_nag() { - if (video_fb_state()) + // With an alt launcher configured the user has fb_terminal on by design + // and the CRT is fed directly by the menu core (snow pattern when status[9]=0, + // or the launcher's framebuffer when status[9]=1). The "fix MiSTer.ini" + // nag is not appropriate — just leave the OSD off without the warning. + if (video_fb_state() && !alt_launcher_configured()) { EnableOsd_on(OSD_VGA); OsdSetSize(16); @@ -6705,7 +6709,11 @@ void HandleUI(void) /* system menu */ /******************************************************************/ case MENU_SYSTEM1: - if (video_fb_state()) + // Without an alt launcher, the wallpaper / fb_terminal flow can't coexist + // with this menu — bail out so vga_nag can show the MiSTer.ini warning. + // With an alt launcher the OSD overlay is exactly what we want on top of + // the running launcher, so let it render through. + if (video_fb_state() && !alt_launcher_configured()) { menustate = MENU_NONE1; break; From 54001f115a05e02f6382bed1ff86384eb0156f2f Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 01:42:27 +0200 Subject: [PATCH 10/24] fix(zaparoo): F12/MENU open the OSD overlay over a running launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three layered gates were silently swallowing F12/MENU when the alt launcher was running in HDMI mode, leaving the previous OSD-overlay work unreachable in practice: 1. user_io.cpp dropped KEY_MENU outright while alt_launcher was active. F12 already passed through, but the user explicitly wants the joypad MENU button to also open the OSD. Drop the early return entirely so both keys go through the normal is_menu_event path. 2. menu.cpp:1277 gated the F12/MENU case statements on "(!video_fb_state || vt != 2)" — i.e. we only processed the keys when fb_terminal was off OR we weren't on tty2. With the launcher running on tty2 with HDMI FB on, both subexpressions are false, the gate fails, the `menu` flag never gets set, and the OSD never opens. Extend the gate to also fire when alt_launcher_active(). 3. menu.cpp:1288 (F12 release) called video_menu_bg + video_fb_enable(0) unconditionally, which would have torn down the launcher's HDMI display on every F12 keystroke. Skip that teardown when the alt launcher is active — the OSD compositor sits post-ascal and overlays whatever the launcher is rendering without needing fb_terminal to drop. Net effect: with alt_launcher running in HDMI mode, F12 (or the joypad MENU button) opens the MiSTer OSD overlay (System Settings, per the earlier commits in this branch); F12/MENU again closes it; the launcher keeps painting HDMI underneath the whole time. Input grabbing toggles automatically through the existing user_io_osd_key_enable / input_switch hookup, so MiSTer steals inputs while the OSD is up and hands them back when it closes. --- menu.cpp | 15 +++++++++++---- user_io.cpp | 14 ++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/menu.cpp b/menu.cpp index b0db347df..b8ad7baa4 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1273,8 +1273,12 @@ void HandleUI(void) } } - //prevent OSD control while script is executing on framebuffer - if ((!video_fb_state() || video_chvt(0) != 2) && !select_ini) + // Prevent OSD control while a script is executing on the framebuffer. + // The alt launcher exception lets F12/MENU open the OSD overlay on top + // of the running launcher app — the OSD compositor sits post-ascal so + // it overlays whatever the launcher renders, and we deliberately skip + // the fb_terminal teardown on release so the launcher's display stays. + if (((!video_fb_state() || video_chvt(0) != 2) || alt_launcher_active()) && !select_ini) { switch (c) { @@ -1289,8 +1293,11 @@ void HandleUI(void) if (!ignore_osd_release) menu = true; ignore_osd_release = false; - if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); - video_fb_enable(0); + if (!alt_launcher_active()) + { + if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); + video_fb_enable(0); + } break; case KEY_F1: if (is_menu() && cfg.fb_terminal) diff --git a/user_io.cpp b/user_io.cpp index 0cb46e31a..94594cbb4 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -4157,14 +4157,12 @@ void user_io_kbd(uint16_t key, int press) if (key) { uint32_t code = get_ps2_code(key); - // While the launcher is running the joypad MENU button (KEY_MENU, - // remapped via alt_launcher_fb_terminal_key) belongs to the launcher - // app's own UI. F12 stays with MiSTer so the user can overlay the - // native OSD on top of the launcher and toggle CRT mode without - // exiting their app — input grabbing flips automatically when the - // OSD opens (user_io_osd_key_enable -> input_switch). - if (alt_launcher_active() && key == KEY_MENU) - return; + // Both F12 and KEY_MENU now reach the normal menu/OSD flow even + // while the alt launcher is running, so the user can open the OSD + // overlay (System Settings) on top of their launcher app from + // either keyboard or joypad MENU button. Input grabbing flips + // automatically when the OSD opens (user_io_osd_key_enable -> + // input_switch -> EVIOCGRAB). bool is_menu_event = ((has_menu() || osd_is_visible || (get_key_mod() & (LALT | RALT | RGUI | LGUI))) && (((key == KEY_F12) && (!is_f12_mod_needed() || (get_key_mod() & (RGUI | LGUI)))) || key == KEY_MENU)); if (!press) { From 00b7251a52930d278c9aac9991415bbf2427b25d Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 01:53:29 +0200 Subject: [PATCH 11/24] fix(zaparoo): allow OSD to close in CRT mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OSD-open trigger at MENU_NONE2 keeps the menu auto-opened on the menu core whenever fb_terminal is off — that's the original assumption that "the menu core is the menu screen, OSD always belongs up." It works fine for vanilla menu core and for the launcher in HDMI mode (where video_fb_state is true and the middle condition is false). In CRT mode with the alt launcher running, video_fb_state is false (the HPS framebuffer is intentionally disabled — the FPGA reads DDR for video directly via status[9]). So the middle condition stays permanently true: every time the user closes the OSD, the next loop iteration re-opens it instantly. Net effect: F12/MENU appears to do nothing in CRT mode, the OSD is stuck open. Suppress the auto-open when alt_launcher_active(). Explicit F12 / MENU presses still set the `menu` flag and open/close the OSD as normal — this just stops the loop from forcing it back up. --- menu.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/menu.cpp b/menu.cpp index b8ad7baa4..d3d8b754c 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1567,7 +1567,13 @@ void HandleUI(void) menustate = MENU_UNLOCK1; osd_code_entry[0] = 0; } - else if (menu || (is_menu() && !video_fb_state()) || (menustate == MENU_NONE2 && !mgl->done && mgl->state == 1)) + // On the menu core without an alt launcher, the menu *is* the screen — + // keep auto-opening the OSD whenever fb_terminal is off. With an alt + // launcher running, that rule would re-open System Settings the moment + // the user closes it (in CRT mode video_fb_state is false), so the OSD + // could never actually close. Suppress the auto-open in that case; + // explicit F12/MENU presses still open and close it normally. + else if (menu || (is_menu() && !video_fb_state() && !alt_launcher_active()) || (menustate == MENU_NONE2 && !mgl->done && mgl->state == 1)) { OsdSetSize(16); menusub = 0; From 6dc8bb8d14d72aeca2c7dfb300b5d589404f699b Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 02:12:42 +0200 Subject: [PATCH 12/24] fix(zaparoo): scope the alt-launcher F-key exception to F12 only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous attempt opened the F-key gate for *all* function keys when the alt launcher was active. That meant other F-keys still ran their side effects on top of the running launcher: - F1 -> user_io_status_set + video_menu_bg, overwriting the launcher's HDMI framebuffer with a wallpaper. (Worse: alt_launcher_fb_terminal_key maps the joypad L2 button to KEY_F1, so any L2 press silently corrupted the HDMI image.) - F9 -> video_chvt(1) + video_fb_enable(!video_fb_state), which yanks the active VT off tty2 and disables fb_terminal — the launcher's display goes black. - F7/F10/F11 -> open OSD-related menus that were never intended to coexist with the launcher. That's the "HDMI framebuffer kind of crash" symptom. Restore the original strict gate for the main switch so all of the above side effects stay disabled while the launcher owns the framebuffer. Add a separate else-if block that handles only F12 / F12-UP when alt_launcher_active(), with no fb_terminal teardown on release. Net behaviour: - Launcher running: F12 toggles the MiSTer OSD overlay on top of the launcher; nothing else touches the framebuffer. - Launcher not active: original F-key behaviour, byte-for-byte. --- menu.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/menu.cpp b/menu.cpp index d3d8b754c..3b89fcdfa 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1273,12 +1273,8 @@ void HandleUI(void) } } - // Prevent OSD control while a script is executing on the framebuffer. - // The alt launcher exception lets F12/MENU open the OSD overlay on top - // of the running launcher app — the OSD compositor sits post-ascal so - // it overlays whatever the launcher renders, and we deliberately skip - // the fb_terminal teardown on release so the launcher's display stays. - if (((!video_fb_state() || video_chvt(0) != 2) || alt_launcher_active()) && !select_ini) + //prevent OSD control while script is executing on framebuffer + if ((!video_fb_state() || video_chvt(0) != 2) && !select_ini) { switch (c) { @@ -1293,11 +1289,8 @@ void HandleUI(void) if (!ignore_osd_release) menu = true; ignore_osd_release = false; - if (!alt_launcher_active()) - { - if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); - video_fb_enable(0); - } + if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); + video_fb_enable(0); break; case KEY_F1: if (is_menu() && cfg.fb_terminal) @@ -1387,6 +1380,29 @@ void HandleUI(void) break; } } + // Alt-launcher exception: while the launcher owns the framebuffer, only + // F12 is honoured — to overlay the MiSTer OSD on top of the launcher app + // and toggle it back off. F1 (video_menu_bg), F9 (video_fb_enable), etc. + // would corrupt or kill the launcher's display, so they're suppressed. + // fb_terminal is NOT torn down on F12 release here. + else if (alt_launcher_active() && !select_ini) + { + switch (c) + { + case KEY_F12: + if (user_io_osd_is_visible()) + { + menu = true; + ignore_osd_release = true; + } + break; + case KEY_F12 | UPSTROKE: + if (!ignore_osd_release) + menu = true; + ignore_osd_release = false; + break; + } + } if (select_ini) { From b9e3beaaef973b8cff8b6927513a9e52be278b8c Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 10:28:00 +0800 Subject: [PATCH 13/24] feat(zaparoo): support custom MENU_RBF and consolidate alt-launcher F-key handling Adds MENU_RBF ini option and support/zaparoo/menu_rbf.{cpp,h} helpers so fpga_load_rbf, ScanDirectory, and the menu reset paths use the configured menu core instead of the hardcoded "menu.rbf". user_io_init forces a reload at startup when u-boot/stock loaded the system menu.rbf before us. menu.cpp HandleUI: fold the separate alt_launcher_active() else-if back into the main switch and gate the destructive F-keys (F1, F9, F12-up fb teardown) with !alt_launcher_active() instead, so the launcher's framebuffer is preserved while still allowing F12 to overlay the OSD. --- cfg.cpp | 1 + cfg.h | 1 + file_io.cpp | 5 +++-- fpga_io.cpp | 5 +++-- menu.cpp | 42 ++++++++++-------------------------- support/zaparoo/menu_rbf.cpp | 23 ++++++++++++++++++++ support/zaparoo/menu_rbf.h | 4 ++++ user_io.cpp | 9 ++++++-- 8 files changed, 53 insertions(+), 37 deletions(-) create mode 100644 support/zaparoo/menu_rbf.cpp create mode 100644 support/zaparoo/menu_rbf.h diff --git a/cfg.cpp b/cfg.cpp index 112a7f1bd..709ce731a 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -140,6 +140,7 @@ static const ini_var_t ini_vars[] = { "XBE2_SHIFT", (void*)(&(cfg.xbe2_shift)), UINT16, 0, 0x22F }, { "SPD_QUIRK", (void*)(&(cfg.spd_quirk)), UINT8, 0, 3 }, { "ALT_LAUNCHER", (void*)(&(cfg.alt_launcher)), STRING, 0, sizeof(cfg.alt_launcher) - 1 }, + { "MENU_RBF", (void*)(&(cfg.menu_rbf)), STRING, 0, sizeof(cfg.menu_rbf) - 1 }, }; static const int nvars = (int)(sizeof(ini_vars) / sizeof(ini_var_t)); diff --git a/cfg.h b/cfg.h index 6b5213d6c..9376a9766 100644 --- a/cfg.h +++ b/cfg.h @@ -107,6 +107,7 @@ typedef struct { uint16_t xbe2_shift; uint8_t spd_quirk; char alt_launcher[1024]; + char menu_rbf[1024]; } cfg_t; extern cfg_t cfg; diff --git a/file_io.cpp b/file_io.cpp index 58e9aea82..055e2b827 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -33,6 +33,7 @@ #include "scheduler.h" #include "video.h" #include "support.h" +#include "support/zaparoo/menu_rbf.h" #define MIN(a,b) (((a)<(b)) ? (a) : (b)) @@ -1127,7 +1128,7 @@ void setStorage(int dev) { device = 0; FileSave(CONFIG_DIR"/device.bin", &dev, sizeof(int)); - fpga_load_rbf("menu.rbf"); + fpga_load_rbf(menu_rbf_name()); } static int orig_device = 0; @@ -1693,7 +1694,7 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons // skip hidden files if (!strncasecmp(de->d_name, ".", 1)) continue; //skip non-selectable files - if (!strcasecmp(de->d_name, "menu.rbf")) continue; + if (is_menu_rbf(de->d_name)) continue; if (!strncasecmp(de->d_name, "menu_20", 7)) continue; if (!strncasecmp(de->d_name, "boot", 4)) { diff --git a/fpga_io.cpp b/fpga_io.cpp index 1583883a6..83ff8736a 100644 --- a/fpga_io.cpp +++ b/fpga_io.cpp @@ -17,6 +17,7 @@ #include "shmem.h" #include "offload.h" #include "support/zaparoo/alt_launcher.h" +#include "support/zaparoo/menu_rbf.h" #include "fpga_base_addr_ac5.h" #include "fpga_manager.h" @@ -441,7 +442,7 @@ int fpga_load_rbf(const char *name, const char *cfg, const char *xml) printf("Loading RBF: %s\n", name); if(name[0] == '/') strcpy(path, name); - else sprintf(path, "%s/%s", !strcasecmp(name, "menu.rbf") ? getStorageDir(0) : getRootDir(), name); + else sprintf(path, "%s/%s", is_menu_rbf(name) ? getStorageDir(0) : getRootDir(), name); int rbf = open(path, O_RDONLY); if (rbf < 0) @@ -504,7 +505,7 @@ int fpga_load_rbf(const char *name, const char *cfg, const char *xml) } close(rbf); - app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path, xml); + app_restart(is_menu_rbf(name) ? menu_rbf_name() : path, xml); return ret; } diff --git a/menu.cpp b/menu.cpp index 3b89fcdfa..60b6b0a40 100644 --- a/menu.cpp +++ b/menu.cpp @@ -50,6 +50,7 @@ along with this program. If not, see . #include "hardware.h" #include "menu.h" #include "support/zaparoo/alt_launcher.h" +#include "support/zaparoo/menu_rbf.h" #include "user_io.h" #include "debug.h" #include "fpga_io.h" @@ -1274,7 +1275,7 @@ void HandleUI(void) } //prevent OSD control while script is executing on framebuffer - if ((!video_fb_state() || video_chvt(0) != 2) && !select_ini) + if (((!video_fb_state() || video_chvt(0) != 2) || alt_launcher_active()) && !select_ini) { switch (c) { @@ -1289,11 +1290,14 @@ void HandleUI(void) if (!ignore_osd_release) menu = true; ignore_osd_release = false; - if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); - video_fb_enable(0); + if (!alt_launcher_active()) + { + if(video_fb_state()) video_menu_bg(user_io_status_get("[3:1]")); + video_fb_enable(0); + } break; case KEY_F1: - if (is_menu() && cfg.fb_terminal) + if (!alt_launcher_active() && is_menu() && cfg.fb_terminal) { user_io_status_set("[3:1]", user_io_status_get("[3:1]") + 1); user_io_status_save(user_io_create_config_name()); @@ -1316,7 +1320,7 @@ void HandleUI(void) break; case KEY_F9: - if ((is_menu() || ((get_key_mod() & (LALT | RALT)) && (get_key_mod() & (LCTRL | RCTRL))) || has_fb_terminal) && cfg.fb_terminal) + if (!alt_launcher_active() && (is_menu() || ((get_key_mod() & (LALT | RALT)) && (get_key_mod() & (LCTRL | RCTRL))) || has_fb_terminal) && cfg.fb_terminal) { video_chvt(1); video_fb_enable(!video_fb_state()); @@ -1380,30 +1384,6 @@ void HandleUI(void) break; } } - // Alt-launcher exception: while the launcher owns the framebuffer, only - // F12 is honoured — to overlay the MiSTer OSD on top of the launcher app - // and toggle it back off. F1 (video_menu_bg), F9 (video_fb_enable), etc. - // would corrupt or kill the launcher's display, so they're suppressed. - // fb_terminal is NOT torn down on F12 release here. - else if (alt_launcher_active() && !select_ini) - { - switch (c) - { - case KEY_F12: - if (user_io_osd_is_visible()) - { - menu = true; - ignore_osd_release = true; - } - break; - case KEY_F12 | UPSTROKE: - if (!ignore_osd_release) - menu = true; - ignore_osd_release = false; - break; - } - } - if (select_ini) { DISKLED_ON; @@ -3160,7 +3140,7 @@ void HandleUI(void) } } - if(!hold_cnt && reboot_req) fpga_load_rbf("menu.rbf"); + if(!hold_cnt && reboot_req) fpga_load_rbf(menu_rbf_name()); break; case MENU_VIDEOPROC1: @@ -6920,7 +6900,7 @@ void HandleUI(void) menustate = MENU_MISC1; } - if (!hold_cnt && reboot_req) fpga_load_rbf("menu.rbf"); + if (!hold_cnt && reboot_req) fpga_load_rbf(menu_rbf_name()); break; case MENU_JOYSYSMAP: diff --git a/support/zaparoo/menu_rbf.cpp b/support/zaparoo/menu_rbf.cpp new file mode 100644 index 000000000..69a003571 --- /dev/null +++ b/support/zaparoo/menu_rbf.cpp @@ -0,0 +1,23 @@ +#include "menu_rbf.h" +#include +#include +#include "../../cfg.h" + +const char *menu_rbf_name(void) +{ + return cfg.menu_rbf[0] ? cfg.menu_rbf : "menu.rbf"; +} + +bool is_menu_rbf(const char *name) +{ + if (!name || !name[0]) return false; + if (!strcasecmp(name, "menu.rbf")) return true; + if (cfg.menu_rbf[0]) + { + if (!strcasecmp(name, cfg.menu_rbf)) return true; + const char *slash = strrchr(cfg.menu_rbf, '/'); + const char *base = slash ? slash + 1 : cfg.menu_rbf; + if (base[0] && !strcasecmp(name, base)) return true; + } + return false; +} diff --git a/support/zaparoo/menu_rbf.h b/support/zaparoo/menu_rbf.h new file mode 100644 index 000000000..72da01dba --- /dev/null +++ b/support/zaparoo/menu_rbf.h @@ -0,0 +1,4 @@ +#pragma once + +const char *menu_rbf_name(void); +bool is_menu_rbf(const char *name); diff --git a/user_io.cpp b/user_io.cpp index 94594cbb4..8e022d831 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -41,6 +41,7 @@ #include "scaler.h" #include "support.h" #include "support/zaparoo/alt_launcher.h" +#include "support/zaparoo/menu_rbf.h" static char core_path[1024] = {}; static char rbf_path[1024] = {}; @@ -1454,6 +1455,10 @@ void user_io_init(const char *path, const char *xml) app_restart(path, xml, main); } + // Zaparoo: u-boot/stock binary may have loaded the system menu.rbf before we got here. + // If our cfg.menu_rbf differs and we booted without an explicit RBF path, force a reload. + if (is_menu() && cfg.menu_rbf[0] && !rbf_path[0]) fpga_load_rbf(menu_rbf_name()); + uint8_t hotswap[4] = {}; ide_reset(hotswap); @@ -3032,7 +3037,7 @@ void user_io_set_ini(int ini_num) if (!name[0]) { - name = "menu.rbf"; + name = menu_rbf_name(); xml = NULL; } @@ -3709,7 +3714,7 @@ void user_io_poll() if (!coldreset_req && prev_coldreset_req) { - fpga_load_rbf("menu.rbf"); + fpga_load_rbf(menu_rbf_name()); } prev_coldreset_req = coldreset_req; From 27019d8af2a6b30abddbbbc8ba864351174621a7 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 10:28:12 +0800 Subject: [PATCH 14/24] fix(zaparoo): route joypad input to launcher in native CRT mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In CRT launcher mode video_fb_state() returns false, so the special input_cb path that remaps joypad buttons via mmap[] (and ultimately calls uinp_send_key for the launcher) was being skipped — events fell through to the per-core input[dev].map[] path, which doesn't reach joy_digital reliably for the menu/system mapping. Mirrors the existing fix at joy_digital line 2475: extend the gate to include alt_launcher_active() so CRT-mode joypad presses generate uinput keys for the launcher's tty. --- input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.cpp b/input.cpp index 28f70a050..d8866fa22 100644 --- a/input.cpp +++ b/input.cpp @@ -3564,7 +3564,7 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int if (osd_event == 2) joy_digital(input[dev].num, 0, 0, 0, BTN_OSD); } - if (user_io_osd_is_visible() || video_fb_state()) + if (user_io_osd_is_visible() || video_fb_state() || alt_launcher_active()) { if (ev->value <= 1) { From 08ccd5dc0ef08166f8a7b8280c896da066c0692e Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 11:09:56 +0800 Subject: [PATCH 15/24] feat(zaparoo): persist alt-launcher CRT/HDMI mode across reboots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OSD CRT/HDMI toggle was ephemeral — both reboots and returning from a core reset the launcher back to HDMI default. Persist the most-recent toggle to config/alt_launcher_crt.bin and restore it on menu init. Adds a dedicated zaparoo_alt_launcher_init_for_menu() entry point so the upstream call site in user_io.cpp stays a one-line edit and avoids overload-resolution coupling between caller and callee. --- support/zaparoo/alt_launcher.cpp | 23 +++++++++++++++++++++++ support/zaparoo/alt_launcher.h | 3 ++- user_io.cpp | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 2e9d1c465..5f1f083e9 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -58,6 +58,20 @@ static const int s_vt = 2; static const char s_tty[] = "tty2"; static const char s_tty_path[] = "/dev/tty2"; static const char s_fb_mode_path[] = "/sys/module/MiSTer_fb/parameters/mode"; +static const char s_crt_state_file[] = "alt_launcher_crt.bin"; + +static bool load_persisted_native_crt(void) +{ + uint8_t v = 0; + FileLoadConfig(s_crt_state_file, &v, sizeof(v)); + return v != 0; +} + +static void save_persisted_native_crt(bool crt) +{ + uint8_t v = crt ? 1 : 0; + FileSaveConfig(s_crt_state_file, &v, sizeof(v)); +} static void set_launcher_fb_mode(int fmt, int rb, int width, int height, int stride, bool log = true) { @@ -279,6 +293,8 @@ void alt_launcher_toggle_crt(void) bool current_crt = alt_launcher_native_crt(); bool target_crt = !current_crt; + save_persisted_native_crt(target_crt); + printf("alt_launcher: toggle CRT path %d -> %d\n", current_crt, target_crt); // Shutdown drops status[9], releases the FB mode and restores HPS framebuffer @@ -429,3 +445,10 @@ void zaparoo_alt_launcher_init_for_core(void) alt_launcher_init(true); } } + +void zaparoo_alt_launcher_init_for_menu(void) +{ + bool crt = load_persisted_native_crt(); + printf("alt_launcher: initializing menu launcher (persisted crt=%d)\n", crt); + alt_launcher_init(crt); +} diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index f74f00a60..36b95b83f 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -5,7 +5,7 @@ #define ALT_LAUNCHER_MENUSUB 31 #define ALT_LAUNCHER_CRT_MENUSUB 30 -void alt_launcher_init(bool native_crt = false); +void alt_launcher_init(bool native_crt); void alt_launcher_poll(void); void alt_launcher_shutdown(void); void alt_launcher_toggle_crt(void); @@ -18,3 +18,4 @@ uint16_t alt_launcher_fb_terminal_key(uint32_t mask, bool osd_button); bool zaparoo_is_native_core(void); void zaparoo_alt_launcher_init_for_core(void); +void zaparoo_alt_launcher_init_for_menu(void); diff --git a/user_io.cpp b/user_io.cpp index 8e022d831..0f97f6edb 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1533,7 +1533,7 @@ void user_io_init(const char *path, const char *xml) else if (is_menu()) { user_io_status_set("[4]", (cfg.menu_pal) ? 1 : 0); - if (cfg.alt_launcher[0] && cfg.fb_terminal) alt_launcher_init(); + if (cfg.alt_launcher[0] && cfg.fb_terminal) zaparoo_alt_launcher_init_for_menu(); else if (cfg.fb_terminal) video_menu_bg(user_io_status_get("[3:1]")); else user_io_status_set("[3:1]", 0); From c7804d22d4c4e8ae59e276e025ff340ca5dbdbbd Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 12:43:09 +0800 Subject: [PATCH 16/24] fix(zaparoo): clear FPGA CRT scan-out region before launcher spawn The alt-launcher's CRT path scans out from a dedicated FPGA-mapped DDR region at 0x3A000000 (control word + two 320x240 RGBA buffers), not from the kernel /dev/fb0 at 0x22000000. Nothing zeros that region between launcher sessions or across software reboots, so the prior session's last frame stayed on screen until the launcher's writer thread had finished Qt startup and produced its first overwrite. Zero the buffers before flipping status[9] so the FPGA scans out black during launcher init instead of stale pixels. Also double-write the kernel FB mode with a 100 ms settle so the 320x240 layout is live before status[9] flips, eliminating the launcher's first-frame size race. --- support/zaparoo/alt_launcher.cpp | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 5f1f083e9..f45821be8 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -9,11 +9,13 @@ #include #include #include +#include #include #include "cfg.h" #include "file_io.h" #include "hardware.h" #include "input.h" +#include "shmem.h" #include "user_io.h" #include "video.h" @@ -93,6 +95,27 @@ static void set_native_crt_fb_mode(bool log = true) set_launcher_fb_mode(8888, 1, 320, 240, 1280, log); } +static void blank_native_crt_fb(void) +{ + // CRT path doesn't read /dev/fb0 (kernel FB at 0x22000000). The launcher + // runs a worker that copies the top-left 320x240 from /dev/fb0 into a + // separate FPGA-mapped region at 0x3A000000 (control word + two 320x240 + // RGBA buffers). The FPGA scans out from that region. Nothing zeros it + // across launcher restarts or software reboots, so the previous session's + // last frame ghosts in until the launcher's writer thread starts. + const uint32_t native_addr = 0x3A000000u; + const uint32_t native_size = 0x000A0000u; + void *p = shmem_map(native_addr, native_size); + if (!p) + { + printf("alt_launcher: blank native shmem_map(0x%x, %u) failed\n", native_addr, native_size); + return; + } + memset(p, 0, native_size); + shmem_unmap(p, native_size); + printf("alt_launcher: blanked %u bytes of CRT native video DDR at 0x%x\n", native_size, native_addr); +} + static void clear_launcher_tty(void) { int tty_fd = open(s_tty_path, O_WRONLY | O_CLOEXEC); @@ -162,7 +185,17 @@ static void enable_native_crt_path(void) { set_vga_fb(0); video_fb_enable(0); + + // Double-write with a settle window so the kernel module's 320x240 layout + // is live before status[9] flips. Without this, the launcher renders for + // up to a second under stale dims (the post-fork retry timer used to be + // what eventually fixed the picture). + set_native_crt_fb_mode(false); + usleep(100000); set_native_crt_fb_mode(); + + blank_native_crt_fb(); + user_io_status_set("[9]", 1); s_native_status_timer = GetTimer(500); if (!s_native_status_timer) s_native_status_timer = 1; From 892777c6cc611fd6f30a08d416214f14856a6bcc Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 14:00:40 +0800 Subject: [PATCH 17/24] refactor(zaparoo): trim alt-launcher OSD menu via dedicated helper Move the alt-launcher System Settings menu (Remap, Define joystick, CRT toggle, Reboot, Exit) out of menu.cpp's MENU_SYSTEM2 block into a new support/zaparoo/alt_launcher_menu.cpp helper. menu.cpp now contains three single-purpose hooks: - hold-to-cold-reboot key gate ORs in alt_launcher_system_holding_reboot - MENU_SYSTEM1 early-exit calls alt_launcher_render_system_menu when the launcher is configured - MENU_SYSTEM2 dispatch translates the trimmed menu's selection to upstream switch cases via alt_launcher_translate_system_select Drops the unused ALT_LAUNCHER_CRT_MENUSUB define. The trim removes "Switch to USB", "Scripts", and "Help" rows that aren't relevant when the launcher is the only "core" running on top of menu.rbf, and routes Reboot through the cold-reboot hold logic. This collapses the upstream-file diff to ~14 lines so future rebases auto-resolve cleanly. --- menu.cpp | 39 ++++------- support/zaparoo/alt_launcher.h | 1 - support/zaparoo/alt_launcher_menu.cpp | 96 +++++++++++++++++++++++++++ support/zaparoo/alt_launcher_menu.h | 30 +++++++++ 4 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 support/zaparoo/alt_launcher_menu.cpp create mode 100644 support/zaparoo/alt_launcher_menu.h diff --git a/menu.cpp b/menu.cpp index 60b6b0a40..debc84af3 100644 --- a/menu.cpp +++ b/menu.cpp @@ -50,6 +50,7 @@ along with this program. If not, see . #include "hardware.h" #include "menu.h" #include "support/zaparoo/alt_launcher.h" +#include "support/zaparoo/alt_launcher_menu.h" #include "support/zaparoo/menu_rbf.h" #include "user_io.h" #include "debug.h" @@ -573,7 +574,7 @@ static uint32_t menu_key_get(void) else if (CheckTimer(repeat)) { repeat = GetTimer(REPEATRATE); - if (GetASCIIKey(c1) || menustate == MENU_FILE_SELECT2 || ((menustate == MENU_COMMON2) && (menusub == 17)) || ((menustate == MENU_SYSTEM2) && (menusub == 5))) + if (GetASCIIKey(c1) || menustate == MENU_FILE_SELECT2 || ((menustate == MENU_COMMON2) && (menusub == 17)) || ((menustate == MENU_SYSTEM2) && (menusub == 5)) || ((menustate == MENU_SYSTEM2) && alt_launcher_system_holding_reboot(menusub))) { c = c1; hold_cnt++; @@ -2835,10 +2836,6 @@ void HandleUI(void) { menumask |= (1ULL << ALT_LAUNCHER_MENUSUB); MenuWrite(n++, " Launcher", menusub == ALT_LAUNCHER_MENUSUB, 0); - - menumask |= (1ULL << ALT_LAUNCHER_CRT_MENUSUB); - sprintf(s, " CRT mode: %s", alt_launcher_native_crt() ? "On" : "Off"); - MenuWrite(n++, s, menusub == ALT_LAUNCHER_CRT_MENUSUB, 0); } MenuWrite(n++, " Core \x16", menusub == 0, 0); @@ -3087,11 +3084,6 @@ void HandleUI(void) reboot_req = 1; break; - case ALT_LAUNCHER_CRT_MENUSUB: - alt_launcher_toggle_crt(); - menustate = MENU_COMMON1; - break; - default: menustate = MENU_NONE1; break; @@ -6732,10 +6724,18 @@ void HandleUI(void) helptext_idx = 0; parentstate = menustate; + // alt-launcher mode delegates the entire System menu render to a + // support helper so this upstream block stays untouched. + if (alt_launcher_configured()) + { + cr = alt_launcher_render_system_menu(menusub, &menumask, &reboot_req, &sysinfo_timer); + menustate = MENU_SYSTEM2; + break; + } + m = 0; OsdSetTitle("System Settings", OSD_ARROW_LEFT); menumask = 0x7F; - if (alt_launcher_configured()) menumask |= (1ULL << 7); OsdWrite(m++); sprintf(s, " MiSTer v%s", version + 5); @@ -6788,11 +6788,6 @@ void HandleUI(void) OsdWrite(m++, " Define joystick buttons \x16", menusub == 2); OsdWrite(m++, " Scripts \x16", menusub == 3); OsdWrite(m++, " Help \x16", menusub == 4); - if (alt_launcher_configured()) - { - sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); - OsdWrite(m++, s, menusub == 7); - } OsdWrite(m++, ""); cr = m; OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 5); @@ -6820,7 +6815,9 @@ void HandleUI(void) } else if (select) { - switch (menusub) + int dispatch = alt_launcher_translate_system_select(menusub); + if (dispatch < 0) { menustate = MENU_SYSTEM1; break; } + switch (dispatch) { case 0: if (getStorage(1) || isUSBMounted()) setStorage(!getStorage(1)); @@ -6885,14 +6882,6 @@ void HandleUI(void) case 6: menustate = MENU_NONE1; break; - - case 7: - if (alt_launcher_configured()) - { - alt_launcher_toggle_crt(); - menustate = MENU_SYSTEM1; - } - break; } } else if (left) diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 36b95b83f..2a4aad69c 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -3,7 +3,6 @@ #include #define ALT_LAUNCHER_MENUSUB 31 -#define ALT_LAUNCHER_CRT_MENUSUB 30 void alt_launcher_init(bool native_crt); void alt_launcher_poll(void); diff --git a/support/zaparoo/alt_launcher_menu.cpp b/support/zaparoo/alt_launcher_menu.cpp new file mode 100644 index 000000000..4334c0b40 --- /dev/null +++ b/support/zaparoo/alt_launcher_menu.cpp @@ -0,0 +1,96 @@ +#include "alt_launcher_menu.h" +#include "alt_launcher.h" +#include "file_io.h" +#include "osd.h" + +#include +#include +#include + +extern const char *version; + +// The OSD column used for the Exit row label, sized to match +// menu.cpp's STD_EXIT define (a local #define there, kept in sync +// here rather than re-exported to avoid a header touch). +#define ALT_STD_EXIT " exit" + +int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, + int *reboot_req, + long *sysinfo_timer) +{ + if (!alt_launcher_configured()) return 0; + + char s[256]; + int m = 0; + + OsdSetTitle("System Settings", OSD_ARROW_LEFT); + *menumask = 0x1F; + + OsdWrite(m++); + sprintf(s, " MiSTer v%s", version + 5); + { + char str[8] = {}; + FILE *f = fopen("/MiSTer.version", "r"); + if (f) + { + if (fread(str, 6, 1, f)) sprintf(s, " MiSTer v%s, OS v%s", version + 5, str); + fclose(f); + } + } + OsdWrite(m++, s); + + { + uint64_t avail = 0; + struct statvfs buf; + memset(&buf, 0, sizeof(buf)); + if (!statvfs(getRootDir(), &buf)) avail = buf.f_bsize * buf.f_bavail; + if (avail < (10ull * 1024 * 1024 * 1024)) + sprintf(s, " Available space: %llumb", (unsigned long long)(avail / (1024 * 1024))); + else + sprintf(s, " Available space: %llugb", (unsigned long long)(avail / (1024 * 1024 * 1024))); + OsdWrite(m + 2, s, 0, 0); + } + + OsdWrite(m++, ""); + OsdWrite(m++, ""); + m++; + OsdWrite(m++, ""); + OsdWrite(m++, ""); + + OsdWrite(m++, " Remap keyboard \x16", menusub == 0); + OsdWrite(m++, " Define joystick buttons \x16", menusub == 1); + + sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); + OsdWrite(m++, s, menusub == 2); + + OsdWrite(m++, ""); + int cr = m; + OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 3); + *sysinfo_timer = 0; + *reboot_req = 0; + + while (m < OsdGetSize() - 1) OsdWrite(m++, ""); + OsdWrite(15, ALT_STD_EXIT, menusub == 4); + + return cr; +} + +int alt_launcher_translate_system_select(int menusub) +{ + if (!alt_launcher_configured()) return menusub; + + if (menusub == 2) + { + alt_launcher_toggle_crt(); + return -1; + } + + static const int map[] = { 1, 2, -1, 5, 6 }; + if (menusub < 0 || menusub >= (int)(sizeof(map) / sizeof(map[0]))) return -1; + return map[menusub]; +} + +bool alt_launcher_system_holding_reboot(int menusub) +{ + return alt_launcher_configured() && menusub == 3; +} diff --git a/support/zaparoo/alt_launcher_menu.h b/support/zaparoo/alt_launcher_menu.h new file mode 100644 index 000000000..98cd6f8c7 --- /dev/null +++ b/support/zaparoo/alt_launcher_menu.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +// Trimmed System Settings menu for alt-launcher mode. The launcher is +// the only "core" running on top of menu.rbf, so storage toggle, +// scripts and the bundled help PDF are irrelevant — this layout +// hides them and exposes only Remap(0), Define joy(1), CRT mode(2), +// Reboot(3), Exit(4). +// +// All three helpers are no-ops / return safe defaults when +// alt_launcher_configured() is false, so menu.cpp's hook sites can +// be unconditional. Caller must have already set OsdSetSize(16); +// returns the row of the Reboot line so the cold-reboot animation +// in MENU_SYSTEM2 can target the right OSD slot. +int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, + int *reboot_req, + long *sysinfo_timer); + +// Translate a select press on the trimmed menu to its upstream +// MENU_SYSTEM2 switch case index. Returns -1 when the press is +// consumed inline (CRT toggle); the caller should re-render +// MENU_SYSTEM1 and skip the dispatch. +int alt_launcher_translate_system_select(int menusub); + +// menu.cpp's hold-to-cold-reboot key-repeat gate hard-codes +// menusub==5 (the upstream Reboot row). The trimmed menu places +// Reboot at menusub 3, so menu.cpp ORs in this helper. +bool alt_launcher_system_holding_reboot(int menusub); From 72037bcbfda9465a21694f86fba185093ef15067 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 14:03:29 +0800 Subject: [PATCH 18/24] refactor(zaparoo): drop ALT_LAUNCHER and MENU_RBF ini knobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fork is single-purpose, so the launcher path and the menu RBF path are now hardcoded: - "zaparoo/launcher" in support/zaparoo/alt_launcher.cpp - "zaparoo/menu_zaparoo.rbf" in support/zaparoo/menu_rbf.cpp alt_launcher_configured() switches from a cfg-string check to a cached FileExists() probe of the hardcoded path, so a missing launcher binary falls back to the upstream OSD instead of attempting to spawn nothing. The CRT persistence file renames from alt_launcher_crt.bin to zaparoo_launcher_crt.bin to match the user-facing "Zaparoo launcher" naming (internal symbols keep the alt_launcher_ prefix). Anyone with FB_TERMINAL or RECENTS in their MiSTer.ini still parses cleanly; alt_launcher_cfg_apply() runs after ini_parse() and forces both back to 1 since the launcher needs them on. ALT_LAUNCHER and MENU_RBF are gone from the parser table — legacy fork users will see a one-time "unknown option" notice and can drop those lines. --- cfg.cpp | 5 ++--- cfg.h | 2 -- support/zaparoo/alt_launcher.cpp | 23 +++++++++++++++-------- support/zaparoo/alt_launcher.h | 2 +- support/zaparoo/menu_rbf.cpp | 16 +++++++--------- user_io.cpp | 6 +++--- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/cfg.cpp b/cfg.cpp index 709ce731a..8a5f13cce 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -139,8 +139,6 @@ static const ini_var_t ini_vars[] = { "SCREENSHOT_IMAGE_FORMAT", (void *)(&(cfg.screenshot_image_format)), STRING, 0, sizeof(cfg.screenshot_image_format) - 1 }, { "XBE2_SHIFT", (void*)(&(cfg.xbe2_shift)), UINT16, 0, 0x22F }, { "SPD_QUIRK", (void*)(&(cfg.spd_quirk)), UINT8, 0, 3 }, - { "ALT_LAUNCHER", (void*)(&(cfg.alt_launcher)), STRING, 0, sizeof(cfg.alt_launcher) - 1 }, - { "MENU_RBF", (void*)(&(cfg.menu_rbf)), STRING, 0, sizeof(cfg.menu_rbf) - 1 }, }; static const int nvars = (int)(sizeof(ini_vars) / sizeof(ini_var_t)); @@ -581,7 +579,6 @@ const char* cfg_get_label(uint8_t alt) void cfg_parse() { memset(&cfg, 0, sizeof(cfg)); - alt_launcher_cfg_defaults(); cfg.csync = 1; cfg.bootscreen = 1; cfg.fb_terminal = 1; @@ -614,6 +611,8 @@ void cfg_parse() ini_parse(altcfg(), video_get_core_mode_name(0)); } + alt_launcher_cfg_apply(); + if (strlen(cfg.vga_mode)) { if (!strcasecmp(cfg.vga_mode, "rgb")) cfg.vga_mode_int = 0; diff --git a/cfg.h b/cfg.h index 9376a9766..9a14fe3bc 100644 --- a/cfg.h +++ b/cfg.h @@ -106,8 +106,6 @@ typedef struct { char screenshot_image_format[16]; uint16_t xbe2_shift; uint8_t spd_quirk; - char alt_launcher[1024]; - char menu_rbf[1024]; } cfg_t; extern cfg_t cfg; diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index f45821be8..2b38551a4 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -19,19 +19,26 @@ #include "user_io.h" #include "video.h" -void alt_launcher_cfg_defaults(void) +static const char s_launcher_path[] = "zaparoo/launcher"; + +void alt_launcher_cfg_apply(void) { + // Override any user ini values: this fork is single-purpose and the + // launcher needs both flags on to render. + cfg.fb_terminal = 1; cfg.recents = 1; } bool alt_launcher_configured(void) { - return cfg.alt_launcher[0] && cfg.fb_terminal; + static int cached = -1; + if (cached < 0) cached = FileExists(s_launcher_path, 0) ? 1 : 0; + return cached != 0; } uint16_t alt_launcher_fb_terminal_key(uint32_t mask, bool osd_button) { - if (!cfg.alt_launcher[0]) + if (!alt_launcher_configured()) return 0; if (osd_button) @@ -60,7 +67,7 @@ static const int s_vt = 2; static const char s_tty[] = "tty2"; static const char s_tty_path[] = "/dev/tty2"; static const char s_fb_mode_path[] = "/sys/module/MiSTer_fb/parameters/mode"; -static const char s_crt_state_file[] = "alt_launcher_crt.bin"; +static const char s_crt_state_file[] = "zaparoo_launcher_crt.bin"; static bool load_persisted_native_crt(void) { @@ -244,7 +251,7 @@ static void kill_launcher(pid_t pid, int sig) static void spawn(void) { char path[2100]; - strncpy(path, getFullPath(cfg.alt_launcher), sizeof(path) - 1); + strncpy(path, getFullPath(s_launcher_path), sizeof(path) - 1); path[sizeof(path) - 1] = '\0'; static const char cmd[] = @@ -339,7 +346,7 @@ void alt_launcher_toggle_crt(void) void alt_launcher_init(bool native_crt) { - if (!cfg.alt_launcher[0] || !cfg.fb_terminal || s_pid || s_gave_up) + if (!alt_launcher_configured() || s_pid || s_gave_up) return; s_crash_count = 0; s_respawn_timer = 0; @@ -394,7 +401,7 @@ void alt_launcher_poll(void) return; } - if (!cfg.alt_launcher[0] || !cfg.fb_terminal) + if (!alt_launcher_configured()) return; if (s_init_pending) @@ -471,7 +478,7 @@ bool zaparoo_is_native_core(void) void zaparoo_alt_launcher_init_for_core(void) { - if (cfg.alt_launcher[0] && cfg.fb_terminal && zaparoo_is_native_core()) + if (alt_launcher_configured() && zaparoo_is_native_core()) { printf("alt_launcher: initializing CRT mode for core '%s' '%s'\n", user_io_get_core_name(1), user_io_get_core_name(0)); diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 2a4aad69c..038501382 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -12,7 +12,7 @@ bool alt_launcher_native_crt(void); bool alt_launcher_active(void); bool alt_launcher_configured(void); -void alt_launcher_cfg_defaults(void); +void alt_launcher_cfg_apply(void); uint16_t alt_launcher_fb_terminal_key(uint32_t mask, bool osd_button); bool zaparoo_is_native_core(void); diff --git a/support/zaparoo/menu_rbf.cpp b/support/zaparoo/menu_rbf.cpp index 69a003571..80db5af2a 100644 --- a/support/zaparoo/menu_rbf.cpp +++ b/support/zaparoo/menu_rbf.cpp @@ -1,23 +1,21 @@ #include "menu_rbf.h" #include #include -#include "../../cfg.h" + +static const char s_menu_rbf_path[] = "zaparoo/menu_zaparoo.rbf"; const char *menu_rbf_name(void) { - return cfg.menu_rbf[0] ? cfg.menu_rbf : "menu.rbf"; + return s_menu_rbf_path; } bool is_menu_rbf(const char *name) { if (!name || !name[0]) return false; if (!strcasecmp(name, "menu.rbf")) return true; - if (cfg.menu_rbf[0]) - { - if (!strcasecmp(name, cfg.menu_rbf)) return true; - const char *slash = strrchr(cfg.menu_rbf, '/'); - const char *base = slash ? slash + 1 : cfg.menu_rbf; - if (base[0] && !strcasecmp(name, base)) return true; - } + if (!strcasecmp(name, s_menu_rbf_path)) return true; + const char *base = strrchr(s_menu_rbf_path, '/'); + base = base ? base + 1 : s_menu_rbf_path; + if (base[0] && !strcasecmp(name, base)) return true; return false; } diff --git a/user_io.cpp b/user_io.cpp index 0f97f6edb..76169251b 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1456,8 +1456,8 @@ void user_io_init(const char *path, const char *xml) } // Zaparoo: u-boot/stock binary may have loaded the system menu.rbf before we got here. - // If our cfg.menu_rbf differs and we booted without an explicit RBF path, force a reload. - if (is_menu() && cfg.menu_rbf[0] && !rbf_path[0]) fpga_load_rbf(menu_rbf_name()); + // Force a reload of our hardcoded menu RBF if we booted without an explicit RBF path. + if (is_menu() && !rbf_path[0]) fpga_load_rbf(menu_rbf_name()); uint8_t hotswap[4] = {}; ide_reset(hotswap); @@ -1533,7 +1533,7 @@ void user_io_init(const char *path, const char *xml) else if (is_menu()) { user_io_status_set("[4]", (cfg.menu_pal) ? 1 : 0); - if (cfg.alt_launcher[0] && cfg.fb_terminal) zaparoo_alt_launcher_init_for_menu(); + if (alt_launcher_configured()) zaparoo_alt_launcher_init_for_menu(); else if (cfg.fb_terminal) video_menu_bg(user_io_status_get("[3:1]")); else user_io_status_set("[3:1]", 0); From 09a746731f121557c01b07caa6ebf0eea2e811ae Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 14:19:15 +0800 Subject: [PATCH 19/24] fix(build): apply cumulative fork diff in stable build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-picking commit-by-commit re-exposes intra-fork revert pairs and parallel feature commits that have since been reconciled on master. Mirror unstable-build.sh and apply the cumulative fork-only diff with 3-way merge fallback so shared regions where stable has drifted from upstream master can still merge cleanly. Exclude MiSTer.ini — the fork's only change is a no-op uncomment of a default-valued line, not worth fighting stable's example-ini drift on every release. --- stable-build.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stable-build.sh b/stable-build.sh index 4e15e0f9d..2cd076cc4 100755 --- a/stable-build.sh +++ b/stable-build.sh @@ -54,7 +54,6 @@ fi STABLE_NAME=$(basename "${STABLE_FILE}") STABLE_DATE=${STABLE_NAME#MiSTer_} -FORK_COMMITS=$(git rev-list --reverse --no-merges "${UPSTREAM_REF}..${FORK_HEAD}") if [ -n "${METADATA_FILE}" ]; then cat >"${METADATA_FILE}" < Building from upstream ${STABLE_NAME} with Zaparoo ${FORK_SHORT_SHA}" git worktree add --detach "${TMP_WORKTREE}" "${STABLE_COMMIT}" >/dev/null -if [ -n "${FORK_COMMITS}" ]; then - git -C "${TMP_WORKTREE}" cherry-pick --no-commit ${FORK_COMMITS} +# Apply the cumulative fork-only diff (relative to upstream master) so revert +# pairs and other intra-fork conflicts cancel out — replaying commit-by-commit +# would re-expose them. -3 falls back to a 3-way merge when stable's content +# for a shared file has drifted from upstream master. MiSTer.ini is excluded: +# the fork's only change is an uncomment of a default-valued line, and stable's +# example ini drifts often enough to cause spurious conflicts. +FORK_DIFF=$(git diff --binary "${UPSTREAM_REF}..${FORK_HEAD}" -- . ':(exclude)MiSTer.ini') +if [ -n "${FORK_DIFF}" ]; then + printf '%s\n' "${FORK_DIFF}" | git -C "${TMP_WORKTREE}" apply -3 --index fi "${TMP_WORKTREE}/docker-build.sh" "$@" From 54fbded3f7343542686cfdb9b65940f4583346c6 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sun, 10 May 2026 17:35:49 +0800 Subject: [PATCH 20/24] feat(zaparoo): restore exit-launcher escape-to-stock behavior When the alt launcher exits cleanly the OSD reverts to stock menu items for the rest of the session (until reboot, which still routes back to the Zaparoo menu RBF). Adds an s_escaped latch in alt_launcher_configured() and gates the cores-picker root in SelectFile() on is_menu() so the populated cores list works while the Zaparoo menu RBF (in zaparoo/) is still loaded. --- menu.cpp | 4 ++-- support/zaparoo/alt_launcher.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/menu.cpp b/menu.cpp index debc84af3..8cb232112 100644 --- a/menu.cpp +++ b/menu.cpp @@ -413,8 +413,8 @@ void SelectFile(const char* path, const char* pFileExt, int Options, unsigned ch if (Options & SCANO_CORES) { - strcpy(selPath, get_rbf_dir()); - if (strlen(get_rbf_name())) + strcpy(selPath, is_menu() ? "" : get_rbf_dir()); + if (!is_menu() && strlen(get_rbf_name())) { if(strlen(selPath)) strcat(selPath, "/"); strcat(selPath, get_rbf_name()); diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 2b38551a4..4d0f61b86 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -29,8 +29,14 @@ void alt_launcher_cfg_apply(void) cfg.recents = 1; } +static bool s_escaped = false; + bool alt_launcher_configured(void) { + // After a clean exit / give-up, masquerade as not-configured so the rest + // of the OSD reverts to stock menu behavior for the rest of this session. + // Reboot re-execs MiSTer and resets this back to the file-existence cache. + if (s_escaped) return false; static int cached = -1; if (cached < 0) cached = FileExists(s_launcher_path, 0) ? 1 : 0; return cached != 0; @@ -231,6 +237,7 @@ static void return_to_normal_mode(void) s_respawn_timer = 0; s_crash_count = 0; s_gave_up = true; + s_escaped = true; } static void reset_launcher_state(void) @@ -240,6 +247,7 @@ static void reset_launcher_state(void) s_crash_count = 0; s_gave_up = false; s_init_pending = false; + s_escaped = false; } static void kill_launcher(pid_t pid, int sig) From af81c62b62af2065bbe463e061a053545d984545 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 18:14:12 +0200 Subject: [PATCH 21/24] feat(zaparoo): right-side Display Centering page with H/V offset Adds a sibling page to the trimmed System Settings menu (reachable via right-arrow) hosting: - H Offset (-8..+7 pixels) - +/- to adjust - V Offset (-8..+7 lines) - +/- to adjust - CRT mode toggle (relocated from System Settings) - Exit Offsets persist via FileSaveConfig in zaparoo_video_offsets.bin (mirror of the existing zaparoo_launcher_crt.bin pattern). Loaded and pushed to the FPGA via user_io_status_set on menu init, so they apply on boot. The 4-bit two's-complement bit pattern matches Menu_MiSTer's signed status[13:10]/status[17:14] inputs which feed h_offset/v_offset on native_video_timing.sv. System Settings page now renders OSD_ARROW_LEFT|OSD_ARROW_RIGHT to indicate the new sibling, and the CRT row + its dispatcher entry have been removed (they live in display_menu now). --- menu.cpp | 55 ++++++++++++++++++++++ support/zaparoo/alt_launcher.cpp | 57 ++++++++++++++++++++++- support/zaparoo/alt_launcher.h | 8 ++++ support/zaparoo/alt_launcher_menu.cpp | 26 +++++------ support/zaparoo/display_menu.cpp | 66 +++++++++++++++++++++++++++ support/zaparoo/display_menu.h | 20 ++++++++ 6 files changed, 216 insertions(+), 16 deletions(-) create mode 100644 support/zaparoo/display_menu.cpp create mode 100644 support/zaparoo/display_menu.h diff --git a/menu.cpp b/menu.cpp index 8cb232112..ee45e43e6 100644 --- a/menu.cpp +++ b/menu.cpp @@ -51,6 +51,7 @@ along with this program. If not, see . #include "menu.h" #include "support/zaparoo/alt_launcher.h" #include "support/zaparoo/alt_launcher_menu.h" +#include "support/zaparoo/display_menu.h" #include "support/zaparoo/menu_rbf.h" #include "user_io.h" #include "debug.h" @@ -85,6 +86,11 @@ enum MENU MENU_MISC1, MENU_MISC2, + // Right-side companion to System Settings on the alt-launcher menu core. + // Hosts H/V offset adjustment and the CRT mode toggle. + MENU_ZAPAROO_DISPLAY1, + MENU_ZAPAROO_DISPLAY2, + MENU_SELECT_INI1, MENU_SELECT_INI2, @@ -6888,10 +6894,59 @@ void HandleUI(void) { menustate = MENU_MISC1; } + else if (right && alt_launcher_configured()) + { + menustate = MENU_ZAPAROO_DISPLAY1; + menusub = 0; + } if (!hold_cnt && reboot_req) fpga_load_rbf(menu_rbf_name()); break; + /******************************************************************/ + /* zaparoo display centering page (right-side sibling of System) */ + /******************************************************************/ + case MENU_ZAPAROO_DISPLAY1: + if (!alt_launcher_configured()) + { + menustate = MENU_NONE1; + break; + } + helptext_idx = 0; + parentstate = menustate; + display_menu_render(menusub, &menumask); + menustate = MENU_ZAPAROO_DISPLAY2; + break; + + case MENU_ZAPAROO_DISPLAY2: + if (menu) + { + menustate = MENU_NONE1; + break; + } + if (left) + { + menustate = MENU_SYSTEM1; + menusub = 0; + break; + } + if (plus || minus) + { + display_menu_adjust(menusub, plus ? +1 : -1); + menustate = MENU_ZAPAROO_DISPLAY1; + break; + } + if (select) + { + if (!display_menu_handle_select(menusub)) + { + menustate = MENU_NONE1; + break; + } + menustate = MENU_ZAPAROO_DISPLAY1; + } + break; + case MENU_JOYSYSMAP: strcpy(joy_bnames[SYS_BTN_A - DPAD_NAMES], "A"); strcpy(joy_bnames[SYS_BTN_B - DPAD_NAMES], "B"); diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index 4d0f61b86..d61e09944 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -74,6 +74,17 @@ static const char s_tty[] = "tty2"; static const char s_tty_path[] = "/dev/tty2"; static const char s_fb_mode_path[] = "/sys/module/MiSTer_fb/parameters/mode"; static const char s_crt_state_file[] = "zaparoo_launcher_crt.bin"; +static const char s_offsets_file[] = "zaparoo_video_offsets.bin"; + +static int8_t s_h_offset = 0; +static int8_t s_v_offset = 0; + +static int8_t clamp_offset(int8_t v) +{ + if (v < -8) return -8; + if (v > 7) return 7; + return v; +} static bool load_persisted_native_crt(void) { @@ -88,6 +99,20 @@ static void save_persisted_native_crt(bool crt) FileSaveConfig(s_crt_state_file, &v, sizeof(v)); } +static void load_persisted_offsets(void) +{ + int8_t buf[2] = { 0, 0 }; + FileLoadConfig(s_offsets_file, buf, sizeof(buf)); + s_h_offset = clamp_offset(buf[0]); + s_v_offset = clamp_offset(buf[1]); +} + +static void save_persisted_offsets(void) +{ + int8_t buf[2] = { s_h_offset, s_v_offset }; + FileSaveConfig(s_offsets_file, buf, sizeof(buf)); +} + static void set_launcher_fb_mode(int fmt, int rb, int width, int height, int stride, bool log = true) { FILE *fp = fopen(s_fb_mode_path, "wt"); @@ -336,6 +361,31 @@ bool alt_launcher_native_crt(void) return s_native_crt && s_pid != 0; } +int8_t alt_launcher_h_offset(void) +{ + return s_h_offset; +} + +int8_t alt_launcher_v_offset(void) +{ + return s_v_offset; +} + +void alt_launcher_set_h_offset(int8_t v) +{ + s_h_offset = clamp_offset(v); + save_persisted_offsets(); + // 4-bit two's-complement bit pattern; FPGA reinterprets as signed -8..+7. + user_io_status_set("[13:10]", (uint32_t)((uint8_t)s_h_offset & 0xF)); +} + +void alt_launcher_set_v_offset(int8_t v) +{ + s_v_offset = clamp_offset(v); + save_persisted_offsets(); + user_io_status_set("[17:14]", (uint32_t)((uint8_t)s_v_offset & 0xF)); +} + void alt_launcher_toggle_crt(void) { bool current_crt = alt_launcher_native_crt(); @@ -497,6 +547,11 @@ void zaparoo_alt_launcher_init_for_core(void) void zaparoo_alt_launcher_init_for_menu(void) { bool crt = load_persisted_native_crt(); - printf("alt_launcher: initializing menu launcher (persisted crt=%d)\n", crt); + load_persisted_offsets(); + printf("alt_launcher: initializing menu launcher (persisted crt=%d, h=%d, v=%d)\n", + crt, s_h_offset, s_v_offset); + // Push the persisted offsets to the FPGA now that the menu RBF is loaded. + user_io_status_set("[13:10]", (uint32_t)((uint8_t)s_h_offset & 0xF)); + user_io_status_set("[17:14]", (uint32_t)((uint8_t)s_v_offset & 0xF)); alt_launcher_init(crt); } diff --git a/support/zaparoo/alt_launcher.h b/support/zaparoo/alt_launcher.h index 038501382..0861fb281 100644 --- a/support/zaparoo/alt_launcher.h +++ b/support/zaparoo/alt_launcher.h @@ -12,6 +12,14 @@ bool alt_launcher_native_crt(void); bool alt_launcher_active(void); bool alt_launcher_configured(void); +// Display centering: signed offsets clamped to -8..+7. Setters update the +// in-memory cache, persist to the config dir, and push to the FPGA via +// user_io_status_set so the change takes effect immediately. +int8_t alt_launcher_h_offset(void); +int8_t alt_launcher_v_offset(void); +void alt_launcher_set_h_offset(int8_t v); +void alt_launcher_set_v_offset(int8_t v); + void alt_launcher_cfg_apply(void); uint16_t alt_launcher_fb_terminal_key(uint32_t mask, bool osd_button); diff --git a/support/zaparoo/alt_launcher_menu.cpp b/support/zaparoo/alt_launcher_menu.cpp index 4334c0b40..9590a7a2b 100644 --- a/support/zaparoo/alt_launcher_menu.cpp +++ b/support/zaparoo/alt_launcher_menu.cpp @@ -23,8 +23,10 @@ int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, char s[256]; int m = 0; - OsdSetTitle("System Settings", OSD_ARROW_LEFT); - *menumask = 0x1F; + // Right arrow indicates a sibling page (Display Centering) accessible + // via the right-arrow key — see MENU_ZAPAROO_DISPLAY1 in menu.cpp. + OsdSetTitle("System Settings", OSD_ARROW_LEFT | OSD_ARROW_RIGHT); + *menumask = 0xF; OsdWrite(m++); sprintf(s, " MiSTer v%s", version + 5); @@ -60,17 +62,14 @@ int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, OsdWrite(m++, " Remap keyboard \x16", menusub == 0); OsdWrite(m++, " Define joystick buttons \x16", menusub == 1); - sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); - OsdWrite(m++, s, menusub == 2); - OsdWrite(m++, ""); int cr = m; - OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 3); + OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 2); *sysinfo_timer = 0; *reboot_req = 0; while (m < OsdGetSize() - 1) OsdWrite(m++, ""); - OsdWrite(15, ALT_STD_EXIT, menusub == 4); + OsdWrite(15, ALT_STD_EXIT, menusub == 3); return cr; } @@ -79,18 +78,15 @@ int alt_launcher_translate_system_select(int menusub) { if (!alt_launcher_configured()) return menusub; - if (menusub == 2) - { - alt_launcher_toggle_crt(); - return -1; - } - - static const int map[] = { 1, 2, -1, 5, 6 }; + // Maps trimmed-menu menusub to upstream MENU_SYSTEM2 dispatch index: + // 0 Remap -> 1, 1 Define joy -> 2, 2 Reboot -> 5, 3 Exit -> 6. + // CRT mode lives on the Display Centering page now, not here. + static const int map[] = { 1, 2, 5, 6 }; if (menusub < 0 || menusub >= (int)(sizeof(map) / sizeof(map[0]))) return -1; return map[menusub]; } bool alt_launcher_system_holding_reboot(int menusub) { - return alt_launcher_configured() && menusub == 3; + return alt_launcher_configured() && menusub == 2; } diff --git a/support/zaparoo/display_menu.cpp b/support/zaparoo/display_menu.cpp new file mode 100644 index 000000000..3b2a5cf72 --- /dev/null +++ b/support/zaparoo/display_menu.cpp @@ -0,0 +1,66 @@ +#include "display_menu.h" +#include "alt_launcher.h" +#include "osd.h" + +#include + +#define DISPLAY_STD_EXIT " exit" + +void display_menu_render(int menusub, uint64_t *menumask) +{ + OsdSetSize(16); + OsdSetTitle("Display Centering", OSD_ARROW_LEFT); + *menumask = 0xF; // 4 entries: H, V, CRT, Exit + + char s[64]; + int m = 0; + + OsdWrite(m++); + OsdWrite(m++, ""); + OsdWrite(m++, ""); + OsdWrite(m++, ""); + + sprintf(s, " H Offset: %+3d (-/+)", alt_launcher_h_offset()); + OsdWrite(m++, s, menusub == 0); + + sprintf(s, " V Offset: %+3d (-/+)", alt_launcher_v_offset()); + OsdWrite(m++, s, menusub == 1); + + OsdWrite(m++, ""); + sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); + OsdWrite(m++, s, menusub == 2); + + while (m < OsdGetSize() - 1) OsdWrite(m++, ""); + OsdWrite(15, DISPLAY_STD_EXIT, menusub == 3); +} + +bool display_menu_handle_select(int menusub) +{ + switch (menusub) + { + case 2: + alt_launcher_toggle_crt(); + return true; + case 3: + return false; + default: + return true; + } +} + +void display_menu_adjust(int menusub, int dir) +{ + if (dir == 0) return; + int8_t step = (int8_t)(dir > 0 ? 1 : -1); + switch (menusub) + { + case 0: + alt_launcher_set_h_offset((int8_t)(alt_launcher_h_offset() + step)); + break; + case 1: + alt_launcher_set_v_offset((int8_t)(alt_launcher_v_offset() + step)); + break; + default: + break; + } +} diff --git a/support/zaparoo/display_menu.h b/support/zaparoo/display_menu.h new file mode 100644 index 000000000..295d2eb78 --- /dev/null +++ b/support/zaparoo/display_menu.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +// Right-side companion to the trimmed System Settings menu. Hosts the +// display centering controls (H/V offset) and the CRT mode toggle that +// used to live next to Reboot in alt_launcher_render_system_menu. +// +// menusub layout: 0 = H offset, 1 = V offset, 2 = CRT mode, 3 = Exit. + +void display_menu_render(int menusub, uint64_t *menumask); + +// Returns true if the press was consumed (re-render required without +// dispatching to MENU_NONE1). Caller checks this before exiting. +bool display_menu_handle_select(int menusub); + +// Adjust the highlighted offset row by `dir` (-1 / +1). No-op when the +// current row is not an offset row. +void display_menu_adjust(int menusub, int dir); From 02552bc746cfba031fc3ba3548539124f62ae813 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 20:41:30 +0200 Subject: [PATCH 22/24] docs(zaparoo): add ZAPAROO_FORK.md change map and cleanup backlog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Living document mapping the Zaparoo-specific changes in this fork (commits by wizzomafizzo + asturur from a2eb35e to HEAD), plus a prioritized list of inconsistencies worth cleaning up — namespace drift, overlapping gating predicates, scattered persistence files, implicit cross-repo status-bit contract, etc. Intended to evolve as the fork iterates so future contributors don't have to re-derive the architecture from git log. --- ZAPAROO_FORK.md | 179 ++++++++++++++++++ .../{display_menu.cpp => launcher_pages.cpp} | 0 .../{display_menu.h => launcher_pages.h} | 0 3 files changed, 179 insertions(+) create mode 100644 ZAPAROO_FORK.md rename support/zaparoo/{display_menu.cpp => launcher_pages.cpp} (100%) rename support/zaparoo/{display_menu.h => launcher_pages.h} (100%) diff --git a/ZAPAROO_FORK.md b/ZAPAROO_FORK.md new file mode 100644 index 000000000..3a2ae6c59 --- /dev/null +++ b/ZAPAROO_FORK.md @@ -0,0 +1,179 @@ +# Zaparoo Fork — Change Map and Cleanup Backlog + +This document maps the Zaparoo-specific changes layered on top of MiSTer-devel +`Main_MiSTer`. It is meant to evolve as the fork iterates, so future +contributors don't have to re-derive the architecture from `git log`. + +**Scope:** commits authored by `wizzomafizzo` (Callan Barrett) and `asturur` +(Andrea Bogazzi) between commit `a2eb35e` and the tip of +`feat/zaparoo-fb-toggle`. Upstream merges, upstream-author changes, and +fully-reverted experiments (F2 toggle, picker/notice commands, perf tweak, +non-blocking spawn) are intentionally omitted. + +> **Living doc:** when you add a Zaparoo-specific behavior, append a row to +> the table below or revise the inconsistencies section. Stale entries are +> worse than no entries — please prune as you cleanup. + +--- + +## 1. Change map + +| # | Cluster | Purpose | Where it lives | +|---|---------|---------|----------------| +| 1 | **External launcher process management** | Spawn `zaparoo/launcher` via `agetty` on tty2; SIGTERM/SIGKILL on shutdown; bounded `waitpid`; respawn timer; 3-strike crash give-up | `support/zaparoo/alt_launcher.cpp` (`spawn`, `kill_launcher`, `alt_launcher_poll`, `return_to_normal_mode`) | +| 2 | **Process discovery & gating** | `alt_launcher_configured()` = file exists at `zaparoo/launcher` (cached, with sticky escape bit); `alt_launcher_active()` = process running | `support/zaparoo/alt_launcher.cpp:34-43,329-332` | +| 3 | **Custom menu RBF discovery** | `menu_rbf_name()` / `is_menu_rbf()` so a Zaparoo build can ship its own renamed menu RBF and the file_io / fpga_io / user_io paths still recognize it | `support/zaparoo/menu_rbf.cpp/.h`; consumers in `file_io.cpp`, `fpga_io.cpp`, `user_io.cpp` | +| 4 | **Forced cfg overrides** | `alt_launcher_cfg_apply()` forces `cfg.fb_terminal = 1; cfg.recents = 1` after INI parse. Original `ALT_LAUNCHER` / `MENU_RBF` INI knobs were dropped in favor of file-existence detection | `cfg.cpp:614`, `support/zaparoo/alt_launcher.cpp:24-30` | +| 5 | **Polling integration** | `alt_launcher_poll()` driven by main scheduler tick | `scheduler.cpp:36`, `support/zaparoo/alt_launcher.cpp:365` | +| 6 | **TTY / framebuffer hygiene** | Clear/reset tty2 around launcher lifecycle; toggle `video_fb_enable` and `video_chvt` only on respawn paths; don't touch them on plain shutdown | `support/zaparoo/alt_launcher.cpp` (`clear_launcher_tty`, `reset_launcher_tty`) | +| 7 | **Joypad routing into launcher** | `alt_launcher_fb_terminal_key()` translates `JOY_L2/R2/OSD` to `KEY_F1/BACKSPACE/MENU`; `joy_digital()` short-circuits to `uinp_send_key` when launcher active | `input.cpp:2475-2484`, `support/zaparoo/alt_launcher.cpp:45-62` | +| 8 | **Native CRT rendering path** | Launcher running in CRT mode: kernel framebuffer at 320×240 RGBA8888, FPGA scans separate region at `0x3A000000`, `status[9]=1` gates it; pre-spawn blank wipes the prior frame | `support/zaparoo/alt_launcher.cpp` (`enable_native_crt_path`, `disable_native_crt_path`, `blank_native_crt_fb`); paired with `Menu_MiSTer/rtl/native_video_*.sv` | +| 9 | **CRT mode persistence** | 1-byte `zaparoo_launcher_crt.bin` via `FileSaveConfig` / `FileLoadConfig`; loaded at menu init, applied on spawn | `support/zaparoo/alt_launcher.cpp:76-89,344,499` | +| 10 | **Native-core auto-init** | `zaparoo_is_native_core()` matches core name `"Zaparoo Launcher"`; `zaparoo_alt_launcher_init_for_core()` auto-spawns when the FPGA loads that core | `support/zaparoo/alt_launcher.cpp:480-495`, `user_io.cpp:1543` | +| 11 | **In-core "Launcher" OSD entry** | Adds row 31 (`ALT_LAUNCHER_MENUSUB`) to MENU_COMMON1 marked with `reboot_req` when activated | `menu.cpp:2831,2845-2849,3088-3091` | +| 12 | **OSD/F12 overlay over running launcher** | F12 / `KEY_MENU` reaches the OSD even with launcher running; on menu core opens System Settings directly (skip file picker); F1/F9 disabled when launcher active; `vga_nag` suppressed; auto-open suppressed in CRT mode | `menu.cpp:843-852,1289,1304-1311,1334,1583,1604-1611,6727,6739,6816,6901`, `user_io.cpp:4162-4171` | +| 13 | **Trimmed System Settings render** | `alt_launcher_render_system_menu()` overrides MENU_SYSTEM1 body for the alt-launcher path; `alt_launcher_translate_system_select()` maps trimmed menusub indices to upstream dispatch slots | `support/zaparoo/alt_launcher_menu.cpp`, `menu.cpp:6739-6745,6816-6821` | +| 14 | **Right-side Display Centering page** | New menu state hosting H/V offset adjustment + relocated CRT toggle; persisted via 2-byte `zaparoo_video_offsets.bin`; pushed via `user_io_status_set("[13:10]" / "[17:14]")` | `support/zaparoo/display_menu.cpp/.h` *(local rename in progress: `launcher_pages.cpp/.h`)*, `support/zaparoo/alt_launcher.cpp` (offset state + setters), `menu.cpp` `MENU_ZAPAROO_DISPLAY*` cases | +| 15 | **Escape-to-stock semantics** | Sticky `s_escaped` flag makes `alt_launcher_configured()` return `false` after a clean exit, so the rest of the session reverts to stock OSD; reboot resets it | `support/zaparoo/alt_launcher.cpp:32,38-43,229-241` | +| 16 | **CI / build infrastructure** | Docker container build; binary named `MiSTer_Zaparoo`; "Z"-suffixed version; release / unstable CI; sync-upstream workflow; deploy script | `docker-build.sh`, `stable-build.sh`, `unstable-build.sh`, `deploy-zaparoo.sh`, `.github/build_*.sh`, `.github/workflows/*.yml` | +| 17 | **Build-time defaults flipped** | `cfg.recents` and `LOG_FILE_ENTRY` default to enabled in Zaparoo builds | `cfg.cpp` (defaults) | + +--- + +## 2. Inconsistencies and cleanup backlog + +These are intentional starting points for follow-up work, ordered roughly from +"30-minute cleanup" to "needs a design pass." + +### 2.1 Mixed namespace prefix in one module +`support/zaparoo/alt_launcher.h` uses two prefixes for the same conceptual thing: + +```c +alt_launcher_init / _shutdown / _toggle_crt / _native_crt / _active / _configured ... +zaparoo_is_native_core +zaparoo_alt_launcher_init_for_core / _for_menu +``` + +The `zaparoo_*` wrappers are the only ones called from `user_io.cpp`. Pick one +prefix (`zap_` is shortest) or split into two headers along that boundary. + +### 2.2 Three overlapping predicates +Gating across the codebase uses `_configured()` / `_active()` / `_native_crt()` +interchangeably without a documented rule. Current de-facto convention: + +| Predicate | Meaning | Used to gate | +|-----------|---------|--------------| +| `_configured` | binary file exists, sticky off after escape | **render paths** (System Settings body, MENU_SYSTEM1 entry, vga_nag, file-picker entry, "Launcher" row visibility, right-arrow gate) | +| `_active` | PID alive | **input handling** (F1/F9 disable, joypad-to-launcher routing, OSD overlay, menu auto-open suppression) | +| `_native_crt` | PID alive AND CRT mode on | **internal video state machine** (`disable_native_crt_path`, status timer) | + +The split is mostly principled but leaks at `MENU_SYSTEM1`, which uses +`_configured` for both the gate AND the body delegation while `MENU_NONE2` +auto-open uses `_active`. A user with the launcher binary present but not yet +running sees different OSD behavior than a user without the binary at all — +worth either a comment or a unified helper. + +### 2.3 Two persistence files, no shared format +Current state: + +``` +zaparoo_launcher_crt.bin 1 byte (CRT mode flag) +zaparoo_video_offsets.bin 2 bytes (h_offset, v_offset) +``` + +Same dir, same `FileSaveConfig` API, but no unified struct. If a third setting +arrives this becomes a per-feature file pattern. A single `zaparoo_state.bin` +with a versioned struct would scale better: + +```c +struct zaparoo_state_v1 { + uint8_t magic; // 'Z' + uint8_t version; // 1 + uint8_t crt; // 0 / 1 + int8_t h_offset; // -8..+7 + int8_t v_offset; // -8..+7 + uint8_t reserved[3]; +}; +``` + +Cost: a one-shot migration on existing installs (read legacy `crt.bin` if +new file is missing; never write the legacy file again). + +### 2.4 Hardcoded paths scattered across modules +- Launcher path: `zaparoo/launcher` in `alt_launcher.cpp:22` +- Menu RBF name(s): hardcoded in `support/zaparoo/menu_rbf.cpp` +- Persistence files: hardcoded in `alt_launcher.cpp` + +INI knobs were intentionally dropped (commit `72037bc`) in favor of +file-existence detection, but the resulting literals are now in three places. +A small `support/zaparoo/paths.h` (or a `paths.cpp` that resolves them at +startup) would centralize them without bringing INI knobs back. + +### 2.5 Status-bit map exists only in code +`status[9]` (CRT gate), `status[13:10]` (h_offset), `status[17:14]` (v_offset) +are agreed upon between this fork and `Menu_MiSTer/feat/dual-mode-native-fb`, +but the agreement is enforced only by lining up `user_io_status_set("[13:10]", …)` +against the SystemVerilog `status[13:10]`. Neither side has a comment +referencing the other. + +A short `STATUS.md` (or a header in `support/zaparoo/`) documenting the shared +register layout would prevent accidental conflicts when a future feature +allocates new bits. + +### 2.6 F-key handling comment is archaeology +F2 toggle was added (`0cea191`), moved to `user_io_kbd` (`6d2690b`), and both +were reverted (`390c141`, `4220a82`). What remains is a multi-line comment +block in `user_io.cpp:4162-4171` that reads like commit-history narration. + +It can shrink to one line: + +```c +// F12/KEY_MENU bypasses alt_launcher_active() so the user can open +// the OSD on top of a running launcher. +``` + +### 2.7 Trimmed-menu dispatcher has a dead branch +`alt_launcher_translate_system_select()` returns `-1` to signal "consumed +inline." That existed for the CRT row, which has now moved to the right page. + +The `if (dispatch < 0) { menustate = MENU_SYSTEM1; break; }` branch in +`MENU_SYSTEM2`'s switch is currently unreachable. Either drop it or note that +it's reserved for future inline-handled rows. + +### 2.8 `alt_launcher.cpp` is doing too many jobs +~600 lines covering: process lifecycle + video state machine + tty handling ++ status-bit pushers + offset persistence + cfg overrides. Splitting into +`alt_launcher_proc.cpp`, `alt_launcher_video.cpp`, `alt_launcher_state.cpp` +would make each concern testable and easier to audit. Not urgent — the file +is still readable — but the next feature will tip it over. + +### 2.9 Hard-override of user INI config is silent +`alt_launcher_cfg_apply()` quietly forces `fb_terminal=1` and `recents=1` +after `cfg_parse`. A user who set `fb_terminal=0` in `MiSTer.ini` gets no +warning that we're overriding them. + +At minimum, log it once at startup: + +```c +printf("alt_launcher: forcing fb_terminal=1, recents=1 (Zaparoo build)\n"); +``` + +### 2.10 Naming drift in the new menu page +The right-side page was committed as `MENU_ZAPAROO_DISPLAY1/2` with files +`display_menu.{cpp,h}`. Local in-progress refactor renames the menu states +to `MENU_ZAPAROO_VIDEO*` / `MENU_ZAPAROO_LAUNCHER*` and the file to +`launcher_pages.{cpp,h}`. After the rename settles, double-check that the +file name and the symbols inside agree on what the page is called. + +--- + +## 3. Boundary commit + +The "fork divergence" reference point used for this analysis is: + +``` +a2eb35eacdd7789abe3411e4d03381e7bf55309f +``` + +Use that as the base in `git log a2eb35e..HEAD` if you want to refresh this +document programmatically. diff --git a/support/zaparoo/display_menu.cpp b/support/zaparoo/launcher_pages.cpp similarity index 100% rename from support/zaparoo/display_menu.cpp rename to support/zaparoo/launcher_pages.cpp diff --git a/support/zaparoo/display_menu.h b/support/zaparoo/launcher_pages.h similarity index 100% rename from support/zaparoo/display_menu.h rename to support/zaparoo/launcher_pages.h From 7d6b40a78c712ab814535e29daadbd135ac92cf2 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 20:56:49 +0200 Subject: [PATCH 23/24] good --- .DS_Store | Bin 0 -> 8196 bytes menu.cpp | 75 ++++++++++++++++++++------ support/.DS_Store | Bin 0 -> 6148 bytes support/zaparoo/alt_launcher.cpp | 18 +++++++ support/zaparoo/alt_launcher_menu.cpp | 20 +++---- support/zaparoo/alt_launcher_menu.h | 8 +-- support/zaparoo/launcher_pages.cpp | 65 ++++++++++++++++------ support/zaparoo/launcher_pages.h | 42 +++++++++++---- 8 files changed, 174 insertions(+), 54 deletions(-) create mode 100644 .DS_Store create mode 100644 support/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..38fff9e3195afafb8fa7caa3eed31dabc9cdc46f GIT binary patch literal 8196 zcmeHMy>HV%6o1#GIH5vR0;Diu2?ivpl2)y%0IEy~%mt%X;;Xfj&{#OWD0Ui&C{-qq z;17U*p<)3h1|(o&Vx(dK7FLE%3{1THNOO++Ar^$-uDbVg?!D*t^DmB1&jkQdY*nTJ zasZIQ$#8rO%?^Y4*-VTPxpD%LU_L+@CzKc#bL2lGqc-Q}LXldmu8E z$QFZ$bo84n9MO{46DZPwh;$&bGLan$;ngwEkW~Z+Sog~PD>@%r!Gci9{k)mv-t7-#r-lWznRgfsf_ZBSQ`1S;v0uZ zWt*yfW^A{8Dz_Jtr@G-M&Q0+TnC#?N>!$86u)0RSF4Uj}u383QmsewnOR9M*hur6eg zd38FVlJv$XELwO{tmh+zxD@B!JRf+}dhcF7>)#?WPpy~q#_G+#W%V-9#M{)z=|G4! zRIfB`jDFuKM&2NnRT+-(AN~-Z zHM<%3G+0F*gqUb?=>1>lpsiM5SOK;T;K;H5|MKqd|9Ox$S^=%Vzo`I8m+VpzudToL z4__whwN0EWIN4xvJ%Kz04R6O0c{`4{{SQMtHZhdtSQ2{zaRrBd5x`~8Ml0|~75D}6 C`Zt0A literal 0 HcmV?d00001 diff --git a/menu.cpp b/menu.cpp index ee45e43e6..6ce4952ce 100644 --- a/menu.cpp +++ b/menu.cpp @@ -51,7 +51,7 @@ along with this program. If not, see . #include "menu.h" #include "support/zaparoo/alt_launcher.h" #include "support/zaparoo/alt_launcher_menu.h" -#include "support/zaparoo/display_menu.h" +#include "support/zaparoo/launcher_pages.h" #include "support/zaparoo/menu_rbf.h" #include "user_io.h" #include "debug.h" @@ -87,9 +87,13 @@ enum MENU MENU_MISC2, // Right-side companion to System Settings on the alt-launcher menu core. - // Hosts H/V offset adjustment and the CRT mode toggle. - MENU_ZAPAROO_DISPLAY1, - MENU_ZAPAROO_DISPLAY2, + // Top "Zaparoo Launcher" page lists sub-pages (Video) and an exit row; + // the Video sub-page hosts CRT mode + H/V centering offsets and binds + // left/right arrows to value adjustment. + MENU_ZAPAROO_LAUNCHER1, + MENU_ZAPAROO_LAUNCHER2, + MENU_ZAPAROO_VIDEO1, + MENU_ZAPAROO_VIDEO2, MENU_SELECT_INI1, MENU_SELECT_INI2, @@ -6896,7 +6900,7 @@ void HandleUI(void) } else if (right && alt_launcher_configured()) { - menustate = MENU_ZAPAROO_DISPLAY1; + menustate = MENU_ZAPAROO_LAUNCHER1; menusub = 0; } @@ -6904,9 +6908,9 @@ void HandleUI(void) break; /******************************************************************/ - /* zaparoo display centering page (right-side sibling of System) */ + /* zaparoo launcher pages (right-side sibling of System) */ /******************************************************************/ - case MENU_ZAPAROO_DISPLAY1: + case MENU_ZAPAROO_LAUNCHER1: if (!alt_launcher_configured()) { menustate = MENU_NONE1; @@ -6914,11 +6918,11 @@ void HandleUI(void) } helptext_idx = 0; parentstate = menustate; - display_menu_render(menusub, &menumask); - menustate = MENU_ZAPAROO_DISPLAY2; + launcher_page_render(menusub, &menumask); + menustate = MENU_ZAPAROO_LAUNCHER2; break; - case MENU_ZAPAROO_DISPLAY2: + case MENU_ZAPAROO_LAUNCHER2: if (menu) { menustate = MENU_NONE1; @@ -6930,20 +6934,61 @@ void HandleUI(void) menusub = 0; break; } - if (plus || minus) + if (right && menusub == 0) { - display_menu_adjust(menusub, plus ? +1 : -1); - menustate = MENU_ZAPAROO_DISPLAY1; + menustate = MENU_ZAPAROO_VIDEO1; + menusub = 0; break; } if (select) { - if (!display_menu_handle_select(menusub)) + int act = launcher_page_handle_select(menusub); + if (act == 1) + { + menustate = MENU_ZAPAROO_VIDEO1; + menusub = 0; + } + else if (act == 0) { menustate = MENU_NONE1; + } + } + break; + + case MENU_ZAPAROO_VIDEO1: + if (!alt_launcher_configured()) + { + menustate = MENU_NONE1; + break; + } + helptext_idx = 0; + parentstate = menustate; + video_page_render(menusub, &menumask); + menustate = MENU_ZAPAROO_VIDEO2; + break; + + case MENU_ZAPAROO_VIDEO2: + if (menu) + { + menustate = MENU_ZAPAROO_LAUNCHER1; + menusub = 0; + break; + } + if (left || right || plus || minus) + { + video_page_adjust(menusub, (right || plus) ? +1 : -1); + menustate = MENU_ZAPAROO_VIDEO1; + break; + } + if (select) + { + if (!video_page_handle_select(menusub)) + { + menustate = MENU_ZAPAROO_LAUNCHER1; + menusub = 0; break; } - menustate = MENU_ZAPAROO_DISPLAY1; + menustate = MENU_ZAPAROO_VIDEO1; } break; diff --git a/support/.DS_Store b/support/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3866aebc5df32793a6b0ed929414c7972754897a GIT binary patch literal 6148 zcmeHKK~4iP478z$mALfCF<->wNg27%B3&i1N?$7aN;eDV^?D7 z9*`;_RM}E8j$=F7kv55mi08ZYjA%+k1)3m>G9qFgow_jRD!DOkwpK| zBzwQ67kZ!$?c4s_PPcnM;?c&cS~YP6k7Bw1eCtoA00{@BlR z-EW(?-CzbRyEp^RfHU9>I0Gj#V7Ezeb7CG3cLtn+^J75Hhkzzn8YabjbfC*60B{0x z7U)t-NK7y+4U-~fAgrN44P`4aSi@lt=2sdfMGYsm;)8AFL-E3Sb>t7(ow!u=-WhNP zh74Tla4Prz0>8{?kv|Oaku%^7oEZZ=sp@KukFvY<==0>R4QNX=5%Ei+K%fsE0T{?R fa+@c0K8Oy#(l9AX7P04Wpg#mMA>KIyf55;OZP7OR literal 0 HcmV?d00001 diff --git a/support/zaparoo/alt_launcher.cpp b/support/zaparoo/alt_launcher.cpp index d61e09944..e356dc1ae 100644 --- a/support/zaparoo/alt_launcher.cpp +++ b/support/zaparoo/alt_launcher.cpp @@ -15,6 +15,7 @@ #include "file_io.h" #include "hardware.h" #include "input.h" +#include "menu.h" #include "shmem.h" #include "user_io.h" #include "video.h" @@ -349,6 +350,11 @@ static void spawn(void) input_switch(0); user_io_status_set("[9]", 1); } + + // The launcher grabs input as soon as it starts. If the OSD is still + // up (e.g. user toggled CRT mode or hit Reboot from System Settings), + // it would trap input with no way to dismiss it — drop it now. + if (menu_present()) MenuHide(); } bool alt_launcher_active(void) @@ -439,6 +445,18 @@ void alt_launcher_poll(void) int sig = WIFSIGNALED(status) ? WTERMSIG(status) : 0; bool escaped = (exited && exit_status == 0) || sig == SIGTERM || sig == SIGINT; bool crashed = !escaped && (sig != 0 || (exited && exit_status != 0)); + // Any exit while in CRT mode drops back to HDMI / no launcher + // for the rest of this session — respawning into CRT after the + // user already left it is a UX trap. The persisted CRT + // preference is intentionally untouched (return_to_normal_mode + // only clears the in-memory s_native_crt), so the next reboot + // honors whatever the user last set in System Settings. + if (s_native_crt) + { + printf("alt_launcher: exited while in CRT mode, dropping to HDMI normal mode\n"); + return_to_normal_mode(); + return; + } if (escaped) { printf("alt_launcher: exited, returning to normal mode until restart\n"); diff --git a/support/zaparoo/alt_launcher_menu.cpp b/support/zaparoo/alt_launcher_menu.cpp index 9590a7a2b..e0bb50dc2 100644 --- a/support/zaparoo/alt_launcher_menu.cpp +++ b/support/zaparoo/alt_launcher_menu.cpp @@ -23,10 +23,10 @@ int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, char s[256]; int m = 0; - // Right arrow indicates a sibling page (Display Centering) accessible - // via the right-arrow key — see MENU_ZAPAROO_DISPLAY1 in menu.cpp. + // Right arrow indicates a sibling page (Zaparoo Launcher) accessible + // via the right-arrow key — see MENU_ZAPAROO_LAUNCHER1 in menu.cpp. OsdSetTitle("System Settings", OSD_ARROW_LEFT | OSD_ARROW_RIGHT); - *menumask = 0xF; + *menumask = 0x1F; OsdWrite(m++); sprintf(s, " MiSTer v%s", version + 5); @@ -61,15 +61,16 @@ int alt_launcher_render_system_menu(int menusub, uint64_t *menumask, OsdWrite(m++, " Remap keyboard \x16", menusub == 0); OsdWrite(m++, " Define joystick buttons \x16", menusub == 1); + OsdWrite(m++, " Scripts \x16", menusub == 2); OsdWrite(m++, ""); int cr = m; - OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 2); + OsdWrite(m++, " Reboot (hold \x16 cold reboot)", menusub == 3); *sysinfo_timer = 0; *reboot_req = 0; while (m < OsdGetSize() - 1) OsdWrite(m++, ""); - OsdWrite(15, ALT_STD_EXIT, menusub == 3); + OsdWrite(15, ALT_STD_EXIT, menusub == 4); return cr; } @@ -79,14 +80,15 @@ int alt_launcher_translate_system_select(int menusub) if (!alt_launcher_configured()) return menusub; // Maps trimmed-menu menusub to upstream MENU_SYSTEM2 dispatch index: - // 0 Remap -> 1, 1 Define joy -> 2, 2 Reboot -> 5, 3 Exit -> 6. - // CRT mode lives on the Display Centering page now, not here. - static const int map[] = { 1, 2, 5, 6 }; + // 0 Remap -> 1, 1 Define joy -> 2, 2 Scripts -> 3, 3 Reboot -> 5, + // 4 Exit -> 6. CRT mode lives on the Zaparoo Launcher's Video + // sub-page now, not here. + static const int map[] = { 1, 2, 3, 5, 6 }; if (menusub < 0 || menusub >= (int)(sizeof(map) / sizeof(map[0]))) return -1; return map[menusub]; } bool alt_launcher_system_holding_reboot(int menusub) { - return alt_launcher_configured() && menusub == 2; + return alt_launcher_configured() && menusub == 3; } diff --git a/support/zaparoo/alt_launcher_menu.h b/support/zaparoo/alt_launcher_menu.h index 98cd6f8c7..797a9e194 100644 --- a/support/zaparoo/alt_launcher_menu.h +++ b/support/zaparoo/alt_launcher_menu.h @@ -4,10 +4,10 @@ #include // Trimmed System Settings menu for alt-launcher mode. The launcher is -// the only "core" running on top of menu.rbf, so storage toggle, -// scripts and the bundled help PDF are irrelevant — this layout -// hides them and exposes only Remap(0), Define joy(1), CRT mode(2), -// Reboot(3), Exit(4). +// the only "core" running on top of menu.rbf, so storage toggle and +// the bundled help PDF are irrelevant — this layout hides them and +// exposes Remap(0), Define joy(1), Scripts(2), Reboot(3), Exit(4). +// CRT mode lives on the Zaparoo Launcher's Video sub-page. // // All three helpers are no-ops / return safe defaults when // alt_launcher_configured() is false, so menu.cpp's hook sites can diff --git a/support/zaparoo/launcher_pages.cpp b/support/zaparoo/launcher_pages.cpp index 3b2a5cf72..9bf2a31e5 100644 --- a/support/zaparoo/launcher_pages.cpp +++ b/support/zaparoo/launcher_pages.cpp @@ -1,16 +1,49 @@ -#include "display_menu.h" +#include "launcher_pages.h" #include "alt_launcher.h" #include "osd.h" #include -#define DISPLAY_STD_EXIT " exit" +// Mirrors menu.cpp's STD_EXIT (a local #define there, kept in sync +// here rather than re-exporting it via a header touch). +#define LAUNCHER_STD_EXIT " exit" -void display_menu_render(int menusub, uint64_t *menumask) +void launcher_page_render(int menusub, uint64_t *menumask) { OsdSetSize(16); - OsdSetTitle("Display Centering", OSD_ARROW_LEFT); - *menumask = 0xF; // 4 entries: H, V, CRT, Exit + OsdSetTitle("Zaparoo Launcher", OSD_ARROW_LEFT); + *menumask = 0x3; // Video, Exit + + int m = 0; + OsdWrite(m++); + OsdWrite(m++, ""); + OsdWrite(m++, ""); + OsdWrite(m++, ""); + OsdWrite(m++, ""); + + OsdWrite(m++, " Video \x16", menusub == 0); + + while (m < OsdGetSize() - 1) OsdWrite(m++, ""); + OsdWrite(15, LAUNCHER_STD_EXIT, menusub == 1); +} + +int launcher_page_handle_select(int menusub) +{ + switch (menusub) + { + case 0: return 1; + case 1: return 0; + default: return -1; + } +} + +void video_page_render(int menusub, uint64_t *menumask) +{ + OsdSetSize(16); + // No arrow flags: left/right are bound to value adjustment on this + // page, not sibling navigation. + OsdSetTitle("Video", 0); + *menumask = 0xF; // CRT, H Offset, V Offset, Exit char s[64]; int m = 0; @@ -18,27 +51,26 @@ void display_menu_render(int menusub, uint64_t *menumask) OsdWrite(m++); OsdWrite(m++, ""); OsdWrite(m++, ""); - OsdWrite(m++, ""); - sprintf(s, " H Offset: %+3d (-/+)", alt_launcher_h_offset()); + sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); OsdWrite(m++, s, menusub == 0); - sprintf(s, " V Offset: %+3d (-/+)", alt_launcher_v_offset()); + OsdWrite(m++, ""); + sprintf(s, " H Offset: %+3d", alt_launcher_h_offset()); OsdWrite(m++, s, menusub == 1); - OsdWrite(m++, ""); - sprintf(s, " CRT mode: %-15s", alt_launcher_native_crt() ? "On" : "Off"); + sprintf(s, " V Offset: %+3d", alt_launcher_v_offset()); OsdWrite(m++, s, menusub == 2); while (m < OsdGetSize() - 1) OsdWrite(m++, ""); - OsdWrite(15, DISPLAY_STD_EXIT, menusub == 3); + OsdWrite(15, LAUNCHER_STD_EXIT, menusub == 3); } -bool display_menu_handle_select(int menusub) +bool video_page_handle_select(int menusub) { switch (menusub) { - case 2: + case 0: alt_launcher_toggle_crt(); return true; case 3: @@ -48,16 +80,19 @@ bool display_menu_handle_select(int menusub) } } -void display_menu_adjust(int menusub, int dir) +void video_page_adjust(int menusub, int dir) { if (dir == 0) return; int8_t step = (int8_t)(dir > 0 ? 1 : -1); switch (menusub) { case 0: - alt_launcher_set_h_offset((int8_t)(alt_launcher_h_offset() + step)); + alt_launcher_toggle_crt(); break; case 1: + alt_launcher_set_h_offset((int8_t)(alt_launcher_h_offset() + step)); + break; + case 2: alt_launcher_set_v_offset((int8_t)(alt_launcher_v_offset() + step)); break; default: diff --git a/support/zaparoo/launcher_pages.h b/support/zaparoo/launcher_pages.h index 295d2eb78..0f7b1afdd 100644 --- a/support/zaparoo/launcher_pages.h +++ b/support/zaparoo/launcher_pages.h @@ -3,18 +3,38 @@ #include #include -// Right-side companion to the trimmed System Settings menu. Hosts the -// display centering controls (H/V offset) and the CRT mode toggle that -// used to live next to Reboot in alt_launcher_render_system_menu. +// Right-side companion to the trimmed System Settings menu, reachable +// via the right arrow when alt_launcher_configured() is true. This file +// hosts both pages of that companion: the top-level "Zaparoo Launcher" +// page and the nested "Video" sub-page that owns the CRT mode toggle +// plus the H/V centering offsets. // -// menusub layout: 0 = H offset, 1 = V offset, 2 = CRT mode, 3 = Exit. +// The Video page binds left/right arrows to value adjustment instead of +// sibling navigation, which is why it lives behind a sub-page rather +// than directly under System Settings. -void display_menu_render(int menusub, uint64_t *menumask); +// Top "Zaparoo Launcher" page. menusub layout: 0 = Video, 1 = Exit. +void launcher_page_render(int menusub, uint64_t *menumask); -// Returns true if the press was consumed (re-render required without -// dispatching to MENU_NONE1). Caller checks this before exiting. -bool display_menu_handle_select(int menusub); +// Translates a select press on the Launcher page. +// 1 -> entered Video sub-page +// 0 -> Exit pressed (close OSD) +// -1 -> no-op +int launcher_page_handle_select(int menusub); -// Adjust the highlighted offset row by `dir` (-1 / +1). No-op when the -// current row is not an offset row. -void display_menu_adjust(int menusub, int dir); +// Video sub-page. menusub layout: 0 = CRT mode, 1 = H Offset, +// 2 = V Offset, 3 = Exit. +// +// The OSD is closed automatically by the launcher spawn path (see +// MenuHide() in spawn() in alt_launcher.cpp) when CRT toggling +// triggers a respawn — these helpers don't need to signal that. +void video_page_render(int menusub, uint64_t *menumask); + +// Returns true if the press was consumed (re-render only); false when +// Exit was selected (caller pops back to the Launcher page). +bool video_page_handle_select(int menusub); + +// Adjust the highlighted row by `dir` (-1 / +1). Toggles CRT mode on +// the CRT row regardless of sign; ±1 on the H/V offset rows; no-op +// elsewhere. +void video_page_adjust(int menusub, int dir); From 3eeb116f4a6521a88e1f4e87d0de2bf6b7f2a730 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 10 May 2026 20:57:16 +0200 Subject: [PATCH 24/24] removed dsstore --- .DS_Store | Bin 8196 -> 0 bytes support/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 support/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 38fff9e3195afafb8fa7caa3eed31dabc9cdc46f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMy>HV%6o1#GIH5vR0;Diu2?ivpl2)y%0IEy~%mt%X;;Xfj&{#OWD0Ui&C{-qq z;17U*p<)3h1|(o&Vx(dK7FLE%3{1THNOO++Ar^$-uDbVg?!D*t^DmB1&jkQdY*nTJ zasZIQ$#8rO%?^Y4*-VTPxpD%LU_L+@CzKc#bL2lGqc-Q}LXldmu8E z$QFZ$bo84n9MO{46DZPwh;$&bGLan$;ngwEkW~Z+Sog~PD>@%r!Gci9{k)mv-t7-#r-lWznRgfsf_ZBSQ`1S;v0uZ zWt*yfW^A{8Dz_Jtr@G-M&Q0+TnC#?N>!$86u)0RSF4Uj}u383QmsewnOR9M*hur6eg zd38FVlJv$XELwO{tmh+zxD@B!JRf+}dhcF7>)#?WPpy~q#_G+#W%V-9#M{)z=|G4! zRIfB`jDFuKM&2NnRT+-(AN~-Z zHM<%3G+0F*gqUb?=>1>lpsiM5SOK;T;K;H5|MKqd|9Ox$S^=%Vzo`I8m+VpzudToL z4__whwN0EWIN4xvJ%Kz04R6O0c{`4{{SQMtHZhdtSQ2{zaRrBd5x`~8Ml0|~75D}6 C`Zt0A diff --git a/support/.DS_Store b/support/.DS_Store deleted file mode 100644 index 3866aebc5df32793a6b0ed929414c7972754897a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKK~4iP478z$mALfCF<->wNg27%B3&i1N?$7aN;eDV^?D7 z9*`;_RM}E8j$=F7kv55mi08ZYjA%+k1)3m>G9qFgow_jRD!DOkwpK| zBzwQ67kZ!$?c4s_PPcnM;?c&cS~YP6k7Bw1eCtoA00{@BlR z-EW(?-CzbRyEp^RfHU9>I0Gj#V7Ezeb7CG3cLtn+^J75Hhkzzn8YabjbfC*60B{0x z7U)t-NK7y+4U-~fAgrN44P`4aSi@lt=2sdfMGYsm;)8AFL-E3Sb>t7(ow!u=-WhNP zh74Tla4Prz0>8{?kv|Oaku%^7oEZZ=sp@KukFvY<==0>R4QNX=5%Ei+K%fsE0T{?R fa+@c0K8Oy#(l9AX7P04Wpg#mMA>KIyf55;OZP7OR