fix: close an idle interface past its first screen

RETROBIOS_IDLE_EXIT only counted while the first screen was up. Given
--platform, the check runs and the plan follows without a key, so the
close never came. It now counts from the end of the last run, as long as
no key has been pressed.
This commit is contained in:
Abdessamad Derraz committed 2026-10-23 22:07:31 +02:00
1 parent 89cfaeef5e
commit b26ce7cbdc
3 files changed
+31 -12

No files matched your search

+11 -7
View File
@@ -10118,9 +10118,9 @@ TUI_PAD_ROUTES = ("gptokeyb", "gptokeyb_muxterm", "muxterm", "evmapy", "miyoo")
_STEAM_MARKERS = ("SteamGamepadUI", "SteamDeck", "SteamGameId", "GAMESCOPE_WAYLAND_DISPLAY")
# Seconds the first screen waits for a first key before it closes, set by a
# launcher whose mapper may never open the pad: the screen would otherwise
# hold a handheld that has no other way out.
# Seconds the interface waits for a first key, no run going, before it
# closes, set by a launcher whose mapper may never open the pad: the screen
# would otherwise hold a handheld that has no other way out.
TUI_IDLE_ENV = "RETROBIOS_IDLE_EXIT"
TUI_IDLE_WORDS = "No button pressed, closing."
@@ -12895,7 +12895,10 @@ def run_tui(args: argparse.Namespace) -> int:
if number is not None:
handlers[number] = signal.signal(number, handler)
idle = tui_idle_exit()
first_screen, opened, pressed = state.screen, time.monotonic(), False
# Counted from the moment the screen last waited for a key with no
# run going: given --platform, the first screen moves on by itself
# to the plan once the check is read, and no key comes either.
quiet_since, pressed = time.monotonic(), False
sys.stdout = sys.stderr = buffer
try:
_prune_work_folders(work.parent, time.time())
@@ -12931,9 +12934,10 @@ def run_tui(args: argparse.Namespace) -> int:
perform(tui_update(state, key))
if state.exit_code is not None:
break
if (idle is not None and not pressed and state.exit_code is None
and state.screen == first_screen
and time.monotonic() - opened >= idle):
if state.running:
quiet_since = time.monotonic()
elif (idle is not None and not pressed and state.exit_code is None
and time.monotonic() - quiet_since >= idle):
state.idle_closed, state.exit_code = True, 0
if flags["interrupt"]:
flags["interrupt"] = False
+12
View File
@@ -3176,6 +3176,18 @@ class EndToEnd(unittest.TestCase):
term.send("q")
self.assertEqual(term.close(), 130)
def test_no_key_on_a_screen_reached_by_itself_closes_it(self):
"""Given --platform, as the offline launcher route is, the check
runs at once and the plan follows without a key: the close counted
only on the first screen, and never came."""
repo = self.repo()
self.env[install.TUI_IDLE_ENV] = "1"
term = self.start("--platform", "retroarch", "--dest", str(repo.dest))
term.wait("> Install")
self.assertEqual(term.close(), 0)
self.assertIn("No button pressed, closing.", term.after())
self.assertEqual(repo.installed(), [])
def test_a_desktop_names_its_keys_and_a_pad_its_buttons(self):
self.repo()
for env, bar in (({"DISPLAY": ":0"}, "Enter Continue Esc Quit ? Help"),
+8 -5
View File
@@ -1072,7 +1072,8 @@ page there: muxterm keeps PgUp and PgDn for its own scrollback, so a list
moves with the D-pad.
Each launcher also sets `RETROBIOS_IDLE_EXIT` to 300: with no button pressed
on its first screen for 5 minutes, the interface closes by itself. A pad the
for 5 minutes since it opened, and no check or install running, the interface
closes by itself. A pad the
system has no mapping for sends nothing, and would otherwise leave the
console stuck on the interface with no way out.
@@ -1089,9 +1090,11 @@ Each launcher tells the interface which buttons reach it, in
A launcher with no mapper at all (a keyboard) leaves it unset.
A launcher can also set `RETROBIOS_IDLE_EXIT` to a number of seconds: when
no button reaches the first screen for that long, before any choice, the
interface closes with `No button pressed, closing.` and exit status 0. A
mapper that never opened the pad would otherwise hold the device on that
no button has reached the interface since it opened, and nothing has run for
that long, it closes with `No button pressed, closing.` and exit status 0.
The time counts from the end of the last check, so a launcher that names the
platform, whose interface moves on to the plan by itself, closes the same way.
A mapper that never opened the pad would otherwise hold the device on that
screen. On a Miyoo, B,
X, Y and Select are Left Ctrl, Shift, Alt and Right Ctrl: pressed alone, a
modifier sends nothing to a terminal, so the interface goes back with R2
@@ -1342,7 +1345,7 @@ RetroArch folder that holds only `scph5501.bin`, in the order written:
| `SSL_CERT_FILE`, `SSL_CERT_DIR` | The trusted certificates to check servers with, for a Python that finds none of its own |
| `RETROBIOS_PLAIN`, `ACCESSIBLE` | Set to anything but `0`: the questions come line by line, as with `--plain`, instead of the full-screen interface |
| `RETROBIOS_PAD` | The buttons a handheld launcher's mapper sends to the full screen (`gptokeyb`, `gptokeyb_muxterm`, `muxterm`, `evmapy`, `miyoo`), so its hints name them. See [On a handheld](#on-a-handheld-the-retrobios-port) |
| `RETROBIOS_IDLE_EXIT` | Seconds the full screen's first screen waits for a first button. With none pressed, it closes with exit status 0 |
| `RETROBIOS_IDLE_EXIT` | Seconds the full screen waits for a first button, counted while nothing runs. With none pressed, it closes with exit status 0 |
| `HTTPS_PROXY`, `NO_PROXY` | Honoured for every download through the standard library's default proxy handling: one names the proxy, the other the hosts to reach directly |
## When something goes wrong