From 2e51d1d3f370d4bed83317170ed5c4db743d6878 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Thu, 1 Oct 2026 23:04:18 +0200 Subject: [PATCH 01/11] feat: "Start Steam silently" sub-option for the SteamOS conversion (silent) and Gaming on NVIDIA (nvsilent) --- TECHNICAL.md | 9 +++++---- lib/backend.sh | 8 +++++++- lib/menu.sh | 41 +++++++++++++++++++++++++++++++++-------- lib/nvidia.sh | 20 +++++++++++++++++++- lib/steam-desktop.sh | 37 ++++++++++++++++++++++++------------- ui/qml/AppState.qml | 14 ++++++++++---- ui/qml/Texts.qml | 6 ++++++ 7 files changed, 104 insertions(+), 31 deletions(-) diff --git a/TECHNICAL.md b/TECHNICAL.md index aea2016..c468b92 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -108,9 +108,9 @@ tools write to the conf.d fragment into the base config. (never `zz-steamos-autologin.conf`, which CachyOS's tools own), and installs `/usr/local/bin/sync-steamos-session.sh` plus `sync-steamos-session.path`/`.service`; -- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a - `steam-desktop-autostart` systemd user service that starts Steam silently - in Plasma only; +- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent` + ("Start Steam silently", on by default) adds a `steam-desktop-autostart` + systemd user service that starts Steam silently in Plasma only; - the **Return to Gaming Mode** shortcut; on plasma-login-manager with a narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can restart the login manager without a password prompt. @@ -242,7 +242,8 @@ Steam at login): it installs `steam` when missing (recorded in state `nvidia`, r unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets `ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session -(Discord, a browser) aren't restored on top of Big Picture; unticked, Steam starts in its normal window. The PC always boots into the desktop: there is no gamescope session. Takes effect at the next +(Discord, a browser) aren't restored on top of Big Picture; unticked, Steam starts in its normal window. The opt-in sub-option `nvsilent` ("Start Steam silently") rewrites the unit with `-silent` +(tray only); it and `bigpicture` exclude each other. The PC always boots into the desktop: there is no gamescope session. Takes effect at the next login. On a supported card (RTX 20 series or newer: not on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids`, the VRAM booster's diff --git a/lib/backend.sh b/lib/backend.sh index 31afcc6..975f9d7 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -50,6 +50,7 @@ backend_status() { items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")" + items+=",\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)")" items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)" items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)" items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)" @@ -154,7 +155,11 @@ backend_apply() { WANTED[boot]=0 fi [[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1 - [[ "${WANTED[nvidia]:-0}" == 0 ]] && WANTED[bigpicture]=0 + [[ "${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 ]] && component_available gaming && WANTED[gaming]=1 + [[ "${WANTED[gaming]:-0}" == 0 ]] && WANTED[silent]=0 [[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1 [[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0 [[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1 @@ -162,6 +167,7 @@ backend_apply() { # Retired: only ever removed. WANTED[hdmi]=0 case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac + silent_normalize REAPPLY=$reapply plan_changes diff --git a/lib/menu.sh b/lib/menu.sh index 4cb8d4c..abc2039 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -5,19 +5,19 @@ # Menu order. Components are turned on in this order and off in reverse; # gaming must come first (single user builds on it). -COMPONENTS=(gaming boot nvidia bigpicture theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) +COMPONENTS=(gaming boot silent nvidia bigpicture nvsilent theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) # One-off actions rather than on/off components: never preselected, never # re-applied, not listed as on or off. ACTIONS=(bios) # Sub-options, shown indented under their parent and only while it's ticked. -declare -A PARENT=([boot]=gaming [bigpicture]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine) +declare -A PARENT=([boot]=gaming [silent]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine) # 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 # upset other devices on the TV, even on SteamOS), except on a Steam Machine, # which has CEC like on SteamOS. HDMI refresh boost needs someone at the # screen to confirm each step. Extended controller support builds kernel modules for # every installed kernel: opt-in. -NO_PRESELECT=(boot cec kpin hdmi extended_controller_support) +NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support) # Feature versions: the Steamify version in which what a component's enable # sets up last changed; set it to the new VERSION whenever you change one. # Each successful run records it (state "features"); a component that's on @@ -26,7 +26,7 @@ NO_PRESELECT=(boot cec kpin hdmi extended_controller_support) # FEATURE_BASELINE. FEATURE_BASELINE=2.1.0 declare -A FEATURE_VERSION=( - [gaming]=2.9.0 [boot]=2.1.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 + [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.1.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0 [kpin]=2.1.0 [hdmi]=2.1.0 ) @@ -35,6 +35,8 @@ declare -A LABEL=( [gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop" [boot]="Boot into the desktop instead of gaming mode" [nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login" + [silent]="Start Steam silently: in the tray at login on the desktop, no window" + [nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)" [bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)" [theme]="Install SteamOS theme: Vapor look (cachyos-vapor)" [glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode" @@ -57,9 +59,9 @@ component_available() { case "$1" in # gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown # anyway when it's already on, so it can be turned off). - gaming|boot|glyphs) ! nvidia_present || gaming_status ;; + gaming|boot|silent|glyphs) ! nvidia_present || gaming_status ;; nvidia) nvidia_available ;; - bigpicture) bigpicture_available ;; + bigpicture|nvsilent) bigpicture_available ;; machine|poweroff) machine_available ;; vram) vram_available ;; # Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs; @@ -79,10 +81,25 @@ boot_mode() { if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi } +silent_needs_boot() { + # On a Steam Machine, silent start only makes sense when it boots into + # the desktop (gaming mode starts its own Steam): the option is hidden, + # and off, while "Boot into" is gaming mode. + machine_available +} + +silent_normalize() { + silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && WANTED[silent]=0 + return 0 +} + menu_visible() { # Shown in the menu. A sub-option ("Boot into", the kernel pin) only # while its parent is ticked. component_available "$1" || return 1 + # Silent start is hidden while Steam starts in Big Picture. + [[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1 + [[ "$1" == silent ]] && silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && return 1 [[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]] } @@ -203,6 +220,7 @@ detect_components() { done machine_available && WANTED[cec]=1 fi + silent_normalize } defaults_options() { @@ -259,6 +277,7 @@ defaults_options() { WANTED[boot]=1 ;; gamescope) WANTED[boot]=0 ;; esac + silent_normalize return 0 } @@ -282,7 +301,7 @@ defaults_list() { [[ "$c" == cec ]] && machine_available && on=true items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" - items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"on\":$on,\"selectable\":$sel}" + items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}" done printf '[%s]\n' "$items" } @@ -299,7 +318,13 @@ toggle_component() { if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi # Big Picture is opt-out: ticked along with "Gaming on NVIDIA". if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi - if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; fi + if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[nvsilent]=0; fi + # Silent and Big Picture exclude each other. + 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; fi + if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi + silent_normalize # The power-off fix is opt-out: ticked along with Steam Machine support. if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi diff --git a/lib/nvidia.sh b/lib/nvidia.sh index bb8ecc1..7bc10f7 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -57,7 +57,8 @@ nvidia_enable() { state_set nvidia installed_pkgs steam fi # Keeps what the Big Picture option set up; a first run starts Steam normally. - local unit_args=""; bigpicture_status && unit_args=-gamepadui + local unit_args="" + if bigpicture_status; then unit_args=-gamepadui; elif nvsilent_status; then unit_args=-silent; fi nvidia_write_unit "$unit_args" || return 1 user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; } nvidia_kernel_enable || return 1 @@ -96,6 +97,23 @@ bigpicture_disable() { nvidia_write_unit "" && ok "Steam starts in its normal window at your next login." } +# Sub-option: Steam starts silently (tray only, no window). Big Picture and +# a silent start exclude each other (the menus untick one when the other is +# ticked); a first run with both gets Big Picture. +nvsilent_status() { grep -qs -- '-silent' "$(nvidia_unit_file)"; } + +nvsilent_enable() { + [[ -f "$(nvidia_unit_file)" ]] || return 0 + bigpicture_status && return 0 + nvidia_write_unit -silent || return 1 + ok "Steam starts silently at your next login." +} + +nvsilent_disable() { + nvsilent_status || return 0 + nvidia_write_unit "" && ok "Steam starts in its normal window at your next login." +} + # --- Kernel parameters and early modules (a supported card only) nvidia_supported() { diff --git a/lib/steam-desktop.sh b/lib/steam-desktop.sh index 51216fe..641c5ec 100644 --- a/lib/steam-desktop.sh +++ b/lib/steam-desktop.sh @@ -5,35 +5,46 @@ steam_enable() { info "Applying non-optional SteamOS environment & keyboard fixes..." - local steam_env_dir systemd_user_dir + local steam_env_dir steam_env_dir="$HOME/.config/environment.d" mkdir -p "$steam_env_dir" # 2. Prevent KDE Wayland from blocking the virtual keyboard overlay echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf" - # 3. Setup robust background systemd service for Steam autostart on Desktop Mode - systemd_user_dir="$HOME/.config/systemd/user" + ok "Steam UI parameters and keyboard fix deployed successfully." +} + +# Sub-option of the SteamOS conversion: Steam starts silently (in the tray, +# no window) on the Plasma desktop. +silent_status() { + [[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]] +} + +silent_enable() { + local systemd_user_dir="$HOME/.config/systemd/user" mkdir -p "$systemd_user_dir" - service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service" - # Clean out old .desktop shortcut so they don't fight rm -f "$HOME/.config/autostart/steam.desktop" - - # Reload user systemd context and activate the background loop user_systemctl daemon-reload user_systemctl enable --now steam-desktop-autostart.service + ok "Steam starts silently on the desktop." +} - ok "Steam UI parameters and keyboard autostart deployed successfully." +silent_disable() { + user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null + rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" + user_systemctl daemon-reload + ok "Steam no longer starts by itself on the desktop." } steam_disable() { - info "Removing Steam desktop autostart..." - user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null - rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \ - "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf" - user_systemctl daemon-reload + info "Removing Steam desktop settings..." + # The autostart unit is the `silent` option's: removed with it, and here + # too for when the conversion goes off by itself. + silent_status && silent_disable + rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf" ok "Steam desktop settings removed (takes full effect at next login)." } diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index f24bac6..26027d1 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -38,7 +38,9 @@ Item { readonly property var status: backend.status || ({}) readonly property var items: status.items || [] - readonly property var rows: items.filter(function (i) { return !i.parent || want[i.parent]; }) + // Hidden: Big Picture excludes a silent start; on a Steam Machine a silent start needs "Boot into" desktop. + function hidden(i) { return (i.id === "nvsilent" && want.bigpicture) || (i.needs === "boot" && boot !== "desktop"); } + readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); }) readonly property var bios: status.bios || null signal passwordRequested() @@ -76,10 +78,13 @@ Item { w[id] = !w[id]; // The same rules as the terminal menu (toggle_component). var hasGaming = items.some(function (i) { return i.id === "gaming"; }); - if (id === "gaming" && !w.gaming) w.single = false; + if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; } if (id === "single" && w.single && hasGaming) w.gaming = true; if (id === "nvidia") w.bigpicture = w.nvidia; - if (id === "bigpicture" && w.bigpicture) w.nvidia = true; + if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; } + if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; } + if (id === "nvidia" && !w.nvidia) w.nvsilent = false; + if (id === "silent" && w.silent) w.gaming = true; if (id === "machine") w.poweroff = w.machine; if (id === "poweroff" && w.poweroff) w.machine = true; if (id === "machine" && !w.machine) w.kpin = false; @@ -93,6 +98,7 @@ Item { for (var i = 0; i < items.length; i++) { var it = items[i]; if (it.kind !== "toggle") continue; + if (hidden(it)) { if (it.on) p.push({ id: it.id, action: "off" }); continue; } if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; } if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] }); else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" }); @@ -109,7 +115,7 @@ Item { function wantedIds() { var ids = []; for (var i = 0; i < items.length; i++) - if (items[i].kind === "toggle" && want[items[i].id] && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id); + if (items[i].kind === "toggle" && want[items[i].id] && !hidden(items[i]) && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id); return ids; } diff --git a/ui/qml/Texts.qml b/ui/qml/Texts.qml index 65b1403..6ba1504 100644 --- a/ui/qml/Texts.qml +++ b/ui/qml/Texts.qml @@ -10,12 +10,18 @@ QtObject { boot: { label: "Boot into", hint: "Where the PC starts", body: "Where the PC starts after a restart. Switching back and forth works the same either way.", changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] }, + silent: { label: "Start Steam silently", hint: "In the tray at login on the desktop, no window", + body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.", + changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] }, nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login", body: "gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards (an open NVIDIA driver bug), so it isn't offered here. This puts Steam on the Plasma desktop instead and starts it when you log in.", changes: ["Steam is installed when it's missing", "Steam starts at login (a systemd user service)", "Off: the service is removed again; Steam is only removed if Steamify installed it"] }, bigpicture: { label: "Steam starts in Big Picture", hint: "The controller-friendly Steam, or the normal window", body: "Steam opens in Big Picture at login, which works well with a controller on the TV. Untick it for Steam's normal window.", changes: ["Steam is started with -gamepadui", "Plasma starts with an empty session, so old windows don't cover Big Picture", "Off: Steam starts in its normal window"] }, + nvsilent: { label: "Start Steam silently", hint: "In the tray at login, no window", + body: "Steam starts in the tray at login without a window. Not together with Big Picture: ticking one unticks the other.", + changes: ["Steam is started with -silent", "Off: Steam starts in its normal window"] }, theme: { label: "SteamOS theme", hint: "Vapor look for the desktop, Add to Steam", body: "The Vapor look of SteamOS for the desktop, with its panel, launcher icon and wallpaper.", changes: ["cachyos-vapor global theme", "Add to Steam in right-click menus", "Nested Desktop, Steam keyboard window rule"] }, From 613149a80710dc47eebe3987d12ff2085ef2824e Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Thu, 1 Oct 2026 23:04:18 +0200 Subject: [PATCH 02/11] docs: changelog for the silent start option --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1d107b..9f28b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 +- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); on a Steam Machine only when it boots into the desktop** + ## 2.10.0 - 2026-10-01 - `d6db4f6` **feat: "Gaming on NVIDIA" (nvidia) replaces the SteamOS conversion on PCs with an NVIDIA GPU, where gamescope's gaming mode shows a corrupted picture (NVIDIA bug 5240452): Steam is installed when missing and starts at login on the Plasma desktop; the sub-option "Steam starts in Big Picture" (bigpicture) starts it in Big Picture, unticked in its normal window, on an empty Plasma session so windows of the last session don't cover it. On a supported card (RTX 20 series or newer) it also sets the NVIDIA kernel parameters and early modules. The conversion and its options are hidden there unless already on** From 349492423eaa7378f3c663faef4e3392b2173ae4 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 09:10:26 +0200 Subject: [PATCH 03/11] feat: "Start Steam silently in desktop mode" is always shown, also on a Steam Machine --- CHANGELOG.md | 2 +- TECHNICAL.md | 2 +- lib/backend.sh | 3 +-- lib/menu.sh | 20 ++------------------ ui/qml/AppState.qml | 4 ++-- ui/qml/Texts.qml | 2 +- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f28b5e..849beb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 -- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); on a Steam Machine only when it boots into the desktop** +- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine** ## 2.10.0 - 2026-10-01 diff --git a/TECHNICAL.md b/TECHNICAL.md index c468b92..a77c966 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -109,7 +109,7 @@ tools write to the conf.d fragment into the base config. installs `/usr/local/bin/sync-steamos-session.sh` plus `sync-steamos-session.path`/`.service`; - `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent` - ("Start Steam silently", on by default) adds a `steam-desktop-autostart` + ("Start Steam silently in desktop mode", on by default, always shown) adds a `steam-desktop-autostart` systemd user service that starts Steam silently in Plasma only; - the **Return to Gaming Mode** shortcut; on plasma-login-manager with a narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can diff --git a/lib/backend.sh b/lib/backend.sh index 975f9d7..fb97b49 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -50,7 +50,7 @@ backend_status() { items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")" - items+=",\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)")" + items+=",\"needs\":\"\"" items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)" items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)" items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)" @@ -167,7 +167,6 @@ backend_apply() { # Retired: only ever removed. WANTED[hdmi]=0 case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac - silent_normalize REAPPLY=$reapply plan_changes diff --git a/lib/menu.sh b/lib/menu.sh index abc2039..cf09ec5 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -35,7 +35,7 @@ declare -A LABEL=( [gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop" [boot]="Boot into the desktop instead of gaming mode" [nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login" - [silent]="Start Steam silently: in the tray at login on the desktop, no window" + [silent]="Start Steam silently in desktop mode: in the tray at login on the desktop, no window" [nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)" [bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)" [theme]="Install SteamOS theme: Vapor look (cachyos-vapor)" @@ -81,25 +81,12 @@ boot_mode() { if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi } -silent_needs_boot() { - # On a Steam Machine, silent start only makes sense when it boots into - # the desktop (gaming mode starts its own Steam): the option is hidden, - # and off, while "Boot into" is gaming mode. - machine_available -} - -silent_normalize() { - silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && WANTED[silent]=0 - return 0 -} - menu_visible() { # Shown in the menu. A sub-option ("Boot into", the kernel pin) only # while its parent is ticked. component_available "$1" || return 1 # Silent start is hidden while Steam starts in Big Picture. [[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1 - [[ "$1" == silent ]] && silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && return 1 [[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]] } @@ -220,7 +207,6 @@ detect_components() { done machine_available && WANTED[cec]=1 fi - silent_normalize } defaults_options() { @@ -277,7 +263,6 @@ defaults_options() { WANTED[boot]=1 ;; gamescope) WANTED[boot]=0 ;; esac - silent_normalize return 0 } @@ -301,7 +286,7 @@ defaults_list() { [[ "$c" == cec ]] && machine_available && on=true items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" - items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}" + items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":\"\",\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}" done printf '[%s]\n' "$items" } @@ -324,7 +309,6 @@ toggle_component() { if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; fi if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi - silent_normalize # The power-off fix is opt-out: ticked along with Steam Machine support. if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index 26027d1..9a95b00 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -38,8 +38,8 @@ Item { readonly property var status: backend.status || ({}) readonly property var items: status.items || [] - // Hidden: Big Picture excludes a silent start; on a Steam Machine a silent start needs "Boot into" desktop. - function hidden(i) { return (i.id === "nvsilent" && want.bigpicture) || (i.needs === "boot" && boot !== "desktop"); } + // Hidden: Big Picture excludes a silent start. + function hidden(i) { return i.id === "nvsilent" && want.bigpicture; } readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); }) readonly property var bios: status.bios || null diff --git a/ui/qml/Texts.qml b/ui/qml/Texts.qml index 6ba1504..5b6ccf2 100644 --- a/ui/qml/Texts.qml +++ b/ui/qml/Texts.qml @@ -10,7 +10,7 @@ QtObject { boot: { label: "Boot into", hint: "Where the PC starts", body: "Where the PC starts after a restart. Switching back and forth works the same either way.", changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] }, - silent: { label: "Start Steam silently", hint: "In the tray at login on the desktop, no window", + silent: { label: "Start Steam silently in desktop mode", hint: "In the tray at login on the desktop, no window", body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.", changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] }, nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login", From fbdad5a785b8796171dd19f633a9892a485e9fd6 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 09:28:03 +0200 Subject: [PATCH 04/11] feat: the silent option is Steam's own autostart entry (~/.config/autostart/steam.desktop with -silent), so its "Run Steam when my computer starts" follows it; the systemd unit is gone --- CHANGELOG.md | 2 +- TECHNICAL.md | 12 ++++--- lib/steam-desktop.sh | 43 ++++++++++++++++-------- lib/steam-game.sh | 8 ++--- services/README.md | 1 - services/steam-desktop-autostart.service | 15 --------- 6 files changed, 39 insertions(+), 42 deletions(-) delete mode 100644 services/steam-desktop-autostart.service diff --git a/CHANGELOG.md b/CHANGELOG.md index 849beb6..11c165b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 -- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine** +- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** ## 2.10.0 - 2026-10-01 diff --git a/TECHNICAL.md b/TECHNICAL.md index a77c966..dde3e2b 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -109,8 +109,10 @@ tools write to the conf.d fragment into the base config. installs `/usr/local/bin/sync-steamos-session.sh` plus `sync-steamos-session.path`/`.service`; - `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent` - ("Start Steam silently in desktop mode", on by default, always shown) adds a `steam-desktop-autostart` - systemd user service that starts Steam silently in Plasma only; + ("Start Steam silently in desktop mode", on by default, always shown) writes + `~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the + file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older + `steam-desktop-autostart` user unit is removed; - the **Return to Gaming Mode** shortcut; on plasma-login-manager with a narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can restart the login manager without a password prompt. @@ -344,8 +346,7 @@ desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X = Steam's keyboard), in gaming mode as a gamepad. Steam reads the list only at startup and writes it back on exit, so Steam is -closed (`steam -shutdown`) for the edit and started again (through -`steam-desktop-autostart.service` when it's there). That's refused in gaming +closed (`steam -shutdown`) for the edit and started again (`steam -silent`). That's refused in gaming mode and when Steamify itself was started from Steam (`SteamGameId`), since closing Steam would end it. An entry for the start script that's already there (added by hand, or with the path from before 2.5.0) is updated, not @@ -490,7 +491,8 @@ In the home folder, everything is under `steamify`: | `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` | | `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon | | `~/.local/share/applications/steamify-*.desktop` | The launcher entries | -| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` | +| `~/.config/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") | +| `~/.config/systemd/user/` | `steamify-update-check.*` | System-wide: `/usr/local/lib/steamify/` (kernel headers script), `/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old diff --git a/lib/steam-desktop.sh b/lib/steam-desktop.sh index 641c5ec..5026856 100644 --- a/lib/steam-desktop.sh +++ b/lib/steam-desktop.sh @@ -16,34 +16,49 @@ steam_enable() { } # Sub-option of the SteamOS conversion: Steam starts silently (in the tray, -# no window) on the Plasma desktop. +# no window) on the Plasma desktop. It is Steam's own autostart entry, the file +# Steam's setting "Run Steam when my computer starts" creates and removes, so +# that setting shows what Steamify did (and the other way around). Steam's copy +# is the system steam.desktop; ours has -silent in its Exec line. +STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop" +STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop + silent_status() { - [[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]] + grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" +} + +silent_old_unit_remove() { + # Before 2.11.0 the option was a systemd user unit: it would start Steam a second time. + local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service" + [[ -f "$unit" ]] || return 0 + user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null + rm -f "$unit" + user_systemctl daemon-reload } silent_enable() { - local systemd_user_dir="$HOME/.config/systemd/user" - mkdir -p "$systemd_user_dir" - service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service" - # Clean out old .desktop shortcut so they don't fight - rm -f "$HOME/.config/autostart/steam.desktop" - user_systemctl daemon-reload - user_systemctl enable --now steam-desktop-autostart.service - ok "Steam starts silently on the desktop." + silent_old_unit_remove + mkdir -p "$(dirname "$STEAM_AUTOSTART")" + if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then + sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART" + fi + silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \ + 'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART" + ok "Steam starts silently on the desktop from the next login." } silent_disable() { - user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null - rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" - user_systemctl daemon-reload + silent_old_unit_remove + silent_status && rm -f "$STEAM_AUTOSTART" ok "Steam no longer starts by itself on the desktop." } steam_disable() { info "Removing Steam desktop settings..." - # The autostart unit is the `silent` option's: removed with it, and here + # The autostart entry is the `silent` option's: removed with it, and here # too for when the conversion goes off by itself. silent_status && silent_disable + silent_old_unit_remove rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf" ok "Steam desktop settings removed (takes full effect at next login)." } diff --git a/lib/steam-game.sh b/lib/steam-game.sh index ff85c82..7b628ca 100644 --- a/lib/steam-game.sh +++ b/lib/steam-game.sh @@ -56,7 +56,7 @@ steamgame_steam_busy() { steamgame_edit() { # steamgame_edit : runs it with Steam closed, then starts Steam - # again if it was running (through our autostart unit when that's there). + # again if it was running (silently, in the tray). local was_running=false i if pgrep -x steam >/dev/null; then steamgame_steam_busy && return 1 @@ -72,11 +72,7 @@ steamgame_edit() { fi "$1"; local rc=$? if [[ "$was_running" == true ]]; then - if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then - user_systemctl start steam-desktop-autostart.service - else - systemd-run --user --collect -q steam -silent >/dev/null 2>&1 - fi + systemd-run --user --collect -q steam -silent >/dev/null 2>&1 info "Steam is starting again." fi return "$rc" diff --git a/services/README.md b/services/README.md index 3ffd152..e13c69e 100644 --- a/services/README.md +++ b/services/README.md @@ -12,6 +12,5 @@ in the shell code. | `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts | | `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` | | `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) | -| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (user unit) | | `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel | | `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) | diff --git a/services/steam-desktop-autostart.service b/services/steam-desktop-autostart.service deleted file mode 100644 index b1c3323..0000000 --- a/services/steam-desktop-autostart.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=Steam Background Autostart for Virtual Keyboard -After=graphical-session.target -PartOf=graphical-session.target - -[Service] -Type=simple -# Only in the Plasma desktop session; gamescope-session starts its own Steam. -ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]' -ExecStart=/usr/bin/steam -silent -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=graphical-session.target From 7869b472be991cf6a8a7ba32b9a3cdb3fcf6e9da Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 10:15:59 +0200 Subject: [PATCH 05/11] feat: Steam Deck/Machine icons is a sub-option of the SteamOS conversion (it only changes gaming mode) --- CHANGELOG.md | 1 + TECHNICAL.md | 3 ++- lib/backend.sh | 4 ++-- lib/menu.sh | 7 ++++--- ui/qml/AppState.qml | 3 ++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11c165b..91ee239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 - `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** +- **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode** ## 2.10.0 - 2026-10-01 diff --git a/TECHNICAL.md b/TECHNICAL.md index dde3e2b..b032ba3 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -126,7 +126,8 @@ The conversion also sets what Steam's System settings show, see **Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"` in `~/.config/environment.d/` (and gamescope-session's own environment -file), which makes Steam show Steam Deck button glyphs in gaming mode. +file), which makes Steam show Steam Deck button glyphs in gaming mode. It is a sub-option of the SteamOS conversion (`gaming`): +it does nothing without gaming mode, ticking it ticks the conversion and turning the conversion off turns it off. ## SteamOS desktop look diff --git a/lib/backend.sh b/lib/backend.sh index fb97b49..f205da8 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -158,8 +158,8 @@ backend_apply() { [[ "${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 ]] && component_available gaming && WANTED[gaming]=1 - [[ "${WANTED[gaming]:-0}" == 0 ]] && WANTED[silent]=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 diff --git a/lib/menu.sh b/lib/menu.sh index cf09ec5..ce65dcb 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -5,12 +5,12 @@ # Menu order. Components are turned on in this order and off in reverse; # gaming must come first (single user builds on it). -COMPONENTS=(gaming boot silent nvidia bigpicture nvsilent theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) +COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) # One-off actions rather than on/off components: never preselected, never # re-applied, not listed as on or off. ACTIONS=(bios) # Sub-options, shown indented under their parent and only while it's ticked. -declare -A PARENT=([boot]=gaming [silent]=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) # 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 # upset other devices on the TV, even on SteamOS), except on a Steam Machine, @@ -307,8 +307,9 @@ toggle_component() { # Silent and Big Picture exclude each other. 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; fi + if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi + if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi # The power-off fix is opt-out: ticked along with Steam Machine support. if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index 9a95b00..6148d9c 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -78,13 +78,14 @@ Item { w[id] = !w[id]; // The same rules as the terminal menu (toggle_component). var hasGaming = items.some(function (i) { return i.id === "gaming"; }); - if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; } + if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; } if (id === "single" && w.single && hasGaming) w.gaming = true; if (id === "nvidia") w.bigpicture = w.nvidia; if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; } if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; } if (id === "nvidia" && !w.nvidia) w.nvsilent = false; if (id === "silent" && w.silent) w.gaming = true; + if (id === "glyphs" && w.glyphs) w.gaming = true; if (id === "machine") w.poweroff = w.machine; if (id === "poweroff" && w.poweroff) w.machine = true; if (id === "machine" && !w.machine) w.kpin = false; From 079e725ba857c74c53cc0fa51de8c4fb930c0feb Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 10:16:40 +0200 Subject: [PATCH 06/11] feat: "Start Steam silently in desktop mode" is opt-in (it was always on); an existing systemd unit counts as on and is migrated by the update --- CHANGELOG.md | 2 +- TECHNICAL.md | 2 +- lib/menu.sh | 4 ++-- lib/steam-desktop.sh | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ee239..5e8ee0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 -- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** +- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** - **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode** ## 2.10.0 - 2026-10-01 diff --git a/TECHNICAL.md b/TECHNICAL.md index b032ba3..b5b47a1 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -109,7 +109,7 @@ tools write to the conf.d fragment into the base config. installs `/usr/local/bin/sync-steamos-session.sh` plus `sync-steamos-session.path`/`.service`; - `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent` - ("Start Steam silently in desktop mode", on by default, always shown) writes + ("Start Steam silently in desktop mode", opt-in, always shown) writes `~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older `steam-desktop-autostart` user unit is removed; diff --git a/lib/menu.sh b/lib/menu.sh index ce65dcb..20a01b5 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -17,7 +17,7 @@ declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nv # which has CEC like on SteamOS. HDMI refresh boost needs someone at the # screen to confirm each step. Extended controller support builds kernel modules for # every installed kernel: opt-in. -NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support) +NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support) # Feature versions: the Steamify version in which what a component's enable # sets up last changed; set it to the new VERSION whenever you change one. # Each successful run records it (state "features"); a component that's on @@ -26,7 +26,7 @@ NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support) # FEATURE_BASELINE. FEATURE_BASELINE=2.1.0 declare -A FEATURE_VERSION=( - [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.1.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 + [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0 [kpin]=2.1.0 [hdmi]=2.1.0 ) diff --git a/lib/steam-desktop.sh b/lib/steam-desktop.sh index 5026856..3c04561 100644 --- a/lib/steam-desktop.sh +++ b/lib/steam-desktop.sh @@ -24,7 +24,9 @@ STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop" STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop silent_status() { - grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" + # The old systemd unit counts as on too (until it is migrated by an update of this option). + grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" || + [[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]] } silent_old_unit_remove() { From 188799e951c2584ace4d95b4535efa68bd4dedc8 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 10:43:25 +0200 Subject: [PATCH 07/11] fix: the SteamOS conversion no longer lists the silent start in what it changes (it is its own opt-in option) --- ui/qml/Texts.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/qml/Texts.qml b/ui/qml/Texts.qml index 5b6ccf2..d10aa0d 100644 --- a/ui/qml/Texts.qml +++ b/ui/qml/Texts.qml @@ -6,7 +6,7 @@ QtObject { readonly property var items: ({ gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop", body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.", - changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] }, + changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut"] }, boot: { label: "Boot into", hint: "Where the PC starts", body: "Where the PC starts after a restart. Switching back and forth works the same either way.", changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] }, From f3810a9fdd6bf81488cc5db05ad8f917e75c24df Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 10:52:04 +0200 Subject: [PATCH 08/11] fix: the SteamOS theme drops the blank Discover pin from the taskbar (also on the first login of an ISO install) --- CHANGELOG.md | 1 + TECHNICAL.md | 4 +++- lib/first-login.sh | 9 ++++----- lib/vapor-theme.sh | 29 ++++++++++++++++++++++------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e8ee0e..5959270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 - `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** +- **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login** - **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode** ## 2.10.0 - 2026-10-01 diff --git a/TECHNICAL.md b/TECHNICAL.md index b5b47a1..dc3f370 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -539,7 +539,9 @@ steamify.sh --defaults --list # what --defaults can se item this PC can't use (e.g. `vram` without a VRAM region) is left off with a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or `bios` in the list: exit code 1 before anything changes. What needs a -Plasma session waits for the first login (`lib/first-login.sh`). +Plasma session waits for the first login (`lib/first-login.sh`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover +(not installed on CachyOS: a blank icon), by CachyOS's own (`taskbar_drop_discover` in `lib/vapor-theme.sh`; skipped when Discover is +installed or the taskbar already has its own `launchers`). With `Relogin=true`, a gamescope session that fails to start is restarted immediately, which can turn into a loop - see diff --git a/lib/first-login.sh b/lib/first-login.sh index 055b68b..47eb9d3 100644 --- a/lib/first-login.sh +++ b/lib/first-login.sh @@ -31,10 +31,9 @@ first_login_run() { [[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break sleep 2 done - if single_status; then - stop_plasmashell_for_edit - single_launcher - restart_plasmashell_if_stopped - fi + stop_plasmashell_for_edit + taskbar_drop_discover + single_status && single_launcher + restart_plasmashell_if_stopped return 0 } diff --git a/lib/vapor-theme.sh b/lib/vapor-theme.sh index 1974c4b..d9b688a 100644 --- a/lib/vapor-theme.sh +++ b/lib/vapor-theme.sh @@ -106,17 +106,32 @@ theme_enable() { # SteamOS panel, launcher icon and wallpaper. It needs plasmashell up. lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 || { err "lookandfeeltool failed."; return 1; } - # The new layout has a new launcher, without single user's settings. - if single_status; then - sleep 3 - stop_plasmashell_for_edit - single_launcher - restart_plasmashell_if_stopped - fi + # The new layout has a new launcher, without single user's settings, and the default taskbar pins. + sleep 3 + stop_plasmashell_for_edit + taskbar_drop_discover + single_status && single_launcher + restart_plasmashell_if_stopped extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on." ok "Vapor theme active." } +taskbar_drop_discover() { + # Plasma's default taskbar pins Discover, which CachyOS doesn't install: the pin shows as a + # blank icon. Pin what CachyOS's own layout pins (/etc/skel) instead. Not when Discover is + # installed, and only on a taskbar that still has the default pins (no launchers key). + # Edit only while plasmashell is stopped. + [[ -e /usr/share/applications/org.kde.discover.desktop ]] && return 0 + local applet grp + for applet in $(plasma_applets org.kde.plasma.icontasks); do + grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General" + [[ -n "$(kreadconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \ + --group Applets --group "${applet#*:}" --group Configuration --group General --key launchers)" ]] && continue + kset theme plasma-org.kde.plasma.desktop-appletsrc "$grp" launchers \ + 'applications:systemsettings.desktop,preferred://filemanager,preferred://browser' + done +} + theme_disable() { extras_disable info "Restoring the previous desktop look and layout..." From 45a23aff340473a83ecd22f4a61c7641d9c072a4 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 11:11:18 +0200 Subject: [PATCH 09/11] feat: STEAMIFY_NO_DOWNLOAD: the first login runs the ISO's Steamify bundle instead of the newest release --- CHANGELOG.md | 1 + lib/first-login.sh | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5959270..66a1f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 - `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** +- **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)** - **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login** - **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode** diff --git a/lib/first-login.sh b/lib/first-login.sh index 47eb9d3..a6f1c7b 100644 --- a/lib/first-login.sh +++ b/lib/first-login.sh @@ -7,13 +7,24 @@ FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop" FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login" +FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh" first_login_schedule() { + # The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with + # steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead. + local run + if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$SCRIPT_DIR/steamify.sh" && ! -d "$SCRIPT_DIR/lib" ]]; then + install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$SCRIPT_DIR/steamify.sh" + run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\"" + else + run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login" + fi install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2 #!/bin/bash # Installed by Steamify CachyOS: runs once, at the first desktop login. set -o pipefail -curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login +mkdir -p ~/.cache +{ $run; } > ~/.cache/steamify-first-login.log 2>&1 rm -f "$FIRST_LOGIN_ENTRY" "\$0" [[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER" EOF2 From bd8f387cf529656d76adb0893fd03fd736082096 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 11:38:25 +0200 Subject: [PATCH 10/11] fix: STEAMIFY_NO_DOWNLOAD finds the bundle through BASH_SOURCE (a bundle has no SCRIPT_DIR: the install failed with an unbound variable) --- lib/first-login.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/first-login.sh b/lib/first-login.sh index a6f1c7b..30c04bd 100644 --- a/lib/first-login.sh +++ b/lib/first-login.sh @@ -12,9 +12,10 @@ FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh" first_login_schedule() { # The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with # steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead. - local run - if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$SCRIPT_DIR/steamify.sh" && ! -d "$SCRIPT_DIR/lib" ]]; then - install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$SCRIPT_DIR/steamify.sh" + # (Only a single-file bundle can be copied; SCRIPT_DIR doesn't exist in one.) + local run self="${BASH_SOURCE[0]:-}" + if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$self" ]] && grep -q '^# Single-file build' "$self"; then + install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$self" run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\"" else run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login" From 2f7b53f64be38e925f27834adca761b2f39eb8b5 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 2 Oct 2026 12:22:20 +0200 Subject: [PATCH 11/11] fix: the Steam Machine serial number step is not fatal in the installer chroot (read-only /sys); the tmpfiles.d file applies at boot --- CHANGELOG.md | 1 + lib/steam-machine.sh | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66a1f58..da6e720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ one per merged pull request. ## 2.11.0 - 2026-10-01 - `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it** +- **fix: the Steam Machine's serial number step no longer fails inside the ISO's installer (`/sys` is read-only in its chroot; the tmpfiles.d file applies at the next boot anyway), which made `machine` report an error and the install log end with `exit: 1`** - **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)** - **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login** - **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode** diff --git a/lib/steam-machine.sh b/lib/steam-machine.sh index ceb6ed7..77833a8 100644 --- a/lib/steam-machine.sh +++ b/lib/steam-machine.sh @@ -407,9 +407,12 @@ wifi_backend_disable() { serial_enable() { printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \ - 'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null && - sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" || + 'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null || { err "Making the serial number readable for Steam failed."; return 1; } + # The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot). + sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" 2>/dev/null || + info "The serial number becomes readable for Steam at the next boot." + return 0 } serial_disable() {