Compare commits

...
110 Commits
Author SHA1 Message Date
theupriser b1b6bde6fd docs: NVIDIA-INSTRUCTIONS.md: how to test the NVIDIA fix on the real PC, read the results and undo it
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:24:38 +02:00
theupriser 878ef9f8d0 docs: TODO-nvidia.md: verify the RTX 20+ check against a real chwd list on the PC
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:22:25 +02:00
theupriser 23ad9d7bc8 feat: NVIDIA fix only for RTX 20 series or newer, with the VRAM booster's chwd legacy check (vram_nvidia_legacy_id)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:20:02 +02:00
theupriser ba8e409ad5 docs: NVIDIA-RESEARCH.md and TODO: hook VM results, opt-out toggle plan, older cards
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:17:03 +02:00
theupriser 017381269f fix: never install an empty NVIDIA hook or script (a failed patch_file piped into install succeeded with no input)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:07:16 +02:00
theupriser 320d5ecfe2 feat: NVIDIA modules in the initramfs only while every kernel has them, decided again by a pacman hook at every kernel change
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 14:42:06 +02:00
theupriser d001a02fdd docs: TODO-nvidia.md: state and open work of the NVIDIA fix, for the next session
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 13:58:06 +02:00
theupriser 5c627da0b8 test: nvidia-hardware-test.sh to check, apply and visually verify the NVIDIA fix on a real PC
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 13:20:01 +02:00
theupriser 74f2c07076 fix: NVIDIA fix checks the edit and the generated boot entries for every boot loader (limine.conf, systemd-boot entries, grub.cfg)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 13:07:07 +02:00
theupriser 1e385095d7 fix: NVIDIA fix on Limine edits the existing cmdline line; early modules only when every kernel has them
Sync git.upriser.nl mirror / sync (push) Skipped
Found by running it in a VM: the appended += line became literal text on the
kernel command line, and a kernel without the modules made limine-mkinitcpio
skip its boot entry.
2026-10-01 12:48:56 +02:00
theupriser 24b517b4ad test: NVIDIA fix against a fake RTX 5080, stub modinfo and temp boot loader files
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 11:07:32 +02:00
theupriser 1f28cb3f4b docs: AGENTS.md: never work on main or a release branch, hardware-specific fixes, git identity
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 10:54:49 +02:00
theupriser ce8c3b9109 feat: NVIDIA fix for gaming mode (kernel parameters and early modules)
Untested on hardware; .no-release-yet keeps it out of the release.
2026-10-01 10:54:27 +02:00
theupriser ca027cb607 chore: Version 2.9.7 2026-10-01 10:54:16 +02:00
theupriser d93f9ea56c Merge pull request #71 from theupriser/release/2.9.6
Single-file build / bundle (push) Successful in 12s
Sync git.upriser.nl mirror / sync (push) Skipped
Release/2.9.6
2026-09-30 13:34:33 +02:00
theupriser 761f921e40 Merge pull request #70 from theupriser/bugfix/iso-steamify-ref
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 13s
fix(ci): a release branch builds its dev ISO with its own Steamify
2026-09-30 12:46:20 +02:00
theupriser 7a54a2fa59 fix(ci): a release branch builds its dev ISO with its own Steamify (steamify_ref), not the newest release 2026-09-30 12:45:14 +02:00
theupriser 9eab3978a9 docs: changelog hashes for 2.9.6
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 11s
2026-09-30 12:33:28 +02:00
theupriser 9602d9d00b Merge pull request #69 from theupriser/bugfix/iso-dispatch-ref
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 14s
fix(ci): main starts a real ISO release, a release branch a dev ISO
2026-09-30 11:41:40 +02:00
theupriser 9a2965d339 fix(ci): the ISO workflow always runs from master; main asks for a release ISO, a release branch for a dev ISO
Sync git.upriser.nl mirror / sync (push) Skipped
2026-09-30 11:32:36 +02:00
theupriser c42d5454bf fix(ci): a version published from main starts a real ISO release, a release branch a dev ISO 2026-09-30 11:31:37 +02:00
theupriser b3bed43854 chore: Version 2.9.6 2026-09-30 11:31:25 +02:00
theupriser 3e79451244 Merge pull request #68 from theupriser/release/2.9.5
Single-file build / bundle (push) Successful in 12s
Sync git.upriser.nl mirror / sync (push) Skipped
chore: Version 2.9.5
2026-09-30 11:27:45 +02:00
theupriser 971e792054 chore: Version 2.9.5
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 12s
2026-09-30 11:26:15 +02:00
theupriser 6557320c81 Merge pull request #67 from theupriser/release/2.9.5
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 13s
Release/2.9.5
2026-09-30 11:21:53 +02:00
theupriser 692e3fcbad Merge pull request #65 from theupriser/feature/git-upriser-sync
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 11s
feat(ci): sync the git.upriser.nl mirror at once
2026-09-30 11:20:48 +02:00
theupriser 70ecb563fd ci: trigger a mirror sync
Sync git.upriser.nl mirror / sync (push) Skipped
2026-09-30 10:55:58 +02:00
theupriser a7276cfd9a ci: sync the git.upriser.nl mirror on every branch and tag
Sync git.upriser.nl mirror / sync (push) Skipped
2026-09-30 08:54:29 +02:00
theupriser b3549d4eea ci: sync the mirror on release branch pushes too (Gitea's vmtest.yml runs on them) 2026-09-30 08:50:13 +02:00
theupriser a232a55bef feat(ci): sync the git.upriser.nl mirror on every push to main and every tag
New git-upriser-sync.yml calls the mirror-sync API (secrets GIT_UPRISER_URL, GIT_UPRISER_TOKEN; retried; skipped on Gitea). bundle.yml dispatches the renamed iso-1-github-tag.yml in the right repo name; docs follow.
2026-09-30 08:12:06 +02:00
theupriser 397b3cb607 Merge pull request #64 from theupriser/release/2.9.4
Single-file build / bundle (push) Successful in 13s
Release/2.9.4
2026-09-30 07:53:56 +02:00
theupriser bda1d3ebbe fix: Merge docs/iso-repo-rename into release/2.9.4
Single-file build / bundle (push) Successful in 12s
2026-09-30 07:47:55 +02:00
theupriser 3676c64c90 docs: link the renamed steamify-cachyos-live-iso repo
- README and AGENTS.md point at theupriser/steamify-cachyos-live-iso
2026-09-30 07:47:55 +02:00
theupriser d44f29956a Merge pull request #63 from theupriser/release/2.9.4
Single-file build / bundle (push) Successful in 13s
Release 2.9.4
2026-09-29 23:08:59 +02:00
theupriser 2858d13429 docs: changelog hash for 2.9.4 2026-09-29 23:08:20 +02:00
theupriser 48cf3c7c7c Merge pull request #62 from theupriser/feature/docs-ci-and-cec-cache
docs: the CEC driver cache and the CI/ISO release flow
2026-09-29 23:08:12 +02:00
theupriser 619ef1f714 docs: AGENTS.md and TECHNICAL.md: the CEC driver cache, one workflow for GitHub and a Gitea mirror, a release starts the Steamify ISO's release 2026-09-29 23:07:28 +02:00
theupriser b6240539e6 chore: Version 2.9.4 2026-09-29 23:07:08 +02:00
theupriser 7d6df21627 Merge pull request #61 from theupriser/release/2.9.3
Single-file build / bundle (push) Successful in 13s
Release 2.9.3
2026-09-29 22:04:49 +02:00
theupriser 3cad70dcc4 docs: changelog hash for 2.9.3
Single-file build / bundle (push) Successful in 24s
2026-09-29 22:03:09 +02:00
theupriser b8742a5642 Merge pull request #60 from theupriser/feature/iso-release-on-steamify-release
feat(ci): a new Steamify release starts the Steamify ISO's release
2026-09-29 21:57:25 +02:00
theupriser 7f5d29c997 feat(ci): a new Steamify release starts the Steamify ISO's release (iso-release.yml in the ISO repo, feat/steamify; secret ISO_DISPATCH_TOKEN) 2026-09-29 21:56:42 +02:00
theupriser cfe3ce7bd0 chore: Version 2.9.3 2026-09-29 21:55:45 +02:00
theupriser 3e4133c14a Merge pull request #58 from theupriser/release/2.9.2
Single-file build / bundle (push) Successful in 14s
Release/2.9.2
2026-09-29 20:31:12 +02:00
theupriser c4b8db85dc Merge pull request #57 from theupriser/feature/gitea-release
Single-file build / bundle (push) Successful in 13s
feat(ci): a Gitea mirror publishes its own releases
2026-09-29 20:30:00 +02:00
theupriser 350011877b feat(ci): a Gitea mirror publishes its own release per version (never overwrites one, notes from the changelog) 2026-09-29 20:29:19 +02:00
theupriser b1d79d48a6 Merge pull request #55 from theupriser/release/2.9.2
Single-file build / bundle (push) Successful in 20s
chore: Version 2.9.2
2026-09-29 20:25:44 +02:00
theupriser 5b42036786 Merge pull request #56 from theupriser/bugfix/ci-shellcheck-gitea
fix(ci): the build also runs on a Gitea mirror
2026-09-29 20:25:10 +02:00
theupriser 4a64232fad fix(ci): Gitea gets christopherhx/gitea-upload-artifact@v4 (GitHub fails a workflow that mentions upload-artifact@v3) 2026-09-29 20:24:23 +02:00
theupriser 4ec92f4d89 fix(ci): the build also runs on a Gitea mirror: shellcheck through ludeeus/action-shellcheck (brings its own binary), the artifact with upload-artifact@v3 there, releases only on GitHub 2026-09-29 20:23:20 +02:00
theupriser fe4f3f43be chore: Version 2.9.2 2026-09-29 20:23:04 +02:00
theupriser 4bacc3b2e6 Merge pull request #54 from theupriser/release/2.9.1
Release/2.9.1
2026-09-29 19:51:54 +02:00
theupriser cc0ca1c35e Merge pull request #53 from theupriser/bugfix/cec-driver-cache
fix: HDMI-CEC: Valve's CEC driver is downloaded once and cached
2026-09-29 19:26:24 +02:00
theupriser 580cc71b57 docs: changelog hashes 2026-09-29 19:26:16 +02:00
theupriser c87e6c763f docs: changelog for the CEC driver cache 2026-09-29 19:19:05 +02:00
theupriser fc05725a91 fix: HDMI-CEC: an older cached CEC driver is removed when a new pin is downloaded 2026-09-29 19:18:55 +02:00
theupriser 90bc5e4408 fix: HDMI-CEC: Valve's CEC driver is downloaded once and kept in /var/cache/steamify (GitHub rate-limits repeated downloads with HTTP 429, which left CEC off) 2026-09-29 19:16:06 +02:00
theupriser d99ff652dc chore: Version 2.9.1 2026-09-29 19:15:42 +02:00
theupriser 2aa3068b60 Merge pull request #51 from theupriser/release/2.9.0
Release 2.9.0: docs (KDE Plasma only)
2026-09-28 20:42:12 +02:00
theupriser 1a6ddcfc0d Merge pull request #52 from theupriser/feature/changelog-hash-fix
docs: changelog hash fix
2026-09-28 19:48:45 +02:00
theupriser 11668db91c docs: changelog hash for 66ea63c (was the merge commit's) 2026-09-28 19:48:36 +02:00
theupriser 3316c1de28 Merge pull request #50 from theupriser/feature/changelog-hashes
docs: changelog hashes
2026-09-28 19:47:55 +02:00
theupriser d9365dac81 docs: changelog hashes 2026-09-28 19:47:47 +02:00
theupriser 853a3926ee Merge pull request #49 from theupriser/feature/docs-not-supported
docs: other desktops are not supported
2026-09-28 19:47:35 +02:00
theupriser 66ea63cf7e docs: KDE Plasma only: other desktops and display managers "are not supported" (README, was "don't work yet") 2026-09-28 19:47:28 +02:00
theupriser f560f332a9 Merge pull request #48 from theupriser/feature/docs-kde-only
docs: KDE Plasma only
2026-09-28 19:46:43 +02:00
theupriser 9b86cd1a6c docs: KDE Plasma only: other desktops don't work yet (README) 2026-09-28 19:46:36 +02:00
theupriser a72a4def71 Merge pull request #47 from theupriser/release/2.9.0
Release 2.9.0: docs
2026-09-28 19:38:41 +02:00
theupriser ea051c77f6 docs: changelog hash for d73e71d 2026-09-28 19:38:10 +02:00
theupriser 4e829c6111 Merge pull request #46 from theupriser/feature/docs-2.9.0
docs: 2.9.0 in README, TECHNICAL and TROUBLESHOOTING
2026-09-28 19:37:15 +02:00
theupriser d73e71d4eb docs: README, TECHNICAL and TROUBLESHOOTING for 2.9.0: Steam's System settings, serial number and Wi-Fi backend, --defaults --list, the Steamify ISO 2026-09-28 19:37:08 +02:00
theupriser 8f2d2be2aa Merge pull request #45 from theupriser/release/2.9.0
Release 2.9.0
2026-09-28 19:35:41 +02:00
theupriser 53b72c8e33 Merge pull request #44 from theupriser/feature/steamos-version
feat: Steam's OS Version steamos-3.9, OS Codename steam-machine
2026-09-28 19:31:35 +02:00
theupriser 3b4f3b2313 docs: changelog hash for a72d848 2026-09-28 19:31:28 +02:00
theupriser a72d848e78 feat: Steam's OS Version is the SteamOS release Steamify follows (steamos-3.9), its OS Codename steam-machine; About this System keeps "CachyOS Linux" (UseOSReleaseVersion) 2026-09-28 19:28:10 +02:00
theupriser 3a58c72d16 Merge pull request #43 from theupriser/bugfix/variant-version
fix: Steam's OS Variant shows Steamify's version
2026-09-28 19:22:31 +02:00
theupriser 27a40702ce fix: Steam's OS Variant shows Steamify's version (VARIANT_ID=steamify-2.9.0; Steam shows VARIANT_ID, not VARIANT) 2026-09-28 19:22:25 +02:00
theupriser 8ab066f034 Merge pull request #42 from theupriser/bugfix/no-version-id
fix: No VERSION_ID in os-release (About this System showed CachyOS Linux 2.9.0)
2026-09-28 19:17:10 +02:00
theupriser 44bfe071d6 fix: No VERSION_ID in os-release: About this System said "CachyOS Linux 2.9.0"; the version is in VARIANT ("Steamify 2.9.0") 2026-09-28 19:17:01 +02:00
theupriser e281d5e879 Merge pull request #41 from theupriser/feature/os-codename
feat: Steamify as OS variant, SteamOS release as codename; the OS name stays CachyOS
2026-09-28 19:14:50 +02:00
theupriser 435f69c151 feat: Steam's System settings: the OS name stays CachyOS (no renaming, also not in About this System), Steamify <version> as the variant, the SteamOS release it follows as the codename (steamos-3.9) 2026-09-28 19:14:43 +02:00
theupriser 9319cbca1e Merge pull request #40 from theupriser/bugfix/progress-checkmarks
fix(ui): The progress screen's checkmarks stand upright
2026-09-28 19:05:09 +02:00
theupriser cf6bee1c86 Merge release/2.9.0 into bugfix/progress-checkmarks 2026-09-28 19:05:02 +02:00
theupriser 16487ba00c Merge pull request #39 from theupriser/feature/steam-system-info
feat: Steam's System settings and About this System like on SteamOS
2026-09-28 19:04:29 +02:00
theupriser 07a94cd274 fix(ui): The progress screen's ✓ and ! stand upright: only a dot on the circle spins while a step runs (they kept the spinner's last angle) 2026-09-28 19:03:56 +02:00
theupriser ce71b34b0d feat: Steam's System settings and About this System like on SteamOS: OS name, Steamify as OS variant and version, serial number and Wi-Fi backend on a Steam Machine 2026-09-28 19:03:54 +02:00
theupriser d30d505f7d chore: Version 2.9.0 2026-09-28 19:03:28 +02:00
theupriser 9755cc3ac3 Merge pull request #38 from theupriser/bugfix/changelog-2.8.0-list
docs: CHANGELOG: 2.8.0's --defaults --list entry was missing
2026-09-28 13:02:11 +02:00
theupriser 6f26e74229 docs: CHANGELOG: 2.8.0's --defaults --list entry was missing 2026-09-28 13:01:00 +02:00
theupriser 2a01583b8f Merge pull request #37 from theupriser/release/2.8.0
Release 2.8.0
2026-09-28 12:46:15 +02:00
theupriser c40aa1f7d9 Merge pull request #36 from theupriser/feature/defaults-list
feat: steamify.sh --defaults --list
2026-09-28 12:45:27 +02:00
theupriser d204efb59d feat: steamify.sh --defaults --list: what --defaults can set up here, as JSON, for an installer page 2026-09-28 11:40:10 +02:00
theupriser 12f6cc0b3a chore: Version 2.8.0 2026-09-28 11:35:47 +02:00
theupriser b01e2c5221 Merge pull request #35 from theupriser/release/2.7.0
Release 2.7.0
2026-09-28 10:57:45 +02:00
theupriser affb5f79b0 Merge pull request #34 from theupriser/bugfix/theme-off-single-launcher
fix: theme off no longer brings back single user's launcher restriction
2026-09-28 10:53:19 +02:00
theupriser 58e43d4c4a fix: turning the theme off no longer brings back single user's launcher restriction when single user was turned off in between 2026-09-28 10:52:28 +02:00
theupriser 23f265b02f Merge pull request #33 from theupriser/feature/remove-v2-ui-preview
chore: remove the v2 app preview
2026-09-28 10:47:10 +02:00
theupriser ced4a45d2f chore: the v2 app preview is gone (it is the released app): no preview pre-release step in CI, no mention in steamify-app.sh 2026-09-28 10:46:23 +02:00
theupriser 6ad686a8b2 fix: Merge branch 'feature/gh-required' into release/2.7.0 2026-09-28 10:19:06 +02:00
theupriser b1adacbcb3 docs: gh is required for the release-branch pull requests; ask the user to install it 2026-09-28 10:18:59 +02:00
theupriser 8dd2db3a97 fix: Merge branch 'feature/release-branches' into release/2.7.0 2026-09-28 10:18:06 +02:00
theupriser 501c0ba425 docs: gh or git for merging into the release branch 2026-09-28 10:17:59 +02:00
theupriser bee18b76a8 docs: the agent merges feature/bugfix branches into the release branch; the release into main stays the user's 2026-09-28 10:17:41 +02:00
theupriser eadbdda271 docs: release branches (release/X.Y.Z, feature/ and bugfix/ branches into it, the release into main); CI builds release/** pushes 2026-09-28 10:14:20 +02:00
theupriser c4ec755a4a feat: --defaults --options <ids> (exactly these on) replaces --skip; steamify.sh --boot gamescope|desktop on its own switches where an installed conversion starts 2026-09-28 10:06:45 +02:00
theupriser 14aa7c0b54 fix: the app's progress screen says "Boot into desktop", not "Boot into Boot into" 2026-09-28 10:06:32 +02:00
theupriser 5bf9da411d fix: HDMI-CEC enables cec-audio-control.socket (the TV remote's volume keys); existing installs get it as an update 2026-09-28 10:06:23 +02:00
theupriser 4f6e6fd0aa feat: --defaults takes --skip <ids> and --boot gamescope|desktop, for the Steam Machine ISO's installer pages 2026-09-27 21:59:08 +02:00
theupriser a79eeedbc4 Merge pull request #32 from theupriser/feat/defaults-mode
feat: --defaults applies the default setup without the menu, also fro…
2026-09-27 21:25:03 +02:00
theupriser b948c2020b feat: --defaults applies the default setup without the menu, also from an installer (no session): the base for a Steam Machine ISO
systemctl --user goes through user_systemctl, which only changes unit files
without a session; the theme lets Plasma build Vapor's layout at the first
login when the layout is still /etc/skel's; a one-time first-login autostart
sets up single user's launcher and opens the app.
2026-09-27 19:21:28 +02:00
36 changed files with 1582 additions and 81 deletions

No files matched your search

+112 -23
View File
@@ -5,18 +5,16 @@
# release are moved to it, so both of these always get the newest version:
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/latest/steamify.sh | bash
# Each release also has the app (v2): steamify-app.tar.gz (ui/, steamify.sh,
# Each release also has the app: steamify-app.tar.gz (ui/, steamify.sh,
# lib/, patches/, services/, the icon) and its launcher, run with:
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
# A push to feat/v2-ui (the app, not released yet) updates the pre-release
# v2-ui-preview instead, whose launcher gets that build:
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/v2-ui-preview/steamify-app.sh | bash
# Pushes to release/** build and check it like pull requests; only main publishes.
# Pull requests only build and check it, and warn when VERSION is already released.
name: Single-file build
on:
push:
branches: [main, feat/v2-ui]
branches: [main, 'release/**']
pull_request:
workflow_dispatch:
@@ -42,12 +40,39 @@ jobs:
- name: Check
run: |
bash -n dist/steamify.sh
# SC2034/SC2154: variables used across the inlined modules.
shellcheck -S warning -e SC2034,SC2154 dist/steamify.sh
shellcheck -S warning dist/steamify-app.sh
python3 -m py_compile ui/steamify-ui
# 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).
- name: shellcheck the bundle
uses: ludeeus/action-shellcheck@2.0.0
env:
# SC2034/SC2154: variables used across the inlined modules.
SHELLCHECK_OPTS: -e SC2034 -e SC2154
with:
severity: warning
scandir: dist
ignore_names: steamify-app.sh
- name: shellcheck the app launcher
uses: ludeeus/action-shellcheck@2.0.0
with:
severity: warning
scandir: dist
ignore_names: steamify.sh
# The build as an artifact on GitHub and on the mirror (Gitea); releases stay GitHub's.
# Gitea's artifact server doesn't speak upload-artifact@v4's protocol, and GitHub fails a workflow
# that merely mentions the deprecated @v3: Gitea gets christopherhx's fork of v4 for Gitea.
- uses: actions/upload-artifact@v4
if: github.server_url == 'https://github.com'
with:
name: steamify
path: |
dist/steamify.sh
dist/steamify-app.tar.gz
dist/steamify-app.sh
- uses: christopherhx/gitea-upload-artifact@v4
if: github.server_url != 'https://github.com'
with:
name: steamify
path: |
@@ -57,6 +82,7 @@ jobs:
- name: Version
id: version
if: github.server_url == 'https://github.com'
env:
GH_TOKEN: ${{ github.token }}
run: |
@@ -71,6 +97,7 @@ jobs:
- name: Publish the v${{ steps.version.outputs.version }} release
if: >-
github.server_url == 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.version.outputs.released == 'false'
env:
@@ -107,22 +134,84 @@ jobs:
fi
gh release upload latest dist/steamify.sh dist/steamify-app.sh dist/steamify-app.tar.gz assets/steam-gaming-settings.svg --clobber
- name: Publish the v2-ui-preview pre-release
if: github.event_name == 'push' && github.ref == 'refs/heads/feat/v2-ui'
# The mirror (Gitea) publishes its own release per version too, the same way: never overwrites one,
# notes from the changelog. gh can't talk to Gitea: its API for the check, a Gitea release action to
# publish. The token is the run's own (repository write); a secret RELEASE_TOKEN overrides it.
- name: Version (mirror)
id: mirror_version
if: github.server_url != 'https://github.com'
env:
GH_TOKEN: ${{ github.token }}
TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
run: |
# Its launcher downloads this pre-release, not the newest release.
sed -i 's/STEAMIFY_RELEASE:-latest/STEAMIFY_RELEASE:-v2-ui-preview/' dist/steamify-app.sh
grep -q 'STEAMIFY_RELEASE:-v2-ui-preview' dist/steamify-app.sh
git tag -f v2-ui-preview "$GITHUB_SHA" && git push -f origin v2-ui-preview
notes="Preview of the Steamify app (v2) from feat/v2-ui ($(git describe --always), $(git log -1 --format='%cs %s')). Not a release.
Run it with:
curl -fsSL https://github.com/${{ github.repository }}/releases/download/v2-ui-preview/steamify-app.sh | bash"
if gh release view v2-ui-preview >/dev/null 2>&1; then
gh release edit v2-ui-preview --title "Steamify app (v2) preview" --notes "$notes" --prerelease --latest=false
version="$(grep -oP '^VERSION=\K.*' steamify.sh)"
echo "version=$version" >> "$GITHUB_OUTPUT"
if curl -fsS -o /dev/null -H "Authorization: token $TOKEN" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/tags/v$version"; then
echo "released=true" >> "$GITHUB_OUTPUT"
echo "::warning::v$version is already released on this server and won't be overwritten."
else
gh release create v2-ui-preview --target "$GITHUB_SHA" --title "Steamify app (v2) preview" --notes "$notes" --prerelease --latest=false
echo "released=false" >> "$GITHUB_OUTPUT"
fi
gh release upload v2-ui-preview dist/steamify-app.sh dist/steamify-app.tar.gz --clobber
- name: Release notes (mirror)
if: >-
github.server_url != 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.mirror_version.outputs.released == 'false'
env:
VERSION: ${{ steps.mirror_version.outputs.version }}
run: |
changes="$(awk -v v="$VERSION" '
$0 ~ "^## " { if (found) exit; if (index($0, "## " v " ") == 1) { found = 1; next } }
found' CHANGELOG.md)"
cat > dist/release-notes.md <<NOTES
Single-file build of v$VERSION ($(git describe --always), $(git log -1 --format=%cs)).
Run this version with:
curl -fsSL ${{ github.server_url }}/${{ github.repository }}/releases/download/v$VERSION/steamify.sh | bash
## Changes in v$VERSION
$changes
NOTES
- name: Publish the v${{ steps.mirror_version.outputs.version }} release (mirror)
if: >-
github.server_url != 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.mirror_version.outputs.released == 'false'
uses: akkuman/gitea-release-action@v1.3.7
with:
token: ${{ secrets.RELEASE_TOKEN || github.token }}
tag_name: v${{ steps.mirror_version.outputs.version }}
target_commitish: ${{ github.sha }}
name: Steamify CachyOS v${{ steps.mirror_version.outputs.version }}
body_path: dist/release-notes.md
files: |
dist/steamify.sh
dist/steamify-app.sh
dist/steamify-app.tar.gz
assets/steam-gaming-settings.svg
# A new version starts the Steamify ISO's release of the ISO repo: its iso-1-github-tag.yml (always run from
# master) names the ISO after the newest Steamify release, tags it, and the Gitea mirror builds and attaches the ISO.
# The branch here decides the kind of build (the workflow's input `kind`):
# main (publishes the release) -> release: a real ISO (tag v<steamify>-<date>)
# release/** (a version not yet released) -> dev: a pre-release (tag v<steamify>-dev.<date>)
# Needs a fine-grained token for that repo (Actions: read and write) as the secret ISO_DISPATCH_TOKEN;
# without it, this is skipped.
- name: Start the Steamify ISO's release
if: >-
github.server_url == 'https://github.com' &&
github.event_name != 'pull_request' &&
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) &&
steps.version.outputs.released == 'false'
env:
GH_TOKEN: ${{ secrets.ISO_DISPATCH_TOKEN }}
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::No ISO_DISPATCH_TOKEN: the Steamify ISO isn't released with this version."; exit 0
fi
# A release branch builds the ISO with its own code (and VERSION): steamify_ref. main builds the release it just published.
if [ "$GITHUB_REF" = refs/heads/main ]; then kind=release; sref=""; else kind=dev; sref="$GITHUB_REF_NAME"; fi
gh workflow run iso-1-github-tag.yml -R theupriser/steamify-cachyos-live-iso --ref master -f kind="$kind" -f steamify_ref="$sref"
echo "Started the Steamify ISO's release (theupriser/steamify-cachyos-live-iso, master, kind $kind, Steamify ${sref:-the newest release})"
+26
View File
@@ -0,0 +1,26 @@
name: Sync git.upriser.nl mirror
# Trigger the Gitea pull-mirror immediately instead of waiting for its interval,
# so Gitea builds/tests right after any branch or tag lands on GitHub (the mirror has no sync interval of its own).
on:
push:
branches: ['**']
tags: ['*']
workflow_dispatch:
jobs:
sync:
# Gitea also reads .github/workflows on the mirror; only run on GitHub
if: github.server_url == 'https://github.com'
runs-on: ubuntu-latest
steps:
- name: Trigger mirror-sync
env:
GITEA_URL: ${{ secrets.GIT_UPRISER_URL }}
GIT_UPRISER_TOKEN: ${{ secrets.GIT_UPRISER_TOKEN }}
# Gitea "owner/repo"; defaults to the same path as on GitHub
GITEA_REPO: ${{ vars.GITEA_REPO || github.repository }}
run: |
curl --fail-with-body -sS --retry 5 --retry-delay 10 --retry-all-errors -X POST \
-H "Authorization: token ${GIT_UPRISER_TOKEN}" \
"${GITEA_URL%/}/api/v1/repos/${GITEA_REPO}/mirror-sync"
+4
View File
@@ -0,0 +1,4 @@
This branch is not ready to be released: do not merge it into the release branch.
When the feature is complete and tested, ask the user whether it may be released;
on a yes, delete this file, then open the pull request into the release branch.
Open work and how to pick it up: TODO-nvidia.md. Research notes: NVIDIA-RESEARCH.md. How to test on the NVIDIA PC: NVIDIA-INSTRUCTIONS.md.
+92 -3
View File
@@ -48,6 +48,13 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
`<id>_available` is checked via `component_available` (e.g. `machine`
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
`gaming` must stay first. Dependencies live in `toggle_component`.
- **Hardware-specific fixes** that belong to a component but aren't a menu
row (e.g. `lib/nvidia.sh`: NVIDIA's kernel parameters and early modules
for gaming mode, called from `gaming_enable`/`gaming_disable`) detect the
hardware themselves, change only what's missing, and undo it on disable.
Add them to the source loop in `steamify.sh` and the table in
`TECHNICAL.md`. They can't be tested without the hardware: say so in the
changelog and keep the branch behind `.no-release-yet` until it was.
- **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new
`VERSION` whenever what `<id>_enable` sets up changes (a new component gets
one too): installs recorded with an older version
@@ -68,6 +75,13 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
the entry point's `for lib in ...; do` source loop and wraps everything
after that loop in `main()`. Keep that loop on one line, keep all logic in
functions, and don't rely on `SCRIPT_DIR` for anything but sourcing.
The workflow is one file for GitHub and a Gitea mirror (`github.server_url`): build and check run on both
(shellcheck through `ludeeus/action-shellcheck`, which brings its own binary; the artifact with
`upload-artifact@v4` on GitHub and `christopherhx/gitea-upload-artifact@v4` elsewhere: never mention
`upload-artifact@v3`, GitHub fails a workflow for a deprecated version even in a skipped step); the
release is `gh` on GitHub and `akkuman/gitea-release-action` on Gitea. A new release on GitHub also starts the
Steamify ISO's release (`gh workflow run iso-1-github-tag.yml` in steamify-cachyos-live-iso, secret
`ISO_DISPATCH_TOKEN`; skipped without it): the ISO repo's GitHub tag names it, the Gitea mirror builds it.
CI (`.github/workflows/bundle.yml`) publishes the bundle as release
`v$VERSION` on pushes to `main`; an existing version is never overwritten,
so bump `VERSION` for every release.
@@ -98,11 +112,49 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
+ subject; a commit can't contain its own hash, so fill it in with the
next commit). The section heading must be `## <VERSION> - <date>`: CI
cuts the release notes out of the changelog by that heading.
- Every PR that should be released bumps `VERSION` and adds its section.
A push to `main` publishes release `v$VERSION` (tag + bundle + that
- **Branches: one release branch per version.** Work for a release goes
into `release/X.Y.Z` (e.g. `release/2.7.0`), branched from `main` when
that version starts. That branch bumps `VERSION` to `X.Y.Z` and adds the
`## X.Y.Z - <date>` changelog section (first commit on it).
- Every change gets its own branch from the release branch:
`feature/<name>` (new behaviour) or `bugfix/<name>` (a fix), and a
pull request **into the release branch**, not into `main`. Its commits
add their changelog lines to that version's section.
- When the release is done and tested (the test plan in
steamify-cachyos-dev, `TESTPLAN.md`), the release branch gets a pull
request **into `main`**. Merging it publishes the release (below).
- A fix for a released version: a new `release/X.Y.Z+1` from `main`,
with the `bugfix/` branch into it; don't reopen an old release branch.
- Up to the release branch, the agent manages it: create the
`feature/`/`bugfix/` branches, commit, push, and merge them into the
release branch itself once tested (with `gh`: `gh pr create --base
release/X.Y.Z` + `gh pr merge --merge`; no review needed). Without
`gh` (`command -v gh`), ask the user to install it (Ubuntu:
`sudo apt install gh`, then `gh auth login`) instead of working around
it. Only the
release branch's pull request into `main` is the user's: never commit
or merge to `main`, the user merges that one. Never work directly on
`main` or a `release/*` branch either: edits, even uncommitted ones,
go on a `feature/`/`bugfix/` branch (create it before editing; the
release branch only gets the version-bump commit and merged PRs).
Don't push a new `release/*` branch before it's needed: a push can
start CI builds (a dev ISO).
A machine without a git identity: pass the repo's author per command
(`git -c user.name=... -c user.email=... commit`, taken from `git
log`) instead of changing the git config.
A `.no-release-yet` file at the root of a feature/bugfix branch means
it must not be merged into the release branch yet (work in progress,
untested on hardware). When the feature is complete, ask the user
whether it may be released; on a yes, delete the file, then open the
pull request and merge it.
Keep a feature/bugfix branch up to date by merging (or rebasing on)
its release branch, the release branch by merging `main` when that
moved.
- A push to `main` publishes release `v$VERSION` (tag + bundle + that
changelog section) and marks it latest. An existing version is never
overwritten: without a bump nothing is released, and pull requests show
a warning.
a warning when `VERSION` is a version that's already released (so a
release branch that forgot its bump shows it on every PR).
- A release that adds, removes or renames a menu row also retakes the
README screenshot (`assets/screenshot-menu.png`): the app from the
branch on a Steam Machine, every row visible (window 1280 wide, tall
@@ -227,6 +279,11 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
kernel only pairs that with a named lookup ("Port C") when the CEC driver
registered first, which never happens since amdgpu loads from the
initramfs. Without it `/dev/cec0` exists but stays at `f.f.f.f`.
The source comes from one raw.githubusercontent.com download, which GitHub rate-limits (HTTP 429 after a
day of test installs, per address): it's kept in `/var/cache/steamify/cros-ec-cec-<sha256:12>.c` and reused
while its checksum matches. The name carries the checksum, so a new pin (commit + SHA-256 in `lib/cec.sh`)
downloads its own file once and removes the old one. The repo is an unofficial mirror of Valve's kernel
without releases: if it ever disappears, ship the file with Steamify. The test VMs share the host's cache.
- Power-off fix (`poweroff`, `lib/fremont-poweroff.sh`, a default sub-option
of `machine`): recent kernels (7.2 and the 6.x/7.0/7.1 updates with the
backport) keep the firmware's S4/S5 wake bit on GPIO
@@ -269,6 +326,38 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
latter only starts with `kcgroupsrc [Foreground Booster] autostart=true`
(set with `kset`). Disable removes only the packages it installed
(`state_get vram installed_pkgs`).
- Install-time mode (`steamify.sh --defaults`, 2.6.0): applies what the menu
would preselect, no menu or prompts (needs passwordless sudo). The Steam
Machine ISO ([steamify-cachyos-live-iso](https://github.com/theupriser/steamify-cachyos-live-iso))
runs it in the installer for a user who has never logged in: no session
bus, user systemd or plasmashell. So every `systemctl --user` goes through
`user_systemctl` (`lib/common.sh`; without a session only unit files change,
via `--root=/`), and the theme, when the layout is still `/etc/skel`'s,
removes it so Plasma builds Vapor's layout at the first login. What needs
that layout (single user's launcher) runs then, from a one-time autostart
(`lib/first-login.sh`, `--first-login`) that also opens the app.
`--options <id>,...` (exactly these on, the rest off; an item on brings its
parent) and `--boot gamescope|desktop` (desktop only with `gaming`) (2.7.0,
`defaults_options` in `lib/menu.sh`); the ISO's installer page passes them.
Items this PC can't use are left off with a warning, not an error.
`steamify.sh --boot gamescope|desktop` on its own (2.7.0, for scripts) only
switches `boot` on an installed conversion: `WANTED` is `CURRENT` plus
that, so no updates or removals a normal run would pick.
- What Steam's System settings show (SteamOS conversion, 2.9.0): the OS name
stays CachyOS's everywhere (legal clarity; Steam's OS Name is
`lsb_release -d`, not touched). `/etc/os-release` gets `VERSION_ID=steamos-X.Y`
(Steam's OS Version: Valve's newest jupiter repo; offline, the previous
value), `VERSION_CODENAME=steam-machine`, `VARIANT="Steamify <version>"` and
`VARIANT_ID=steamify-<version>` (Steam shows VARIANT_ID as OS Variant),
refreshed by `os_version_refresh` after every run that changes something; a
pacman hook (`zz-steamify-os-release`) runs after cachyos-hooks. KDE's About
this System would show VERSION_ID after the name: `kcm-about-distrorc`
`UseOSReleaseVersion=true` (kset) makes it show os-release's VERSION, which
CachyOS doesn't have. Never `NAME` or `PRETTY_NAME`: limine-snapper-sync
finds the boot entries by the OS name ("Target OS name ... not found in
/boot/limine.conf"); `/etc/default/limine` gets `TARGET_OS_NAME="CachyOS"`
when it has none, as a guard. The serial number (tmpfiles rule) is Steam
Machine support's, so Fremont only.
- `Relogin=true` means a gamescope that fails to start is relaunched in a
tight loop; keep that in mind when changing session handling.
+85 -1
View File
@@ -5,9 +5,93 @@ All notable changes, per version and per commit. Versions follow
`steamify.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request.
## 2.9.7 - 2026-10-01
- **feat: the SteamOS conversion fixes a corrupted gaming mode screen with an NVIDIA GPU: nvidia-drm.modeset=1 and fbdev=1 on the kernel command line, NVIDIA modules in the initramfs (lib/nvidia.sh)**
- **test: tests/nvidia-test.sh runs the NVIDIA fix against a fake RTX 5080 beside an iGPU, a stub modinfo and temp copies of the Limine, systemd-boot and GRUB files (no root, VM or hardware); NVIDIA_DRM_DIR points detection at a fake sysfs tree**
- **fix: NVIDIA fix on Limine edits the KERNEL_CMDLINE[default] line (an appended += line ended up as literal text on the kernel command line, found in a VM); the modules are only loaded early when every installed kernel has them, and a Limine boot entry without the parameters is an error**
- **test: tests/nvidia-hardware-test.sh for a real NVIDIA PC: check (read-only state of the detection, the live nvidia_drm modeset/fbdev, versions), apply, and visual (was the gaming mode picture clean), with a report file to paste**
- **fix: the NVIDIA modules are loaded early only while every installed kernel has them, decided again at every kernel or driver change by a pacman hook (steamify-nvidia-initramfs): a later kernel without the modules (another kernel, a failed DKMS build, a downgrade) no longer makes its initramfs and Limine boot entry fail**
- **feat: the NVIDIA fix is only for RTX 20 series or newer, decided like the VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists); older cards are left alone**
## 2.9.6 - 2026-09-30
- **fix(ci): a dev ISO from a release branch is built with that branch's own Steamify (input steamify_ref of the ISO workflow), not the newest published release: release/2.9.6 kept producing 2.9.5 ISOs**
- **docs: changelog hashes for 2.9.6**
- `9a2965d` **fix(ci): the ISO workflow always runs from master; main asks for a release ISO, a release branch for a dev ISO (input `kind` of iso-1-github-tag.yml; feat/steamify is no longer needed)**
- `c42d545` **fix(ci): a version published from main starts a real ISO release, a release branch a dev ISO (it always started the dev one)**
- `b3bed43` **chore: Version 2.9.6**
## 2.9.5 - 2026-09-30
- `70ecb56` **ci: trigger a mirror sync**
- `a7276cf` **ci: sync the git.upriser.nl mirror on every branch and tag**
- `b3549d4` **ci: sync the mirror on release branch pushes too**
- `a232a55` **feat(ci): sync the git.upriser.nl mirror on every push to main and every tag (git-upriser-sync.yml calls the mirror-sync API: the Gitea mirror builds at once instead of at its interval; secrets GIT_UPRISER_URL and GIT_UPRISER_TOKEN, retried, skipped on Gitea itself)**
- `3676c64` **docs: link the renamed steamify-cachyos-live-iso repo (the release dispatches the ISO workflow iso-1-github-tag.yml there)**
- `971e792` **chore: Version 2.9.5**
## 2.9.4 - 2026-09-29
- `619ef1f` **docs: AGENTS.md and TECHNICAL.md: the CEC driver cache, the one workflow for GitHub and a Gitea mirror, and that a new release starts the Steamify ISO's release**
- `b624053` **chore: Version 2.9.4**
## 2.9.3 - 2026-09-29
- `7f5d29c` **feat(ci): a new Steamify release starts the Steamify ISO's release (a test build from the ISO repo's feat/steamify; secret ISO_DISPATCH_TOKEN)**
- `cfe3ce7` **chore: Version 2.9.3**
## 2.9.2 - 2026-09-29
- **feat(ci): a Gitea mirror publishes its own release per version (akkuman/gitea-release-action; never overwrites one, notes from the changelog, links to the mirror)**
- **fix(ci): the build also runs on a Gitea mirror (act_runner): shellcheck through ludeeus/action-shellcheck, which brings its own binary; the artifact goes up there with christopherhx/gitea-upload-artifact (GitHub refuses a workflow that mentions the deprecated upload-artifact@v3); releases are only published on GitHub**
- `fe4f3f4` **chore: Version 2.9.2**
## 2.9.1 - 2026-09-29
- `c87e6c7` **docs: changelog for the CEC driver cache**
- `fc05725` **fix: HDMI-CEC: an older cached CEC driver is removed when a new pin is downloaded**
- `90bc5e4` **fix: HDMI-CEC: Valve's CEC driver is downloaded once and kept in /var/cache/steamify (GitHub rate-limits repeated downloads with HTTP 429, which left CEC off); turning CEC on again needs no network**
- `d99ff65` **chore: Version 2.9.1**
## 2.9.0 - 2026-09-28
- `d30d505` **chore: Version 2.9.0**
- `66ea63c` **docs: KDE Plasma only: other desktops and display managers "are not supported" (README, was "don't work yet")**
- `9b86cd1` **docs: KDE Plasma only: other desktops don't work yet (README)**
- `d73e71d` **docs: README, TECHNICAL and TROUBLESHOOTING for 2.9.0: Steam's System settings, serial number and Wi-Fi backend, --defaults --list, the Steamify ISO**
- `a72d848` **feat: Steam's OS Version is the SteamOS release Steamify follows (steamos-3.9), its OS Codename steam-machine; About this System keeps "CachyOS Linux" (UseOSReleaseVersion)**
- `27a4070` **fix: Steam's OS Variant shows Steamify's version (VARIANT_ID=steamify-2.9.0; Steam shows VARIANT_ID, not VARIANT)**
- `44bfe07` **fix: No VERSION_ID in os-release: About this System said "CachyOS Linux 2.9.0"; the version is in VARIANT ("Steamify 2.9.0")**
- `435f69c` **feat: Steam's System settings: the OS name stays CachyOS (no renaming, also not in About this System), Steamify <version> as the variant, the SteamOS release it follows as the codename (steamos-3.9)**
- `ce71b34` **feat: Steam's System settings and About this System like on SteamOS: OS name "CachyOS with Steamify" (lsb-release, kept through CachyOS updates by a pacman hook), Steamify as OS variant and version (os-release VARIANT/VERSION_ID; NAME/PRETTY_NAME stay CachyOS's for limine, TARGET_OS_NAME pinned), "CachyOS Linux with Steamify" in About this System; on a Steam Machine the serial number and Steam's Wi-Fi backend setting (existing installs get it as an update)**
- `07a94cd` **fix(ui): The progress screen's ✓ and ! stand upright: only a dot on the circle spins while a step runs (they kept the spinner's last angle)**
## 2.8.0 - 2026-09-28
- **chore: Version 2.8.0**
- **feat: steamify.sh --defaults --list: what --defaults can set up here, as JSON, for an installer page**
## 2.7.0 - 2026-09-28
- `4f6e6fd` **feat: --defaults takes --skip <ids> and --boot gamescope|desktop, for the Steam Machine ISO's installer pages**
- `5bf9da4` **fix: HDMI-CEC enables cec-audio-control.socket (the TV remote's volume keys); existing installs get it as an update**
- `14aa7c0` **fix: the app's progress screen says "Boot into desktop", not "Boot into Boot into"**
- `c4ec755` **feat: --defaults --options <ids> (exactly these on) replaces --skip; steamify.sh --boot gamescope|desktop on its own switches where an installed conversion starts**
- `eadbdda` **docs: release branches (release/X.Y.Z, feature/ and bugfix/ branches into it, the release into main); CI builds release/** pushes**
- `bee18b7` **docs: the agent merges feature/bugfix branches into the release branch; the release into main stays the user's**
- `501c0ba` **docs: gh or git for merging into the release branch**
- `b1adacb` **docs: gh is required for the release-branch pull requests; ask the user to install it**
- `ced4a45` **chore: the v2 app preview is gone (it is the released app): no preview pre-release step in CI, no mention in steamify-app.sh**
- **fix: turning the theme off no longer brings back single user's launcher restriction when single user was turned off in between**
## 2.6.0 - 2026-09-27
- `b948c20` **feat: --defaults applies the default setup without the menu, also from an installer (no session): the base for a Steam Machine ISO**
## 2.5.2 - 2026-09-27
- **docs: README screenshot at 2.5.2: everything on, nothing to update**
- `0c96bed` **docs: README screenshot at 2.5.2: everything on, nothing to update**
## 2.5.1 - 2026-09-27
+86
View File
@@ -0,0 +1,86 @@
# Testing the NVIDIA fix on a real PC
For the PC with an RTX 5080 (or any RTX 20 series or newer card) that shows a corrupted picture when
gaming mode (gamescope) starts. Branch `feature/nvidia-gaming-fix`, not released. Background and open
work: `TODO-nvidia.md`; research with sources: `NVIDIA-RESEARCH.md`.
## What the fix does
With a supported NVIDIA GPU (RTX 20 series or newer, same check as the VRAM booster) and its driver installed it
- adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine, systemd-boot or GRUB;
the file is backed up as `<file>.bak-gamescope-wizard`),
- loads the NVIDIA modules in the initramfs, but only while every installed kernel has them (a pacman hook,
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, decides again at every kernel change),
- rebuilds the initramfs and boot entries and checks that the parameters really are in them.
It takes effect after a reboot. Older cards (GTX 10 series and older) are left alone.
## Before you start
- CachyOS with the NVIDIA driver installed (`nvidia-open`), a user with sudo, `git`.
- Be at the PC and able to see the screen: the last step needs your eyes.
- Know the way back (below) in case the PC doesn't boot to a picture: a TTY (Ctrl+Alt+F3) or the boot menu's
other kernel entry.
## Steps
1. Get the code:
```
git clone -b feature/nvidia-gaming-fix https://github.com/theupriser/steamify-cachyos
cd steamify-cachyos
```
(An existing checkout: `git fetch && git checkout feature/nvidia-gaming-fix && git pull`.)
2. Look first, change nothing:
```
bash tests/nvidia-hardware-test.sh check
```
3. Apply the fix (asks for your sudo password), then **reboot**:
```
bash tests/nvidia-hardware-test.sh apply
```
4. After the reboot, check again:
```
bash tests/nvidia-hardware-test.sh check
```
5. Start gaming mode, look at the screen, then (from the desktop or a TTY):
```
bash tests/nvidia-hardware-test.sh visual
```
It asks whether the picture was clean and for one line on what you saw.
6. Send back `~/steamify-nvidia-report.txt` (every run adds to it), or start a new session in the checkout and
say "read TODO-nvidia.md and the report".
(`./steamify.sh` from the same checkout also applies the fix, automatically, as part of the SteamOS conversion:
there is no menu option for it yet. The script above shows more.)
## Reading `check`
| Line | Good result | If not |
|---|---|---|
| `PASS a supported NVIDIA GPU ... is detected` | your 5080 | `FAIL ... older than RTX 20`: the card is skipped on purpose. `FAIL no NVIDIA GPU with its driver`: driver not installed (nouveau?) |
| `NVIDIA PCI device id 0x... (not on a legacy list ...)` | RTX 20 or newer | on a legacy list: older card |
| `no chwd legacy lists found` | (note only) | the check cannot tell old from new cards; every card counts as supported. Tell me, it's open item 4 in `TODO-nvidia.md` |
| `PASS nvidia-drm.modeset=1 is on the running kernel's command line` (and `fbdev=1`) | after step 3 and the reboot | "in the boot loader's file but not booted yet": reboot, or the boot entry used is another one |
| `PASS nvidia_drm modeset = Y` (and `fbdev = Y`) | after the reboot | `unreadable`: it needs sudo, enter the password |
| `... early-load drop-in is used / skipped` | note only: skipped means a kernel without the NVIDIA modules is installed | nothing to do |
## Reading the result
- Parameters on, `modeset = Y`, `fbdev = Y`, picture clean: the fix works.
- Parameters on and `Y`, picture still corrupted: not this fix. The report has the gamescope and NVIDIA log lines and
the versions of `nvidia-open`, `nvidia-utils`, `gamescope` and `gamescope-session-cachyos`: the cause is probably the
gamescope/driver combination for Blackwell (see `NVIDIA-RESEARCH.md`).
- No picture at all after the reboot: undo it (next section) from a TTY or the other kernel entry, and send the report.
## Undo
Turning the SteamOS conversion off in the wizard removes the fix too. On its own, from the checkout:
```
SCRIPT_DIR=$PWD bash -c 'source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; nvidia_disable'
```
It removes the parameters, the early-load file, the pacman hook and its script, and rebuilds the boot entries (reboot after).
By hand: delete ` nvidia-drm.modeset=1 nvidia-drm.fbdev=1` from `/etc/default/limine` (`KERNEL_CMDLINE[default]`),
`/etc/sdboot-manage.conf` (`LINUX_OPTIONS`) or `/etc/default/grub` (`GRUB_CMDLINE_LINUX_DEFAULT`), or restore the
`.bak-gamescope-wizard` copy next to it; remove `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`,
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook` and `/usr/local/libexec/steamify-nvidia-initramfs`; then
`sudo limine-mkinitcpio` (Limine) or `sudo mkinitcpio -P` and `sudo sdboot-manage gen` / `sudo grub-mkconfig -o /boot/grub/grub.cfg`.
## What is and isn't proven
Proven in VMs (QEMU/KVM, CachyOS ISO 260809): the parameters land and survive a reboot on Limine, systemd-boot and GRUB;
disabling restores the original; on Limine the pacman hook keeps the early-load file right across kernel reinstalls
(with fake NVIDIA modules). Not proven: that the fix cures the 5080's picture, the real NVIDIA modules in the
initramfs, DKMS hook order, systemd-boot/GRUB with a pacman transaction, and the RTX 20+ check against a real chwd list.
Unit test (no hardware): `bash tests/nvidia-test.sh`.
+65
View File
@@ -0,0 +1,65 @@
# NVIDIA and gamescope: research notes (branch `feature/nvidia-gaming-fix`)
Written 2026-10-01 for the NVIDIA fix (`lib/nvidia.sh`). Delete with `TODO-nvidia.md` and
`.no-release-yet` when the feature is released, or move what is still useful to `TECHNICAL.md`.
"Verified" means seen in this session (a VM run or a fetched page); the rest is from search results or memory.
## The user's PC
RTX 5080 (Blackwell). Blackwell only works with NVIDIA's open kernel modules (`nvidia-open`), driver 570+.
The corrupted picture at gaming mode start is not diagnosed yet: the fix adds kernel parameters, the real cause
may be the gamescope/driver combination. `tests/nvidia-hardware-test.sh` collects the facts.
## What the fix changes and why (reasoning, not proven for gamescope)
- gamescope runs the display itself through DRM/KMS. With NVIDIA that needs `nvidia-drm.modeset=1`; `nvidia-drm.fbdev=1`
gives the console a framebuffer from `nvidia-drm`, so the hand-off from the console to gamescope is clean.
- Loading the NVIDIA modules in the initramfs (early KMS) only changes how early boot looks (native resolution,
splash, passphrase prompt), not speed. It is not needed for gamescope, which starts after login (believed, not proven).
- No source found that mentions these parameters for gamescope; the fix is a standard NVIDIA/Wayland setup, applied
automatically. Whether it cures the 5080's picture is only known after `tests/nvidia-hardware-test.sh`.
## Which cards (decision 2026-10-01: RTX 20 series or newer only, same check as the VRAM booster)
The code skips a card whose PCI id is on chwd's legacy lists (`vram_nvidia_legacy_id`); the notes below are why older
cards are not promised.
- Open kernel modules: Turing (RTX 20, GTX 16) and newer only; they need the GSP processor first built into Turing.
Maxwell, Pascal and Volta (GTX 900/10 series, Titan V) only work with the proprietary driver, whose legacy branch
is 580. Source: [NVIDIA README, open kernel modules](https://download.nvidia.com/XFree86/Linux-x86_64/560.35.03/README/kernel_open.html),
[NVIDIA datacenter driver guide, kernel modules](https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/kernel-modules.html).
- `nvidia-drm.modeset` and `fbdev` are options of the `nvidia-drm` module in both flavours, so the fix applies to
any card whose driver provides `nvidia_drm` (what `nvidia_present` tests: GPU vendor 0x10de + `modinfo nvidia_drm`).
Whether gamescope then works on an older card is a different question, and no source says the fix helps there.
- Not NVIDIA's proprietary driver: nouveau has no `nvidia_drm`, so the fix does nothing. The CachyOS handheld ISO boots
GTX 10xx and older with nouveau until the NVIDIA driver is installed
([CachyOS forum](https://discuss.cachyos.org/t/information-experimental-cachyos-handheld-edition/203)).
## Known gamescope problems that are not this fix
- **GTX 1050 Ti (Pascal), driver 580.119.02, gamescope newer than 3.16.16:** the CachyOS handheld session fails to start when
a display is on the GPU's HDMI port (back to the TTY, loop). Workarounds: downgrade `gamescope` and `lib32-gamescope`
to 3.16.16, or use the motherboard's video port. Fixed upstream? unknown.
[CachyOS forum](https://discuss.cachyos.org/t/no-display-on-cachyos-handheld-edition-on-nvidia-with-gamescope-3-16-16/20935)
- **VRS on PCs:** CachyOS' gamescope-session enables variable rate shading (`STEAM_USE_DYNAMIC_VRS=1`,
`RADV_FORCE_VRS_CONFIG_FILE`, `echo 1x1 > ...` in `/usr/lib/steamos/gamescope-session`). It broke rendering (missing
floors/lighting, bad post-processing) on a PC with an AMD RX 6800 XT. RADV is AMD's driver: not the NVIDIA corruption.
Workaround: comment those three lines, or per game `env -u RADV_FORCE_VRS_CONFIG_FILE STEAM_USE_DYNAMIC_VRS=0 %command%`.
[CachyOS forum](https://discuss.cachyos.org/t/cachyos-gamescope-session-asset-missing-vrs-fix/34971)
- gamescope's DRM backend needs Vulkan DRM format modifiers; with the open Mesa driver NVK that came in Mesa 24.1
([GamingOnLinux](https://www.gamingonlinux.com/2024/05/nvk-driver-gets-drm-format-modifiers-to-work-with-gamescope-in-mesa-24-1)).
The proprietary driver had format-modifier trouble with gamescope too (GitHub issues
[ValveSoftware/gamescope#1662](https://github.com/ValveSoftware/gamescope/issues/1662),
[#1516](https://github.com/ValveSoftware/gamescope/issues/1516): titles seen only, not read).
## What was verified in VMs (QEMU/KVM, CachyOS ISO 260809)
- Kernel parameters land and survive a reboot on Limine, systemd-boot and GRUB; disable restores the original.
- Limine's tool is a compiled program: an appended `KERNEL_CMDLINE[default]+=" ..."` line was pasted into the kernel
command line as text; the fix edits the existing `KERNEL_CMDLINE[default]="..."` line.
- `mkinitcpio` fails on a MODULES entry a kernel lacks; `limine-mkinitcpio` then skips that kernel's initramfs and boot
entry (parameters included); systemd-boot/GRUB image: "may not be complete" (not run with failing modules).
- Real CachyOS/Limine pacman hooks: `10-limine-snapper-lock`, `60-limine-mkinitcpio-remove-pre`, `60-mkinitcpio-remove`,
`80-limine-efi-deploy`, `90-limine-mkinitcpio-remove-post`, `90-mkinitcpio-install`; Steamify's hook is `85-`
(DKMS's is `71-dkms-install`, not installed in the VM). A mirror older than the ISO "downgrades" kernels on reinstall.
- The hook keeps the early-load drop-in right across kernel changes (see `TODO-nvidia.md`).
## Still unknown (needs the hardware)
- Does the fix cure the 5080's corrupted picture? Which gamescope/driver versions does the PC have?
- Does it help, harm or do nothing on Maxwell/Pascal/Volta cards? No older card available yet.
- Real NVIDIA modules in the initramfs (VMs only had renamed fake modules); DKMS hook order on a PC with
`nvidia-open-dkms`.
+24 -1
View File
@@ -19,6 +19,10 @@ Steam Machine.
on the desktop too.
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
the default.
- Steam's **System** settings show the SteamOS release Steamify follows
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
Steamify's version as OS Variant. The OS name stays CachyOS
([details](TECHNICAL.md#what-steams-system-settings-show)).
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
**Add to Steam** in right-click menus
([details](TECHNICAL.md#steamos-desktop-look)).
@@ -62,7 +66,8 @@ What Steamify can do on a Valve Steam Machine:
([details](TECHNICAL.md#hdmi-cec)).
- **Steam Machine support** - the front **LED bar** works, Steam's
**hardware settings** (fan, performance) work, and the power button puts
it to sleep like a console.
it to sleep like a console. Steam's System settings show the serial
number, and Steam's **Wi-Fi backend** setting works.
- **Power-off fix** - on by default: shutting down really turns the Steam
Machine off, also with the newest CachyOS kernel
([details](TECHNICAL.md#power-off-fix-steam-machine)).
@@ -73,6 +78,11 @@ What Steamify can do on a Valve Steam Machine:
## Requirements
- CachyOS with the KDE Plasma desktop (the default CachyOS Desktop edition)
> **KDE Plasma only.** Steamify works with KDE Plasma and its login managers
> (plasma-login-manager or SDDM). Other desktops (GNOME, Hyprland, Cosmic,
> ...) and other display managers are not supported: the switching between gaming mode
> and the desktop, the theme and the shortcuts are all built for Plasma.
- Your normal user account, with permission to use `sudo`
## Installation
@@ -83,6 +93,11 @@ Open **Konsole** on your Plasma desktop and run:
curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
```
Installing CachyOS on a Steam Machine? The
[Steamify CachyOS ISO](https://github.com/theupriser/steamify-cachyos-live-iso)
has Steamify built into the installer: pick the options there, and the
first boot is already set up.
Prefer to look at the script first? Clone the repository and run
[`./steamify.sh`](steamify.sh) (keep the whole folder: it needs
[`lib/`](lib/)).
@@ -125,6 +140,14 @@ steamos-session-select persistent # start where you left off last time
steamos-session-select oneshot # always start in gaming mode (default)
```
Where the PC starts after a restart can also be set from a script, once the
SteamOS conversion is on (only that changes; `sudo` may ask for your password):
```bash
steamify.sh --boot desktop # start in the desktop from the next boot on
steamify.sh --boot gamescope # start in gaming mode again (default)
```
## Something wrong?
Stuck on a black screen in gaming mode: press **Ctrl+Alt+F3**, log in, and run
+97 -3
View File
@@ -111,6 +111,9 @@ Turning it off restores `/etc/plasmalogin.conf` from its backup, removes the
SDDM autologin, sync bridge, shortcut, sudoers rule and Steam autostart, and
switches back to plasma-login-manager.
The conversion also sets what Steam's System settings show, see
[below](#what-steams-system-settings-show).
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
in `~/.config/environment.d/` (and gamescope-session's own environment
file), which makes Steam show Steam Deck button glyphs in gaming mode.
@@ -139,6 +142,33 @@ taken from the newest `steamdeck-kde-presets` on Valve's SteamOS mirror
Turning it off restores your previous look and panel layout, and removes `cachyos-vapor` again
if the wizard installed it (and nothing else, like `cachyos-handheld`, needs it).
## What Steam's System settings show
With the SteamOS conversion on, `/etc/os-release` gets:
| Key | Value | Shown in Steam as |
|---|---|---|
| `VERSION_ID` | `steamos-3.9`: the newest SteamOS release in Valve's repo (offline: the previous value) | OS Version |
| `VERSION_CODENAME` | `steam-machine` | OS Codename |
| `VARIANT` / `VARIANT_ID` | `Steamify 2.9.0` / `steamify-2.9.0` | OS Variant (`VARIANT_ID`) |
The OS name stays CachyOS everywhere: Steam's OS Name comes from
`lsb_release -d`, which isn't touched, and `NAME`/`PRETTY_NAME` stay
CachyOS's. limine-snapper-sync finds the boot entries by that name, so
changing it would break snapshot boot entries; `/etc/default/limine` gets
`TARGET_OS_NAME="CachyOS"` as a guard when it has none.
KDE's About this System would show `VERSION_ID` after the name
("CachyOS Linux steamos-3.9"); `UseOSReleaseVersion=true` in
`~/.config/kcm-about-distrorc` makes it show `VERSION`, which CachyOS doesn't
have, so it keeps saying "CachyOS Linux".
CachyOS's own hooks (`cachyos-hooks`) reset os-release on updates of
`filesystem`; the pacman hook `zz-steamify-os-release` runs after them and
sets the keys again (`/usr/local/libexec/steamify-os-release`). The values are
refreshed after every Steamify run that changes something. Turning the
conversion off removes the hook and runs CachyOS's `cachyos-branding` again.
## Front LED bar (Steam Machine)
The **Steam Machine support** component, only shown on Fremont hardware
@@ -156,7 +186,14 @@ The **Steam Machine support** component, only shown on Fremont hardware
- installs and enables `steamos-manager`, the service Steam in gaming mode
uses for hardware settings (fan, performance, and the HDMI-CEC settings
when [HDMI-CEC](#hdmi-cec) is on); it recognises the Steam Machine from its
DMI data.
DMI data;
- makes the serial number readable for Steam, which shows it in its System
settings (`/etc/tmpfiles.d/steamify-serial.conf`: `product_serial` is
root-only by default);
- makes Steam's Wi-Fi backend setting work: steamos-manager switches it in
`/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf`, which is created
with `wifi.backend=wpa_supplicant` (NetworkManager's default) when no
backend is set anywhere yet.
Turning it off removes all of that again (the AUR helper is kept).
@@ -169,6 +206,34 @@ or upgraded. A newly added kernel doesn't come with its headers, so
`ensure-kernel-headers.service` checks at every boot and installs any
missing `-headers` package, which makes DKMS build the driver for it.
## NVIDIA fix for gaming mode
gamescope drives the display itself through DRM/KMS, which with NVIDIA needs
kernel modesetting and the framebuffer driver, and the driver loaded early;
without them gaming mode can show a corrupted image. With a supported NVIDIA GPU (RTX 20 series or newer, decided like the VRAM
booster does: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids`
is older and left alone, `vram_nvidia_legacy_id`; without those lists every
card counts) and its driver installed (`lib/nvidia.sh`), the SteamOS conversion adds
`nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine,
systemd-boot or GRUB; the file is backed up first) and
`/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia
nvidia_modeset nvidia_uvm nvidia_drm)`), then rebuilds the initramfs and boot
entries. The early-load drop-in is only there while every installed kernel has the
NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio`
then skips that kernel's boot entry, parameters included). That is decided again
at every kernel or driver change by a pacman hook
(`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS builds,
before the initramfs is built) running `/usr/local/libexec/steamify-nvidia-initramfs`:
another kernel without the modules, a failed DKMS build or a downgrade removes
the drop-in, and it comes back once every kernel has them again.
On Limine the parameters go into the existing `KERNEL_CMDLINE[default]="..."`
line: an extra appended `+=` line is pasted into the command line as text.
Only what's missing is changed; it applies after a reboot. Turning
the conversion off removes both, the hook and its script. `tests/nvidia-test.sh` tests it against a fake GPU
and fake boot loader files; `tests/nvidia-hardware-test.sh check|apply|visual` is for a
real NVIDIA PC (read-only check, the real apply, and a prompt for whether the picture
was clean), and writes `~/steamify-nvidia-report.txt`.
## HDMI-CEC
The **HDMI-CEC** item (on every PC; ticked by default only on a Steam
@@ -180,7 +245,9 @@ SHA-256 in Valve's package index:
- `cecd`, Valve's CEC daemon (a user service started with the desktop and
gaming mode): TV remote keys become normal key presses (arrows, Enter,
Back), and it turns the TV on and off with the PC;
- `cec-audio-control`: volume of the TV or receiver;
- `cec-audio-control`: volume of the TV or receiver (the TV remote's volume
keys); its user socket is enabled by Steamify, since SteamOS enables it
through a preset that pacman doesn't apply;
- `inputattach-cec-units` (with `linuxconsole` from CachyOS for
`inputattach`): attaches USB CEC adapters (Pulse-Eight, RainShadow).
@@ -418,6 +485,31 @@ steamos-session-select persistent # remember the last-used session across reboo
steamos-session-select oneshot # always start in gamescope (default, like a Deck)
```
`steamify.sh --boot gamescope|desktop` sets where the PC starts after a
restart (the menu's Boot into row) from a script: it needs the SteamOS
conversion and changes nothing else, not even the updates a normal run would
apply. Exit code 1 without the conversion or with another value.
## Install-time mode (`--defaults`)
For an installer (the Steam Machine ISO), without a session or prompts
(passwordless sudo required):
```bash
steamify.sh --defaults # what the menu would preselect
steamify.sh --defaults --options gaming,theme,cec,machine --boot desktop
steamify.sh --defaults --list # what --defaults can set up here, as JSON
```
`--options` turns on exactly the listed items (the menu's ids: `gaming`,
`theme`, `glyphs`, `single`, `launcher`, `notify`, `vram`, `cec`, `machine`,
`poweroff`), everything else off; an item that's on brings its parent
(single user the conversion, the power-off fix Steam Machine support). An
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
`bios` in the list: exit code 1 before anything changes. What needs a
Plasma session waits for the first login (`lib/first-login.sh`).
With `Relogin=true`, a gamescope session that fails to start is restarted
immediately, which can turn into a loop - see
[TROUBLESHOOTING.md](TROUBLESHOOTING.md) for the way out.
@@ -445,11 +537,13 @@ immediately, which can turn into a loop - see
| `lib/fremont-poweroff.sh` | Steam Machine support: the power-off fix (DKMS module from `patches/`) |
| `lib/steam-game.sh` | Add as non-Steam game: Steamify in the Steam library (`patches/steam-shortcuts.py`) |
| `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer |
| `lib/first-login.sh` | `--defaults` without a session (the Steam Machine ISO's installer): the one-time first-login step that sets up single user's launcher on Plasma's new layout and opens the app |
| `lib/nvidia.sh` | NVIDIA fix for gaming mode: kernel parameters and early modules (part of the SteamOS conversion) |
| `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) |
| `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README |
| `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README |
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`), with `patches/` and `services/` embedded |
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
| `.github/workflows/bundle.yml` | Builds and checks it on every push (GitHub and a Gitea mirror); publishes it on `main`, and starts the Steamify ISO's release |
The single-file version is generated: on every push to `main`, GitHub
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
+111
View File
@@ -0,0 +1,111 @@
# TODO: NVIDIA fix for gaming mode (branch `feature/nvidia-gaming-fix`)
Delete this file, `NVIDIA-INSTRUCTIONS.md`, `NVIDIA-RESEARCH.md` and `.no-release-yet` when the feature is released.
Written 2026-10-01 so a new session can pick this up.
## Problem
A PC with an NVIDIA RTX 5080 (Blackwell, open kernel modules) shows a corrupted
image when gaming mode (gamescope) starts. Cause not confirmed. Steamify had no
NVIDIA handling at all. Likely: `nvidia-drm.modeset=1` / `nvidia-drm.fbdev=1`
missing, or a gamescope/driver mismatch.
## What is built (all on this branch, pushed)
- `lib/nvidia.sh`: part of the SteamOS conversion (`gaming_enable` / `gaming_disable`).
With an NVIDIA GPU + driver it adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the
kernel command line (Limine, systemd-boot, GRUB; backup first) and, only when every
installed kernel has `nvidia_drm`, `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`.
Rebuilds initramfs + boot entries, verifies the config and the generated entries
have the parameters (error otherwise). Undone on disable. Description: `TECHNICAL.md`.
- `FEATURE_VERSION[gaming]=2.9.7` so installs that already have the conversion re-apply it.
- Test hooks `NVIDIA_DRM_DIR`, `NVIDIA_MODULES_DIR`, `NVIDIA_LIMINE_CONF`,
`NVIDIA_SDBOOT_DIR`, `NVIDIA_GRUB_CFG`: only set by tests; defaults are the real paths.
## Tested
- `bash tests/nvidia-test.sh`: 22 checks against a fake RTX 5080 beside an iGPU, a stub
`modinfo`, temp boot loader files. All pass.
- Real VMs (QEMU/KVM, Limine, systemd-boot, GRUB): enable, reboot, kernel command line
has the parameters; disable, reboot, original command line. All pass. Found and fixed:
Limine pasted an appended `+=` line as text into the cmdline; a kernel without the
NVIDIA modules made limine-mkinitcpio skip its boot entry.
## Kernel changes (done, VM-tested 2026-10-01, Limine)
The early-load drop-in is kept right by a pacman hook (`patches/steamify-nvidia-initramfs.{sh,hook}`,
installed by `nvidia_enable`, `/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`). Real pacman
transactions in a Limine VM: the hook runs between "Updating module dependencies" and "Updating
linux initcpios" (real hook names there: 60-*-remove, 80-limine-efi-deploy, 90-limine-mkinitcpio-remove-post,
90-mkinitcpio-install; DKMS would be 71-): the drop-in is present while every kernel has the modules, removed
when the LTS kernel loses them, back when they return; initramfs nvidia files 1 -> 5 -> 1 -> 5 -> 1
(1 = baseline, 4 modules added); no ERROR/skipping in any rebuild; cmdline kept the parameters after a reboot;
disable removes hook, script and drop-in. Found on the way: an empty hook/script was installed when
`patch_file` failed (now an error). Only tested with fake modules (renamed copies of a small module), on
Limine; systemd-boot and GRUB use the same hook but were not run with pacman transactions.
## Opt-out toggle (new request, 2026-10-01: not built yet)
When a compatible NVIDIA card is listed there should be a menu option, on by default (opt-out), named
"NVIDIA compatibility", as a sub-option of the SteamOS conversion, directly under "Boot into" (`boot`).
Today the fix runs unconditionally inside `gaming_enable`/`gaming_disable`.
- [ ] New component `nvidia` in `lib/menu.sh`: `COMPONENTS` right after `boot`, `PARENT[nvidia]=gaming`, `LABEL`,
`FEATURE_VERSION[nvidia]`, `component_available` -> `nvidia_available` (= `nvidia_present`); not in
`NO_PRESELECT` (ticked by default, `feature_new` ticks it for installs that already have the conversion).
`nvidia_status` from the system (hook + parameters present), `nvidia_enable`/`nvidia_disable` = the code now
called from `gaming_enable`/`gaming_disable` (remove those calls). Check `toggle_component` dependencies,
`feature_record_unticked`, the plan texts ("This will: ...").
- [ ] The app: `ui/qml/Texts.qml` item texts, `AppState.qml`, the screen rows, `lib/backend.sh` if it lists ids;
`--defaults [--options <ids>]` (the Steam Machine ISO's installer pages: it names the ids) and `--skip`.
- [ ] README rows/screenshot rule (a release that adds a menu row retakes `assets/screenshot-menu.png`), TECHNICAL.md,
CHANGELOG, `tests/nvidia-test.sh` (status/enable/disable through the component), VM menu test in
steamify-cachyos-dev (`share/vmtest/menu`, TESTPLAN.md row).
- [x] What "compatible" means (decided 2026-10-01): RTX 20 series or newer, the same check as the VRAM booster
(`vram_nvidia_legacy_id`: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids` is older; without the
lists every card counts). `nvidia_present` = such a card + `nvidia_drm` available; the toggle's `nvidia_available`
is the same function. Older cards (GTX 10/9 series) are left alone: no promise they work with gamescope.
## Older cards and other research
Decision 2026-10-01: support RTX 20 series or newer only, with the VRAM booster's check (done in `lib/nvidia.sh`).
The user had hoped older GPUs would work too; not promised. Full notes with sources: **`NVIDIA-RESEARCH.md`**.
Short version: open kernel modules need Turing+, Maxwell/Pascal/Volta need the proprietary driver (580 legacy branch);
`nvidia-drm.modeset/fbdev` exist in both, so the fix applies to any card with `nvidia_drm`, but nothing found says gamescope
works better or worse there (a GTX 1050 Ti has a known gamescope>3.16.16 start problem on HDMI, not ours). Cannot be promised:
needs a test on a real older card. Design for the toggle: on by default for any card with `nvidia_drm`, the label says
what it does, `tests/nvidia-hardware-test.sh` reports GPU and driver so results can be compared.
## Still to do
1. [ ] **On the NVIDIA PC** (only place the real fix can be judged; the full steps, how to read the results and the undo
are in `NVIDIA-INSTRUCTIONS.md`), from this checkout:
`bash tests/nvidia-hardware-test.sh check` (before), `... apply` (asks sudo), reboot,
`... check` (after: `nvidia_drm modeset/fbdev = Y`), boot gaming mode, then
`... visual` (was the picture clean?). Everything goes to `~/steamify-nvidia-report.txt`:
paste it into the session.
2. [ ] If the parameters apply but the picture is still corrupted: look at the report's
gamescope/NVIDIA log lines and the versions (`nvidia-open`, `nvidia-utils`, `gamescope`,
`gamescope-session-cachyos`); the cause is then probably a gamescope/driver mismatch
for Blackwell, not this fix.
3. [ ] Not covered by any test: the early-load drop-in with the REAL NVIDIA modules (the VMs only have renamed
fake ones), and systemd-boot/GRUB with a pacman transaction (only Limine was run).
4. [ ] **Verify the RTX 20+ check on the PC** (decided 2026-10-01, only unit-tested with a fake chwd list; this laptop and the VMs
have no `/var/lib/chwd/ids`): `bash tests/nvidia-hardware-test.sh check` prints the NVIDIA PCI id, whether it is on a chwd legacy
list, and whether the lists exist at all. Expect for the RTX 5080: "supported", "not on a legacy list". If it says "no chwd
legacy lists found" the check cannot tell old from new there (every card then counts as supported, like the VRAM booster):
look at what `chwd`/`/var/lib/chwd/ids` provide on CachyOS and whether another source (the open-driver device list, the
`nvidia-open` package) would be better for both the VRAM booster and this fix. Also try `check` on any older NVIDIA card
that turns up (GTX 10/9 series): it must say "older than RTX 20 ... not applied" and `apply` must change nothing.
5. [ ] Changelog: fill in the commit hashes of this feature's lines (next commit, per AGENTS.md).
6. [ ] Build the opt-out toggle (section above) before release.
7. [ ] When complete and tested: ask the user whether it may be released. On a yes delete
`.no-release-yet` and this file, open the PR into `release/2.9.7` (local branch only so
far, one commit `chore: Version 2.9.7`; push it then) and merge it. The user merges
`release/2.9.7` into `main`.
## Working rules for this repo (see AGENTS.md and ../steamify-cachyos-dev/AGENTS.md)
- Never work on `main` or a `release/*` branch; no `Co-Authored-By` / "Generated with
Claude" lines in commits or PRs. No git identity on the dev laptop: use
`git -c user.name="Rick Peters" -c user.email="rickpeters@upriser.nl" commit`.
- Don't push `release/2.9.7` before the PR (a push can start a dev ISO build).
## If the VM tests need repeating (dev laptop, Ubuntu)
- `scripts/vminstall.sh` (steamify-cachyos-dev) with `VM_BOOTLOADER=limine|systemd-boot|grub`,
`CI=1`, a short `VM_DIR` (`~/vms/...`: socket paths over 108 bytes fail) and `VM_SSH_KEY`.
- This session's shell lacked the `kvm` group: run QEMU steps as `sg kvm -c "..."`.
- `/tmp/vminstall-iso.lock` belongs to another user and there is no `bsdtar`: use a copy of
`vminstall.sh` with another lock path and a `bsdtar` shim (Python `pycdlib` in a venv).
- Delete everything afterwards (`~/vms` incl. `pkg-cache`, the 3 GB ISO, keys).
+8
View File
@@ -18,6 +18,14 @@ restarted right away (`Relogin=true`), which is why it can loop.
Run the wizard again and press `a` in the menu to re-apply everything that's
on (also useful after a CachyOS update). To undo a part, untick it.
## "Target OS name ... not found in /boot/limine.conf"
limine-snapper-sync finds the boot entries by the OS name. Steamify never
changes that name (it only adds version keys to `/etc/os-release`), and pins
`TARGET_OS_NAME="CachyOS"` in `/etc/default/limine`. If you see this message,
check that `PRETTY_NAME` in `/etc/os-release` still says `CachyOS`, or set
`TARGET_OS_NAME` in `/etc/default/limine` to the name your boot entries use.
## The LED bar on the Steam Machine stays dark
Restart once more; a freshly installed driver often needs a reboot. The menu
+1
View File
@@ -177,6 +177,7 @@ backend_apply() {
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
done
feature_record_unticked
os_version_refresh
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " =~ \ (gaming|single|boot|kpin)\ ]] && RESTART_FOR_LOGIN=true
backend_event finished "\"failed\":$(json_list "${failed[@]}"),\"restart\":$(restart_needed && echo true || echo false)"
}
+30 -16
View File
@@ -26,6 +26,10 @@ CEC_DKMS_VER=1
CEC_DKMS_SRC="/usr/src/$CEC_DKMS_NAME-$CEC_DKMS_VER"
CEC_DRIVER_URL="https://raw.githubusercontent.com/evlaV/linux-integration/10c8c8800ccd3ae359203b4eefb6479f613b3b8e/drivers/media/cec/platform/cros-ec/cros-ec-cec.c"
CEC_DRIVER_SHA256=e89fd4e87fceb32d713ffc59b64794779b3c2b3c012b0e2f2e9f0c40b42f4373
# Downloaded once, then kept: raw.githubusercontent.com rate-limits (HTTP 429) repeated downloads
# from one address, and turning CEC off and on again needs no network then. Named after its
# checksum, so a new pin (a new commit and checksum above) downloads its file once by itself.
CEC_DRIVER_CACHE="/var/cache/steamify/cros-ec-cec-${CEC_DRIVER_SHA256:0:12}.c"
cec_link_steamos_manager() {
# On a Steam Machine: steamos-manager writes cecd's config from Steam's
@@ -34,11 +38,11 @@ cec_link_steamos_manager() {
# called by Steam Machine support, which installs steamos-manager after
# this item ran.
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
systemctl --user daemon-reload
systemctl --user enable steamos-manager-configure-cecd.service 2>/dev/null
systemctl --user start steamos-manager-configure-cecd.service 2>/dev/null
systemctl --user restart cecd.service 2>/dev/null
systemctl --user restart steamos-manager.service 2>/dev/null
user_systemctl daemon-reload
user_systemctl enable steamos-manager-configure-cecd.service 2>/dev/null
user_systemctl start steamos-manager-configure-cecd.service 2>/dev/null
user_systemctl restart cecd.service 2>/dev/null
user_systemctl restart steamos-manager.service 2>/dev/null
return 0
}
@@ -51,10 +55,10 @@ cec_status() { cec_installed && [[ -f "$CEC_STEAM_DROPIN" ]] && cec_driver_ok; }
cec_reload_driver() {
# cecd keeps /dev/cec0 open, so the old module can't be unloaded under it.
systemctl --user stop cecd.service 2>/dev/null
user_systemctl stop cecd.service 2>/dev/null
sudo modprobe -r cros_ec_cec 2>/dev/null
sudo modprobe cros_ec_cec 2>/dev/null
systemctl --user start cecd.service 2>/dev/null
user_systemctl start cecd.service 2>/dev/null
}
cec_driver_enable() {
@@ -65,13 +69,20 @@ cec_driver_enable() {
fi
install_kernel_headers || return 1
tmp="$(mktemp -d)"
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"
else
info "Downloading Valve's Steam Machine CEC driver..."
if ! curl -fsL "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
rm -rf "$tmp"
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
return 1
fi
# 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
sudo install -Dm644 "$tmp/cros-ec-cec.c" "$CEC_DRIVER_CACHE"
fi
# So it finds amdgpu's HDMI port (see the patch for why).
patch_file cros-ec-cec-single-port.patch | patch -s -d "$tmp" -p1 ||
{ rm -rf "$tmp"; err "Patching Valve's CEC driver failed."; return 1; }
@@ -154,10 +165,13 @@ cec_enable() {
sudo tee "$CEC_STEAM_ENV" >/dev/null
printf '%s\n' "# Written by Steamify: overrides STEAM_ENABLE_CEC=0 from the gaming mode script." \
'[Service]' "EnvironmentFile=-$CEC_STEAM_ENV" | sudo tee "$CEC_STEAM_DROPIN" >/dev/null
systemctl --user daemon-reload
user_systemctl daemon-reload
# The TV remote's volume keys: SteamOS enables this socket through its
# preset, which pacman doesn't apply, so nothing else does on CachyOS.
user_systemctl enable --now cec-audio-control.socket 2>/dev/null
cec_link_steamos_manager
if compgen -G "/dev/cec*" >/dev/null; then
systemctl --user restart cecd.service 2>/dev/null
user_systemctl restart cecd.service 2>/dev/null
ok "HDMI-CEC on ($(cd /dev && echo cec*)); Steam shows its settings from the next gaming mode start."
info "Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
else
@@ -168,20 +182,20 @@ cec_enable() {
cec_disable() {
info "Removing HDMI-CEC..."
systemctl --user disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
systemctl --user disable steamos-manager-configure-cecd.service 2>/dev/null
user_systemctl disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
user_systemctl disable steamos-manager-configure-cecd.service 2>/dev/null
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
cec_driver_disable
sudo rm -f "$CEC_ORDER_DROPIN" "$CEC_STEAM_DROPIN" "$CEC_STEAM_ENV"
sudo rmdir "$(dirname "$CEC_ORDER_DROPIN")" "$(dirname "$CEC_STEAM_DROPIN")" "$(dirname "$CEC_STEAM_ENV")" 2>/dev/null
systemctl --user daemon-reload
user_systemctl daemon-reload
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
state_clear cec
fi
sudo udevadm control --reload
systemctl --user is-active -q steamos-manager.service 2>/dev/null &&
systemctl --user restart steamos-manager.service
user_systemctl is-active -q steamos-manager.service 2>/dev/null &&
user_systemctl restart steamos-manager.service
ok "HDMI-CEC removed."
}
@@ -189,5 +203,5 @@ cec_overview() {
# For the menu's kernel overview.
local dev="none"
compgen -G "/dev/cec*" >/dev/null && dev="$(cd /dev && echo cec*)"
echo "CEC devices: $dev cecd: $(systemctl --user is-active cecd 2>/dev/null)"
echo "CEC devices: $dev cecd: $(user_systemctl is-active cecd 2>/dev/null)"
}
+24
View File
@@ -44,6 +44,30 @@ require_root_helper() {
fi
}
user_session() {
# A running user systemd and session bus. Not in the installer's chroot,
# where the ISO applies Steamify for a user who has never logged in.
[[ -S "${XDG_RUNTIME_DIR:-/nonexistent}/bus" ]]
}
user_systemctl() {
# systemctl --user, also without a session: then only the unit files
# change (enable/disable through --root); starting and stopping is left
# to the first login, which starts what's enabled anyway.
if user_session; then systemctl --user "$@"; return; fi
local a verb="" args=()
for a in "$@"; do
[[ "$a" == --now ]] && continue
[[ -z "$verb" && "$a" != -* ]] && verb="$a"
args+=("$a")
done
case "$verb" in
enable|disable|is-enabled|mask|unmask) systemctl --user --root=/ "${args[@]}" ;;
is-active) return 1 ;;
*) return 0 ;;
esac
}
plasma_applets() {
# Print "containment:applet" for every applet of plugin $1 in the
# user's Plasma layout, for kwriteconfig6 --group paths.
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# The ISO applies Steamify in the installer, before the user ever logged
# in (steamify.sh --defaults without a session). What needs Plasma's first
# layout is finished at the first desktop login, by a one-time autostart
# that then opens the app, next to CachyOS Hello.
# Sourced by steamify.sh; not meant to be run on its own.
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
first_login_schedule() {
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
#!/bin/bash
# Installed by Steamify CachyOS: runs once, at the first desktop login.
set -o pipefail
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
EOF2
printf '%s\n' '[Desktop Entry]' 'Type=Application' 'Name=Steamify first login' \
"Exec=$FIRST_LOGIN_SCRIPT" 'OnlyShowIn=KDE;' 'X-KDE-autostart-phase=2' 'NoDisplay=true' |
install_executable "$FIRST_LOGIN_ENTRY" 644
}
first_login_run() {
# plasmashell has just laid out the desktop from the look-and-feel
# package; wait for its config, then put single user's launcher
# settings on the new launcher.
local _
for _ in $(seq 30); do
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
sleep 2
done
if single_status; then
stop_plasmashell_for_edit
single_launcher
restart_plasmashell_if_stopped
fi
return 0
}
+77
View File
@@ -18,6 +18,78 @@ gaming_status() {
esac
}
# What Steam shows in its System settings besides the OS name (which stays
# CachyOS's, for legal clarity and because limine-snapper-sync finds the boot
# entries by it): the SteamOS release as the OS version, steam-machine as the
# codename, Steamify with its version as the variant (os-release VERSION_ID,
# VERSION_CODENAME, VARIANT_ID; see patches/steamify-os-release.sh).
OS_NAME_SCRIPT=/usr/local/libexec/steamify-os-release
OS_NAME_HOOK=/etc/pacman.d/hooks/zz-steamify-os-release.hook
# limine's tools take the OS name from TARGET_OS_NAME, else os-release's
# PRETTY_NAME: pinned to CachyOS, the boot entries never depend on os-release.
LIMINE_DEFAULTS=/etc/default/limine
steamos_release() {
# The SteamOS release Steamify follows: Valve's newest jupiter-X.Y repo
# (where the SteamOS extras come from), as an os-release ID (no spaces or
# capitals: steamos-3.9). Offline (e.g. in the installer): the one set
# before, if any.
local v
v="$(curl -fsL --max-time 15 "$VALVE_MIRROR/" 2>/dev/null | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}"
else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi
}
os_name_enable() {
# 2.9.0 pre-releases renamed the OS itself; the name stays CachyOS's.
if grep -q '^DISTRIB_DESCRIPTION=.*with Steamify' /etc/lsb-release 2>/dev/null &&
[[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then
sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release
fi
[[ -n "$(kreadconfig6 --file kcm-about-distrorc --group General --key Name 2>/dev/null)" ]] &&
kset gaming kcm-about-distrorc General Name --delete
# About this System: os-release's VERSION (CachyOS has none) instead of
# VERSION_ID, which is the SteamOS release now.
kset gaming kcm-about-distrorc General UseOSReleaseVersion true
patch_file steamify-os-release.sh | fill VERSION="$VERSION" STEAMOS="$(steamos_release)" |
sudo install -Dm755 /dev/stdin "$OS_NAME_SCRIPT" &&
patch_file steamify-os-release.hook | fill SCRIPT="$OS_NAME_SCRIPT" |
sudo install -Dm644 /dev/stdin "$OS_NAME_HOOK" &&
sudo "$OS_NAME_SCRIPT" || { err "Setting Steamify's version for Steam failed."; return 1; }
if [[ -f "$LIMINE_DEFAULTS" ]] && ! grep -q '^TARGET_OS_NAME=' "$LIMINE_DEFAULTS"; then
backup_file "$LIMINE_DEFAULTS"
printf '%s\n' 'TARGET_OS_NAME="CachyOS"' | sudo tee -a "$LIMINE_DEFAULTS" > /dev/null
state_set gaming limine_target 1
fi
return 0
}
os_name_disable() {
sudo rm -f "$OS_NAME_HOOK" "$OS_NAME_SCRIPT"
[[ -f /etc/os-release ]] && sudo sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release
# CachyOS's own values back, the way its hooks write them.
if [[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then
sudo /usr/share/libalpm/scripts/cachyos-branding os-release
# Undoes 2.9.0 pre-releases, which changed lsb-release's name too.
sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release
fi
if [[ -n "$(state_get gaming limine_target)" ]]; then
sudo sed -i '/^TARGET_OS_NAME="CachyOS"$/d' "$LIMINE_DEFAULTS"
state_set gaming limine_target ""
fi
return 0
}
os_version_refresh() {
# After every run that changed something (sudo is at hand then): Steam's
# OS version follows Steamify's, not just the one that set it up. Silent:
# the app reads the backend's stdout as JSON.
gaming_status 2>/dev/null || return 0
grep -qx "VARIANT_ID=steamify-$VERSION" /etc/os-release 2>/dev/null && return 0
os_name_enable > /dev/null 2>&1
return 0
}
gaming_enable() {
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
# menu. Re-running with the other value switches over cleanly.
@@ -37,6 +109,8 @@ gaming_enable() {
esac
create_desktop_shortcut
steam_enable
nvidia_enable || return 1
os_name_enable || return 1
}
gaming_disable() {
@@ -49,6 +123,9 @@ gaming_disable() {
switch_to_plasmalogin
remove_desktop_shortcut
steam_disable
krevert gaming
os_name_disable
nvidia_disable
ok "The PC boots to the normal login screen again (from the next boot)."
}
+85 -2
View File
@@ -25,8 +25,8 @@ NO_PRESELECT=(boot cec kpin hdmi)
# FEATURE_BASELINE.
FEATURE_BASELINE=2.1.0
declare -A FEATURE_VERSION=(
[gaming]=2.1.0 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
[launcher]=2.1.0 [cec]=2.1.0 [machine]=2.2.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1
[gaming]=2.9.7 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1
[kpin]=2.1.0 [hdmi]=2.1.0
)
@@ -179,6 +179,88 @@ detect_components() {
fi
}
defaults_options() {
# defaults_options [--options <id>[,<id>...]] [--boot gamescope|desktop]:
# what --defaults sets up, from the Steam Machine ISO's installer page.
# --options: exactly these items on, every other off (without it, the
# menu's preselection). An item that's on brings its parent (single user
# the conversion, like ticking it in the menu); one this PC can't use is
# left off with a warning. --boot desktop needs the conversion. Returns 1
# on an unknown option, item or value.
local c ids list=false boot=""
while [[ $# -gt 0 ]]; do
# Both take a value: without one, shift 2 fails and never shifts, so
# the loop would spin forever.
[[ "$1" == --options || "$1" == --boot ]] && [[ $# -lt 2 ]] && { err "$1 needs a value"; return 1; }
case "$1" in
--options)
list=true
IFS=, read -ra ids <<< "$2"
shift 2 ;;
--boot)
case "$2" in
gamescope|desktop) boot="$2" ;;
*) err "--boot takes gamescope or desktop"; return 1 ;;
esac
shift 2 ;;
*) err "Unknown option: $1"; return 1 ;;
esac
done
if [[ "$list" == true ]]; then
for c in "${ids[@]}"; do
[[ -n "$c" ]] || continue
[[ -n "${LABEL[$c]:-}" ]] || { err "Unknown item: $c"; return 1; }
[[ "$c" == boot ]] && { err "Where to start is --boot, not an item."; return 1; }
is_action "$c" && { err "$c can't be part of the install."; return 1; }
done
for c in "${COMPONENTS[@]}"; do WANTED[$c]=0; done
for c in "${ids[@]}"; do
[[ -n "$c" ]] || continue
if component_available "$c" && component_selectable "$c"; then
WANTED[$c]=1
else
warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC."
fi
done
[[ "${WANTED[single]}" == 1 ]] && WANTED[gaming]=1
for c in "${COMPONENTS[@]}"; do
[[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1
done
fi
case "$boot" in
desktop)
[[ "${WANTED[gaming]}" == 1 ]] || { err "--boot desktop needs the SteamOS conversion (gaming)."; return 1; }
WANTED[boot]=1 ;;
gamescope) WANTED[boot]=0 ;;
esac
return 0
}
defaults_list() {
# --defaults --list: what --defaults can set up on this PC, as one JSON
# array, for an installer page (the Steam Machine ISO builds its Steamify
# page from it, so new items show up without a new ISO). Per item: id,
# label, hint, kind (toggle, or choice for boot: on = desktop), parent,
# on (preselected like a first run) and selectable. Actions, retired
# items and items this PC can't use (e.g. no Steam account yet) are
# left out. Read-only: no sudo, no state.
local c kind on sel items=""
for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue
is_action "$c" && continue
[[ "$c" == kpin || "$c" == hdmi ]] && continue
kind=toggle; [[ "$c" == boot ]] && kind=choice
sel=false; component_selectable "$c" && sel=true
on=false
[[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true
[[ "$c" == cec ]] && machine_available && on=true
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"on\":$on,\"selectable\":$sel}"
done
printf '[%s]\n' "$items"
}
toggle_component() {
local c="$1"
component_selectable "$c" || return 1
@@ -383,5 +465,6 @@ apply_changes() {
if "${c}_enable"; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
done
feature_record_unticked
os_version_refresh
FAILED=("${failed[@]}")
}
+165
View File
@@ -0,0 +1,165 @@
#!/bin/bash
# NVIDIA fix for gaming mode, part of the SteamOS conversion
# (gaming_enable/gaming_disable). gamescope drives the display itself
# through DRM/KMS; with NVIDIA that needs kernel modesetting and the
# framebuffer driver (nvidia-drm.modeset=1 nvidia-drm.fbdev=1) and the
# driver in the initramfs, or the screen shows a corrupted image.
# Does nothing without a supported NVIDIA GPU (RTX 20 series or newer) that has
# its driver installed.
# Sourced by steamify.sh; not meant to be run on its own.
NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1"
NVIDIA_INITRAMFS_CONF=/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf
# The script and pacman hook that keep the initramfs file right at every kernel change.
NVIDIA_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs}
NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook}
# The DRM devices in sysfs; the tests point this at a fake tree.
NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm}
nvidia_present() {
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
# driver installed, and not older than the RTX 20 series, decided like the
# VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every
# other card runs NVIDIA's open modules). Older cards are left alone.
local d
for d in "$NVIDIA_DRM_DIR"/card[0-9]*/device; do
[[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de ]] || continue
[[ "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue
vram_nvidia_legacy_id "$(cat "$d/device" 2>/dev/null)" && continue
modinfo nvidia_drm >/dev/null 2>&1 && return 0
done
return 1
}
nvidia_legacy_gpu() {
# 0 when the only NVIDIA GPU(s) are older than RTX 20 (reported, not fixed).
local d found=0
for d in "$NVIDIA_DRM_DIR"/card[0-9]*/device; do
[[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de && "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue
vram_nvidia_legacy_id "$(cat "$d/device" 2>/dev/null)" || return 1
found=1
done
[[ $found == 1 ]]
}
nvidia_boot_file() {
# Same boot loaders as the kernel command line elsewhere (lib/hdmi-refresh.sh).
hdmi_boot_file
}
nvidia_param_set() {
# 0 when $1 (e.g. nvidia-drm.modeset=1) is on the kernel command line or
# already in the boot loader's file (not booted yet).
local f; f="$(nvidia_boot_file)"
grep -qw -- "$1" /proc/cmdline 2>/dev/null ||
{ [[ -n "$f" ]] && grep -qw -- "$1" "$f" 2>/dev/null; }
}
nvidia_params_missing() {
local p
for p in $NVIDIA_PARAMS; do nvidia_param_set "$p" || return 0; done
return 1
}
nvidia_initramfs_ok() {
[[ -f "$NVIDIA_INITRAMFS_CONF" ]] || grep -qE '^MODULES=.*nvidia_drm' /etc/mkinitcpio.conf 2>/dev/null
}
nvidia_modules_everywhere() {
# 0 when every installed kernel has the nvidia_drm module (the script's own check).
patch_file steamify-nvidia-initramfs.sh | NVIDIA_MODULES_DIR="${NVIDIA_MODULES_DIR:-/usr/lib/modules}" bash -s check
}
nvidia_hook_install() {
# Never installs an empty script or hook (a piped patch_file that failed
# still lets install succeed with no input).
local script hook
script="$(patch_file steamify-nvidia-initramfs.sh)" && [[ -n "$script" ]] &&
hook="$(patch_file steamify-nvidia-initramfs.hook | fill SCRIPT="$NVIDIA_SCRIPT")" && [[ -n "$hook" ]] || return 1
printf '%s\n' "$script" | sudo install -Dm755 /dev/stdin "$NVIDIA_SCRIPT" &&
printf '%s\n' "$hook" | sudo install -Dm644 /dev/stdin "$NVIDIA_HOOK"
}
nvidia_rebuild_boot() {
local f; f="$(nvidia_boot_file)"
info "Rebuilding the initramfs and boot entries..."
case "$f" in
/etc/default/limine) sudo limine-mkinitcpio ;;
/etc/sdboot-manage.conf) sudo /usr/bin/mkinitcpio -P && sudo sdboot-manage gen ;;
/etc/default/grub) sudo /usr/bin/mkinitcpio -P && sudo grub-mkconfig -o /boot/grub/grub.cfg ;;
*) sudo /usr/bin/mkinitcpio -P ;;
esac
}
nvidia_boot_has_params() {
# 0 when the generated boot entries carry the parameters (or can't be
# checked): limine.conf, systemd-boot's entries, grub.cfg.
local target
case "$1" in
*/limine) target="${NVIDIA_LIMINE_CONF:-/boot/limine.conf}" ;;
*/sdboot-manage.conf) target="${NVIDIA_SDBOOT_DIR:-/boot/loader/entries}" ;;
*/grub) target="${NVIDIA_GRUB_CFG:-/boot/grub/grub.cfg}" ;;
*) return 0 ;;
esac
sudo test -e "$target" || return 0
sudo grep -rqs 'nvidia-drm.modeset=1' "$target"
}
nvidia_enable() {
nvidia_present || return 0
local f changed=0 p; f="$(nvidia_boot_file)"
if nvidia_params_missing; then
if [[ -z "$f" ]]; then
warn "NVIDIA GPU found, but no supported boot loader: add '$NVIDIA_PARAMS' to the kernel command line yourself."
else
info "NVIDIA GPU found: adding $NVIDIA_PARAMS to the kernel command line (fixes a corrupted screen in gaming mode)..."
backup_file "$f"
case "$f" in
*/limine)
sudo sed -i -E "s/^(KERNEL_CMDLINE\[default\]=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/sdboot-manage.conf)
sudo sed -i -E "s/^(LINUX_OPTIONS=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/grub)
sudo sed -i -E "s/^(GRUB_CMDLINE_LINUX_DEFAULT=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
esac
if ! grep -q "nvidia-drm.fbdev=1" "$f"; then
err "Couldn't add the NVIDIA parameters to $f (no kernel command line setting in it): add '$NVIDIA_PARAMS' yourself."
return 1
fi
changed=1
fi
fi
nvidia_hook_install || { err "Installing the NVIDIA initramfs hook failed."; return 1; }
local had=0; [[ -f "$NVIDIA_INITRAMFS_CONF" ]] && had=1
sudo env NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="${NVIDIA_MODULES_DIR:-/usr/lib/modules}" "$NVIDIA_SCRIPT" sync
if [[ -f "$NVIDIA_INITRAMFS_CONF" && $had == 0 ]]; then
info "Loading the NVIDIA modules early (initramfs)..."
changed=1
elif [[ ! -f "$NVIDIA_INITRAMFS_CONF" && $had == 1 ]]; then
warn "A kernel without the NVIDIA modules is installed: not loading them early any more (rebuilding the initramfs without them)."
changed=1
elif [[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && ! nvidia_initramfs_ok; then
warn "Not every installed kernel has the NVIDIA modules: not loading them early for now (the kernel parameters still apply; this is checked again at every kernel update)."
fi
if [[ $changed == 1 ]]; then
nvidia_rebuild_boot || { err "Rebuilding the boot entries failed."; return 1; }
if ! nvidia_boot_has_params "$f"; then
err "The boot entries don't have the NVIDIA parameters: the initramfs or boot entry build failed (see above)."
return 1
fi
ok "NVIDIA gaming mode fix applied; it takes effect after a reboot."
fi
return 0
}
nvidia_disable() {
local f changed=0; f="$(nvidia_boot_file)"
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
sudo sed -i "s/ \?$NVIDIA_PARAMS//" "$f"
changed=1
fi
[[ -f "$NVIDIA_INITRAMFS_CONF" ]] && { sudo rm -f "$NVIDIA_INITRAMFS_CONF"; changed=1; }
sudo rm -f "$NVIDIA_HOOK" "$NVIDIA_SCRIPT"
[[ $changed == 1 ]] && nvidia_rebuild_boot
return 0
}
+18
View File
@@ -101,6 +101,24 @@ single_launcher() {
done
}
single_launcher_drop() {
# The theme's layout backup is taken when it's turned on: with single
# user on then, it holds single's launcher keys, and restoring it after
# single was turned off brings them back. Drop exactly single's values
# (a launcher set up differently by the user is left alone).
local applet
local -a kick_args
for applet in $(plasma_applets org.kde.plasma.kickoff); do
kick_args=(--file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}"
--group Applets --group "${applet#*:}" --group Configuration --group General)
[[ "$(kreadconfig6 "${kick_args[@]}" --key primaryActions)" == 3 ]] &&
kwriteconfig6 "${kick_args[@]}" --key primaryActions --delete
[[ "$(kreadconfig6 "${kick_args[@]}" --key systemFavorites)" == 'suspend,reboot,shutdown' ]] &&
kwriteconfig6 "${kick_args[@]}" --key systemFavorites --delete
done
return 0
}
single_enable() {
info "Turning off the lock screen, user switching and logging out..."
stop_plasmashell_for_edit
+1 -1
View File
@@ -123,7 +123,7 @@ migrate_layout() {
"$(wizard_desktop_dir)/$WIZARD_DESKTOP_NAME"; do
[[ -f "$f" ]] && sed -i "s|$old_bin/|$STEAMIFY_BIN/|g" "$f"
done
systemctl --user daemon-reload 2>/dev/null
user_systemctl daemon-reload 2>/dev/null
fi
if [[ -f "$old_icon" ]]; then
if [[ -e "$WIZARD_ICON" ]]; then rm -f "$old_icon"; else mv "$old_icon" "$WIZARD_ICON"; fi
+4 -4
View File
@@ -22,18 +22,18 @@ steam_enable() {
rm -f "$HOME/.config/autostart/steam.desktop"
# Reload user systemd context and activate the background loop
systemctl --user daemon-reload
systemctl --user enable --now steam-desktop-autostart.service
user_systemctl daemon-reload
user_systemctl enable --now steam-desktop-autostart.service
ok "Steam UI parameters and keyboard autostart deployed successfully."
}
steam_disable() {
info "Removing Steam desktop autostart..."
systemctl --user disable --now steam-desktop-autostart.service 2>/dev/null
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \
"$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
systemctl --user daemon-reload
user_systemctl daemon-reload
ok "Steam desktop settings removed (takes full effect at next login)."
}
+2 -2
View File
@@ -72,8 +72,8 @@ steamgame_edit() {
fi
"$1"; local rc=$?
if [[ "$was_running" == true ]]; then
if systemctl --user is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
systemctl --user start steam-desktop-autostart.service
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
user_systemctl start steam-desktop-autostart.service
else
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
fi
+46 -2
View File
@@ -378,6 +378,46 @@ machine_status() {
pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 && pacman -Qi steamos-manager >/dev/null 2>&1
}
# Steam (steamwebhelper) reads the serial number for its System settings
# straight from DMI, which the kernel makes root-only; SteamOS makes it
# readable. A tmpfiles rule does that at every boot.
SERIAL_TMPFILES=/etc/tmpfiles.d/steamify-serial.conf
# Steam's Wi-Fi backend switch goes through steamos-manager, which reads and
# writes the backend in this file (SteamOS ships it); without it, it fails
# with "Wi-Fi backend not found in config". wpa_supplicant is what
# NetworkManager uses on CachyOS anyway. Not written when someone set a
# backend themselves.
WIFI_BACKEND_CONF=/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf
wifi_backend_enable() {
[[ -f "$WIFI_BACKEND_CONF" ]] && return 0
grep -rqs '^wifi.backend=' /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/conf.d && return 0
printf '%s\n' "# Written by Steamify: Steam's Wi-Fi backend setting (steamos-manager)." \
'[device]' 'wifi.backend=wpa_supplicant' | sudo install -Dm644 /dev/stdin "$WIFI_BACKEND_CONF" ||
{ err "Writing the Wi-Fi backend setting failed."; return 1; }
state_set machine wifi_backend 1
}
wifi_backend_disable() {
[[ -n "$(state_get machine wifi_backend)" ]] || return 0
sudo rm -f "$WIFI_BACKEND_CONF"
state_clear machine
}
serial_enable() {
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null &&
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
{ err "Making the serial number readable for Steam failed."; return 1; }
}
serial_disable() {
sudo rm -f "$SERIAL_TMPFILES"
sudo chmod 0400 /sys/class/dmi/id/product_serial 2>/dev/null
return 0
}
machine_enable() {
# The pinned kernel first when it's wanted too, so DKMS builds the LED
# driver for it once, instead of for the current kernel and then again.
@@ -403,9 +443,11 @@ EOF
# for hardware and controller settings; it knows the Steam Machine from its DMI data.
info "Installing hardware manager packages (steamos-manager & inputplumber)..."
sudo pacman -S --needed --noconfirm steamos-manager inputplumber || { err "Installing hardware manager packages failed."; return 1; }
serial_enable || return 1
wifi_backend_enable || return 1
sudo systemctl enable --now inputplumber.service
sudo systemctl enable --now steamos-manager.service
systemctl --user enable steamos-manager.service 2>/dev/null
user_systemctl enable steamos-manager.service 2>/dev/null
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
cec_status && cec_link_steamos_manager
@@ -422,10 +464,12 @@ EOF
machine_disable() {
info "Removing Steam Machine support..."
systemctl --user disable --now steamos-manager.service 2>/dev/null
user_systemctl disable --now steamos-manager.service 2>/dev/null
sudo systemctl disable --now steamos-manager.service 2>/dev/null
sudo systemctl disable --now inputplumber.service 2>/dev/null
sudo pacman -Rns --noconfirm steamos-manager inputplumber 2>/dev/null
serial_disable
wifi_backend_disable
sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf
sudo udevadm control --reload
sudo modprobe -r leds-valve 2>/dev/null
+7 -7
View File
@@ -12,8 +12,8 @@ NOTIFY_NAME=steamify-update-check
notify_status() {
[[ -f "$NOTIFY_SCRIPT" ]] &&
systemctl --user is-enabled -q "$NOTIFY_NAME.timer" 2>/dev/null &&
systemctl --user is-enabled -q "$NOTIFY_NAME.service" 2>/dev/null
user_systemctl is-enabled -q "$NOTIFY_NAME.timer" 2>/dev/null &&
user_systemctl is-enabled -q "$NOTIFY_NAME.service" 2>/dev/null
}
notify_seen() {
@@ -40,19 +40,19 @@ notify_enable() {
mkdir -p "$NOTIFY_UNITS"
service_file "$NOTIFY_NAME.service" NOTIFY_SCRIPT="$NOTIFY_SCRIPT" > "$NOTIFY_UNITS/$NOTIFY_NAME.service"
service_file "$NOTIFY_NAME.timer" > "$NOTIFY_UNITS/$NOTIFY_NAME.timer"
systemctl --user daemon-reload
systemctl --user enable "$NOTIFY_NAME.service" >/dev/null 2>&1 &&
systemctl --user enable --now "$NOTIFY_NAME.timer" >/dev/null 2>&1 ||
user_systemctl daemon-reload
user_systemctl enable "$NOTIFY_NAME.service" >/dev/null 2>&1 &&
user_systemctl enable --now "$NOTIFY_NAME.timer" >/dev/null 2>&1 ||
{ err "Enabling the update check failed."; return 1; }
state_set notify seen "$VERSION"
ok "Update notifications on: you'll get a notification when there's a new Steamify."
}
notify_disable() {
systemctl --user disable --now "$NOTIFY_NAME.timer" "$NOTIFY_NAME.service" >/dev/null 2>&1
user_systemctl disable --now "$NOTIFY_NAME.timer" "$NOTIFY_NAME.service" >/dev/null 2>&1
rm -f "$NOTIFY_UNITS/$NOTIFY_NAME.service" "$NOTIFY_UNITS/$NOTIFY_NAME.timer" "$NOTIFY_SCRIPT"
rmdir "$STEAMIFY_BIN" 2>/dev/null || true
systemctl --user daemon-reload
user_systemctl daemon-reload
state_clear notify
ok "Update notifications off."
}
+19 -1
View File
@@ -54,10 +54,18 @@ theme_enable() {
# Only remove it again on disable if we were the ones installing it.
state_set theme installed_pkg 1
fi
# 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
# removed (after the backup below), and Plasma builds its first layout
# from the look-and-feel package, as --resetLayout does below.
local offline=false 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
err "Run this from the Plasma desktop: applying the Vapor layout needs a running Plasma session."
return 1
fi
offline=true
fi
# Only the first time, so a re-apply doesn't overwrite the originals.
local backup="$STATE_DIR/theme-layout" f
@@ -87,6 +95,12 @@ theme_enable() {
kset theme kdeglobals General ColorScheme --delete
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
if [[ "$offline" == true ]]; then
rm -f ~/.config/plasma-org.kde.plasma.desktop-appletsrc ~/.config/plasmashellrc
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
ok "Vapor theme set; Plasma lays out the Vapor desktop at the first login."
return 0
fi
info "Applying the Vapor theme with its desktop and window layout..."
# --resetLayout is "Desktop and window layout" in System Settings: the
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
@@ -120,7 +134,11 @@ theme_disable() {
fi
# After the tools above, so keys that weren't set before are removed again.
krevert theme
single_status && single_launcher
if single_status; then
single_launcher
else
single_launcher_drop
fi
restart_plasmashell_if_stopped
qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true
+12 -6
View File
@@ -44,6 +44,13 @@ vram_nvidia() {
# 470xx, 390xx); every other NVIDIA card runs the open kernel modules.
VRAM_CHWD_IDS=/var/lib/chwd/ids
vram_nvidia_legacy_id() {
# vram_nvidia_legacy_id <pci device id, with or without 0x>: 0 when chwd
# lists the card for a closed legacy branch, i.e. it is older than the
# RTX 20 series. Also what lib/nvidia.sh uses to decide if a card is supported.
grep -qwi "${1#0x}" "$VRAM_CHWD_IDS"/nvidia-*.ids 2>/dev/null
}
vram_nvidia_case() {
# Why an NVIDIA card's VRAM isn't registered, so the menu can say what to
# do: "update" (open modules older than 615), "switch <chwd profile>"
@@ -62,8 +69,7 @@ vram_nvidia_case() {
esac
for d in /sys/bus/pci/devices/*; do
[[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de && "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue
id="$(cat "$d/device")"; id="${id#0x}"
grep -qwi "$id" "$VRAM_CHWD_IDS"/nvidia-*.ids 2>/dev/null && { echo legacy; return; }
vram_nvidia_legacy_id "$(cat "$d/device")" && { echo legacy; return; }
done
for p in 580xx 470xx 390xx; do
pacman -Q "nvidia-$p-dkms" >/dev/null 2>&1 && { echo "switch nvidia-dkms-$p"; return; }
@@ -101,7 +107,7 @@ vram_selectable() { vram_supported || vram_status; }
vram_status() {
pacman -Q "${VRAM_PKGS[@]}" >/dev/null 2>&1 &&
systemctl is-enabled -q dmemcg-booster-system.service 2>/dev/null &&
systemctl --user is-enabled -q dmemcg-booster-user.service 2>/dev/null
user_systemctl is-enabled -q dmemcg-booster-user.service 2>/dev/null
}
vram_enable() {
@@ -115,18 +121,18 @@ vram_enable() {
fi
sudo systemctl enable --now dmemcg-booster-system.service >/dev/null 2>&1 ||
{ err "Starting dmemcg-booster failed."; return 1; }
systemctl --user enable --now dmemcg-booster-user.service >/dev/null 2>&1 ||
user_systemctl enable --now dmemcg-booster-user.service >/dev/null 2>&1 ||
{ err "Starting dmemcg-booster for $USER failed."; return 1; }
kset vram kcgroupsrc "Foreground Booster" autostart true
# Started by the Plasma session from now on; start it in this one too.
[[ "${XDG_CURRENT_DESKTOP:-}" == KDE ]] &&
systemctl --user start plasma-foreground-booster.service >/dev/null 2>&1
user_systemctl start plasma-foreground-booster.service >/dev/null 2>&1
ok "VRAM booster on: the game in front keeps its VRAM."
}
vram_disable() {
local pkgs
systemctl --user disable --now plasma-foreground-booster.service dmemcg-booster-user.service >/dev/null 2>&1
user_systemctl disable --now plasma-foreground-booster.service dmemcg-booster-user.service >/dev/null 2>&1
sudo systemctl disable --now dmemcg-booster-system.service >/dev/null 2>&1
krevert vram
pkgs="$(state_get vram installed_pkgs)"
+2
View File
@@ -13,4 +13,6 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
| `steamify-fremont-poweroff.dkms.conf`, `steamify-cros-ec-cec.dkms.conf` | `lib/fremont-poweroff.sh`, `lib/cec.sh` | The DKMS modules' `dkms.conf` (`fill NAME=... VERSION=...`) |
| `steam-shortcuts.py` | `lib/steam-game.sh` (Add as non-Steam game) | Reads and writes Steam's binary `shortcuts.vdf` (find, add or update, remove) |
| `steamify-notifier.py` | `lib/update-notifier.sh` (Update notifications) | The daily check: notification and tray icon when there's a new release |
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
| `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 |
+17
View File
@@ -0,0 +1,17 @@
# Installed by Steamify CachyOS (SteamOS conversion, NVIDIA fix): decides
# again whether the NVIDIA modules go into the initramfs, after DKMS has built
# its modules (71-dkms-install) and before the initramfs is built
# (90-mkinitcpio-install); hooks run in file name order.
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/modules/*/extramodules/nvidia*
Target = usr/lib/modules/*/updates/*
[Action]
Description = Steamify: NVIDIA modules in the initramfs only if every kernel has them
When = PostTransaction
Exec = @SCRIPT@ sync
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
# Installed by Steamify CachyOS (SteamOS conversion, NVIDIA fix), run by the
# pacman hook steamify-nvidia-initramfs.hook before the initramfs is built.
# The NVIDIA modules go into the initramfs (early KMS) only while EVERY
# installed kernel has them: mkinitcpio fails on a module a kernel lacks, and
# limine-mkinitcpio then skips that kernel's boot entry, kernel parameters
# included. Decided again at every kernel or driver change, so a new kernel
# without the modules (another kernel, a failed DKMS build, a downgrade) gets
# a working initramfs and the file comes back once it has them.
# steamify-nvidia-initramfs [sync|check]
# sync (default) write or remove the drop-in to match
# check exit status 0 when every installed kernel has nvidia_drm
conf="${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf}"
mods="${NVIDIA_MODULES_DIR:-/usr/lib/modules}"
everywhere() {
local k found=0
for k in "$mods"/*/; do
[[ -f "$k/vmlinuz" || -f "$k/pkgbase" ]] || continue # an installed kernel, not a leftover folder
find "$k" -name 'nvidia-drm.ko*' -print -quit 2>/dev/null | grep -q . || return 1
found=1
done
[[ $found == 1 ]]
}
case "${1:-sync}" in
check) everywhere ;;
sync)
if everywhere; then
[[ -f "$conf" ]] || { mkdir -p "$(dirname "$conf")" &&
echo 'MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)' > "$conf"; }
else
rm -f "$conf"
fi ;;
*) echo "usage: $0 [sync|check]" >&2; exit 2 ;;
esac
+14
View File
@@ -0,0 +1,14 @@
# Installed by Steamify CachyOS (SteamOS conversion): runs after
# cachyos-hooks' os-release/cachyos-branding hooks (hooks run in file name
# order).
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = filesystem
Target = cachyos-hooks
[Action]
Description = Steamify: the OS variant and version Steam shows
When = PostTransaction
Exec = @SCRIPT@
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
# Installed by Steamify CachyOS (SteamOS conversion): what Steam shows in its
# System settings besides the OS name, which stays CachyOS's: the SteamOS
# release Steamify follows as the OS version (VERSION_ID, e.g. steamos-3.9),
# steam-machine as the codename, and Steamify with its version as the variant
# (VARIANT_ID, which Steam shows). KDE's About this System would show
# VERSION_ID after the name: the conversion sets its UseOSReleaseVersion, so it
# shows os-release's VERSION instead, which CachyOS doesn't have. NAME and
# PRETTY_NAME are never touched: limine-snapper-sync finds the boot entries by
# the OS name. The zz-steamify-os-release hook runs this after cachyos-hooks.
sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release
printf '%s\n' 'VARIANT="Steamify @VERSION@"' 'VARIANT_ID=steamify-@VERSION@' 'VERSION_CODENAME=steam-machine' >> /etc/os-release
[ -n "@STEAMOS@" ] && echo 'VERSION_ID=@STEAMOS@' >> /etc/os-release
exit 0
+65 -3
View File
@@ -15,11 +15,11 @@
set -uo pipefail
# Release version, see CHANGELOG.md.
VERSION=2.5.2
VERSION=2.9.7
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 cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier menu backend; do
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia 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
source "$SCRIPT_DIR/lib/$lib.sh"
done
@@ -28,8 +28,21 @@ require_root_helper
BACKEND=false
[[ "${1:-}" == --backend ]] && BACKEND=true
# --defaults [--options <id>,...] [--boot gamescope|desktop]: apply what the
# menu would preselect (or exactly the listed items), without the menu or any
# prompt (the Steam Machine ISO's first login runs this; sudo must not ask).
DEFAULTS=false
[[ "${1:-}" == --defaults ]] && DEFAULTS=true
# --defaults --list: what --defaults can set up here, as JSON (an installer
# page is built from it); nothing else on stdout.
LIST=false
[[ "$DEFAULTS" == true && "${2:-}" == --list ]] && LIST=true
# --boot gamescope|desktop: only change where an installed conversion
# starts, everything else stays as it is (for scripts; no menu).
BOOT_ONLY=false
[[ "${1:-}" == --boot ]] && BOOT_ONLY=true
if [[ "$BACKEND" == false ]]; then
if [[ "$BACKEND" == false && "$LIST" == false ]]; then
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
echo "anything you turn off is put back the way it was."
@@ -114,6 +127,55 @@ if [[ "$BACKEND" == true ]]; then
exit $?
fi
if [[ "${1:-}" == --first-login ]]; then
first_login_run
exit 0
fi
if [[ "$LIST" == true ]]; then
defaults_list
exit 0
fi
if [[ "$DEFAULTS" == true ]]; then
RESTART_FOR_LOGIN=false
REAPPLY=false
sudo -n true 2>/dev/null || { err "--defaults needs sudo without a password."; exit 1; }
detect_components
defaults_options "${@:2}" || exit 1
plan_changes
apply_changes
# Run by the installer: the rest waits for the first desktop login.
user_session || first_login_schedule
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
ok "Done; the changes take effect after a restart."
exit 0
fi
if [[ "$BOOT_ONLY" == true ]]; then
RESTART_FOR_LOGIN=false
REAPPLY=false
case "${2:-}" in
gamescope|desktop) ;;
*) err "--boot takes gamescope or desktop"; exit 1 ;;
esac
detect_components
[[ "${CURRENT[gaming]}" == 1 ]] || { err "--boot needs the SteamOS conversion; turn it on first."; exit 1; }
# What is on stays on, and nothing else changes: not the updates or
# removals a normal run would pick.
for c in "${COMPONENTS[@]}"; do WANTED[$c]=${CURRENT[$c]:-0}; done
WANTED[boot]=0; [[ "$2" == desktop ]] && WANTED[boot]=1
plan_changes
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
ok "Already starting in $2."
exit 0
fi
apply_changes
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
ok "Starts in $2 from the next boot on."
exit 0
fi
# Menu loop: after each run the menu comes back with the new state, until
# the user quits; the restart question comes then, once, for everything.
RESTART_FOR_LOGIN=false
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
# one: tests/nvidia-test.sh). Run from the Steamify checkout:
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
# Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help.
cd "$(dirname "$0")/.." || exit 1
REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}"
source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
mode="${1:-check}"
fail=0
say() { echo "$*" | tee -a "$REPORT"; }
pass() { say "PASS $*"; }
bad() { say "FAIL $*"; fail=1; }
note() { say " $*"; }
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
report_system() {
say "-- GPU and software"
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
done
note "boot loader file: $(nvidia_boot_file || true)"
note "cmdline: $(cat /proc/cmdline)"
}
check_state() {
say "-- Steamify's view"
if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected"
elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied"
else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi
for c in /sys/class/drm/card[0-9]*/device; do
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')"
done
ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported"
local p
for p in $NVIDIA_PARAMS; do
if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line"
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
done
say "-- the live NVIDIA driver"
local m
for m in modeset fbdev; do
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
done
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
local c found=0
for c in /sys/class/drm/card[0-9]*/device; do
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
done
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
say "-- initramfs"
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
say "-- what apply would change"
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
}
case "$mode" in
check)
report_system; check_state ;;
apply)
report_system
say "-- applying"
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
else bad "nvidia_enable failed (output above)"; fi
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
visual)
report_system
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
say "visual result: $a: $what"
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
say "-- gamescope and NVIDIA lines from this boot's log"
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
note "(more in $REPORT)" ;;
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
esac
say ""; say "Report: $REPORT"
exit $fail
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
# Tests lib/nvidia.sh against a fake RTX 5080 (PCI 10de:2c02) beside an
# Intel iGPU, a stub modinfo, and temp copies of the boot loader files. No
# root, VM or NVIDIA hardware needed: bash tests/nvidia-test.sh
cd "$(dirname "$0")/.." || exit 1
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
fail=0
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
SCRIPT_DIR="$PWD"; source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
sudo() { "$@"; }
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
echo 0x2c02 > "$T/drm/card1/device/device"
NVIDIA_DRM_DIR="$T/drm"
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
NVIDIA_MODULES_DIR="$T/mods"
NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked
mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd"
FAKE_DRIVER=1; check "finds the NVIDIA card as card1 beside an iGPU (no legacy lists)" nvidia_present
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
check "RTX 5080 (2c02) is not on a legacy list: supported" nvidia_present
echo 0x1c03 > "$T/drm/card1/device/device"
check "GTX 1060 (on chwd's legacy list, older than RTX 20): not supported" '! nvidia_present'
check "...and reported as a legacy GPU" nvidia_legacy_gpu
echo 0x2c02 > "$T/drm/card1/device/device"; check "RTX 5080 is not a legacy GPU" '! nvidia_legacy_gpu'
printf '2c02\n' > "$T/chwd/nvidia-580.ids"; check "a card id that is on a legacy list is skipped, whatever it is" '! nvidia_present'
printf '1c03\n' > "$T/chwd/nvidia-580.ids"
FAKE_DRIVER=0; check "skips when the driver isn't installed" '! nvidia_present'
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "skips without an NVIDIA GPU" '! nvidia_present'
NVIDIA_DRM_DIR="$T/drm"
for loader in limine sdboot grub; do
case $loader in
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
esac
nvidia_boot_file() { echo "$F"; }
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
nvidia_enable
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
SUM="$(cat "$F")"; nvidia_enable
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
nvidia_disable
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
done
# A missing patches/ file must be an error, never an empty script or hook.
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
# The pacman hook's script decides again at every kernel change.
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
rm -rf "$T/mods/5.0.0-leftover"; nvidia_disable
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_enable
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
rm -rf "$T/mods/6.6.0-lts"
# Generated boot entries without the parameters (the initramfs build failed): an error.
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
check "boot entries without the parameters: error" '! nvidia_enable >/dev/null'
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
# A config file without the setting to edit: an error, not "applied".
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
check "no setting to edit: error, nothing rebuilt" '! nvidia_enable >/dev/null && [[ $REBUILDS == 0 ]]'
FAKE_DRIVER=0; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_enable
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
exit $fail
+8 -2
View File
@@ -35,9 +35,15 @@ Item {
border.width: step.st === "wait" || step.st === "run" ? 2 : 0; border.color: step.st === "run" ? Theme.accent : "#343f50"
Text { anchors.centerIn: parent; text: step.st === "ok" ? "✓" : (step.st === "fail" ? "!" : ""); color: step.st === "ok" ? Theme.good : Theme.bad
font.pixelSize: 13; font.weight: Font.Bold }
RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } }
// Only this dot turns while the step runs: ✓ and ! never rotate
// (an animator leaves its item at whatever angle it stopped).
Item { anchors.fill: parent; visible: step.st === "run"
Rectangle { width: 6; height: 6; radius: 3; color: Theme.accent; x: parent.width / 2 - 3; y: -3 }
RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } } }
Row { width: 380; anchors.verticalCenter: parent.verticalCenter; spacing: 10
Text { text: (Texts.actions[step.modelData.action] || [])[3] + Texts.label(step.modelData.id)
// Boot into's label is its prefix already: "Boot into desktop", not "Boot into Boot into".
Text { text: step.modelData.id === "boot" ? (Texts.actions[step.modelData.action] || [])[3] + Texts.actions[step.modelData.action][0].toLowerCase()
: (Texts.actions[step.modelData.action] || [])[3] + Texts.label(step.modelData.id)
color: step.st === "wait" ? Theme.faint : Theme.textHi; font.family: Theme.body; font.pixelSize: 16; font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter; elide: Text.ElideRight
width: Math.min(implicitWidth, parent.width - (badge.visible ? badge.width + parent.spacing : 0)) }
+4 -4
View File
@@ -1,12 +1,12 @@
#!/bin/bash
# Steamify CachyOS - get and start the app (v2), for `curl | bash`:
# Steamify CachyOS - get and start the app, for `curl | bash`:
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
# Downloads the newest release's app package (steamify-app.tar.gz: the app,
# steamify.sh, lib/, patches/ and services/) to ~/.local/share/steamify/app, installs PySide6 if
# it's missing, adds a launcher entry, and starts the app.
# STEAMIFY_RELEASE=<tag> takes that release instead of the newest (the
# v2-ui-preview build's copy of this script sets it). STEAMIFY_BRANCH=<branch>
# takes that branch's source instead (for testing before a build).
# STEAMIFY_RELEASE=<tag> takes that release instead of the newest.
# STEAMIFY_BRANCH=<branch> takes that branch's source instead (for testing
# before a build).
set -euo pipefail
REPO="theupriser/steamify-cachyos"