feat(zaparoo): OSD menu entry to toggle CRT/HDMI launcher mode#2
Conversation
…modes
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.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds configured menu-RBF helpers and cfg.menu_rbf, persistent alt-launcher native-CRT state and toggle, routes menu entry into System Settings when the alt launcher is configured, updates RBF load/scanning to use the configured menu RBF, and adjusts input/OSD handling so Menu/F12 reach the OSD while other menu actions and auto-reopen are suppressed when the alt launcher owns the framebuffer. ChangesCRT menu integration and toggle
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
This reverts commit 6d2690b.
…and CRT modes" This reverts commit 0cea191.
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.
…SYSTEM1)
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.
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.
…loses it
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.
… over launcher
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.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
menu.cpp (1)
6729-6729: ⚡ Quick winReplace hardcoded System-menu index
7withALT_LAUNCHER_CRT_MENUSUB.
MENU_COMMONuses the symbolic constant, butMENU_SYSTEMstill hardcodes7. This is brittle if indices shift.♻️ Proposed fix
- menumask = 0x7F; - if (alt_launcher_configured()) menumask |= (1ULL << 7); + menumask = 0x7F; + if (alt_launcher_configured()) menumask |= (1ULL << ALT_LAUNCHER_CRT_MENUSUB); ... - OsdWrite(m++, s, menusub == 7); + OsdWrite(m++, s, menusub == ALT_LAUNCHER_CRT_MENUSUB); ... - case 7: + case ALT_LAUNCHER_CRT_MENUSUB: if (alt_launcher_configured()) { alt_launcher_toggle_crt(); menustate = MENU_SYSTEM1; } break;Also applies to: 6782-6786, 6880-6886
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@menu.cpp` at line 6729, Replace the hardcoded System-menu bit shift (1ULL << 7) with the symbolic constant ALT_LAUNCHER_CRT_MENUSUB wherever the System menu mask is built (e.g., in the block that checks alt_launcher_configured() and sets menumask for MENU_SYSTEM and the other occurrences at the noted offsets); update the expressions using (1ULL << 7) to instead compute the mask using (1ULL << ALT_LAUNCHER_CRT_MENUSUB) or an equivalent macro-based mask so the code consistently uses ALT_LAUNCHER_CRT_MENUSUB with menumask and alt_launcher_configured().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@menu.cpp`:
- Line 6729: Replace the hardcoded System-menu bit shift (1ULL << 7) with the
symbolic constant ALT_LAUNCHER_CRT_MENUSUB wherever the System menu mask is
built (e.g., in the block that checks alt_launcher_configured() and sets
menumask for MENU_SYSTEM and the other occurrences at the noted offsets); update
the expressions using (1ULL << 7) to instead compute the mask using (1ULL <<
ALT_LAUNCHER_CRT_MENUSUB) or an equivalent macro-based mask so the code
consistently uses ALT_LAUNCHER_CRT_MENUSUB with menumask and
alt_launcher_configured().
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8afda085-06fe-4447-8cf8-7f9605fbee62
📒 Files selected for processing (4)
menu.cppsupport/zaparoo/alt_launcher.cppsupport/zaparoo/alt_launcher.huser_io.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
- support/zaparoo/alt_launcher.cpp
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.
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.
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.
…-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.
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.
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.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fpga_io.cpp`:
- Around line 444-446: The write into the fixed char path[1024] in fpga_load_rbf
uses sprintf and can overflow; replace both sprintf/sprintf-like usage with
snprintf(path, sizeof(path), ...) and check the return value for truncation (ret
< 0 or ret >= sizeof(path)) and treat that as an error path (reject the name and
return/fail), and for the absolute case (name[0]=='/') similarly use snprintf
and check truncation; reference is_menu_rbf, getStorageDir, getRootDir and the
local buffer path when implementing the bounded write and rejection on
truncation.
In `@support/zaparoo/alt_launcher.cpp`:
- Around line 300-305: The shutdown path calls alt_launcher_shutdown()
synchronously and its bounded polling loops can block the cooperative scheduler;
modify alt_launcher_shutdown() to insert scheduler_yield() inside any
bounded/wait loops (e.g., the polling loops that wait for FB/HPS release or
status[9] drop) or convert the CRT toggle to an asynchronous workflow so the
coroutine can relinquish control; ensure scheduler_yield() is called on each
loop iteration or on long waits and keep alt_launcher_init(target_crt)
invocation unchanged so the caller remains cooperative.
- Around line 293-295: The toggle logic uses alt_launcher_native_crt() which
returns false when s_pid==0, causing target_crt to always be true for
pending/stopped windows; instead read the configured/current CRT state without
PID-gating. Replace the use of alt_launcher_native_crt() for determining
current_crt with a PID-agnostic accessor (e.g., a new
alt_launcher_configured_crt() or existing stored flag) that returns the real
enabled/disabled CRT setting, then compute target_crt = !current_crt; do not
change s_pid-checks in the accessor so the toggle flips the actual saved state
rather than being forced by s_pid==0.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c4152ef8-7a6c-41e4-a183-131ec857f8e8
📒 Files selected for processing (11)
cfg.cppcfg.hfile_io.cppfpga_io.cppinput.cppmenu.cppsupport/zaparoo/alt_launcher.cppsupport/zaparoo/alt_launcher.hsupport/zaparoo/menu_rbf.cppsupport/zaparoo/menu_rbf.huser_io.cpp
| 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); | ||
|
|
There was a problem hiding this comment.
Bound path writes in fpga_load_rbf.
Line 445 writes into a fixed 1024-byte buffer with sprintf; a long name can overflow path and corrupt stack state. Please switch to bounded writes and reject truncation.
💡 Suggested fix
- if(name[0] == '/') strcpy(path, name);
- else sprintf(path, "%s/%s", is_menu_rbf(name) ? getStorageDir(0) : getRootDir(), name);
+ if (name[0] == '/')
+ {
+ if (snprintf(path, sizeof(path), "%s", name) >= (int)sizeof(path)) return -1;
+ }
+ else
+ {
+ if (snprintf(path, sizeof(path), "%s/%s",
+ is_menu_rbf(name) ? getStorageDir(0) : getRootDir(), name) >= (int)sizeof(path)) return -1;
+ }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fpga_io.cpp` around lines 444 - 446, The write into the fixed char path[1024]
in fpga_load_rbf uses sprintf and can overflow; replace both
sprintf/sprintf-like usage with snprintf(path, sizeof(path), ...) and check the
return value for truncation (ret < 0 or ret >= sizeof(path)) and treat that as
an error path (reject the name and return/fail), and for the absolute case
(name[0]=='/') similarly use snprintf and check truncation; reference
is_menu_rbf, getStorageDir, getRootDir and the local buffer path when
implementing the bounded write and rejection on truncation.
| // 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); | ||
| } |
There was a problem hiding this comment.
Avoid blocking cooperative scheduling during CRT toggle.
This path synchronously calls alt_launcher_shutdown(), which can wait in bounded polling loops. Add scheduler_yield() in those wait loops (or make toggle async) so UI/poll coroutines stay responsive.
As per coding guidelines, "Long-running support code in cooperative scheduler context must call scheduler_yield() to stay cooperative and allow the coroutine to switch between poll and ui threads".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@support/zaparoo/alt_launcher.cpp` around lines 300 - 305, The shutdown path
calls alt_launcher_shutdown() synchronously and its bounded polling loops can
block the cooperative scheduler; modify alt_launcher_shutdown() to insert
scheduler_yield() inside any bounded/wait loops (e.g., the polling loops that
wait for FB/HPS release or status[9] drop) or convert the CRT toggle to an
asynchronous workflow so the coroutine can relinquish control; ensure
scheduler_yield() is called on each loop iteration or on long waits and keep
alt_launcher_init(target_crt) invocation unchanged so the caller remains
cooperative.
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.
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.
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.
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.
|
you can remove alt_launcher from mister.ini now you must copy the menu fork to zaparoo/menu_zaparoo.rbf |
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.
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).
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.
Reflects 7d6b40a: - right-side surface is now two pages (Launcher top + Video sub-page), files renamed to launcher_pages.{cpp,h}, symbols split into launcher_page_* / video_page_* - Scripts row back in trimmed System Settings - OSD auto-dismiss on launcher spawn (MenuHide in spawn()) - CRT-mode-on-exit drops to HDMI for the rest of the session Cleanup backlog: closes #2.10 (naming drift resolved), adds #2.11 (two OSD-dismiss paths) and #2.12 (CRT-on-exit policy).
Summary
Adds a "CRT mode: On/Off" entry to the System OSD menu (the one shown via F12 / OSD button) that toggles the Zaparoo launcher between HDMI mode (default) and native CRT mode at runtime. Activating the entry kills the running launcher and re-spawns it with the opposite mode flag — when toggling on, the bash wrapper sets
ALT_LAUNCHER_CRT=1and the launcher restarts with--crtso it adapts to 320×240 native resolution and starts the DDR3 writer. Toggle off restarts without the flag and returns to the HPS-framebuffer HDMI path.This is the userspace counterpart to Menu_MiSTer#3, which adds a
status[9]gate on the FPGA side selecting between the original cosine pattern (default) and the native DDR reader.Behavior
--crt, setstatus[9]=1,input_switch(0)--crt, setstatus[9]=1status[9], restores HPS FB mode), respawn without--crtThe entry is shown only when
alt_launcher_configured()is true — same gate as the existing "Launcher" item it sits beside. Label updates to reflect current mode after activation.Implementation
alt_launcher_toggle_crt()reuses the existing lifecycle:alt_launcher_shutdown()already handles SIGTERM/SIGKILL, callsdisable_native_crt_path()if the launcher was in CRT mode (dropsstatus[9], restores HPS fb mode 960×720), and resets state viareset_launcher_state().alt_launcher_init(target_crt)then schedules a respawn picked up by the nextalt_launcher_poll()tick — same path the auto-init for the "Zaparoo Launcher" core uses on core load. The bash wrapper at/tmp/alt_launcheralready keys off$ALT_LAUNCHER_CRTand adds--crtto the launcher command line.A new
alt_launcher_native_crt()getter exposes the current state so the menu label can show "On" or "Off".Test plan
alt_launcherconfigured, activating "CRT mode: Off" starts the launcher in CRT mode (status[9]=1, FPGA reads DDR)Out of scope
--crt)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
Fixes