Skip to content

Refactor/back stack lifecycle - #3

Merged
DefKorns merged 5 commits into
masterfrom
refactor/back-stack-lifecycle
Oct 20, 2026
Merged

DefKorns merged 5 commits into
masterfrom
refactor/back-stack-lifecycle

Conversation

@DefKorns

@DefKorns DefKorns commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Moves the back-stack protocol out of main.cpp, replaces the global ExitManager with an explicit exit decision, and makes a killed options hand the screen back to the home menu.

Changes

  • back_stack.{h,cpp}: pure functions for OM_BACK_STACK (MakeEntry, PopIfLast, Push, BackCommand). Output is byte-identical to the old inline code. The format is unchanged: entries separated by ;, fields by , (commandPath,scriptPath,titleKey[,marker]).
  • ApplicationLifecycle replaces ExitManager. Each exit point now calls Decide(Resume | Leave). ResumeUI.sh still runs from a static destructor, after main()'s locals (SDL) are released, and at most once.
  • SIGTERM / SIGHUP handler: a killed options (killall, S8103OptionsMenu stop) now resumes the UI and clears /tmp/options.flag. The handler only uses async-signal-safe calls (vfork + execve, then _exit).
  • launch_save_manager.sh: on 4-field entries, title_key used to swallow ,marker. The marker is now passed on as --selectedMarker.

Exit decisions

Exit point Decision
Startup exit(1) (missing or empty commands folder) Resume
SDL_QUIT, reset button Resume
A on an external command RESTART_UI decides (default: Leave)
B with a valid parent entry Leave (parent menu relaunched)
B at root, or malformed parent entry Resume
Delete (hold B + confirm) Leave (DELETE_STR relaunches)
SIGTERM / SIGHUP Resume, unless a Leave was already decided

RESTART_UI keeps its old meaning. Decide runs before the system() it guards, so a signal during that call does not resume over a screen another process owns.

Testing

  • Host (local harness, not part of this PR): the real options binary built natively in Docker, with an LD_PRELOAD shim that records system() calls and injects keys. It pins the exact OM_BACK_STACK and backCommand strings, the early-exit ResumeUI, the external/back/delete paths, the SIGTERM/SIGHUP exit code with a single resume, command-file parsing (CRLF, comments, lines without =), and the launchers run with stubs. All pass.
  • Console (SNES Classic, plain build):
    • Startup exits, B at root, B in a submenu, external command, delete and the reset button all behave as in the table.
    • With the menu idle: SIGTERM and SIGHUP resume ReedPlayer (T → running) and remove the flag.
    • With a confirm dialog open: SIGTERM does the same. Before this change it did nothing, because only the main loop reads SDL events.
    • launch_save_manager.sh runs under BusyBox ash with 3- and 4-field entries.
  • Baseline check: before this change, SDL's own handler already turned SIGTERM into SDL_QUIT, but only in the main loop. SIGHUP was not handled at all.

Not covered

  • SIGKILL and crashes. optiond ignores the exit status, so it cannot recover either.
  • Add-on binaries (theme_manager, the gamepad tools) do not get the handler. Their vendored OptionsMenu picks up back_stack only when they bump the submodule.
  • The same marker fix for launch_favorites_manager.sh lives in the om-favorites repo and needs its own PR.

@DefKorns DefKorns self-assigned this Oct 20, 2026
@DefKorns
DefKorns merged commit 3ee5439 into master Oct 20, 2026
4 checks passed
@DefKorns
DefKorns deleted the refactor/back-stack-lifecycle branch October 20, 2026 23:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant