mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-03 17:41:58 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f91dd1f0b1 | ||
|
|
0411429654 | ||
|
|
1aa5e955fe | ||
|
|
ce75e895c4 | ||
|
|
9aef0a986a | ||
|
|
f7aa2412df | ||
|
|
87162efaa2 | ||
|
|
c79a3bbda5 | ||
|
|
ba11f58d9e | ||
|
|
45ff036f09 | ||
|
|
de02f267f4 | ||
|
|
0f123004d0 | ||
|
|
3048b35dd8 | ||
|
|
f7837f82b9 | ||
|
|
3eb41eef5a | ||
|
|
41422e5bb4 | ||
|
|
6c2e203563 | ||
|
|
1522e5632d | ||
|
|
1d994ae359 | ||
|
|
700f3e514b | ||
|
|
d78652c862 | ||
|
|
727e6a2302 | ||
|
|
c4bd1ca39c | ||
|
|
a449a9e467 | ||
|
|
388b1286c9 | ||
|
|
508f22acaf | ||
|
|
3f8e0372d1 | ||
|
|
bd90e29e7a | ||
|
|
4895de3a46 | ||
|
|
0f503dd112 | ||
|
|
d7cf0c0491 | ||
|
|
5ab83d6e6f | ||
|
|
2e107e537e | ||
|
|
986b3c8c07 | ||
|
|
afc05b0b23 | ||
|
|
b0553aecf7 | ||
|
|
69a420b8aa | ||
|
|
1c34a97598 | ||
|
|
be874b8594 | ||
|
|
f01aa93d0e | ||
|
|
852205317a | ||
|
|
77b94c29a2 | ||
|
|
c0014ee623 | ||
|
|
d39731a8b9 | ||
|
|
99a95abf1f | ||
|
|
429e840a9f | ||
|
|
45a8757f58 | ||
|
|
54fc9e362b | ||
|
|
b70c9d614f | ||
|
|
40c9ee638b | ||
|
|
2f9b2a54e1 |
No files matched your search
@@ -1,16 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Build a single-file version of the wizard for `curl | bash` use:
|
# Build a single-file version of the wizard for `curl | bash` use:
|
||||||
# .github/tools/bundle.sh [output] (default: dist/setup-gamescope-boot.sh)
|
# .github/tools/bundle.sh [output] (default: dist/steamify.sh)
|
||||||
#
|
#
|
||||||
# Inlines lib/*.sh in the order setup-gamescope-boot.sh sources them and
|
# Inlines lib/*.sh in the order steamify.sh sources them and
|
||||||
# wraps the entry point's body in main(), so bash has read the whole file
|
# wraps the entry point's body in main(), so bash has read the whole file
|
||||||
# before anything runs. That lets the bundle reattach stdin to the terminal
|
# before anything runs. That lets the bundle reattach stdin to the terminal
|
||||||
# when it was piped in by curl, so the interactive menu still works.
|
# when it was piped in by curl, so the interactive menu still works.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")/../.."
|
cd "$(dirname "$0")/../.."
|
||||||
|
|
||||||
out="${1:-dist/setup-gamescope-boot.sh}"
|
out="${1:-dist/steamify.sh}"
|
||||||
entry=setup-gamescope-boot.sh
|
entry=steamify.sh
|
||||||
mkdir -p "$(dirname "$out")"
|
mkdir -p "$(dirname "$out")"
|
||||||
|
|
||||||
# Library order, taken from the entry point's source loop.
|
# Library order, taken from the entry point's source loop.
|
||||||
@@ -23,15 +23,15 @@ version="v$(grep -oP '^VERSION=\K.*' "$entry"), $(git describe --always --dirty
|
|||||||
# Header comment and `set` line of the entry point, up to the source loop.
|
# Header comment and `set` line of the entry point, up to the source loop.
|
||||||
sed -n '1,/^SCRIPT_DIR=/p' "$entry" | sed '$d'
|
sed -n '1,/^SCRIPT_DIR=/p' "$entry" | sed '$d'
|
||||||
echo "# Single-file build ($version), generated by .github/tools/bundle.sh - edit the"
|
echo "# Single-file build ($version), generated by .github/tools/bundle.sh - edit the"
|
||||||
echo "# sources in the repository instead: https://github.com/theupriser/cachyos-gamescope-boot"
|
echo "# sources in the repository instead: https://github.com/theupriser/steamify-cachyos"
|
||||||
echo
|
echo
|
||||||
for lib in $libs; do
|
for lib in $libs; do
|
||||||
echo "# ----- lib/$lib.sh -----"
|
echo "# ----- lib/$lib.sh -----"
|
||||||
# Drop each module's shebang and its "Sourced by ..." boilerplate.
|
# Drop each module's shebang and its "Sourced by ..." boilerplate.
|
||||||
sed -e '1{/^#!/d}' -e '/^# Sourced by setup-gamescope-boot.sh/d' "lib/$lib.sh"
|
sed -e '1{/^#!/d}' -e '/^# Sourced by steamify.sh/d' "lib/$lib.sh"
|
||||||
echo
|
echo
|
||||||
done
|
done
|
||||||
echo "# ----- setup-gamescope-boot.sh -----"
|
echo "# ----- steamify.sh -----"
|
||||||
echo "main() {"
|
echo "main() {"
|
||||||
# Everything after the source loop is the entry point's body.
|
# Everything after the source loop is the entry point's body.
|
||||||
sed -n '/^for lib in /,$p' "$entry" | sed '1,/^done$/d' | sed 's/^/ /; s/^ $//'
|
sed -n '/^for lib in /,$p' "$entry" | sed '1,/^done$/d' | sed 's/^/ /; s/^ $//'
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Builds the single-file wizard (.github/tools/bundle.sh) and publishes it as a
|
# Builds the single-file wizard (.github/tools/bundle.sh) and publishes it as a
|
||||||
# release per version: tag v$VERSION (VERSION in setup-gamescope-boot.sh),
|
# release per version: tag v$VERSION (VERSION in steamify.sh),
|
||||||
# with that version's CHANGELOG.md section as notes. A released version is
|
# with that version's CHANGELOG.md section as notes. A released version is
|
||||||
# never overwritten; the newest one is marked latest, and the "latest" tag and
|
# never overwritten; the newest one is marked latest, and the "latest" tag and
|
||||||
# release are moved to it, so both of these always get the newest version:
|
# release are moved to it, so both of these always get the newest version:
|
||||||
# curl -fsSL https://github.com/theupriser/cachyos-gamescope-boot/releases/latest/download/setup-gamescope-boot.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
||||||
# curl -fsSL https://github.com/theupriser/cachyos-gamescope-boot/releases/download/latest/setup-gamescope-boot.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/latest/steamify.sh | bash
|
||||||
# Pull requests only build and check it, and warn when VERSION is already released.
|
# Pull requests only build and check it, and warn when VERSION is already released.
|
||||||
name: Single-file build
|
name: Single-file build
|
||||||
|
|
||||||
@@ -26,29 +26,30 @@ jobs:
|
|||||||
fetch-depth: 0 # for the version in the bundle's header
|
fetch-depth: 0 # for the version in the bundle's header
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: .github/tools/bundle.sh dist/setup-gamescope-boot.sh
|
run: |
|
||||||
|
.github/tools/bundle.sh dist/steamify.sh
|
||||||
|
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
bash -n dist/setup-gamescope-boot.sh
|
bash -n dist/steamify.sh
|
||||||
# SC2034/SC2154: variables used across the inlined modules.
|
# SC2034/SC2154: variables used across the inlined modules.
|
||||||
shellcheck -S warning -e SC2034,SC2154 dist/setup-gamescope-boot.sh
|
shellcheck -S warning -e SC2034,SC2154 dist/steamify.sh
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: setup-gamescope-boot
|
name: steamify
|
||||||
path: dist/setup-gamescope-boot.sh
|
path: dist/steamify.sh
|
||||||
|
|
||||||
- name: Version
|
- name: Version
|
||||||
id: version
|
id: version
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
version="$(grep -oP '^VERSION=\K.*' setup-gamescope-boot.sh)"
|
version="$(grep -oP '^VERSION=\K.*' steamify.sh)"
|
||||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
if gh release view "v$version" >/dev/null 2>&1; then
|
if gh release view "v$version" >/dev/null 2>&1; then
|
||||||
echo "released=true" >> "$GITHUB_OUTPUT"
|
echo "released=true" >> "$GITHUB_OUTPUT"
|
||||||
echo "::warning::v$version is already released and won't be overwritten. Bump VERSION in setup-gamescope-boot.sh and add a CHANGELOG.md section to release this."
|
echo "::warning::v$version is already released and won't be overwritten. Bump VERSION in steamify.sh and add a CHANGELOG.md section to release this."
|
||||||
else
|
else
|
||||||
echo "released=false" >> "$GITHUB_OUTPUT"
|
echo "released=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
@@ -68,12 +69,12 @@ jobs:
|
|||||||
notes="Single-file build of v$VERSION ($(git describe --always), $(git log -1 --format=%cs)).
|
notes="Single-file build of v$VERSION ($(git describe --always), $(git log -1 --format=%cs)).
|
||||||
Run the newest version with:
|
Run the newest version with:
|
||||||
|
|
||||||
curl -fsSL https://github.com/${{ github.repository }}/releases/latest/download/setup-gamescope-boot.sh | bash
|
curl -fsSL https://github.com/${{ github.repository }}/releases/latest/download/steamify.sh | bash
|
||||||
|
|
||||||
## Changes in v$VERSION
|
## Changes in v$VERSION
|
||||||
$changes"
|
$changes"
|
||||||
gh release create "v$VERSION" dist/setup-gamescope-boot.sh \
|
gh release create "v$VERSION" dist/steamify.sh assets/steam-gaming-settings.svg \
|
||||||
--target "$GITHUB_SHA" --title "v$VERSION" --notes "$notes" --latest
|
--target "$GITHUB_SHA" --title "Steamify CachyOS v$VERSION" --notes "$notes" --latest
|
||||||
|
|
||||||
# "latest" follows the newest version tag, for the older install URL
|
# "latest" follows the newest version tag, for the older install URL
|
||||||
# (.../releases/download/latest/...). Only moved when a new version
|
# (.../releases/download/latest/...). Only moved when a new version
|
||||||
@@ -81,8 +82,8 @@ jobs:
|
|||||||
git tag -f latest "$GITHUB_SHA" && git push -f origin latest
|
git tag -f latest "$GITHUB_SHA" && git push -f origin latest
|
||||||
latest_notes="Always the newest version, currently v$VERSION (see its release for the changes)."
|
latest_notes="Always the newest version, currently v$VERSION (see its release for the changes)."
|
||||||
if gh release view latest >/dev/null 2>&1; then
|
if gh release view latest >/dev/null 2>&1; then
|
||||||
gh release edit latest --title "Latest (v$VERSION)" --notes "$latest_notes" --latest=false
|
gh release edit latest --title "Steamify CachyOS - latest (v$VERSION)" --notes "$latest_notes" --latest=false
|
||||||
else
|
else
|
||||||
gh release create latest --title "Latest (v$VERSION)" --notes "$latest_notes" --latest=false
|
gh release create latest --title "Steamify CachyOS - latest (v$VERSION)" --notes "$latest_notes" --latest=false
|
||||||
fi
|
fi
|
||||||
gh release upload latest dist/setup-gamescope-boot.sh --clobber
|
gh release upload latest dist/steamify.sh assets/steam-gaming-settings.svg --clobber
|
||||||
@@ -5,19 +5,19 @@ for what the script does from a user's point of view.
|
|||||||
|
|
||||||
## Project overview
|
## Project overview
|
||||||
|
|
||||||
A bash wizard that makes CachyOS (KDE Plasma 6 + `plasma-login-manager`)
|
**Steamify CachyOS**: a bash wizard that makes CachyOS (KDE Plasma 6 + `plasma-login-manager`)
|
||||||
boot into a SteamOS-style gamescope session, with working switching between
|
boot into a SteamOS-style gamescope session, with working switching between
|
||||||
gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
||||||
(DMI `Valve`/`Fremont`) running CachyOS Desktop edition.
|
(DMI `Valve`/`Fremont`) running CachyOS Desktop edition.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `setup-gamescope-boot.sh` - the only entry point. Pre-flight checks,
|
- `steamify.sh` - the only entry point. Pre-flight checks,
|
||||||
sources `lib/*.sh`, runs the menu and applies the plan. No component
|
sources `lib/*.sh`, runs the menu and applies the plan. No component
|
||||||
logic here.
|
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 besides constants). See the table in
|
(no top-level side effects besides constants). See the table in
|
||||||
`README.md`.
|
`TECHNICAL.md`.
|
||||||
- **Components.** Every menu item `<id>` (listed in `COMPONENTS` and `LABEL`
|
- **Components.** Every menu item `<id>` (listed in `COMPONENTS` and `LABEL`
|
||||||
in `lib/menu.sh`) provides `<id>_status` (return 0 if on, detected from
|
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
|
the system, no state file needed), `<id>_enable` and `<id>_disable`, all
|
||||||
@@ -59,7 +59,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
- Comments explain *why* (the CachyOS/Plasma quirk being worked around),
|
- Comments explain *why* (the CachyOS/Plasma quirk being worked around),
|
||||||
not what the next line does.
|
not what the next line does.
|
||||||
|
|
||||||
- **Versioning and releases.** SemVer in `VERSION` (`setup-gamescope-boot.sh`,
|
- **Versioning and releases.** SemVer in `VERSION` (`steamify.sh`,
|
||||||
shown in the menu header and the bundle header).
|
shown in the menu header and the bundle header).
|
||||||
- Every commit gets an entry in `CHANGELOG.md` under its version (short hash
|
- Every commit gets an entry in `CHANGELOG.md` under its version (short hash
|
||||||
+ subject; a commit can't contain its own hash, so fill it in with the
|
+ subject; a commit can't contain its own hash, so fill it in with the
|
||||||
@@ -70,7 +70,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
changelog section) and marks it latest. An existing version is never
|
changelog section) and marks it latest. An existing version is never
|
||||||
overwritten: without a bump nothing is released, and pull requests show
|
overwritten: without a bump nothing is released, and pull requests show
|
||||||
a warning.
|
a warning.
|
||||||
- Users install through `releases/latest/download/setup-gamescope-boot.sh`
|
- Users install through `releases/latest/download/steamify.sh`
|
||||||
(GitHub's newest release). The `latest` tag and release follow the newest
|
(GitHub's newest release). The `latest` tag and release follow the newest
|
||||||
version tag too (moved, asset replaced, when a new version is released),
|
version tag too (moved, asset replaced, when a new version is released),
|
||||||
so the older URL `releases/download/latest/...` keeps working.
|
so the older URL `releases/download/latest/...` keeps working.
|
||||||
@@ -132,16 +132,60 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
and `ensure-kernel-headers.service` installs missing ones at boot (a
|
and `ensure-kernel-headers.service` installs missing ones at boot (a
|
||||||
pacman hook can't run pacman), which triggers DKMS's install hook. The module creates
|
pacman hook can't run pacman), which triggers DKMS's install hook. The module creates
|
||||||
`/sys/class/leds/valve-leds*`.
|
`/sys/class/leds/valve-leds*`.
|
||||||
|
- `boot` ("Boot into: [gamescope] / desktop") is a choice row, not a
|
||||||
|
checkbox: on = desktop. It's a sub-option of the conversion: `menu_visible`
|
||||||
|
only shows it (indented, `└`) while `gaming` is ticked, so menu numbers
|
||||||
|
after it shift by one when the conversion is unticked. It needs `gaming` (ticking it ticks gaming,
|
||||||
|
unticking gaming unticks it) and is never preselected (`NO_PRESELECT`), so
|
||||||
|
the conversion boots into gamescope by default. Desktop is
|
||||||
|
`steamify-boot-desktop.service`, ordered `Before=` the login managers:
|
||||||
|
`steam-set-session plasma.desktop` plus the plasmalogin sync bridge when it
|
||||||
|
exists, at every boot. CachyOS's `cachyos-gamescope-autologin` still sets
|
||||||
|
gamescope during each desktop session; the unit corrects it at boot.
|
||||||
|
- `bios` is an *action* (`ACTIONS` in `lib/menu.sh`), not an on/off
|
||||||
|
component: never preselected (not even on a first run), never re-applied
|
||||||
|
by `a`, not listed in the state overview, and `bios_status` is always off.
|
||||||
|
Only selectable when Valve's version differs from the installed one
|
||||||
|
(`component_selectable`, greyed out otherwise). Download, SHA-256 and the
|
||||||
|
fwupd device check (`get-details --json`: no `UpdateError`) come before the
|
||||||
|
warnings. The warning box uses `█` for its frame: Konsole draws a long
|
||||||
|
coloured row of `#` narrower, so the right edge wouldn't line up.
|
||||||
|
Keep both confirmations (y/N, then typing `UPDATE`) and the warnings; the
|
||||||
|
firmware comes from the newest `holo-X.Y` repo (`.files` db names the
|
||||||
|
`.cab`, `.db` gives the SHA-256), and fwupd itself refuses non-Fremont
|
||||||
|
hardware. In the VM, test it with `WIZARD_BIOS_DRY_RUN=1` (skips only the
|
||||||
|
device check, never flashes) and a faked version (dev-env
|
||||||
|
`BIOS_VERSION=F7F0107 ./run.sh --fremont`).
|
||||||
|
- The entry point loops: menu, run, "back to the menu" (or `[m]`/`[r]` when a
|
||||||
|
restart is needed), until `q`. When a restart is needed, `q` asks "Restart
|
||||||
|
now? [Y/n]" (`quit_prompt`): `n` goes back to the menu, the next `q` asks
|
||||||
|
again. Scripted input that runs out quits without restarting (never
|
||||||
|
restart on EOF: `ask_yn` would take its default).
|
||||||
|
- Steamify shortcut (`launcher`): the icon runs `curl | bash` of
|
||||||
|
`releases/latest/download/steamify.sh` in Konsole, so it's
|
||||||
|
always the newest release. Its icon, `assets/steam-gaming-settings.svg`
|
||||||
|
(Valve's GPL-2.0 return icon with a gear), is a release asset too, and is
|
||||||
|
downloaded from there (Steam's icon if that fails). Desktop files are
|
||||||
|
written with their mode already set (`install_executable`): Plasma opens a
|
||||||
|
desktop icon it first saw non-executable in an editor.
|
||||||
|
The start script closes its window after a 10-second countdown on success
|
||||||
|
and waits for Enter after an error; it uses `pipefail`, or a failed
|
||||||
|
download would run an empty script and count as success.
|
||||||
- `Relogin=true` means a gamescope that fails to start is relaunched in a
|
- `Relogin=true` means a gamescope that fails to start is relaunched in a
|
||||||
tight loop; keep that in mind when changing session handling.
|
tight loop; keep that in mind when changing session handling.
|
||||||
|
|
||||||
## Checking changes
|
## Checking changes
|
||||||
|
|
||||||
|
The bundle puts every module in one file, so shellcheck sees all their
|
||||||
|
`local` variables together: don't reuse a name another module uses as an
|
||||||
|
array (e.g. `g` in `lib/state.sh`), or CI's shellcheck on the bundle fails.
|
||||||
|
|
||||||
|
|
||||||
There is no test suite. At minimum:
|
There is no test suite. At minimum:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
for f in setup-gamescope-boot.sh lib/*.sh; do bash -n "$f"; done
|
for f in steamify.sh lib/*.sh; do bash -n "$f"; done
|
||||||
shellcheck -S warning setup-gamescope-boot.sh lib/*.sh # if available
|
shellcheck -S warning steamify.sh lib/*.sh # if available
|
||||||
```
|
```
|
||||||
|
|
||||||
Behaviour is verified in a CachyOS QEMU/KVM test VM. The VM scripts and a
|
Behaviour is verified in a CachyOS QEMU/KVM test VM. The VM scripts and a
|
||||||
@@ -150,5 +194,5 @@ the wizard with scripted menu input such as `printf '2\n\ny\nn\n'`, the
|
|||||||
per-component checks; when stdin is not a terminal the menu falls back to a
|
per-component checks; when stdin is not a terminal the menu falls back to a
|
||||||
numbered prompt, which is what scripted runs use, reboot checks, the full test matrix, `--fremont` to
|
numbered prompt, which is what scripted runs use, reboot checks, the full test matrix, `--fremont` to
|
||||||
fake Steam Machine hardware) live in
|
fake Steam Machine hardware) live in
|
||||||
[cachyos-gamescope-boot-dev-env](https://github.com/theupriser/cachyos-gamescope-boot-dev-env).
|
[steamify-cachyos-dev](https://github.com/theupriser/steamify-cachyos-dev).
|
||||||
Gamescope itself and the real LED bar can only be verified on hardware.
|
Gamescope itself and the real LED bar can only be verified on hardware.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# HDMI-CEC: does my PC have it?
|
||||||
|
|
||||||
|
The **HDMI-CEC** item in Steamify lets you use Steam with your TV's remote,
|
||||||
|
and turns the TV on and off with the PC. It only works when the PC has a
|
||||||
|
CEC device (`/dev/cec*`). Many PCs don't: on desktop PCs CEC is rare.
|
||||||
|
How it works: [TECHNICAL.md](TECHNICAL.md#hdmi-cec); problems:
|
||||||
|
[TROUBLESHOOTING.md](TROUBLESHOOTING.md#the-tv-remote-does-nothing-hdmi-cec).
|
||||||
|
|
||||||
|
## Graphics cards
|
||||||
|
|
||||||
|
- **NVIDIA:** no. The driver doesn't expose CEC on the HDMI port, on Linux
|
||||||
|
or Windows.
|
||||||
|
- **AMD and Intel:** the CEC line of the HDMI port is normally not
|
||||||
|
connected on desktop cards. The Linux drivers (`amdgpu`, `i915`) only
|
||||||
|
support CEC over a **DisplayPort** connection: some DisplayPort-to-HDMI
|
||||||
|
adapters and built-in converter chips pass CEC along ("DP-AUX CEC"). That
|
||||||
|
depends on the adapter or chip, not on the graphics card, so it's worth
|
||||||
|
trying a different adapter.
|
||||||
|
|
||||||
|
## Devices with CEC built in
|
||||||
|
|
||||||
|
- the **Valve Steam Machine** (Steamify ticks HDMI-CEC by default there);
|
||||||
|
- some **Intel NUC** mini PCs, which have a CEC chip on the board;
|
||||||
|
- the **Raspberry Pi**.
|
||||||
|
|
||||||
|
## Any PC: a USB CEC adapter
|
||||||
|
|
||||||
|
A USB CEC adapter, such as the **Pulse-Eight USB-CEC adapter** (or a
|
||||||
|
RainShadow Tech one), sits between the PC and the TV on the HDMI cable and
|
||||||
|
works on Linux. This is the way to get CEC on a custom build, e.g. with an
|
||||||
|
NVIDIA card. Steamify installs what these adapters need
|
||||||
|
(`inputattach-cec-units`), so plug it in and turn on HDMI-CEC.
|
||||||
|
|
||||||
|
## Check your PC
|
||||||
|
|
||||||
|
After turning on HDMI-CEC in Steamify, the menu lists the CEC devices it
|
||||||
|
found. Or run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /dev/cec*
|
||||||
|
```
|
||||||
|
|
||||||
|
No device (and no USB adapter): no CEC on this PC. Also turn on CEC on the
|
||||||
|
TV itself: it has a brand name there (Sony: BRAVIA Sync, Samsung: Anynet+,
|
||||||
|
LG: SimpLink, Philips: EasyLink, Panasonic: VIERA Link).
|
||||||
|
|
||||||
|
This overview is based on how the Linux drivers work; hardware differs,
|
||||||
|
so the only sure test is `ls /dev/cec*` on your own PC.
|
||||||
+186
-3
@@ -2,10 +2,193 @@
|
|||||||
|
|
||||||
All notable changes, per version and per commit. Versions follow
|
All notable changes, per version and per commit. Versions follow
|
||||||
[Semantic Versioning](https://semver.org/); the current one is `VERSION` in
|
[Semantic Versioning](https://semver.org/); the current one is `VERSION` in
|
||||||
`setup-gamescope-boot.sh`. Versions before 0.7.0 were numbered afterwards,
|
`steamify.sh`. Versions before 0.7.0 were numbered afterwards,
|
||||||
one per merged pull request.
|
one per merged pull request.
|
||||||
|
|
||||||
## 0.7.0 - 2026-09-24
|
## 1.1.3 - 2026-09-25
|
||||||
|
|
||||||
|
- **fix: HDMI-CEC settings shown in Steam**
|
||||||
|
- CachyOS's gaming mode script sets `STEAM_ENABLE_CEC=0`, which hides
|
||||||
|
Steam's HDMI-CEC settings (and its CEC volume buttons). HDMI-CEC now adds
|
||||||
|
a drop-in for `steam-launcher.service` that overrides it with
|
||||||
|
`STEAM_ENABLE_CEC=1` (`/etc/steamify/steam-cec.env`).
|
||||||
|
- HDMI-CEC set up by 1.1.0-1.1.2 shows as off and ticked, so a normal run
|
||||||
|
(Enter) adds this.
|
||||||
|
|
||||||
|
## 1.1.2 - 2026-09-25
|
||||||
|
|
||||||
|
- **fix: Steam's HDMI-CEC settings reach cecd on a first run**
|
||||||
|
- HDMI-CEC runs before Steam Machine support, which installs
|
||||||
|
steamos-manager; so steamos-manager's `configure-cecd` unit couldn't be
|
||||||
|
enabled and cecd ran without Steam's settings. Steam Machine support now
|
||||||
|
links them once steamos-manager is there.
|
||||||
|
|
||||||
|
## 1.1.1 - 2026-09-25
|
||||||
|
|
||||||
|
- **perf: Pinned kernel before the LED driver**
|
||||||
|
- With the kernel pin ticked, Steam Machine support installs kernel
|
||||||
|
7.1.6-1 first, so DKMS builds the LED driver once, for that kernel,
|
||||||
|
instead of for the current kernel first and then again. The LED driver
|
||||||
|
then loads after the restart, which it now says instead of warning.
|
||||||
|
- **fix: steamos-manager starts after cecd**
|
||||||
|
- It checks only at its start whether cecd runs; if it was first, Steam's
|
||||||
|
HDMI-CEC settings were missing until it restarted. A drop-in
|
||||||
|
(`/etc/systemd/user/steamos-manager.service.d/`) orders it after cecd.
|
||||||
|
|
||||||
|
## 1.1.0 - 2026-09-25
|
||||||
|
|
||||||
|
- **feat: HDMI-CEC** (experimental, on every PC; ticked by default only on a
|
||||||
|
Steam Machine)
|
||||||
|
- Valve's `cecd`, `cec-audio-control` and `inputattach-cec-units` from its
|
||||||
|
SteamOS repository (SHA-256 checked): use Steam with the TV remote, and
|
||||||
|
the TV turns on and off with the PC. On a Steam Machine, steamos-manager
|
||||||
|
configures it from Steam's settings.
|
||||||
|
- Works with any `/dev/cec*` (GPU or USB adapter); the menu lists them.
|
||||||
|
- `CEC.md`: which PCs have CEC (NVIDIA doesn't, AMD/Intel only over some
|
||||||
|
DisplayPort adapters), and USB adapters for your own build.
|
||||||
|
- Restarts steamos-manager, which only offers Steam its HDMI-CEC settings
|
||||||
|
when cecd was there at its start.
|
||||||
|
- The README no longer says Steam Machine support alone gives HDMI-CEC:
|
||||||
|
`cecd` wasn't installed, so it didn't.
|
||||||
|
|
||||||
|
## 1.0.0 - 2026-09-25
|
||||||
|
|
||||||
|
- **feat: Pin the kernel to 7.1.6-1 on a Steam Machine**
|
||||||
|
- New sub-option under Steam Machine support, ticked along with it (opt
|
||||||
|
out): newer CachyOS kernels make the Steam Machine reboot instead of
|
||||||
|
shutting down. Installs `linux-cachyos` and `-headers` 7.1.6-1 and adds
|
||||||
|
them to `IgnorePkg`; unticking removes the pin and updates the system.
|
||||||
|
- The packages are kept in `/var/cache/steamify/kernel` and reinstalled
|
||||||
|
from there without downloading; else from pacman's cache, the CachyOS
|
||||||
|
archive, the CachyOS mirror, or `PINNED_KERNEL_URL`.
|
||||||
|
- First download source: the `kernel-7.1.6-1` release of this repo, a
|
||||||
|
one-off release that always has these files.
|
||||||
|
- Every file is checked against its SHA-256 (in the script) and its
|
||||||
|
CachyOS signature before it's installed; a bad file is deleted.
|
||||||
|
- Installed kernel headers are no longer updated by the wizard, so the
|
||||||
|
pinned kernel keeps matching headers.
|
||||||
|
- The BIOS item moves down one (9 on a Steam Machine).
|
||||||
|
- **docs: Shorter README, with a Steam Machine section**
|
||||||
|
- How it works moved to `TECHNICAL.md`, problems to `TROUBLESHOOTING.md`;
|
||||||
|
the README links to them and to the files it mentions.
|
||||||
|
- **feat: No more KDE wallet password prompts in single user mode**
|
||||||
|
- Uses Valve's empty, password-less wallet, like SteamOS; apps such as
|
||||||
|
Brave no longer ask for the wallet password after autologin.
|
||||||
|
- Your own wallet is moved to `kdewallet.kwl.bak-steamify` and comes back,
|
||||||
|
unchanged, when single user mode is off; the single user wallet is kept
|
||||||
|
and reused next time.
|
||||||
|
- Moved from the SteamOS theme, where it only helped without any wallet.
|
||||||
|
- **fix: No second sudo password prompt while installing yay**
|
||||||
|
- `makepkg -si` installs with `sudo -k`, which forgets the cached password;
|
||||||
|
yay is now built with makepkg and installed with `sudo pacman -U`.
|
||||||
|
- **docs: LICENSE.md** with the MIT license the README already named.
|
||||||
|
- **chore: No more `setup-gamescope-boot.sh` release asset**
|
||||||
|
- Only `steamify.sh` is published; the old name from before 0.9.0 is gone.
|
||||||
|
|
||||||
|
## 0.10.0 - 2026-09-24
|
||||||
|
|
||||||
|
- `0f503dd` **feat: Boot into gamescope or the desktop**
|
||||||
|
- New menu row under the conversion, "Boot into: [gamescope] / desktop";
|
||||||
|
gamescope stays the default and is never changed on a first run.
|
||||||
|
- Desktop: `steamify-boot-desktop.service` sets the autologin session to
|
||||||
|
Plasma at every boot, before the login manager starts; Return to Gaming
|
||||||
|
Mode and Steam's Switch to Desktop keep working. Back to gamescope removes
|
||||||
|
it. Choosing desktop turns the conversion on; turning the conversion off
|
||||||
|
resets it to gamescope.
|
||||||
|
- The later menu items move down one (BIOS is now 8 on a Steam Machine).
|
||||||
|
- `4895de3` **feat: "Boot into" is a sub-option of the conversion**
|
||||||
|
- Shown indented under the SteamOS conversion, and only while it's ticked.
|
||||||
|
- `bd90e29` **feat: Left/Right arrows choose on the "Boot into" row**
|
||||||
|
- Left = gamescope, right = desktop (Space still switches); the row says
|
||||||
|
"←/→ choose" and the key help lists Left/Right.
|
||||||
|
- **fix: Messages say which way it boots**
|
||||||
|
- "This will: boot into: gamescope (from the next boot)" instead of "turn
|
||||||
|
off: Boot into the desktop instead of gaming mode", and the same in the
|
||||||
|
progress line and the "Done" overview.
|
||||||
|
|
||||||
|
## 0.9.1 - 2026-09-24 (#10)
|
||||||
|
|
||||||
|
- `2e107e5` **fix: LED driver for every kernel on a fresh install**
|
||||||
|
- The DKMS override was written to `/etc/dkms` before `dkms` was installed,
|
||||||
|
when that folder doesn't exist yet, so it silently failed and the build
|
||||||
|
for other kernels (e.g. LTS) failed as in 0.6. The folder is created first
|
||||||
|
now, and a failed write stops with an error.
|
||||||
|
- `5ab83d6` **feat: Restart question on quit is "Restart now? [Y/n]"**
|
||||||
|
- When something needs a restart, `q` asks with yes as the default; `n` goes
|
||||||
|
back to the menu and the next `q` asks again. Ctrl+C quits without
|
||||||
|
restarting; scripted input that runs out never restarts.
|
||||||
|
|
||||||
|
## 0.9.0 - 2026-09-24 (#9)
|
||||||
|
|
||||||
|
The wizard is now called **Steamify CachyOS**, and can put a shortcut to
|
||||||
|
itself on the desktop.
|
||||||
|
|
||||||
|
- `f01aa93` **feat: Wizard shortcut on the desktop and in the launcher**
|
||||||
|
- New menu item: a desktop icon and app launcher entry
|
||||||
|
that open the newest release of the wizard in Konsole (`curl | bash`).
|
||||||
|
- Its icon: Valve's Return to Gaming Mode icon with a gear instead of the
|
||||||
|
arrow (`assets/steam-gaming-settings.svg`), published with every release
|
||||||
|
and downloaded from there.
|
||||||
|
- Desktop files are written already executable, so Plasma runs them instead
|
||||||
|
of opening them in an editor.
|
||||||
|
- `be874b8` **feat: Rename to Steamify CachyOS**
|
||||||
|
- Menu header, the shortcut ("Steamify CachyOS", menu item "Steamify
|
||||||
|
shortcut"), release titles, README and AGENTS.md.
|
||||||
|
- `1c34a97` **chore: Repository renamed to steamify-cachyos**
|
||||||
|
- All URLs point to `github.com/theupriser/steamify-cachyos` (the old ones
|
||||||
|
redirect). The script keeps its name, `setup-gamescope-boot.sh`, so the
|
||||||
|
old download URL keeps working; internal names such as
|
||||||
|
`~/.local/state/cachyos-gamescope-boot` stay, so existing installs can
|
||||||
|
still be turned off.
|
||||||
|
- `69a420b` **feat: The script is now steamify.sh**
|
||||||
|
- `setup-gamescope-boot.sh` is renamed to `steamify.sh`; releases publish the
|
||||||
|
bundle under both names, so `.../download/setup-gamescope-boot.sh` keeps
|
||||||
|
working. The Steamify shortcut runs `steamify.sh`.
|
||||||
|
- `b0553ae` **docs: Shorter README intro**
|
||||||
|
- `afc05b0` **feat: The shortcut's window closes itself after a countdown**
|
||||||
|
- After the wizard ends, a 10-second countdown closes the Konsole window
|
||||||
|
(Enter closes it right away); after an error it stays open until Enter.
|
||||||
|
- A failed download now counts as an error (`pipefail`) instead of running
|
||||||
|
an empty script.
|
||||||
|
|
||||||
|
## 0.8.0 - 2026-09-24 (#8)
|
||||||
|
|
||||||
|
An opt-in BIOS update for the Steam Machine, and a menu that comes back after
|
||||||
|
every run.
|
||||||
|
|
||||||
|
- `2f9b2a5` **feat: Opt-in BIOS update for the Steam Machine**
|
||||||
|
- New menu item (Steam Machine only, never ticked by default) showing the
|
||||||
|
current BIOS version and the newest from Valve's `fremont-hw-support`.
|
||||||
|
- Two large warnings and two confirmations (y/N, then typing `UPDATE`),
|
||||||
|
checksum-verified download, installed with fwupd; the wizard then offers
|
||||||
|
the restart that writes it, with a warning to keep the power on.
|
||||||
|
- `40c9ee6` **fix: BIOS update only when newer, device check first, aligned warnings**
|
||||||
|
- The item is greyed out and can't be ticked unless Valve has a newer BIOS.
|
||||||
|
- Before any warning: SHA-256 of Valve's package, then fwupd confirms the
|
||||||
|
firmware fits this machine's hardware; otherwise it stops.
|
||||||
|
- Warning box drawn with a solid red frame whose edges line up, and the
|
||||||
|
menu's "Now" column aligned.
|
||||||
|
- `b70c9d6` **fix: shellcheck in the bundle, and the docs for the BIOS checks**
|
||||||
|
- A variable name in `lib/bios.sh` clashed with `lib/state.sh` in the bundle
|
||||||
|
(CI's shellcheck would fail); README, AGENTS.md and this changelog updated.
|
||||||
|
- `54fc9e3` **feat: Menu comes back after each run, BIOS dry run, version 0.8.0**
|
||||||
|
- After a run the menu returns with the new state; quit with `q`. When
|
||||||
|
something needs a restart, choose between back to the menu (`m`) and
|
||||||
|
restart now (`r`); quitting asks once more.
|
||||||
|
- A staged BIOS update greys the item out until the restart.
|
||||||
|
- `WIZARD_BIOS_DRY_RUN=1` walks through the whole BIOS update (download,
|
||||||
|
checksum, both warnings) but only prints the install and never flashes.
|
||||||
|
- README: the menu loop and the BIOS update step by step.
|
||||||
|
- `45a8757` **fix: BIOS dry run also walks through the restart choices**
|
||||||
|
- A dry run counts as staged, so `[m]`/`[r]` and the restart question on `q`
|
||||||
|
show up; in dry-run mode restarting only prints what it would do.
|
||||||
|
- `429e840` **fix: Shorter BIOS labels so the menu fits 80 columns**
|
||||||
|
- "now F7F0107, newest F7F0108 (own risk)", "F7F0108 waits for a restart",
|
||||||
|
"F7F0107 is up to date"; shorter dry-run line.
|
||||||
|
- `99a95ab` **fix: Kernel legend only mentions the LEDs on a Steam Machine**
|
||||||
|
- `c0014ee` **docs: Last commit hash in the changelog; 0.7.0 was released on its own (#6, #7)**
|
||||||
|
|
||||||
|
## 0.7.0 - 2026-09-24 (#6, #7)
|
||||||
|
|
||||||
The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with
|
The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with
|
||||||
Vapor's own desktop layout, and gains the SteamOS desktop extras. The Steam
|
Vapor's own desktop layout, and gains the SteamOS desktop extras. The Steam
|
||||||
@@ -52,7 +235,7 @@ Machine LED driver works on every installed kernel and survives kernel updates.
|
|||||||
- Install with `.../releases/latest/download/setup-gamescope-boot.sh`, which
|
- Install with `.../releases/latest/download/setup-gamescope-boot.sh`, which
|
||||||
always points to the newest release.
|
always points to the newest release.
|
||||||
- `1604ed1` **docs: Versioning and release rules in AGENTS.md**
|
- `1604ed1` **docs: Versioning and release rules in AGENTS.md**
|
||||||
- **ci: The latest tag follows the newest version tag**
|
- `6afef78` **ci: The latest tag follows the newest version tag**
|
||||||
- When a new version is released, the `latest` tag and release move to it
|
- When a new version is released, the `latest` tag and release move to it
|
||||||
(bundle replaced), so the older `.../releases/download/latest/...` URL
|
(bundle replaced), so the older `.../releases/download/latest/...` URL
|
||||||
also always gives the newest version.
|
also always gives the newest version.
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Rick Peters
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
The kernel packages in the `kernel-7.1.6-1` release are unmodified CachyOS
|
||||||
|
packages under their own license (GPL-2.0); see that release for the source.
|
||||||
@@ -1,32 +1,58 @@
|
|||||||
# CachyOS Gamescope Boot Wizard
|
# Steamify CachyOS
|
||||||
|
|
||||||
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
|
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
|
||||||
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
|
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
|
||||||
desktop and back whenever you like - just like on a Steam Deck or Valve's
|
desktop and back whenever you like - just like on a Steam Deck or Valve's
|
||||||
Steam Machine.
|
Steam Machine.
|
||||||
|
|
||||||
Out of the box, CachyOS doesn't quite manage this: the switch to the desktop
|
- **One command**, then a simple checklist: pick what you want.
|
||||||
can hang, and the PC doesn't reliably boot back into gaming mode. This
|
- **Everything is undoable**: untick something and it's put back the way it was.
|
||||||
script fixes that and sets everything up for you.
|
- **Made for the Steam Machine**, and works on any CachyOS KDE desktop PC.
|
||||||
|
|
||||||
## What you get
|
## What you get
|
||||||
|
|
||||||
The wizard is a menu: pick what you want, and it turns each part on or off.
|
1. **SteamOS conversion** - boots straight into gaming mode. **Switch to
|
||||||
Everything you turn off is put back the way it was.
|
Desktop** in Steam works, and so does going back (the **Return to Gaming
|
||||||
|
Mode** icon on the desktop). Steam's on-screen keyboard (Steam + X) works
|
||||||
1. **SteamOS conversion** - boots straight into gaming mode, **Switch to
|
on the desktop too.
|
||||||
Desktop** in Steam works and so does going back (the **Return to Gaming
|
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
||||||
Mode** icon on the desktop), you're back in gaming mode after a restart,
|
the default.
|
||||||
and Steam's on-screen keyboard (Steam + X) also works on the desktop.
|
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
||||||
2. **SteamOS theme** - the Vapor look for the desktop (CachyOS's
|
**Add to Steam** in right-click menus
|
||||||
`cachyos-vapor` package).
|
([details](TECHNICAL.md#steamos-desktop-look)).
|
||||||
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode.
|
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
|
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
||||||
user switching or logging out. Typing a password with a controller is no
|
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
||||||
fun. (Needs 1.)
|
controller is no fun
|
||||||
5. **Steam Machine support** - only shown on a Valve Steam Machine: the
|
([details](TECHNICAL.md#single-user-mode-sddm-no-locking)).
|
||||||
driver for the front LED bar, and the hardware settings in Steam (fan,
|
5. **Steamify shortcut** - an icon on the desktop and in the launcher that
|
||||||
TV control over HDMI-CEC).
|
opens the newest Steamify, so you don't need the install command again.
|
||||||
|
6. **HDMI-CEC** (experimental; off by default, on by default on a Steam
|
||||||
|
Machine) - use Steam with your TV's
|
||||||
|
remote, and the TV turns on and off with the PC. Needs a PC with CEC (like
|
||||||
|
the Steam Machine) or a USB CEC adapter; most graphics cards, NVIDIA
|
||||||
|
included, don't have it. See [CEC.md](CEC.md) for which PCs do, and how to
|
||||||
|
add it to your own build ([details](TECHNICAL.md#hdmi-cec)).
|
||||||
|
|
||||||
|
## Steam Machine
|
||||||
|
|
||||||
|
What Steamify can do on a Valve Steam Machine:
|
||||||
|
|
||||||
|
- **HDMI-CEC** - ticked by default here, as on SteamOS: use Steam with your
|
||||||
|
TV's remote, and the TV turns on and off with the Steam Machine
|
||||||
|
([details](TECHNICAL.md#hdmi-cec)).
|
||||||
|
- **Steam Machine support** - the front **LED bar** works, Steam's
|
||||||
|
**hardware settings** (fan, performance) work, and the power
|
||||||
|
button puts it to sleep like a console.
|
||||||
|
- **Pin the kernel to 7.1.6-1** - on by default: with newer CachyOS kernels
|
||||||
|
the Steam Machine reboots instead of shutting down. Untick it once CachyOS
|
||||||
|
fixes that. The kernel comes from its own
|
||||||
|
[release](https://github.com/theupriser/steamify-cachyos/releases/tag/kernel-7.1.6-1),
|
||||||
|
checked against CachyOS's signature
|
||||||
|
([details](TECHNICAL.md#kernel-pin-steam-machine)).
|
||||||
|
- **Update BIOS** - installs Valve's newest Steam Machine BIOS. Never ticked
|
||||||
|
by default, at your own risk, and only after two warnings
|
||||||
|
([details](TECHNICAL.md#bios-updates-steam-machine)).
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -38,324 +64,63 @@ Everything you turn off is put back the way it was.
|
|||||||
Open **Konsole** on your Plasma desktop and run:
|
Open **Konsole** on your Plasma desktop and run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://github.com/theupriser/cachyos-gamescope-boot/releases/latest/download/setup-gamescope-boot.sh | bash
|
curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
That downloads and runs the latest single-file version, and works in any
|
Prefer to look at the script first? Clone the repository and run
|
||||||
shell, including fish (CachyOS's default). Prefer to keep a copy, or to look
|
[`./steamify.sh`](steamify.sh) (keep the whole folder: it needs
|
||||||
at the script first? Clone the repository instead:
|
[`lib/`](lib/)).
|
||||||
|
|
||||||
```bash
|
You'll see a checklist:
|
||||||
git clone https://github.com/theupriser/cachyos-gamescope-boot.git
|
|
||||||
cd cachyos-gamescope-boot
|
|
||||||
./setup-gamescope-boot.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Run it as yourself, not as root. You'll see a checklist:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
[x] SteamOS conversion: boot into gaming mode, Steam on the desktop (now: off)
|
[x] SteamOS conversion: boot into gaming mode, Steam on the desktop (now: off)
|
||||||
|
└ Boot into: [gamescope] desktop
|
||||||
> [x] Install SteamOS theme: Vapor look (cachyos-vapor) (now: off)
|
> [x] Install SteamOS theme: Vapor look (cachyos-vapor) (now: off)
|
||||||
[x] Install Steam Deck/Machine icons: Deck button icons in gaming mode (now: off)
|
[x] Install Steam Deck/Machine icons: Deck button icons in gaming mode (now: off)
|
||||||
[x] Single user mode: no password, lock screen or log out (SDDM) (now: off)
|
[x] Single user mode: no password, lock screen or log out (SDDM) (now: off)
|
||||||
|
[x] Steamify shortcut: desktop icon to run this again (now: off)
|
||||||
|
|
||||||
Kernels (> = running; controller = Steam controller driver, LEDs = LED bar driver built)
|
Up/Down move Space select Left/Right choose Enter run
|
||||||
6.18.52-1-cachyos-lts linux-cachyos-lts headers yes controller yes
|
a run + re-apply what's on q quit
|
||||||
> 7.2.7-1-cachyos linux-cachyos headers yes controller yes
|
|
||||||
|
|
||||||
Up/Down move Space select Enter run a run + re-apply what's on q quit
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Move with the **arrow keys**, tick or untick with **Space**, and press
|
Tick with **Space**, run with **Enter**. It shows what it will change, asks
|
||||||
**Enter** to run. "now:" shows what's on at the moment. Below the list, every
|
your password once, and offers to restart at the end. Below the list you see
|
||||||
installed kernel is shown with its headers and Steam controller driver; on a
|
every installed kernel, so after an update it's easy to check that
|
||||||
Steam Machine also whether the LED bar driver is built for it, and whether
|
everything is in place.
|
||||||
it's loaded right now, so a kernel update is easy to check. The wizard then
|
|
||||||
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
|
Run it again whenever you like: to change your choices, or after a CachyOS
|
||||||
again, or after a CachyOS update (press `a` in the menu to re-apply
|
update (press `a` to re-apply what's on).
|
||||||
everything that's on).
|
|
||||||
|
|
||||||
If you cloned the repository, keep the whole folder: the script needs the
|
|
||||||
files in `lib/` next to it.
|
|
||||||
|
|
||||||
## 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're not using single user mode).
|
desktop.
|
||||||
- After a restart you always start in gaming mode.
|
- **Remove it all:** run the wizard and untick everything. You get the
|
||||||
|
normal CachyOS login screen back; Steam stays installed.
|
||||||
|
|
||||||
Prefer to decide yourself where your PC starts? Run one of these in Konsole:
|
Prefer to start where you left off last time?
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
steamos-session-select persistent # start where you left off last time
|
steamos-session-select persistent # start where you left off last time
|
||||||
steamos-session-select oneshot # always start in gaming mode (default)
|
steamos-session-select oneshot # always start in gaming mode (default)
|
||||||
```
|
```
|
||||||
|
|
||||||
## If something goes wrong
|
## Something wrong?
|
||||||
|
|
||||||
**Gaming mode shows a black screen or keeps restarting.** Press
|
Stuck on a black screen in gaming mode: press **Ctrl+Alt+F3**, log in, and run
|
||||||
**Ctrl+Alt+F3**, log in with your username and password, and run:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo /usr/lib/steamos/steam-set-session plasma.desktop && sudo systemctl restart display-manager
|
sudo /usr/lib/steamos/steam-set-session plasma.desktop && sudo systemctl restart display-manager
|
||||||
```
|
```
|
||||||
|
|
||||||
That takes you back to the desktop.
|
More in [TROUBLESHOOTING.md](TROUBLESHOOTING.md). How it all works:
|
||||||
|
[TECHNICAL.md](TECHNICAL.md). Changes per version: [CHANGELOG.md](CHANGELOG.md).
|
||||||
**The LED bar on the Steam Machine stays dark.** Restart the PC once more; a
|
Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md).
|
||||||
freshly installed driver often needs a reboot. Still dark? See
|
|
||||||
[Front LED bar](#front-led-bar-steam-machine) under technical details.
|
|
||||||
|
|
||||||
**Undo something:** run the wizard again and untick it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Technical details
|
|
||||||
|
|
||||||
### How turning things on and off works
|
|
||||||
|
|
||||||
At startup every component checks whether it is on (`*_status` in `lib/`).
|
|
||||||
You choose; the wizard then turns off what you unticked (in reverse order)
|
|
||||||
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
|
|
||||||
(`kscreenlockerrc`), Meta+L and Ctrl+Alt+Del unbound, and the launcher shows
|
|
||||||
only Sleep / Restart / Shut Down (kickoff `primaryActions=3`), which hides
|
|
||||||
the Session dropdown with Log Out. (Restricting `action/logout` would also
|
|
||||||
hide Restart and Shut Down.) Turning it off restores all of that and moves
|
|
||||||
the conversion back to plasma-login-manager.
|
|
||||||
|
|
||||||
**SDDM** is what SteamOS uses, and CachyOS's `steam-set-session` supports it
|
|
||||||
directly: it writes `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM
|
|
||||||
honours. The script installs and enables `sddm` (active from the next boot),
|
|
||||||
writes `User=`, `Session=` and `Relogin=true` to
|
|
||||||
`/etc/sddm.conf.d/10-gamescope-autologin.conf`, and removes any
|
|
||||||
`[Autologin]` from `/etc/sddm.conf` (read last, so it would override both).
|
|
||||||
No sync bridge or sudoers rule is needed; the shortcut just runs
|
|
||||||
`steamos-session-select gamescope`, which logs out, and `Relogin=true` logs
|
|
||||||
straight back in to gamescope.
|
|
||||||
|
|
||||||
Without single user mode, the conversion uses **plasma-login-manager**
|
|
||||||
(CachyOS's default since March 2026), which needs the workarounds below.
|
|
||||||
|
|
||||||
### Why this is needed (plasma-login-manager)
|
|
||||||
|
|
||||||
CachyOS's `gamescope-session-cachyos` package ships `steamos-session-select`,
|
|
||||||
which is meant to work exactly like it does on real SteamOS. Since the March
|
|
||||||
2026 release, CachyOS uses `plasma-login-manager` instead of SDDM, and three
|
|
||||||
things get in the way:
|
|
||||||
|
|
||||||
1. **No `User=` written to the autologin config.**
|
|
||||||
`steam-set-session` (called by `steamos-session-select`) only writes a
|
|
||||||
`Session=` key. `plasma-login-manager` needs both `Session=` and `User=`
|
|
||||||
to autologin at all; without `User=` it shows the greeter every boot.
|
|
||||||
|
|
||||||
2. **Missing `/etc/plasmalogin.conf.d` directory.**
|
|
||||||
Without it, `steam-set-session` fails, and Steam's "Switch to Desktop"
|
|
||||||
hangs forever. *(Fixed upstream in `gamescope-session-cachyos` 1.1.6; the
|
|
||||||
script still creates the directory for older versions.)*
|
|
||||||
|
|
||||||
3. **The base `/etc/plasmalogin.conf` wins over conf.d, and CachyOS ships it
|
|
||||||
with `Session=plasma`.**
|
|
||||||
Every tool that changes sessions (`steamos-session-select`, Steam's power
|
|
||||||
menu, and `cachyos-gamescope-autologin.service`, which resets you to
|
|
||||||
gamescope after a desktop session) only writes
|
|
||||||
`/etc/plasmalogin.conf.d/zz-steamos-autologin.conf`. The base file takes
|
|
||||||
priority, so none of those switches stick.
|
|
||||||
|
|
||||||
The script sets `Session=`, `User=` and `Relogin=true` in the base config,
|
|
||||||
and installs a small systemd path watcher that copies whatever CachyOS's
|
|
||||||
tools write to the conf.d fragment into the base config.
|
|
||||||
|
|
||||||
### What each component changes
|
|
||||||
|
|
||||||
**SteamOS conversion** (`lib/login-manager.sh`, `lib/steam-desktop.sh`,
|
|
||||||
`lib/desktop-shortcut.sh`):
|
|
||||||
|
|
||||||
- installs missing packages: `gamescope-session-cachyos`, `steam`,
|
|
||||||
`mangohud`, `xterm`, `ttf-liberation`, `wqy-zenhei`, `plasma-keyboard`;
|
|
||||||
- *SDDM (single user mode):* installs/enables SDDM and writes its autologin
|
|
||||||
config;
|
|
||||||
- *plasma-login-manager:* creates `/etc/plasmalogin.conf.d`, backs up and
|
|
||||||
rewrites the `[Autologin]` section of `/etc/plasmalogin.conf`, removes
|
|
||||||
stray `zzz-steamos-autologin*.conf` files from manual troubleshooting
|
|
||||||
(never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
|
|
||||||
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
|
||||||
`sync-steamos-session.path`/`.service`;
|
|
||||||
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a
|
|
||||||
`steam-desktop-autostart` systemd user service that starts Steam silently
|
|
||||||
in Plasma only;
|
|
||||||
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
|
||||||
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
|
||||||
restart the login manager without a password prompt.
|
|
||||||
|
|
||||||
Turning it off restores `/etc/plasmalogin.conf` from its backup, removes the
|
|
||||||
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
|
|
||||||
|
|
||||||
Installs CachyOS's `cachyos-vapor` package (the SteamOS Vapor theme the
|
|
||||||
CachyOS handheld edition uses) from the CachyOS repository and switches your
|
|
||||||
desktop to its Vapor global theme, including its desktop and window layout
|
|
||||||
(like ticking "Desktop and window layout" in System Settings): Vapor colors
|
|
||||||
and Plasma style, the SteamOS panel and launcher icon, and the Steam Deck
|
|
||||||
wallpaper. Run it from the Plasma desktop: applying the layout needs a
|
|
||||||
running Plasma session.
|
|
||||||
|
|
||||||
It also adds the SteamOS desktop extras that `cachyos-vapor` doesn't ship,
|
|
||||||
taken from the newest `steamdeck-kde-presets` on Valve's SteamOS mirror
|
|
||||||
(checksum verified) and installed to `/usr/local`:
|
|
||||||
|
|
||||||
- **Add to Steam** in the right-click menu of apps, AppImages and `.exe`
|
|
||||||
files, and in the launcher: adds them to Steam as non-Steam games;
|
|
||||||
- **Nested Desktop**: add it to Steam from the launcher, then start it in
|
|
||||||
gaming mode for a Plasma desktop inside gaming mode;
|
|
||||||
- the SteamOS **Return to Gaming Mode** icon (Steam logo with a return arrow);
|
|
||||||
- a window rule that keeps the **Steam keyboard** above other windows;
|
|
||||||
- an empty, password-less **KWallet**, only if you don't have a wallet yet,
|
|
||||||
so nothing asks for a wallet password after autologin.
|
|
||||||
|
|
||||||
Turning it off restores your previous look and panel layout, and removes `cachyos-vapor` again
|
|
||||||
if the wizard installed it (and nothing else, like `cachyos-handheld`, needs it).
|
|
||||||
|
|
||||||
### Front LED bar (Steam Machine)
|
|
||||||
|
|
||||||
The **Steam Machine support** component, only shown on Fremont hardware
|
|
||||||
(DMI `Valve`/`Fremont`, or `OEM`/`F7F` on early units):
|
|
||||||
|
|
||||||
- installs an AUR helper (`yay`) if neither `yay` nor `paru` is present;
|
|
||||||
- installs the kernel headers for every installed kernel;
|
|
||||||
- installs `leds-valve-dkms-git` from the AUR - Valve's own driver from the
|
|
||||||
SteamOS kernel - builds it for every installed kernel (so the LTS kernel
|
|
||||||
works too), and loads it at every 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;
|
|
||||||
- console-like power button: it puts the machine to sleep, and it never
|
|
||||||
suspends by itself on mains power (the launcher's Shut Down still shuts down);
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
Turning it off removes all of that again (the AUR helper is kept).
|
|
||||||
|
|
||||||
The LEDs appear as `/sys/class/leds/valve-leds*`. The driver's Makefile
|
|
||||||
builds against the running kernel (`uname -r`) instead of the kernel DKMS
|
|
||||||
builds for, so the wizard adds a DKMS override
|
|
||||||
(`/etc/dkms/leds-valve-dkms.conf`) that passes DKMS's target kernel in. With
|
|
||||||
it, DKMS rebuilds the driver whenever a kernel or its headers are installed
|
|
||||||
or upgraded. A newly added kernel doesn't come with its headers, so
|
|
||||||
`ensure-kernel-headers.service` checks at every boot and installs any
|
|
||||||
missing `-headers` package, which makes DKMS build the driver for it.
|
|
||||||
|
|
||||||
Troubleshooting:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
dkms status
|
|
||||||
ls -l /sys/class/leds/valve-leds*/
|
|
||||||
sudo dmesg | grep -i valve
|
|
||||||
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
|
|
||||||
|
|
||||||
```bash
|
|
||||||
steamos-session-select gamescope # switch to gamescope right now
|
|
||||||
steamos-session-select plasma # switch to desktop right now
|
|
||||||
steamos-session-select persistent # remember the last-used session across reboots
|
|
||||||
steamos-session-select oneshot # always start in gamescope (default, like a Deck)
|
|
||||||
```
|
|
||||||
|
|
||||||
With `Relogin=true`, a gamescope session that fails to start is restarted
|
|
||||||
immediately, which can turn into a loop - hence the Ctrl+Alt+F3 escape above.
|
|
||||||
|
|
||||||
### Removing everything
|
|
||||||
|
|
||||||
Run the wizard and untick everything. Afterwards the PC boots to the normal
|
|
||||||
CachyOS login screen again; packages installed for the conversion (Steam,
|
|
||||||
gamescope-session, ...) stay installed.
|
|
||||||
|
|
||||||
### Project layout
|
|
||||||
|
|
||||||
| File | Responsibility |
|
|
||||||
|---|---|
|
|
||||||
| `setup-gamescope-boot.sh` | Entry point: checks, menu, apply, summary, restart |
|
|
||||||
| `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/login-manager.sh` | SteamOS conversion: SDDM or plasmalogin autologin, sync bridge |
|
|
||||||
| `lib/steam-desktop.sh` | Steam in the Plasma session; Steam Deck/Machine icons |
|
|
||||||
| `lib/desktop-shortcut.sh` | Return to Gaming Mode shortcut and its sudoers rule |
|
|
||||||
| `lib/vapor-theme.sh` | SteamOS theme: installs and switches to `cachyos-vapor` |
|
|
||||||
| `lib/steamos-extras.sh` | SteamOS desktop extras from Valve's package (Add to Steam, Nested Desktop, icon, keyboard rule, KWallet) |
|
|
||||||
| `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 |
|
|
||||||
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/setup-gamescope-boot.sh`) |
|
|
||||||
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
|
|
||||||
|
|
||||||
The single-file version is generated: on every push to `main`, GitHub
|
|
||||||
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
|
|
||||||
shellcheck, and publishes it as a release per version (tag `v<VERSION>`,
|
|
||||||
never overwritten; the newest is marked latest, and the `latest` tag follows
|
|
||||||
it). It inlines
|
|
||||||
`lib/*.sh` and wraps the entry point in `main()`, so bash has read the whole
|
|
||||||
file before anything runs; when stdin is a pipe (`curl | bash`) it reattaches
|
|
||||||
the terminal for the menu (set `WIZARD_KEEP_STDIN=1` to keep piped input).
|
|
||||||
|
|
||||||
Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md).
|
|
||||||
|
|
||||||
### Caveats
|
|
||||||
|
|
||||||
- This works around CachyOS/`plasma-login-manager` behavior as of September
|
|
||||||
2026. If CachyOS fixes `steam-set-session` upstream, parts of this script
|
|
||||||
become unnecessary - please open an issue or PR if you notice that.
|
|
||||||
- Tested on a Valve Steam Machine running CachyOS Desktop edition. It should
|
|
||||||
work on any CachyOS desktop install using `plasma-login-manager`, but
|
|
||||||
hasn't been tested on Steam Deck/Legion Go hardware.
|
|
||||||
|
|
||||||
### Related upstream reports
|
|
||||||
|
|
||||||
- [CachyOS/gamescope-session#9](https://github.com/CachyOS/gamescope-session/issues/9) - "Switch to Desktop" hang due to missing `/etc/plasmalogin.conf.d`
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT - do whatever you want with it.
|
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
||||||
+326
@@ -0,0 +1,326 @@
|
|||||||
|
# Technical details
|
||||||
|
|
||||||
|
How Steamify CachyOS works under the hood. For using it, see
|
||||||
|
[README.md](README.md); for problems, [TROUBLESHOOTING.md](TROUBLESHOOTING.md).
|
||||||
|
|
||||||
|
## How turning things on and off works
|
||||||
|
|
||||||
|
At startup every component checks whether it is on (`*_status` in `lib/`).
|
||||||
|
You choose; the wizard then turns off what you unticked (in reverse order)
|
||||||
|
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
|
||||||
|
(`kscreenlockerrc`), Meta+L and Ctrl+Alt+Del unbound, and the launcher shows
|
||||||
|
only Sleep / Restart / Shut Down (kickoff `primaryActions=3`), which hides
|
||||||
|
the Session dropdown with Log Out. (Restricting `action/logout` would also
|
||||||
|
hide Restart and Shut Down.) Turning it off restores all of that and moves
|
||||||
|
the conversion back to plasma-login-manager.
|
||||||
|
|
||||||
|
**KDE wallet.** KDE normally unlocks your wallet with the password you log in
|
||||||
|
with; with autologin nobody types it, so apps that keep passwords in it (Brave,
|
||||||
|
for example) ask for the wallet password. Single user mode does what SteamOS
|
||||||
|
does: it uses Valve's empty wallet without a password (from
|
||||||
|
`steamdeck-kde-presets`, checksum verified). Your own wallet in
|
||||||
|
`~/.local/share/kwalletd/` is moved to `kdewallet.kwl.bak-steamify` (and
|
||||||
|
`.salt`). Turning single user mode off puts it back, unchanged; the single
|
||||||
|
user wallet, with anything saved in it meanwhile, is kept as
|
||||||
|
`kdewallet.kwl.steamify-single-user` and used again the next time it's on.
|
||||||
|
Passwords aren't shared between the two wallets.
|
||||||
|
|
||||||
|
**SDDM** is what SteamOS uses, and CachyOS's `steam-set-session` supports it
|
||||||
|
directly: it writes `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM
|
||||||
|
honours. The script installs and enables `sddm` (active from the next boot),
|
||||||
|
writes `User=`, `Session=` and `Relogin=true` to
|
||||||
|
`/etc/sddm.conf.d/10-gamescope-autologin.conf`, and removes any
|
||||||
|
`[Autologin]` from `/etc/sddm.conf` (read last, so it would override both).
|
||||||
|
No sync bridge or sudoers rule is needed; the shortcut just runs
|
||||||
|
`steamos-session-select gamescope`, which logs out, and `Relogin=true` logs
|
||||||
|
straight back in to gamescope.
|
||||||
|
|
||||||
|
Without single user mode, the conversion uses **plasma-login-manager**
|
||||||
|
(CachyOS's default since March 2026), which needs the workarounds below.
|
||||||
|
|
||||||
|
## Why this is needed (plasma-login-manager)
|
||||||
|
|
||||||
|
CachyOS's `gamescope-session-cachyos` package ships `steamos-session-select`,
|
||||||
|
which is meant to work exactly like it does on real SteamOS. Since the March
|
||||||
|
2026 release, CachyOS uses `plasma-login-manager` instead of SDDM, and three
|
||||||
|
things get in the way:
|
||||||
|
|
||||||
|
1. **No `User=` written to the autologin config.**
|
||||||
|
`steam-set-session` (called by `steamos-session-select`) only writes a
|
||||||
|
`Session=` key. `plasma-login-manager` needs both `Session=` and `User=`
|
||||||
|
to autologin at all; without `User=` it shows the greeter every boot.
|
||||||
|
|
||||||
|
2. **Missing `/etc/plasmalogin.conf.d` directory.**
|
||||||
|
Without it, `steam-set-session` fails, and Steam's "Switch to Desktop"
|
||||||
|
hangs forever. *(Fixed upstream in `gamescope-session-cachyos` 1.1.6; the
|
||||||
|
script still creates the directory for older versions.)*
|
||||||
|
|
||||||
|
3. **The base `/etc/plasmalogin.conf` wins over conf.d, and CachyOS ships it
|
||||||
|
with `Session=plasma`.**
|
||||||
|
Every tool that changes sessions (`steamos-session-select`, Steam's power
|
||||||
|
menu, and `cachyos-gamescope-autologin.service`, which resets you to
|
||||||
|
gamescope after a desktop session) only writes
|
||||||
|
`/etc/plasmalogin.conf.d/zz-steamos-autologin.conf`. The base file takes
|
||||||
|
priority, so none of those switches stick.
|
||||||
|
|
||||||
|
The script sets `Session=`, `User=` and `Relogin=true` in the base config,
|
||||||
|
and installs a small systemd path watcher that copies whatever CachyOS's
|
||||||
|
tools write to the conf.d fragment into the base config.
|
||||||
|
|
||||||
|
## What each component changes
|
||||||
|
|
||||||
|
**SteamOS conversion** (`lib/login-manager.sh`, `lib/steam-desktop.sh`,
|
||||||
|
`lib/desktop-shortcut.sh`):
|
||||||
|
|
||||||
|
- installs missing packages: `gamescope-session-cachyos`, `steam`,
|
||||||
|
`mangohud`, `xterm`, `ttf-liberation`, `wqy-zenhei`, `plasma-keyboard`;
|
||||||
|
- *SDDM (single user mode):* installs/enables SDDM and writes its autologin
|
||||||
|
config;
|
||||||
|
- *plasma-login-manager:* creates `/etc/plasmalogin.conf.d`, backs up and
|
||||||
|
rewrites the `[Autologin]` section of `/etc/plasmalogin.conf`, removes
|
||||||
|
stray `zzz-steamos-autologin*.conf` files from manual troubleshooting
|
||||||
|
(never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
|
||||||
|
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
||||||
|
`sync-steamos-session.path`/`.service`;
|
||||||
|
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a
|
||||||
|
`steam-desktop-autostart` systemd user service that starts Steam silently
|
||||||
|
in Plasma only;
|
||||||
|
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
||||||
|
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
||||||
|
restart the login manager without a password prompt.
|
||||||
|
|
||||||
|
Turning it off restores `/etc/plasmalogin.conf` from its backup, removes the
|
||||||
|
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
|
||||||
|
|
||||||
|
Installs CachyOS's `cachyos-vapor` package (the SteamOS Vapor theme the
|
||||||
|
CachyOS handheld edition uses) from the CachyOS repository and switches your
|
||||||
|
desktop to its Vapor global theme, including its desktop and window layout
|
||||||
|
(like ticking "Desktop and window layout" in System Settings): Vapor colors
|
||||||
|
and Plasma style, the SteamOS panel and launcher icon, and the Steam Deck
|
||||||
|
wallpaper. Run it from the Plasma desktop: applying the layout needs a
|
||||||
|
running Plasma session.
|
||||||
|
|
||||||
|
It also adds the SteamOS desktop extras that `cachyos-vapor` doesn't ship,
|
||||||
|
taken from the newest `steamdeck-kde-presets` on Valve's SteamOS mirror
|
||||||
|
(checksum verified) and installed to `/usr/local`:
|
||||||
|
|
||||||
|
- **Add to Steam** in the right-click menu of apps, AppImages and `.exe`
|
||||||
|
files, and in the launcher: adds them to Steam as non-Steam games;
|
||||||
|
- **Nested Desktop**: add it to Steam from the launcher, then start it in
|
||||||
|
gaming mode for a Plasma desktop inside gaming mode;
|
||||||
|
- the SteamOS **Return to Gaming Mode** icon (Steam logo with a return arrow);
|
||||||
|
- a window rule that keeps the **Steam keyboard** above other windows.
|
||||||
|
|
||||||
|
Turning it off restores your previous look and panel layout, and removes `cachyos-vapor` again
|
||||||
|
if the wizard installed it (and nothing else, like `cachyos-handheld`, needs it).
|
||||||
|
|
||||||
|
## Front LED bar (Steam Machine)
|
||||||
|
|
||||||
|
The **Steam Machine support** component, only shown on Fremont hardware
|
||||||
|
(DMI `Valve`/`Fremont`, or `OEM`/`F7F` on early units):
|
||||||
|
|
||||||
|
- installs an AUR helper (`yay`) if neither `yay` nor `paru` is present;
|
||||||
|
- installs the kernel headers for every installed kernel;
|
||||||
|
- installs `leds-valve-dkms-git` from the AUR - Valve's own driver from the
|
||||||
|
SteamOS kernel - builds it for every installed kernel (so the LTS kernel
|
||||||
|
works too), and loads it at every 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;
|
||||||
|
- console-like power button: it puts the machine to sleep, and it never
|
||||||
|
suspends by itself on mains power (the launcher's Shut Down still shuts down);
|
||||||
|
- installs and enables `steamos-manager`, the service Steam in gaming mode
|
||||||
|
uses for hardware settings (fan, performance, and the HDMI-CEC settings
|
||||||
|
when [HDMI-CEC](#hdmi-cec) is on); it recognises the Steam Machine from its
|
||||||
|
DMI data.
|
||||||
|
|
||||||
|
Turning it off removes all of that again (the AUR helper is kept).
|
||||||
|
|
||||||
|
The LEDs appear as `/sys/class/leds/valve-leds*`. The driver's Makefile
|
||||||
|
builds against the running kernel (`uname -r`) instead of the kernel DKMS
|
||||||
|
builds for, so the wizard adds a DKMS override
|
||||||
|
(`/etc/dkms/leds-valve-dkms.conf`) that passes DKMS's target kernel in. With
|
||||||
|
it, DKMS rebuilds the driver whenever a kernel or its headers are installed
|
||||||
|
or upgraded. A newly added kernel doesn't come with its headers, so
|
||||||
|
`ensure-kernel-headers.service` checks at every boot and installs any
|
||||||
|
missing `-headers` package, which makes DKMS build the driver for it.
|
||||||
|
|
||||||
|
## HDMI-CEC
|
||||||
|
|
||||||
|
The **HDMI-CEC** item (on every PC; ticked by default only on a Steam
|
||||||
|
Machine) installs
|
||||||
|
Valve's CEC stack from its SteamOS `holo` repository, the newest `holo-X.Y`
|
||||||
|
on `steamdeck-packages.steamos.cloud`, each package checked against the
|
||||||
|
SHA-256 in Valve's package index:
|
||||||
|
|
||||||
|
- `cecd`, Valve's CEC daemon (a user service started with the desktop and
|
||||||
|
gaming mode): TV remote keys become normal key presses (arrows, Enter,
|
||||||
|
Back), and it turns the TV on and off with the PC;
|
||||||
|
- `cec-audio-control`: volume of the TV or receiver;
|
||||||
|
- `inputattach-cec-units` (with `linuxconsole` from CachyOS for
|
||||||
|
`inputattach`): attaches USB CEC adapters (Pulse-Eight, RainShadow).
|
||||||
|
|
||||||
|
It works with any `/dev/cec*`: a GPU that has CEC on its HDMI port (the
|
||||||
|
Steam Machine; the CachyOS kernel has DisplayPort CEC built in) or a USB
|
||||||
|
adapter ([CEC.md](CEC.md) lists which PCs have one). The menu lists the CEC
|
||||||
|
devices found. Also turn on CEC on the TV
|
||||||
|
(Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink). On a Steam Machine
|
||||||
|
`steamos-manager` writes cecd's settings from Steam's (wake the TV, put it to
|
||||||
|
sleep), in `~/.config/cecd/config.d/`, and Steam shows its HDMI-CEC
|
||||||
|
settings; the wizard restarts steamos-manager so that happens right away.
|
||||||
|
CachyOS's gaming mode script (`/usr/lib/steamos/gamescope-session`) sets
|
||||||
|
`STEAM_ENABLE_CEC=0`, which hides those settings; Steam reads the script's
|
||||||
|
variables from `$XDG_RUNTIME_DIR/gamescope-environment`. HDMI-CEC adds a
|
||||||
|
drop-in for `steam-launcher.service`
|
||||||
|
(`/etc/systemd/user/steam-launcher.service.d/10-steamify-cec.conf`) with a
|
||||||
|
second `EnvironmentFile=` (`/etc/steamify/steam-cec.env`,
|
||||||
|
`STEAM_ENABLE_CEC=1`), which overrides it from the next gaming mode start.
|
||||||
|
|
||||||
|
It's experimental: on SteamOS itself CEC can wake the Steam Machine right
|
||||||
|
after it goes to sleep (Samsung TVs,
|
||||||
|
[SteamOS#2626](https://github.com/ValveSoftware/SteamOS/issues/2626)) and
|
||||||
|
upset CEC for the TV's other devices
|
||||||
|
([SteamOS#2817](https://github.com/ValveSoftware/SteamOS/issues/2817)).
|
||||||
|
Turning it off removes the packages again (`linuxconsole` only if the
|
||||||
|
wizard installed it).
|
||||||
|
|
||||||
|
## Kernel pin (Steam Machine)
|
||||||
|
|
||||||
|
With CachyOS kernels newer than 7.1.6 a Steam Machine reboots instead of
|
||||||
|
shutting down. The **Pin the kernel** sub-option (ticked along with Steam
|
||||||
|
Machine support) installs `linux-cachyos` and `linux-cachyos-headers`
|
||||||
|
7.1.6-1 and adds them to `IgnorePkg` in `/etc/pacman.conf`, so updates skip
|
||||||
|
them. DKMS builds the LED driver for it; restart to boot it.
|
||||||
|
|
||||||
|
The packages (and their signatures, which pacman checks) are kept in
|
||||||
|
`/var/cache/steamify/kernel`, so re-applying needs no download. Missing
|
||||||
|
files are taken from pacman's cache, else downloaded from this repo's
|
||||||
|
`kernel-7.1.6-1` release, then `archive.cachyos.org`, then
|
||||||
|
`mirror.cachyos.org` (which only has the current kernel). Every file must
|
||||||
|
match the SHA-256 in the script and have a valid CachyOS signature; a bad
|
||||||
|
one is deleted, so the next run downloads it again. Set `PINNED_KERNEL_URL`
|
||||||
|
to a directory URL with the files to try another source first, or drop them
|
||||||
|
into the kernel directory yourself.
|
||||||
|
|
||||||
|
Unticking it removes the pin and runs `sudo pacman -Syu`, which brings the
|
||||||
|
kernel back to CachyOS's current version; the files stay for next time.
|
||||||
|
|
||||||
|
## BIOS updates (Steam Machine)
|
||||||
|
|
||||||
|
The **Update BIOS** item is only shown on a Steam Machine and is never ticked
|
||||||
|
by default. It shows the BIOS version you have now and the newest one Valve
|
||||||
|
ships (the `.cab` file in its `fremont-hw-support` package, looked up on
|
||||||
|
Valve's SteamOS mirror):
|
||||||
|
|
||||||
|
```
|
||||||
|
[ ] Update BIOS: now F7F0107, newest F7F0108 (own risk) (opt-in, runs once)
|
||||||
|
```
|
||||||
|
|
||||||
|
It can only be ticked when Valve has a newer BIOS than yours; when you're up
|
||||||
|
to date, when the newest version can't be looked up (offline), or when an
|
||||||
|
update is already waiting for a restart, it's greyed out.
|
||||||
|
|
||||||
|
When you run it, the wizard:
|
||||||
|
|
||||||
|
1. downloads Valve's package and checks its **SHA-256** against Valve's
|
||||||
|
repository, so it's exactly Valve's file;
|
||||||
|
2. asks **fwupd** whether the firmware is for this very machine (fwupd compares
|
||||||
|
the firmware's hardware IDs with the device) and stops if it isn't;
|
||||||
|
3. shows a large red **warning** with the current and the new version, and asks
|
||||||
|
whether you understand the risks (default: no);
|
||||||
|
4. shows the warning **again** and only continues when you type `UPDATE`;
|
||||||
|
5. hands the firmware to fwupd, which writes it during the **next restart**:
|
||||||
|
choose "restart now" or restart later yourself.
|
||||||
|
|
||||||
|
**At your own risk:** a failed or interrupted BIOS update can leave the machine
|
||||||
|
unable to start. Keep it on mains power, and never turn off the power, unplug
|
||||||
|
it or press the power button while it updates, including during the restart;
|
||||||
|
the screen can stay black for several minutes.
|
||||||
|
|
||||||
|
To walk through it without flashing anything, run the wizard with
|
||||||
|
`WIZARD_BIOS_DRY_RUN=1`: it downloads and checks the package and shows both
|
||||||
|
warnings, skips fwupd's device check, and only prints the install command.
|
||||||
|
|
||||||
|
## Manual session control
|
||||||
|
|
||||||
|
```bash
|
||||||
|
steamos-session-select gamescope # switch to gamescope right now
|
||||||
|
steamos-session-select plasma # switch to desktop right now
|
||||||
|
steamos-session-select persistent # remember the last-used session across reboots
|
||||||
|
steamos-session-select oneshot # always start in gamescope (default, like a Deck)
|
||||||
|
```
|
||||||
|
|
||||||
|
With `Relogin=true`, a gamescope session that fails to start is restarted
|
||||||
|
immediately, which can turn into a loop - see
|
||||||
|
[TROUBLESHOOTING.md](TROUBLESHOOTING.md) for the way out.
|
||||||
|
|
||||||
|
## Project layout
|
||||||
|
|
||||||
|
| File | Responsibility |
|
||||||
|
|---|---|
|
||||||
|
| `steamify.sh` | Entry point: checks, menu, apply, summary, restart |
|
||||||
|
| `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/boot-session.sh` | Boot into gamescope or the desktop (`steamify-boot-desktop.service`) |
|
||||||
|
| `lib/login-manager.sh` | SteamOS conversion: SDDM or plasmalogin autologin, sync bridge |
|
||||||
|
| `lib/steam-desktop.sh` | Steam in the Plasma session; Steam Deck/Machine icons |
|
||||||
|
| `lib/desktop-shortcut.sh` | Return to Gaming Mode shortcut and its sudoers rule |
|
||||||
|
| `lib/vapor-theme.sh` | SteamOS theme: installs and switches to `cachyos-vapor` |
|
||||||
|
| `lib/steamos-extras.sh` | SteamOS desktop extras from Valve's package (Add to Steam, Nested Desktop, icon, keyboard rule, KWallet) |
|
||||||
|
| `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out |
|
||||||
|
| `lib/wizard-shortcut.sh` | Steamify shortcut: desktop icon and launcher entry that run the newest release |
|
||||||
|
| `lib/bios.sh` | Update BIOS (Steam Machine, opt-in): current/newest version, double confirmation, fwupd |
|
||||||
|
| `lib/cec.sh` | HDMI-CEC: Valve's `cecd` and friends from its `holo` repository |
|
||||||
|
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager; kernel pin |
|
||||||
|
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`) |
|
||||||
|
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
|
||||||
|
|
||||||
|
The single-file version is generated: on every push to `main`, GitHub
|
||||||
|
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
|
||||||
|
shellcheck, and publishes it as a release per version (tag `v<VERSION>`,
|
||||||
|
never overwritten; the newest is marked latest, and the `latest` tag follows
|
||||||
|
it). It inlines
|
||||||
|
`lib/*.sh` and wraps the entry point in `main()`, so bash has read the whole
|
||||||
|
file before anything runs; when stdin is a pipe (`curl | bash`) it reattaches
|
||||||
|
the terminal for the menu (set `WIZARD_KEEP_STDIN=1` to keep piped input).
|
||||||
|
|
||||||
|
Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md).
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- This works around CachyOS/`plasma-login-manager` behavior as of September
|
||||||
|
2026. If CachyOS fixes `steam-set-session` upstream, parts of this script
|
||||||
|
become unnecessary - please open an issue or PR if you notice that.
|
||||||
|
- Tested on a Valve Steam Machine running CachyOS Desktop edition. It should
|
||||||
|
work on any CachyOS desktop install using `plasma-login-manager`, but
|
||||||
|
hasn't been tested on Steam Deck/Legion Go hardware.
|
||||||
|
|
||||||
|
## Related upstream reports
|
||||||
|
|
||||||
|
- [CachyOS/gamescope-session#9](https://github.com/CachyOS/gamescope-session/issues/9) - "Switch to Desktop" hang due to missing `/etc/plasmalogin.conf.d`
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
See [TECHNICAL.md](TECHNICAL.md) for how each part works.
|
||||||
|
|
||||||
|
## Gaming mode shows a black screen or keeps restarting
|
||||||
|
|
||||||
|
Press **Ctrl+Alt+F3**, log in with your username and password, and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /usr/lib/steamos/steam-set-session plasma.desktop && sudo systemctl restart display-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
That takes you back to the desktop. Gamescope sessions that fail to start are
|
||||||
|
restarted right away (`Relogin=true`), which is why it can loop.
|
||||||
|
|
||||||
|
## Something is set up wrong
|
||||||
|
|
||||||
|
Run the wizard again and press `a` in the menu to re-apply everything that's
|
||||||
|
on (also useful after a CachyOS update). To undo a part, untick it.
|
||||||
|
|
||||||
|
## The LED bar on the Steam Machine stays dark
|
||||||
|
|
||||||
|
Restart once more; a freshly installed driver often needs a reboot. The menu
|
||||||
|
shows per kernel whether the LED driver is built, and whether it's loaded.
|
||||||
|
Still dark:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dkms status
|
||||||
|
ls -l /sys/class/leds/valve-leds*/
|
||||||
|
sudo dmesg | grep -i valve
|
||||||
|
cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log
|
||||||
|
journalctl --user -b | grep -i led
|
||||||
|
```
|
||||||
|
|
||||||
|
## The TV remote does nothing (HDMI-CEC)
|
||||||
|
|
||||||
|
- Turn on CEC in the TV's settings (Sony: BRAVIA Sync, Samsung: Anynet+, LG:
|
||||||
|
SimpLink) and, if it has one, allow the PC to control it.
|
||||||
|
- Check that the PC has a CEC device, and that `cecd` runs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /dev/cec*
|
||||||
|
systemctl --user status cecd
|
||||||
|
journalctl --user -u cecd -b
|
||||||
|
cec-ctl -d /dev/cec0 -S # the devices on the TV's CEC bus (v4l-utils)
|
||||||
|
```
|
||||||
|
|
||||||
|
No `/dev/cec*`: your PC has no CEC; a USB CEC adapter (e.g. Pulse-Eight)
|
||||||
|
works. See [CEC.md](CEC.md). The Steam Machine wakes up again right after going
|
||||||
|
to sleep, or other devices lose CEC? That happens on SteamOS too; turn
|
||||||
|
HDMI-CEC off in the wizard.
|
||||||
|
|
||||||
|
## The Steam Machine still reboots when I shut it down
|
||||||
|
|
||||||
|
Check that the pinned kernel is installed and running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uname -r # should be 7.1.6-1-cachyos
|
||||||
|
pacman -Q linux-cachyos linux-cachyos-headers
|
||||||
|
grep '^IgnorePkg' /etc/pacman.conf # should list both packages
|
||||||
|
```
|
||||||
|
|
||||||
|
Not running it yet? Restart. Not installed? Run the wizard and make sure
|
||||||
|
**Pin the kernel** under Steam Machine support is ticked. If you have more
|
||||||
|
kernels installed (e.g. the LTS kernel), pick `linux-cachyos` in the boot menu.
|
||||||
|
|
||||||
|
## The kernel pin can't download or verify the kernel
|
||||||
|
|
||||||
|
The wizard tries this repo's `kernel-7.1.6-1` release, then the CachyOS
|
||||||
|
archive and mirror. A file that fails its checksum or CachyOS signature is
|
||||||
|
deleted, so running the wizard again downloads it once more. Offline? Put
|
||||||
|
the four files from the
|
||||||
|
[kernel-7.1.6-1 release](https://github.com/theupriser/steamify-cachyos/releases/tag/kernel-7.1.6-1)
|
||||||
|
in `/var/cache/steamify/kernel` and run it again.
|
||||||
|
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Icon for the "Steamify CachyOS" shortcut (cachyos-gamescope-boot).
|
||||||
|
Derived from Valve's steam-gaming-return.svg (steamdeck-kde-presets,
|
||||||
|
GPL-2.0): the Return to Gaming Mode arrow replaced by a gear. -->
|
||||||
|
<svg
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
viewBox="0 0 48 48"
|
||||||
|
version="1.1"
|
||||||
|
id="svg11"
|
||||||
|
sodipodi:docname="steam-gaming-settings.svg"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview11"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="8"
|
||||||
|
inkscape:cx="16.6875"
|
||||||
|
inkscape:cy="16.4375"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1014"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg11">
|
||||||
|
<inkscape:grid
|
||||||
|
id="grid11"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1"
|
||||||
|
empcolor="#3f3fff"
|
||||||
|
empopacity="0.25098039"
|
||||||
|
color="#3f3fff"
|
||||||
|
opacity="0.1254902"
|
||||||
|
empspacing="5"
|
||||||
|
enabled="true"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<linearGradient
|
||||||
|
id="blue-gradient-5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#054e87;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#1d99f3;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop2" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="shadow-3">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#31363b;stop-opacity:0.208"
|
||||||
|
offset="0"
|
||||||
|
id="stop3" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#31363b;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4199"
|
||||||
|
x1="21.969"
|
||||||
|
y1="1035.362"
|
||||||
|
x2="35.969"
|
||||||
|
y2="1049.362"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(10,-1018.3622)" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4203"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="23"
|
||||||
|
y1="1035.362"
|
||||||
|
x2="36"
|
||||||
|
y2="1048.362"
|
||||||
|
gradientTransform="translate(13,-1021.3622)" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4227"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-15.75,-1005.8622)"
|
||||||
|
x1="21.475"
|
||||||
|
y1="1035.158"
|
||||||
|
x2="34.475"
|
||||||
|
y2="1048.158" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#blue-gradient-5"
|
||||||
|
id="linearGradient4351"
|
||||||
|
x1="24"
|
||||||
|
y1="1008.362"
|
||||||
|
x2="24"
|
||||||
|
y2="1048.362"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,-1004.3622)" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4373"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(5.9783302,-1021.8757)"
|
||||||
|
x1="21.085"
|
||||||
|
y1="1036.975"
|
||||||
|
x2="35.969"
|
||||||
|
y2="1049.362" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4377"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-6.3297472,-1009.2141)"
|
||||||
|
x1="21.085"
|
||||||
|
y1="1036.975"
|
||||||
|
x2="35.969"
|
||||||
|
y2="1049.362" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient4381"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-2.8703079,-1005.5321)"
|
||||||
|
x1="21.969"
|
||||||
|
y1="1035.362"
|
||||||
|
x2="35.969"
|
||||||
|
y2="1049.362" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#blue-gradient-5"
|
||||||
|
id="linearGradient12"
|
||||||
|
x1="34.848072"
|
||||||
|
y1="2.7402468"
|
||||||
|
x2="35.248451"
|
||||||
|
y2="46.980125"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient14"
|
||||||
|
x1="34.345119"
|
||||||
|
y1="37.896885"
|
||||||
|
x2="42.498322"
|
||||||
|
y2="45.409893"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#shadow-3"
|
||||||
|
id="linearGradient16"
|
||||||
|
x1="3.5050631"
|
||||||
|
y1="46.96999"
|
||||||
|
x2="3.6629491"
|
||||||
|
y2="50.93874"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<circle
|
||||||
|
style="fill:url(#linearGradient4351);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
cx="24"
|
||||||
|
cy="23.999861"
|
||||||
|
r="20"
|
||||||
|
id="circle4" />
|
||||||
|
<circle
|
||||||
|
id="path43518"
|
||||||
|
cx="34.995033"
|
||||||
|
cy="34.995033"
|
||||||
|
style="fill:url(#linearGradient12);fill-rule:evenodd;stroke-width:0.999996;fill-opacity:1"
|
||||||
|
r="12" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4203);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 35.923828,13.330078 C 37.206994,14.675942 38,16.493653 38,18.5 c -10e-7,4.142136 -3.357865,7.5 -7.5,7.5 -0.203438,-0.0015 -0.406734,-0.01127 -0.609375,-0.0293 l -5.896484,5.111328 c -0.0083,0.739616 -0.153346,1.471317 -0.427735,2.158203 -1.23712,3.074359 -4.732395,4.563589 -7.80664,3.326172 -0.24293,-0.09775 -0.470788,-0.215212 -0.69336,-0.339844 -0.04331,-0.0244 -0.08621,-0.04875 -0.128906,-0.07422 -0.211403,-0.125374 -0.414371,-0.260582 -0.605469,-0.408203 -0.0063,-0.0049 -0.01326,-0.0088 -0.01953,-0.01367 l -0.01172,0.002 8.19336,8.193359 C 22.994984,43.969391 23.497293,43.994196 24,44 a 20,20 0 0 0 1.310547,-0.04687 c 0.06663,-0.0043 0.132772,-0.01066 0.199219,-0.01563 a 20,20 0 0 0 1.845703,-0.222656 c 0.03199,-0.0054 0.06377,-0.01202 0.0957,-0.01758 a 20,20 0 0 0 1.396484,-0.3125 c 0.240477,-0.05998 0.481808,-0.116947 0.71875,-0.185547 A 20,20 0 0 0 30.7832,42.79492 c 0.221103,-0.07984 0.444706,-0.154851 0.662109,-0.242188 a 20,20 0 0 0 1.148441,-0.51367 C 32.813074,41.93437 33.035177,41.835015 33.25,41.722656 a 20,20 0 0 0 1.03125,-0.591797 c 0.231705,-0.139379 0.46789,-0.271541 0.693359,-0.419921 a 20,20 0 0 0 0.953125,-0.685547 c 0.206289,-0.153802 0.419094,-0.299475 0.619141,-0.460938 a 20,20 0 0 0 0.908203,-0.796875 c 0.190109,-0.173313 0.387023,-0.339092 0.570313,-0.519531 a 20,20 0 0 0 0.833984,-0.892578 c 0.163426,-0.181706 0.335418,-0.355335 0.492187,-0.542969 a 20,20 0 0 0 0.863282,-1.136719 c 0.102363,-0.141895 0.215754,-0.275269 0.314453,-0.419922 a 20,20 0 0 0 3.371094,-9.257812 c 6.3e-5,-6.43e-4 -6.4e-5,-0.0013 0,-0.002 a 20,20 0 0 0 0,-0.0059 A 20,20 0 0 0 44,24 20,20 0 0 0 43.779297,21.185547 Z"
|
||||||
|
id="path6" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4227);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 5.7695312,29.3125 19.363281,43.431641 a 20,20 0 0 0 3.13086,0.49414 l -8.19336,-8.193359 -2.001953,-4.97461 z"
|
||||||
|
id="path9" />
|
||||||
|
<g
|
||||||
|
id="g11">
|
||||||
|
<path
|
||||||
|
d="m 26.586,23.6632 8.104641,-0.4201 1.91027,-6.7552 -5.59099,-4.4419 -6.871493,5.8329 z"
|
||||||
|
style="fill:url(#linearGradient4373);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4199);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 31.027515,23.9946 35,23 l 1.976562,-2.9766 -4,-4 -4.949047,4.9712 z"
|
||||||
|
id="path5" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4377);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 15.316486,35.7061 21.675457,35.065 23.0333,27.5143 16.403747,25.7462 12.603749,30.3195 Z"
|
||||||
|
id="path7" />
|
||||||
|
<path
|
||||||
|
d="m 16.985332,35.8717 3.972485,-0.4165 2.210937,-3.4453 -3.0625,-3.1563 -6.933422,3.9868 z"
|
||||||
|
style="fill:url(#linearGradient4381);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path8" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 30.5,11 c -4.142135,0 -7.499999,3.357864 -7.5,7.5 0.0017,0.201484 0.01143,0.402819 0.0293,0.603516 -1.289636,1.575722 -4.80544,5.546997 -5.113281,5.902343 -2.416761,0.03284 -4.577852,1.51258 -5.482422,3.753907 -1.237432,3.074241 0.2518,6.569519 3.326172,7.80664 3.074245,1.237417 6.56952,-0.251813 7.80664,-3.326172 0.274389,-0.686886 0.419405,-1.418587 0.427735,-2.158203 l 5.896484,-5.111328 C 30.093269,25.98873 30.296562,25.998503 30.5,26 34.642135,26 37.999999,22.642136 38,18.5 37.999999,14.357864 34.642135,11 30.5,11 Z m 0,3 c 2.48528,0 4.499999,2.014718 4.5,4.5 -10e-7,2.485282 -2.01472,4.5 -4.5,4.5 -2.48528,0 -4.499999,-2.014718 -4.5,-4.5 1e-6,-2.485282 2.01472,-4.5 4.5,-4.5 z M 18.046875,27 c 0.496175,0.0058 0.986949,0.103774 1.447266,0.289062 2.049689,0.825003 3.042263,3.155585 2.216797,5.205079 -0.825003,2.049668 -3.155579,3.04224 -5.205079,2.216797 C 14.45617,33.885935 13.463596,31.555353 14.289062,29.505859 14.905127,27.975627 16.397393,26.980525 18.046875,27 Z"
|
||||||
|
id="path10" />
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
cx="30.5"
|
||||||
|
cy="18.4998"
|
||||||
|
id="ellipse10"
|
||||||
|
r="3.5" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 5.0722656,22.564453 A 19,19 0 0 0 5,24 19,19 0 0 0 5.7695312,29.3125 l 11.1113278,4.470703 a 3,3 0 0 0 3.902344,-1.664062 3,3 0 0 0 -1.664062,-3.902344 z"
|
||||||
|
id="path11" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<path id="gear" style="fill:#ffffff;fill-rule:evenodd;stroke:none" d="M 40.440,33.688 L 42.527,33.983 L 42.527,36.007 L 40.440,36.302 L 39.770,37.921 L 41.037,39.606 L 39.606,41.037 L 37.921,39.770 L 36.302,40.440 L 36.007,42.527 L 33.983,42.527 L 33.688,40.440 L 32.069,39.770 L 30.384,41.037 L 28.953,39.606 L 30.220,37.921 L 29.550,36.302 L 27.463,36.007 L 27.463,33.983 L 29.550,33.688 L 30.220,32.069 L 28.953,30.384 L 30.384,28.953 L 32.069,30.220 L 33.688,29.550 L 33.983,27.463 L 36.007,27.463 L 36.302,29.550 L 37.921,30.220 L 39.606,28.953 L 41.037,30.384 L 39.770,32.069 Z M 37.395,34.995 A 2.4,2.4 0 1 0 32.595,34.995 A 2.4,2.4 0 1 0 37.395,34.995 Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
+203
@@ -0,0 +1,203 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "Update BIOS" menu item, only on a Steam Machine and always opt-in: flashes
|
||||||
|
# the newest Steam Machine BIOS from Valve's fremont-hw-support package with
|
||||||
|
# fwupd. It's an action, not an on/off component: never preselected, never
|
||||||
|
# re-applied, and there is nothing to turn off afterwards.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
BIOS_REPO_PREFIX=holo
|
||||||
|
# WIZARD_BIOS_DRY_RUN=1 walks through the whole BIOS update (download,
|
||||||
|
# checksum, both warnings) but never flashes: fwupd's device check is
|
||||||
|
# skipped and the install is only printed. For testing, e.g. in a VM.
|
||||||
|
BIOS_DRY_RUN="${WIZARD_BIOS_DRY_RUN:-}"
|
||||||
|
|
||||||
|
bios_available() { detect_valve_fremont; }
|
||||||
|
|
||||||
|
bios_status() { return 1; }
|
||||||
|
|
||||||
|
bios_disable() { return 0; }
|
||||||
|
|
||||||
|
bios_current() {
|
||||||
|
cat /sys/class/dmi/id/bios_version 2>/dev/null || echo unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_lookup_newest() {
|
||||||
|
# Sets BIOS_REPO, BIOS_PKG, BIOS_SHA256 and BIOS_NEWEST (e.g. F7F0108)
|
||||||
|
# from the newest holo-X.Y repository on Valve's mirror: its .files
|
||||||
|
# database names the firmware file, its .db gives the package checksum.
|
||||||
|
# Only once per run, and with short timeouts so an offline machine
|
||||||
|
# doesn't hold up the menu.
|
||||||
|
[[ -n "${BIOS_LOOKED_UP:-}" ]] && return 0
|
||||||
|
BIOS_LOOKED_UP=1; BIOS_NEWEST=""
|
||||||
|
local tmp desc
|
||||||
|
BIOS_REPO="$(curl -fsL --max-time 10 "$VALVE_MIRROR/" | grep -oE "$BIOS_REPO_PREFIX-[0-9]+\.[0-9]+/" | tr -d / | sort -uV | tail -n 1)"
|
||||||
|
[[ -n "$BIOS_REPO" ]] || return 1
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
if curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.files" -o "$tmp/files" &&
|
||||||
|
curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.db" -o "$tmp/db"; then
|
||||||
|
desc="$(tar -tf "$tmp/files" 2>/dev/null | grep -E '^fremont-hw-support-[0-9][^/]*/files$' | head -n 1)"
|
||||||
|
[[ -n "$desc" ]] && BIOS_CAB="$(tar -xOf "$tmp/files" "$desc" | grep -E '^usr/share/fwupd/.*\.cab$' | head -n 1)"
|
||||||
|
desc="${desc%/files}/desc"
|
||||||
|
BIOS_PKG="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%FILENAME%$/ { getline; print }')"
|
||||||
|
BIOS_SHA256="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%SHA256SUM%$/ { getline; print }')"
|
||||||
|
[[ -n "${BIOS_CAB:-}" && -n "$BIOS_PKG" && -n "$BIOS_SHA256" ]] && BIOS_NEWEST="$(basename "$BIOS_CAB" .cab)"
|
||||||
|
fi
|
||||||
|
rm -rf "$tmp"
|
||||||
|
[[ -n "$BIOS_NEWEST" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_selectable() {
|
||||||
|
# Only when Valve has a newer BIOS than the one installed; the menu
|
||||||
|
# greys the item out otherwise (up to date, or newest unknown/offline).
|
||||||
|
[[ -z "${BIOS_NEEDS_RESTART:-}" && -n "${BIOS_NEWEST:-}" && "$BIOS_NEWEST" != "$(bios_current)" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_label() {
|
||||||
|
# Menu label with the current and the newest version; kept short so the
|
||||||
|
# row (with "(not available)" when greyed out) fits 80 columns.
|
||||||
|
local current
|
||||||
|
current="$(bios_current)"
|
||||||
|
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
|
||||||
|
echo "Update BIOS: $BIOS_NEWEST waits for a restart"
|
||||||
|
elif [[ -z "${BIOS_NEWEST:-}" ]]; then
|
||||||
|
echo "Update BIOS: now $current, newest unknown (offline?)"
|
||||||
|
elif [[ "$BIOS_NEWEST" == "$current" ]]; then
|
||||||
|
echo "Update BIOS: $current is up to date"
|
||||||
|
else
|
||||||
|
echo "Update BIOS: now $current, newest $BIOS_NEWEST (own risk)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BIOS_BOX_WIDTH=68
|
||||||
|
|
||||||
|
bios_box_line() {
|
||||||
|
# bios_box_line [text]: one line of the warning box, padded to the same
|
||||||
|
# visible width (colour codes don't count) so the right edge lines up.
|
||||||
|
local text="${1:-}" plain pad
|
||||||
|
plain="$(printf '%b' "$text" | sed 's/\x1b\[[0-9;]*m//g')"
|
||||||
|
pad=$(( BIOS_BOX_WIDTH - 6 - ${#plain} ))
|
||||||
|
(( pad < 0 )) && pad=0
|
||||||
|
printf ' %b██%b %b%*s%b██%b\n' "$c_red" "$c_reset" "$text" "$pad" "" "$c_red" "$c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_box_border() {
|
||||||
|
# Block characters: Konsole draws a long coloured row of # narrower
|
||||||
|
# than the box's other lines, so its right edge wouldn't line up.
|
||||||
|
printf ' %b%s%b\n' "$c_red" "$(printf '█%.0s' $(seq "$BIOS_BOX_WIDTH"))" "$c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_disclaimer() {
|
||||||
|
# bios_disclaimer <title> [line...]: the warning box; extra lines are
|
||||||
|
# shown above the fixed risks.
|
||||||
|
local title="$1" line b="$c_bold" n="$c_reset"
|
||||||
|
shift
|
||||||
|
echo
|
||||||
|
bios_box_border
|
||||||
|
bios_box_line
|
||||||
|
bios_box_line "$c_red$b$title$n"
|
||||||
|
bios_box_line
|
||||||
|
bios_box_border
|
||||||
|
for line in "$@"; do bios_box_line "$line"; done
|
||||||
|
bios_box_line
|
||||||
|
bios_box_line "- A failed or interrupted BIOS update can leave the machine"
|
||||||
|
bios_box_line " unable to start (bricked). This wizard, CachyOS and Valve"
|
||||||
|
bios_box_line " take no responsibility for that."
|
||||||
|
bios_box_line "- ${b}NEVER turn off the power, unplug the machine or press${n}"
|
||||||
|
bios_box_line " ${b}the power button while the update runs${n}, including the"
|
||||||
|
bios_box_line " restart(s) afterwards, when the firmware is written."
|
||||||
|
bios_box_line "- The screen can stay black for several minutes. Wait."
|
||||||
|
bios_box_line "- Only on mains power, with all other programs closed."
|
||||||
|
bios_box_line
|
||||||
|
bios_box_border
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_fits_device() {
|
||||||
|
# bios_fits_device <cab>: does fwupd match this firmware to a device in
|
||||||
|
# this machine? It compares the file's hardware IDs (GUIDs) with the
|
||||||
|
# hardware; for a file that doesn't fit it reports an UpdateError.
|
||||||
|
local details
|
||||||
|
details="$(sudo fwupdmgr get-details --json "$1" 2>/dev/null)" || return 1
|
||||||
|
grep -q '"Guid"' <<< "$details" && ! grep -q '"UpdateError"' <<< "$details"
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_enable() {
|
||||||
|
if ! bios_lookup_newest; then
|
||||||
|
err "Couldn't find the newest Steam Machine BIOS on Valve's mirror ($VALVE_MIRROR)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local current tmp compatible
|
||||||
|
current="$(bios_current)"
|
||||||
|
[[ -n "$BIOS_DRY_RUN" ]] && warn "DRY RUN (WIZARD_BIOS_DRY_RUN): nothing will be flashed."
|
||||||
|
if [[ "$current" == "$BIOS_NEWEST" ]]; then
|
||||||
|
ok "The BIOS is already the newest version ($current); nothing to do."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download and check everything before asking: the warnings only come
|
||||||
|
# when the file is Valve's (SHA-256 from Valve's repo database) and fwupd
|
||||||
|
# confirms it's firmware for this very machine.
|
||||||
|
pacman -Q fwupd >/dev/null 2>&1 || sudo pacman -S --needed --noconfirm fwupd ||
|
||||||
|
{ err "Installing fwupd failed."; return 1; }
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
info "Downloading $BIOS_PKG ($BIOS_REPO)..."
|
||||||
|
if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$tmp/pkg.tar.zst" ||
|
||||||
|
! echo "$BIOS_SHA256 $tmp/pkg.tar.zst" | sha256sum -c --quiet - ||
|
||||||
|
! tar -I unzstd -xf "$tmp/pkg.tar.zst" -C "$tmp" "$BIOS_CAB"; then
|
||||||
|
err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched."
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
ok "Checksum OK: this is Valve's $BIOS_PKG."
|
||||||
|
local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
|
||||||
|
if [[ -n "$BIOS_DRY_RUN" ]]; then
|
||||||
|
warn "Dry run: skipping fwupd's check that the firmware fits this machine."
|
||||||
|
compatible="${c_yellow}${b}not checked${n} (dry run)"
|
||||||
|
elif bios_fits_device "$tmp/$BIOS_CAB"; then
|
||||||
|
ok "fwupd confirms BIOS $BIOS_NEWEST is firmware for this machine."
|
||||||
|
compatible="${yes}yes${n} (checked by fwupd)"
|
||||||
|
else
|
||||||
|
err "fwupd says BIOS $BIOS_NEWEST is not for this machine's hardware; not installing it."
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bios_disclaimer "WARNING: BIOS UPDATE - ENTIRELY AT YOUR OWN RISK" \
|
||||||
|
"Current BIOS: ${b}$current${n}" \
|
||||||
|
"New BIOS: ${b}$BIOS_NEWEST${n}" \
|
||||||
|
"Checksum: ${yes}OK${n} (Valve's package)" \
|
||||||
|
"Compatible: $compatible"
|
||||||
|
if ! ask_yn "Do you understand the risks and want to continue?" n; then
|
||||||
|
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
|
||||||
|
fi
|
||||||
|
bios_disclaimer "LAST CHANCE: THIS FLASHES BIOS $BIOS_NEWEST" \
|
||||||
|
"After this, keep the power on until the machine has fully" \
|
||||||
|
"started again. Don't touch it, even if the screen is black."
|
||||||
|
local reply
|
||||||
|
read -rp "$(echo -e "${c_red}${c_bold}Type UPDATE (in capitals) to flash the BIOS, anything else cancels:${c_reset} ")" reply
|
||||||
|
if [[ "$reply" != UPDATE ]]; then
|
||||||
|
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$BIOS_DRY_RUN" ]]; then
|
||||||
|
ok "Dry run: would run: fwupdmgr install -y --no-reboot-check $(basename "$BIOS_CAB")"
|
||||||
|
ok "Dry run finished; nothing was flashed."
|
||||||
|
# Treated as staged, so the restart choices that follow a real
|
||||||
|
# update show up too; restarting only prints (see restart_now).
|
||||||
|
BIOS_NEEDS_RESTART=1
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
info "Handing BIOS $BIOS_NEWEST to fwupd. Do NOT turn off the power from now on."
|
||||||
|
# -y: we already asked twice; --no-reboot-check: the wizard's own
|
||||||
|
# restart question comes at the end.
|
||||||
|
if ! sudo fwupdmgr install -y --no-reboot-check "$tmp/$BIOS_CAB"; then
|
||||||
|
err "fwupd could not install the BIOS update (see above); the BIOS was not changed."
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
rm -rf "$tmp"
|
||||||
|
BIOS_NEEDS_RESTART=1
|
||||||
|
ok "BIOS $BIOS_NEWEST is staged. It is written during the next restart:"
|
||||||
|
warn "keep the power on and don't touch the machine until it has fully started again."
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "Boot into: gamescope / desktop" menu item, on top of the SteamOS
|
||||||
|
# conversion. Gamescope is the default (the conversion's autologin, and
|
||||||
|
# CachyOS's cachyos-gamescope-autologin resetting to it after a desktop
|
||||||
|
# session). Desktop: a unit that sets the autologin session to Plasma at
|
||||||
|
# every boot, before the login manager starts. Switching between the two in
|
||||||
|
# a running system (Return to Gaming Mode, Steam's Switch to Desktop) works
|
||||||
|
# the same either way.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
BOOT_UNIT_NAME="steamify-boot-desktop.service"
|
||||||
|
BOOT_UNIT="/etc/systemd/system/$BOOT_UNIT_NAME"
|
||||||
|
SESSION_SYNC="/usr/local/bin/sync-steamos-session.sh"
|
||||||
|
|
||||||
|
boot_status() {
|
||||||
|
# On = boots into the desktop.
|
||||||
|
[[ -f "$BOOT_UNIT" ]] && systemctl is-enabled -q "$BOOT_UNIT_NAME" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_enable() {
|
||||||
|
info "Setting the PC to boot into the desktop..."
|
||||||
|
# The sync bridge (plasma-login-manager only; not there with SDDM) copies
|
||||||
|
# the session into the base config; run it right away rather than rely
|
||||||
|
# on its path unit, which could still be pending when the login manager
|
||||||
|
# starts.
|
||||||
|
sudo tee "$BOOT_UNIT" > /dev/null << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Steamify CachyOS: boot into the desktop instead of gaming mode
|
||||||
|
Before=display-manager.service sddm.service plasmalogin.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/lib/steamos/steam-set-session plasma.desktop
|
||||||
|
ExecStart=/bin/sh -c '[ -x $SESSION_SYNC ] && exec $SESSION_SYNC || true'
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical.target
|
||||||
|
EOF
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable "$BOOT_UNIT_NAME" || { err "Enabling $BOOT_UNIT_NAME failed."; return 1; }
|
||||||
|
ok "Boots into the desktop from the next boot on (Return to Gaming Mode still works)."
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_disable() {
|
||||||
|
info "Setting the PC to boot into gaming mode again..."
|
||||||
|
sudo systemctl disable "$BOOT_UNIT_NAME" 2>/dev/null
|
||||||
|
sudo rm -f "$BOOT_UNIT"
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
# Next boot into gamescope, as the conversion sets it up.
|
||||||
|
sudo /usr/lib/steamos/steam-set-session gamescope-session.desktop
|
||||||
|
[[ -x "$SESSION_SYNC" ]] && sudo "$SESSION_SYNC"
|
||||||
|
ok "Boots into gaming mode from the next boot on."
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_choice() {
|
||||||
|
# The menu row: the chosen option in brackets.
|
||||||
|
if [[ "$1" == 1 ]]; then
|
||||||
|
echo "Boot into: gamescope [desktop]"
|
||||||
|
else
|
||||||
|
echo "Boot into: [gamescope] desktop"
|
||||||
|
fi
|
||||||
|
}
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "HDMI-CEC" menu item, on any PC: Valve's CEC daemon (cecd), TV/receiver
|
||||||
|
# volume control (cec-audio-control) and the units that attach USB CEC
|
||||||
|
# adapters (Pulse-Eight, RainShadow) with inputattach. They're only in
|
||||||
|
# Valve's SteamOS (holo) repository, not in CachyOS or the AUR. Works with
|
||||||
|
# any /dev/cec*: a GPU with CEC (e.g. the Steam Machine) or a USB adapter.
|
||||||
|
# On a Steam Machine, steamos-manager configures cecd from Steam's settings.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
CEC_PKGS=(cecd cec-audio-control inputattach-cec-units)
|
||||||
|
# steamos-manager checks once, at its start, whether cecd runs; order it
|
||||||
|
# after cecd so it never misses it at login.
|
||||||
|
CEC_ORDER_DROPIN=/etc/systemd/user/steamos-manager.service.d/10-steamify-after-cecd.conf
|
||||||
|
# CachyOS's gaming mode script exports STEAM_ENABLE_CEC=0, which hides
|
||||||
|
# Steam's HDMI-CEC settings; Steam reads it from the gamescope environment
|
||||||
|
# file. A later EnvironmentFile= overrides it.
|
||||||
|
CEC_STEAM_ENV=/etc/steamify/steam-cec.env
|
||||||
|
CEC_STEAM_DROPIN=/etc/systemd/user/steam-launcher.service.d/10-steamify-cec.conf
|
||||||
|
|
||||||
|
cec_link_steamos_manager() {
|
||||||
|
# On a Steam Machine: steamos-manager writes cecd's config from Steam's
|
||||||
|
# CEC settings (its configure-cecd unit, run before cecd), and only
|
||||||
|
# offers Steam those settings when cecd was there at its start. Also
|
||||||
|
# called by Steam Machine support, which installs steamos-manager after
|
||||||
|
# this item ran.
|
||||||
|
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
|
systemctl --user start steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
|
systemctl --user restart cecd.service 2>/dev/null
|
||||||
|
systemctl --user restart steamos-manager.service 2>/dev/null
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cec_installed() { pacman -Q "${CEC_PKGS[@]}" >/dev/null 2>&1; }
|
||||||
|
# On = installed and Steam told to show its CEC settings. An install from
|
||||||
|
# before 1.1.3 lacks the latter; the menu then ticks it (see cec_repair).
|
||||||
|
cec_status() { cec_installed && [[ -f "$CEC_STEAM_DROPIN" ]]; }
|
||||||
|
cec_repair() { cec_installed && ! cec_status; }
|
||||||
|
|
||||||
|
fetch_holo_pkg() {
|
||||||
|
# fetch_holo_pkg <dir> <package>: download the newest <package> from
|
||||||
|
# Valve's newest holo repository into <dir> and print its path. The
|
||||||
|
# SHA-256 comes from Valve's package index and is verified.
|
||||||
|
local dir="$1" name="$2" repo desc file_name sha256
|
||||||
|
repo="$(curl -fsL "$VALVE_MIRROR/" | grep -oE 'holo-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
|
||||||
|
if [[ ! -f "$dir/holo.db" ]]; then
|
||||||
|
[[ -n "$repo" ]] && curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$repo.db" -o "$dir/holo.db" ||
|
||||||
|
{ err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; }
|
||||||
|
fi
|
||||||
|
desc="$(tar -tf "$dir/holo.db" 2>/dev/null | grep -E "^$name-[0-9][^/]*/desc$" | head -n 1)"
|
||||||
|
[[ -n "$desc" ]] || { err "No $name in Valve's $repo repository."; return 1; }
|
||||||
|
file_name="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%FILENAME%$/ { getline; print }')"
|
||||||
|
sha256="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%SHA256SUM%$/ { getline; print }')"
|
||||||
|
info "Downloading $file_name ($repo)..." >&2
|
||||||
|
curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$file_name" -o "$dir/$file_name" ||
|
||||||
|
{ err "Downloading $file_name failed."; return 1; }
|
||||||
|
echo "$sha256 $dir/$file_name" | sha256sum -c --quiet - >&2 ||
|
||||||
|
{ err "Checksum mismatch for $file_name; not using it."; return 1; }
|
||||||
|
echo "$dir/$file_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
cec_enable() {
|
||||||
|
local tmp p f files=()
|
||||||
|
# inputattach, needed by inputattach-cec-units.
|
||||||
|
if ! pacman -Q linuxconsole >/dev/null 2>&1; then
|
||||||
|
sudo pacman -S --needed --noconfirm linuxconsole || { err "Installing linuxconsole failed."; return 1; }
|
||||||
|
state_set cec installed_linuxconsole 1
|
||||||
|
fi
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
for p in "${CEC_PKGS[@]}"; do
|
||||||
|
f="$(fetch_holo_pkg "$tmp" "$p")" || { rm -rf "$tmp"; return 1; }
|
||||||
|
files+=("$f")
|
||||||
|
done
|
||||||
|
info "Installing Valve's CEC daemon..."
|
||||||
|
if ! sudo pacman -U --needed --noconfirm "${files[@]}"; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
err "Installing ${CEC_PKGS[*]} failed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
rm -rf "$tmp"
|
||||||
|
# Its udev rule gives the user /dev/cec*; cecd starts with the graphical
|
||||||
|
# session, after steamos-manager wrote its config from Steam's settings.
|
||||||
|
sudo udevadm control --reload
|
||||||
|
sudo udevadm trigger --subsystem-match=cec --action=add
|
||||||
|
sudo mkdir -p "$(dirname "$CEC_ORDER_DROPIN")"
|
||||||
|
printf '%s\n' "# Written by Steamify: steamos-manager only sees cecd if it runs at its start." \
|
||||||
|
'[Unit]' 'After=cecd.service' | sudo tee "$CEC_ORDER_DROPIN" >/dev/null
|
||||||
|
sudo mkdir -p "$(dirname "$CEC_STEAM_ENV")" "$(dirname "$CEC_STEAM_DROPIN")"
|
||||||
|
printf '%s\n' "# Written by Steamify: Steam's HDMI-CEC settings in gaming mode." 'STEAM_ENABLE_CEC=1' |
|
||||||
|
sudo tee "$CEC_STEAM_ENV" >/dev/null
|
||||||
|
printf '%s\n' "# Written by Steamify: overrides STEAM_ENABLE_CEC=0 from the gaming mode script." \
|
||||||
|
'[Service]' "EnvironmentFile=-$CEC_STEAM_ENV" | sudo tee "$CEC_STEAM_DROPIN" >/dev/null
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
cec_link_steamos_manager
|
||||||
|
if compgen -G "/dev/cec*" >/dev/null; then
|
||||||
|
systemctl --user restart cecd.service 2>/dev/null
|
||||||
|
ok "HDMI-CEC on ($(cd /dev && echo cec*)); Steam shows its settings from the next gaming mode start."
|
||||||
|
info "Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
|
||||||
|
else
|
||||||
|
warn "No CEC device (/dev/cec*) found: your GPU may not support CEC. A USB CEC adapter"
|
||||||
|
warn "(e.g. Pulse-Eight) works too. Check again after a restart with: ls /dev/cec*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cec_disable() {
|
||||||
|
info "Removing HDMI-CEC..."
|
||||||
|
systemctl --user disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
|
||||||
|
systemctl --user disable steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
|
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
|
||||||
|
sudo rm -f "$CEC_ORDER_DROPIN" "$CEC_STEAM_DROPIN" "$CEC_STEAM_ENV"
|
||||||
|
sudo rmdir "$(dirname "$CEC_ORDER_DROPIN")" "$(dirname "$CEC_STEAM_DROPIN")" "$(dirname "$CEC_STEAM_ENV")" 2>/dev/null
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
|
||||||
|
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
|
||||||
|
state_clear cec
|
||||||
|
fi
|
||||||
|
sudo udevadm control --reload
|
||||||
|
systemctl --user is-active -q steamos-manager.service 2>/dev/null &&
|
||||||
|
systemctl --user restart steamos-manager.service
|
||||||
|
ok "HDMI-CEC removed."
|
||||||
|
}
|
||||||
|
|
||||||
|
cec_overview() {
|
||||||
|
# For the menu's kernel overview.
|
||||||
|
local dev="none"
|
||||||
|
compgen -G "/dev/cec*" >/dev/null && dev="$(cd /dev && echo cec*)"
|
||||||
|
echo "CEC devices: $dev cecd: $(systemctl --user is-active cecd 2>/dev/null)"
|
||||||
|
}
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Output helpers, prompts and small shared utilities.
|
# Output helpers, prompts and small shared utilities.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
c_reset="\033[0m"; c_bold="\033[1m"; c_green="\033[32m"; c_yellow="\033[33m"; c_red="\033[31m"; c_cyan="\033[36m"
|
c_reset="\033[0m"; c_bold="\033[1m"; c_green="\033[32m"; c_yellow="\033[33m"; c_red="\033[31m"; c_cyan="\033[36m"; c_dim="\033[2m"
|
||||||
|
|
||||||
info() { echo -e "${c_cyan}[INFO]${c_reset} $*"; }
|
info() { echo -e "${c_cyan}[INFO]${c_reset} $*"; }
|
||||||
ok() { echo -e "${c_green}[OK]${c_reset} $*"; }
|
ok() { echo -e "${c_green}[OK]${c_reset} $*"; }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# "Return to Gaming Mode" desktop shortcut and the sudoers rule it needs.
|
# "Return to Gaming Mode" desktop shortcut and the sudoers rule it needs.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
create_desktop_shortcut() {
|
create_desktop_shortcut() {
|
||||||
# Determine the home directory of the target user
|
# Determine the home directory of the target user
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Booting into gaming mode: autologin into gamescope with SDDM or
|
# Booting into gaming mode: autologin into gamescope with SDDM or
|
||||||
# plasma-login-manager (plus the session sync bridge the latter needs).
|
# 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 steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
BASE_CONF="/etc/plasmalogin.conf"
|
BASE_CONF="/etc/plasmalogin.conf"
|
||||||
|
|
||||||
|
|||||||
+114
-19
@@ -1,23 +1,63 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Interactive menu: detects which components are on, lets the user pick what
|
# Interactive menu: detects which components are on, lets the user pick what
|
||||||
# they want, then turns components on or off to match.
|
# they want, then turns components on or off to match.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
# Menu order. Components are turned on in this order and off in reverse;
|
# Menu order. Components are turned on in this order and off in reverse;
|
||||||
# gaming must come first (single user builds on it).
|
# gaming must come first (single user builds on it).
|
||||||
COMPONENTS=(gaming theme glyphs single machine)
|
COMPONENTS=(gaming boot theme glyphs single launcher cec machine kpin bios)
|
||||||
|
# One-off actions rather than on/off components: never preselected, never
|
||||||
|
# re-applied, not listed as on or off.
|
||||||
|
ACTIONS=(bios)
|
||||||
|
# Sub-options, shown indented under their parent and only while it's ticked.
|
||||||
|
declare -A PARENT=([boot]=gaming [kpin]=machine)
|
||||||
|
# Never preselected on a first run: booting into the desktop is a choice,
|
||||||
|
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
||||||
|
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
||||||
|
# which has CEC like on SteamOS.
|
||||||
|
NO_PRESELECT=(boot cec)
|
||||||
|
|
||||||
declare -A LABEL=(
|
declare -A LABEL=(
|
||||||
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
|
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
|
||||||
|
[boot]="Boot into the desktop instead of gaming mode"
|
||||||
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
||||||
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
||||||
[single]="Single user mode: no password, lock screen or log out (SDDM)"
|
[single]="Single user mode: no password, lock screen or log out (SDDM)"
|
||||||
|
[launcher]="Steamify shortcut: desktop icon to run this again"
|
||||||
|
[cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)"
|
||||||
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
|
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
|
||||||
|
[kpin]="Pin the kernel to $PINNED_KERNEL_VER (fixes rebooting after shutdown)"
|
||||||
|
[bios]="Update BIOS"
|
||||||
)
|
)
|
||||||
declare -A CURRENT WANTED
|
declare -A CURRENT WANTED
|
||||||
|
|
||||||
component_available() {
|
component_available() {
|
||||||
[[ "$1" != machine ]] || machine_available
|
case "$1" in
|
||||||
|
machine|kpin) machine_available ;;
|
||||||
|
bios) bios_available ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
is_action() { [[ " ${ACTIONS[*]} " == *" $1 "* ]]; }
|
||||||
|
|
||||||
|
boot_mode() {
|
||||||
|
# boot_mode 0|1: the "Boot into" choice as a word, for messages; "turn
|
||||||
|
# off boot into the desktop" reads as the opposite of what was chosen.
|
||||||
|
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_visible() {
|
||||||
|
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
||||||
|
# while its parent is ticked.
|
||||||
|
component_available "$1" || return 1
|
||||||
|
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
component_selectable() {
|
||||||
|
# Greyed out and not tickable when it has nothing to do.
|
||||||
|
case "$1" in
|
||||||
|
bios) bios_selectable ;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_components() {
|
detect_components() {
|
||||||
@@ -27,20 +67,32 @@ detect_components() {
|
|||||||
if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi
|
if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi
|
||||||
WANTED[$c]=${CURRENT[$c]}
|
WANTED[$c]=${CURRENT[$c]}
|
||||||
done
|
done
|
||||||
# First run: preselect the full SteamOS experience.
|
# HDMI-CEC set up by an older version: tick it, so a normal run fixes it.
|
||||||
|
component_available cec && cec_repair && WANTED[cec]=1
|
||||||
|
# Shows the current and newest BIOS version.
|
||||||
|
bios_available && { bios_lookup_newest; LABEL[bios]="$(bios_label)"; }
|
||||||
|
# First run: preselect the full SteamOS experience (never an action).
|
||||||
if [[ "$any" == false ]]; then
|
if [[ "$any" == false ]]; then
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" && WANTED[$c]=1
|
component_available "$c" && ! is_action "$c" &&
|
||||||
|
[[ " ${NO_PRESELECT[*]} " != *" $c "* ]] && WANTED[$c]=1
|
||||||
done
|
done
|
||||||
|
machine_available && WANTED[cec]=1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_component() {
|
toggle_component() {
|
||||||
local c="$1"
|
local c="$1"
|
||||||
|
component_selectable "$c" || return 1
|
||||||
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
||||||
# Single user mode only makes sense on top of the SteamOS conversion.
|
# 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" == single && "${WANTED[single]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; fi
|
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
|
||||||
|
# Where to boot to is part of the conversion, too.
|
||||||
|
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
|
# The kernel pin is opt-out: ticked along with Steam Machine support.
|
||||||
|
if [[ "$c" == machine ]]; then WANTED[kpin]=${WANTED[machine]}; fi
|
||||||
|
if [[ "$c" == kpin && "${WANTED[kpin]}" == 1 ]]; then WANTED[machine]=1; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
@@ -49,11 +101,27 @@ show_menu() {
|
|||||||
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
||||||
MENU_ITEMS=()
|
MENU_ITEMS=()
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" || continue
|
menu_visible "$c" || continue
|
||||||
i=$((i + 1)); MENU_ITEMS[$i]=$c
|
i=$((i + 1)); MENU_ITEMS[$i]=$c
|
||||||
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="${c_green}on${c_reset} "
|
# Pad the plain word, then colour it: colour codes would count as width.
|
||||||
|
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="on"
|
||||||
|
is_action "$c" && now="-"
|
||||||
|
now="$(printf '%-6s' "$now")"
|
||||||
|
[[ "${CURRENT[$c]}" == 1 ]] && now="${now/on/${c_green}on${c_reset}}"
|
||||||
want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]"
|
want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]"
|
||||||
printf " %-3s %-6b %-6s %s\n" "$i" "$now " "$want" "${LABEL[$c]}"
|
if [[ "$c" == boot ]]; then
|
||||||
|
# A choice rather than a checkbox: Now/Want show the mode.
|
||||||
|
now="gaming"; [[ "${CURRENT[boot]}" == 1 ]] && now="desk"
|
||||||
|
[[ "${CURRENT[gaming]}" == 1 ]] || now="-"
|
||||||
|
want="gaming"; [[ "${WANTED[boot]}" == 1 ]] && want="desk"
|
||||||
|
printf " %-3s %-6s %-6s └ %s\n" "$i" "$now" "$want" "$(boot_choice "${WANTED[boot]}")"
|
||||||
|
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
||||||
|
printf " %-3s %b %-6s └ %s\n" "$i" "$now" "$want" "${LABEL[$c]}"
|
||||||
|
elif component_selectable "$c"; then
|
||||||
|
printf " %-3s %b %-6s %s\n" "$i" "$now" "$want" "${LABEL[$c]}"
|
||||||
|
else
|
||||||
|
printf " %b%-3s %-6s %-6s %s (not available)%b\n" "$c_dim" "$i" "$now" "$want" "${LABEL[$c]}" "$c_reset"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
echo -e "$KERNEL_OVERVIEW"
|
echo -e "$KERNEL_OVERVIEW"
|
||||||
@@ -76,28 +144,45 @@ run_menu() {
|
|||||||
draw_menu_tui() {
|
draw_menu_tui() {
|
||||||
local cursor="$1" i=0 c box state line
|
local cursor="$1" i=0 c box state line
|
||||||
printf '\033[H\033[2J'
|
printf '\033[H\033[2J'
|
||||||
echo -e "${c_bold}CachyOS Steam Deck-style Gamescope Boot Wizard${c_reset} v$VERSION"
|
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
|
||||||
echo "Pick what you want. Anything you untick is put back the way it was."
|
echo "Pick what you want. Anything you untick is put back the way it was."
|
||||||
echo
|
echo
|
||||||
MENU_ITEMS=()
|
MENU_ITEMS=()
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" || continue
|
menu_visible "$c" || continue
|
||||||
MENU_ITEMS[$i]=$c
|
MENU_ITEMS[$i]=$c
|
||||||
box="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && box="[${c_green}x${c_reset}]"
|
box="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && box="[${c_green}x${c_reset}]"
|
||||||
state="off"; [[ "${CURRENT[$c]}" == 1 ]] && state="${c_green}on${c_reset}"
|
state=" (now: off)"; [[ "${CURRENT[$c]}" == 1 ]] && state=" (now: ${c_green}on${c_reset})"
|
||||||
|
is_action "$c" && state=" (opt-in, runs once)"
|
||||||
line="$box ${LABEL[$c]}"
|
line="$box ${LABEL[$c]}"
|
||||||
if (( i == cursor )); then
|
if [[ "$c" == boot ]]; then
|
||||||
|
# A choice rather than a checkbox; Space switches it.
|
||||||
|
# Indented under the conversion, whose sub-option it is.
|
||||||
|
line="$(boot_choice "${WANTED[boot]}")"
|
||||||
|
line=" └ ${line/\[/[${c_green}}"; line="${line/\]/${c_reset}]}"
|
||||||
|
local mode=gamescope; [[ "${CURRENT[boot]}" == 1 ]] && mode=desktop
|
||||||
|
state=" (${c_bold}←/→${c_reset} choose)"
|
||||||
|
[[ "${CURRENT[gaming]}" == 1 ]] && state=" (now: $mode; ${c_bold}←/→${c_reset} choose)"
|
||||||
|
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
||||||
|
line=" └ $line"
|
||||||
|
fi
|
||||||
|
if ! component_selectable "$c"; then
|
||||||
|
# Greyed out: nothing to do (e.g. BIOS already up to date).
|
||||||
|
local mark=" "; (( i == cursor )) && mark=" ${c_cyan}>${c_reset} "
|
||||||
|
echo -e "${mark}${c_dim}[ ] ${LABEL[$c]} (not available)${c_reset}"
|
||||||
|
elif (( i == cursor )); then
|
||||||
# The green x's reset would end the bold too: re-enable it after.
|
# The green x's reset would end the bold too: re-enable it after.
|
||||||
echo -e " ${c_cyan}>${c_reset} ${c_bold}${line//"$c_reset"/"$c_reset$c_bold"}${c_reset} (now: ${state})"
|
echo -e " ${c_cyan}>${c_reset} ${c_bold}${line//"$c_reset"/"$c_reset$c_bold"}${c_reset}${state}"
|
||||||
else
|
else
|
||||||
echo -e " ${line} (now: ${state})"
|
echo -e " ${line}${state}"
|
||||||
fi
|
fi
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
echo -e "$KERNEL_OVERVIEW"
|
echo -e "$KERNEL_OVERVIEW"
|
||||||
echo
|
echo
|
||||||
echo -e " ${c_bold}Up/Down${c_reset} move ${c_bold}Space${c_reset} select ${c_bold}Enter${c_reset} run ${c_bold}a${c_reset} run + re-apply what's on ${c_bold}q${c_reset} quit"
|
echo -e " ${c_bold}Up/Down${c_reset} move ${c_bold}Space${c_reset} select ${c_bold}Left/Right${c_reset} choose ${c_bold}Enter${c_reset} run"
|
||||||
|
echo -e " ${c_bold}a${c_reset} run + re-apply what's on ${c_bold}q${c_reset} quit"
|
||||||
}
|
}
|
||||||
|
|
||||||
run_menu_tui() {
|
run_menu_tui() {
|
||||||
@@ -107,6 +192,8 @@ run_menu_tui() {
|
|||||||
while true; do
|
while true; do
|
||||||
draw_menu_tui "$cursor"
|
draw_menu_tui "$cursor"
|
||||||
count=${#MENU_ITEMS[@]}
|
count=${#MENU_ITEMS[@]}
|
||||||
|
# The list shrinks when the conversion (and its sub-option) is unticked.
|
||||||
|
if (( cursor >= count )); then cursor=$(( count - 1 )); draw_menu_tui "$cursor"; fi
|
||||||
IFS= read -rsn1 key
|
IFS= read -rsn1 key
|
||||||
if [[ "$key" == $'\e' ]]; then
|
if [[ "$key" == $'\e' ]]; then
|
||||||
IFS= read -rsn2 -t 0.05 rest
|
IFS= read -rsn2 -t 0.05 rest
|
||||||
@@ -116,6 +203,9 @@ run_menu_tui() {
|
|||||||
$'\e[A'|k) (( cursor = (cursor + count - 1) % count )) ;;
|
$'\e[A'|k) (( cursor = (cursor + count - 1) % count )) ;;
|
||||||
$'\e[B'|j) (( cursor = (cursor + 1) % count )) ;;
|
$'\e[B'|j) (( cursor = (cursor + 1) % count )) ;;
|
||||||
" ") toggle_component "${MENU_ITEMS[$cursor]}" ;;
|
" ") toggle_component "${MENU_ITEMS[$cursor]}" ;;
|
||||||
|
# On the "Boot into" row: left = gamescope, right = desktop.
|
||||||
|
$'\e[D'|h) [[ "${MENU_ITEMS[$cursor]}" == boot && "${WANTED[boot]}" == 1 ]] && toggle_component boot ;;
|
||||||
|
$'\e[C'|l) [[ "${MENU_ITEMS[$cursor]}" == boot && "${WANTED[boot]}" == 0 ]] && toggle_component boot ;;
|
||||||
"") break ;;
|
"") break ;;
|
||||||
a|A) REAPPLY=true; break ;;
|
a|A) REAPPLY=true; break ;;
|
||||||
q|Q) tput cnorm 2>/dev/null; echo; return 1 ;;
|
q|Q) tput cnorm 2>/dev/null; echo; return 1 ;;
|
||||||
@@ -137,7 +227,8 @@ run_menu_lines() {
|
|||||||
q|Q) return 1 ;;
|
q|Q) return 1 ;;
|
||||||
*)
|
*)
|
||||||
if [[ "$reply" =~ ^[0-9]+$ && -n "${MENU_ITEMS[$reply]:-}" ]]; then
|
if [[ "$reply" =~ ^[0-9]+$ && -n "${MENU_ITEMS[$reply]:-}" ]]; then
|
||||||
toggle_component "${MENU_ITEMS[$reply]}"
|
toggle_component "${MENU_ITEMS[$reply]}" ||
|
||||||
|
warn "Not available: ${LABEL[${MENU_ITEMS[$reply]}]}"
|
||||||
else
|
else
|
||||||
warn "Unknown choice: $reply"
|
warn "Unknown choice: $reply"
|
||||||
fi
|
fi
|
||||||
@@ -160,6 +251,7 @@ plan_changes() {
|
|||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" || continue
|
component_available "$c" || continue
|
||||||
[[ "${WANTED[$c]}" == 1 ]] || continue
|
[[ "${WANTED[$c]}" == 1 ]] || continue
|
||||||
|
if is_action "$c"; then TO_ENABLE+=("$c"); continue; fi
|
||||||
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] ||
|
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] ||
|
||||||
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
|
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
|
||||||
TO_ENABLE+=("$c")
|
TO_ENABLE+=("$c")
|
||||||
@@ -173,11 +265,14 @@ apply_changes() {
|
|||||||
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
|
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
|
||||||
|
|
||||||
for c in "${TO_DISABLE[@]}"; do
|
for c in "${TO_DISABLE[@]}"; do
|
||||||
echo; echo -e "${c_bold}Turning off: ${LABEL[$c]}${c_reset}"
|
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: gamescope${c_reset}"
|
||||||
|
else echo; echo -e "${c_bold}Turning off: ${LABEL[$c]}${c_reset}"; fi
|
||||||
"${c}_disable" || failed+=("$c")
|
"${c}_disable" || failed+=("$c")
|
||||||
done
|
done
|
||||||
for c in "${TO_ENABLE[@]}"; do
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"
|
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
||||||
|
elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
|
||||||
|
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
|
||||||
"${c}_enable" || failed+=("$c")
|
"${c}_enable" || failed+=("$c")
|
||||||
done
|
done
|
||||||
FAILED=("${failed[@]}")
|
FAILED=("${failed[@]}")
|
||||||
|
|||||||
+7
-2
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Required packages and AUR helper handling.
|
# Required packages and AUR helper handling.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
aur_noninteractive_flags() {
|
aur_noninteractive_flags() {
|
||||||
# Fully non-interactive install flags for the given AUR helper: no
|
# Fully non-interactive install flags for the given AUR helper: no
|
||||||
@@ -41,8 +41,13 @@ bootstrap_yay() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Build only, then install it ourselves: makepkg -i runs `sudo -k pacman`,
|
||||||
|
# which forgets the cached sudo password and asks for it again.
|
||||||
info "Building and installing yay (this runs makepkg as your user, not root)..."
|
info "Building and installing yay (this runs makepkg as your user, not root)..."
|
||||||
if (cd "$tmp_dir/yay-bin" && makepkg -si --noconfirm); then
|
local -a pkgs
|
||||||
|
if (cd "$tmp_dir/yay-bin" && makepkg --noconfirm) &&
|
||||||
|
mapfile -t pkgs < <(cd "$tmp_dir/yay-bin" && makepkg --packagelist | grep -v -- '-debug-') &&
|
||||||
|
sudo pacman -U --noconfirm "${pkgs[@]}"; then
|
||||||
ok "yay installed."
|
ok "yay installed."
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
+75
-1
@@ -3,12 +3,84 @@
|
|||||||
# log out, since typing a password with a controller is miserable. Goes
|
# log out, since typing a password with a controller is miserable. Goes
|
||||||
# together with SDDM (see lib/login-manager.sh). All changes are journaled
|
# 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.
|
# 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.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
single_status() {
|
single_status() {
|
||||||
[[ "$(kreadconfig6 --file kdeglobals --group "KDE Action Restrictions" --key action/lock_screen)" == false ]]
|
[[ "$(kreadconfig6 --file kdeglobals --group "KDE Action Restrictions" --key action/lock_screen)" == false ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WALLET_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/kwalletd"
|
||||||
|
# The user's own wallet while single user mode is on, and ours after.
|
||||||
|
WALLET_BACKUP=".bak-steamify"
|
||||||
|
WALLET_OURS=".steamify-single-user"
|
||||||
|
|
||||||
|
stop_kwallet() {
|
||||||
|
# The wallet daemon keeps the file open and would write it back.
|
||||||
|
local d
|
||||||
|
for d in kwalletd6 ksecretd; do
|
||||||
|
pkill -u "$USER" -x "$d" 2>/dev/null && sleep 1
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
single_wallet_enable() {
|
||||||
|
# Like SteamOS: an empty, password-less wallet (Valve's own file), so
|
||||||
|
# nothing asks for a wallet password (e.g. Brave at start): with
|
||||||
|
# autologin nobody typed the login password that unlocks the usual one.
|
||||||
|
# The user's wallet is moved aside and comes back when this is off. The
|
||||||
|
# wallet from an earlier time in single user mode is reused, with
|
||||||
|
# whatever was saved in it then.
|
||||||
|
local tmp f
|
||||||
|
if [[ -f "$WALLET_DIR/kdewallet.kwl$WALLET_OURS" ]]; then
|
||||||
|
stop_kwallet
|
||||||
|
for f in kdewallet.kwl kdewallet.salt; do
|
||||||
|
[[ -f "$WALLET_DIR/$f" && ! -e "$WALLET_DIR/$f$WALLET_BACKUP" ]] &&
|
||||||
|
mv "$WALLET_DIR/$f" "$WALLET_DIR/$f$WALLET_BACKUP"
|
||||||
|
[[ -f "$WALLET_DIR/$f$WALLET_OURS" ]] && mv -f "$WALLET_DIR/$f$WALLET_OURS" "$WALLET_DIR/$f"
|
||||||
|
done
|
||||||
|
kset single kwalletrc Wallet "First Use" false
|
||||||
|
ok "Single user mode's wallet (no password) is back; your own is kept as kdewallet.kwl$WALLET_BACKUP."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
if ! fetch_valve_presets "$tmp"; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
warn "Couldn't get Valve's empty wallet; apps may still ask for the wallet password."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ -f "$WALLET_DIR/kdewallet.kwl" ]] &&
|
||||||
|
cmp -s "$WALLET_DIR/kdewallet.kwl" "$tmp/usr/share/kwalletd/kdewallet.kwl"; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
stop_kwallet
|
||||||
|
mkdir -p "$WALLET_DIR"
|
||||||
|
for f in kdewallet.kwl kdewallet.salt; do
|
||||||
|
# Never overwrite an earlier backup: that one is the user's.
|
||||||
|
[[ -f "$WALLET_DIR/$f" && ! -e "$WALLET_DIR/$f$WALLET_BACKUP" ]] &&
|
||||||
|
mv "$WALLET_DIR/$f" "$WALLET_DIR/$f$WALLET_BACKUP"
|
||||||
|
install -m 600 "$tmp/usr/share/kwalletd/$f" "$WALLET_DIR/$f"
|
||||||
|
done
|
||||||
|
rm -rf "$tmp"
|
||||||
|
kset single kwalletrc Wallet "First Use" false
|
||||||
|
[[ -f "$WALLET_DIR/kdewallet.kwl$WALLET_BACKUP" ]] &&
|
||||||
|
info "Your wallet is kept as $WALLET_DIR/kdewallet.kwl$WALLET_BACKUP and comes back when single user mode is off."
|
||||||
|
ok "Empty wallet without a password: apps no longer ask for the wallet password."
|
||||||
|
}
|
||||||
|
|
||||||
|
single_wallet_disable() {
|
||||||
|
# The user's wallet back; ours (maybe with passwords saved since) is
|
||||||
|
# kept next to it.
|
||||||
|
[[ -f "$WALLET_DIR/kdewallet.kwl$WALLET_BACKUP" ]] || return 0
|
||||||
|
stop_kwallet
|
||||||
|
local f
|
||||||
|
for f in kdewallet.kwl kdewallet.salt; do
|
||||||
|
[[ -f "$WALLET_DIR/$f" ]] && mv -f "$WALLET_DIR/$f" "$WALLET_DIR/$f$WALLET_OURS"
|
||||||
|
[[ -f "$WALLET_DIR/$f$WALLET_BACKUP" ]] && mv "$WALLET_DIR/$f$WALLET_BACKUP" "$WALLET_DIR/$f"
|
||||||
|
done
|
||||||
|
ok "Your own wallet is back (the empty one is kept as kdewallet.kwl$WALLET_OURS)."
|
||||||
|
}
|
||||||
|
|
||||||
single_launcher() {
|
single_launcher() {
|
||||||
# Launcher: only Sleep / Restart / Shut Down, no Session dropdown (where
|
# Launcher: only Sleep / Restart / Shut Down, no Session dropdown (where
|
||||||
# Log Out lives). Restricting action/logout instead would also hide
|
# Log Out lives). Restricting action/logout instead would also hide
|
||||||
@@ -42,6 +114,7 @@ single_enable() {
|
|||||||
single_launcher
|
single_launcher
|
||||||
|
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
|
single_wallet_enable
|
||||||
ok "Single user: no lock screen, user switching or log out."
|
ok "Single user: no lock screen, user switching or log out."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,5 +143,6 @@ single_disable() {
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
|
single_wallet_disable
|
||||||
ok "KDE's normal lock screen and user switching are back."
|
ok "KDE's normal lock screen and user switching are back."
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
# off again exactly: the first time a component changes a key, the key's
|
# 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
|
# previous value is recorded, and reverting the component puts it back (or
|
||||||
# deletes the key if it didn't exist before).
|
# deletes the key if it didn't exist before).
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/cachyos-gamescope-boot"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/cachyos-gamescope-boot"
|
||||||
UNSET=$'\x01'
|
UNSET=$'\x01'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/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. Part of the SteamOS conversion (gaming_enable/gaming_disable).
|
# 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 steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
steam_enable() {
|
steam_enable() {
|
||||||
info "Applying non-optional SteamOS environment & keyboard fixes..."
|
info "Applying non-optional SteamOS environment & keyboard fixes..."
|
||||||
|
|||||||
+186
-5
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# "Steam Machine support" menu item, only on Valve Fremont hardware: the
|
# "Steam Machine support" menu item, only on Valve Fremont hardware: the
|
||||||
# front LED bar driver, LED access for Steam, and steamos-manager.
|
# 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 steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
detect_valve_fremont() {
|
detect_valve_fremont() {
|
||||||
# Valve Steam Machine (Fremont) boards. The leds-valve driver's own DMI
|
# Valve Steam Machine (Fremont) boards. The leds-valve driver's own DMI
|
||||||
@@ -14,16 +14,175 @@ detect_valve_fremont() {
|
|||||||
[[ "$vendor" == "OEM" && "$product" == "F7F" ]]
|
[[ "$vendor" == "OEM" && "$product" == "F7F" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Kernel pinned on a Steam Machine: with newer linux-cachyos releases it
|
||||||
|
# reboots instead of shutting down. The packages are kept in
|
||||||
|
# PINNED_KERNEL_DIR, so re-applying (or reinstalling after an update slipped
|
||||||
|
# through) needs no download.
|
||||||
|
PINNED_KERNEL_VER="7.1.6-1"
|
||||||
|
PINNED_KERNEL_KVER="7.1.6-1-cachyos"
|
||||||
|
PINNED_KERNEL_PKGS=(linux-cachyos linux-cachyos-headers)
|
||||||
|
PINNED_KERNEL_DIR="${PINNED_KERNEL_DIR:-/var/cache/steamify/kernel}"
|
||||||
|
# SHA-256 of each package, so a file from any source is the one reviewed
|
||||||
|
# here; its CachyOS signature is checked as well.
|
||||||
|
declare -A PINNED_KERNEL_SHA256=(
|
||||||
|
[linux-cachyos]=417fcd07102192b86e78e92ed7171d5a49378e9f57faea3fa2c7c541e9f68d08
|
||||||
|
[linux-cachyos-headers]=d069866a11d9092746e1d5133cefd8924f027da2c9bf5af38d30b3aed6ded9bf
|
||||||
|
)
|
||||||
|
# Tried in order, after the kernel dir and pacman's cache. Our own release
|
||||||
|
# always has these files; the archive keeps every release; the mirror only
|
||||||
|
# the current one. PINNED_KERNEL_URL puts another source (a directory
|
||||||
|
# holding the files) in front.
|
||||||
|
PINNED_KERNEL_SOURCES=(
|
||||||
|
${PINNED_KERNEL_URL:+"$PINNED_KERNEL_URL"}
|
||||||
|
"https://github.com/theupriser/steamify-cachyos/releases/download/kernel-$PINNED_KERNEL_VER"
|
||||||
|
"https://archive.cachyos.org/archive/cachyos"
|
||||||
|
"https://mirror.cachyos.org/repo/x86_64/cachyos"
|
||||||
|
)
|
||||||
|
|
||||||
|
pinned_kernel_installed() {
|
||||||
|
local p
|
||||||
|
for p in "${PINNED_KERNEL_PKGS[@]}"; do
|
||||||
|
[[ "$(pacman -Q "$p" 2>/dev/null)" == "$p $PINNED_KERNEL_VER" ]] || return 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch_pinned_kernel_file() {
|
||||||
|
# $1 = file name. Local kernel dir first, then pacman's cache, then the
|
||||||
|
# download sources. Downloads go to a .part file so a broken one is never
|
||||||
|
# mistaken for a finished one.
|
||||||
|
local f="$1" dest="$PINNED_KERNEL_DIR/$1" src
|
||||||
|
[[ -s "$dest" ]] && return 0
|
||||||
|
if [[ -s "/var/cache/pacman/pkg/$f" ]]; then
|
||||||
|
sudo cp "/var/cache/pacman/pkg/$f" "$dest" && return 0
|
||||||
|
fi
|
||||||
|
for src in "${PINNED_KERNEL_SOURCES[@]}"; do
|
||||||
|
if sudo curl -fL --retry 2 --connect-timeout 15 -o "$dest.part" "$src/$f" 2>/dev/null; then
|
||||||
|
sudo mv "$dest.part" "$dest"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
warn "Couldn't get $f from $src, trying the next source..."
|
||||||
|
done
|
||||||
|
sudo rm -f "$dest.part"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_pinned_kernel_pkg() {
|
||||||
|
# $1 = package name, $2 = file. Both checks must pass: the SHA-256 from
|
||||||
|
# this script, and the CachyOS signature (pacman on its own installs a
|
||||||
|
# local file without a .sig: LocalFileSigLevel = Optional).
|
||||||
|
local sum
|
||||||
|
sum="$(sha256sum "$2" | cut -d' ' -f1)"
|
||||||
|
if [[ "$sum" != "${PINNED_KERNEL_SHA256[$1]}" ]]; then
|
||||||
|
err "$(basename "$2") doesn't match its expected checksum."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! sudo pacman-key --verify "$2.sig" "$2" >/dev/null 2>&1; then
|
||||||
|
err "$(basename "$2") doesn't have a valid CachyOS signature."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pin_kernel_in_pacman_conf() {
|
||||||
|
# Adds our packages to IgnorePkg in [options], keeping what's there.
|
||||||
|
local p
|
||||||
|
for p in "${PINNED_KERNEL_PKGS[@]}"; do
|
||||||
|
grep -Eq "^IgnorePkg\s*=.*(\s|=)$p(\s|$)" /etc/pacman.conf && continue
|
||||||
|
if grep -Eq '^IgnorePkg\s*=' /etc/pacman.conf; then
|
||||||
|
sudo sed -i -E "0,/^IgnorePkg\s*=/s/^(IgnorePkg\s*=.*)$/\1 $p/" /etc/pacman.conf
|
||||||
|
else
|
||||||
|
sudo sed -i -E "0,/^\[options\]/s//[options]\nIgnorePkg = $p/" /etc/pacman.conf
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
unpin_kernel_in_pacman_conf() {
|
||||||
|
local p
|
||||||
|
for p in "${PINNED_KERNEL_PKGS[@]}"; do
|
||||||
|
sudo sed -i -E "/^IgnorePkg\s*=/s/\s$p(\s|$)/\1/" /etc/pacman.conf
|
||||||
|
done
|
||||||
|
# Drop the line if nothing is left on it.
|
||||||
|
sudo sed -i -E '/^IgnorePkg\s*=\s*$/d' /etc/pacman.conf
|
||||||
|
}
|
||||||
|
|
||||||
|
install_pinned_kernel() {
|
||||||
|
sudo mkdir -p "$PINNED_KERNEL_DIR"
|
||||||
|
pin_kernel_in_pacman_conf
|
||||||
|
if pinned_kernel_installed; then
|
||||||
|
ok "Kernel $PINNED_KERNEL_VER already installed and pinned."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local p f files=()
|
||||||
|
info "Getting kernel $PINNED_KERNEL_VER (kept in $PINNED_KERNEL_DIR)..."
|
||||||
|
for p in "${PINNED_KERNEL_PKGS[@]}"; do
|
||||||
|
f="$p-$PINNED_KERNEL_VER-x86_64.pkg.tar.zst"
|
||||||
|
fetch_pinned_kernel_file "$f" && fetch_pinned_kernel_file "$f.sig" ||
|
||||||
|
{ err "Couldn't download $f from any source."; return 1; }
|
||||||
|
if ! verify_pinned_kernel_pkg "$p" "$PINNED_KERNEL_DIR/$f"; then
|
||||||
|
# Removed, so the next run fetches it again.
|
||||||
|
sudo rm -f "$PINNED_KERNEL_DIR/$f" "$PINNED_KERNEL_DIR/$f.sig"
|
||||||
|
err "Removed it; run the wizard again to download it once more."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
files+=("$PINNED_KERNEL_DIR/$f")
|
||||||
|
done
|
||||||
|
|
||||||
|
# pacman checks each package against the .sig next to it.
|
||||||
|
info "Installing kernel $PINNED_KERNEL_VER..."
|
||||||
|
if ! sudo pacman -U --noconfirm "${files[@]}"; then
|
||||||
|
err "Installing kernel $PINNED_KERNEL_VER failed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
[[ "$(uname -r)" != "$PINNED_KERNEL_KVER" ]] && RESTART_FOR_LOGIN=true
|
||||||
|
ok "Kernel $PINNED_KERNEL_VER installed and pinned (restart to use it)."
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_kernel_pin() {
|
||||||
|
# Back to CachyOS's current kernel. The packages stay in
|
||||||
|
# PINNED_KERNEL_DIR, so turning support on again doesn't download.
|
||||||
|
unpin_kernel_in_pacman_conf
|
||||||
|
pinned_kernel_installed || return 0
|
||||||
|
info "Updating the kernel back to CachyOS's current version..."
|
||||||
|
sudo pacman -Syu --noconfirm ||
|
||||||
|
{ warn "Updating the kernel failed; run: sudo pacman -Syu"; return 0; }
|
||||||
|
RESTART_FOR_LOGIN=true
|
||||||
|
}
|
||||||
|
|
||||||
|
# "Pin the kernel" menu item, a sub-option of Steam Machine support.
|
||||||
|
kpin_status() {
|
||||||
|
pinned_kernel_installed && grep -Eq '^IgnorePkg\s*=.*\slinux-cachyos(\s|$)' /etc/pacman.conf
|
||||||
|
}
|
||||||
|
|
||||||
|
kpin_enable() {
|
||||||
|
install_pinned_kernel || return 1
|
||||||
|
# The DKMS pacman hook built leds-valve for the new headers; make sure.
|
||||||
|
if pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 &&
|
||||||
|
! dkms status -k "$PINNED_KERNEL_KVER" leds-valve-dkms 2>/dev/null | grep -q installed; then
|
||||||
|
sudo dkms install leds-valve-dkms/0.1 -k "$PINNED_KERNEL_KVER" ||
|
||||||
|
warn "Building the LED driver for $PINNED_KERNEL_KVER failed."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
kpin_disable() { remove_kernel_pin; }
|
||||||
|
|
||||||
install_kernel_headers() {
|
install_kernel_headers() {
|
||||||
# DKMS can only build leds-valve against kernels whose headers are
|
# DKMS can only build leds-valve against kernels whose headers are
|
||||||
# installed. CachyOS ships several kernels (linux-cachyos, -lts, -bore,
|
# installed. CachyOS ships several kernels (linux-cachyos, -lts, -bore,
|
||||||
# ...); install the matching -headers package for every one present.
|
# ...); install the matching -headers package for every one present.
|
||||||
local -a kernels headers=()
|
local -a kernels headers=()
|
||||||
mapfile -t kernels < <(pacman -Qqo /usr/lib/modules/*/pkgbase 2>/dev/null | sort -u)
|
|
||||||
local k
|
local k
|
||||||
|
mapfile -t kernels < <(pacman -Qqo /usr/lib/modules/*/pkgbase 2>/dev/null | sort -u)
|
||||||
|
# Installed headers are left alone: -S would update them past a pinned
|
||||||
|
# kernel (linux-cachyos-headers on a Steam Machine).
|
||||||
|
local have=0
|
||||||
for k in "${kernels[@]}"; do
|
for k in "${kernels[@]}"; do
|
||||||
|
pacman -Q "${k}-headers" >/dev/null 2>&1 && { have=$((have + 1)); continue; }
|
||||||
pacman -Si "${k}-headers" >/dev/null 2>&1 && headers+=("${k}-headers")
|
pacman -Si "${k}-headers" >/dev/null 2>&1 && headers+=("${k}-headers")
|
||||||
done
|
done
|
||||||
|
if [[ ${#headers[@]} -eq 0 && $have -gt 0 ]]; then
|
||||||
|
ok "Kernel headers already installed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
if [[ ${#headers[@]} -eq 0 ]]; then
|
if [[ ${#headers[@]} -eq 0 ]]; then
|
||||||
warn "Couldn't work out which kernel headers package you need."
|
warn "Couldn't work out which kernel headers package you need."
|
||||||
warn "Install the -headers package for your kernel (e.g. linux-cachyos-headers) yourself."
|
warn "Install the -headers package for your kernel (e.g. linux-cachyos-headers) yourself."
|
||||||
@@ -56,8 +215,13 @@ install_valve_led_driver() {
|
|||||||
# got the running kernel's tree and failed (wrong kernel, and gcc against
|
# got the running kernel's tree and failed (wrong kernel, and gcc against
|
||||||
# a clang-built tree). DKMS reads this override after the package's
|
# a clang-built tree). DKMS reads this override after the package's
|
||||||
# dkms.conf; written before the install so its own build works too.
|
# dkms.conf; written before the install so its own build works too.
|
||||||
printf '%s\n' "# Written by cachyos-gamescope-boot: build for DKMS's target kernel." \
|
# On a fresh system dkms isn't installed yet, so /etc/dkms doesn't exist.
|
||||||
'MAKE[0]="make KVERSION=${kernelver}"' | sudo tee "$LED_DKMS_OVERRIDE" >/dev/null
|
sudo mkdir -p "$(dirname "$LED_DKMS_OVERRIDE")"
|
||||||
|
if ! printf '%s\n' "# Written by cachyos-gamescope-boot: build for DKMS's target kernel." \
|
||||||
|
'MAKE[0]="make KVERSION=${kernelver}"' | sudo tee "$LED_DKMS_OVERRIDE" >/dev/null; then
|
||||||
|
err "Couldn't write $LED_DKMS_OVERRIDE; without it the LED driver only builds for the running kernel."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
if ! pacman -Qi leds-valve-dkms-git >/dev/null 2>&1; then
|
if ! pacman -Qi leds-valve-dkms-git >/dev/null 2>&1; then
|
||||||
info "Installing leds-valve-dkms-git from the AUR via $aur_helper (non-interactive)..."
|
info "Installing leds-valve-dkms-git from the AUR via $aur_helper (non-interactive)..."
|
||||||
@@ -87,6 +251,13 @@ install_valve_led_driver() {
|
|||||||
# Load now, and on every boot.
|
# Load now, and on every boot.
|
||||||
echo leds-valve | sudo tee /etc/modules-load.d/leds-valve.conf >/dev/null
|
echo leds-valve | sudo tee /etc/modules-load.d/leds-valve.conf >/dev/null
|
||||||
|
|
||||||
|
# The running kernel was just replaced (the kernel pin): its modules are
|
||||||
|
# gone, so the driver can only load after the restart.
|
||||||
|
if [[ ! -d "/usr/lib/modules/$(uname -r)/kernel" ]]; then
|
||||||
|
ok "The LED driver loads after the restart (into the new kernel)."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
info "Loading the leds-valve kernel module..."
|
info "Loading the leds-valve kernel module..."
|
||||||
if sudo modprobe leds-valve; then
|
if sudo modprobe leds-valve; then
|
||||||
ok "Module loaded."
|
ok "Module loaded."
|
||||||
@@ -163,7 +334,9 @@ kernel_overview() {
|
|||||||
local mark="${c_green}yes${c_reset}" miss="${c_red}no ${c_reset}" leds=false
|
local mark="${c_green}yes${c_reset}" miss="${c_red}no ${c_reset}" leds=false
|
||||||
detect_valve_fremont && command -v dkms >/dev/null 2>&1 && leds=true
|
detect_valve_fremont && command -v dkms >/dev/null 2>&1 && leds=true
|
||||||
local kdir k pkg headers hid led running line
|
local kdir k pkg headers hid led running line
|
||||||
echo -e " ${c_bold}Kernels${c_reset} (> = running; controller = Steam controller driver, LEDs = LED bar driver built)"
|
local legend="> = running; controller = Steam controller driver"
|
||||||
|
[[ "$leds" == true ]] && legend+=", LEDs = LED bar driver built"
|
||||||
|
echo -e " ${c_bold}Kernels${c_reset} ($legend)"
|
||||||
for kdir in /usr/lib/modules/*/; do
|
for kdir in /usr/lib/modules/*/; do
|
||||||
k="$(basename "$kdir")"
|
k="$(basename "$kdir")"
|
||||||
[[ -f "$kdir/pkgbase" ]] || continue
|
[[ -f "$kdir/pkgbase" ]] || continue
|
||||||
@@ -178,6 +351,7 @@ kernel_overview() {
|
|||||||
fi
|
fi
|
||||||
echo -e " ${running}${line}"
|
echo -e " ${running}${line}"
|
||||||
done
|
done
|
||||||
|
cec_installed && { echo; echo -e " $(cec_overview)"; }
|
||||||
if [[ "$leds" == true ]]; then
|
if [[ "$leds" == true ]]; then
|
||||||
local loaded="$miss" nodes
|
local loaded="$miss" nodes
|
||||||
lsmod | grep -q '^leds_valve' && loaded="$mark"
|
lsmod | grep -q '^leds_valve' && loaded="$mark"
|
||||||
@@ -194,6 +368,11 @@ machine_status() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
machine_enable() {
|
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.
|
||||||
|
if [[ "${WANTED[kpin]:-0}" == 1 ]]; then
|
||||||
|
install_pinned_kernel || { err "Couldn't set up kernel $PINNED_KERNEL_VER."; return 1; }
|
||||||
|
fi
|
||||||
ensure_aur_helper || { warn "Couldn't set up an AUR helper automatically. Install yay or paru, then run the wizard again."; return 1; }
|
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; }
|
install_valve_led_driver || { warn "LED driver setup ran into a problem - see errors above."; return 1; }
|
||||||
install_headers_boot_check
|
install_headers_boot_check
|
||||||
@@ -216,6 +395,8 @@ EOF
|
|||||||
sudo systemctl enable --now inputplumber.service
|
sudo systemctl enable --now inputplumber.service
|
||||||
sudo systemctl enable --now steamos-manager.service
|
sudo systemctl enable --now steamos-manager.service
|
||||||
systemctl --user enable steamos-manager.service 2>/dev/null
|
systemctl --user enable steamos-manager.service 2>/dev/null
|
||||||
|
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
|
||||||
|
cec_status && cec_link_steamos_manager
|
||||||
|
|
||||||
# Console-like power handling, as SteamOS's powerdevilrc (mains-power
|
# Console-like power handling, as SteamOS's powerdevilrc (mains-power
|
||||||
# part; there is no battery): the power button sleeps instead of showing
|
# part; there is no battery): the power button sleeps instead of showing
|
||||||
|
|||||||
+3
-13
@@ -3,10 +3,10 @@
|
|||||||
# newest Valve steamdeck-kde-presets package: "Add to Steam" (file
|
# newest Valve steamdeck-kde-presets package: "Add to Steam" (file
|
||||||
# right-click menu and launcher), Nested Desktop (Plasma as a game inside
|
# right-click menu and launcher), Nested Desktop (Plasma as a game inside
|
||||||
# gaming mode), the "Return to Gaming Mode" icon, the Steam Keyboard window
|
# gaming mode), the "Return to Gaming Mode" icon, the Steam Keyboard window
|
||||||
# rule and an empty KWallet. Part of the SteamOS theme component
|
# rule. Part of the SteamOS theme component
|
||||||
# (lib/vapor-theme.sh). System files go to /usr/local (nothing
|
# (lib/vapor-theme.sh). System files go to /usr/local (nothing
|
||||||
# package-owned); per-user settings go through the undo journal.
|
# package-owned); per-user settings go through the undo journal.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
VALVE_MIRROR="https://steamdeck-packages.steamos.cloud/archlinux-mirror"
|
VALVE_MIRROR="https://steamdeck-packages.steamos.cloud/archlinux-mirror"
|
||||||
NESTED_DIR=/usr/local/share/applications/steam/holo-nested-desktop
|
NESTED_DIR=/usr/local/share/applications/steam/holo-nested-desktop
|
||||||
@@ -75,15 +75,6 @@ extras_enable() {
|
|||||||
sudo cp -r "$src/share/applications/steam/holo-nested-desktop" "$NESTED_DIR"
|
sudo cp -r "$src/share/applications/steam/holo-nested-desktop" "$NESTED_DIR"
|
||||||
sudo sed -i "s|/usr/share/applications/steam/holo-nested-desktop|$NESTED_DIR|" "$NESTED_DIR/holo-nested-desktop.desktop"
|
sudo sed -i "s|/usr/share/applications/steam/holo-nested-desktop|$NESTED_DIR|" "$NESTED_DIR/holo-nested-desktop.desktop"
|
||||||
|
|
||||||
# An empty, password-less wallet (Valve's), so nothing asks for a wallet
|
|
||||||
# password: with autologin nobody typed one to unlock it. Only when the
|
|
||||||
# user has no wallet yet; an existing one is never touched.
|
|
||||||
local wallet="${XDG_DATA_HOME:-$HOME/.local/share}/kwalletd"
|
|
||||||
if [[ ! -f "$wallet/kdewallet.kwl" ]]; then
|
|
||||||
mkdir -p "$wallet"
|
|
||||||
install -m 600 "$src/share/kwalletd/kdewallet.kwl" "$src/share/kwalletd/kdewallet.salt" "$wallet/"
|
|
||||||
kset theme kwalletrc Wallet "First Use" false
|
|
||||||
fi
|
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
|
|
||||||
sudo gtk-update-icon-cache -q -f -t /usr/local/share/icons/hicolor 2>/dev/null || true
|
sudo gtk-update-icon-cache -q -f -t /usr/local/share/icons/hicolor 2>/dev/null || true
|
||||||
@@ -122,7 +113,6 @@ extras_disable() {
|
|||||||
for pkg in kdialog zstd curl; do
|
for pkg in kdialog zstd curl; do
|
||||||
[[ -n "$(state_get theme "installed_$pkg")" ]] && sudo pacman -R --noconfirm "$pkg" >/dev/null 2>&1
|
[[ -n "$(state_get theme "installed_$pkg")" ]] && sudo pacman -R --noconfirm "$pkg" >/dev/null 2>&1
|
||||||
done
|
done
|
||||||
# The keyboard rule and kwalletrc are reverted by the theme's journal.
|
# The keyboard rule is reverted by the theme's journal.
|
||||||
# The wallet itself stays: secrets may have been saved in it since.
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# SteamOS Vapor desktop theme, from CachyOS's cachyos-vapor package.
|
# SteamOS Vapor desktop theme, from CachyOS's cachyos-vapor package.
|
||||||
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
VAPOR_LOOKANDFEEL=com.valve.vapor.desktop
|
VAPOR_LOOKANDFEEL=com.valve.vapor.desktop
|
||||||
VAPOR_DEFAULTS=/usr/share/plasma/look-and-feel/$VAPOR_LOOKANDFEEL/contents/defaults
|
VAPOR_DEFAULTS=/usr/share/plasma/look-and-feel/$VAPOR_LOOKANDFEEL/contents/defaults
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "Steamify shortcut" menu item: a desktop icon and an app launcher entry that
|
||||||
|
# open the newest release of Steamify CachyOS in Konsole (curl | bash, like the
|
||||||
|
# install command in the README), so it's never out of date.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
WIZARD_RELEASE="https://github.com/theupriser/steamify-cachyos/releases/latest/download"
|
||||||
|
WIZARD_URL="$WIZARD_RELEASE/steamify.sh"
|
||||||
|
# Steam logo with a gear (assets/ in the repo, published with every release).
|
||||||
|
WIZARD_ICON="${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor/scalable/apps/cachyos-gamescope-boot-wizard.svg"
|
||||||
|
WIZARD_LAUNCHER="${XDG_DATA_HOME:-$HOME/.local/share}/cachyos-gamescope-boot/run-wizard"
|
||||||
|
WIZARD_DESKTOP_NAME="cachyos-gamescope-boot-wizard.desktop"
|
||||||
|
WIZARD_APP_ENTRY="${XDG_DATA_HOME:-$HOME/.local/share}/applications/$WIZARD_DESKTOP_NAME"
|
||||||
|
|
||||||
|
wizard_desktop_file() {
|
||||||
|
echo "$(xdg-user-dir DESKTOP 2>/dev/null || echo "$HOME/Desktop")/$WIZARD_DESKTOP_NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_executable() {
|
||||||
|
# install_executable <dest> <mode>: stdin to <dest>, with its mode set
|
||||||
|
# before it appears. Plasma treats a desktop icon it saw while it wasn't
|
||||||
|
# executable yet as untrusted and opens it in an editor.
|
||||||
|
local dest="$1" tmp
|
||||||
|
mkdir -p "$(dirname "$dest")"
|
||||||
|
tmp="$(mktemp "$(dirname "$dest")/.tmp.XXXXXX")"
|
||||||
|
cat > "$tmp"
|
||||||
|
chmod "$2" "$tmp"
|
||||||
|
mv -f "$tmp" "$dest"
|
||||||
|
}
|
||||||
|
|
||||||
|
launcher_status() {
|
||||||
|
[[ -x "$WIZARD_LAUNCHER" && -f "$WIZARD_APP_ENTRY" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
launcher_enable() {
|
||||||
|
info "Adding the Steamify shortcut (desktop icon and app launcher entry)..."
|
||||||
|
install_executable "$WIZARD_LAUNCHER" 755 << EOF
|
||||||
|
#!/bin/bash
|
||||||
|
# Installed by Steamify CachyOS: run its newest release.
|
||||||
|
# pipefail: a failed download must count as a failure, not an empty script.
|
||||||
|
set -o pipefail
|
||||||
|
if ! curl -fsSL --max-time 30 "$WIZARD_URL" | bash; then
|
||||||
|
echo
|
||||||
|
echo "Couldn't download or run the wizard. Are you connected to the internet?"
|
||||||
|
echo
|
||||||
|
read -rp "Press Enter to close this window... " _
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Done: close the window after a countdown (Enter closes it right away).
|
||||||
|
echo
|
||||||
|
for (( i = 10; i > 0; i-- )); do
|
||||||
|
printf '\rClosing this window in %2d seconds (Enter to close now)... ' "\$i"
|
||||||
|
read -rs -t 1 _ && break
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# The icon comes with the release; without it, Steam's own icon.
|
||||||
|
local icon=steam tmp
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
if curl -fsSL --max-time 20 "$WIZARD_RELEASE/steam-gaming-settings.svg" -o "$tmp" && grep -q '<svg' "$tmp"; then
|
||||||
|
install -D -m 644 "$tmp" "$WIZARD_ICON"
|
||||||
|
icon=cachyos-gamescope-boot-wizard
|
||||||
|
gtk-update-icon-cache -q -f -t "${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
warn "Couldn't download the shortcut's icon; using Steam's icon instead."
|
||||||
|
fi
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
local entry
|
||||||
|
entry="[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Steamify CachyOS
|
||||||
|
Comment=Turn the SteamOS-style parts of this PC on or off
|
||||||
|
Exec=konsole -e $WIZARD_LAUNCHER
|
||||||
|
Icon=$icon
|
||||||
|
Terminal=false
|
||||||
|
Categories=Game;System;Settings;"
|
||||||
|
printf '%s\n' "$entry" | install_executable "$WIZARD_APP_ENTRY" 644
|
||||||
|
printf '%s\n' "$entry" | install_executable "$(wizard_desktop_file)" 755
|
||||||
|
kbuildsycoca6 >/dev/null 2>&1 || true
|
||||||
|
ok "Steamify shortcut added: \"Steamify CachyOS\" on the desktop and in the launcher."
|
||||||
|
}
|
||||||
|
|
||||||
|
launcher_disable() {
|
||||||
|
rm -f "$(wizard_desktop_file)" "$WIZARD_APP_ENTRY" "$WIZARD_LAUNCHER" "$WIZARD_ICON"
|
||||||
|
rmdir "$(dirname "$WIZARD_LAUNCHER")" 2>/dev/null || true
|
||||||
|
kbuildsycoca6 >/dev/null 2>&1 || true
|
||||||
|
ok "Steamify shortcut removed."
|
||||||
|
}
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# setup-gamescope-boot.sh
|
|
||||||
#
|
|
||||||
# Wizard that makes a CachyOS (KDE Plasma) install behave like SteamOS:
|
|
||||||
# boot into a Steam Deck-style gamescope session, switch to the Plasma
|
|
||||||
# desktop and back, and reset to gamescope on the next boot/logout.
|
|
||||||
#
|
|
||||||
# It opens with a menu that detects which components are on and turns
|
|
||||||
# them on or off to match what the user picks; turning one off restores
|
|
||||||
# what was there before (system files from .bak-gamescope-wizard backups,
|
|
||||||
# KDE settings from the undo journal in lib/state.sh). Components live in
|
|
||||||
# lib/, see README.md. Safe to re-run.
|
|
||||||
|
|
||||||
set -uo pipefail
|
|
||||||
|
|
||||||
# Release version, see CHANGELOG.md.
|
|
||||||
VERSION=0.7.0
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
|
|
||||||
for lib in common state packages login-manager single-user steam-desktop steam-machine vapor-theme steamos-extras desktop-shortcut menu; do
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source "$SCRIPT_DIR/lib/$lib.sh"
|
|
||||||
done
|
|
||||||
|
|
||||||
require_root_helper
|
|
||||||
|
|
||||||
echo -e "${c_bold}CachyOS Steam Deck-style Gamescope Boot Wizard${c_reset} v$VERSION"
|
|
||||||
echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
|
|
||||||
echo "anything you turn off is put back the way it was."
|
|
||||||
|
|
||||||
if ! command -v pacman >/dev/null 2>&1; then
|
|
||||||
err "This doesn't look like an Arch/CachyOS system (no pacman found). Aborting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Everything per-user (autologin user, Steam, theme, shortcut) is for the
|
|
||||||
# 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
|
|
||||||
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
|
|
||||||
|
|
||||||
apply_changes
|
|
||||||
|
|
||||||
echo
|
|
||||||
detect_components
|
|
||||||
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
|
|
||||||
echo
|
|
||||||
|
|
||||||
# Login manager changes only take effect after a restart.
|
|
||||||
if [[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]]; then
|
|
||||||
if ask_yn "Restart now so the changes take effect?" n; then
|
|
||||||
sudo reboot
|
|
||||||
else
|
|
||||||
info "Restart whenever you're ready."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
Executable
+170
@@ -0,0 +1,170 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# steamify.sh - Steamify CachyOS
|
||||||
|
#
|
||||||
|
# Wizard that makes a CachyOS (KDE Plasma) install behave like SteamOS:
|
||||||
|
# boot into a Steam Deck-style gamescope session, switch to the Plasma
|
||||||
|
# desktop and back, and reset to gamescope on the next boot/logout.
|
||||||
|
#
|
||||||
|
# It opens with a menu that detects which components are on and turns
|
||||||
|
# them on or off to match what the user picks; turning one off restores
|
||||||
|
# what was there before (system files from .bak-gamescope-wizard backups,
|
||||||
|
# KDE settings from the undo journal in lib/state.sh). Components live in
|
||||||
|
# lib/, see TECHNICAL.md. Safe to re-run.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
# Release version, see CHANGELOG.md.
|
||||||
|
VERSION=1.1.3
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
for lib in common state packages login-manager single-user steam-desktop steam-machine cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut menu; do
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$SCRIPT_DIR/lib/$lib.sh"
|
||||||
|
done
|
||||||
|
|
||||||
|
require_root_helper
|
||||||
|
|
||||||
|
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
|
||||||
|
echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
|
||||||
|
echo "anything you turn off is put back the way it was."
|
||||||
|
|
||||||
|
if ! command -v pacman >/dev/null 2>&1; then
|
||||||
|
err "This doesn't look like an Arch/CachyOS system (no pacman found). Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Everything per-user (autologin user, Steam, theme, shortcut) is for the
|
||||||
|
# user running the script.
|
||||||
|
TARGET_USER="$(id -un)"
|
||||||
|
|
||||||
|
restart_needed() { [[ -n "${BIOS_NEEDS_RESTART:-}" || "$RESTART_FOR_LOGIN" == true ]]; }
|
||||||
|
|
||||||
|
restart_now() {
|
||||||
|
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
|
||||||
|
warn "The BIOS update is written during this restart. Keep the power on and don't"
|
||||||
|
warn "touch the machine until it has fully started again, even if the screen stays black."
|
||||||
|
fi
|
||||||
|
if [[ -n "${BIOS_DRY_RUN:-}" ]]; then
|
||||||
|
ok "Dry run: would restart now (sudo reboot); not restarting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
info "Restarting..."
|
||||||
|
sudo reboot
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
after_run() {
|
||||||
|
# After a run: back to the menu, or restart right away when something
|
||||||
|
# that just ran needs it. Returns 1 when input has ended (scripted runs).
|
||||||
|
local reply
|
||||||
|
if ! restart_needed; then
|
||||||
|
read -rp "Press Enter to go back to the menu... " _ || return 1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
|
||||||
|
warn "The BIOS update is installed at the next restart."
|
||||||
|
else
|
||||||
|
info "The login changes take effect after a restart."
|
||||||
|
fi
|
||||||
|
while true; do
|
||||||
|
read -rp "$(echo -e "${c_bold}[m]${c_reset} back to the menu ${c_bold}[r]${c_reset} restart now: ")" reply || return 1
|
||||||
|
case "$reply" in
|
||||||
|
m|M|"") return 0 ;;
|
||||||
|
r|R) restart_now ;;
|
||||||
|
*) warn "Type m or r." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
quit_prompt() {
|
||||||
|
# On q: when something needs a restart, offer it (default yes); "n" goes
|
||||||
|
# back to the menu, and the next q asks again. Returns 0 to show the menu
|
||||||
|
# again, 1 to quit (nothing to restart, or input ended in scripted runs).
|
||||||
|
local reply
|
||||||
|
restart_needed || return 1
|
||||||
|
echo
|
||||||
|
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
|
||||||
|
warn "The BIOS update is written during the next restart. Keep the power on and"
|
||||||
|
warn "don't touch the machine until it has fully started again, even if the screen stays black."
|
||||||
|
else
|
||||||
|
info "The changes take effect after a restart."
|
||||||
|
fi
|
||||||
|
read -rp "$(echo -e "${c_bold}Restart now?${c_reset} [Y/n] (n = back to the menu, Ctrl+C = quit without restarting) ")" reply || return 1
|
||||||
|
case "$reply" in
|
||||||
|
""|y|Y) restart_now ;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Menu loop: after each run the menu comes back with the new state, until
|
||||||
|
# the user quits; the restart question comes then, once, for everything.
|
||||||
|
RESTART_FOR_LOGIN=false
|
||||||
|
SUDO_KEEPALIVE=false
|
||||||
|
while true; do
|
||||||
|
detect_components
|
||||||
|
if ! run_menu; then
|
||||||
|
quit_prompt && continue
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
plan_changes
|
||||||
|
|
||||||
|
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
|
||||||
|
ok "Everything is already the way you want it."
|
||||||
|
read -rp "Press Enter to go back to the menu... " _ || break
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${c_bold}This will:${c_reset}"
|
||||||
|
for c in "${TO_DISABLE[@]}"; do
|
||||||
|
if [[ "$c" == boot ]]; then echo " - boot into: gamescope (from the next boot)"
|
||||||
|
else echo " - turn off: ${LABEL[$c]}"; fi
|
||||||
|
done
|
||||||
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
|
if [[ "$c" == boot ]]; then echo " - boot into: desktop (from the next boot)"
|
||||||
|
elif is_action "$c"; then echo " - run: ${LABEL[$c]%%:*} at your own risk (checks, then asks twice more)"
|
||||||
|
elif [[ "${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."; continue; }
|
||||||
|
|
||||||
|
# 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
|
||||||
|
if [[ "$SUDO_KEEPALIVE" == false ]]; then
|
||||||
|
SUDO_KEEPALIVE=true
|
||||||
|
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
|
||||||
|
fi
|
||||||
|
|
||||||
|
apply_changes
|
||||||
|
# Login manager changes only take effect after a restart.
|
||||||
|
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " =~ \ (gaming|single|boot|kpin)\ ]] &&
|
||||||
|
RESTART_FOR_LOGIN=true
|
||||||
|
|
||||||
|
echo
|
||||||
|
detect_components
|
||||||
|
echo -e "${c_bold}Done. Current state:${c_reset}"
|
||||||
|
for c in "${COMPONENTS[@]}"; do
|
||||||
|
component_available "$c" && ! is_action "$c" || continue
|
||||||
|
if [[ "$c" == boot ]]; then
|
||||||
|
[[ "${CURRENT[gaming]}" == 1 ]] && echo " └ boots into: $(boot_mode "${CURRENT[boot]}")"
|
||||||
|
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
||||||
|
[[ "${CURRENT[${PARENT[$c]}]}" == 1 ]] || continue
|
||||||
|
if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " └ ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " └ off ${LABEL[$c]}"; fi
|
||||||
|
elif [[ "${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
|
||||||
|
echo
|
||||||
|
after_run || break
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
if restart_needed; then
|
||||||
|
# Only reached when input ended (scripted runs): never restart then.
|
||||||
|
info "Not restarted; the changes take effect after a restart."
|
||||||
|
else
|
||||||
|
info "Bye."
|
||||||
|
fi
|
||||||
Reference in new issue
Block a user