mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-03 17:41:58 +02:00
Compare commits
312
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac0e5e28b3 | ||
|
|
095e7bca5c | ||
|
|
18e06797b3 | ||
|
|
6080cd7491 | ||
|
|
dd863a3402 | ||
|
|
99f7fea4d1 | ||
|
|
272e073784 | ||
|
|
00c7a365a3 | ||
|
|
bce24f3356 | ||
|
|
a85f29a0fc | ||
|
|
949873f14a | ||
|
|
f183c1cf8e | ||
|
|
398910b1e1 | ||
|
|
7151bddedd | ||
|
|
67cbf986f7 | ||
|
|
280468e5a7 | ||
|
|
8a355721dd | ||
|
|
9da15a183f | ||
|
|
f3f29473ac | ||
|
|
3398582d13 | ||
|
|
59ea0cb22b | ||
|
|
0e7a2b67a3 | ||
|
|
c1bed4a0a4 | ||
|
|
af665d0690 | ||
|
|
3a81198cf6 | ||
|
|
e708c6d545 | ||
|
|
3cae62292b | ||
|
|
033dbf1a67 | ||
|
|
97a9b43dd4 | ||
|
|
456b5ca883 | ||
|
|
23aaf0a344 | ||
|
|
71bd3b4573 | ||
|
|
47229e1ab7 | ||
|
|
880fb900a3 | ||
|
|
814c48c7a7 | ||
|
|
d5e3701883 | ||
|
|
58de009297 | ||
|
|
b5a9b7aa0e | ||
|
|
4e5b7753af | ||
|
|
99777128f1 | ||
|
|
48aac0fb68 | ||
|
|
f9522d21f3 | ||
|
|
7a6df40c43 | ||
|
|
8e5ea9d430 | ||
|
|
cfa44c7cca | ||
|
|
a49e8a9b6a | ||
|
|
0f5f2ab893 | ||
|
|
209446744b | ||
|
|
218e141670 | ||
|
|
b3c74f392f | ||
|
|
6f79dca05c | ||
|
|
439b632d71 | ||
|
|
80b1fac9c1 | ||
|
|
3eb22502ec | ||
|
|
948dc1f587 | ||
|
|
76cf1b4adb | ||
|
|
4092fdc9ee | ||
|
|
b5c86e1e72 | ||
|
|
1b7e2e8842 | ||
|
|
30b315e678 | ||
|
|
68d28b95ed | ||
|
|
5aa4c65254 | ||
|
|
799f5abcca | ||
|
|
ad6cf26521 | ||
|
|
d354eace93 | ||
|
|
71f11a9f8a | ||
|
|
414b73388e | ||
|
|
ee487e1763 | ||
|
|
6d6b41f55e | ||
|
|
b8477432b5 | ||
|
|
c697c29c39 | ||
|
|
2321f41195 | ||
|
|
f708488c3e | ||
|
|
ad0b9cae21 | ||
|
|
9b560e0bf1 | ||
|
|
b597a94554 | ||
|
|
dcb7a8005d | ||
|
|
eaebebf89e | ||
|
|
10b82ec35d | ||
|
|
23b3954adf | ||
|
|
d12fa45594 | ||
|
|
af3659d607 | ||
|
|
8173ea7527 | ||
|
|
b2bf2f836b | ||
|
|
f6a8aff25b | ||
|
|
d2ead64ab2 | ||
|
|
52b096067b | ||
|
|
088e6acfe3 | ||
|
|
6cf4142878 | ||
|
|
654755f826 | ||
|
|
e5ac602e6e | ||
|
|
6aac821ed9 | ||
|
|
b613114d7a | ||
|
|
4e0f3a3de6 | ||
|
|
87e510dfbe | ||
|
|
cea9186d64 | ||
|
|
9958843e84 | ||
|
|
f2d6fa1cc0 | ||
|
|
e24c81dcc6 | ||
|
|
ef3436028d | ||
|
|
a66f8724e6 | ||
|
|
548f9c5e9a | ||
|
|
eeb47bac0a | ||
|
|
eaa88884ce | ||
|
|
441f95d60c | ||
|
|
331a9a661c | ||
|
|
2e4c5d36b0 | ||
|
|
e0ac9464e4 | ||
|
|
8da6a56804 | ||
|
|
394facb226 | ||
|
|
fa181e3fee | ||
|
|
e3ffea1c33 | ||
|
|
df797950e0 | ||
|
|
bb8fa3d6bd | ||
|
|
f0642ca372 | ||
|
|
fd4fe0c8b8 | ||
|
|
cc4b4a282d | ||
|
|
1df407d8f6 | ||
|
|
f059112169 | ||
|
|
c130918935 | ||
|
|
3358b0c162 | ||
|
|
5c16e8bb84 | ||
|
|
bdeb797b5b | ||
|
|
65841a45a1 | ||
|
|
ce71c1518b | ||
|
|
311f8ba0cd | ||
|
|
5cea90926a | ||
|
|
6eb4a5a1e4 | ||
|
|
fa96a243e6 | ||
|
|
1da4558f89 | ||
|
|
0ffd0f957a | ||
|
|
8bb705699f | ||
|
|
6095aff379 | ||
|
|
3a7db6f5f6 | ||
|
|
8578c39ceb | ||
|
|
074475b524 | ||
|
|
9049586a0e | ||
|
|
70a01d7087 | ||
|
|
fadfd1d0a9 | ||
|
|
b59ab1b464 | ||
|
|
52548b5d43 | ||
|
|
6e87a00bf3 | ||
|
|
9a796f0a54 | ||
|
|
53b536ac2b | ||
|
|
21a3251af5 | ||
|
|
c378b0ad63 | ||
|
|
0432d5470c | ||
|
|
9ae1388f88 | ||
|
|
3f9b9abc06 | ||
|
|
e615b27654 | ||
|
|
46f194e105 | ||
|
|
1830bea979 | ||
|
|
6a2030bb78 | ||
|
|
257cde113c | ||
|
|
3e2da4925c | ||
|
|
7c125e8c1c | ||
|
|
9c74195f8a | ||
|
|
0b90e91522 | ||
|
|
59747baa2b | ||
|
|
6b6480efdf | ||
|
|
540549b828 | ||
|
|
ad3b872437 | ||
|
|
f157a799a1 | ||
|
|
da73762e6d | ||
|
|
3cf1947638 | ||
|
|
d8e26542a7 | ||
|
|
db7b2eb11c | ||
|
|
26139f3e0e | ||
|
|
ce93da67df | ||
|
|
77f724e547 | ||
|
|
aee51b9bf1 | ||
|
|
59c746b3fe | ||
|
|
50b50cb726 | ||
|
|
66dd04799b | ||
|
|
75f8e868d3 | ||
|
|
8062e5374e | ||
|
|
8ec1632704 | ||
|
|
cde0188c3d | ||
|
|
d683c30895 | ||
|
|
268c2f96b2 | ||
|
|
bbc742940c | ||
|
|
7381b62af9 | ||
|
|
ca500c995f | ||
|
|
e2ad40dfb9 | ||
|
|
0883e7a501 | ||
|
|
de70fad000 | ||
|
|
7a73247f79 | ||
|
|
1d98aa3ee0 | ||
|
|
7268c77c80 | ||
|
|
73b70e1b12 | ||
|
|
35b7a4d72e | ||
|
|
1cfaa4ef4d | ||
|
|
aad1e3254c | ||
|
|
794e94ea89 | ||
|
|
dfacf3306b | ||
|
|
f774b79007 | ||
|
|
91128917c8 | ||
|
|
a087757dc7 | ||
|
|
83dcad1622 | ||
|
|
64536fe531 | ||
|
|
c4280ecf60 | ||
|
|
956b712099 | ||
|
|
24f15421fd | ||
|
|
a252d38c7c | ||
|
|
dc1abd912b | ||
|
|
40a121f4d1 | ||
|
|
2fa347be73 | ||
|
|
38642dc6db | ||
|
|
997cd0744d | ||
|
|
28555175bb | ||
|
|
321bf9bfcb | ||
|
|
443dbcdfb8 | ||
|
|
b2c4a0a00a | ||
|
|
a4781d4e39 | ||
|
|
617f5aa613 | ||
|
|
8840e24d1a | ||
|
|
2149adf995 | ||
|
|
eb8d06879d | ||
|
|
5d03b2a214 | ||
|
|
02872423ac | ||
|
|
69e184c303 | ||
|
|
66213f55de | ||
|
|
4c3186109f | ||
|
|
441a931540 | ||
|
|
5efe448a51 | ||
|
|
881330c3a6 | ||
|
|
fe6798d951 | ||
|
|
17cbb6ed1c | ||
|
|
e9cd578c9b | ||
|
|
3974481e9e | ||
|
|
bb07d4a5d1 | ||
|
|
4dffcef60f | ||
|
|
f28e880c04 | ||
|
|
b9999182d5 | ||
|
|
7060a6dae1 | ||
|
|
57ec2726cb | ||
|
|
ad3e7ac80e | ||
|
|
fdb49f2503 | ||
|
|
0c99ba325d | ||
|
|
23a171c937 | ||
|
|
232b51e379 | ||
|
|
387991dff3 | ||
|
|
224aede84b | ||
|
|
9802beb8d8 | ||
|
|
b13466ada8 | ||
|
|
3f5c8b28b0 | ||
|
|
17be6bdb18 | ||
|
|
d211e09795 | ||
|
|
6c2a1bef55 | ||
|
|
fac9277206 | ||
|
|
eb5a088f03 | ||
|
|
2aa5751ec0 | ||
|
|
58f156c6ae | ||
|
|
7ad20956a3 | ||
|
|
7ab275d82b | ||
|
|
31e438673b | ||
|
|
8eaf3353f5 | ||
|
|
d9d4f3e3f8 | ||
|
|
72a18232a5 | ||
|
|
ebbc70b213 | ||
|
|
d3496bbd02 | ||
|
|
ebfffe81e7 | ||
|
|
3e3ededc62 | ||
|
|
e68776b454 | ||
|
|
d296f20cac | ||
|
|
66286744df | ||
|
|
e50cc6fc92 | ||
|
|
8975346019 | ||
|
|
b81e30babf | ||
|
|
0a17f2a336 | ||
|
|
c862da789f | ||
|
|
942de7f615 | ||
|
|
438e6aeacd | ||
|
|
bee06251c1 | ||
|
|
40dfaee0b5 | ||
|
|
cda7dbe49f | ||
|
|
176f27b44f | ||
|
|
102cc97893 | ||
|
|
af9638ec06 | ||
|
|
38c7c98eed | ||
|
|
00b863fc9e | ||
|
|
f3955c438c | ||
|
|
0b4a1555b7 | ||
|
|
0607be86ac | ||
|
|
528f46a35e | ||
|
|
c82af166e4 | ||
|
|
69ac9d3b7b | ||
|
|
7382ca6be3 | ||
|
|
207c62e12f | ||
|
|
0c50170a37 | ||
|
|
0cb9f8b9ca | ||
|
|
2e6d20a3f0 | ||
|
|
68981821a3 | ||
|
|
fe20a7d871 | ||
|
|
176bd52957 | ||
|
|
eacc6368db | ||
|
|
b306a72255 | ||
|
|
b2858d3d60 | ||
|
|
04891ee2cd | ||
|
|
b0563e0b30 | ||
|
|
b469324fbd | ||
|
|
2d80e16e6f | ||
|
|
9d27239d00 | ||
|
|
259a72068a | ||
|
|
c797bff322 | ||
|
|
130998345a | ||
|
|
4719fd8e64 | ||
|
|
58345cfbe8 | ||
|
|
f845952462 | ||
|
|
c3eae54477 | ||
|
|
060d545f1e | ||
|
|
221c97f958 |
No files matched your search
@@ -0,0 +1,15 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{yml,yaml,qml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
bash -n dist/steamify.sh
|
bash -n dist/steamify.sh
|
||||||
python3 -m py_compile ui/steamify-ui
|
python3 -c 'import ast, sys; [ast.parse(open(f).read(), f) for f in sys.argv[1:]]' ui/steamify-ui patches/*.py
|
||||||
|
|
||||||
# shellcheck through an action that brings its own binary: GitHub's runner has it installed,
|
# shellcheck through an action that brings its own binary: GitHub's runner has it installed,
|
||||||
# Gitea's act_runner image doesn't. One file per run, as before (the exceptions are the bundle's).
|
# Gitea's act_runner image doesn't. One file per run, as before (the exceptions are the bundle's).
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Lint: shell, Python and QML. Separate from bundle.yml (which builds and
|
||||||
|
# releases) so a style problem shows up as its own check. Runs on GitHub and on
|
||||||
|
# the Gitea mirror; the same checks locally: make check.
|
||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, 'release/**']
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
shell:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# The sources, not only the bundle (bundle.yml checks that): .shellcheckrc
|
||||||
|
# lists the exceptions (variables shared across modules).
|
||||||
|
- name: shellcheck the modules
|
||||||
|
uses: ludeeus/action-shellcheck@2.0.0
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
scandir: lib
|
||||||
|
additional_files: steamify.sh ui/steamify-app.sh .github/tools/bundle.sh
|
||||||
|
# steamify-os-release.sh is a template (@STEAMOS@ is filled in at install time).
|
||||||
|
- name: shellcheck the helper scripts
|
||||||
|
uses: ludeeus/action-shellcheck@2.0.0
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
scandir: patches
|
||||||
|
ignore_names: steamify-os-release.sh
|
||||||
|
|
||||||
|
python:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: ruff (ruff.toml)
|
||||||
|
uses: astral-sh/ruff-action@v4.1.0
|
||||||
|
with:
|
||||||
|
args: check ui/steamify-ui patches
|
||||||
|
|
||||||
|
qml:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Not blocking until it has run once on the runner image (Qt packages).
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install qmllint and the QML modules the app imports
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq qt6-declarative-dev-tools qml6-module-qtquick qml6-module-qtquick-controls qml6-module-qtquick-window
|
||||||
|
# "unqualified" (a screen reading `app` from its parent) is how the screens get their
|
||||||
|
# AppState, so it is off; everything else must be clean.
|
||||||
|
- name: qmllint
|
||||||
|
run: |
|
||||||
|
lint="$(command -v qmllint6 || echo /usr/lib/qt6/bin/qmllint)"
|
||||||
|
"$lint" --unqualified disable --max-warnings 0 ui/qml/*.qml
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# The modules share variables across files once bundled (see AGENTS.md).
|
||||||
|
disable=SC2034,SC2154
|
||||||
@@ -47,7 +47,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
idempotent. `<id>_enable` is also used to re-apply. Optional
|
idempotent. `<id>_enable` is also used to re-apply. Optional
|
||||||
`<id>_available` is checked via `component_available` (e.g. `machine`
|
`<id>_available` is checked via `component_available` (e.g. `machine`
|
||||||
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
|
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
|
||||||
`gaming` must stay first. Dependencies live in `toggle_component`.
|
`gaming` must stay first. Dependencies are the `REQUIRES`, `FOLLOWS` and `EXCLUDES` tables in `lib/menu.sh`, used by `toggle_component` (the menu) and `normalize_wanted` (the app).
|
||||||
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
|
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
|
||||||
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
|
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
|
||||||
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
|
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
|
||||||
@@ -90,6 +90,16 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
|
|
||||||
- Bash, `set -uo pipefail` (no `-e`): check exit codes of steps that matter
|
- Bash, `set -uo pipefail` (no `-e`): check exit codes of steps that matter
|
||||||
explicitly (`|| { err ...; exit 1; }` or `|| return 1`).
|
explicitly (`|| { err ...; exit 1; }` or `|| return 1`).
|
||||||
|
- **Failure and quiet steps.** A function returns 0 when what it was asked
|
||||||
|
to do is in place and 1 when it isn't (after `err`); a step that is only an
|
||||||
|
extra (an icon cache, a service that may not exist) warns or stays silent and
|
||||||
|
doesn't change the return value. Never `cmd 2>/dev/null` on a step that
|
||||||
|
changes the system: use `best_effort cmd...` (same exit status, its errors go
|
||||||
|
to `$STATE_DIR/log/steamify.log`). `2>/dev/null` stays for probes (`pacman -Q`,
|
||||||
|
`grep -q`, `is-active`) whose failure is the answer.
|
||||||
|
- **Temp dirs.** `make_tmpdir <variable>` (not `$(mktemp -d)`, whose
|
||||||
|
subshell can't register it): the entry point's `on_exit` removes them, also
|
||||||
|
when a run stops half way. That handler is the only `EXIT` trap.
|
||||||
- Use the helpers from `lib/common.sh` (`info`, `ok`, `warn`, `err`,
|
- Use the helpers from `lib/common.sh` (`info`, `ok`, `warn`, `err`,
|
||||||
`ask_yn`, `backup_file`) for all output and prompts.
|
`ask_yn`, `backup_file`) for all output and prompts.
|
||||||
- Runs as the normal user; use `sudo` per command, never require root.
|
- Runs as the normal user; use `sudo` per command, never require root.
|
||||||
|
|||||||
+25
-1
@@ -5,9 +5,33 @@ All notable changes, per version and per commit. Versions follow
|
|||||||
`steamify.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.
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- **refactor: Valve's package mirror in one module (`lib/valve-mirror.sh`: newest repo, package database fields, checksummed download); the SteamOS extras, CEC driver, BIOS lookup and os-release version used four copies**
|
||||||
|
- **refactor: the rules between menu items are three tables (`REQUIRES`, `FOLLOWS`, `EXCLUDES` in `lib/menu.sh`) used by the menu's toggles and, as `normalize_wanted`, by the app's selection (it had its own copy of the rules). The app now also ticks the Steamify shortcut for "Add as non-Steam game" and unticks the game entry with it, like the menu**
|
||||||
|
- **refactor: the entry point picks its mode once (`MODE`) and `--defaults` and `--boot` are functions with one failure report, instead of four booleans and two copies of the apply-and-report code; `NO_COLOR` gives plain output**
|
||||||
|
- **refactor: `is_wanted` and `is_current` instead of repeated `[[ "${WANTED[x]}" == 1 ]]` checks in the menu, the app's backend and the entry point**
|
||||||
|
- **refactor: the start of every item's JSON (id, label, hint, kind, parent) is built in one place (`json_item_head`) for the app and the installer page, and `json_bool` replaces the `&& echo true || echo false` copies**
|
||||||
|
- **ci: a Lint workflow runs shellcheck on the modules and helper scripts, ruff on the app and `patches/*.py` (`ruff.toml`) and qmllint on the QML (not blocking until it has run once on the runner); `make lint` runs the same locally**
|
||||||
|
- **refactor: `best_effort` for the steps whose failure doesn't matter (stopping or disabling units, removing packages, `modprobe -r`, ...): same behaviour, but their errors go to `~/.local/state/steamify/log/steamify.log` instead of `/dev/null`; temp dirs are registered with `make_tmpdir` and removed by the one exit handler (also when a run is interrupted), which replaces the menu's own `EXIT` trap**
|
||||||
|
- **refactor: the retired kernel pin moved out of `lib/steam-machine.sh` into `lib/kernel-pin.sh`**
|
||||||
|
- **refactor: the shortcut's two start scripts are files in `patches/` (`steamify-start.sh`, `steamify-app-start.sh`) instead of heredocs in `launcher_enable`, and the 83-line LED driver install is split into steps (`led_write_dkms_override`, `led_install_package`, `led_build_all_kernels`, `led_load_module`); what gets installed is byte-identical**
|
||||||
|
- **fix: the daily update check no longer crashes on a release tag that isn't a plain version number (`TypeError` comparing it, found by the new unit tests); it is simply never offered**
|
||||||
|
- **refactor: `theme_enable` and `create_desktop_shortcut` split into steps; the Return to Gaming Mode shortcut is written with its mode already set (`install_executable`), like the other shortcuts, instead of chmod afterwards**
|
||||||
|
- **test: the menu rules, the plan and the app's and installer's JSON are checked against a golden file (`tests/menu-test.sh` in steamify-cachyos-dev); `make check`, `.editorconfig`, `.shellcheckrc`**
|
||||||
|
- **docs: README lists the sources and projects Steamify builds on, with licences and thanks**
|
||||||
|
|
||||||
|
## 2.11.1 - 2026-10-02
|
||||||
|
|
||||||
|
- `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion**
|
||||||
## 2.11.0 - 2026-10-01
|
## 2.11.0 - 2026-10-01
|
||||||
|
|
||||||
- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); on a Steam Machine only when it boots into the desktop**
|
- `2e51d1d`, `3494924`, `fbdad5a`, `079e725`, `188799e` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it**
|
||||||
|
- `2f7b53f` **fix: the Steam Machine's serial number step no longer fails inside the ISO's installer (`/sys` is read-only in its chroot; the tmpfiles.d file applies at the next boot anyway), which made `machine` report an error and the install log end with `exit: 1`**
|
||||||
|
- `45a23af`, `bd8f387` **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)**
|
||||||
|
- `f3810a9` **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login**
|
||||||
|
- `7869b47` **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode**
|
||||||
|
- `4d387b2` **chore: the Steamify unit tests (`controllers-test.sh`, `nvidia-test.sh`) and the NVIDIA hardware test live in steamify-cachyos-dev (`tests/`) now; `tests/` is removed here**
|
||||||
|
|
||||||
## 2.10.0 - 2026-10-01
|
## 2.10.0 - 2026-10-01
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Local checks, the same as CI's: make check
|
||||||
|
SH := steamify.sh $(wildcard lib/*.sh) ui/steamify-app.sh .github/tools/bundle.sh
|
||||||
|
# The unit tests live in ../steamify-cachyos-dev/tests (REPO points at this checkout).
|
||||||
|
DEV ?= ../steamify-cachyos-dev
|
||||||
|
# Not the hardware test: it is for a real NVIDIA PC and writes a report in $$HOME.
|
||||||
|
TESTS := $(filter-out %-hardware-test.sh,$(wildcard $(DEV)/tests/*-test.sh))
|
||||||
|
|
||||||
|
.PHONY: check syntax lint lint-sh lint-py lint-qml test bundle fmt-check
|
||||||
|
check: syntax lint test bundle
|
||||||
|
|
||||||
|
syntax:
|
||||||
|
@for f in $(SH); do bash -n "$$f" || exit 1; done
|
||||||
|
python3 -c 'import ast, sys; [ast.parse(open(f).read(), f) for f in sys.argv[1:]]' ui/steamify-ui patches/*.py
|
||||||
|
|
||||||
|
lint: lint-sh lint-py lint-qml
|
||||||
|
|
||||||
|
lint-sh:
|
||||||
|
@command -v shellcheck >/dev/null && shellcheck -S warning $(SH) || echo "shellcheck not installed: skipped"
|
||||||
|
|
||||||
|
lint-py:
|
||||||
|
@command -v ruff >/dev/null && ruff check ui/steamify-ui patches || echo "ruff not installed: skipped"
|
||||||
|
|
||||||
|
lint-qml:
|
||||||
|
@Q="$$(command -v qmllint6 || command -v qmllint || ls /usr/lib/qt6/bin/qmllint 2>/dev/null)"; \
|
||||||
|
[ -n "$$Q" ] && "$$Q" --unqualified disable --max-warnings 0 ui/qml/*.qml || echo "qmllint not installed: skipped"
|
||||||
|
|
||||||
|
test:
|
||||||
|
@for t in $(TESTS); do echo "== $$t"; REPO="$(CURDIR)" bash "$$t" || exit 1; done
|
||||||
|
|
||||||
|
bundle:
|
||||||
|
.github/tools/bundle.sh dist/steamify.sh
|
||||||
|
|
||||||
|
fmt-check:
|
||||||
|
@command -v shfmt >/dev/null && shfmt -d -i 4 -ci $(SH) || echo "shfmt not installed: skipped"
|
||||||
@@ -27,6 +27,10 @@ Steam Machine.
|
|||||||
on the desktop too.
|
on the desktop too.
|
||||||
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
||||||
the default.
|
the default.
|
||||||
|
- **Start Steam silently in desktop mode** (off by default) - Steam starts
|
||||||
|
at login on the desktop, in the tray without a window. It is Steam's own
|
||||||
|
autostart entry, so Steam's setting "Run Steam when my computer starts"
|
||||||
|
follows it (the Linux Steam client has no silent option of its own).
|
||||||
- Steam's **System** settings show the SteamOS release Steamify follows
|
- Steam's **System** settings show the SteamOS release Steamify follows
|
||||||
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
||||||
Steamify's version as OS Variant. The OS name stays CachyOS
|
Steamify's version as OS Variant. The OS name stays CachyOS
|
||||||
@@ -40,7 +44,7 @@ Steam Machine.
|
|||||||
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
||||||
**Add to Steam** in right-click menus
|
**Add to Steam** in right-click menus
|
||||||
([details](TECHNICAL.md#steamos-desktop-look)).
|
([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 (an option of the SteamOS conversion).
|
||||||
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
||||||
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
||||||
controller is no fun
|
controller is no fun
|
||||||
@@ -183,6 +187,51 @@ Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md).
|
|||||||
|
|
||||||
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
||||||
|
|
||||||
|
## Sources and credits
|
||||||
|
|
||||||
|
Steamify is glue around other people's work. It installs, configures or
|
||||||
|
downloads the following, and doesn't claim any of it:
|
||||||
|
|
||||||
|
| Project | What Steamify uses it for |
|
||||||
|
|---|---|
|
||||||
|
| [CachyOS](https://cachyos.org) | The distribution it targets, and its packages: `cachyos-vapor` (the Vapor theme), the gamescope session packages (`gamescope-session-cachyos` and the autologin helpers), `dmemcg-booster` and `plasma-foreground-booster` (VRAM booster), and the `xone` / `xpadneo` DKMS packages (extended controller support) |
|
||||||
|
| [Valve / SteamOS](https://github.com/ValveSoftware/SteamOS) | The behaviour it imitates: SteamOS's session switching (`steam-set-session`, `steamos-manager`) and the Steam Deck UI. Downloaded from Valve's package mirror at install time, never shipped here: `steamdeck-kde-presets` (the SteamOS extras, installed under `/usr/local`), the Steam Machine BIOS package and its checksums, and the SteamOS release number shown in Steam's System settings. The gear icon (`assets/steam-gaming-settings.svg`) is Valve's *Return to Gaming Mode* icon (GPL-2.0) with a gear |
|
||||||
|
| [Steam](https://store.steampowered.com), [gamescope](https://github.com/ValveSoftware/gamescope) and [MangoHud](https://github.com/flightlessmango/MangoHud) | The client, the compositor the gaming session is built on, and the overlay; installed through CachyOS's packages |
|
||||||
|
| [evlaV/linux-integration](https://github.com/evlaV/linux-integration) | An unofficial mirror of Valve's kernel: its `cros_ec_cec` driver (GPL-2.0) for the Steam Machine's HDMI-CEC, downloaded at a pinned commit and checksum, then patched by `patches/cros-ec-cec-single-port.patch` |
|
||||||
|
| `leds-valve-dkms-git` (AUR) | The Steam Machine's front LED bar driver |
|
||||||
|
| [KDE Plasma](https://kde.org/plasma-desktop/), SDDM, plasma-login-manager | The desktop and the login managers whose settings it edits (`kwriteconfig6`, `lookandfeeltool`) |
|
||||||
|
| [DKMS](https://github.com/dell/dkms), [fwupd](https://fwupd.org), [yay](https://github.com/Jguer/yay) / [paru](https://github.com/Morganamilo/paru) | Building kernel modules, flashing the BIOS, and installing AUR packages (yay is built from the AUR's `yay-bin` when neither is installed) |
|
||||||
|
| [PySide6 / Qt](https://doc.qt.io/qtforpython-6/) | The graphical app |
|
||||||
|
|
||||||
|
Licences: Steamify itself is MIT. `patches/steamify-fremont-poweroff.c` is a
|
||||||
|
kernel module and therefore GPL-2.0 (see its SPDX header), and the CEC
|
||||||
|
driver it patches is GPL-2.0 too. Each of the projects above keeps its own
|
||||||
|
licence.
|
||||||
|
|
||||||
|
The problems other people found first are credited where they were used: the
|
||||||
|
[SteamOS](https://github.com/ValveSoftware/SteamOS/issues/2626) and
|
||||||
|
[CachyOS gamescope-session](https://github.com/CachyOS/gamescope-session/issues/9)
|
||||||
|
issues linked in [TECHNICAL.md](TECHNICAL.md).
|
||||||
|
|
||||||
|
### Mentions
|
||||||
|
|
||||||
|
Thanks to:
|
||||||
|
|
||||||
|
- The **CachyOS** team and packagers, for a distribution that makes this
|
||||||
|
possible and for the gamescope session packages Steamify builds on.
|
||||||
|
- **Valve**, for SteamOS, its public package repositories, Steam and
|
||||||
|
gamescope.
|
||||||
|
- **evlaV** for the public `linux-integration` mirror of Valve's kernel, the
|
||||||
|
source of the Steam Machine's CEC driver.
|
||||||
|
- The maintainers of **`leds-valve-dkms-git`**, **xone**, **xpadneo**,
|
||||||
|
**dmemcg-booster** and **plasma-foreground-booster**.
|
||||||
|
- The **KDE**, **Arch Linux** and **AUR** communities, and the authors of
|
||||||
|
**yay** and **paru**.
|
||||||
|
- Everyone who reported problems or tested on real hardware.
|
||||||
|
|
||||||
|
If something here is missing or wrongly credited, open an issue or a pull
|
||||||
|
request and it will be fixed.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Steamify CachyOS is an unofficial community project. It is not affiliated
|
Steamify CachyOS is an unofficial community project. It is not affiliated
|
||||||
|
|||||||
+14
-9
@@ -109,8 +109,10 @@ tools write to the conf.d fragment into the base config.
|
|||||||
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
||||||
`sync-steamos-session.path`/`.service`;
|
`sync-steamos-session.path`/`.service`;
|
||||||
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
|
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
|
||||||
("Start Steam silently", on by default) adds a `steam-desktop-autostart`
|
("Start Steam silently in desktop mode", opt-in, always shown) writes
|
||||||
systemd user service that starts Steam silently in Plasma only;
|
`~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the
|
||||||
|
file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older
|
||||||
|
`steam-desktop-autostart` user unit is removed;
|
||||||
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
||||||
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
||||||
restart the login manager without a password prompt.
|
restart the login manager without a password prompt.
|
||||||
@@ -124,7 +126,8 @@ The conversion also sets what Steam's System settings show, see
|
|||||||
|
|
||||||
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
||||||
in `~/.config/environment.d/` (and gamescope-session's own environment
|
in `~/.config/environment.d/` (and gamescope-session's own environment
|
||||||
file), which makes Steam show Steam Deck button glyphs in gaming mode.
|
file), which makes Steam show Steam Deck button glyphs in gaming mode. It is a sub-option of the SteamOS conversion (`gaming`):
|
||||||
|
it does nothing without gaming mode, ticking it ticks the conversion and turning the conversion off turns it off.
|
||||||
|
|
||||||
## SteamOS desktop look
|
## SteamOS desktop look
|
||||||
|
|
||||||
@@ -224,7 +227,7 @@ DKMS modules, built for every installed kernel, so `install_kernel_headers` (`li
|
|||||||
headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
|
headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
|
||||||
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
||||||
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
||||||
plugged in again, or the controller reconnected. `tests/controllers-test.sh` tests it with a stub `pacman`.
|
plugged in again, or the controller reconnected. Its test is in steamify-cachyos-dev (`tests/controllers-test.sh`).
|
||||||
|
|
||||||
## Gaming on NVIDIA
|
## Gaming on NVIDIA
|
||||||
|
|
||||||
@@ -256,7 +259,7 @@ and boot entries are rebuilt and checked for the parameters. The early-load drop
|
|||||||
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
||||||
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
|
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
|
||||||
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
|
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
|
||||||
all of it. `tests/nvidia-hardware-test.sh check|apply|visual` is for a real NVIDIA PC (writes `~/steamify-nvidia-report.txt`). `tests/nvidia-test.sh` tests it against a fake GPU, a stub `pacman` and `systemctl`, and a temp home.
|
all of it. The tests are in steamify-cachyos-dev: `tests/nvidia-test.sh` (a fake GPU, a stub `pacman` and `systemctl`, a temp home) and `tests/nvidia-hardware-test.sh` (a real NVIDIA PC).
|
||||||
|
|
||||||
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
|
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
|
||||||
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
||||||
@@ -344,8 +347,7 @@ desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X =
|
|||||||
Steam's keyboard), in gaming mode as a gamepad.
|
Steam's keyboard), in gaming mode as a gamepad.
|
||||||
|
|
||||||
Steam reads the list only at startup and writes it back on exit, so Steam is
|
Steam reads the list only at startup and writes it back on exit, so Steam is
|
||||||
closed (`steam -shutdown`) for the edit and started again (through
|
closed (`steam -shutdown`) for the edit and started again (`steam -silent`). That's refused in gaming
|
||||||
`steam-desktop-autostart.service` when it's there). That's refused in gaming
|
|
||||||
mode and when Steamify itself was started from Steam (`SteamGameId`), since
|
mode and when Steamify itself was started from Steam (`SteamGameId`), since
|
||||||
closing Steam would end it. An entry for the start script that's already
|
closing Steam would end it. An entry for the start script that's already
|
||||||
there (added by hand, or with the path from before 2.5.0) is updated, not
|
there (added by hand, or with the path from before 2.5.0) is updated, not
|
||||||
@@ -490,7 +492,8 @@ In the home folder, everything is under `steamify`:
|
|||||||
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
|
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
|
||||||
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
|
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
|
||||||
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
|
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
|
||||||
| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` |
|
| `~/.config/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") |
|
||||||
|
| `~/.config/systemd/user/` | `steamify-update-check.*` |
|
||||||
|
|
||||||
System-wide: `/usr/local/lib/steamify/` (kernel headers script),
|
System-wide: `/usr/local/lib/steamify/` (kernel headers script),
|
||||||
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
|
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
|
||||||
@@ -536,7 +539,9 @@ steamify.sh --defaults --list # what --defaults can se
|
|||||||
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
||||||
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
||||||
`bios` in the list: exit code 1 before anything changes. What needs a
|
`bios` in the list: exit code 1 before anything changes. What needs a
|
||||||
Plasma session waits for the first login (`lib/first-login.sh`).
|
Plasma session waits for the first login (`lib/first-login.sh`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover
|
||||||
|
(not installed on CachyOS: a blank icon), by CachyOS's own (`taskbar_drop_discover` in `lib/vapor-theme.sh`; skipped when Discover is
|
||||||
|
installed or the taskbar already has its own `launchers`).
|
||||||
|
|
||||||
With `Relogin=true`, a gamescope session that fails to start is restarted
|
With `Relogin=true`, a gamescope session that fails to start is restarted
|
||||||
immediately, which can turn into a loop - see
|
immediately, which can turn into a loop - see
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
See [TECHNICAL.md](TECHNICAL.md) for how each part works.
|
See [TECHNICAL.md](TECHNICAL.md) for how each part works.
|
||||||
|
|
||||||
|
## Where are the errors of the quiet steps?
|
||||||
|
|
||||||
|
Steps that may fail without it mattering (stopping a service that isn't
|
||||||
|
running, removing a package that isn't installed) don't show their errors in the
|
||||||
|
wizard. They are kept in `~/.local/state/steamify/log/steamify.log` (the last
|
||||||
|
512 KB), with the command and its exit status: attach it when you ask for help.
|
||||||
|
|
||||||
## Gaming mode shows a black screen or keeps restarting
|
## Gaming mode shows a black screen or keeps restarting
|
||||||
|
|
||||||
Press **Ctrl+Alt+F3**, log in with your username and password, and run:
|
Press **Ctrl+Alt+F3**, log in with your username and password, and run:
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 276 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 465 KiB After Width: | Height: | Size: 322 KiB |
+27
-35
@@ -31,31 +31,41 @@ json_list() {
|
|||||||
printf '[%s]' "$out"
|
printf '[%s]' "$out"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json_bool() {
|
||||||
|
# json_bool <command>...: true or false by the command's exit status.
|
||||||
|
if "$@"; then printf true; else printf false; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
json_item_head() {
|
||||||
|
# json_item_head <id> <kind>: the start of an item's object (no closing
|
||||||
|
# brace) with what the app and the installer page both read: id, label,
|
||||||
|
# hint (the part of the label after the colon), kind, parent.
|
||||||
|
local c="$1" hint=""
|
||||||
|
[[ "${LABEL[$c]}" == *:* ]] && hint="${LABEL[$c]#*: }"
|
||||||
|
printf '{"id":%s,"label":%s,"hint":%s,"kind":"%s","parent":%s,"needs":""' \
|
||||||
|
"$(json_str "$c")" "$(json_str "${LABEL[$c]%%:*}")" "$(json_str "$hint")" "$2" "$(json_str "${PARENT[$c]:-}")"
|
||||||
|
}
|
||||||
|
|
||||||
backend_event() {
|
backend_event() {
|
||||||
# backend_event <event> [<json fields without braces>]
|
# backend_event <event> [<json fields without braces>]
|
||||||
printf '{"event":%s%s}\n' "$(json_str "$1")" "${2:+,$2}"
|
printf '{"event":%s%s}\n' "$(json_str "$1")" "${2:+,$2}"
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_status() {
|
backend_status() {
|
||||||
local c first_run=true items="" kind parent now
|
local c first_run=true items="" kind
|
||||||
detect_components
|
detect_components
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" && ! is_action "$c" && [[ "${CURRENT[$c]}" == 1 ]] && first_run=false
|
component_available "$c" && ! is_action "$c" && is_current "$c" && first_run=false
|
||||||
done
|
done
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" || continue
|
component_available "$c" || continue
|
||||||
kind=toggle; is_action "$c" && kind=action; [[ "$c" == boot ]] && kind=choice
|
kind=toggle; is_action "$c" && kind=action; [[ "$c" == boot ]] && kind=choice
|
||||||
parent="${PARENT[$c]:-}"
|
items+="${items:+,}$(json_item_head "$c" "$kind")"
|
||||||
now="${CURRENT[$c]:-0}"
|
items+=",\"on\":$(json_bool is_current "$c")"
|
||||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
items+=",\"wanted\":$(json_bool is_wanted "$c")"
|
||||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
items+=",\"update\":$(json_bool feature_outdated "$c")"
|
||||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")"
|
items+=",\"new\":$(json_bool feature_any_new "$c")"
|
||||||
items+=",\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)")"
|
items+=",\"selectable\":$(json_bool component_selectable "$c")"
|
||||||
items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)"
|
|
||||||
items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)"
|
|
||||||
items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)"
|
|
||||||
items+=",\"new\":$({ feature_new "$c" || feature_new_optin "$c"; } && echo true || echo false)"
|
|
||||||
items+=",\"selectable\":$(component_selectable "$c" && echo true || echo false)"
|
|
||||||
# Why it can't be turned on, for the app's explanation.
|
# Why it can't be turned on, for the app's explanation.
|
||||||
[[ "$c" == vram && -n "${VRAM_NVIDIA_CASE:-}" ]] &&
|
[[ "$c" == vram && -n "${VRAM_NVIDIA_CASE:-}" ]] &&
|
||||||
items+=",\"note\":$(json_str "$(vram_nvidia_note "$VRAM_NVIDIA_CASE")")"
|
items+=",\"note\":$(json_str "$(vram_nvidia_note "$VRAM_NVIDIA_CASE")")"
|
||||||
@@ -65,11 +75,11 @@ backend_status() {
|
|||||||
for f in /dev/cec*; do [[ -e "$f" ]] && cec+="${cec:+ }$(basename "$f")"; done
|
for f in /dev/cec*; do [[ -e "$f" ]] && cec+="${cec:+ }$(basename "$f")"; done
|
||||||
local bios='null'
|
local bios='null'
|
||||||
if bios_available; then
|
if bios_available; then
|
||||||
bios="{\"current\":$(json_str "$(bios_current)"),\"newest\":$(json_str "${BIOS_NEWEST:-}"),\"selectable\":$(bios_selectable && echo true || echo false),\"dryRun\":$([[ -n "$BIOS_DRY_RUN" ]] && echo true || echo false)}"
|
bios="{\"current\":$(json_str "$(bios_current)"),\"newest\":$(json_str "${BIOS_NEWEST:-}"),\"selectable\":$(json_bool bios_selectable),\"dryRun\":$([[ -n "$BIOS_DRY_RUN" ]] && echo true || echo false)}"
|
||||||
fi
|
fi
|
||||||
printf '{"version":%s,"firstRun":%s,"steamMachine":%s,"kernel":%s,"pinnedKernel":%s,"cecDevices":%s,"leds":%s,"bios":%s,"items":[%s]}\n' \
|
printf '{"version":%s,"firstRun":%s,"steamMachine":%s,"kernel":%s,"pinnedKernel":%s,"cecDevices":%s,"leds":%s,"bios":%s,"items":[%s]}\n' \
|
||||||
"$(json_str "$VERSION")" "$first_run" \
|
"$(json_str "$VERSION")" "$first_run" \
|
||||||
"$(detect_valve_fremont && echo true || echo false)" \
|
"$(json_bool detect_valve_fremont)" \
|
||||||
"$(json_str "$(uname -r)")" "$(json_str "${PINNED_KERNEL_VER:-}")" \
|
"$(json_str "$(uname -r)")" "$(json_str "${PINNED_KERNEL_VER:-}")" \
|
||||||
"$(json_str "$cec")" \
|
"$(json_str "$cec")" \
|
||||||
"$(compgen -G '/sys/class/leds/valve-leds*' | wc -l)" \
|
"$(compgen -G '/sys/class/leds/valve-leds*' | wc -l)" \
|
||||||
@@ -146,28 +156,10 @@ backend_apply() {
|
|||||||
WANTED[$c]=0
|
WANTED[$c]=0
|
||||||
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
|
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
|
||||||
done
|
done
|
||||||
# The same rules as the menu's toggles.
|
normalize_wanted
|
||||||
# (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.)
|
|
||||||
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
|
||||||
if component_available gaming; then
|
|
||||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
|
|
||||||
else
|
|
||||||
WANTED[boot]=0
|
|
||||||
fi
|
|
||||||
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1
|
|
||||||
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
|
|
||||||
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
|
|
||||||
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; WANTED[nvsilent]=0; }
|
|
||||||
[[ "${WANTED[silent]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
|
||||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && WANTED[silent]=0
|
|
||||||
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
|
|
||||||
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
|
|
||||||
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
|
|
||||||
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[kpin]=0
|
|
||||||
# Retired: only ever removed.
|
# Retired: only ever removed.
|
||||||
WANTED[hdmi]=0
|
WANTED[hdmi]=0
|
||||||
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
|
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
|
||||||
silent_normalize
|
|
||||||
|
|
||||||
REAPPLY=$reapply
|
REAPPLY=$reapply
|
||||||
plan_changes
|
plan_changes
|
||||||
@@ -181,7 +173,7 @@ backend_apply() {
|
|||||||
backend_sudo || return 1
|
backend_sudo || return 1
|
||||||
|
|
||||||
LOGIN_MANAGER=plasmalogin
|
LOGIN_MANAGER=plasmalogin
|
||||||
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
|
is_wanted single && LOGIN_MANAGER=sddm
|
||||||
local -a failed=()
|
local -a failed=()
|
||||||
for c in "${TO_DISABLE[@]}"; do
|
for c in "${TO_DISABLE[@]}"; do
|
||||||
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||||
|
|||||||
+7
-7
@@ -30,16 +30,16 @@ bios_lookup_newest() {
|
|||||||
[[ -n "${BIOS_LOOKED_UP:-}" ]] && return 0
|
[[ -n "${BIOS_LOOKED_UP:-}" ]] && return 0
|
||||||
BIOS_LOOKED_UP=1; BIOS_NEWEST=""
|
BIOS_LOOKED_UP=1; BIOS_NEWEST=""
|
||||||
local tmp desc
|
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)"
|
BIOS_REPO="$(valve_newest_repo "$BIOS_REPO_PREFIX" 10)"
|
||||||
[[ -n "$BIOS_REPO" ]] || return 1
|
[[ -n "$BIOS_REPO" ]] || return 1
|
||||||
tmp="$(mktemp -d)"
|
make_tmpdir tmp
|
||||||
if curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.files" -o "$tmp/files" &&
|
if curl -fsL --max-time 30 "$(valve_repo_url "$BIOS_REPO")/$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
|
curl -fsL --max-time 30 "$(valve_repo_url "$BIOS_REPO")/$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)"
|
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)"
|
[[ -n "$desc" ]] && BIOS_CAB="$(tar -xOf "$tmp/files" "$desc" | grep -E '^usr/share/fwupd/.*\.cab$' | head -n 1)"
|
||||||
desc="${desc%/files}/desc"
|
desc="${desc%/files}/desc"
|
||||||
BIOS_PKG="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%FILENAME%$/ { getline; print }')"
|
BIOS_PKG="$(valve_desc_field "$tmp/db" "$desc" FILENAME)"
|
||||||
BIOS_SHA256="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%SHA256SUM%$/ { getline; print }')"
|
BIOS_SHA256="$(valve_desc_field "$tmp/db" "$desc" SHA256SUM)"
|
||||||
[[ -n "${BIOS_CAB:-}" && -n "$BIOS_PKG" && -n "$BIOS_SHA256" ]] && BIOS_NEWEST="$(basename "$BIOS_CAB" .cab)"
|
[[ -n "${BIOS_CAB:-}" && -n "$BIOS_PKG" && -n "$BIOS_SHA256" ]] && BIOS_NEWEST="$(basename "$BIOS_CAB" .cab)"
|
||||||
fi
|
fi
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
@@ -143,7 +143,7 @@ bios_prepare() {
|
|||||||
{ err "Installing fwupd failed."; return 1; }
|
{ err "Installing fwupd failed."; return 1; }
|
||||||
rm -rf "$BIOS_STAGE_DIR"; mkdir -p "$BIOS_STAGE_DIR"; chmod 700 "$BIOS_STAGE_DIR"
|
rm -rf "$BIOS_STAGE_DIR"; mkdir -p "$BIOS_STAGE_DIR"; chmod 700 "$BIOS_STAGE_DIR"
|
||||||
info "Downloading $BIOS_PKG ($BIOS_REPO)..."
|
info "Downloading $BIOS_PKG ($BIOS_REPO)..."
|
||||||
if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$BIOS_STAGE_DIR/pkg.tar.zst" ||
|
if ! curl -fsSL "$(valve_repo_url "$BIOS_REPO")/$BIOS_PKG" -o "$BIOS_STAGE_DIR/pkg.tar.zst" ||
|
||||||
! echo "$BIOS_SHA256 $BIOS_STAGE_DIR/pkg.tar.zst" | sha256sum -c --quiet - ||
|
! echo "$BIOS_SHA256 $BIOS_STAGE_DIR/pkg.tar.zst" | sha256sum -c --quiet - ||
|
||||||
! tar -I unzstd -xf "$BIOS_STAGE_DIR/pkg.tar.zst" -C "$BIOS_STAGE_DIR" "$BIOS_CAB"; then
|
! tar -I unzstd -xf "$BIOS_STAGE_DIR/pkg.tar.zst" -C "$BIOS_STAGE_DIR" "$BIOS_CAB"; then
|
||||||
err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched."
|
err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched."
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ boot_enable() {
|
|||||||
|
|
||||||
boot_disable() {
|
boot_disable() {
|
||||||
info "Setting the PC to boot into gaming mode again..."
|
info "Setting the PC to boot into gaming mode again..."
|
||||||
sudo systemctl disable "$BOOT_UNIT_NAME" 2>/dev/null
|
best_effort sudo systemctl disable "$BOOT_UNIT_NAME"
|
||||||
sudo rm -f "$BOOT_UNIT"
|
sudo rm -f "$BOOT_UNIT"
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
# Next boot into gamescope, as the conversion sets it up.
|
# Next boot into gamescope, as the conversion sets it up.
|
||||||
|
|||||||
+20
-36
@@ -39,10 +39,10 @@ cec_link_steamos_manager() {
|
|||||||
# this item ran.
|
# this item ran.
|
||||||
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
|
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
user_systemctl enable steamos-manager-configure-cecd.service 2>/dev/null
|
best_effort user_systemctl enable steamos-manager-configure-cecd.service
|
||||||
user_systemctl start steamos-manager-configure-cecd.service 2>/dev/null
|
best_effort user_systemctl start steamos-manager-configure-cecd.service
|
||||||
user_systemctl restart cecd.service 2>/dev/null
|
best_effort user_systemctl restart cecd.service
|
||||||
user_systemctl restart steamos-manager.service 2>/dev/null
|
best_effort user_systemctl restart steamos-manager.service
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,10 +55,10 @@ cec_status() { cec_installed && [[ -f "$CEC_STEAM_DROPIN" ]] && cec_driver_ok; }
|
|||||||
|
|
||||||
cec_reload_driver() {
|
cec_reload_driver() {
|
||||||
# cecd keeps /dev/cec0 open, so the old module can't be unloaded under it.
|
# cecd keeps /dev/cec0 open, so the old module can't be unloaded under it.
|
||||||
user_systemctl stop cecd.service 2>/dev/null
|
best_effort user_systemctl stop cecd.service
|
||||||
sudo modprobe -r cros_ec_cec 2>/dev/null
|
best_effort sudo modprobe -r cros_ec_cec
|
||||||
sudo modprobe cros_ec_cec 2>/dev/null
|
best_effort sudo modprobe cros_ec_cec
|
||||||
user_systemctl start cecd.service 2>/dev/null
|
best_effort user_systemctl start cecd.service
|
||||||
}
|
}
|
||||||
|
|
||||||
cec_driver_enable() {
|
cec_driver_enable() {
|
||||||
@@ -68,7 +68,7 @@ cec_driver_enable() {
|
|||||||
sudo pacman -S --needed --noconfirm dkms patch || { err "Installing dkms failed."; return 1; }
|
sudo pacman -S --needed --noconfirm dkms patch || { err "Installing dkms failed."; return 1; }
|
||||||
fi
|
fi
|
||||||
install_kernel_headers || return 1
|
install_kernel_headers || return 1
|
||||||
tmp="$(mktemp -d)"
|
make_tmpdir tmp
|
||||||
if [[ -f "$CEC_DRIVER_CACHE" ]] && echo "$CEC_DRIVER_SHA256 $CEC_DRIVER_CACHE" | sha256sum -c --quiet - 2>/dev/null; then
|
if [[ -f "$CEC_DRIVER_CACHE" ]] && echo "$CEC_DRIVER_SHA256 $CEC_DRIVER_CACHE" | sha256sum -c --quiet - 2>/dev/null; then
|
||||||
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
||||||
else
|
else
|
||||||
@@ -80,7 +80,7 @@ cec_driver_enable() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
||||||
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
best_effort sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete
|
||||||
sudo install -Dm644 "$tmp/cros-ec-cec.c" "$CEC_DRIVER_CACHE"
|
sudo install -Dm644 "$tmp/cros-ec-cec.c" "$CEC_DRIVER_CACHE"
|
||||||
fi
|
fi
|
||||||
# So it finds amdgpu's HDMI port (see the patch for why).
|
# So it finds amdgpu's HDMI port (see the patch for why).
|
||||||
@@ -113,24 +113,8 @@ cec_repair() { cec_installed && ! cec_status; }
|
|||||||
|
|
||||||
fetch_holo_pkg() {
|
fetch_holo_pkg() {
|
||||||
# fetch_holo_pkg <dir> <package>: download the newest <package> from
|
# fetch_holo_pkg <dir> <package>: download the newest <package> from
|
||||||
# Valve's newest holo repository into <dir> and print its path. The
|
# Valve's newest holo repository into <dir> and print its path.
|
||||||
# SHA-256 comes from Valve's package index and is verified.
|
valve_fetch_pkg holo "$2" "$1"
|
||||||
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() {
|
cec_enable() {
|
||||||
@@ -140,7 +124,7 @@ cec_enable() {
|
|||||||
sudo pacman -S --needed --noconfirm linuxconsole || { err "Installing linuxconsole failed."; return 1; }
|
sudo pacman -S --needed --noconfirm linuxconsole || { err "Installing linuxconsole failed."; return 1; }
|
||||||
state_set cec installed_linuxconsole 1
|
state_set cec installed_linuxconsole 1
|
||||||
fi
|
fi
|
||||||
tmp="$(mktemp -d)"
|
make_tmpdir tmp
|
||||||
for p in "${CEC_PKGS[@]}"; do
|
for p in "${CEC_PKGS[@]}"; do
|
||||||
f="$(fetch_holo_pkg "$tmp" "$p")" || { rm -rf "$tmp"; return 1; }
|
f="$(fetch_holo_pkg "$tmp" "$p")" || { rm -rf "$tmp"; return 1; }
|
||||||
files+=("$f")
|
files+=("$f")
|
||||||
@@ -168,10 +152,10 @@ cec_enable() {
|
|||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
# The TV remote's volume keys: SteamOS enables this socket through its
|
# The TV remote's volume keys: SteamOS enables this socket through its
|
||||||
# preset, which pacman doesn't apply, so nothing else does on CachyOS.
|
# preset, which pacman doesn't apply, so nothing else does on CachyOS.
|
||||||
user_systemctl enable --now cec-audio-control.socket 2>/dev/null
|
best_effort user_systemctl enable --now cec-audio-control.socket
|
||||||
cec_link_steamos_manager
|
cec_link_steamos_manager
|
||||||
if compgen -G "/dev/cec*" >/dev/null; then
|
if compgen -G "/dev/cec*" >/dev/null; then
|
||||||
user_systemctl restart cecd.service 2>/dev/null
|
best_effort user_systemctl restart cecd.service
|
||||||
ok "HDMI-CEC on ($(cd /dev && echo cec*)); Steam shows its settings from the next gaming mode start."
|
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)."
|
info "Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
|
||||||
else
|
else
|
||||||
@@ -182,15 +166,15 @@ cec_enable() {
|
|||||||
|
|
||||||
cec_disable() {
|
cec_disable() {
|
||||||
info "Removing HDMI-CEC..."
|
info "Removing HDMI-CEC..."
|
||||||
user_systemctl disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
|
best_effort user_systemctl disable --now cecd.service cec-audio-control.socket cec-audio-control.service
|
||||||
user_systemctl disable steamos-manager-configure-cecd.service 2>/dev/null
|
best_effort user_systemctl disable steamos-manager-configure-cecd.service
|
||||||
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
|
best_effort sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}"
|
||||||
cec_driver_disable
|
cec_driver_disable
|
||||||
sudo rm -f "$CEC_ORDER_DROPIN" "$CEC_STEAM_DROPIN" "$CEC_STEAM_ENV"
|
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
|
best_effort sudo rmdir "$(dirname "$CEC_ORDER_DROPIN")" "$(dirname "$CEC_STEAM_DROPIN")" "$(dirname "$CEC_STEAM_ENV")"
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
|
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
|
||||||
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
|
best_effort sudo pacman -Rns --noconfirm linuxconsole
|
||||||
state_clear cec
|
state_clear cec
|
||||||
fi
|
fi
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
|
|||||||
+41
-3
@@ -2,7 +2,12 @@
|
|||||||
# Output helpers, prompts and small shared utilities.
|
# Output helpers, prompts and small shared utilities.
|
||||||
# Sourced by steamify.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_dim="\033[2m"
|
# NO_COLOR (https://no-color.org): plain output, e.g. for a log file.
|
||||||
|
if [[ -n "${NO_COLOR:-}" ]]; then
|
||||||
|
c_reset=""; c_bold=""; c_green=""; c_yellow=""; c_red=""; c_cyan=""; c_dim=""
|
||||||
|
else
|
||||||
|
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"
|
||||||
|
fi
|
||||||
|
|
||||||
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} $*"; }
|
||||||
@@ -34,6 +39,39 @@ ask_yn() {
|
|||||||
[[ "$reply" =~ ^[Yy]$ ]]
|
[[ "$reply" =~ ^[Yy]$ ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
best_effort() {
|
||||||
|
# best_effort <command>...: for a step whose failure is fine (stopping a
|
||||||
|
# unit that isn't running, removing what isn't installed). Same exit status
|
||||||
|
# and output as the command, but its errors go to the log
|
||||||
|
# (~/.local/state/steamify/log/steamify.log) instead of vanishing, so a problem
|
||||||
|
# can still be found afterwards.
|
||||||
|
local log="${STEAMIFY_LOG:-${STATE_DIR:-$HOME/.local/state/steamify}/log/steamify.log}" e rc
|
||||||
|
e="$(mktemp)" || { "$@" 2>/dev/null; return; }
|
||||||
|
"$@" 2>"$e"; rc=$?
|
||||||
|
if [[ -s "$e" ]]; then
|
||||||
|
mkdir -p "${log%/*}" 2>/dev/null
|
||||||
|
# Kept small: a run that fails the same way every time shouldn't fill the disk.
|
||||||
|
[[ "$(stat -c %s "$log" 2>/dev/null || echo 0)" -gt 524288 ]] && : > "$log"
|
||||||
|
{ echo "$(date -Is) exit $rc: $*"; sed 's/^/ /' "$e"; } >> "$log" 2>/dev/null
|
||||||
|
fi
|
||||||
|
rm -f "$e"
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Temp dirs of this run, removed at exit (on_exit in steamify.sh), also when it
|
||||||
|
# stops half way: make_tmpdir <variable>.
|
||||||
|
TMP_DIRS=()
|
||||||
|
make_tmpdir() {
|
||||||
|
local d
|
||||||
|
d="$(mktemp -d)" || return 1
|
||||||
|
TMP_DIRS+=("$d")
|
||||||
|
printf -v "$1" '%s' "$d"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_tmpdirs() {
|
||||||
|
[[ ${#TMP_DIRS[@]} -eq 0 ]] || rm -rf "${TMP_DIRS[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
require_root_helper() {
|
require_root_helper() {
|
||||||
# Re-exec any privileged step through sudo rather than requiring the
|
# Re-exec any privileged step through sudo rather than requiring the
|
||||||
# whole script to run as root, so $HOME/whoami stay correct for the
|
# whole script to run as root, so $HOME/whoami stay correct for the
|
||||||
@@ -97,7 +135,7 @@ stop_plasmashell_for_edit() {
|
|||||||
PLASMASHELL_WAS_RUNNING=false
|
PLASMASHELL_WAS_RUNNING=false
|
||||||
if pgrep -u "$USER" -x plasmashell >/dev/null; then
|
if pgrep -u "$USER" -x plasmashell >/dev/null; then
|
||||||
PLASMASHELL_WAS_RUNNING=true
|
PLASMASHELL_WAS_RUNNING=true
|
||||||
systemctl --user stop plasma-plasmashell.service 2>/dev/null
|
best_effort systemctl --user stop plasma-plasmashell.service
|
||||||
pkill -u "$USER" -x plasmashell && sleep 2
|
pkill -u "$USER" -x plasmashell && sleep 2
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -105,7 +143,7 @@ stop_plasmashell_for_edit() {
|
|||||||
restart_plasmashell_if_stopped() {
|
restart_plasmashell_if_stopped() {
|
||||||
if [[ "${PLASMASHELL_WAS_RUNNING:-false}" == true ]]; then
|
if [[ "${PLASMASHELL_WAS_RUNNING:-false}" == true ]]; then
|
||||||
rm -rf ~/.cache/plasmashell* ~/.cache/org.kde.dirmodel-qml.kcache
|
rm -rf ~/.cache/plasmashell* ~/.cache/org.kde.dirmodel-qml.kcache
|
||||||
systemctl --user start plasma-plasmashell.service 2>/dev/null ||
|
best_effort systemctl --user start plasma-plasmashell.service ||
|
||||||
{ setsid plasmashell >/dev/null 2>&1 & }
|
{ setsid plasmashell >/dev/null 2>&1 & }
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
+30
-29
@@ -2,41 +2,46 @@
|
|||||||
# "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 steamify.sh; not meant to be run on its own.
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
create_desktop_shortcut() {
|
shortcut_desktop_dir() {
|
||||||
# Determine the home directory of the target user
|
# The target user's Desktop folder, from their user-dirs.dirs.
|
||||||
local user_home
|
local user_home desktop_dir
|
||||||
user_home="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
|
user_home="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
|
||||||
|
|
||||||
# Locate the correct Desktop directory
|
|
||||||
local desktop_dir
|
|
||||||
if [[ -f "$user_home/.config/user-dirs.dirs" ]]; then
|
if [[ -f "$user_home/.config/user-dirs.dirs" ]]; then
|
||||||
desktop_dir=$(grep '^XDG_DESKTOP_DIR=' "$user_home/.config/user-dirs.dirs" | cut -d '"' -f 2)
|
desktop_dir=$(grep '^XDG_DESKTOP_DIR=' "$user_home/.config/user-dirs.dirs" | cut -d '"' -f 2)
|
||||||
desktop_dir="${desktop_dir/\$HOME/$user_home}"
|
desktop_dir="${desktop_dir/\$HOME/$user_home}"
|
||||||
fi
|
fi
|
||||||
desktop_dir="${desktop_dir:-$user_home/Desktop}"
|
echo "${desktop_dir:-$user_home/Desktop}"
|
||||||
|
}
|
||||||
|
|
||||||
|
shortcut_install_sudoers() {
|
||||||
|
# plasma-login-manager needs the sync bridge run and a restart, which the
|
||||||
|
# shortcut can't sudo for interactively (Terminal=false), so it gets a
|
||||||
|
# password-less rule scoped to exactly those two commands.
|
||||||
|
local sudoers_tmp
|
||||||
|
sudoers_tmp="$(mktemp)"
|
||||||
|
cat > "$sudoers_tmp" << EOF
|
||||||
|
$TARGET_USER ALL=(root) NOPASSWD: /usr/bin/systemctl start sync-steamos-session.service, /usr/bin/systemctl restart plasmalogin
|
||||||
|
EOF
|
||||||
|
if sudo visudo -cf "$sudoers_tmp" >/dev/null; then
|
||||||
|
sudo install -m 0440 -o root -g root "$sudoers_tmp" /etc/sudoers.d/gamescope-session-switch
|
||||||
|
ok "Installed /etc/sudoers.d/gamescope-session-switch for the shortcut."
|
||||||
|
else
|
||||||
|
warn "Generated sudoers rule failed validation; the shortcut will not be able to restart plasmalogin."
|
||||||
|
fi
|
||||||
|
rm -f "$sudoers_tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_desktop_shortcut() {
|
||||||
|
local desktop_dir
|
||||||
|
desktop_dir="$(shortcut_desktop_dir)"
|
||||||
mkdir -p "$desktop_dir"
|
mkdir -p "$desktop_dir"
|
||||||
|
|
||||||
# On SDDM, steamos-session-select logging out is enough: Relogin=true
|
# On SDDM, steamos-session-select logging out is enough: Relogin=true
|
||||||
# logs straight back in to the newly selected session, like SteamOS.
|
# logs straight back in to the newly selected session, like SteamOS.
|
||||||
# plasma-login-manager needs the sync bridge run and a restart, which
|
|
||||||
# the shortcut can't sudo for interactively (Terminal=false), so it gets
|
|
||||||
# a password-less rule scoped to exactly those two commands.
|
|
||||||
local exec_line="steamos-session-select gamescope"
|
local exec_line="steamos-session-select gamescope"
|
||||||
if [[ "$LOGIN_MANAGER" == "plasmalogin" ]]; then
|
if [[ "$LOGIN_MANAGER" == "plasmalogin" ]]; then
|
||||||
exec_line="sh -c 'steamos-session-select gamescope && sudo -n /usr/bin/systemctl start sync-steamos-session.service && sudo -n /usr/bin/systemctl restart plasmalogin'"
|
exec_line="sh -c 'steamos-session-select gamescope && sudo -n /usr/bin/systemctl start sync-steamos-session.service && sudo -n /usr/bin/systemctl restart plasmalogin'"
|
||||||
local sudoers_tmp
|
shortcut_install_sudoers
|
||||||
sudoers_tmp="$(mktemp)"
|
|
||||||
cat > "$sudoers_tmp" << EOF
|
|
||||||
$TARGET_USER ALL=(root) NOPASSWD: /usr/bin/systemctl start sync-steamos-session.service, /usr/bin/systemctl restart plasmalogin
|
|
||||||
EOF
|
|
||||||
if sudo visudo -cf "$sudoers_tmp" >/dev/null; then
|
|
||||||
sudo install -m 0440 -o root -g root "$sudoers_tmp" /etc/sudoers.d/gamescope-session-switch
|
|
||||||
ok "Installed /etc/sudoers.d/gamescope-session-switch for the shortcut."
|
|
||||||
else
|
|
||||||
warn "Generated sudoers rule failed validation; the shortcut will not be able to restart plasmalogin."
|
|
||||||
fi
|
|
||||||
rm -f "$sudoers_tmp"
|
|
||||||
else
|
else
|
||||||
sudo rm -f /etc/sudoers.d/gamescope-session-switch
|
sudo rm -f /etc/sudoers.d/gamescope-session-switch
|
||||||
fi
|
fi
|
||||||
@@ -49,11 +54,11 @@ EOF
|
|||||||
[[ -f /usr/local/share/icons/hicolor/scalable/actions/gaming-return.svg ]] &&
|
[[ -f /usr/local/share/icons/hicolor/scalable/actions/gaming-return.svg ]] &&
|
||||||
shortcut_icon="gaming-return"
|
shortcut_icon="gaming-return"
|
||||||
|
|
||||||
# 2. Generate the .desktop shortcut with instant session switcher strings
|
|
||||||
local shortcut_path="$desktop_dir/Return to Gaming Mode.desktop"
|
local shortcut_path="$desktop_dir/Return to Gaming Mode.desktop"
|
||||||
info "Creating 'Return to Gaming Mode' desktop shortcut at: $shortcut_path"
|
info "Creating 'Return to Gaming Mode' desktop shortcut at: $shortcut_path"
|
||||||
|
# Written with its mode already set: Plasma opens a desktop icon it first
|
||||||
cat << EOF > "$shortcut_path"
|
# saw non-executable in an editor.
|
||||||
|
install_executable "$shortcut_path" 755 << EOF
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Return to Gaming Mode
|
Name=Return to Gaming Mode
|
||||||
Comment=Switch session back to Gamescope
|
Comment=Switch session back to Gamescope
|
||||||
@@ -63,10 +68,6 @@ Terminal=false
|
|||||||
Type=Application
|
Type=Application
|
||||||
Categories=System;
|
Categories=System;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Fix permissions for the target user and KDE Plasma desktop ecosystem
|
|
||||||
chmod +x "$shortcut_path"
|
|
||||||
|
|
||||||
ok "Desktop shortcut created successfully."
|
ok "Desktop shortcut created successfully."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-6
@@ -7,13 +7,25 @@
|
|||||||
|
|
||||||
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
||||||
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
||||||
|
FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh"
|
||||||
|
|
||||||
first_login_schedule() {
|
first_login_schedule() {
|
||||||
|
# The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with
|
||||||
|
# steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead.
|
||||||
|
# (Only a single-file bundle can be copied; SCRIPT_DIR doesn't exist in one.)
|
||||||
|
local run self="${BASH_SOURCE[0]:-}"
|
||||||
|
if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$self" ]] && grep -q '^# Single-file build' "$self"; then
|
||||||
|
install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$self"
|
||||||
|
run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\""
|
||||||
|
else
|
||||||
|
run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login"
|
||||||
|
fi
|
||||||
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
|
mkdir -p ~/.cache
|
||||||
|
{ $run; } > ~/.cache/steamify-first-login.log 2>&1
|
||||||
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
||||||
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
||||||
EOF2
|
EOF2
|
||||||
@@ -31,10 +43,9 @@ first_login_run() {
|
|||||||
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
if single_status; then
|
stop_plasmashell_for_edit
|
||||||
stop_plasmashell_for_edit
|
taskbar_drop_discover
|
||||||
single_launcher
|
single_status && single_launcher
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
fi
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ poweroff_fix_enable() {
|
|||||||
sudo pacman -S --needed --noconfirm dkms || { err "Installing dkms failed."; return 1; }
|
sudo pacman -S --needed --noconfirm dkms || { err "Installing dkms failed."; return 1; }
|
||||||
fi
|
fi
|
||||||
install_kernel_headers || return 1
|
install_kernel_headers || return 1
|
||||||
tmp="$(mktemp -d)"
|
make_tmpdir tmp
|
||||||
patch_file "$POWEROFF_DKMS_NAME.c" > "$tmp/$POWEROFF_DKMS_NAME.c"
|
patch_file "$POWEROFF_DKMS_NAME.c" > "$tmp/$POWEROFF_DKMS_NAME.c"
|
||||||
echo "obj-m += $POWEROFF_DKMS_NAME.o" >"$tmp/Makefile"
|
echo "obj-m += $POWEROFF_DKMS_NAME.o" >"$tmp/Makefile"
|
||||||
patch_file "$POWEROFF_DKMS_NAME.dkms.conf" | fill NAME="$POWEROFF_DKMS_NAME" VERSION="$POWEROFF_DKMS_VER" >"$tmp/dkms.conf"
|
patch_file "$POWEROFF_DKMS_NAME.dkms.conf" | fill NAME="$POWEROFF_DKMS_NAME" VERSION="$POWEROFF_DKMS_VER" >"$tmp/dkms.conf"
|
||||||
@@ -43,13 +43,13 @@ poweroff_fix_enable() {
|
|||||||
warn "Building the power-off fix for $k failed; with that kernel it may start again after shutting down."
|
warn "Building the power-off fix for $k failed; with that kernel it may start again after shutting down."
|
||||||
done
|
done
|
||||||
echo "$POWEROFF_DKMS_NAME" | sudo tee "$POWEROFF_MODULES_LOAD" >/dev/null
|
echo "$POWEROFF_DKMS_NAME" | sudo tee "$POWEROFF_MODULES_LOAD" >/dev/null
|
||||||
sudo modprobe "$POWEROFF_DKMS_NAME" 2>/dev/null
|
best_effort sudo modprobe "$POWEROFF_DKMS_NAME"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
poweroff_fix_disable() {
|
poweroff_fix_disable() {
|
||||||
sudo rm -f "$POWEROFF_MODULES_LOAD"
|
sudo rm -f "$POWEROFF_MODULES_LOAD"
|
||||||
sudo modprobe -r "$POWEROFF_DKMS_NAME" 2>/dev/null
|
best_effort sudo modprobe -r "$POWEROFF_DKMS_NAME"
|
||||||
[[ -d "$POWEROFF_DKMS_SRC" ]] || return 0
|
[[ -d "$POWEROFF_DKMS_SRC" ]] || return 0
|
||||||
sudo dkms remove "$POWEROFF_DKMS_NAME/$POWEROFF_DKMS_VER" --all >/dev/null 2>&1
|
sudo dkms remove "$POWEROFF_DKMS_NAME/$POWEROFF_DKMS_VER" --all >/dev/null 2>&1
|
||||||
sudo rm -rf "$POWEROFF_DKMS_SRC"
|
sudo rm -rf "$POWEROFF_DKMS_SRC"
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "Pin the kernel" (kpin), retired: newer linux-cachyos releases rebooted the
|
||||||
|
# Steam Machine instead of shutting down, which the power-off fix
|
||||||
|
# (lib/fremont-poweroff.sh) made unnecessary. Only what removes an existing pin
|
||||||
|
# is still offered (kpin_available), a sub-option of Steam Machine support.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
# Kernel pinned on a Steam Machine (optional): newer linux-cachyos releases
|
||||||
|
# rebooted it instead of shutting down, which the power-off fix now handles. 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. The
|
||||||
|
# power-off fix made it unnecessary: only shown while on, to remove it.
|
||||||
|
kpin_available() { detect_valve_fremont && kpin_status; }
|
||||||
|
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() {
|
||||||
|
# Saved HDMI refresh boost EDIDs were for the pinned kernel only (newer
|
||||||
|
# ones read the whole EDID), also those of displays not connected now.
|
||||||
|
hdmi_status && hdmi_forget_all
|
||||||
|
remove_kernel_pin
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ steamos_release() {
|
|||||||
# capitals: steamos-3.9). Offline (e.g. in the installer): the one set
|
# capitals: steamos-3.9). Offline (e.g. in the installer): the one set
|
||||||
# before, if any.
|
# before, if any.
|
||||||
local v
|
local v
|
||||||
v="$(curl -fsL --max-time 15 "$VALVE_MIRROR/" 2>/dev/null | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
|
v="$(valve_newest_repo jupiter 15)"
|
||||||
if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}"
|
if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}"
|
||||||
else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi
|
else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ remove_session_sync() {
|
|||||||
# The plasmalogin sync bridge from an earlier run isn't needed on SDDM.
|
# The plasmalogin sync bridge from an earlier run isn't needed on SDDM.
|
||||||
if [[ -f /etc/systemd/system/sync-steamos-session.path ]]; then
|
if [[ -f /etc/systemd/system/sync-steamos-session.path ]]; then
|
||||||
info "Removing the plasma-login-manager sync bridge (not needed with SDDM)..."
|
info "Removing the plasma-login-manager sync bridge (not needed with SDDM)..."
|
||||||
sudo systemctl disable --now sync-steamos-session.path 2>/dev/null
|
best_effort sudo systemctl disable --now sync-steamos-session.path
|
||||||
sudo rm -f /etc/systemd/system/sync-steamos-session.path \
|
sudo rm -f /etc/systemd/system/sync-steamos-session.path \
|
||||||
/etc/systemd/system/sync-steamos-session.service \
|
/etc/systemd/system/sync-steamos-session.service \
|
||||||
/usr/local/bin/sync-steamos-session.sh
|
/usr/local/bin/sync-steamos-session.sh
|
||||||
|
|||||||
+78
-65
@@ -5,19 +5,33 @@
|
|||||||
|
|
||||||
# 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 boot silent nvidia bigpicture nvsilent theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
||||||
# One-off actions rather than on/off components: never preselected, never
|
# One-off actions rather than on/off components: never preselected, never
|
||||||
# re-applied, not listed as on or off.
|
# re-applied, not listed as on or off.
|
||||||
ACTIONS=(bios)
|
ACTIONS=(bios)
|
||||||
# Sub-options, shown indented under their parent and only while it's ticked.
|
# Sub-options, shown indented under their parent and only while it's ticked.
|
||||||
declare -A PARENT=([boot]=gaming [silent]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
||||||
|
# What ticking one item does to another, for the menu's toggles (toggle_component)
|
||||||
|
# and the app's ticks (normalize_wanted). A sub-option needs its parent: ticking it
|
||||||
|
# ticks the parent, unticking the parent unticks it (Where to boot is chosen with
|
||||||
|
# --boot, so the app's ticks never bring the conversion for it; HDMI refresh boost is
|
||||||
|
# retired and never brings Steam Machine support). Single user mode only makes sense
|
||||||
|
# on top of the SteamOS conversion (where that is offered: on NVIDIA it logs in by
|
||||||
|
# itself, see lib/single-user.sh).
|
||||||
|
declare -A REQUIRES=([single]=gaming)
|
||||||
|
for _c in "${!PARENT[@]}"; do [[ "$_c" == hdmi ]] || REQUIRES[$_c]=${PARENT[$_c]}; done
|
||||||
|
unset _c
|
||||||
|
# Opt-out sub-options are ticked and unticked along with their parent.
|
||||||
|
declare -A FOLLOWS=([nvidia]=bigpicture [machine]=poweroff [launcher]=steamgame)
|
||||||
|
# Ticking one unticks the other; in normalize_wanted the first in COMPONENTS wins.
|
||||||
|
declare -A EXCLUDES=([bigpicture]=nvsilent [nvsilent]=bigpicture)
|
||||||
# Never preselected on a first run: booting into the desktop is a choice,
|
# Never preselected on a first run: booting into the desktop is a choice,
|
||||||
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
||||||
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
||||||
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the
|
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the
|
||||||
# screen to confirm each step. Extended controller support builds kernel modules for
|
# screen to confirm each step. Extended controller support builds kernel modules for
|
||||||
# every installed kernel: opt-in.
|
# every installed kernel: opt-in.
|
||||||
NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support)
|
NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
||||||
# Feature versions: the Steamify version in which what a component's enable
|
# Feature versions: the Steamify version in which what a component's enable
|
||||||
# sets up last changed; set it to the new VERSION whenever you change one.
|
# sets up last changed; set it to the new VERSION whenever you change one.
|
||||||
# Each successful run records it (state "features"); a component that's on
|
# Each successful run records it (state "features"); a component that's on
|
||||||
@@ -26,7 +40,7 @@ NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support)
|
|||||||
# FEATURE_BASELINE.
|
# FEATURE_BASELINE.
|
||||||
FEATURE_BASELINE=2.1.0
|
FEATURE_BASELINE=2.1.0
|
||||||
declare -A FEATURE_VERSION=(
|
declare -A FEATURE_VERSION=(
|
||||||
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.1.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
||||||
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
|
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
|
||||||
[kpin]=2.1.0 [hdmi]=2.1.0
|
[kpin]=2.1.0 [hdmi]=2.1.0
|
||||||
)
|
)
|
||||||
@@ -35,7 +49,7 @@ 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"
|
[boot]="Boot into the desktop instead of gaming mode"
|
||||||
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
|
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
|
||||||
[silent]="Start Steam silently: in the tray at login on the desktop, no window"
|
[silent]="Start Steam silently in desktop mode: in the tray at login on the desktop, no window"
|
||||||
[nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)"
|
[nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)"
|
||||||
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
|
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
|
||||||
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
||||||
@@ -73,6 +87,8 @@ component_available() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_wanted() { [[ "${WANTED[$1]:-0}" == 1 ]]; }
|
||||||
|
is_current() { [[ "${CURRENT[$1]:-0}" == 1 ]]; }
|
||||||
is_action() { [[ " ${ACTIONS[*]} " == *" $1 "* ]]; }
|
is_action() { [[ " ${ACTIONS[*]} " == *" $1 "* ]]; }
|
||||||
|
|
||||||
boot_mode() {
|
boot_mode() {
|
||||||
@@ -81,25 +97,12 @@ boot_mode() {
|
|||||||
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
silent_needs_boot() {
|
|
||||||
# On a Steam Machine, silent start only makes sense when it boots into
|
|
||||||
# the desktop (gaming mode starts its own Steam): the option is hidden,
|
|
||||||
# and off, while "Boot into" is gaming mode.
|
|
||||||
machine_available
|
|
||||||
}
|
|
||||||
|
|
||||||
silent_normalize() {
|
|
||||||
silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && WANTED[silent]=0
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
menu_visible() {
|
menu_visible() {
|
||||||
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
||||||
# while its parent is ticked.
|
# while its parent is ticked.
|
||||||
component_available "$1" || return 1
|
component_available "$1" || return 1
|
||||||
# Silent start is hidden while Steam starts in Big Picture.
|
# Silent start is hidden while Steam starts in Big Picture.
|
||||||
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
||||||
[[ "$1" == silent ]] && silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && return 1
|
|
||||||
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +131,7 @@ feature_outdated() {
|
|||||||
# On, but set up by an older version of that feature (compared as
|
# On, but set up by an older version of that feature (compared as
|
||||||
# versions: 2.10.0 is newer than 2.9.0).
|
# versions: 2.10.0 is newer than 2.9.0).
|
||||||
local have want
|
local have want
|
||||||
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
is_current "$1" || return 1
|
||||||
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
||||||
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
||||||
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
||||||
@@ -167,6 +170,8 @@ feature_new() {
|
|||||||
feature_added "$1" && [[ " ${NO_PRESELECT[*]} " != *" $1 "* ]]
|
feature_added "$1" && [[ " ${NO_PRESELECT[*]} " != *" $1 "* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
feature_any_new() { feature_new "$1" || feature_new_optin "$1"; }
|
||||||
|
|
||||||
feature_new_optin() {
|
feature_new_optin() {
|
||||||
# A new opt-in option (unticked by default): the "new" badge only, it stays
|
# A new opt-in option (unticked by default): the "new" badge only, it stays
|
||||||
# unticked. Boot into is a choice row of the conversion, not an item.
|
# unticked. Boot into is a choice row of the conversion, not an item.
|
||||||
@@ -220,7 +225,6 @@ detect_components() {
|
|||||||
done
|
done
|
||||||
machine_available && WANTED[cec]=1
|
machine_available && WANTED[cec]=1
|
||||||
fi
|
fi
|
||||||
silent_normalize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defaults_options() {
|
defaults_options() {
|
||||||
@@ -266,18 +270,17 @@ defaults_options() {
|
|||||||
warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC."
|
warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC."
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
[[ "${WANTED[single]}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
is_wanted single && component_available gaming && WANTED[gaming]=1
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
[[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1
|
[[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
case "$boot" in
|
case "$boot" in
|
||||||
desktop)
|
desktop)
|
||||||
[[ "${WANTED[gaming]}" == 1 ]] || { err "--boot desktop needs the SteamOS conversion (gaming)."; return 1; }
|
is_wanted gaming || { err "--boot desktop needs the SteamOS conversion (gaming)."; return 1; }
|
||||||
WANTED[boot]=1 ;;
|
WANTED[boot]=1 ;;
|
||||||
gamescope) WANTED[boot]=0 ;;
|
gamescope) WANTED[boot]=0 ;;
|
||||||
esac
|
esac
|
||||||
silent_normalize
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,42 +302,53 @@ defaults_list() {
|
|||||||
on=false
|
on=false
|
||||||
[[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true
|
[[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true
|
||||||
[[ "$c" == cec ]] && machine_available && on=true
|
[[ "$c" == cec ]] && machine_available && on=true
|
||||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
items+="${items:+,}$(json_item_head "$c" "$kind"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
||||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
|
||||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
|
||||||
done
|
done
|
||||||
printf '[%s]\n' "$items"
|
printf '[%s]\n' "$items"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
children_of() {
|
||||||
|
# children_of <id>: the items that need <id> (REQUIRES), one per line.
|
||||||
|
local c
|
||||||
|
for c in "${COMPONENTS[@]}"; do [[ "${REQUIRES[$c]:-}" == "$1" ]] && echo "$c"; done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
toggle_component() {
|
toggle_component() {
|
||||||
local c="$1"
|
local c="$1" p x
|
||||||
component_selectable "$c" || return 1
|
component_selectable "$c" || return 1
|
||||||
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
||||||
# Single user mode only makes sense on top of the SteamOS conversion.
|
if is_wanted "$c"; then
|
||||||
# (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.)
|
p="${REQUIRES[$c]:-}"
|
||||||
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi
|
[[ -n "$p" ]] && component_available "$p" && WANTED[$p]=1
|
||||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
|
x="${EXCLUDES[$c]:-}"
|
||||||
# Where to boot to is part of the conversion, too.
|
[[ -n "$x" ]] && WANTED[$x]=0
|
||||||
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi
|
else
|
||||||
# Big Picture is opt-out: ticked along with "Gaming on NVIDIA".
|
for x in $(children_of "$c"); do WANTED[$x]=0; done
|
||||||
if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi
|
fi
|
||||||
if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[nvsilent]=0; fi
|
x="${FOLLOWS[$c]:-}"
|
||||||
# Silent and Big Picture exclude each other.
|
[[ -n "$x" ]] && component_available "$x" && WANTED[$x]=${WANTED[$c]}
|
||||||
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi
|
}
|
||||||
if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi
|
|
||||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; fi
|
normalize_wanted() {
|
||||||
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
|
# The same rules for a whole selection (the app ticks exactly the items it
|
||||||
silent_normalize
|
# sends): a ticked sub-option brings its parent, two that exclude each other
|
||||||
# The power-off fix is opt-out: ticked along with Steam Machine support.
|
# keep the first, and an unticked parent takes its sub-options with it
|
||||||
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi
|
# (only where the parent is offered: single user mode stays on NVIDIA PCs).
|
||||||
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi
|
local c p x
|
||||||
if [[ "$c" == machine && "${WANTED[machine]}" == 0 ]]; then WANTED[kpin]=0; WANTED[bios]=0; fi
|
for c in "${COMPONENTS[@]}"; do
|
||||||
if [[ "$c" == kpin && "${WANTED[kpin]}" == 1 ]]; then WANTED[machine]=1; fi
|
p="${REQUIRES[$c]:-}"
|
||||||
if [[ "$c" == bios && "${WANTED[bios]}" == 1 ]]; then WANTED[machine]=1; fi
|
[[ -n "$p" && "$c" != boot && "${WANTED[$c]:-0}" == 1 ]] && component_available "$p" && WANTED[$p]=1
|
||||||
# Steam starts Steamify through the shortcut's start script.
|
done
|
||||||
# Opt-out, like the power-off fix: ticked along with the shortcut.
|
for c in "${COMPONENTS[@]}"; do
|
||||||
if [[ "$c" == launcher ]] && component_available steamgame; then WANTED[steamgame]=${WANTED[launcher]}; fi
|
x="${EXCLUDES[$c]:-}"
|
||||||
if [[ "$c" == steamgame && "${WANTED[steamgame]}" == 1 ]]; then WANTED[launcher]=1; fi
|
[[ -n "$x" && "${WANTED[$c]:-0}" == 1 ]] && WANTED[$x]=0
|
||||||
|
done
|
||||||
|
for c in "${COMPONENTS[@]}"; do
|
||||||
|
p="${REQUIRES[$c]:-}"
|
||||||
|
[[ -n "$p" && "${WANTED[$p]:-0}" == 0 ]] && component_available "$p" && WANTED[$c]=0
|
||||||
|
done
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
@@ -346,16 +360,16 @@ show_menu() {
|
|||||||
menu_visible "$c" || continue
|
menu_visible "$c" || continue
|
||||||
i=$((i + 1)); MENU_ITEMS[$i]=$c
|
i=$((i + 1)); MENU_ITEMS[$i]=$c
|
||||||
# Pad the plain word, then colour it: colour codes would count as width.
|
# Pad the plain word, then colour it: colour codes would count as width.
|
||||||
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="on"
|
now="off"; is_current "$c" && now="on"
|
||||||
is_action "$c" && now="-"
|
is_action "$c" && now="-"
|
||||||
now="$(printf '%-6s' "$now")"
|
now="$(printf '%-6s' "$now")"
|
||||||
[[ "${CURRENT[$c]}" == 1 ]] && now="${now/on/${c_green}on${c_reset}}"
|
is_current "$c" && now="${now/on/${c_green}on${c_reset}}"
|
||||||
want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]"
|
want="[ ]"; is_wanted "$c" && want="[x]"
|
||||||
if [[ "$c" == boot ]]; then
|
if [[ "$c" == boot ]]; then
|
||||||
# A choice rather than a checkbox: Now/Want show the mode.
|
# A choice rather than a checkbox: Now/Want show the mode.
|
||||||
now="gaming"; [[ "${CURRENT[boot]}" == 1 ]] && now="desk"
|
now="gaming"; is_current boot && now="desk"
|
||||||
[[ "${CURRENT[gaming]}" == 1 ]] || now="-"
|
is_current gaming || now="-"
|
||||||
want="gaming"; [[ "${WANTED[boot]}" == 1 ]] && want="desk"
|
want="gaming"; is_wanted boot && want="desk"
|
||||||
printf " %-3s %-6s %-6s └ %s\n" "$i" "$now" "$want" "$(boot_choice "${WANTED[boot]}")"
|
printf " %-3s %-6s %-6s └ %s\n" "$i" "$now" "$want" "$(boot_choice "${WANTED[boot]}")"
|
||||||
elif ! component_selectable "$c"; then
|
elif ! component_selectable "$c"; then
|
||||||
local tree=""; [[ -n "${PARENT[$c]:-}" ]] && tree=" └ "
|
local tree=""; [[ -n "${PARENT[$c]:-}" ]] && tree=" └ "
|
||||||
@@ -394,8 +408,8 @@ draw_menu_tui() {
|
|||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
menu_visible "$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="[ ]"; is_wanted "$c" && box="[${c_green}x${c_reset}]"
|
||||||
state=" (now: off)"; [[ "${CURRENT[$c]}" == 1 ]] && state=" (now: ${c_green}on${c_reset})"
|
state=" (now: off)"; is_current "$c" && state=" (now: ${c_green}on${c_reset})"
|
||||||
is_action "$c" && state=" (opt-in, runs once)"
|
is_action "$c" && state=" (opt-in, runs once)"
|
||||||
line="$box ${LABEL[$c]}"
|
line="$box ${LABEL[$c]}"
|
||||||
if [[ "$c" == boot ]]; then
|
if [[ "$c" == boot ]]; then
|
||||||
@@ -403,9 +417,9 @@ draw_menu_tui() {
|
|||||||
# Indented under the conversion, whose sub-option it is.
|
# Indented under the conversion, whose sub-option it is.
|
||||||
line="$(boot_choice "${WANTED[boot]}")"
|
line="$(boot_choice "${WANTED[boot]}")"
|
||||||
line=" └ ${line/\[/[${c_green}}"; line="${line/\]/${c_reset}]}"
|
line=" └ ${line/\[/[${c_green}}"; line="${line/\]/${c_reset}]}"
|
||||||
local mode=gamescope; [[ "${CURRENT[boot]}" == 1 ]] && mode=desktop
|
local mode=gamescope; is_current boot && mode=desktop
|
||||||
state=" (${c_bold}←/→${c_reset} choose)"
|
state=" (${c_bold}←/→${c_reset} choose)"
|
||||||
[[ "${CURRENT[gaming]}" == 1 ]] && state=" (now: $mode; ${c_bold}←/→${c_reset} choose)"
|
is_current gaming && state=" (now: $mode; ${c_bold}←/→${c_reset} choose)"
|
||||||
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
||||||
line=" └ $line"
|
line=" └ $line"
|
||||||
fi
|
fi
|
||||||
@@ -432,7 +446,6 @@ draw_menu_tui() {
|
|||||||
run_menu_tui() {
|
run_menu_tui() {
|
||||||
local cursor=0 key rest count
|
local cursor=0 key rest count
|
||||||
tput civis 2>/dev/null
|
tput civis 2>/dev/null
|
||||||
trap 'tput cnorm 2>/dev/null' EXIT
|
|
||||||
while true; do
|
while true; do
|
||||||
draw_menu_tui "$cursor"
|
draw_menu_tui "$cursor"
|
||||||
count=${#MENU_ITEMS[@]}
|
count=${#MENU_ITEMS[@]}
|
||||||
@@ -494,7 +507,7 @@ plan_changes() {
|
|||||||
done
|
done
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" || continue
|
component_available "$c" || continue
|
||||||
[[ "${WANTED[$c]}" == 1 ]] || continue
|
is_wanted "$c" || continue
|
||||||
if is_action "$c"; then TO_ENABLE+=("$c"); continue; fi
|
if is_action "$c"; then TO_ENABLE+=("$c"); continue; fi
|
||||||
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] || feature_outdated "$c" ||
|
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] || feature_outdated "$c" ||
|
||||||
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
|
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
|
||||||
@@ -506,7 +519,7 @@ plan_changes() {
|
|||||||
apply_changes() {
|
apply_changes() {
|
||||||
local c failed=()
|
local c failed=()
|
||||||
LOGIN_MANAGER=plasmalogin
|
LOGIN_MANAGER=plasmalogin
|
||||||
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
|
is_wanted single && LOGIN_MANAGER=sddm
|
||||||
|
|
||||||
for c in "${TO_DISABLE[@]}"; do
|
for c in "${TO_DISABLE[@]}"; do
|
||||||
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: gamescope${c_reset}"
|
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: gamescope${c_reset}"
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ bootstrap_yay() {
|
|||||||
sudo pacman -S --needed --noconfirm base-devel git || return 1
|
sudo pacman -S --needed --noconfirm base-devel git || return 1
|
||||||
|
|
||||||
local tmp_dir
|
local tmp_dir
|
||||||
tmp_dir="$(mktemp -d)"
|
make_tmpdir tmp_dir
|
||||||
info "Cloning yay-bin from the AUR..."
|
info "Cloning yay-bin from the AUR..."
|
||||||
if ! git clone --depth 1 https://aur.archlinux.org/yay-bin.git "$tmp_dir/yay-bin"; then
|
if ! git clone --depth 1 https://aur.archlinux.org/yay-bin.git "$tmp_dir/yay-bin"; then
|
||||||
err "Failed to clone yay-bin from the AUR."
|
err "Failed to clone yay-bin from the AUR."
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ single_wallet_enable() {
|
|||||||
ok "Single user mode's wallet (no password) is back; your own is kept as kdewallet.kwl$WALLET_BACKUP."
|
ok "Single user mode's wallet (no password) is back; your own is kept as kdewallet.kwl$WALLET_BACKUP."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
tmp="$(mktemp -d)"
|
make_tmpdir tmp
|
||||||
if ! fetch_valve_presets "$tmp"; then
|
if ! fetch_valve_presets "$tmp"; then
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
warn "Couldn't get Valve's empty wallet; apps may still ask for the wallet password."
|
warn "Couldn't get Valve's empty wallet; apps may still ask for the wallet password."
|
||||||
|
|||||||
+1
-1
@@ -123,7 +123,7 @@ migrate_layout() {
|
|||||||
"$(wizard_desktop_dir)/$WIZARD_DESKTOP_NAME"; do
|
"$(wizard_desktop_dir)/$WIZARD_DESKTOP_NAME"; do
|
||||||
[[ -f "$f" ]] && sed -i "s|$old_bin/|$STEAMIFY_BIN/|g" "$f"
|
[[ -f "$f" ]] && sed -i "s|$old_bin/|$STEAMIFY_BIN/|g" "$f"
|
||||||
done
|
done
|
||||||
user_systemctl daemon-reload 2>/dev/null
|
best_effort user_systemctl daemon-reload
|
||||||
fi
|
fi
|
||||||
if [[ -f "$old_icon" ]]; then
|
if [[ -f "$old_icon" ]]; then
|
||||||
if [[ -e "$WIZARD_ICON" ]]; then rm -f "$old_icon"; else mv "$old_icon" "$WIZARD_ICON"; fi
|
if [[ -e "$WIZARD_ICON" ]]; then rm -f "$old_icon"; else mv "$old_icon" "$WIZARD_ICON"; fi
|
||||||
|
|||||||
+31
-14
@@ -16,34 +16,51 @@ steam_enable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
|
# Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
|
||||||
# no window) on the Plasma desktop.
|
# no window) on the Plasma desktop. It is Steam's own autostart entry, the file
|
||||||
|
# Steam's setting "Run Steam when my computer starts" creates and removes, so
|
||||||
|
# that setting shows what Steamify did (and the other way around). Steam's copy
|
||||||
|
# is the system steam.desktop; ours has -silent in its Exec line.
|
||||||
|
STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop"
|
||||||
|
STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop
|
||||||
|
|
||||||
silent_status() {
|
silent_status() {
|
||||||
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
# The old systemd unit counts as on too (until it is migrated by an update of this option).
|
||||||
|
grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" ||
|
||||||
|
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
silent_old_unit_remove() {
|
||||||
|
# Before 2.11.0 the option was a systemd user unit: it would start Steam a second time.
|
||||||
|
local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||||
|
[[ -f "$unit" ]] || return 0
|
||||||
|
best_effort user_systemctl disable --now steam-desktop-autostart.service
|
||||||
|
rm -f "$unit"
|
||||||
|
user_systemctl daemon-reload
|
||||||
}
|
}
|
||||||
|
|
||||||
silent_enable() {
|
silent_enable() {
|
||||||
local systemd_user_dir="$HOME/.config/systemd/user"
|
silent_old_unit_remove
|
||||||
mkdir -p "$systemd_user_dir"
|
mkdir -p "$(dirname "$STEAM_AUTOSTART")"
|
||||||
service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service"
|
if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then
|
||||||
# Clean out old .desktop shortcut so they don't fight
|
sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART"
|
||||||
rm -f "$HOME/.config/autostart/steam.desktop"
|
fi
|
||||||
user_systemctl daemon-reload
|
silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \
|
||||||
user_systemctl enable --now steam-desktop-autostart.service
|
'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART"
|
||||||
ok "Steam starts silently on the desktop."
|
ok "Steam starts silently on the desktop from the next login."
|
||||||
}
|
}
|
||||||
|
|
||||||
silent_disable() {
|
silent_disable() {
|
||||||
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
silent_old_unit_remove
|
||||||
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
silent_status && rm -f "$STEAM_AUTOSTART"
|
||||||
user_systemctl daemon-reload
|
|
||||||
ok "Steam no longer starts by itself on the desktop."
|
ok "Steam no longer starts by itself on the desktop."
|
||||||
}
|
}
|
||||||
|
|
||||||
steam_disable() {
|
steam_disable() {
|
||||||
info "Removing Steam desktop settings..."
|
info "Removing Steam desktop settings..."
|
||||||
# The autostart unit is the `silent` option's: removed with it, and here
|
# The autostart entry is the `silent` option's: removed with it, and here
|
||||||
# too for when the conversion goes off by itself.
|
# too for when the conversion goes off by itself.
|
||||||
silent_status && silent_disable
|
silent_status && silent_disable
|
||||||
|
silent_old_unit_remove
|
||||||
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
||||||
ok "Steam desktop settings removed (takes full effect at next login)."
|
ok "Steam desktop settings removed (takes full effect at next login)."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-6
@@ -56,7 +56,7 @@ steamgame_steam_busy() {
|
|||||||
|
|
||||||
steamgame_edit() {
|
steamgame_edit() {
|
||||||
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
||||||
# again if it was running (through our autostart unit when that's there).
|
# again if it was running (silently, in the tray).
|
||||||
local was_running=false i
|
local was_running=false i
|
||||||
if pgrep -x steam >/dev/null; then
|
if pgrep -x steam >/dev/null; then
|
||||||
steamgame_steam_busy && return 1
|
steamgame_steam_busy && return 1
|
||||||
@@ -72,11 +72,7 @@ steamgame_edit() {
|
|||||||
fi
|
fi
|
||||||
"$1"; local rc=$?
|
"$1"; local rc=$?
|
||||||
if [[ "$was_running" == true ]]; then
|
if [[ "$was_running" == true ]]; then
|
||||||
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
|
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
||||||
user_systemctl start steam-desktop-autostart.service
|
|
||||||
else
|
|
||||||
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
info "Steam is starting again."
|
info "Steam is starting again."
|
||||||
fi
|
fi
|
||||||
return "$rc"
|
return "$rc"
|
||||||
|
|||||||
+48
-194
@@ -15,164 +15,6 @@ detect_valve_fremont() {
|
|||||||
[[ "$vendor" == "OEM" && "$product" == "F7F" ]]
|
[[ "$vendor" == "OEM" && "$product" == "F7F" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Kernel pinned on a Steam Machine (optional): newer linux-cachyos releases
|
|
||||||
# rebooted it instead of shutting down, which the power-off fix now handles. 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. The
|
|
||||||
# power-off fix made it unnecessary: only shown while on, to remove it.
|
|
||||||
kpin_available() { detect_valve_fremont && kpin_status; }
|
|
||||||
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() {
|
|
||||||
# Saved HDMI refresh boost EDIDs were for the pinned kernel only (newer
|
|
||||||
# ones read the whole EDID), also those of displays not connected now.
|
|
||||||
hdmi_status && hdmi_forget_all
|
|
||||||
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,
|
||||||
@@ -200,24 +42,7 @@ install_kernel_headers() {
|
|||||||
sudo pacman -S --needed --noconfirm "${headers[@]}"
|
sudo pacman -S --needed --noconfirm "${headers[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
install_valve_led_driver() {
|
led_write_dkms_override() {
|
||||||
# Installs the leds-valve DKMS driver from the AUR so the front LED
|
|
||||||
# bar is exposed under /sys/class/leds/valve-leds[N].
|
|
||||||
local aur_helper
|
|
||||||
aur_helper="$(find_aur_helper)"
|
|
||||||
if [[ -z "$aur_helper" ]]; then
|
|
||||||
warn "No AUR helper available - can't install leds-valve-dkms-git."
|
|
||||||
warn "Install one yourself, then run: yay -S leds-valve-dkms-git"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local -a flags
|
|
||||||
read -ra flags <<< "$(aur_noninteractive_flags "$aur_helper")"
|
|
||||||
|
|
||||||
# Headers first: without them the package installs fine but DKMS
|
|
||||||
# silently builds nothing, so modprobe later finds no module.
|
|
||||||
install_kernel_headers || return 1
|
|
||||||
|
|
||||||
# The upstream Makefile builds against `uname -r` instead of the kernel
|
# The upstream Makefile builds against `uname -r` instead of the kernel
|
||||||
# DKMS targets, so every other installed kernel (e.g. linux-cachyos-lts)
|
# DKMS targets, so every other installed kernel (e.g. linux-cachyos-lts)
|
||||||
# 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
|
||||||
@@ -232,17 +57,22 @@ install_valve_led_driver() {
|
|||||||
err "Couldn't write $LED_DKMS_OVERRIDE; without it the LED driver only builds for the running kernel."
|
err "Couldn't write $LED_DKMS_OVERRIDE; without it the LED driver only builds for the running kernel."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if ! pacman -Qi leds-valve-dkms-git >/dev/null 2>&1; then
|
led_install_package() {
|
||||||
info "Installing leds-valve-dkms-git from the AUR via $aur_helper (non-interactive)..."
|
# led_install_package <aur helper>
|
||||||
if ! "$aur_helper" -S "${flags[@]}" leds-valve-dkms-git; then
|
local aur_helper="$1"
|
||||||
err "Installing leds-valve-dkms-git failed."
|
local -a flags
|
||||||
return 1
|
read -ra flags <<< "$(aur_noninteractive_flags "$aur_helper")"
|
||||||
fi
|
if pacman -Qi leds-valve-dkms-git >/dev/null 2>&1; then
|
||||||
else
|
|
||||||
ok "leds-valve-dkms-git already installed."
|
ok "leds-valve-dkms-git already installed."
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
info "Installing leds-valve-dkms-git from the AUR via $aur_helper (non-interactive)..."
|
||||||
|
"$aur_helper" -S "${flags[@]}" leds-valve-dkms-git || { err "Installing leds-valve-dkms-git failed."; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
led_build_all_kernels() {
|
||||||
# Build for every installed kernel that has headers, so booting another
|
# Build for every installed kernel that has headers, so booting another
|
||||||
# one (e.g. the LTS kernel) still has the driver.
|
# one (e.g. the LTS kernel) still has the driver.
|
||||||
local kdir kver
|
local kdir kver
|
||||||
@@ -257,7 +87,9 @@ install_valve_led_driver() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
led_load_module() {
|
||||||
# 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
|
||||||
|
|
||||||
@@ -282,7 +114,26 @@ install_valve_led_driver() {
|
|||||||
warn "No valve-leds nodes under /sys/class/leds/ yet. Reboot, then check with:"
|
warn "No valve-leds nodes under /sys/class/leds/ yet. Reboot, then check with:"
|
||||||
warn " ls /sys/class/leds/ | grep valve ; sudo dmesg | grep -i valve"
|
warn " ls /sys/class/leds/ | grep valve ; sudo dmesg | grep -i valve"
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_valve_led_driver() {
|
||||||
|
# Installs the leds-valve DKMS driver from the AUR so the front LED
|
||||||
|
# bar is exposed under /sys/class/leds/valve-leds[N].
|
||||||
|
local aur_helper
|
||||||
|
aur_helper="$(find_aur_helper)"
|
||||||
|
if [[ -z "$aur_helper" ]]; then
|
||||||
|
warn "No AUR helper available - can't install leds-valve-dkms-git."
|
||||||
|
warn "Install one yourself, then run: yay -S leds-valve-dkms-git"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Headers first: without them the package installs fine but DKMS
|
||||||
|
# silently builds nothing, so modprobe later finds no module.
|
||||||
|
install_kernel_headers || return 1
|
||||||
|
led_write_dkms_override || return 1
|
||||||
|
led_install_package "$aur_helper" || return 1
|
||||||
|
led_build_all_kernels || return 1
|
||||||
|
led_load_module
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_UDEV_RULE="/etc/udev/rules.d/70-valve-leds-user.rules"
|
LED_UDEV_RULE="/etc/udev/rules.d/70-valve-leds-user.rules"
|
||||||
@@ -407,14 +258,17 @@ wifi_backend_disable() {
|
|||||||
|
|
||||||
serial_enable() {
|
serial_enable() {
|
||||||
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
||||||
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null &&
|
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null ||
|
||||||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
|
||||||
{ err "Making the serial number readable for Steam failed."; return 1; }
|
{ err "Making the serial number readable for Steam failed."; return 1; }
|
||||||
|
# The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot).
|
||||||
|
best_effort sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
||||||
|
info "The serial number becomes readable for Steam at the next boot."
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_disable() {
|
serial_disable() {
|
||||||
sudo rm -f "$SERIAL_TMPFILES"
|
sudo rm -f "$SERIAL_TMPFILES"
|
||||||
sudo chmod 0400 /sys/class/dmi/id/product_serial 2>/dev/null
|
best_effort sudo chmod 0400 /sys/class/dmi/id/product_serial
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,7 +301,7 @@ EOF
|
|||||||
wifi_backend_enable || return 1
|
wifi_backend_enable || return 1
|
||||||
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
|
||||||
user_systemctl enable steamos-manager.service 2>/dev/null
|
best_effort user_systemctl enable steamos-manager.service
|
||||||
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
|
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
|
||||||
cec_status && cec_link_steamos_manager
|
cec_status && cec_link_steamos_manager
|
||||||
|
|
||||||
@@ -464,19 +318,19 @@ EOF
|
|||||||
|
|
||||||
machine_disable() {
|
machine_disable() {
|
||||||
info "Removing Steam Machine support..."
|
info "Removing Steam Machine support..."
|
||||||
user_systemctl disable --now steamos-manager.service 2>/dev/null
|
best_effort user_systemctl disable --now steamos-manager.service
|
||||||
sudo systemctl disable --now steamos-manager.service 2>/dev/null
|
best_effort sudo systemctl disable --now steamos-manager.service
|
||||||
sudo systemctl disable --now inputplumber.service 2>/dev/null
|
best_effort sudo systemctl disable --now inputplumber.service
|
||||||
sudo pacman -Rns --noconfirm steamos-manager inputplumber 2>/dev/null
|
best_effort sudo pacman -Rns --noconfirm steamos-manager inputplumber
|
||||||
serial_disable
|
serial_disable
|
||||||
wifi_backend_disable
|
wifi_backend_disable
|
||||||
sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf
|
sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
sudo modprobe -r leds-valve 2>/dev/null
|
best_effort sudo modprobe -r leds-valve
|
||||||
sudo pacman -Rns --noconfirm leds-valve-dkms-git 2>/dev/null
|
best_effort sudo pacman -Rns --noconfirm leds-valve-dkms-git
|
||||||
krevert machine
|
krevert machine
|
||||||
reload_powerdevil
|
reload_powerdevil
|
||||||
sudo systemctl disable ensure-kernel-headers.service 2>/dev/null
|
best_effort sudo systemctl disable ensure-kernel-headers.service
|
||||||
led_dkms_override_remove
|
led_dkms_override_remove
|
||||||
sudo rm -f "$HEADERS_UNIT" "$HEADERS_SCRIPT"
|
sudo rm -f "$HEADERS_UNIT" "$HEADERS_SCRIPT"
|
||||||
sudo rm -rf "$(dirname "$HEADERS_SCRIPT")" "$(dirname "$HEADERS_SCRIPT_OLD")"
|
sudo rm -rf "$(dirname "$HEADERS_SCRIPT")" "$(dirname "$HEADERS_SCRIPT_OLD")"
|
||||||
|
|||||||
+7
-21
@@ -8,7 +8,6 @@
|
|||||||
# package-owned); per-user settings go through the undo journal.
|
# package-owned); per-user settings go through the undo journal.
|
||||||
# Sourced by steamify.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"
|
|
||||||
NESTED_DIR=/usr/local/share/applications/steam/holo-nested-desktop
|
NESTED_DIR=/usr/local/share/applications/steam/holo-nested-desktop
|
||||||
EXTRAS_FILES=(
|
EXTRAS_FILES=(
|
||||||
/usr/local/bin/holo-add-to-steam
|
/usr/local/bin/holo-add-to-steam
|
||||||
@@ -23,25 +22,12 @@ STEAM_KEYBOARD_RULE=cachyos-gamescope-boot-steam-keyboard
|
|||||||
|
|
||||||
fetch_valve_presets() {
|
fetch_valve_presets() {
|
||||||
# fetch_valve_presets <dir>: download and extract the newest
|
# fetch_valve_presets <dir>: download and extract the newest
|
||||||
# steamdeck-kde-presets into <dir>. The newest SteamOS release repo
|
# steamdeck-kde-presets (from the newest SteamOS release repo, jupiter-3.9,
|
||||||
# (jupiter-3.9, jupiter-3.10, ...) is found on the mirror; its pacman
|
# jupiter-3.10, ...) into <dir>.
|
||||||
# database gives the exact file name and SHA-256, which is verified.
|
local dir="$1" pkg
|
||||||
local dir="$1" repo desc file_name sha256
|
pkg="$(valve_fetch_pkg jupiter steamdeck-kde-presets "$dir")" || return 1
|
||||||
repo="$(curl -fsL "$VALVE_MIRROR/" | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
|
tar -I unzstd -xf "$pkg" -C "$dir" usr/bin usr/share ||
|
||||||
[[ -n "$repo" ]] && curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$repo.db" -o "$dir/repo.db" ||
|
{ err "Extracting $(basename "$pkg") failed."; return 1; }
|
||||||
{ err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; }
|
|
||||||
desc="$(tar -tf "$dir/repo.db" 2>/dev/null | grep -E '^steamdeck-kde-presets-[0-9][^/]*/desc$' | head -n 1)"
|
|
||||||
[[ -n "$desc" ]] || { err "No steamdeck-kde-presets in Valve's $repo repository."; return 1; }
|
|
||||||
file_name="$(tar -xOf "$dir/repo.db" "$desc" | awk '/^%FILENAME%$/ { getline; print }')"
|
|
||||||
sha256="$(tar -xOf "$dir/repo.db" "$desc" | awk '/^%SHA256SUM%$/ { getline; print }')"
|
|
||||||
|
|
||||||
info "Downloading $file_name ($repo)..."
|
|
||||||
curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$file_name" -o "$dir/presets.pkg.tar.zst" ||
|
|
||||||
{ err "Downloading $file_name failed."; return 1; }
|
|
||||||
echo "$sha256 $dir/presets.pkg.tar.zst" | sha256sum -c --quiet - ||
|
|
||||||
{ err "Checksum mismatch for $file_name; not using it."; return 1; }
|
|
||||||
tar -I unzstd -xf "$dir/presets.pkg.tar.zst" -C "$dir" usr/bin usr/share ||
|
|
||||||
{ err "Extracting $file_name failed."; return 1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extras_enable() {
|
extras_enable() {
|
||||||
@@ -54,7 +40,7 @@ extras_enable() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
local tmp_dir src
|
local tmp_dir src
|
||||||
tmp_dir="$(mktemp -d)"
|
make_tmpdir tmp_dir
|
||||||
if ! fetch_valve_presets "$tmp_dir"; then
|
if ! fetch_valve_presets "$tmp_dir"; then
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Valve's SteamOS package mirror: finding its newest repository and fetching a
|
||||||
|
# verified package from it. Used by the SteamOS extras, the Steam Machine CEC
|
||||||
|
# driver, the BIOS update and the os-release version.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
VALVE_MIRROR="https://steamdeck-packages.steamos.cloud/archlinux-mirror"
|
||||||
|
|
||||||
|
valve_newest_repo() {
|
||||||
|
# valve_newest_repo <prefix> [max-seconds]: the newest <prefix>-X.Y repo
|
||||||
|
# (jupiter, holo), compared as versions: 3.10 is newer than 3.9. Prints
|
||||||
|
# nothing when the mirror can't be reached.
|
||||||
|
local -a limit=()
|
||||||
|
[[ -n "${2:-}" ]] && limit=(--max-time "$2")
|
||||||
|
curl -fsL "${limit[@]}" "$VALVE_MIRROR/" 2>/dev/null | grep -oE "$1-[0-9]+\.[0-9]+/" | tr -d / | sort -uV | tail -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
valve_repo_url() { echo "$VALVE_MIRROR/$1/os/x86_64"; }
|
||||||
|
|
||||||
|
valve_desc_field() {
|
||||||
|
# valve_desc_field <db> <desc path> <FIELD>: one value from a package's
|
||||||
|
# entry in a pacman database (FILENAME, SHA256SUM).
|
||||||
|
tar -xOf "$1" "$2" 2>/dev/null | awk -v f="%$3%" '$0 == f { getline; print }'
|
||||||
|
}
|
||||||
|
|
||||||
|
valve_fetch_pkg() {
|
||||||
|
# valve_fetch_pkg <repo prefix> <package> <dir>: download the newest
|
||||||
|
# <package> from the newest <prefix> repository into <dir> and print its
|
||||||
|
# path. The file name and SHA-256 come from the repository's database and
|
||||||
|
# the checksum is verified; the database is kept in <dir> for more calls.
|
||||||
|
local prefix="$1" name="$2" dir="$3" repo db desc file_name sha256
|
||||||
|
repo="$(valve_newest_repo "$prefix")"
|
||||||
|
db="$dir/$prefix.db"
|
||||||
|
if [[ ! -f "$db" ]]; then
|
||||||
|
[[ -n "$repo" ]] && curl -fsL "$(valve_repo_url "$repo")/$repo.db" -o "$db" ||
|
||||||
|
{ err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; }
|
||||||
|
fi
|
||||||
|
desc="$(tar -tf "$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="$(valve_desc_field "$db" "$desc" FILENAME)"
|
||||||
|
sha256="$(valve_desc_field "$db" "$desc" SHA256SUM)"
|
||||||
|
|
||||||
|
info "Downloading $file_name ($repo)..." >&2
|
||||||
|
curl -fsL "$(valve_repo_url "$repo")/$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"
|
||||||
|
}
|
||||||
+50
-21
@@ -47,26 +47,27 @@ theme_status() {
|
|||||||
[[ "$(kreadconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage)" == "$VAPOR_LOOKANDFEEL" ]]
|
[[ "$(kreadconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage)" == "$VAPOR_LOOKANDFEEL" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
theme_enable() {
|
theme_install_package() {
|
||||||
if ! pacman -Q cachyos-vapor >/dev/null 2>&1; then
|
pacman -Q cachyos-vapor >/dev/null 2>&1 && return 0
|
||||||
info "Installing cachyos-vapor..."
|
info "Installing cachyos-vapor..."
|
||||||
sudo pacman -S --needed --noconfirm cachyos-vapor || { err "Installing cachyos-vapor failed."; return 1; }
|
sudo pacman -S --needed --noconfirm cachyos-vapor || { err "Installing cachyos-vapor failed."; return 1; }
|
||||||
# Only remove it again on disable if we were the ones installing it.
|
# Only remove it again on disable if we were the ones installing it.
|
||||||
state_set theme installed_pkg 1
|
state_set theme installed_pkg 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
|
theme_check_offline() {
|
||||||
# Without a session (the ISO's installer), for a user who has never
|
# Without a session (the ISO's installer), for a user who has never
|
||||||
# logged in: the layout still CachyOS's default from /etc/skel is
|
# logged in: the layout still CachyOS's default from /etc/skel is
|
||||||
# removed (after the backup below), and Plasma builds its first layout
|
# removed (after the backup below), and Plasma builds its first layout
|
||||||
# from the look-and-feel package, as --resetLayout does below.
|
# from the look-and-feel package, as --resetLayout does below.
|
||||||
local offline=false layout=~/.config/plasma-org.kde.plasma.desktop-appletsrc
|
local layout=~/.config/plasma-org.kde.plasma.desktop-appletsrc
|
||||||
if [[ -z "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]]; then
|
if [[ -e "$layout" ]] && ! cmp -s "$layout" "/etc/skel/.config/${layout##*/}"; then
|
||||||
if [[ -e "$layout" ]] && ! cmp -s "$layout" "/etc/skel/.config/${layout##*/}"; then
|
err "Run this from the Plasma desktop: applying the Vapor layout needs a running Plasma session."
|
||||||
err "Run this from the Plasma desktop: applying the Vapor layout needs a running Plasma session."
|
return 1
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
offline=true
|
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_backup_originals() {
|
||||||
# Only the first time, so a re-apply doesn't overwrite the originals.
|
# Only the first time, so a re-apply doesn't overwrite the originals.
|
||||||
local backup="$STATE_DIR/theme-layout" f
|
local backup="$STATE_DIR/theme-layout" f
|
||||||
if [[ ! -d "$backup" ]]; then
|
if [[ ! -d "$backup" ]]; then
|
||||||
@@ -84,7 +85,9 @@ theme_enable() {
|
|||||||
[[ -f "$f" ]] && kset theme "$f" Settings gtk-cursor-theme-name \
|
[[ -f "$f" ]] && kset theme "$f" Settings gtk-cursor-theme-name \
|
||||||
"$(kreadconfig6 --file "$f" --group Settings --key gtk-cursor-theme-name)"
|
"$(kreadconfig6 --file "$f" --group Settings --key gtk-cursor-theme-name)"
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_set_look() {
|
||||||
kset theme kdeglobals KDE LookAndFeelPackage "$VAPOR_LOOKANDFEEL"
|
kset theme kdeglobals KDE LookAndFeelPackage "$VAPOR_LOOKANDFEEL"
|
||||||
# Vapor is a dark theme: register it as the dark one, or Plasma's Dark
|
# Vapor is a dark theme: register it as the dark one, or Plasma's Dark
|
||||||
# Mode toggle shows "off" and offers to switch to Breeze Dark.
|
# Mode toggle shows "off" and offers to switch to Breeze Dark.
|
||||||
@@ -94,6 +97,17 @@ theme_enable() {
|
|||||||
# scheme that is already named in the config, without writing its colors.
|
# scheme that is already named in the config, without writing its colors.
|
||||||
kset theme kdeglobals General ColorScheme --delete
|
kset theme kdeglobals General ColorScheme --delete
|
||||||
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
|
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_enable() {
|
||||||
|
theme_install_package || return 1
|
||||||
|
local offline=false
|
||||||
|
if [[ -z "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]]; then
|
||||||
|
theme_check_offline || return 1
|
||||||
|
offline=true
|
||||||
|
fi
|
||||||
|
theme_backup_originals
|
||||||
|
theme_set_look
|
||||||
|
|
||||||
if [[ "$offline" == true ]]; then
|
if [[ "$offline" == true ]]; then
|
||||||
rm -f ~/.config/plasma-org.kde.plasma.desktop-appletsrc ~/.config/plasmashellrc
|
rm -f ~/.config/plasma-org.kde.plasma.desktop-appletsrc ~/.config/plasmashellrc
|
||||||
@@ -106,17 +120,32 @@ theme_enable() {
|
|||||||
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
||||||
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
|
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
|
||||||
{ err "lookandfeeltool failed."; return 1; }
|
{ err "lookandfeeltool failed."; return 1; }
|
||||||
# The new layout has a new launcher, without single user's settings.
|
# The new layout has a new launcher, without single user's settings, and the default taskbar pins.
|
||||||
if single_status; then
|
sleep 3
|
||||||
sleep 3
|
stop_plasmashell_for_edit
|
||||||
stop_plasmashell_for_edit
|
taskbar_drop_discover
|
||||||
single_launcher
|
single_status && single_launcher
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
fi
|
|
||||||
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
||||||
ok "Vapor theme active."
|
ok "Vapor theme active."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskbar_drop_discover() {
|
||||||
|
# Plasma's default taskbar pins Discover, which CachyOS doesn't install: the pin shows as a
|
||||||
|
# blank icon. Pin what CachyOS's own layout pins (/etc/skel) instead. Not when Discover is
|
||||||
|
# installed, and only on a taskbar that still has the default pins (no launchers key).
|
||||||
|
# Edit only while plasmashell is stopped.
|
||||||
|
[[ -e /usr/share/applications/org.kde.discover.desktop ]] && return 0
|
||||||
|
local applet grp
|
||||||
|
for applet in $(plasma_applets org.kde.plasma.icontasks); do
|
||||||
|
grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General"
|
||||||
|
[[ -n "$(kreadconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
|
||||||
|
--group Applets --group "${applet#*:}" --group Configuration --group General --key launchers)" ]] && continue
|
||||||
|
kset theme plasma-org.kde.plasma.desktop-appletsrc "$grp" launchers \
|
||||||
|
'applications:systemsettings.desktop,preferred://filemanager,preferred://browser'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
theme_disable() {
|
theme_disable() {
|
||||||
extras_disable
|
extras_disable
|
||||||
info "Restoring the previous desktop look and layout..."
|
info "Restoring the previous desktop look and layout..."
|
||||||
|
|||||||
+3
-35
@@ -48,43 +48,11 @@ launcher_repair() { [[ -f "$WIZARD_APPS/$WIZARD_OLD_NAME" ]] && ! launcher_statu
|
|||||||
|
|
||||||
launcher_enable() {
|
launcher_enable() {
|
||||||
info "Adding the Steamify shortcut (the app on the desktop and in the launcher, Steamify Terminal in the launcher)..."
|
info "Adding the Steamify shortcut (the app on the desktop and in the launcher, Steamify Terminal in the launcher)..."
|
||||||
install_executable "$WIZARD_LAUNCHER" 755 << EOF
|
# Both scripts download the newest release when they run (patches/).
|
||||||
#!/bin/bash
|
patch_file steamify-start.sh | fill URL="$WIZARD_URL" | install_executable "$WIZARD_LAUNCHER" 755
|
||||||
# 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 app, without a terminal. Only the first time, when PySide6 still
|
# The app, without a terminal. Only the first time, when PySide6 still
|
||||||
# has to be installed, it runs in Konsole: sudo asks for the password there.
|
# has to be installed, it runs in Konsole: sudo asks for the password there.
|
||||||
install_executable "$WIZARD_APP_LAUNCHER" 755 << EOF
|
patch_file steamify-app-start.sh | fill URL="$WIZARD_APP_URL" | install_executable "$WIZARD_APP_LAUNCHER" 755
|
||||||
#!/bin/bash
|
|
||||||
# Installed by Steamify CachyOS: start the newest release of its app.
|
|
||||||
set -o pipefail
|
|
||||||
if [[ "\${1:-}" != --in-terminal ]] && ! python3 -c 'import PySide6.QtQml' 2>/dev/null; then
|
|
||||||
exec konsole -e "\$0" --in-terminal
|
|
||||||
fi
|
|
||||||
if ! curl -fsSL --max-time 30 "$WIZARD_APP_URL" | bash; then
|
|
||||||
msg="Couldn't download or start Steamify. Are you connected to the internet?"
|
|
||||||
if [[ "\${1:-}" == --in-terminal ]]; then echo; echo "\$msg"; read -rp "Press Enter to close this window... " _
|
|
||||||
else kdialog --title Steamify --sorry "\$msg" 2>/dev/null; fi
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# The icon comes with the release; without it, Steam's own icon.
|
# The icon comes with the release; without it, Steam's own icon.
|
||||||
local icon=steam tmp
|
local icon=steam tmp
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
|
|||||||
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
||||||
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
||||||
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
||||||
|
| `steamify-start.sh`, `steamify-app-start.sh` | `lib/wizard-shortcut.sh` (Steamify shortcut) | The two start scripts of the shortcut: "Steamify Terminal" runs the newest `steamify.sh` in Konsole, the app's launcher runs the newest `steamify-app.sh` (`fill URL=...`) |
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Installed by Steamify CachyOS: start the newest release of its app.
|
||||||
|
set -o pipefail
|
||||||
|
if [[ "${1:-}" != --in-terminal ]] && ! python3 -c 'import PySide6.QtQml' 2>/dev/null; then
|
||||||
|
exec konsole -e "$0" --in-terminal
|
||||||
|
fi
|
||||||
|
if ! curl -fsSL --max-time 30 "@URL@" | bash; then
|
||||||
|
msg="Couldn't download or start Steamify. Are you connected to the internet?"
|
||||||
|
if [[ "${1:-}" == --in-terminal ]]; then echo; echo "$msg"; read -rp "Press Enter to close this window... " _
|
||||||
|
else kdialog --title Steamify --sorry "$msg" 2>/dev/null; fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -51,8 +51,9 @@ def latest():
|
|||||||
|
|
||||||
def pending(new):
|
def pending(new):
|
||||||
# Newer than the last Steamify that ran here, and not skipped.
|
# Newer than the last Steamify that ran here, and not skipped.
|
||||||
seen = version(state("seen") or "0")
|
seen, found = version(state("seen") or "0"), version(new)
|
||||||
return seen is not None and version(new) > seen and new != state("skipped")
|
# A tag that isn't a plain version (a pre-release name) is never offered.
|
||||||
|
return seen is not None and found is not None and found > seen and new != state("skipped")
|
||||||
|
|
||||||
|
|
||||||
def desktop():
|
def desktop():
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/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 "@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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Python: the app (ui/steamify-ui, no .py extension) and patches/*.py.
|
||||||
|
line-length = 130
|
||||||
|
target-version = "py312"
|
||||||
|
|
||||||
|
[lint]
|
||||||
|
select = ["E", "F", "W", "B"]
|
||||||
@@ -12,6 +12,5 @@ in the shell code.
|
|||||||
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
|
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
|
||||||
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
|
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
|
||||||
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
|
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
|
||||||
| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (user unit) |
|
|
||||||
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
|
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
|
||||||
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
|
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Steam Background Autostart for Virtual Keyboard
|
|
||||||
After=graphical-session.target
|
|
||||||
PartOf=graphical-session.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
# Only in the Plasma desktop session; gamescope-session starts its own Steam.
|
|
||||||
ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]'
|
|
||||||
ExecStart=/usr/bin/steam -silent
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=graphical-session.target
|
|
||||||
+69
-57
@@ -15,34 +15,39 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
# Release version, see CHANGELOG.md.
|
# Release version, see CHANGELOG.md.
|
||||||
VERSION=2.11.0
|
VERSION=2.11.1
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
for lib in common valve-mirror state packages login-manager single-user steam-desktop steam-machine kernel-pin fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
source "$SCRIPT_DIR/lib/$lib.sh"
|
source "$SCRIPT_DIR/lib/$lib.sh"
|
||||||
done
|
done
|
||||||
|
|
||||||
require_root_helper
|
require_root_helper
|
||||||
|
|
||||||
BACKEND=false
|
# What this run does, from the first argument:
|
||||||
[[ "${1:-}" == --backend ]] && BACKEND=true
|
# --backend ... the graphical app's machine-readable mode
|
||||||
# --defaults [--options <id>,...] [--boot gamescope|desktop]: apply what the
|
# --defaults [--options <id>,...] [--boot gamescope|desktop]: apply what the
|
||||||
# menu would preselect (or exactly the listed items), without the menu or any
|
# menu would preselect (or exactly the listed items), without the menu or
|
||||||
# prompt (the Steam Machine ISO's first login runs this; sudo must not ask).
|
# any prompt (the Steam Machine ISO's first login runs this; sudo must not
|
||||||
DEFAULTS=false
|
# ask)
|
||||||
[[ "${1:-}" == --defaults ]] && DEFAULTS=true
|
# --defaults --list what --defaults can set up here, as JSON
|
||||||
# --defaults --list: what --defaults can set up here, as JSON (an installer
|
# (an installer page is built from it); nothing else on stdout
|
||||||
# page is built from it); nothing else on stdout.
|
# --boot gamescope|desktop only change where an installed conversion
|
||||||
LIST=false
|
# starts, everything else stays as it is (for scripts; no menu)
|
||||||
[[ "$DEFAULTS" == true && "${2:-}" == --list ]] && LIST=true
|
# --first-login the installer's one-time follow-up
|
||||||
# --boot gamescope|desktop: only change where an installed conversion
|
# (none) the menu
|
||||||
# starts, everything else stays as it is (for scripts; no menu).
|
MODE=menu
|
||||||
BOOT_ONLY=false
|
case "${1:-}" in
|
||||||
[[ "${1:-}" == --boot ]] && BOOT_ONLY=true
|
--backend) MODE=backend ;;
|
||||||
|
--defaults) MODE=defaults; [[ "${2:-}" == --list ]] && MODE=list ;;
|
||||||
|
--boot) MODE=boot ;;
|
||||||
|
--first-login) MODE=first-login ;;
|
||||||
|
esac
|
||||||
|
BACKEND=false; [[ "$MODE" == backend ]] && BACKEND=true
|
||||||
|
|
||||||
if [[ "$BACKEND" == false && "$LIST" == false ]]; then
|
if [[ "$MODE" != backend && "$MODE" != list ]]; then
|
||||||
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
|
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 "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."
|
echo "anything you turn off is put back the way it was."
|
||||||
@@ -59,6 +64,14 @@ TARGET_USER="$(id -un)"
|
|||||||
migrate_layout
|
migrate_layout
|
||||||
notify_seen
|
notify_seen
|
||||||
|
|
||||||
|
# One exit handler (a second trap would replace it): the cursor the menu hid
|
||||||
|
# and the run's temp dirs, also when the run stops half way.
|
||||||
|
on_exit() {
|
||||||
|
[[ -t 1 ]] && tput cnorm 2>/dev/null
|
||||||
|
cleanup_tmpdirs
|
||||||
|
}
|
||||||
|
trap on_exit EXIT
|
||||||
|
|
||||||
restart_needed() { [[ -n "${BIOS_NEEDS_RESTART:-}" || "$RESTART_FOR_LOGIN" == true ]]; }
|
restart_needed() { [[ -n "${BIOS_NEEDS_RESTART:-}" || "$RESTART_FOR_LOGIN" == true ]]; }
|
||||||
|
|
||||||
restart_now() {
|
restart_now() {
|
||||||
@@ -118,63 +131,62 @@ quit_prompt() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# The graphical app (steamify-ui) drives the same components through
|
report_failed() {
|
||||||
# lib/backend.sh instead of the menu.
|
# Exit status for the scripted modes: 1 when a component had problems.
|
||||||
if [[ "$BACKEND" == true ]]; then
|
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; return 1; }
|
||||||
RESTART_FOR_LOGIN=false
|
}
|
||||||
shift
|
|
||||||
backend_main "$@"
|
|
||||||
exit $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${1:-}" == --first-login ]]; then
|
run_defaults() {
|
||||||
first_login_run
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$LIST" == true ]]; then
|
|
||||||
defaults_list
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$DEFAULTS" == true ]]; then
|
|
||||||
RESTART_FOR_LOGIN=false
|
RESTART_FOR_LOGIN=false
|
||||||
REAPPLY=false
|
REAPPLY=false
|
||||||
sudo -n true 2>/dev/null || { err "--defaults needs sudo without a password."; exit 1; }
|
sudo -n true 2>/dev/null || { err "--defaults needs sudo without a password."; return 1; }
|
||||||
detect_components
|
detect_components
|
||||||
defaults_options "${@:2}" || exit 1
|
defaults_options "${@:2}" || return 1
|
||||||
plan_changes
|
plan_changes
|
||||||
apply_changes
|
apply_changes
|
||||||
# Run by the installer: the rest waits for the first desktop login.
|
# Run by the installer: the rest waits for the first desktop login.
|
||||||
user_session || first_login_schedule
|
user_session || first_login_schedule
|
||||||
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
|
report_failed || return 1
|
||||||
ok "Done; the changes take effect after a restart."
|
ok "Done; the changes take effect after a restart."
|
||||||
exit 0
|
}
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$BOOT_ONLY" == true ]]; then
|
run_boot_only() {
|
||||||
|
local mode="${2:-}" c
|
||||||
RESTART_FOR_LOGIN=false
|
RESTART_FOR_LOGIN=false
|
||||||
REAPPLY=false
|
REAPPLY=false
|
||||||
case "${2:-}" in
|
case "$mode" in
|
||||||
gamescope|desktop) ;;
|
gamescope|desktop) ;;
|
||||||
*) err "--boot takes gamescope or desktop"; exit 1 ;;
|
*) err "--boot takes gamescope or desktop"; return 1 ;;
|
||||||
esac
|
esac
|
||||||
detect_components
|
detect_components
|
||||||
[[ "${CURRENT[gaming]}" == 1 ]] || { err "--boot needs the SteamOS conversion; turn it on first."; exit 1; }
|
is_current gaming || { err "--boot needs the SteamOS conversion; turn it on first."; return 1; }
|
||||||
# What is on stays on, and nothing else changes: not the updates or
|
# What is on stays on, and nothing else changes: not the updates or
|
||||||
# removals a normal run would pick.
|
# removals a normal run would pick.
|
||||||
for c in "${COMPONENTS[@]}"; do WANTED[$c]=${CURRENT[$c]:-0}; done
|
for c in "${COMPONENTS[@]}"; do WANTED[$c]=${CURRENT[$c]:-0}; done
|
||||||
WANTED[boot]=0; [[ "$2" == desktop ]] && WANTED[boot]=1
|
WANTED[boot]=0; [[ "$mode" == desktop ]] && WANTED[boot]=1
|
||||||
plan_changes
|
plan_changes
|
||||||
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
|
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
|
||||||
ok "Already starting in $2."
|
ok "Already starting in $mode."
|
||||||
exit 0
|
return 0
|
||||||
fi
|
fi
|
||||||
apply_changes
|
apply_changes
|
||||||
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
|
report_failed || return 1
|
||||||
ok "Starts in $2 from the next boot on."
|
ok "Starts in $mode from the next boot on."
|
||||||
exit 0
|
}
|
||||||
fi
|
|
||||||
|
case "$MODE" in
|
||||||
|
backend)
|
||||||
|
# The graphical app (steamify-ui) drives the same components through
|
||||||
|
# lib/backend.sh instead of the menu.
|
||||||
|
RESTART_FOR_LOGIN=false
|
||||||
|
shift
|
||||||
|
backend_main "$@"
|
||||||
|
exit $? ;;
|
||||||
|
first-login) first_login_run; exit 0 ;;
|
||||||
|
list) defaults_list; exit 0 ;;
|
||||||
|
defaults) run_defaults "$@"; exit $? ;;
|
||||||
|
boot) run_boot_only "$@"; exit $? ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Menu loop: after each run the menu comes back with the new state, until
|
# 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.
|
# the user quits; the restart question comes then, once, for everything.
|
||||||
@@ -205,7 +217,7 @@ while true; do
|
|||||||
if [[ "$c" == boot ]]; then echo " - boot into: desktop (from the next boot)"
|
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 is_action "$c"; then echo " - run: ${LABEL[$c]%%:*} at your own risk (checks, then asks twice more)"
|
||||||
elif feature_outdated "$c"; then echo " - update: ${LABEL[$c]} (changed in this version)"
|
elif feature_outdated "$c"; then echo " - update: ${LABEL[$c]} (changed in this version)"
|
||||||
elif [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"
|
elif is_current "$c"; then echo " - re-apply: ${LABEL[$c]}"
|
||||||
elif feature_new "$c"; then echo " - turn on: ${LABEL[$c]} (new in this version)"
|
elif feature_new "$c"; then echo " - turn on: ${LABEL[$c]} (new in this version)"
|
||||||
else echo " - turn on: ${LABEL[$c]}"; fi
|
else echo " - turn on: ${LABEL[$c]}"; fi
|
||||||
done
|
done
|
||||||
@@ -230,11 +242,11 @@ while true; do
|
|||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
component_available "$c" && ! is_action "$c" || continue
|
component_available "$c" && ! is_action "$c" || continue
|
||||||
if [[ "$c" == boot ]]; then
|
if [[ "$c" == boot ]]; then
|
||||||
[[ "${CURRENT[gaming]}" == 1 ]] && echo " └ boots into: $(boot_mode "${CURRENT[boot]}")"
|
is_current gaming && echo " └ boots into: $(boot_mode "${CURRENT[boot]}")"
|
||||||
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
elif [[ -n "${PARENT[$c]:-}" ]]; then
|
||||||
[[ "${CURRENT[${PARENT[$c]}]}" == 1 ]] || continue
|
[[ "${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
|
if is_current "$c"; 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
|
elif is_current "$c"; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi
|
||||||
done
|
done
|
||||||
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
||||||
warn "These had problems (see above): ${FAILED[*]}"
|
warn "These had problems (see above): ${FAILED[*]}"
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Tests lib/controllers.sh (extended controller support: xone, the Xbox wireless dongle, and xpadneo, Xbox Bluetooth) with a stub pacman
|
|
||||||
# and a temp home. No root, VM or hardware needed: bash tests/controllers-test.sh
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
||||||
fail=0
|
|
||||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
|
||||||
|
|
||||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
|
||||||
source lib/common.sh; source lib/state.sh; source lib/controllers.sh; source lib/menu.sh
|
|
||||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
|
||||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
|
||||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
|
||||||
kwriteconfig6() { local f="" k="" v=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; *) v="$1" ;; esac; shift; done; mkdir -p "$(dirname "$f")"; sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; }
|
|
||||||
kreadconfig6() { local f="" k=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group|--default) shift ;; esac; shift; done; sed -n "s/^$k=//p" "$f" 2>/dev/null; }
|
|
||||||
# A pretend package database.
|
|
||||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; PACMAN_FAIL=0
|
|
||||||
pacman() {
|
|
||||||
case "$1" in
|
|
||||||
-Q) local p; for p in "${@:2}"; do [[ " $PKGS " == *" $p "* ]] || return 1; done ;;
|
|
||||||
-S) [[ $PACMAN_FAIL == 1 ]] && return 1; echo "S ${*:4}" >> "$PACMAN_LOG"; PKGS+=" ${*:4}" ;;
|
|
||||||
-Rns) echo "R ${*:3}" >> "$PACMAN_LOG"; local p; for p in ${*:3}; do PKGS=" ${PKGS// $p / } "; done ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
HEADERS=0; install_kernel_headers() { HEADERS=$((HEADERS + 1)); }
|
|
||||||
|
|
||||||
check "off to begin with" '! extended_controller_support_status'
|
|
||||||
extended_controller_support_enable
|
|
||||||
check "installs the repo's xpadneo-dkms, xone-dkms and the dongle firmware" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware'
|
|
||||||
check "kernel headers are made sure of first" '[[ $HEADERS == 1 ]]'
|
|
||||||
check "what we installed is recorded" '[[ "$(state_get extended_controller_support installed_pkgs)" == "xpadneo-dkms xone-dkms xone-dongle-firmware" ]]'
|
|
||||||
check "it is on" extended_controller_support_status
|
|
||||||
n="$(wc -l < "$PACMAN_LOG")"; extended_controller_support_enable
|
|
||||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
|
||||||
extended_controller_support_disable
|
|
||||||
check "off: the three packages are removed again" '! pacman -Q xpadneo-dkms 2>/dev/null && ! pacman -Q xone-dkms 2>/dev/null && ! pacman -Q xone-dongle-firmware 2>/dev/null && [[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
|
||||||
|
|
||||||
# The AUR's xone-dkms-git conflicts with the repo's xone-dkms: it counts, and is kept.
|
|
||||||
PKGS=" xone-dkms-git xone-dongle-firmware xpadneo-dkms"; : > "$PACMAN_LOG"
|
|
||||||
check "xone-dkms-git counts as xone: already on" extended_controller_support_status
|
|
||||||
extended_controller_support_enable; extended_controller_support_disable
|
|
||||||
check "with xone-dkms-git: nothing installed and nothing removed" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q xone-dkms-git xpadneo-dkms xone-dongle-firmware'
|
|
||||||
PKGS=" xone-dkms-git"
|
|
||||||
extended_controller_support_enable
|
|
||||||
check "xone-dkms-git present: only the missing ones are installed, never xone-dkms" 'grep -q "^S xpadneo-dkms xone-dongle-firmware$" "$PACMAN_LOG" && ! pacman -Q xone-dkms 2>/dev/null'
|
|
||||||
extended_controller_support_disable
|
|
||||||
check "and off removes only those two, xone-dkms-git stays" 'pacman -Q xone-dkms-git && ! pacman -Q xpadneo-dkms 2>/dev/null'
|
|
||||||
|
|
||||||
# A failed install is an error and records nothing.
|
|
||||||
PKGS=""; PACMAN_FAIL=1
|
|
||||||
check "a failed pacman is an error" '! extended_controller_support_enable >/dev/null'
|
|
||||||
check "...and records nothing" '[[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
|
||||||
PACMAN_FAIL=0
|
|
||||||
|
|
||||||
# Packages that were already there are never removed by turning it off.
|
|
||||||
PKGS=" xpadneo-dkms xone-dkms xone-dongle-firmware"; : > "$PACMAN_LOG"
|
|
||||||
extended_controller_support_enable; extended_controller_support_disable
|
|
||||||
check "packages you had before stay" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware && [[ ! -s "$PACMAN_LOG" ]]'
|
|
||||||
|
|
||||||
# The menu.
|
|
||||||
check "offered on every PC" 'component_available extended_controller_support'
|
|
||||||
check "not preselected: it builds kernel modules for every kernel" '[[ " ${NO_PRESELECT[*]} " == *" extended_controller_support "* ]]'
|
|
||||||
check "a top-level item with a label" '[[ -z "${PARENT[extended_controller_support]:-}" && -n "${LABEL[extended_controller_support]}" ]]'
|
|
||||||
|
|
||||||
# The "new" badge: an opt-in option added after setup shows it, but is never ticked for you.
|
|
||||||
component_selectable() { return 0; }
|
|
||||||
declare -A CURRENT=([gaming]=1 [nvidia]=0 [extended_controller_support]=0 [vram]=0 [boot]=0)
|
|
||||||
rm -f "$STATE_DIR/features.state"
|
|
||||||
check "new opt-in option (conversion on, no record): the new badge" 'feature_new_optin extended_controller_support'
|
|
||||||
check "...but it is not ticked for you (not a new default option)" '! feature_new extended_controller_support'
|
|
||||||
check "...and the menu label says (new)" '[[ "$(menu_label extended_controller_support)" == *"(new)"* ]]'
|
|
||||||
check "a new default option is still ticked for you, and is not the opt-in kind" 'feature_new vram && ! feature_new_optin vram'
|
|
||||||
check "Boot into never gets the badge (it is a choice row)" '! feature_new_optin boot'
|
|
||||||
state_set_features() { kwriteconfig6 --file "$STATE_DIR/features.state" --group State --key "$1" "$2"; }
|
|
||||||
state_set_features extended_controller_support off
|
|
||||||
check "once a run recorded it as off, the badge is gone" '! feature_new_optin extended_controller_support'
|
|
||||||
rm -f "$STATE_DIR/features.state"
|
|
||||||
CURRENT[gaming]=0; CURRENT[nvidia]=1
|
|
||||||
check "on an NVIDIA PC (Gaming on NVIDIA on, no conversion) it shows too" 'feature_new_optin extended_controller_support'
|
|
||||||
CURRENT[nvidia]=0
|
|
||||||
check "with neither the conversion nor Gaming on NVIDIA on (a fresh PC) nothing is new" '! feature_new_optin extended_controller_support && ! feature_new vram'
|
|
||||||
CURRENT[gaming]=1; CURRENT[extended_controller_support]=1
|
|
||||||
check "already on: not new" '! feature_new_optin extended_controller_support'
|
|
||||||
exit $fail
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
|
|
||||||
# one: tests/nvidia-test.sh). Run from the Steamify checkout:
|
|
||||||
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
|
|
||||||
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
|
|
||||||
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
|
|
||||||
# Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help.
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
# patch_file (lib/common.sh) reads the hook script from $SCRIPT_DIR/patches.
|
|
||||||
SCRIPT_DIR="$PWD"
|
|
||||||
REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}"
|
|
||||||
source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
|
|
||||||
mode="${1:-check}"
|
|
||||||
fail=0
|
|
||||||
say() { echo "$*" | tee -a "$REPORT"; }
|
|
||||||
pass() { say "PASS $*"; }
|
|
||||||
bad() { say "FAIL $*"; fail=1; }
|
|
||||||
note() { say " $*"; }
|
|
||||||
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
|
|
||||||
|
|
||||||
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
|
|
||||||
|
|
||||||
report_system() {
|
|
||||||
say "-- GPU and software"
|
|
||||||
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
|
|
||||||
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
|
|
||||||
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
|
|
||||||
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
|
|
||||||
done
|
|
||||||
note "boot loader file: $(nvidia_boot_file || true)"
|
|
||||||
note "cmdline: $(cat /proc/cmdline)"
|
|
||||||
}
|
|
||||||
|
|
||||||
check_state() {
|
|
||||||
say "-- Steamify's view"
|
|
||||||
if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected"
|
|
||||||
elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied"
|
|
||||||
else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi
|
|
||||||
for c in /sys/class/drm/card[0-9]*/device; do
|
|
||||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')"
|
|
||||||
done
|
|
||||||
ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported"
|
|
||||||
local p
|
|
||||||
for p in $NVIDIA_PARAMS; do
|
|
||||||
if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line"
|
|
||||||
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
|
|
||||||
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
|
|
||||||
done
|
|
||||||
say "-- the live NVIDIA driver"
|
|
||||||
local m
|
|
||||||
for m in modeset fbdev; do
|
|
||||||
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
|
|
||||||
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
|
|
||||||
done
|
|
||||||
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
|
|
||||||
local c found=0
|
|
||||||
for c in /sys/class/drm/card[0-9]*/device; do
|
|
||||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
|
|
||||||
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
|
|
||||||
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
|
|
||||||
done
|
|
||||||
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
|
|
||||||
say "-- initramfs"
|
|
||||||
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
|
|
||||||
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
|
|
||||||
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
|
|
||||||
say "-- what apply would change"
|
|
||||||
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
|
|
||||||
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$mode" in
|
|
||||||
check)
|
|
||||||
report_system; check_state ;;
|
|
||||||
apply)
|
|
||||||
report_system
|
|
||||||
say "-- applying"
|
|
||||||
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
|
|
||||||
else bad "nvidia_enable failed (output above)"; fi
|
|
||||||
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
|
|
||||||
visual)
|
|
||||||
report_system
|
|
||||||
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
|
|
||||||
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
|
|
||||||
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
|
|
||||||
say "visual result: $a: $what"
|
|
||||||
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
|
|
||||||
say "-- gamescope and NVIDIA lines from this boot's log"
|
|
||||||
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
|
|
||||||
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
|
|
||||||
note "(more in $REPORT)" ;;
|
|
||||||
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
|
|
||||||
esac
|
|
||||||
say ""; say "Report: $REPORT"
|
|
||||||
exit $fail
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Tests lib/nvidia.sh ("Gaming on NVIDIA" and its Big Picture option) and the menu rules around it, against a fake RTX 5080
|
|
||||||
# (PCI 10de:2c02) beside an Intel iGPU, a stub modinfo, pacman and systemctl, and a temp home. No root, VM or NVIDIA
|
|
||||||
# hardware needed: bash tests/nvidia-test.sh
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
||||||
fail=0
|
|
||||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
|
||||||
|
|
||||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
|
||||||
source lib/common.sh; source lib/state.sh; source lib/login-manager.sh; source lib/single-user.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; source lib/menu.sh
|
|
||||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
|
||||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
|
||||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
|
||||||
# KDE's config tools on plain files under the temp home (a relative file name is relative to ~/.config, as in KDE).
|
|
||||||
kwriteconfig6() {
|
|
||||||
local f="" k="" v="" del=0
|
|
||||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; --delete) del=1 ;; *) v="$1" ;; esac; shift; done
|
|
||||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"; mkdir -p "$(dirname "$f")"
|
|
||||||
if [[ $del == 1 ]]; then sed -i "/^$k=/d" "$f" 2>/dev/null; else sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; fi
|
|
||||||
}
|
|
||||||
kreadconfig6() {
|
|
||||||
local f="" k="" d="" r
|
|
||||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --default) d="$2"; shift ;; --group) shift ;; esac; shift; done
|
|
||||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"
|
|
||||||
r="$(sed -n "s/^$k=//p" "$f" 2>/dev/null)"; printf '%s\n' "${r:-$d}"
|
|
||||||
}
|
|
||||||
# A pretend package database and systemd: what the tests assert on.
|
|
||||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; ENABLED=0
|
|
||||||
pacman() {
|
|
||||||
case "$1" in
|
|
||||||
-Q) [[ " $PKGS " == *" $2 "* ]] ;;
|
|
||||||
-S) echo "S $*" >> "$PACMAN_LOG"; PKGS+=" ${*: -1}" ;;
|
|
||||||
-Rns) echo "R $*" >> "$PACMAN_LOG"; PKGS=" ${PKGS//${*: -1}/} " ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
user_systemctl() {
|
|
||||||
case "$1" in
|
|
||||||
enable) ENABLED=1 ;;
|
|
||||||
disable) ENABLED=0 ;;
|
|
||||||
is-enabled) [[ $ENABLED == 1 ]] ;;
|
|
||||||
esac
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
FAKE_DRIVER=1; modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
|
|
||||||
GAMING_ON=0; gaming_status() { [[ "$GAMING_ON" == 1 ]]; }
|
|
||||||
UNIT="$HOME/.config/systemd/user/$NVIDIA_UNIT"
|
|
||||||
|
|
||||||
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
|
|
||||||
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
|
|
||||||
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
|
|
||||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
|
|
||||||
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
|
|
||||||
: > "$T/cmdline"; NVIDIA_CMDLINE="$T/cmdline" # the running kernel's command line: without the parameters
|
|
||||||
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
|
|
||||||
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
|
|
||||||
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
|
|
||||||
NVIDIA_MODULES_DIR="$T/mods"
|
|
||||||
NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked
|
|
||||||
mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd"
|
|
||||||
# The component's kernel step edits this boot loader file (systemd-boot's) in the tests, never a real one.
|
|
||||||
printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot-manage.conf"; nvidia_boot_file() { echo "$T/sdboot-manage.conf"; }
|
|
||||||
|
|
||||||
# --- detection
|
|
||||||
check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
|
|
||||||
FAKE_DRIVER=0; check "no nvidia_drm module (nouveau): not an NVIDIA PC" '! nvidia_present'
|
|
||||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA GPU: not an NVIDIA PC" '! nvidia_present'
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- which items the menu shows
|
|
||||||
check "NVIDIA PC: the SteamOS conversion and its gamescope options are hidden" '! component_available gaming && ! component_available boot && ! component_available glyphs'
|
|
||||||
check "NVIDIA PC: Gaming on NVIDIA and Big Picture are shown" 'component_available nvidia && component_available bigpicture'
|
|
||||||
GAMING_ON=1
|
|
||||||
check "NVIDIA PC with the conversion already on: it is shown, so it can be turned off" 'component_available gaming && component_available boot'
|
|
||||||
check "...and Gaming on NVIDIA is hidden (both would start Steam)" '! component_available nvidia && ! component_available bigpicture'
|
|
||||||
GAMING_ON=0; NVIDIA_DRM_DIR="$T/none"
|
|
||||||
check "no NVIDIA: the conversion is shown as before" 'component_available gaming && component_available boot'
|
|
||||||
check "...and Gaming on NVIDIA is hidden" '! component_available nvidia && ! component_available bigpicture'
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- "Add as non-Steam game" is for gaming mode's controller: not offered on an NVIDIA PC (unless already on)
|
|
||||||
steamgame_available() { return 0; }; STEAMGAME_ON=0; steamgame_status() { [[ "$STEAMGAME_ON" == 1 ]]; }
|
|
||||||
check "NVIDIA PC: Add as non-Steam game is hidden" '! component_available steamgame'
|
|
||||||
STEAMGAME_ON=1; check "...unless it is already on (so it can be turned off)" 'component_available steamgame'; STEAMGAME_ON=0
|
|
||||||
NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA: it is offered as before" 'component_available steamgame'
|
|
||||||
steamgame_available() { return 1; }; check "no NVIDIA, no Steam account yet: still not offered" '! component_available steamgame'
|
|
||||||
steamgame_available() { return 0; }; NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- turning it on
|
|
||||||
check "off to begin with" '! nvidia_status && ! bigpicture_status'
|
|
||||||
nvidia_enable
|
|
||||||
check "Steam is installed when missing, and recorded as ours" 'grep -q "^S " "$PACMAN_LOG" && [[ "$(state_get nvidia installed_pkgs)" == steam ]]'
|
|
||||||
check "the autostart unit is written: Steam without arguments" 'grep -q "^ExecStart=/usr/bin/steam $" "$UNIT"'
|
|
||||||
check "it is on" 'nvidia_status && ! bigpicture_status'
|
|
||||||
n="$(wc -l < "$PACMAN_LOG")"; nvidia_enable
|
|
||||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
|
||||||
|
|
||||||
# --- Big Picture
|
|
||||||
bigpicture_enable
|
|
||||||
check "Big Picture: Steam starts with -gamepadui" 'grep -q "^ExecStart=/usr/bin/steam -gamepadui$" "$UNIT" && bigpicture_status'
|
|
||||||
nvidia_enable
|
|
||||||
check "turning Gaming on NVIDIA on again keeps Big Picture" 'bigpicture_status'
|
|
||||||
check "Big Picture: Plasma starts with an empty session" '[[ "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" == emptySession ]]'
|
|
||||||
bigpicture_disable
|
|
||||||
check "Big Picture off: Steam's normal window again" '! bigpicture_status && nvidia_status'
|
|
||||||
check "...and the session setting is back as it was (not set)" '[[ -z "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" ]]'
|
|
||||||
|
|
||||||
# --- turning it off
|
|
||||||
bigpicture_enable; nvidia_disable
|
|
||||||
check "off: the unit is gone and Steam, which we installed, is removed" '! nvidia_status && [[ ! -e "$UNIT" ]] && ! pacman -Q steam && [[ -z "$(state_get nvidia installed_pkgs)" ]]'
|
|
||||||
check "Big Picture without the unit does nothing" 'bigpicture_enable && bigpicture_disable && [[ ! -e "$UNIT" ]]'
|
|
||||||
|
|
||||||
# --- Steam that was there already is never removed
|
|
||||||
PKGS=" steam"; : > "$PACMAN_LOG"
|
|
||||||
nvidia_enable; nvidia_disable
|
|
||||||
check "Steam installed before is kept, and not installed again" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q steam'
|
|
||||||
|
|
||||||
# --- kernel parameters and early modules (a supported card only: RTX 20 series or newer)
|
|
||||||
check "RTX 5080 (2c02) is supported: no chwd legacy lists" nvidia_supported
|
|
||||||
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
|
|
||||||
check "RTX 5080 is not on a legacy list" 'nvidia_supported && ! nvidia_legacy_gpu'
|
|
||||||
echo 0x1c03 > "$T/drm/card1/device/device"
|
|
||||||
check "GTX 1060 (older than RTX 20): no kernel setup, but still an NVIDIA PC" '! nvidia_supported && nvidia_legacy_gpu && nvidia_present'
|
|
||||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
|
||||||
|
|
||||||
for loader in limine limineplus sdboot grub; do
|
|
||||||
case $loader in
|
|
||||||
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
|
|
||||||
# CachyOS writes its line as "+=" and may already have nvidia_drm.modeset=1 in it.
|
|
||||||
limineplus) F="$T/limine"; printf 'KERNEL_CMDLINE[default]+="quiet splash nvidia_drm.modeset=1"\n' > "$F" ;;
|
|
||||||
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
|
|
||||||
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
|
|
||||||
esac
|
|
||||||
nvidia_boot_file() { echo "$F"; }
|
|
||||||
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
|
|
||||||
nvidia_kernel_enable
|
|
||||||
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
|
|
||||||
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
|
|
||||||
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
|
|
||||||
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
|
|
||||||
SUM="$(cat "$F")"; nvidia_kernel_enable
|
|
||||||
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
|
|
||||||
nvidia_kernel_disable
|
|
||||||
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
|
|
||||||
done
|
|
||||||
|
|
||||||
# A missing patches/ file must be an error, never an empty script or hook.
|
|
||||||
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
|
|
||||||
# The pacman hook's script decides again at every kernel change.
|
|
||||||
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
|
|
||||||
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
|
|
||||||
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
|
|
||||||
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
|
|
||||||
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
|
|
||||||
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
rm -rf "$T/mods/5.0.0-leftover"; nvidia_kernel_disable
|
|
||||||
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
|
|
||||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
|
|
||||||
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_kernel_enable
|
|
||||||
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
|
|
||||||
rm -rf "$T/mods/6.6.0-lts"
|
|
||||||
# Generated boot entries without the parameters (the initramfs build failed): an error.
|
|
||||||
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
|
|
||||||
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
|
|
||||||
check "boot entries without the parameters: error" '! nvidia_kernel_enable >/dev/null'
|
|
||||||
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
|
|
||||||
# A config file without the setting to edit: an error, not "applied".
|
|
||||||
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
|
|
||||||
check "no setting to edit: error, nothing rebuilt" '! nvidia_kernel_enable >/dev/null && [[ $REBUILDS == 0 ]]'
|
|
||||||
FAKE_DRIVER=0; NVIDIA_DRM_DIR="$T/drm"; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_kernel_enable
|
|
||||||
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
|
|
||||||
|
|
||||||
# --- single user mode on NVIDIA: its own login step (SDDM, autologin into Plasma) without the conversion
|
|
||||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/drm" # an earlier section ended without the driver
|
|
||||||
SW="$T/switches.log"; : > "$SW"; TARGET_USER=tester; SINGLE_AUTOLOGIN="$T/sddm.conf.d/zzz-steamify-autologin.conf"
|
|
||||||
switch_to_sddm() { echo sddm >> "$SW"; }; switch_to_plasmalogin() { echo plasmalogin >> "$SW"; }
|
|
||||||
remove_sddm_base_autologin() { :; } # would look at the real /etc/sddm.conf
|
|
||||||
GAMING_ON=0
|
|
||||||
check "single user mode is offered on NVIDIA without the conversion..." 'component_available single'
|
|
||||||
GAMING_ON=1; check "...and with it" 'component_available single'; GAMING_ON=0
|
|
||||||
single_login_enable
|
|
||||||
check "single user: SDDM, autologin of the user into the Plasma session" 'grep -qx "User=tester" "$SINGLE_AUTOLOGIN" && grep -qx "Session=plasma.desktop" "$SINGLE_AUTOLOGIN" && grep -qx "Relogin=true" "$SINGLE_AUTOLOGIN" && grep -qx sddm "$SW"'
|
|
||||||
c1="$(cat "$SINGLE_AUTOLOGIN")"; single_login_enable
|
|
||||||
check "single user login: a second run changes nothing" '[[ "$(cat "$SINGLE_AUTOLOGIN")" == "$c1" ]]'
|
|
||||||
single_login_disable
|
|
||||||
check "single user off: the file is gone and plasma-login-manager is the login manager again" '[[ ! -e "$SINGLE_AUTOLOGIN" ]] && grep -qx plasmalogin "$SW"'
|
|
||||||
: > "$SW"; GAMING_ON=1; single_login_enable
|
|
||||||
check "with the conversion on, single user mode leaves the login to it" '[[ ! -e "$SINGLE_AUTOLOGIN" && ! -s "$SW" ]]'
|
|
||||||
GAMING_ON=0
|
|
||||||
# --- the menu rules
|
|
||||||
declare -A WANTED=([nvidia]=1 [bigpicture]=1 [gaming]=0 [boot]=0 [single]=0 [machine]=0 [poweroff]=0 [launcher]=0 [steamgame]=0)
|
|
||||||
component_selectable() { return 0; }
|
|
||||||
toggle_component nvidia
|
|
||||||
check "unticking Gaming on NVIDIA unticks Big Picture" '[[ "${WANTED[nvidia]}" == 0 && "${WANTED[bigpicture]}" == 0 ]]'
|
|
||||||
toggle_component bigpicture
|
|
||||||
check "ticking Big Picture ticks Gaming on NVIDIA" '[[ "${WANTED[nvidia]}" == 1 && "${WANTED[bigpicture]}" == 1 ]]'
|
|
||||||
WANTED[single]=0; WANTED[gaming]=0; toggle_component single
|
|
||||||
check "ticking single user mode does not tick the conversion where it isn't offered" '[[ "${WANTED[single]}" == 1 && "${WANTED[gaming]}" == 0 ]]'
|
|
||||||
check "Big Picture follows Gaming on NVIDIA in the menu" '[[ " ${COMPONENTS[*]} " == *" nvidia bigpicture "* && "${PARENT[bigpicture]}" == nvidia ]]'
|
|
||||||
|
|
||||||
exit $fail
|
|
||||||
+4
-3
@@ -38,8 +38,8 @@ Item {
|
|||||||
|
|
||||||
readonly property var status: backend.status || ({})
|
readonly property var status: backend.status || ({})
|
||||||
readonly property var items: status.items || []
|
readonly property var items: status.items || []
|
||||||
// Hidden: Big Picture excludes a silent start; on a Steam Machine a silent start needs "Boot into" desktop.
|
// Hidden: Big Picture excludes a silent start.
|
||||||
function hidden(i) { return (i.id === "nvsilent" && want.bigpicture) || (i.needs === "boot" && boot !== "desktop"); }
|
function hidden(i) { return i.id === "nvsilent" && want.bigpicture; }
|
||||||
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
|
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
|
||||||
readonly property var bios: status.bios || null
|
readonly property var bios: status.bios || null
|
||||||
|
|
||||||
@@ -78,13 +78,14 @@ Item {
|
|||||||
w[id] = !w[id];
|
w[id] = !w[id];
|
||||||
// The same rules as the terminal menu (toggle_component).
|
// The same rules as the terminal menu (toggle_component).
|
||||||
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
||||||
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; }
|
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; }
|
||||||
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
||||||
if (id === "nvidia") w.bigpicture = w.nvidia;
|
if (id === "nvidia") w.bigpicture = w.nvidia;
|
||||||
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
||||||
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
||||||
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
||||||
if (id === "silent" && w.silent) w.gaming = true;
|
if (id === "silent" && w.silent) w.gaming = true;
|
||||||
|
if (id === "glyphs" && w.glyphs) w.gaming = true;
|
||||||
if (id === "machine") w.poweroff = w.machine;
|
if (id === "machine") w.poweroff = w.machine;
|
||||||
if (id === "poweroff" && w.poweroff) w.machine = true;
|
if (id === "poweroff" && w.poweroff) w.machine = true;
|
||||||
if (id === "machine" && !w.machine) w.kpin = false;
|
if (id === "machine" && !w.machine) w.kpin = false;
|
||||||
|
|||||||
+2
-2
@@ -6,11 +6,11 @@ QtObject {
|
|||||||
readonly property var items: ({
|
readonly property var items: ({
|
||||||
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
|
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
|
||||||
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
|
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
|
||||||
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] },
|
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut"] },
|
||||||
boot: { label: "Boot into", hint: "Where the PC starts",
|
boot: { label: "Boot into", hint: "Where the PC starts",
|
||||||
body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
|
body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
|
||||||
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
|
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
|
||||||
silent: { label: "Start Steam silently", hint: "In the tray at login on the desktop, no window",
|
silent: { label: "Start Steam silently in desktop mode", hint: "In the tray at login on the desktop, no window",
|
||||||
body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.",
|
body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.",
|
||||||
changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] },
|
changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] },
|
||||||
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
||||||
|
|||||||
Reference in new issue
Block a user