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.
|
||||||
|
|||||||
@@ -5,6 +5,22 @@ 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
|
## 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**
|
- `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**
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -187,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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
+27
-34
@@ -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\":\"\""
|
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,24 +156,7 @@ 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 || "${WANTED[glyphs]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
|
||||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
|
|
||||||
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
|
|
||||||
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
|
|
||||||
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
|
|
||||||
[[ "${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
|
||||||
@@ -180,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
|
||||||
|
|||||||
+40
-2
@@ -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.
|
||||||
|
|
||||||
|
# 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"
|
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
|
||||||
}
|
}
|
||||||
+25
-24
@@ -2,29 +2,21 @@
|
|||||||
# "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}"
|
||||||
|
}
|
||||||
|
|
||||||
mkdir -p "$desktop_dir"
|
shortcut_install_sudoers() {
|
||||||
|
# plasma-login-manager needs the sync bridge run and a restart, which the
|
||||||
# On SDDM, steamos-session-select logging out is enough: Relogin=true
|
# shortcut can't sudo for interactively (Terminal=false), so it gets a
|
||||||
# logs straight back in to the newly selected session, like SteamOS.
|
# password-less rule scoped to exactly those two commands.
|
||||||
# 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"
|
|
||||||
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'"
|
|
||||||
local sudoers_tmp
|
local sudoers_tmp
|
||||||
sudoers_tmp="$(mktemp)"
|
sudoers_tmp="$(mktemp)"
|
||||||
cat > "$sudoers_tmp" << EOF
|
cat > "$sudoers_tmp" << EOF
|
||||||
@@ -37,6 +29,19 @@ EOF
|
|||||||
warn "Generated sudoers rule failed validation; the shortcut will not be able to restart plasmalogin."
|
warn "Generated sudoers rule failed validation; the shortcut will not be able to restart plasmalogin."
|
||||||
fi
|
fi
|
||||||
rm -f "$sudoers_tmp"
|
rm -f "$sudoers_tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_desktop_shortcut() {
|
||||||
|
local desktop_dir
|
||||||
|
desktop_dir="$(shortcut_desktop_dir)"
|
||||||
|
mkdir -p "$desktop_dir"
|
||||||
|
|
||||||
|
# On SDDM, steamos-session-select logging out is enough: Relogin=true
|
||||||
|
# logs straight back in to the newly selected session, like SteamOS.
|
||||||
|
local exec_line="steamos-session-select gamescope"
|
||||||
|
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'"
|
||||||
|
shortcut_install_sudoers
|
||||||
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."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+73
-45
@@ -11,6 +11,20 @@ COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single la
|
|||||||
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 [glyphs]=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,
|
||||||
@@ -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() {
|
||||||
@@ -115,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}"
|
||||||
@@ -154,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.
|
||||||
@@ -252,14 +270,14 @@ 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
|
||||||
@@ -284,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\":\"\",\"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; WANTED[glyphs]=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
|
||||||
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi
|
# 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() {
|
||||||
@@ -331,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=" └ "
|
||||||
@@ -379,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
|
||||||
@@ -388,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
|
||||||
@@ -417,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[@]}
|
||||||
@@ -479,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
|
||||||
@@ -491,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
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ silent_old_unit_remove() {
|
|||||||
# Before 2.11.0 the option was a systemd user unit: it would start Steam a second time.
|
# 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"
|
local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||||
[[ -f "$unit" ]] || return 0
|
[[ -f "$unit" ]] || return 0
|
||||||
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
best_effort user_systemctl disable --now steam-desktop-autostart.service
|
||||||
rm -f "$unit"
|
rm -f "$unit"
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-193
@@ -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"
|
||||||
@@ -410,14 +261,14 @@ serial_enable() {
|
|||||||
'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 ||
|
||||||
{ 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).
|
# The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot).
|
||||||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" 2>/dev/null ||
|
best_effort sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
||||||
info "The serial number becomes readable for Steam at the next boot."
|
info "The serial number becomes readable for Steam at the next boot."
|
||||||
return 0
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,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
|
||||||
|
|
||||||
@@ -467,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"
|
||||||
|
}
|
||||||
+21
-7
@@ -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
|
fi
|
||||||
offline=true
|
}
|
||||||
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
|
||||||
|
|||||||
+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"]
|
||||||
+67
-55
@@ -19,30 +19,35 @@ 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[*]}"
|
||||||
|
|||||||
Reference in new issue
Block a user