refactor: the menu's dependency rules as tables, shared by the menu and the app

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
theupriserandClaude Sonnet 5.5 committed 2026-10-03 11:51:28 +02:00
1 parent 2a42410cd0
commit 1d23dc02d4
4 files changed
+56 -45

No files matched your search

+1 -1
View File
@@ -47,7 +47,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
idempotent. `<id>_enable` is also used to re-apply. Optional idempotent. `<id>_enable` is also used to re-apply. Optional
`<id>_available` is checked via `component_available` (e.g. `machine` `<id>_available` is checked via `component_available` (e.g. `machine`
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse; only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
`gaming` must stay first. Dependencies live in `toggle_component`. `gaming` must stay first. Dependencies are the `REQUIRES`, `FOLLOWS` and `EXCLUDES` tables in `lib/menu.sh`, used by `toggle_component` (the menu) and `normalize_wanted` (the app).
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`, - **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it: `glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
+1
View File
@@ -8,6 +8,7 @@ one per merged pull request.
## Unreleased ## Unreleased
- **refactor: Valve's package mirror in one module (`lib/valve-mirror.sh`: newest repo, package database fields, checksummed download); the SteamOS extras, CEC driver, BIOS lookup and os-release version used four copies** - **refactor: Valve's package mirror in one module (`lib/valve-mirror.sh`: newest repo, package database fields, checksummed download); the SteamOS extras, CEC driver, BIOS lookup and os-release version used four copies**
- **refactor: the rules between menu items are three tables (`REQUIRES`, `FOLLOWS`, `EXCLUDES` in `lib/menu.sh`) used by the menu's toggles and, as `normalize_wanted`, by the app's selection (it had its own copy of the rules). The app now also ticks the Steamify shortcut for "Add as non-Steam game" and unticks the game entry with it, like the menu**
- **test: the menu rules, the plan and the app's and installer's JSON are checked against a golden file (`tests/menu-test.sh` in steamify-cachyos-dev); `make check`, `.editorconfig`, `.shellcheckrc`** - **test: the menu rules, the plan and the app's and installer's JSON are checked against a golden file (`tests/menu-test.sh` in steamify-cachyos-dev); `make check`, `.editorconfig`, `.shellcheckrc`**
- **docs: README lists the sources and projects Steamify builds on, with licences and thanks** - **docs: README lists the sources and projects Steamify builds on, with licences and thanks**
+1 -18
View File
@@ -146,24 +146,7 @@ backend_apply() {
WANTED[$c]=0 WANTED[$c]=0
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
done done
# The same rules as the menu's toggles. normalize_wanted
# (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.)
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
if component_available gaming; then
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
else
WANTED[boot]=0
fi
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; WANTED[nvsilent]=0; }
[[ "${WANTED[silent]:-0}" == 1 || "${WANTED[glyphs]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[kpin]=0
# Retired: only ever removed. # Retired: only ever removed.
WANTED[hdmi]=0 WANTED[hdmi]=0
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
+53 -26
View File
@@ -11,6 +11,20 @@ COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single la
ACTIONS=(bios) ACTIONS=(bios)
# Sub-options, shown indented under their parent and only while it's ticked. # Sub-options, shown indented under their parent and only while it's ticked.
declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine) declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
# What ticking one item does to another, for the menu's toggles (toggle_component)
# and the app's ticks (normalize_wanted). A sub-option needs its parent: ticking it
# ticks the parent, unticking the parent unticks it (Where to boot is chosen with
# --boot, so the app's ticks never bring the conversion for it; HDMI refresh boost is
# retired and never brings Steam Machine support). Single user mode only makes sense
# on top of the SteamOS conversion (where that is offered: on NVIDIA it logs in by
# itself, see lib/single-user.sh).
declare -A REQUIRES=([single]=gaming)
for _c in "${!PARENT[@]}"; do [[ "$_c" == hdmi ]] || REQUIRES[$_c]=${PARENT[$_c]}; done
unset _c
# Opt-out sub-options are ticked and unticked along with their parent.
declare -A FOLLOWS=([nvidia]=bigpicture [machine]=poweroff [launcher]=steamgame)
# Ticking one unticks the other; in normalize_wanted the first in COMPONENTS wins.
declare -A EXCLUDES=([bigpicture]=nvsilent [nvsilent]=bigpicture)
# Never preselected on a first run: booting into the desktop is a choice, # Never preselected on a first run: booting into the desktop is a choice,
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or # gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
# upset other devices on the TV, even on SteamOS), except on a Steam Machine, # upset other devices on the TV, even on SteamOS), except on a Steam Machine,
@@ -291,35 +305,48 @@ defaults_list() {
printf '[%s]\n' "$items" printf '[%s]\n' "$items"
} }
children_of() {
# children_of <id>: the items that need <id> (REQUIRES), one per line.
local c
for c in "${COMPONENTS[@]}"; do [[ "${REQUIRES[$c]:-}" == "$1" ]] && echo "$c"; done
return 0
}
toggle_component() { toggle_component() {
local c="$1" local c="$1" p x
component_selectable "$c" || return 1 component_selectable "$c" || return 1
WANTED[$c]=$(( 1 - WANTED[$c] )) WANTED[$c]=$(( 1 - WANTED[$c] ))
# Single user mode only makes sense on top of the SteamOS conversion. if [[ "${WANTED[$c]}" == 1 ]]; then
# (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.) p="${REQUIRES[$c]:-}"
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi [[ -n "$p" ]] && component_available "$p" && WANTED[$p]=1
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi x="${EXCLUDES[$c]:-}"
# Where to boot to is part of the conversion, too. [[ -n "$x" ]] && WANTED[$x]=0
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi else
# Big Picture is opt-out: ticked along with "Gaming on NVIDIA". for x in $(children_of "$c"); do WANTED[$x]=0; done
if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi fi
if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[nvsilent]=0; fi x="${FOLLOWS[$c]:-}"
# Silent and Big Picture exclude each other. [[ -n "$x" ]] && component_available "$x" && WANTED[$x]=${WANTED[$c]}
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi }
if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi normalize_wanted() {
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi # The same rules for a whole selection (the app ticks exactly the items it
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi # sends): a ticked sub-option brings its parent, two that exclude each other
# The power-off fix is opt-out: ticked along with Steam Machine support. # keep the first, and an unticked parent takes its sub-options with it
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi # (only where the parent is offered: single user mode stays on NVIDIA PCs).
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi local c p x
if [[ "$c" == machine && "${WANTED[machine]}" == 0 ]]; then WANTED[kpin]=0; WANTED[bios]=0; fi for c in "${COMPONENTS[@]}"; do
if [[ "$c" == kpin && "${WANTED[kpin]}" == 1 ]]; then WANTED[machine]=1; fi p="${REQUIRES[$c]:-}"
if [[ "$c" == bios && "${WANTED[bios]}" == 1 ]]; then WANTED[machine]=1; fi [[ -n "$p" && "$c" != boot && "${WANTED[$c]:-0}" == 1 ]] && component_available "$p" && WANTED[$p]=1
# Steam starts Steamify through the shortcut's start script. done
# Opt-out, like the power-off fix: ticked along with the shortcut. for c in "${COMPONENTS[@]}"; do
if [[ "$c" == launcher ]] && component_available steamgame; then WANTED[steamgame]=${WANTED[launcher]}; fi x="${EXCLUDES[$c]:-}"
if [[ "$c" == steamgame && "${WANTED[steamgame]}" == 1 ]]; then WANTED[launcher]=1; fi [[ -n "$x" && "${WANTED[$c]:-0}" == 1 ]] && WANTED[$x]=0
done
for c in "${COMPONENTS[@]}"; do
p="${REQUIRES[$c]:-}"
[[ -n "$p" && "${WANTED[$p]:-0}" == 0 ]] && component_available "$p" && WANTED[$c]=0
done
return 0
} }
show_menu() { show_menu() {