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") _STEAM_MARKERS = ("SteamGamepadUI", "SteamDeck", "SteamGameId", "GAMESCOPE_WAYLAND_DISPLAY")
# Seconds the first screen waits for a first key before it closes, set by a # Seconds the interface waits for a first key, no run going, before it
# launcher whose mapper may never open the pad: the screen would otherwise # closes, set by a launcher whose mapper may never open the pad: the screen
# hold a handheld that has no other way out. # would otherwise hold a handheld that has no other way out.
TUI_IDLE_ENV = "RETROBIOS_IDLE_EXIT" TUI_IDLE_ENV = "RETROBIOS_IDLE_EXIT"
TUI_IDLE_WORDS = "No button pressed, closing." TUI_IDLE_WORDS = "No button pressed, closing."
@@ -12895,7 +12895,10 @@ def run_tui(args: argparse.Namespace) -> int:
if number is not None: if number is not None:
handlers[number] = signal.signal(number, handler) handlers[number] = signal.signal(number, handler)
idle = tui_idle_exit() 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 sys.stdout = sys.stderr = buffer
try: try:
_prune_work_folders(work.parent, time.time()) _prune_work_folders(work.parent, time.time())
@@ -12931,9 +12934,10 @@ def run_tui(args: argparse.Namespace) -> int:
perform(tui_update(state, key)) perform(tui_update(state, key))
if state.exit_code is not None: if state.exit_code is not None:
break break
if (idle is not None and not pressed and state.exit_code is None if state.running:
and state.screen == first_screen quiet_since = time.monotonic()
and time.monotonic() - opened >= idle): 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 state.idle_closed, state.exit_code = True, 0
if flags["interrupt"]: if flags["interrupt"]:
flags["interrupt"] = False flags["interrupt"] = False
+12
View File
@@ -3176,6 +3176,18 @@ class EndToEnd(unittest.TestCase):
term.send("q") term.send("q")
self.assertEqual(term.close(), 130) 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): def test_a_desktop_names_its_keys_and_a_pad_its_buttons(self):
self.repo() self.repo()
for env, bar in (({"DISPLAY": ":0"}, "Enter Continue Esc Quit ? Help"), 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. moves with the D-pad.
Each launcher also sets `RETROBIOS_IDLE_EXIT` to 300: with no button pressed 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 system has no mapping for sends nothing, and would otherwise leave the
console stuck on the interface with no way out. 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 with no mapper at all (a keyboard) leaves it unset.
A launcher can also set `RETROBIOS_IDLE_EXIT` to a number of seconds: when 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 no button has reached the interface since it opened, and nothing has run for
interface closes with `No button pressed, closing.` and exit status 0. A that long, it closes with `No button pressed, closing.` and exit status 0.
mapper that never opened the pad would otherwise hold the device on that 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, screen. On a Miyoo, B,
X, Y and Select are Left Ctrl, Shift, Alt and Right Ctrl: pressed alone, a 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 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 | | `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_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_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 | | `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 ## When something goes wrong