fix: Replace the question flow with a menu that turns components on and off

- Menu detects what is on and applies only the changes: SteamOS
  conversion, SteamOS theme, Steam Deck/Machine icons, single user mode,
  and Steam Machine support (only on Fremont hardware)
- Everything is reversible: KDE settings go through an undo journal
  (lib/state.sh), system files are restored from their backups
- Steam Machine support: LED driver, udev rule giving the user the LED
  files, steamos-manager for Steam's hardware settings; OpenRGB dropped
- Edit Plasma files only while plasmashell is stopped so it can't
  overwrite them
- README and AGENTS.md describe the menu, the component model and the
  test environment
This commit is contained in:
theupriser committed 2026-09-23 15:16:46 +02:00
1 parent a0bc385765
commit b91fa4bc83
13 files changed
+768 -562

No files matched your search

+32 -28
View File
@@ -13,11 +13,24 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
## Layout ## Layout
- `setup-gamescope-boot.sh` - the only entry point. Pre-flight checks, - `setup-gamescope-boot.sh` - the only entry point. Pre-flight checks,
sources `lib/*.sh`, then calls the steps in order. No step logic here. sources `lib/*.sh`, runs the menu and applies the plan. No component
logic here.
- `lib/*.sh` - one file per responsibility, each defining functions only - `lib/*.sh` - one file per responsibility, each defining functions only
(no top-level side effects). See the table in `README.md`. New (no top-level side effects besides constants). See the table in
functionality goes in the module it belongs to, or a new module that is `README.md`.
added to the `source` loop in `setup-gamescope-boot.sh`. - **Components.** Every menu item `<id>` (listed in `COMPONENTS` and `LABEL`
in `lib/menu.sh`) provides `<id>_status` (return 0 if on, detected from
the system, no state file needed), `<id>_enable` and `<id>_disable`, all
idempotent. `<id>_enable` is also used to re-apply. Optional
`<id>_available` is checked via `component_available` (e.g. `machine`
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
`gaming` must stay first. Dependencies live in `toggle_component`.
- **Reversibility.** Every per-user KDE setting a component changes goes
through `kset <component> <file> <group|group> <key> <value>`
(`lib/state.sh`), which records the old value once; `<id>_disable` calls
`krevert <component>`. Never call `kwriteconfig6` directly for settings a
component owns. System files are backed up with `backup_file` and restored
on disable.
## Conventions ## Conventions
@@ -41,12 +54,11 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
## Non-obvious behaviour to preserve ## Non-obvious behaviour to preserve
- One wizard question in `choose_setup_mode` sets `$SINGLE_USER` and - `apply_changes` sets `$LOGIN_MANAGER` from the menu: `sddm` when single
`$LOGIN_MANAGER`. "Single user, no password" = SteamOS: SDDM plus no lock user mode is wanted, else `plasmalogin`. Toggling single user re-applies
screen, user switching or log out (`setup_single_user`; the launcher's `gaming` so it moves to the other login manager. Single user mode hides
Session dropdown is hidden via kickoff `primaryActions=3` because the launcher's Session dropdown via kickoff `primaryActions=3` (restricting
restricting `action/logout` also hides Restart/Shut Down). Otherwise the `action/logout` also hides Restart/Shut Down). Two login-manager paths:
current login manager stays. Two login-manager paths:
**sddm** (like SteamOS: `steam-set-session` writes **sddm** (like SteamOS: `steam-set-session` writes
`/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM honours; we add `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM honours; we add
`User=`/`Relogin=` in `10-gamescope-autologin.conf`, and `/etc/sddm.conf` `User=`/`Relogin=` in `10-gamescope-autologin.conf`, and `/etc/sddm.conf`
@@ -75,6 +87,9 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
launches). launches).
- Live Plasma changes (`qdbus6 ... evaluateScript`, `lookandfeeltool`) only - Live Plasma changes (`qdbus6 ... evaluateScript`, `lookandfeeltool`) only
run when `plasmashell` is running; config-file fallbacks cover the rest. run when `plasmashell` is running; config-file fallbacks cover the rest.
- plasmashell writes its in-memory config back on exit: edit panel/applet/
wallpaper files only between `stop_plasmashell_for_edit` and
`restart_plasmashell_if_stopped` (`lib/common.sh`).
- LED driver: `leds-valve-dkms-git`'s Makefile builds against `uname -r`, - LED driver: `leds-valve-dkms-git`'s Makefile builds against `uname -r`,
so the script builds explicitly for the running kernel and installs so the script builds explicitly for the running kernel and installs
headers for every installed kernel first. The module creates headers for every installed kernel first. The module creates
@@ -91,21 +106,10 @@ for f in setup-gamescope-boot.sh lib/*.sh; do bash -n "$f"; done
shellcheck -S warning setup-gamescope-boot.sh lib/*.sh # if available shellcheck -S warning setup-gamescope-boot.sh lib/*.sh # if available
``` ```
Behaviour is best verified in a CachyOS VM (QEMU/KVM, KDE Plasma install, Behaviour is verified in a CachyOS QEMU/KVM test VM. The VM scripts and a
`plasma-login-manager`) with SSH access, reset from a disk snapshot between Claude Code skill describing the whole test workflow (snapshots, SSH, running
runs. Notes from doing this: the wizard with scripted menu input such as `printf '2\n\ny\nn\n'`, the
per-component checks, reboot checks, the full test matrix, `--fremont` to
- Run the script non-interactively by piping answers, e.g. fake Steam Machine hardware) live in
`printf "\ny\nn\nn\n" | ./setup-gamescope-boot.sh` (user, single user, [cachyos-gamescope-boot-dev-env](https://github.com/theupriser/cachyos-gamescope-boot-dev-env).
theme, reboot). Gamescope itself and the real LED bar can only be verified on hardware.
The prompt order depends on what's already installed.
- Over SSH, export the session environment before running it so the live
Plasma steps work:
`XDG_RUNTIME_DIR=/run/user/$UID WAYLAND_DISPLAY=wayland-0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus`.
- `spectacle -b -n -f -o shot.png` takes a screenshot to check the look.
Apps you launch over SSH lack the session's Qt platform theme and look
light; launch them with `systemd-run --user` to judge colors correctly.
- Gamescope usually won't render in a VM (no suitable Vulkan), so test the
session logic with `plasma.desktop` as the autologin session. The
gamescope boot itself and the LED driver can only be verified on real
hardware.
+136 -121
View File
@@ -11,16 +11,22 @@ script fixes that and sets everything up for you.
## What you get ## What you get
- **Boots into gaming mode** automatically - you never see a login screen, The wizard is a menu: pick what you want, and it turns each part on or off.
just like SteamOS. Everything you turn off is put back the way it was.
- **Switch to Desktop** from Steam's power menu works, and so does going
back: use the **Return to Gaming Mode** icon on the desktop, or just log 1. **SteamOS conversion** - boots straight into gaming mode, **Switch to
out. Desktop** in Steam works and so does going back (the **Return to Gaming
- **Back to gaming mode after a restart**, like SteamOS. Mode** icon on the desktop), you're back in gaming mode after a restart,
- **Steam's on-screen keyboard** (Steam + X) also works on the desktop. and Steam's on-screen keyboard (Steam + X) also works on the desktop.
- *Optional:* the **SteamOS desktop look** - Valve's own Vapor theme, 2. **SteamOS theme** - Valve's own Vapor look for the desktop: wallpaper,
wallpaper, dark mode and taskbar. dark mode and the SteamOS taskbar.
- *Optional, Steam Machine only:* a driver for the **front LED bar**. 3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode.
4. **Single user mode** - like SteamOS: never a login or lock screen, no
user switching or logging out. Typing a password with a controller is no
fun. (Needs 1.)
5. **Steam Machine support** - only shown on a Valve Steam Machine: the
driver for the front LED bar, and the hardware settings in Steam (fan,
TV control over HDMI-CEC).
## Requirements ## Requirements
@@ -37,31 +43,34 @@ cd <this-repo>
./setup-gamescope-boot.sh ./setup-gamescope-boot.sh
``` ```
Run it as yourself, not as root. It asks for your password once, then asks a Run it as yourself, not as root. You'll see a menu like this:
few yes/no questions:
- **Single user, no password, like SteamOS?** Recommended for a console. ```
You never see a login or lock screen, and there's no user switching or # Now Want Component
logging out - typing a password with a controller is no fun. This 1 off [x] SteamOS conversion: boot into gaming mode, Steam on the desktop
switches to SDDM, the login manager SteamOS uses. Say no to keep 2 off [x] Install SteamOS theme: Vapor look, dark mode, SteamOS taskbar
CachyOS's default login manager and KDE's normal lock screen; gaming mode 3 off [x] Install Steam Deck/Machine icons: Deck button icons in gaming mode
still starts automatically. 4 off [x] Single user mode: no password, lock screen or log out (SDDM)
- whether to install missing packages; ```
- the LED driver (Steam Machine only) and the SteamOS look.
At the end it offers to restart. The switch to SDDM takes effect from that **Now** shows what's on at the moment, **Want** what you'd like. Type a
restart. number and press Enter to tick or untick it, then press Enter on an empty
line to continue. The wizard shows what it will change, asks your password
once, and at the end offers to restart (needed for changes to how the PC
starts).
Run it again whenever you like - to change your choices, to turn things off
again, or after a CachyOS update (type `a` in the menu to re-apply
everything that's on).
Keep the whole folder: the script needs the files in `lib/` next to it. Keep the whole folder: the script needs the files in `lib/` next to it.
It's safe to run again later, for example after a CachyOS update.
## Using it ## Using it
- **To the desktop:** in gaming mode, open the Steam menu and choose - **To the desktop:** in gaming mode, open the Steam menu and choose
**Power > Switch to Desktop**. **Power > Switch to Desktop**.
- **Back to gaming mode:** double-click **Return to Gaming Mode** on the - **Back to gaming mode:** double-click **Return to Gaming Mode** on the
desktop (or log out, if you didn't choose single user). desktop (or log out, if you're not using single user mode).
- After a restart you always start in gaming mode. - After a restart you always start in gaming mode.
Prefer to decide yourself where your PC starts? Run one of these in Konsole: Prefer to decide yourself where your PC starts? Run one of these in Konsole:
@@ -86,42 +95,53 @@ That takes you back to the desktop.
freshly installed driver often needs a reboot. Still dark? See freshly installed driver often needs a reboot. Still dark? See
[Front LED bar](#front-led-bar-steam-machine) under technical details. [Front LED bar](#front-led-bar-steam-machine) under technical details.
**Undo the SteamOS look:** pick another theme under **System Settings > **Undo something:** run the wizard again and untick it.
Colors & Themes > Global Theme**.
To remove everything the script set up, see
[Removing everything](#removing-everything).
--- ---
## Technical details ## Technical details
### Single user: SDDM, no locking ### How turning things on and off works
The wizard's first question. Answering yes switches to **SDDM** and turns At startup every component checks whether it is on (`*_status` in `lib/`).
off everything that asks for a password or another user, per user and You choose; the wizard then turns off what you unticked (in reverse order)
without touching system files: `action/lock_screen`, `switch_user` and and turns on what you ticked. To be able to undo:
- **System files** are backed up once, next to the original, with a
`.bak-gamescope-wizard` suffix, and restored when you turn the component
off.
- **KDE settings** in your home directory are recorded with their previous
value the first time the wizard changes them, in an undo journal under
`~/.local/state/cachyos-gamescope-boot/`. Turning the component off writes
the old values back (or removes keys that didn't exist before). Setups
made by older versions of the script, without a journal, fall back to
KDE's defaults.
- **Packages** installed for the conversion (Steam, gamescope-session, ...)
are kept when you turn it off; Steam Machine support removes its own.
### Single user mode: SDDM, no locking
Turning it on switches to **SDDM** and turns off everything that asks for a
password or another user, per user: `action/lock_screen`, `switch_user` and
`start_new_session` restrictions in `kdeglobals`, no automatic locking `start_new_session` restrictions in `kdeglobals`, no automatic locking
(`kscreenlockerrc`), Meta+L and Ctrl+Alt+Del unbound, and the launcher shows (`kscreenlockerrc`), Meta+L and Ctrl+Alt+Del unbound, and the launcher shows
only Sleep / Restart / Shut Down (kickoff `primaryActions=3`), which hides only Sleep / Restart / Shut Down (kickoff `primaryActions=3`), which hides
the Session dropdown with Log Out. (Restricting `action/logout` would also the Session dropdown with Log Out. (Restricting `action/logout` would also
hide Restart and Shut Down.) Answering no restores KDE's defaults and keeps hide Restart and Shut Down.) Turning it off restores all of that and moves
the current login manager. the conversion back to plasma-login-manager.
**SDDM** is what SteamOS uses, and CachyOS's **SDDM** is what SteamOS uses, and CachyOS's `steam-set-session` supports it
`steam-set-session` supports it directly: it writes directly: it writes `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM
`/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM honours. The script honours. The script installs and enables `sddm` (active from the next boot),
installs and enables `sddm` (disabling the current display manager, active writes `User=`, `Session=` and `Relogin=true` to
from the next boot), writes `User=`, `Session=` and `Relogin=true` to
`/etc/sddm.conf.d/10-gamescope-autologin.conf`, and removes any `/etc/sddm.conf.d/10-gamescope-autologin.conf`, and removes any
`[Autologin]` from `/etc/sddm.conf` (read last, so it would override both). `[Autologin]` from `/etc/sddm.conf` (read last, so it would override both).
No sync bridge or sudoers rule is needed; the shortcut just runs No sync bridge or sudoers rule is needed; the shortcut just runs
`steamos-session-select gamescope`, which logs out, and `Relogin=true` `steamos-session-select gamescope`, which logs out, and `Relogin=true` logs
logs straight back in to gamescope. Switching an existing straight back in to gamescope.
plasma-login-manager setup to SDDM removes the sync bridge.
Keeping **plasma-login-manager** (CachyOS's default since March 2026) needs Without single user mode, the conversion uses **plasma-login-manager**
the workarounds below. (CachyOS's default since March 2026), which needs the workarounds below.
### Why this is needed (plasma-login-manager) ### Why this is needed (plasma-login-manager)
@@ -152,34 +172,35 @@ The script sets `Session=`, `User=` and `Relogin=true` in the base config,
and installs a small systemd path watcher that copies whatever CachyOS's and installs a small systemd path watcher that copies whatever CachyOS's
tools write to the conf.d fragment into the base config. tools write to the conf.d fragment into the base config.
### What the script changes ### What each component changes
In order: **SteamOS conversion** (`lib/login-manager.sh`, `lib/steam-desktop.sh`,
`lib/desktop-shortcut.sh`):
1. Checks that it runs as the user that should autologin, and asks whether - installs missing packages: `gamescope-session-cachyos`, `steam`,
to switch to SDDM (see above). `mangohud`, `xterm`, `ttf-liberation`, `wqy-zenhei`, `plasma-keyboard`;
2. Installs missing packages: `gamescope-session-cachyos`, `steam`, - *SDDM (single user mode):* installs/enables SDDM and writes its autologin
`mangohud`, `xterm`, `ttf-liberation`, `wqy-zenhei`, `plasma-keyboard`. config;
3. *SDDM:* installs/enables SDDM and writes its autologin config. - *plasma-login-manager:* creates `/etc/plasmalogin.conf.d`, backs up and
*plasma-login-manager:* creates `/etc/plasmalogin.conf.d`, backs up and rewrites the rewrites the `[Autologin]` section of `/etc/plasmalogin.conf`, removes
`[Autologin]` section of `/etc/plasmalogin.conf`, and removes stray stray `zzz-steamos-autologin*.conf` files from manual troubleshooting
`zzz-steamos-autologin*.conf` files from manual troubleshooting (never (never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
`zz-steamos-autologin.conf`, which CachyOS's tools own). installs `/usr/local/bin/sync-steamos-session.sh` plus
4. *plasma-login-manager only:* installs `/usr/local/bin/sync-steamos-session.sh` plus `sync-steamos-session.path`/`.service`;
`sync-steamos-session.path`/`.service`, which keep the base config in sync - `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a
with session switches. `steam-desktop-autostart` systemd user service that starts Steam silently
5. Sets up Steam for the desktop: `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"` in Plasma only;
(gamepad UI with Steam Deck glyphs), `KWIN_IM_SHOW_ALWAYS=1` for the - the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
virtual keyboard, and a `steam-desktop-autostart` systemd user service narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
that starts Steam silently in Plasma only. restart the login manager without a password prompt.
6. *(Steam Machine, optional)* the LED driver - see below.
7. *(Optional)* the SteamOS desktop look - see below.
8. Creates the **Return to Gaming Mode** shortcut. On plasma-login-manager it
also adds a narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`)
so it can restart the login manager without a password prompt.
Re-running doesn't duplicate any settings. Every system file it modifies is Turning it off restores `/etc/plasmalogin.conf` from its backup, removes the
backed up once, next to the original, with a `.bak-gamescope-wizard` suffix. SDDM autologin, sync bridge, shortcut, sudoers rule and Steam autostart, and
switches back to plasma-login-manager.
**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.
### SteamOS desktop look ### SteamOS desktop look
@@ -191,7 +212,7 @@ SteamOS mirror and installs it into `~/.local/share` - nothing system-wide:
- Valve's SteamOS desktop defaults, merged into your own config: Noto Sans - Valve's SteamOS desktop defaults, merged into your own config: Noto Sans
fonts, no Xwayland input-permission prompt for Steam Input, the window fonts, no Xwayland input-permission prompt for Steam Input, the window
rule that keeps the Steam keyboard on top and out of the taskbar, no rule that keeps the Steam keyboard on top and out of the taskbar, no
screen locking, no welcome screen, light file indexing; welcome screen, light file indexing;
- the SteamOS panel: solid (not floating), full width, 44 px high, tray icons - the SteamOS panel: solid (not floating), full width, 44 px high, tray icons
scaled to fit, date below the time, and the SteamOS launcher icon; scaled to fit, date below the time, and the SteamOS launcher icon;
- dark mode for GTK, libadwaita and portal-aware apps (Firefox, Flatpaks). - dark mode for GTK, libadwaita and portal-aware apps (Firefox, Flatpaks).
@@ -215,30 +236,47 @@ curl -fsL $m/$r/os/x86_64/$r.db | bsdtar -tf - | grep -o '^steamdeck-kde-presets
### Front LED bar (Steam Machine) ### Front LED bar (Steam Machine)
Standard desktop kernels, including CachyOS's, lack Valve's `leds-valve` The **Steam Machine support** component, only shown on Fremont hardware
driver, so the Steam Machine's front LED bar goes dark or "breathes". On (DMI `Valve`/`Fremont`, or `OEM`/`F7F` on early units):
Fremont hardware (DMI `Valve`/`Fremont`) the script offers to:
- install an AUR helper (`yay`) if neither `yay` nor `paru` is present; - installs an AUR helper (`yay`) if neither `yay` nor `paru` is present;
- install the kernel headers for every installed kernel; - installs the kernel headers for every installed kernel;
- install `leds-valve-dkms-git` from the AUR, build it for the running - installs `leds-valve-dkms-git` from the AUR - Valve's own driver from the
kernel, and load it at every boot (`/etc/modules-load.d/leds-valve.conf`); SteamOS kernel - builds it for the running kernel, and loads it at every
- optionally install the experimental `openrgb-git`, which can drive the bar. boot (`/etc/modules-load.d/leds-valve.conf`);
- adds a udev rule (`/etc/udev/rules.d/70-valve-leds-user.rules`) that gives
your user the LED files, so Steam, which runs as you, can drive the bar;
- installs and enables `steamos-manager`, the service Steam in gaming mode
uses for hardware settings (fan, HDMI-CEC, performance); it recognises the
Steam Machine from its DMI data.
The LEDs appear as `/sys/class/leds/valve-leds*`. Steam itself only drives Turning it off removes all of that again (the AUR helper is kept).
the bar (e.g. download progress) in real SteamOS Game Mode.
The driver's Makefile builds against the running kernel, so after a kernel The LEDs appear as `/sys/class/leds/valve-leds*`. The driver's Makefile
update, boot the new kernel and re-run the script (or builds against the running kernel, so after a kernel update, boot the new
`sudo dkms install leds-valve-dkms/0.1 -k "$(uname -r)"`). kernel and re-apply (`a` in the menu) or run
`sudo dkms install leds-valve-dkms/0.1 -k "$(uname -r)"`.
Troubleshooting: Troubleshooting:
```bash ```bash
dkms status dkms status
ls /sys/class/leds | grep valve ls -l /sys/class/leds/valve-leds*/
sudo dmesg | grep -i valve sudo dmesg | grep -i valve
cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log
journalctl --user -b | grep -i led
```
**BIOS updates** are not part of the wizard. Valve ships the Steam Machine
BIOS as `F7F0108.cab` in its `fremont-hw-support` package for fwupd. To
install it by hand (keep the machine on mains power and don't interrupt it):
```bash
sudo dmidecode -s bios-version # current version
sudo pacman -S fwupd
curl -LO https://steamdeck-packages.steamos.cloud/archlinux-mirror/holo-3.9/os/x86_64/fremont-hw-support-20260807.1-1-any.pkg.tar.zst
mkdir fhw && tar -I zstd -xf fremont-hw-support-*.pkg.tar.zst -C fhw
sudo fwupdmgr install fhw/usr/share/fwupd/remotes.d/fremont/firmware/F7F0108.cab
``` ```
### Manual session control ### Manual session control
@@ -255,48 +293,25 @@ immediately, which can turn into a loop - hence the Ctrl+Alt+F3 escape above.
### Removing everything ### Removing everything
```bash Run the wizard and untick everything. Afterwards the PC boots to the normal
# SDDM: go back to plasma-login-manager CachyOS login screen again; packages installed for the conversion (Steam,
sudo rm /etc/sddm.conf.d/10-gamescope-autologin.conf gamescope-session, ...) stay installed.
sudo systemctl disable sddm && sudo systemctl enable plasmalogin
# plasma-login-manager: restore the original login config
sudo cp /etc/plasmalogin.conf.bak-gamescope-wizard /etc/plasmalogin.conf
# session sync watcher
sudo systemctl disable --now sync-steamos-session.path
sudo rm /etc/systemd/system/sync-steamos-session.path
sudo rm /etc/systemd/system/sync-steamos-session.service
sudo rm /usr/local/bin/sync-steamos-session.sh
sudo systemctl daemon-reload
# shortcut and its sudoers rule
sudo rm /etc/sudoers.d/gamescope-session-switch
rm ~/Desktop/"Return to Gaming Mode.desktop"
# Steam desktop autostart and environment
systemctl --user disable --now steam-desktop-autostart.service
rm ~/.config/systemd/user/steam-desktop-autostart.service
rm ~/.config/environment.d/99-gamescope-steam-glyphs.conf \
~/.config/environment.d/99-kde-virtual-keyboard.conf
# LED driver (Steam Machine)
sudo rm /etc/modules-load.d/leds-valve.conf
sudo pacman -R leds-valve-dkms-git
```
### Project layout ### Project layout
| File | Responsibility | | File | Responsibility |
|---|---| |---|---|
| `setup-gamescope-boot.sh` | Entry point: user and sudo checks, step order, summary, reboot | | `setup-gamescope-boot.sh` | Entry point: checks, menu, apply, summary, restart |
| `lib/common.sh` | Output helpers, yes/no prompts, backups | | `lib/menu.sh` | The menu: detect, toggle, plan and apply changes |
| `lib/state.sh` | Undo journal for KDE settings (`kset`/`krevert`) |
| `lib/common.sh` | Output helpers, prompts, backups, plasmashell handling |
| `lib/packages.sh` | Required packages, AUR helper (yay/paru) | | `lib/packages.sh` | Required packages, AUR helper (yay/paru) |
| `lib/login-manager.sh` | SDDM or plasmalogin choice and autologin, session sync bridge | | `lib/login-manager.sh` | SteamOS conversion: SDDM or plasmalogin autologin, sync bridge |
| `lib/steam-desktop.sh` | Steam in the Plasma session: gamepad UI flags, virtual keyboard, autostart | | `lib/steam-desktop.sh` | Steam in the Plasma session; Steam Deck/Machine icons |
| `lib/led-driver.sh` | Fremont detection, kernel headers, LED driver, OpenRGB |
| `lib/vapor-theme.sh` | Vapor theme, Valve's SteamOS defaults, panel, dark mode |
| `lib/desktop-shortcut.sh` | Return to Gaming Mode shortcut and its sudoers rule | | `lib/desktop-shortcut.sh` | Return to Gaming Mode shortcut and its sudoers rule |
| `lib/vapor-theme.sh` | SteamOS theme: Vapor, Valve's defaults, panel, dark mode |
| `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out |
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager |
Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md). Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md).
+22
View File
@@ -45,3 +45,25 @@ backup_file() {
info "Backed up $f -> ${f}.bak-gamescope-wizard" info "Backed up $f -> ${f}.bak-gamescope-wizard"
fi fi
} }
# plasmashell keeps its config in memory and writes it back on exit, so
# edits to its files (panels, applets, wallpaper) must be made while it is
# stopped. It is restarted through systemd so it keeps the session's
# environment (platform theme etc.); a plain --replace from this shell
# may not, which gives a light-themed desktop.
stop_plasmashell_for_edit() {
PLASMASHELL_WAS_RUNNING=false
if pgrep -u "$USER" -x plasmashell >/dev/null; then
PLASMASHELL_WAS_RUNNING=true
systemctl --user stop plasma-plasmashell.service 2>/dev/null
pkill -u "$USER" -x plasmashell && sleep 2
fi
}
restart_plasmashell_if_stopped() {
if [[ "${PLASMASHELL_WAS_RUNNING:-false}" == true ]]; then
rm -rf ~/.cache/plasmashell* ~/.cache/org.kde.dirmodel-qml.kcache
systemctl --user start plasma-plasmashell.service 2>/dev/null ||
{ setsid plasmashell >/dev/null 2>&1 & }
fi
}
+7
View File
@@ -68,3 +68,10 @@ EOF
ok "Desktop shortcut created successfully." ok "Desktop shortcut created successfully."
} }
remove_desktop_shortcut() {
local desktop_dir
desktop_dir="$(xdg-user-dir DESKTOP 2>/dev/null || echo "$HOME/Desktop")"
rm -f "$desktop_dir/Return to Gaming Mode.desktop"
sudo rm -f /etc/sudoers.d/gamescope-session-switch
}
+62 -35
View File
@@ -1,58 +1,86 @@
#!/bin/bash #!/bin/bash
# plasma-login-manager autologin into gamescope, and the session sync bridge. # Booting into gaming mode: autologin into gamescope with SDDM or
# plasma-login-manager (plus the session sync bridge the latter needs).
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own. # Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
BASE_CONF="/etc/plasmalogin.conf" BASE_CONF="/etc/plasmalogin.conf"
choose_setup_mode() { # The "SteamOS conversion" menu item: gaming mode boot, the Return to
# Step 1: one question decides both the login manager and locking. # Gaming Mode shortcut and Steam on the desktop (lib/steam-desktop.sh).
# "Single user, no password" is SteamOS: SDDM (which CachyOS's session gaming_status() {
# tools support directly, no workarounds) plus no lock screen, user # Autologin into gamescope is configured for this user.
# switching or log out. Otherwise keep the current login manager case "$(current_display_manager)" in
# (CachyOS's default plasma-login-manager gets the sync bridge below) sddm) [[ -f /etc/sddm.conf.d/10-gamescope-autologin.conf ]] ;;
# and KDE's normal locking. Sets SINGLE_USER and LOGIN_MANAGER. plasmalogin)
local current sed -n '/^\[Autologin\]/,/^\[/p' "$BASE_CONF" 2>/dev/null | grep -qx "User=$USER" &&
current="$(systemctl show -p Id --value display-manager 2>/dev/null | sed 's/\.service$//')" [[ -f /etc/systemd/system/sync-steamos-session.path ]] ;;
info "Detected display manager: ${current:-none}" *) return 1 ;;
esac
echo "SteamOS is a single-user console without passwords: no login screen, no"
echo "lock screen, no user switching or logging out - typing a password with a"
echo "controller is no fun. It uses the SDDM login manager for that."
if ask_yn "Single user, no password, like SteamOS? (switches to SDDM)" y; then
SINGLE_USER=true
LOGIN_MANAGER="sddm"
return
fi
SINGLE_USER=false
if [[ "$current" == "sddm" ]]; then
LOGIN_MANAGER="sddm"
return
fi
LOGIN_MANAGER="plasmalogin"
if [[ "$current" != "plasmalogin" ]]; then
warn "The workarounds are built for plasma-login-manager, but '${current:-unknown}' is active."
ask_yn "Continue anyway?" n || exit 0
fi
} }
setup_login_manager() { gaming_enable() {
# Steps 3-8 for whichever login manager was chosen in step 1. # LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
# menu. Re-running with the other value switches over cleanly.
install_required_packages || return 1
case "$LOGIN_MANAGER" in case "$LOGIN_MANAGER" in
sddm) sddm)
switch_to_sddm || exit 1 switch_to_sddm || return 1
configure_sddm_autologin configure_sddm_autologin
remove_session_sync remove_session_sync
;; ;;
plasmalogin) plasmalogin)
remove_sddm_autologin
switch_to_plasmalogin || return 1
configure_autologin configure_autologin
install_session_sync install_session_sync
;; ;;
esac esac
create_desktop_shortcut
steam_enable
}
gaming_disable() {
# Back to a normal desktop boot with CachyOS's default login manager.
# Packages (steam, gamescope-session-cachyos, ...) are kept.
info "Turning off booting into gaming mode..."
remove_sddm_autologin
remove_session_sync
restore_plasmalogin_config
switch_to_plasmalogin
remove_desktop_shortcut
steam_disable
ok "The PC boots to the normal login screen again (from the next boot)."
}
switch_to_plasmalogin() {
[[ "$(current_display_manager)" == plasmalogin ]] && return 0
info "Switching the login manager to plasma-login-manager..."
sudo pacman -S --needed --noconfirm plasma-login-manager || { err "Installing plasma-login-manager failed."; return 1; }
local current
current="$(systemctl show -p Id --value display-manager 2>/dev/null)"
[[ -n "$current" && "$current" != plasmalogin.service ]] && sudo systemctl disable "$current"
sudo systemctl enable -f plasmalogin.service || { err "Enabling plasmalogin failed."; return 1; }
ok "plasma-login-manager is the login manager from the next boot on."
}
remove_sddm_autologin() {
sudo rm -f /etc/sddm.conf.d/10-gamescope-autologin.conf
}
restore_plasmalogin_config() {
# Put back the original /etc/plasmalogin.conf from the first run's
# backup, or at least drop our [Autologin] section.
if [[ -f "${BASE_CONF}.bak-gamescope-wizard" ]]; then
sudo cp -a "${BASE_CONF}.bak-gamescope-wizard" "$BASE_CONF"
elif [[ -f "$BASE_CONF" ]]; then
sudo awk '/^\[Autologin\]/ { skip=1; next } /^\[/ { skip=0 } !skip { print }' "$BASE_CONF" |
sudo tee "${BASE_CONF}.tmp" > /dev/null && sudo mv "${BASE_CONF}.tmp" "$BASE_CONF"
fi
} }
switch_to_sddm() { switch_to_sddm() {
# Takes effect at the next boot; the running session is left alone. # Takes effect at the next boot; the running session is left alone.
[[ "$(current_display_manager)" == sddm ]] && return 0
info "Installing and enabling SDDM..." info "Installing and enabling SDDM..."
sudo pacman -S --needed --noconfirm sddm || { err "Installing sddm failed."; return 1; } sudo pacman -S --needed --noconfirm sddm || { err "Installing sddm failed."; return 1; }
local current local current
@@ -62,7 +90,6 @@ switch_to_sddm() {
fi fi
sudo systemctl enable -f sddm.service || { err "Enabling sddm failed."; return 1; } sudo systemctl enable -f sddm.service || { err "Enabling sddm failed."; return 1; }
ok "SDDM is the login manager from the next boot on." ok "SDDM is the login manager from the next boot on."
echo
} }
configure_sddm_autologin() { configure_sddm_autologin() {
+118
View File
@@ -0,0 +1,118 @@
#!/bin/bash
# Interactive menu: detects which components are on, lets the user pick what
# they want, then turns components on or off to match.
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
# Menu order. Components are turned on in this order and off in reverse;
# gaming must come first (single user builds on it).
COMPONENTS=(gaming theme glyphs single machine)
declare -A LABEL=(
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
[theme]="Install SteamOS theme: Vapor look, dark mode, SteamOS taskbar"
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
[single]="Single user mode: no password, lock screen or log out (SDDM)"
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
)
declare -A CURRENT WANTED
component_available() {
[[ "$1" != machine ]] || machine_available
}
detect_components() {
local c any=false
for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue
if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi
WANTED[$c]=${CURRENT[$c]}
done
# First run: preselect the full SteamOS experience.
if [[ "$any" == false ]]; then
for c in "${COMPONENTS[@]}"; do
component_available "$c" && WANTED[$c]=1
done
fi
}
toggle_component() {
local c="$1"
WANTED[$c]=$(( 1 - WANTED[$c] ))
# Single user mode only makes sense on top of the SteamOS conversion.
if [[ "$c" == single && "${WANTED[single]}" == 1 ]]; then WANTED[gaming]=1; fi
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; fi
}
show_menu() {
local i=0 c now want
echo
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
MENU_ITEMS=()
for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue
i=$((i + 1)); MENU_ITEMS[$i]=$c
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="${c_green}on${c_reset} "
want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]"
printf " %-3s %-6b %-6s %s\n" "$i" "$now " "$want" "${LABEL[$c]}"
done
echo
}
run_menu() {
# Sets REAPPLY. Returns 1 if the user quit.
REAPPLY=false
local reply
while true; do
show_menu
read -rp "$(echo -e "${c_bold}Type a number to toggle, Enter to continue, a = also re-apply what's on, q = quit:${c_reset} ")" reply
case "$reply" in
"") return 0 ;;
a|A) REAPPLY=true; return 0 ;;
q|Q) return 1 ;;
*)
if [[ "$reply" =~ ^[0-9]+$ && -n "${MENU_ITEMS[$reply]:-}" ]]; then
toggle_component "${MENU_ITEMS[$reply]}"
else
warn "Unknown choice: $reply"
fi
;;
esac
done
}
plan_changes() {
# Fills TO_DISABLE (reverse order) and TO_ENABLE. Switching single user
# on or off moves gaming mode to the other login manager, so gaming
# mode is re-applied then too.
TO_DISABLE=(); TO_ENABLE=()
local c i
for (( i = ${#COMPONENTS[@]} - 1; i >= 0; i-- )); do
c=${COMPONENTS[$i]}
component_available "$c" || continue
[[ "${CURRENT[$c]}" == 1 && "${WANTED[$c]}" == 0 ]] && TO_DISABLE+=("$c")
done
for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue
[[ "${WANTED[$c]}" == 1 ]] || continue
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] ||
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
TO_ENABLE+=("$c")
fi
done
}
apply_changes() {
local c failed=()
LOGIN_MANAGER=plasmalogin
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
for c in "${TO_DISABLE[@]}"; do
echo; echo -e "${c_bold}Turning off: ${LABEL[$c]}${c_reset}"
"${c}_disable" || failed+=("$c")
done
for c in "${TO_ENABLE[@]}"; do
echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"
"${c}_enable" || failed+=("$c")
done
FAILED=("${failed[@]}")
}
+2 -7
View File
@@ -60,13 +60,8 @@ install_required_packages() {
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard) mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
if [[ ${#MISSING[@]} -gt 0 ]]; then if [[ ${#MISSING[@]} -gt 0 ]]; then
info "Missing packages: ${MISSING[*]}" info "Installing missing packages: ${MISSING[*]}"
if ask_yn "Install them now?"; then sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; exit 1; }
else
err "Cannot continue without these packages."
exit 1
fi
else else
ok "All required packages already installed." ok "All required packages already installed."
fi fi
+68
View File
@@ -0,0 +1,68 @@
#!/bin/bash
# Single user, no password, like SteamOS: no lock screen, user switching or
# log out, since typing a password with a controller is miserable. Goes
# together with SDDM (see lib/login-manager.sh). All changes are journaled
# per user (lib/state.sh), so turning it off restores KDE's previous state.
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
single_status() {
[[ "$(kreadconfig6 --file kdeglobals --group "KDE Action Restrictions" --key action/lock_screen)" == false ]]
}
single_enable() {
info "Turning off the lock screen, user switching and logging out..."
stop_plasmashell_for_edit
# Hides Lock / Switch User in menus.
local action applet
for action in lock_screen switch_user start_new_session; do
kset single kdeglobals "KDE Action Restrictions" "action/$action" false
done
# Never lock on idle or resume.
kset single kscreenlockerrc Daemon Autolock false
kset single kscreenlockerrc Daemon LockOnResume false
kset single kscreenlockerrc Daemon Timeout 0
# The restrictions don't cover the shortcuts: unbind Meta+L and the
# Ctrl+Alt+Del logout screen (format: current,default,description).
kset single kglobalshortcutsrc ksmserver "Lock Session" $'none,Screensaver\tMeta+L,Lock Session'
kset single kglobalshortcutsrc ksmserver "Log Out" 'none,Ctrl+Alt+Del,Show Logout Screen'
# Launcher: only Sleep / Restart / Shut Down, no Session dropdown (where
# Log Out lives). Restricting action/logout instead would also hide
# Restart and Shut Down.
for applet in $(plasma_applets org.kde.plasma.kickoff); do
local grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General"
kset single plasma-org.kde.plasma.desktop-appletsrc "$grp" primaryActions 3
kset single plasma-org.kde.plasma.desktop-appletsrc "$grp" systemFavorites 'suspend,reboot,shutdown'
done
restart_plasmashell_if_stopped
ok "Single user: no lock screen, user switching or log out."
}
single_disable() {
info "Restoring the lock screen, user switching and logging out..."
stop_plasmashell_for_edit
if has_journal single; then
krevert single
else
# Set up by a version of this script without the undo journal:
# fall back to KDE's defaults for everything it changes.
local action applet key
for action in lock_screen switch_user start_new_session; do
kwriteconfig6 --file kdeglobals --group "KDE Action Restrictions" --key "action/$action" --delete
done
for key in Autolock LockOnResume Timeout; do
kwriteconfig6 --file kscreenlockerrc --group Daemon --key "$key" --delete
done
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Lock Session" $'Screensaver\tMeta+L,Screensaver\tMeta+L,Lock Session'
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Log Out" 'Ctrl+Alt+Del,Ctrl+Alt+Del,Show Logout Screen'
for applet in $(plasma_applets org.kde.plasma.kickoff); do
kwriteconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
--group Applets --group "${applet#*:}" --group Configuration --group General --key primaryActions --delete
kwriteconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
--group Applets --group "${applet#*:}" --group Configuration --group General --key systemFavorites --delete
done
fi
restart_plasmashell_if_stopped
ok "KDE's normal lock screen and user switching are back."
}
+79
View File
@@ -0,0 +1,79 @@
#!/bin/bash
# Undo journal for per-user KDE settings, so every component can be turned
# off again exactly: the first time a component changes a key, the key's
# previous value is recorded, and reverting the component puts it back (or
# deletes the key if it didn't exist before).
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/cachyos-gamescope-boot"
UNSET=$'\x01'
kset() {
# kset <component> <file> <group[|group...]> <key> <value>
# kwriteconfig6, recording the old value in the component's journal.
# <value> "--delete" removes the key.
local component="$1" file="$2" groups="$3" key="$4" value="$5"
local journal="$STATE_DIR/$component.journal" old id
local -a gargs=() g
local groups_item
IFS='|' read -ra g <<< "$groups"
for groups_item in "${g[@]}"; do gargs+=(--group "$groups_item"); done
mkdir -p "$STATE_DIR"
id="$(printf '%s\t%s\t%s' "$file" "$groups" "$key")"
if ! grep -qxF -- "$id" <(cut -f1-3 "$journal" 2>/dev/null); then
old="$(kreadconfig6 --file "$file" "${gargs[@]}" --key "$key" --default "$UNSET")"
printf '%s\t%s\n' "$id" "$(printf '%s' "$old" | base64 -w0)" >> "$journal"
fi
if [[ "$value" == "--delete" ]]; then
kwriteconfig6 --file "$file" "${gargs[@]}" --key "$key" --delete
else
kwriteconfig6 --file "$file" "${gargs[@]}" --key "$key" "$value"
fi
}
krevert() {
# krevert <component>: restore every key the component changed, newest
# first, then forget the journal.
local component="$1"
local journal="$STATE_DIR/$component.journal"
local file groups key old groups_item
local -a g
[[ -f "$journal" ]] || return 0
while IFS=$'\t' read -r file groups key old; do
local -a gargs=()
IFS='|' read -ra g <<< "$groups"
for groups_item in "${g[@]}"; do gargs+=(--group "$groups_item"); done
old="$(printf '%s' "$old" | base64 -d)"
if [[ "$old" == "$UNSET" ]]; then
kwriteconfig6 --file "$file" "${gargs[@]}" --key "$key" --delete
else
kwriteconfig6 --file "$file" "${gargs[@]}" --key "$key" "$old"
fi
done < <(tac "$journal")
rm -f "$journal"
}
has_journal() {
[[ -s "$STATE_DIR/$1.journal" ]]
}
state_set() {
# state_set <component> <name> <value>: remember a value for later.
mkdir -p "$STATE_DIR"
kwriteconfig6 --file "$STATE_DIR/$1.state" --group State --key "$2" "$3"
}
state_get() {
# state_get <component> <name> [default]
kreadconfig6 --file "$STATE_DIR/$1.state" --group State --key "$2" --default "${3:-}"
}
state_clear() {
rm -f "$STATE_DIR/$1.state"
}
current_display_manager() {
systemctl show -p Id --value display-manager 2>/dev/null | sed 's/\.service$//'
}
+32 -76
View File
@@ -1,24 +1,14 @@
#!/bin/bash #!/bin/bash
# Steam in the Plasma desktop session: gamepad UI args, virtual keyboard, # Steam in the Plasma desktop session: gamepad UI args, virtual keyboard,
# autostart, and no screen locking (like SteamOS). # autostart. Part of the SteamOS conversion (gaming_enable/gaming_disable).
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own. # Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
setup_steam_desktop() { steam_enable() {
# Step 8b: always runs.
info "Applying non-optional SteamOS environment & keyboard fixes..." info "Applying non-optional SteamOS environment & keyboard fixes..."
local steam_env_dir gs_env systemd_user_dir local steam_env_dir systemd_user_dir
steam_env_dir="$HOME/.config/environment.d" steam_env_dir="$HOME/.config/environment.d"
mkdir -p "$steam_env_dir" mkdir -p "$steam_env_dir"
# 1. Force Gamescope Steam to boot into Deck mode and load Deck glyphs
echo "STEAM_GAMEPADUI_ARGS=\"-gamepadui -steamos3\"" > "$steam_env_dir/99-gamescope-steam-glyphs.conf"
gs_env="$HOME/.config/gamescope-session/environment"
if [[ -d "$HOME/.config/gamescope-session" ]]; then
touch "$gs_env"
sed -i '/^STEAM_GAMEPADUI_ARGS=/d' "$gs_env"
echo "STEAM_GAMEPADUI_ARGS=\"-gamepadui -steamos3\"" >> "$gs_env"
fi
# 2. Prevent KDE Wayland from blocking the virtual keyboard overlay # 2. Prevent KDE Wayland from blocking the virtual keyboard overlay
echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf" echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf"
@@ -54,70 +44,36 @@ EOF
ok "Steam UI parameters and keyboard autostart deployed successfully." ok "Steam UI parameters and keyboard autostart deployed successfully."
} }
setup_single_user() { steam_disable() {
# With SINGLE_USER (chosen in step 1), like SteamOS: one user and no info "Removing Steam desktop autostart..."
# password prompts, since typing a password with a controller is systemctl --user disable --now steam-desktop-autostart.service 2>/dev/null
# miserable. Hides Lock / Switch User / Log Out rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \
# everywhere (launcher, Meta+L, Ctrl+Alt+Del) and never locks on idle or "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
# resume; "Return to Gaming Mode" is the way out of the desktop. Declining systemctl --user daemon-reload
# restores KDE's defaults. ok "Steam desktop settings removed (takes full effect at next login)."
local action allow=true
[[ "$SINGLE_USER" == true ]] && allow=false
for action in lock_screen switch_user start_new_session; do
kwriteconfig6 --file kdeglobals --group "KDE Action Restrictions" --key "action/$action" "$allow"
done
if [[ "$allow" == false ]]; then
kwriteconfig6 --file kscreenlockerrc --group Daemon --key Autolock false
kwriteconfig6 --file kscreenlockerrc --group Daemon --key LockOnResume false
kwriteconfig6 --file kscreenlockerrc --group Daemon --key Timeout 0
# The action restriction hides Lock in menus but not the Meta+L
# shortcut; unbind it (format: current,default,description).
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Lock Session" \
$'none,Screensaver\tMeta+L,Lock Session'
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Log Out" \
'none,Ctrl+Alt+Del,Show Logout Screen'
set_launcher_leave_buttons single
ok "Screen locking, user switching and logging out disabled."
else
kwriteconfig6 --file kscreenlockerrc --group Daemon --key Autolock --delete
kwriteconfig6 --file kscreenlockerrc --group Daemon --key LockOnResume --delete
kwriteconfig6 --file kscreenlockerrc --group Daemon --key Timeout --delete
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Lock Session" \
$'Screensaver\tMeta+L,Screensaver\tMeta+L,Lock Session'
kwriteconfig6 --file kglobalshortcutsrc --group ksmserver --key "Log Out" \
'Ctrl+Alt+Del,Ctrl+Alt+Del,Show Logout Screen'
set_launcher_leave_buttons default
ok "Keeping KDE's normal screen locking and user switching."
fi
} }
set_launcher_leave_buttons() { # "Steam Deck/Machine icons" menu item: Steam's gamepad UI in SteamOS 3
# "single": only Sleep / Restart / Shut Down buttons in the launcher, no # mode, which shows Steam Deck button glyphs in gaming mode.
# Session dropdown (that's where Log Out lives). Restricting the glyphs_status() {
# "logout" action instead would also hide Restart and Shut Down. [[ -f "$HOME/.config/environment.d/99-gamescope-steam-glyphs.conf" ]]
# "default": Plasma's own buttons. }
local mode="$1" applet
for applet in $(plasma_applets org.kde.plasma.kickoff); do glyphs_enable() {
local -a grp=(--file plasma-org.kde.plasma.desktop-appletsrc --group Containments local gs_env="$HOME/.config/gamescope-session/environment"
--group "${applet%%:*}" --group Applets --group "${applet#*:}" mkdir -p "$HOME/.config/environment.d"
--group Configuration --group General) echo 'STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"' > "$HOME/.config/environment.d/99-gamescope-steam-glyphs.conf"
if [[ "$mode" == single ]]; then if [[ -d "$HOME/.config/gamescope-session" ]]; then
kwriteconfig6 "${grp[@]}" --key primaryActions 3 touch "$gs_env"
kwriteconfig6 "${grp[@]}" --key systemFavorites 'suspend,reboot,shutdown' sed -i '/^STEAM_GAMEPADUI_ARGS=/d' "$gs_env"
else echo 'STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"' >> "$gs_env"
kwriteconfig6 "${grp[@]}" --key primaryActions --delete
kwriteconfig6 "${grp[@]}" --key systemFavorites --delete
fi fi
done ok "Steam Deck/Machine icons on (from the next gaming mode start)."
if pgrep -u "$USER" -x plasmashell >/dev/null; then }
local js
if [[ "$mode" == single ]]; then glyphs_disable() {
js="w.writeConfig('primaryActions', 3); w.writeConfig('systemFavorites', 'suspend,reboot,shutdown');" rm -f "$HOME/.config/environment.d/99-gamescope-steam-glyphs.conf"
else [[ -f "$HOME/.config/gamescope-session/environment" ]] &&
js="w.writeConfig('primaryActions', 0); w.writeConfig('systemFavorites', 'suspend,hibernate,reboot,shutdown');" sed -i '/^STEAM_GAMEPADUI_ARGS=/d' "$HOME/.config/gamescope-session/environment"
fi ok "Steam's default button icons are back (from the next gaming mode start)."
qdbus6 org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript \
"panels().forEach(function (p) { p.widgets('org.kde.plasma.kickoff').forEach(function (w) { w.currentConfigGroup = ['General']; $js w.reloadConfig(); }); })" \
>/dev/null 2>&1 || true
fi
} }
+45 -17
View File
@@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# Valve Fremont (Steam Machine) front LED bar driver. # "Steam Machine support" menu item, only on Valve Fremont hardware: the
# front LED bar driver, LED access for Steam, and steamos-manager.
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own. # Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
detect_valve_fremont() { detect_valve_fremont() {
@@ -92,22 +93,49 @@ install_valve_led_driver() {
warn " ls /sys/class/leds/ | grep valve ; sudo dmesg | grep -i valve" warn " ls /sys/class/leds/ | grep valve ; sudo dmesg | grep -i valve"
fi fi
echo
info "Steam only pushes download progress to the LED bar in real SteamOS Game Mode."
if ask_yn "Also install the experimental OpenRGB build (openrgb-git), which can drive the LED bar?" n; then
"$aur_helper" -S "${flags[@]}" openrgb-git &&
ok "openrgb-git installed. Launch OpenRGB to detect and configure the front panel."
fi
} }
setup_led_driver() { LED_UDEV_RULE="/etc/udev/rules.d/70-valve-leds-user.rules"
# Step 8c: only on Fremont hardware, and only if the user wants it.
if detect_valve_fremont; then machine_available() { detect_valve_fremont; }
info "Detected Valve Fremont hardware (Steam Machine)."
if ask_yn "Set up the front-panel LED bar driver (leds-valve) so it isn't stuck dark/breathing?" y; then machine_status() {
ensure_aur_helper || warn "Couldn't set up an AUR helper automatically. You can install one yourself later and run: yay -S leds-valve-dkms-git" pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 && pacman -Qi steamos-manager >/dev/null 2>&1
install_valve_led_driver || warn "LED driver setup ran into a problem - see errors above. Your gamescope boot setup above is unaffected." }
fi
echo machine_enable() {
fi ensure_aur_helper || { warn "Couldn't set up an AUR helper automatically. Install yay or paru, then run the wizard again."; return 1; }
install_valve_led_driver || { warn "LED driver setup ran into a problem - see errors above."; return 1; }
# The LED files are root-only. Steam runs as the user; let it write them
# in case it drives the bar directly (Valve's own privileged-write helper
# doesn't cover the Steam Machine's LED bar).
info "Letting $TARGET_USER control the LED bar..."
sudo tee "$LED_UDEV_RULE" > /dev/null << EOF
# Let the console user (and Steam) control the Steam Machine's front LED bar.
SUBSYSTEM=="leds", KERNEL=="valve-leds*", RUN+="/usr/bin/find /sys%p -maxdepth 1 -type f -exec /usr/bin/chown $TARGET_USER {} +"
EOF
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=leds --action=add
# steamos-manager is what Steam in gaming mode talks to for hardware
# settings (fan, HDMI-CEC TV control, performance); it knows the Steam
# Machine from its DMI data.
info "Installing steamos-manager (Steam Machine hardware settings in Steam)..."
sudo pacman -S --needed --noconfirm steamos-manager || { err "Installing steamos-manager failed."; return 1; }
sudo systemctl enable --now steamos-manager.service
systemctl --user enable steamos-manager.service 2>/dev/null
ok "Steam Machine support on."
}
machine_disable() {
info "Removing Steam Machine support..."
systemctl --user disable --now steamos-manager.service 2>/dev/null
sudo systemctl disable --now steamos-manager.service 2>/dev/null
sudo pacman -Rns --noconfirm steamos-manager 2>/dev/null
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
sudo pacman -Rns --noconfirm leds-valve-dkms-git 2>/dev/null
ok "Steam Machine support removed (the AUR helper, if installed, is kept)."
} }
+116 -171
View File
@@ -4,22 +4,22 @@
merge_kde_config() { merge_kde_config() {
# Merge a KDE-style ini file (e.g. one of Valve's /etc/xdg defaults) into # Merge a KDE-style ini file (e.g. one of Valve's /etc/xdg defaults) into
# the user's own config with kwriteconfig6, so SteamOS defaults win over # the user's own config (journaled, see lib/state.sh), so SteamOS defaults win over
# the distro's without touching package-owned files in /etc/xdg. # the distro's without touching package-owned files in /etc/xdg.
# Nested groups ("[A][B]") are supported; immutable "[$i]" groups and # Nested groups ("[A][B]") are supported; immutable "[$i]" groups and
# comments are skipped. # comments are skipped.
local src="$1" target="$2" line key value local src="$1" target="$2" line key value
local -a groups=() local groups=""
local skip=0 local skip=0
while IFS= read -r line || [[ -n "$line" ]]; do while IFS= read -r line || [[ -n "$line" ]]; do
line="${line%$'\r'}" line="${line%$'\r'}"
[[ -z "$line" || "$line" == \#* ]] && continue [[ -z "$line" || "$line" == \#* ]] && continue
if [[ "$line" == \[* ]]; then if [[ "$line" == \[* ]]; then
skip=0; groups=() skip=0; groups=""
[[ "$line" == *'[$'* ]] && { skip=1; continue; } [[ "$line" == *'[$'* ]] && { skip=1; continue; }
local rest="$line" local rest="$line"
while [[ "$rest" =~ ^\[([^]]*)\](.*)$ ]]; do while [[ "$rest" =~ ^\[([^]]*)\](.*)$ ]]; do
groups+=("--group" "${BASH_REMATCH[1]}") groups+="${groups:+|}${BASH_REMATCH[1]}"
rest="${BASH_REMATCH[2]}" rest="${BASH_REMATCH[2]}"
done done
continue continue
@@ -27,7 +27,7 @@ merge_kde_config() {
(( skip )) && continue (( skip )) && continue
[[ "$line" == *=* ]] || continue [[ "$line" == *=* ]] || continue
key="${line%%=*}"; value="${line#*=}" key="${line%%=*}"; value="${line#*=}"
kwriteconfig6 --file "$target" "${groups[@]}" --key "$key" "$value" kset theme "$target" "$groups" "$key" "$value"
done < "$src" done < "$src"
} }
@@ -113,15 +113,19 @@ install_vapor_theme() {
[[ -f "${tmp_dir}/etc/xdg/$f" ]] && merge_kde_config "${tmp_dir}/etc/xdg/$f" "$f" [[ -f "${tmp_dir}/etc/xdg/$f" ]] && merge_kde_config "${tmp_dir}/etc/xdg/$f" "$f"
done done
[[ -f "${tmp_dir}/etc/xdg/kded5rc" ]] && merge_kde_config "${tmp_dir}/etc/xdg/kded5rc" kded6rc [[ -f "${tmp_dir}/etc/xdg/kded5rc" ]] && merge_kde_config "${tmp_dir}/etc/xdg/kded5rc" kded6rc
kwriteconfig6 --file konsolerc --group "Desktop Entry" --key DefaultProfile Vapor.profile kset theme konsolerc "Desktop Entry" DefaultProfile Vapor.profile
mkdir -p ~/.config/gtk-3.0 ~/.config/gtk-4.0 mkdir -p ~/.config/gtk-3.0 ~/.config/gtk-4.0
kwriteconfig6 --file ~/.config/gtk-3.0/settings.ini --group Settings --key gtk-theme-name Vapor kset theme ~/.config/gtk-3.0/settings.ini Settings gtk-theme-name Vapor
kwriteconfig6 --file ~/.config/gtk-4.0/settings.ini --group Settings --key gtk-theme-name Vapor kset theme ~/.config/gtk-4.0/settings.ini Settings gtk-theme-name Vapor
# Vapor is a dark theme: tell GTK, libadwaita and portal-aware apps # Vapor is a dark theme: tell GTK, libadwaita and portal-aware apps
# (Firefox, Steam's web views, Flatpaks) to use their dark variants too. # (Firefox, Steam's web views, Flatpaks) to use their dark variants too.
kwriteconfig6 --file ~/.config/gtk-3.0/settings.ini --group Settings --key gtk-application-prefer-dark-theme true kset theme ~/.config/gtk-3.0/settings.ini Settings gtk-application-prefer-dark-theme true
kwriteconfig6 --file ~/.config/gtk-4.0/settings.ini --group Settings --key gtk-application-prefer-dark-theme true kset theme ~/.config/gtk-4.0/settings.ini Settings gtk-application-prefer-dark-theme true
if command -v gsettings >/dev/null 2>&1; then if command -v gsettings >/dev/null 2>&1; then
[[ -n "$(state_get theme gsettings_scheme)" ]] ||
state_set theme gsettings_scheme "$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null)"
[[ -n "$(state_get theme gsettings_gtk)" ]] ||
state_set theme gsettings_gtk "$(gsettings get org.gnome.desktop.interface gtk-theme 2>/dev/null)"
gsettings set org.gnome.desktop.interface color-scheme prefer-dark 2>/dev/null || true gsettings set org.gnome.desktop.interface color-scheme prefer-dark 2>/dev/null || true
gsettings set org.gnome.desktop.interface gtk-theme Vapor 2>/dev/null || true gsettings set org.gnome.desktop.interface gtk-theme Vapor 2>/dev/null || true
fi fi
@@ -130,138 +134,52 @@ install_vapor_theme() {
info "Cleaning up temporary files..." info "Cleaning up temporary files..."
rm -rf "$tmp_dir" rm -rf "$tmp_dir"
# Launcher icon # Remember what to go back to when the theme is turned off again.
[[ -n "$(state_get theme lookandfeel)" ]] ||
state_set theme lookandfeel "$(kreadconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage \
--default "$(kreadconfig6 --file /etc/xdg/kdeglobals --group KDE --key LookAndFeelPackage --default org.kde.breeze.desktop)")"
[[ -n "$(state_get theme colorscheme)" ]] ||
state_set theme colorscheme "$(kreadconfig6 --file kdeglobals --group General --key ColorScheme --default BreezeLight)"
local appletsrc="plasma-org.kde.plasma.desktop-appletsrc" applet
# Same launcher icon SteamOS sets (Vapor Deck plasmoid setup script). # Same launcher icon SteamOS sets (Vapor Deck plasmoid setup script).
local icon_name="distributor-logo-steamdeck" for applet in $(plasma_applets org.kde.plasma.kickoff); do
local conf_file="$HOME/.config/plasma-org.kde.plasma.desktop-appletsrc" kset theme "$appletsrc" "Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General" icon distributor-logo-steamdeck
done
if ! find ~/.local/share/icons /usr/share/icons -iname "${icon_name}.*" 2>/dev/null | grep -q .; then # SteamOS scales tray icons to the panel height. Valve's setup script
warn "Could not find '${icon_name}' installed anywhere under ~/.local/share/icons or /usr/share/icons." # targets Plasma 5's separate tray containment; in Plasma 6 the setting
warn "The launcher icon will be set anyway, but it may show as a broken icon until the file is installed." # lives on the systemtray applet itself.
fi for applet in $(plasma_applets org.kde.plasma.systemtray); do
kset theme "$appletsrc" "Containments|${applet%%:*}|Applets|${applet#*:}|General" scaleIconsToFit true
if [[ -f "$conf_file" ]]; then done
info "Looking for the Application Launcher applet (Kickoff/Kicker) to set the custom icon..." # SteamOS shows the date below the time.
local matches=() for applet in $(plasma_applets org.kde.plasma.digitalclock); do
local current_section="" kset theme "$appletsrc" "Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|Appearance" dateDisplayFormat BelowTime
local current_containment=""
local current_applet=""
while IFS= read -r line; do
if [[ "$line" =~ ^\[Containments\]\[([0-9]+)\]\[Applets\]\[([0-9]+)\]$ ]]; then
current_containment="${BASH_REMATCH[1]}"
current_applet="${BASH_REMATCH[2]}"
current_section="applet_root"
continue
fi
if [[ "$line" =~ ^\[ ]]; then
current_section=""
continue
fi
if [[ "$current_section" == "applet_root" && "$line" =~ ^plugin=(org\.kde\.plasma\.(kickoff|kicker|simplemenu|homerun|application-menu))$ ]]; then
matches+=( "${current_containment}:${current_applet}:${BASH_REMATCH[1]}" )
current_section=""
fi
done < "$conf_file"
if [[ ${#matches[@]} -gt 0 ]]; then
for m in "${matches[@]}"; do
IFS=':' read -r containment applet plugin <<< "$m"
info "Setting launcher icon on Containment $containment / Applet $applet ($plugin)..."
kwriteconfig6 \
--file "$conf_file" \
--group Containments --group "$containment" \
--group Applets --group "$applet" \
--group Configuration --group General \
--key icon "$icon_name"
ok "Icon set to '$icon_name'."
done done
else
warn "No compatible Application Launcher applet found in panel config. Skipping icon assignment."
fi
else
warn "$conf_file not found. Skipping menu icon configuration."
fi
# SteamOS scales system tray icons to the panel height. Valve's setup # Wallpaper: Valve ships them as flat JPGs in usr/share/wallpapers.
# script targets Plasma 5's separate tray containment; in Plasma 6 the local wallpaper="$HOME/.local/share/wallpapers/Steam Deck Logo Default.jpg" containment
# setting lives on the systemtray applet itself. if [[ -f "$wallpaper" ]]; then
if [[ -f "$conf_file" ]]; then for containment in $(grep -oP '^\[Containments\]\[\K[0-9]+(?=\]$)' ~/.config/"$appletsrc" 2>/dev/null); do
local tray grep -q "^\[Containments\]\[$containment\]\[Wallpaper\]" ~/.config/"$appletsrc" || continue
for tray in $(awk ' kset theme "$appletsrc" "Containments|$containment|Wallpaper|org.kde.image|General" Image "file://$wallpaper"
/^\[Containments\]\[[0-9]+\]\[Applets\]\[[0-9]+\]$/ { split($0, p, /[][]+/); sect = p[3] ":" p[5] }
/^\[/ && !/\]\[Applets\]\[[0-9]+\]$/ { sect = "" }
/^plugin=org\.kde\.plasma\.systemtray$/ && sect != "" { print sect }
' "$conf_file"); do
kwriteconfig6 --file "$conf_file" --group Containments --group "${tray%%:*}" \
--group Applets --group "${tray#*:}" --group General \
--key scaleIconsToFit true
done done
fi fi
# SteamOS shows the date below the time in the panel clock. # Vapor color scheme and Plasma style; the theme's own defaults use
if [[ -f "$conf_file" ]]; then # breeze-dark icons (there is no "Vapor" icon theme).
local clock kset theme kdeglobals KDE LookAndFeelPackage com.valve.vapor.desktop
for clock in $(awk ' kset theme kdeglobals Icons Theme breeze-dark
/^\[Containments\]\[[0-9]+\]\[Applets\]\[[0-9]+\]$/ { split($0, p, /[][]+/); sect = p[3] ":" p[5] } kset theme kdeglobals General ColorScheme Vapor
/^\[/ && !/\]\[Applets\]\[[0-9]+\]$/ { sect = "" } kset theme plasmarc Theme name Vapor
/^plugin=org\.kde\.plasma\.digitalclock$/ && sect != "" { print sect }
' "$conf_file"); do
kwriteconfig6 --file "$conf_file" --group Containments --group "${clock%%:*}" \
--group Applets --group "${clock#*:}" --group Configuration --group Appearance \
--key dateDisplayFormat BelowTime
done
fi
# Wallpaper # SteamOS uses a solid, full-width bottom panel at Plasma's stock 44px
# Valve ships the wallpapers as flat JPGs in usr/share/wallpapers. # height (CachyOS ships a floating 30px one).
local wallpaper_path="$HOME/.local/share/wallpapers/Steam Deck Logo Default.jpg"
if [[ -f "$wallpaper_path" ]]; then
info "Applying official Steam Deck Vapor wallpaper via D-Bus script..."
local dbus_cmd="
var allDesktops = desktops();
for (var i = 0; i < allDesktops.length; i++) {
var d = allDesktops[i];
d.currentConfigGroup = ['Wallpaper', 'org.kde.image', 'General'];
d.writeConfig('Image', 'file://${wallpaper_path}');
}
"
if ! pgrep -u "$USER" -x plasmashell >/dev/null; then
:
elif command -v qdbus6 >/dev/null 2>&1; then
qdbus6 org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "$dbus_cmd" >/dev/null 2>&1 || true
else
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "$dbus_cmd" >/dev/null 2>&1 || true
fi
if [[ -f "$conf_file" ]]; then
local desktop_sections=$(grep -E '^\[Containments\]\[[0-9]+\]$' "$conf_file" || true)
while read -r section; do
if [[ -n "$section" ]]; then
local clean_sec=$(echo "$section" | tr -d '[]')
kwriteconfig6 --file "$conf_file" --group "$clean_sec" --group Wallpaper --group org.kde.image --group General --key Image "file://${wallpaper_path}"
fi
done <<< "$desktop_sections"
fi
ok "Wallpaper path pushed to session config."
else
warn "Could not find extracted Vapor wallpaper file. Skipping."
fi
# Activate the Vapor global theme and color scheme, then restart
# plasmashell once so it picks everything up (restarting first races
# with the settings being written). The theme's own defaults use
# breeze-dark icons; there is no "Vapor" icon theme.
kwriteconfig6 --file kdeglobals --group Icons --key Theme "breeze-dark"
kwriteconfig6 --file kdeglobals --group General --key ColorScheme "Vapor"
kwriteconfig6 --file plasmarc --group Theme --key name "Vapor"
# Same panel change for the next login, in case Plasma isn't running now.
local panel local panel
for panel in $(grep -oP '^\[PlasmaViews\]\[Panel \K[0-9]+(?=\]$)' ~/.config/plasmashellrc 2>/dev/null); do for panel in $(grep -oP '^\[PlasmaViews\]\[Panel \K[0-9]+(?=\]$)' ~/.config/plasmashellrc 2>/dev/null); do
kwriteconfig6 --file plasmashellrc --group PlasmaViews --group "Panel $panel" --key floating 0 kset theme plasmashellrc "PlasmaViews|Panel $panel" floating 0
kwriteconfig6 --file plasmashellrc --group PlasmaViews --group "Panel $panel" --group Defaults --key thickness 44 kset theme plasmashellrc "PlasmaViews|Panel $panel|Defaults" thickness 44
done done
gtk-update-icon-cache -f -t ~/.local/share/icons/hicolor 2>/dev/null || true gtk-update-icon-cache -f -t ~/.local/share/icons/hicolor 2>/dev/null || true
@@ -269,56 +187,83 @@ install_vapor_theme() {
# Live changes need a running Plasma session; otherwise they are picked # Live changes need a running Plasma session; otherwise they are picked
# up from the config files above at the next Plasma login. # up from the config files above at the next Plasma login.
if pgrep -u "$USER" -x plasmashell >/dev/null; then if [[ "${PLASMASHELL_WAS_RUNNING:-false}" == true ]]; then
info "Applying the theme to the running Plasma session..." info "Applying the theme to the running Plasma session..."
lookandfeeltool -a com.valve.vapor.desktop >/dev/null 2>&1 || true lookandfeeltool -a com.valve.vapor.desktop >/dev/null 2>&1 || true
# lookandfeeltool leaves the distro's color scheme active; apply it explicitly. # lookandfeeltool leaves the distro's color scheme active; apply it explicitly.
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
qdbus6 org.kde.kded6 /modules/gtkconfig org.kde.gtkconfig.setGtkTheme Vapor >/dev/null 2>&1 || true qdbus6 org.kde.kded6 /modules/gtkconfig org.kde.gtkconfig.setGtkTheme Vapor >/dev/null 2>&1 || true
qdbus6 org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript \
'panels().forEach(function (p) {
p.widgets("org.kde.plasma.systemtray").forEach(function (w) { w.currentConfigGroup = ["General"]; w.writeConfig("scaleIconsToFit", true); });
p.widgets("org.kde.plasma.digitalclock").forEach(function (w) { w.currentConfigGroup = ["Appearance"]; w.writeConfig("dateDisplayFormat", "BelowTime"); });
})' \
>/dev/null 2>&1 || true
# SteamOS uses a solid, full-width bottom panel at Plasma's stock
# 44px height (CachyOS ships a floating 30px one).
qdbus6 org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript \
'panels().forEach(function (p) { p.floating = false; p.lengthMode = "fill"; p.height = 44; })' \
>/dev/null 2>&1 || true
sleep 2 # let plasmashell flush the scripted changes before replacing it
rm -rf ~/.cache/plasmashell* ~/.cache/org.kde.dirmodel-qml.kcache
qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true
# Restart through systemd so plasmashell keeps the session's environment
# (platform theme etc.); a plain --replace from this shell may not.
if systemctl --user cat plasma-plasmashell.service >/dev/null 2>&1; then
# Also takes over from a stray instance started by an earlier --replace.
systemctl --user stop plasma-plasmashell.service
pkill -u "$USER" -x plasmashell && sleep 2
systemctl --user start plasma-plasmashell.service
else
setsid plasmashell --replace >/dev/null 2>&1 &
fi
else else
info "No running Plasma session; the theme applies at your next desktop login." info "No running Plasma session; the theme applies at your next desktop login."
fi fi
ok "SteamOS desktop look installed."
ok "Vapor theme assets installed. Apply it under System Settings > Appearance"
ok "> Global Theme > Vapor (Steam Deck), next time you're in a Plasma session."
} }
setup_vapor_theme() { theme_status() {
# Step 9 (optional): ask, make sure curl/zstd exist, then install. [[ "$(kreadconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage)" == com.valve.vapor.desktop ]]
echo }
if ask_yn "Also install Valve's official Vapor (Steam Deck) KDE theme for your desktop session?" n; then
if ! command -v curl >/dev/null 2>&1; then theme_enable() {
warn "curl not found, installing it first..." command -v curl >/dev/null 2>&1 || sudo pacman -S --needed --noconfirm curl
sudo pacman -S --needed --noconfirm curl command -v unzstd >/dev/null 2>&1 || sudo pacman -S --needed --noconfirm zstd
# Stop plasmashell first: the panel and wallpaper edits go to files it
# would otherwise overwrite with its in-memory config on exit.
stop_plasmashell_for_edit
install_vapor_theme
local rc=$?
restart_plasmashell_if_stopped
(( rc == 0 )) || warn "Vapor theme install ran into a problem - see errors above."
return $rc
}
theme_disable() {
info "Restoring the previous desktop look..."
local lookandfeel colorscheme
lookandfeel="$(state_get theme lookandfeel org.kde.breeze.desktop)"
colorscheme="$(state_get theme colorscheme BreezeLight)"
stop_plasmashell_for_edit
if has_journal theme; then
krevert theme
else
# Installed by a version of this script without the undo journal:
# undo the main settings it made.
kwriteconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage --delete
kwriteconfig6 --file kdeglobals --group General --key ColorScheme --delete
kwriteconfig6 --file kdeglobals --group Icons --key Theme --delete
kwriteconfig6 --file plasmarc --group Theme --key name --delete
local f
for f in ~/.config/gtk-3.0/settings.ini ~/.config/gtk-4.0/settings.ini; do
[[ -f "$f" ]] || continue
kwriteconfig6 --file "$f" --group Settings --key gtk-theme-name --delete
kwriteconfig6 --file "$f" --group Settings --key gtk-application-prefer-dark-theme --delete
done
kwriteconfig6 --file konsolerc --group "Desktop Entry" --key DefaultProfile --delete
fi fi
if ! command -v unzstd >/dev/null 2>&1; then if command -v gsettings >/dev/null 2>&1; then
warn "zstd not found, installing it first..." local v
sudo pacman -S --needed --noconfirm zstd v="$(state_get theme gsettings_scheme)"
if [[ -n "$v" ]]; then gsettings set org.gnome.desktop.interface color-scheme "$v" 2>/dev/null
else gsettings reset org.gnome.desktop.interface color-scheme 2>/dev/null; fi
v="$(state_get theme gsettings_gtk)"
if [[ -n "$v" ]]; then gsettings set org.gnome.desktop.interface gtk-theme "$v" 2>/dev/null
else gsettings reset org.gnome.desktop.interface gtk-theme 2>/dev/null; fi
fi fi
install_vapor_theme || warn "Vapor theme install ran into a problem - see errors above. Your gamescope boot setup above is unaffected." rm -rf ~/.local/share/plasma/look-and-feel/com.valve.vapor.desktop \
~/.local/share/plasma/desktoptheme/Vapor \
~/.local/share/themes/Vapor \
~/.local/share/color-schemes/Vapor.colors ~/.local/share/color-schemes/VGUI.colors \
~/.local/share/konsole/Vapor.profile ~/.local/share/konsole/Vapor.colorscheme \
~/.local/share/wallpapers/Steam\ Deck\ Logo*.jpg ~/.local/share/wallpapers/Troll.jpg
rm -f ~/.gtkrc-2.0
kbuildsycoca6 --noincremental 2>/dev/null || true
if [[ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]]; then
lookandfeeltool -a "$lookandfeel" >/dev/null 2>&1 || true
plasma-apply-colorscheme "$colorscheme" >/dev/null 2>&1 || true
fi fi
restart_plasmashell_if_stopped
state_clear theme
ok "Previous desktop look restored."
} }
+49 -107
View File
@@ -2,46 +2,21 @@
# #
# setup-gamescope-boot.sh # setup-gamescope-boot.sh
# #
# Wizard to configure a CachyOS (KDE Plasma + plasma-login-manager) install # Wizard that makes a CachyOS (KDE Plasma) install behave like SteamOS:
# to always boot into a Steam Deck-style gamescope session, with the # boot into a Steam Deck-style gamescope session, switch to the Plasma
# ability to switch to Plasma desktop and back, Deck-style, and have it # desktop and back, and reset to gamescope on the next boot/logout.
# reset to gamescope on the next boot/logout.
# #
# Covers three real bugs found on CachyOS as of Sep 2026: # It opens with a menu that detects which components are on and turns
# 1. steam-set-session never writes User= to plasmalogin's autologin # them on or off to match what the user picks; turning one off restores
# config, so plasma-login-manager never actually autologs in. # what was there before (system files from .bak-gamescope-wizard backups,
# 2. steam-set-session fails outright if /etc/plasmalogin.conf.d is # KDE settings from the undo journal in lib/state.sh). Components live in
# missing, breaking "Switch to Desktop" from inside gamescope. # lib/, see README.md. Safe to re-run.
# 3. /etc/plasmalogin.conf (the base config) hardcodes Session=plasma
# and takes priority over anything written to
# /etc/plasmalogin.conf.d/*.conf, so session switches never stick
# without a bridge that copies the conf.d value back into the base
# file, plus Relogin=true so ending a session re-triggers autologin
# instead of dropping to the greeter.
#
# Safe to re-run: it is idempotent and backs up files before editing.
#
# Automatically configures a permanent background systemd autostart for Steam
# and Wayland overrides so the Steam Controller virtual keyboard (Steam+X)
# always works in desktop mode.
#
# Optionally also offers to install the official Valve "Vapor" KDE Plasma
# theme (colors, icons, wallpapers, Plasma look-and-feel package) used on
# real SteamOS, pulled directly from Valve's own package mirror, so the
# desktop side matches the gamescope side visually.
#
# On Valve Fremont hardware (DMI sys_vendor=Valve, product_name=Fremont --
# i.e. the Steam Machine), also offers to install the
# leds-valve DKMS driver from the AUR so the front LED bar is exposed under
# /sys/class/leds instead of sitting dark or "breathing" under a standard
# desktop kernel, plus the option to pull in an experimental OpenRGB build
# that has native support for driving it.
set -uo pipefail set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for lib in common packages login-manager steam-desktop led-driver vapor-theme desktop-shortcut; do for lib in common state packages login-manager single-user steam-desktop steam-machine vapor-theme desktop-shortcut menu; do
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/$lib.sh" source "$SCRIPT_DIR/lib/$lib.sh"
done done
@@ -49,92 +24,59 @@ done
require_root_helper require_root_helper
echo -e "${c_bold}CachyOS Steam Deck-style Gamescope Boot Wizard${c_reset}" echo -e "${c_bold}CachyOS Steam Deck-style Gamescope Boot Wizard${c_reset}"
echo "This sets your machine up to always boot into gamescope (like SteamOS)," echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
echo "with working Switch-to-Desktop and switch-back, surviving reboots." echo "anything you turn off is put back the way it was."
echo
if ! command -v pacman >/dev/null 2>&1; then if ! command -v pacman >/dev/null 2>&1; then
err "This doesn't look like an Arch/CachyOS system (no pacman found). Aborting." err "This doesn't look like an Arch/CachyOS system (no pacman found). Aborting."
exit 1 exit 1
fi fi
# Ask for the sudo password once up front and keep it fresh, instead of # Everything per-user (autologin user, Steam, theme, shortcut) is for the
# prompting at random points during the run. # user running the script.
TARGET_USER="$(id -un)"
detect_components
run_menu || { info "Nothing changed."; exit 0; }
plan_changes
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
ok "Everything is already the way you want it."
exit 0
fi
echo
echo -e "${c_bold}This will:${c_reset}"
for c in "${TO_DISABLE[@]}"; do echo " - turn off: ${LABEL[$c]}"; done
for c in "${TO_ENABLE[@]}"; do
if [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"; else echo " - turn on: ${LABEL[$c]}"; fi
done
ask_yn "Go ahead?" y || { info "Nothing changed."; exit 0; }
# Ask for the sudo password once and keep it fresh, instead of prompting at
# random points during the run.
sudo -n true 2>/dev/null || sudo -v || exit 1 sudo -n true 2>/dev/null || sudo -v || exit 1
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null & while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
TARGET_USER="${SUDO_USER:-$USER}" apply_changes
read -rp "$(echo -e "${c_bold}Which user should autologin into gamescope?${c_reset} [${TARGET_USER}] ")" input_user
TARGET_USER="${input_user:-$TARGET_USER}"
if ! id "$TARGET_USER" >/dev/null 2>&1; then echo
err "User '$TARGET_USER' does not exist on this system." detect_components
exit 1 echo -e "${c_bold}Done. Current state:${c_reset}"
for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue
if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi
done
if [[ ${#FAILED[@]} -gt 0 ]]; then
warn "These had problems (see above): ${FAILED[*]}"
fi fi
if [[ "$TARGET_USER" != "$(id -un)" ]]; then
# Environment, systemd user units, theme and shortcut are all written
# into the invoking user's home and user session.
err "Run this script as '$TARGET_USER' itself so per-user settings land in the right home."
exit 1
fi
ok "Using user: $TARGET_USER"
echo echo
choose_setup_mode # Login manager changes only take effect after a restart.
echo if [[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]]; then
if ask_yn "Restart now so the changes take effect?" n; then
install_required_packages
echo
setup_login_manager
setup_steam_desktop
echo
setup_single_user
echo
setup_led_driver
setup_vapor_theme
echo
create_desktop_shortcut
echo
# ---------- 11. Summary + reboot ----------
echo -e "${c_bold}Setup complete.${c_reset}"
echo "What this did:"
echo " - Installed gamescope-session-cachyos, steam, mangohud and friends (if missing)"
if [[ "$LOGIN_MANAGER" == "sddm" ]]; then
echo " - Made SDDM the login manager, autologging '$TARGET_USER' into gamescope"
echo " with Relogin=true, like SteamOS (active from the next boot)"
else
echo " - Created /etc/plasmalogin.conf.d (fixes Switch-to-Desktop crash)"
echo " - Set $BASE_CONF to autologin '$TARGET_USER' into gamescope, with Relogin=true"
echo " - Installed a sync bridge + systemd watcher so Steam's Switch-to-Desktop"
echo " (and cachyos-gamescope-autologin.service resetting back to gamescope"
echo " on logout) both actually take effect"
echo " - Added /etc/sudoers.d/gamescope-session-switch so the desktop shortcut works"
fi
echo " - Configured permanent silent Steam autostart so Steam+X works everywhere"
echo " - Injected -steamos3 flag to force original Steam Deck overlay glyphs"
echo " - Optionally installed Valve's Vapor (Steam Deck) KDE theme, if you chose to"
echo " - On Valve Fremont hardware, optionally set up the leds-valve front LED bar driver"
echo
echo "Backups of any files this script modified were saved with a"
echo ".bak-gamescope-wizard suffix next to the original."
echo
echo "To manually flip sessions any time:"
echo " steamos-session-select gamescope # boot straight into gamescope now"
echo " steamos-session-select plasma # boot straight into desktop now"
echo " steamos-session-select persistent # remember last-used session across reboots"
echo " steamos-session-select oneshot # always start in gamescope regardless (default Deck behavior)"
echo
if ask_yn "Reboot now to test it?" n; then
sudo reboot sudo reboot
else else
info "Skipping reboot. Run 'sudo reboot' whenever you're ready to test." info "Restart whenever you're ready."
fi
fi fi