diff --git a/AGENTS.md b/AGENTS.md index 699aace..b0bae5e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -311,6 +311,21 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine `steamify.sh --boot gamescope|desktop` on its own (2.7.0, for scripts) only switches `boot` on an installed conversion: `WANTED` is `CURRENT` plus that, so no updates or removals a normal run would pick. +- What Steam's System settings show (SteamOS conversion, 2.9.0): the OS name + stays CachyOS's everywhere (legal clarity; Steam's OS Name is + `lsb_release -d`, not touched). `/etc/os-release` gets `VERSION_ID=steamos-X.Y` + (Steam's OS Version: Valve's newest jupiter repo; offline, the previous + value), `VERSION_CODENAME=steam-machine`, `VARIANT="Steamify "` and + `VARIANT_ID=steamify-` (Steam shows VARIANT_ID as OS Variant), + refreshed by `os_version_refresh` after every run that changes something; a + pacman hook (`zz-steamify-os-release`) runs after cachyos-hooks. KDE's About + this System would show VERSION_ID after the name: `kcm-about-distrorc` + `UseOSReleaseVersion=true` (kset) makes it show os-release's VERSION, which + CachyOS doesn't have. Never `NAME` or `PRETTY_NAME`: limine-snapper-sync + finds the boot entries by the OS name ("Target OS name ... not found in + /boot/limine.conf"); `/etc/default/limine` gets `TARGET_OS_NAME="CachyOS"` + when it has none, as a guard. The serial number (tmpfiles rule) is Steam + Machine support's, so Fremont only. - `Relogin=true` means a gamescope that fails to start is relaunched in a tight loop; keep that in mind when changing session handling. diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e5918..ee1c854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes, per version and per commit. Versions follow `steamify.sh`. Versions before 0.7.0 were numbered afterwards, one per merged pull request. +## 2.9.0 - 2026-09-28 + +- `d30d505` **chore: Version 2.9.0** +- `a72d848` **feat: Steam's OS Version is the SteamOS release Steamify follows (steamos-3.9), its OS Codename steam-machine; About this System keeps "CachyOS Linux" (UseOSReleaseVersion)** +- `27a4070` **fix: Steam's OS Variant shows Steamify's version (VARIANT_ID=steamify-2.9.0; Steam shows VARIANT_ID, not VARIANT)** +- `44bfe07` **fix: No VERSION_ID in os-release: About this System said "CachyOS Linux 2.9.0"; the version is in VARIANT ("Steamify 2.9.0")** +- `435f69c` **feat: Steam's System settings: the OS name stays CachyOS (no renaming, also not in About this System), Steamify as the variant, the SteamOS release it follows as the codename (steamos-3.9)** +- `ce71b34` **feat: Steam's System settings and About this System like on SteamOS: OS name "CachyOS with Steamify" (lsb-release, kept through CachyOS updates by a pacman hook), Steamify as OS variant and version (os-release VARIANT/VERSION_ID; NAME/PRETTY_NAME stay CachyOS's for limine, TARGET_OS_NAME pinned), "CachyOS Linux with Steamify" in About this System; on a Steam Machine the serial number and Steam's Wi-Fi backend setting (existing installs get it as an update)** +- `07a94cd` **fix(ui): The progress screen's ✓ and ! stand upright: only a dot on the circle spins while a step runs (they kept the spinner's last angle)** + ## 2.8.0 - 2026-09-28 - **chore: Version 2.8.0** diff --git a/lib/backend.sh b/lib/backend.sh index 05be3c1..1e351ec 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -177,6 +177,7 @@ backend_apply() { if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi done feature_record_unticked + os_version_refresh [[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " =~ \ (gaming|single|boot|kpin)\ ]] && RESTART_FOR_LOGIN=true backend_event finished "\"failed\":$(json_list "${failed[@]}"),\"restart\":$(restart_needed && echo true || echo false)" } diff --git a/lib/login-manager.sh b/lib/login-manager.sh index d2c4ea8..bd35013 100644 --- a/lib/login-manager.sh +++ b/lib/login-manager.sh @@ -18,6 +18,78 @@ gaming_status() { esac } +# What Steam shows in its System settings besides the OS name (which stays +# CachyOS's, for legal clarity and because limine-snapper-sync finds the boot +# entries by it): the SteamOS release as the OS version, steam-machine as the +# codename, Steamify with its version as the variant (os-release VERSION_ID, +# VERSION_CODENAME, VARIANT_ID; see patches/steamify-os-release.sh). +OS_NAME_SCRIPT=/usr/local/libexec/steamify-os-release +OS_NAME_HOOK=/etc/pacman.d/hooks/zz-steamify-os-release.hook +# limine's tools take the OS name from TARGET_OS_NAME, else os-release's +# PRETTY_NAME: pinned to CachyOS, the boot entries never depend on os-release. +LIMINE_DEFAULTS=/etc/default/limine + +steamos_release() { + # The SteamOS release Steamify follows: Valve's newest jupiter-X.Y repo + # (where the SteamOS extras come from), as an os-release ID (no spaces or + # capitals: steamos-3.9). Offline (e.g. in the installer): the one set + # before, if any. + local v + v="$(curl -fsL --max-time 15 "$VALVE_MIRROR/" 2>/dev/null | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)" + if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}" + else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi +} + +os_name_enable() { + # 2.9.0 pre-releases renamed the OS itself; the name stays CachyOS's. + if grep -q '^DISTRIB_DESCRIPTION=.*with Steamify' /etc/lsb-release 2>/dev/null && + [[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then + sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release + fi + [[ -n "$(kreadconfig6 --file kcm-about-distrorc --group General --key Name 2>/dev/null)" ]] && + kset gaming kcm-about-distrorc General Name --delete + # About this System: os-release's VERSION (CachyOS has none) instead of + # VERSION_ID, which is the SteamOS release now. + kset gaming kcm-about-distrorc General UseOSReleaseVersion true + patch_file steamify-os-release.sh | fill VERSION="$VERSION" STEAMOS="$(steamos_release)" | + sudo install -Dm755 /dev/stdin "$OS_NAME_SCRIPT" && + patch_file steamify-os-release.hook | fill SCRIPT="$OS_NAME_SCRIPT" | + sudo install -Dm644 /dev/stdin "$OS_NAME_HOOK" && + sudo "$OS_NAME_SCRIPT" || { err "Setting Steamify's version for Steam failed."; return 1; } + if [[ -f "$LIMINE_DEFAULTS" ]] && ! grep -q '^TARGET_OS_NAME=' "$LIMINE_DEFAULTS"; then + backup_file "$LIMINE_DEFAULTS" + printf '%s\n' 'TARGET_OS_NAME="CachyOS"' | sudo tee -a "$LIMINE_DEFAULTS" > /dev/null + state_set gaming limine_target 1 + fi + return 0 +} + +os_name_disable() { + sudo rm -f "$OS_NAME_HOOK" "$OS_NAME_SCRIPT" + [[ -f /etc/os-release ]] && sudo sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release + # CachyOS's own values back, the way its hooks write them. + if [[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then + sudo /usr/share/libalpm/scripts/cachyos-branding os-release + # Undoes 2.9.0 pre-releases, which changed lsb-release's name too. + sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release + fi + if [[ -n "$(state_get gaming limine_target)" ]]; then + sudo sed -i '/^TARGET_OS_NAME="CachyOS"$/d' "$LIMINE_DEFAULTS" + state_set gaming limine_target "" + fi + return 0 +} + +os_version_refresh() { + # After every run that changed something (sudo is at hand then): Steam's + # OS version follows Steamify's, not just the one that set it up. Silent: + # the app reads the backend's stdout as JSON. + gaming_status 2>/dev/null || return 0 + grep -qx "VARIANT_ID=steamify-$VERSION" /etc/os-release 2>/dev/null && return 0 + os_name_enable > /dev/null 2>&1 + return 0 +} + gaming_enable() { # LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the # menu. Re-running with the other value switches over cleanly. @@ -37,6 +109,7 @@ gaming_enable() { esac create_desktop_shortcut steam_enable + os_name_enable || return 1 } gaming_disable() { @@ -49,6 +122,8 @@ gaming_disable() { switch_to_plasmalogin remove_desktop_shortcut steam_disable + krevert gaming + os_name_disable ok "The PC boots to the normal login screen again (from the next boot)." } diff --git a/lib/menu.sh b/lib/menu.sh index 9fcebde..4356cee 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -25,8 +25,8 @@ NO_PRESELECT=(boot cec kpin hdmi) # FEATURE_BASELINE. FEATURE_BASELINE=2.1.0 declare -A FEATURE_VERSION=( - [gaming]=2.1.0 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 - [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.2.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 + [gaming]=2.9.0 [boot]=2.1.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 [kpin]=2.1.0 [hdmi]=2.1.0 ) @@ -465,5 +465,6 @@ apply_changes() { if "${c}_enable"; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi done feature_record_unticked + os_version_refresh FAILED=("${failed[@]}") } diff --git a/lib/steam-machine.sh b/lib/steam-machine.sh index 66fe10d..ceb6ed7 100644 --- a/lib/steam-machine.sh +++ b/lib/steam-machine.sh @@ -378,6 +378,46 @@ machine_status() { pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 && pacman -Qi steamos-manager >/dev/null 2>&1 } +# Steam (steamwebhelper) reads the serial number for its System settings +# straight from DMI, which the kernel makes root-only; SteamOS makes it +# readable. A tmpfiles rule does that at every boot. +SERIAL_TMPFILES=/etc/tmpfiles.d/steamify-serial.conf + +# Steam's Wi-Fi backend switch goes through steamos-manager, which reads and +# writes the backend in this file (SteamOS ships it); without it, it fails +# with "Wi-Fi backend not found in config". wpa_supplicant is what +# NetworkManager uses on CachyOS anyway. Not written when someone set a +# backend themselves. +WIFI_BACKEND_CONF=/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf + +wifi_backend_enable() { + [[ -f "$WIFI_BACKEND_CONF" ]] && return 0 + grep -rqs '^wifi.backend=' /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/conf.d && return 0 + printf '%s\n' "# Written by Steamify: Steam's Wi-Fi backend setting (steamos-manager)." \ + '[device]' 'wifi.backend=wpa_supplicant' | sudo install -Dm644 /dev/stdin "$WIFI_BACKEND_CONF" || + { err "Writing the Wi-Fi backend setting failed."; return 1; } + state_set machine wifi_backend 1 +} + +wifi_backend_disable() { + [[ -n "$(state_get machine wifi_backend)" ]] || return 0 + sudo rm -f "$WIFI_BACKEND_CONF" + state_clear machine +} + +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" || + { err "Making the serial number readable for Steam failed."; return 1; } +} + +serial_disable() { + sudo rm -f "$SERIAL_TMPFILES" + sudo chmod 0400 /sys/class/dmi/id/product_serial 2>/dev/null + return 0 +} + machine_enable() { # The pinned kernel first when it's wanted too, so DKMS builds the LED # driver for it once, instead of for the current kernel and then again. @@ -403,6 +443,8 @@ EOF # for hardware and controller settings; it knows the Steam Machine from its DMI data. info "Installing hardware manager packages (steamos-manager & inputplumber)..." sudo pacman -S --needed --noconfirm steamos-manager inputplumber || { err "Installing hardware manager packages failed."; return 1; } + serial_enable || return 1 + wifi_backend_enable || return 1 sudo systemctl enable --now inputplumber.service sudo systemctl enable --now steamos-manager.service user_systemctl enable steamos-manager.service 2>/dev/null @@ -426,6 +468,8 @@ machine_disable() { sudo systemctl disable --now steamos-manager.service 2>/dev/null sudo systemctl disable --now inputplumber.service 2>/dev/null sudo pacman -Rns --noconfirm steamos-manager inputplumber 2>/dev/null + serial_disable + wifi_backend_disable sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf sudo udevadm control --reload sudo modprobe -r leds-valve 2>/dev/null diff --git a/patches/README.md b/patches/README.md index ffed613..5b67b00 100644 --- a/patches/README.md +++ b/patches/README.md @@ -13,4 +13,5 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `steamify-fremont-poweroff.dkms.conf`, `steamify-cros-ec-cec.dkms.conf` | `lib/fremont-poweroff.sh`, `lib/cec.sh` | The DKMS modules' `dkms.conf` (`fill NAME=... VERSION=...`) | | `steam-shortcuts.py` | `lib/steam-game.sh` (Add as non-Steam game) | Reads and writes Steam's binary `shortcuts.vdf` (find, add or update, remove) | | `steamify-notifier.py` | `lib/update-notifier.sh` (Update notifications) | The daily check: notification and tray icon when there's a new release | +| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) | | `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port | diff --git a/patches/steamify-os-release.hook b/patches/steamify-os-release.hook new file mode 100644 index 0000000..3aba938 --- /dev/null +++ b/patches/steamify-os-release.hook @@ -0,0 +1,14 @@ +# Installed by Steamify CachyOS (SteamOS conversion): runs after +# cachyos-hooks' os-release/cachyos-branding hooks (hooks run in file name +# order). +[Trigger] +Operation = Install +Operation = Upgrade +Type = Package +Target = filesystem +Target = cachyos-hooks + +[Action] +Description = Steamify: the OS variant and version Steam shows +When = PostTransaction +Exec = @SCRIPT@ diff --git a/patches/steamify-os-release.sh b/patches/steamify-os-release.sh new file mode 100644 index 0000000..33c3f3c --- /dev/null +++ b/patches/steamify-os-release.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Installed by Steamify CachyOS (SteamOS conversion): what Steam shows in its +# System settings besides the OS name, which stays CachyOS's: the SteamOS +# release Steamify follows as the OS version (VERSION_ID, e.g. steamos-3.9), +# steam-machine as the codename, and Steamify with its version as the variant +# (VARIANT_ID, which Steam shows). KDE's About this System would show +# VERSION_ID after the name: the conversion sets its UseOSReleaseVersion, so it +# shows os-release's VERSION instead, which CachyOS doesn't have. NAME and +# PRETTY_NAME are never touched: limine-snapper-sync finds the boot entries by +# the OS name. The zz-steamify-os-release hook runs this after cachyos-hooks. +sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release +printf '%s\n' 'VARIANT="Steamify @VERSION@"' 'VARIANT_ID=steamify-@VERSION@' 'VERSION_CODENAME=steam-machine' >> /etc/os-release +[ -n "@STEAMOS@" ] && echo 'VERSION_ID=@STEAMOS@' >> /etc/os-release +exit 0 diff --git a/steamify.sh b/steamify.sh index f9662b4..7337f10 100755 --- a/steamify.sh +++ b/steamify.sh @@ -15,7 +15,7 @@ set -uo pipefail # Release version, see CHANGELOG.md. -VERSION=2.8.0 +VERSION=2.9.0 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" diff --git a/ui/qml/ApplyingScreen.qml b/ui/qml/ApplyingScreen.qml index 56c69b6..64a5d7a 100644 --- a/ui/qml/ApplyingScreen.qml +++ b/ui/qml/ApplyingScreen.qml @@ -35,7 +35,11 @@ Item { border.width: step.st === "wait" || step.st === "run" ? 2 : 0; border.color: step.st === "run" ? Theme.accent : "#343f50" Text { anchors.centerIn: parent; text: step.st === "ok" ? "✓" : (step.st === "fail" ? "!" : ""); color: step.st === "ok" ? Theme.good : Theme.bad font.pixelSize: 13; font.weight: Font.Bold } - RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } } + // Only this dot turns while the step runs: ✓ and ! never rotate + // (an animator leaves its item at whatever angle it stopped). + Item { anchors.fill: parent; visible: step.st === "run" + Rectangle { width: 6; height: 6; radius: 3; color: Theme.accent; x: parent.width / 2 - 3; y: -3 } + RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } } } Row { width: 380; anchors.verticalCenter: parent.verticalCenter; spacing: 10 // Boot into's label is its prefix already: "Boot into desktop", not "Boot into Boot into". Text { text: step.modelData.id === "boot" ? (Texts.actions[step.modelData.action] || [])[3] + Texts.actions[step.modelData.action][0].toLowerCase()