mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-13 20:35:40 +02:00
Compare commits
57
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d36fcee6b | ||
|
|
5fc815c356 | ||
|
|
452955ae68 | ||
|
|
27263411ba | ||
|
|
b112082704 | ||
|
|
89a66f3159 | ||
|
|
e738297c7f | ||
|
|
f1cdf313ad | ||
|
|
59e941e8e4 | ||
|
|
d4bb4c4d92 | ||
|
|
77715f9f73 | ||
|
|
9c15d14c4a | ||
|
|
4c614a2f38 | ||
|
|
43fa06eb3c | ||
|
|
2e64fde7d5 | ||
|
|
f234c727b1 | ||
|
|
124b424d3d | ||
|
|
06ffc8bc8b | ||
|
|
5b5181f33e | ||
|
|
03f9e87cf2 | ||
|
|
4325d80f09 | ||
|
|
f3cd053ea0 | ||
|
|
2811ecce1c | ||
|
|
515019770f | ||
|
|
0ba94b23d8 | ||
|
|
127b8cf88b | ||
|
|
4d60dd227d | ||
|
|
ce4bc67e8c | ||
|
|
cab1a9792f | ||
|
|
708df2f7d8 | ||
|
|
cef5c8d175 | ||
|
|
d70aeb8ac8 | ||
|
|
40d468cf83 | ||
|
|
2bd6e98ce0 | ||
|
|
93a26a0d16 | ||
|
|
f05078d932 | ||
|
|
4d387b2f86 | ||
|
|
19089a1eda | ||
|
|
2f7b53f64b | ||
|
|
bd8f387cf5 | ||
|
|
45a23aff34 | ||
|
|
f3810a9fdd | ||
|
|
188799e951 | ||
|
|
079e725ba8 | ||
|
|
7869b472be | ||
|
|
fbdad5a785 | ||
|
|
349492423e | ||
|
|
613149a807 | ||
|
|
2e51d1d3f3 | ||
|
|
e5110ada40 | ||
|
|
1074514b83 | ||
|
|
2c004322af | ||
|
|
3915e1a96f | ||
|
|
098dc3d0d8 | ||
|
|
48352b5601 | ||
|
|
05b8f11c19 | ||
|
|
8b96e2d8a9 |
No files matched your search
+2
-5
@@ -1,5 +1,2 @@
|
|||||||
This branch is not ready to be released: do not merge it into the release branch.
|
Not tested on hardware yet: the whole Steamify flow for the patched gamescope on NVIDIA (apply, reboot, session).
|
||||||
When the feature is complete and tested, ask the user whether it may be released;
|
Delete this file when it was, after asking the user (AGENTS.md).
|
||||||
on a yes, delete this file, then open the pull request into the release branch.
|
|
||||||
Open work, research and the test instructions for the NVIDIA PC are NOT in this repo:
|
|
||||||
see steamify-cachyos-dev, folder nvidia/ (github.com/theupriser/steamify-cachyos-dev).
|
|
||||||
@@ -48,11 +48,15 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
`<id>_available` is checked via `component_available` (e.g. `machine`
|
`<id>_available` is checked via `component_available` (e.g. `machine`
|
||||||
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
|
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
|
||||||
`gaming` must stay first. Dependencies live in `toggle_component`.
|
`gaming` must stay first. Dependencies live in `toggle_component`.
|
||||||
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
|
- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.12.0 the SteamOS conversion (`gaming` and its options) runs on
|
||||||
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
|
NVIDIA PCs with a patched gamescope (GBM scan-out: gamescope#2309; Steam's UI kept at the display's size), downloaded as the
|
||||||
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
|
newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO
|
||||||
hardware (notes: steamify-cachyos-dev, `nvidia/`). It can't be tested without the hardware: keep the branch behind
|
leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`,
|
||||||
`.no-release-yet` until it was.
|
`bigpicture`, `nvsilent`) isn't offered any more (`nvidia_available`); turning the conversion on turns it off (`nvidia_swap_out`).
|
||||||
|
Builds exist per CPU level (`gsn_cpu_variant`: znver4, v4, v3, generic; `GSN_SHA256` is a map; the installed one must pass `gsn_smoke_test`, else generic). A new pin = the release's tag + each variant's sha256 (from `SHA256SUMS`) in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the
|
||||||
|
repository (the patches in `patches/` must stay identical to that repository's). Steam must keep running with `-steamos3`
|
||||||
|
(without it games don't launch in gaming mode and the settings pages go): never "fix" the UI size by dropping flags or by
|
||||||
|
`XWAYLAND_COUNT`. Tested on an RTX 5080 only; keep the branch behind `.no-release-yet` until the whole flow ran on hardware.
|
||||||
- **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new
|
- **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new
|
||||||
`VERSION` whenever what `<id>_enable` sets up changes (a new component gets
|
`VERSION` whenever what `<id>_enable` sets up changes (a new component gets
|
||||||
one too): installs recorded with an older version
|
one too): installs recorded with an older version
|
||||||
@@ -156,9 +160,8 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
a warning when `VERSION` is a version that's already released (so a
|
a warning when `VERSION` is a version that's already released (so a
|
||||||
release branch that forgot its bump shows it on every PR).
|
release branch that forgot its bump shows it on every PR).
|
||||||
- A release that adds, removes or renames a menu row also retakes the
|
- A release that adds, removes or renames a menu row also retakes the
|
||||||
README screenshots (`assets/screenshot-menu-steam-machine.png` and
|
README screenshot (`assets/screenshot-menu-steam-machine.png`; NVIDIA PCs get the same menu, so there is no separate
|
||||||
`assets/screenshot-menu-nvidia.png`, side by side in the README): the app from the branch on a Steam Machine and on a PC
|
one): the app from the branch on a Steam Machine, every row visible and the window only as tall as its options need, the header showing the new
|
||||||
with an NVIDIA card, every row visible and each window only as tall as its options need, the header showing the new
|
|
||||||
`VERSION`, 1600 px wide. Size the window with a KWin script (match the `steamify-ui` class exactly: a title match also hits
|
`VERSION`, 1600 px wide. Size the window with a KWin script (match the `steamify-ui` class exactly: a title match also hits
|
||||||
Konsole and editor windows) and crop the full-screen capture to the client rectangle; mind the display scale (the Steam
|
Konsole and editor windows) and crop the full-screen capture to the client rectangle; mind the display scale (the Steam
|
||||||
Machine runs at 1.75).
|
Machine runs at 1.75).
|
||||||
|
|||||||
+38
-21
@@ -5,30 +5,47 @@ All notable changes, per version and per commit. Versions follow
|
|||||||
`steamify.sh`. Versions before 0.7.0 were numbered afterwards,
|
`steamify.sh`. Versions before 0.7.0 were numbered afterwards,
|
||||||
one per merged pull request.
|
one per merged pull request.
|
||||||
|
|
||||||
|
## 2.12.0 - 2026-10-13
|
||||||
|
|
||||||
|
- **feat: setting up the SteamOS conversion on NVIDIA first checks that nothing blocks it (a pacman lock, less than 1.5 GB free), and a failed setup is remembered: a desktop notification now and a reminder in the menu until a setup works**
|
||||||
|
- **docs: the README and TECHNICAL.md describe NVIDIA as it is now (the SteamOS conversion with the patched gamescope; "Gaming on NVIDIA" only as history); the NVIDIA menu screenshot is gone, NVIDIA PCs get the same menu**
|
||||||
|
- **feat: the patched gamescope comes in one build per CPU level, like CachyOS's repositories (generic, x86-64-v3, v4, znver4): Steamify picks the best one this CPU can run (`gsn_cpu_variant`), falls back to generic, and starts the installed gamescope once headless (`gsn_smoke_test`): a build that doesn't start is replaced by the generic one. CI compiles each with an explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checks the binary for instructions beyond its level.**
|
||||||
|
- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-3` of steamify-gamescope-nvidia, now the pin; built once per CPU level, see below) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts**
|
||||||
|
|
||||||
|
- **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again**
|
||||||
|
|
||||||
|
- **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)**
|
||||||
|
|
||||||
|
- **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it**
|
||||||
|
|
||||||
|
- **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container**
|
||||||
|
|
||||||
|
- `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256**
|
||||||
|
|
||||||
|
- `127b8cf`, `2811ecc`, `f3cd053`, `4325d80`, `03f9e87`, `5b5181f`, `06ffc8b`, `4d60dd2`, `0ba94b2` **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet**
|
||||||
|
|
||||||
|
- `ce4bc67` **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet**
|
||||||
|
|
||||||
|
## 2.11.1 - 2026-10-02
|
||||||
|
|
||||||
|
- `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion**
|
||||||
|
## 2.11.0 - 2026-10-01
|
||||||
|
|
||||||
|
- `2e51d1d`, `3494924`, `fbdad5a`, `079e725`, `188799e` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it**
|
||||||
|
- `2f7b53f` **fix: the Steam Machine's serial number step no longer fails inside the ISO's installer (`/sys` is read-only in its chroot; the tmpfiles.d file applies at the next boot anyway), which made `machine` report an error and the install log end with `exit: 1`**
|
||||||
|
- `45a23af`, `bd8f387` **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)**
|
||||||
|
- `f3810a9` **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login**
|
||||||
|
- `7869b47` **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode**
|
||||||
|
- `4d387b2` **chore: the Steamify unit tests (`controllers-test.sh`, `nvidia-test.sh`) and the NVIDIA hardware test live in steamify-cachyos-dev (`tests/`) now; `tests/` is removed here**
|
||||||
|
|
||||||
## 2.10.0 - 2026-10-01
|
## 2.10.0 - 2026-10-01
|
||||||
|
|
||||||
- **docs: changelog hashes for 2.10.0**
|
- `d6db4f6` **feat: "Gaming on NVIDIA" (nvidia) replaces the SteamOS conversion on PCs with an NVIDIA GPU, where gamescope's gaming mode shows a corrupted picture (NVIDIA bug 5240452): Steam is installed when missing and starts at login on the Plasma desktop; the sub-option "Steam starts in Big Picture" (bigpicture) starts it in Big Picture, unticked in its normal window, on an empty Plasma session so windows of the last session don't cover it. On a supported card (RTX 20 series or newer) it also sets the NVIDIA kernel parameters and early modules. The conversion and its options are hidden there unless already on**
|
||||||
|
- `d1373e2` **feat: single user mode also works on NVIDIA PCs, without the SteamOS conversion**
|
||||||
|
- `5811f5c` **fix: "Add as non-Steam game" isn't offered on NVIDIA PCs (shown when already on, so it can be turned off)**
|
||||||
|
- `83248a8` **feat: Extended controller support (extended_controller_support, off by default): the Xbox wireless dongle (xone) and Xbox controllers over Bluetooth with rumble and battery level (xpadneo), built for every installed kernel; off removes only what Steamify installed**
|
||||||
|
- `01a77b7` **feat: a new opt-in option (unticked by default) shows the "new" badge in the menu and the app**
|
||||||
- `f1983a9` **docs: README screenshots of the 2.10.0 app, side by side: on a Steam Machine and on a PC with an NVIDIA card**
|
- `f1983a9` **docs: README screenshots of the 2.10.0 app, side by side: on a Steam Machine and on a PC with an NVIDIA card**
|
||||||
- `01a77b7` **feat: a new opt-in option (unticked by default, e.g. Extended controller support) shows the "new" badge in the menu and the app without being ticked for you (feature_new_optin); it counts "Gaming on NVIDIA" as its parent where the conversion isn't offered**
|
|
||||||
- `83248a8` **feat: Extended controller support (extended_controller_support, off by default): the Xbox wireless dongle (xone-dkms, xone-dongle-firmware) and Xbox controllers over Bluetooth with rumble, button mapping and battery level (xpadneo-dkms), from the CachyOS repo, built for every installed kernel; a PC with the AUR's xone-dkms-git keeps it; off removes only what Steamify installed (lib/controllers.sh, tests/controllers-test.sh)**
|
|
||||||
- `5811f5c` **fix: "Add as non-Steam game" isn't offered on NVIDIA PCs (there is no gaming mode there for it to give the controller; shown when already on, so it can be turned off)**
|
|
||||||
- `d0e4d8c` **feat: Big Picture on NVIDIA starts on an empty Plasma session (ksmserverrc loginMode=emptySession, undone when it is turned off), so windows of the last session don't cover it**
|
|
||||||
- `d1373e2` **feat: single user mode also works on NVIDIA PCs, without the SteamOS conversion: it switches to SDDM and logs in to the Plasma session by itself (zzz-steamify-autologin.conf), and no longer ticks the conversion where that isn't offered**
|
|
||||||
- `d6db4f6` **feat: "Gaming on NVIDIA" (nvidia) replaces the SteamOS conversion on PCs with an NVIDIA GPU, where gamescope's gaming mode shows a corrupted picture (NVIDIA bug 5240452): Steam is installed when missing and starts at login on the Plasma desktop; the sub-option "Steam starts in Big Picture" (bigpicture, ticked along with it) starts it in Big Picture, unticked in its normal window. On a supported card (RTX 20 series or newer) it also sets the NVIDIA kernel parameters and early modules of the commits below. The conversion and its options are hidden there unless already on (lib/nvidia.sh, services/steamify-steam-autostart.service, tests/nvidia-test.sh)**
|
|
||||||
- `a5e9015` **fix: the NVIDIA kernel part handles Limine's `+=` command line and the underscore spelling nvidia_drm.modeset=1; the hardware test sets SCRIPT_DIR**
|
|
||||||
- `ae238ff` **chore: .no-release-yet: this NVIDIA branch is not ready to be released**
|
|
||||||
- `c1217bc` **feat: NVIDIA fix only for RTX 20 series or newer, with the VRAM booster's chwd legacy check (vram_nvidia_legacy_id)**
|
|
||||||
- `f3d67fb` **fix: never install an empty NVIDIA hook or script (a failed patch_file piped into install succeeded with no input)**
|
|
||||||
- `84cf095` **feat: NVIDIA modules in the initramfs only while every kernel has them, decided again by a pacman hook at every kernel change**
|
|
||||||
- `7caefb7` **test: nvidia-hardware-test.sh to check, apply and visually verify the NVIDIA fix on a real PC**
|
|
||||||
- `453656a` **fix: NVIDIA fix checks the edit and the generated boot entries for every boot loader (limine.conf, systemd-boot entries, grub.cfg)**
|
|
||||||
- `6aa1377` **fix: NVIDIA fix on Limine edits the existing cmdline line; early modules only when every kernel has them**
|
|
||||||
- `6bcae8a` **test: NVIDIA fix against a fake RTX 5080, stub modinfo and temp boot loader files**
|
|
||||||
- `3cbeb58` **docs: AGENTS.md: never work on main or a release branch, hardware-specific fixes, git identity**
|
|
||||||
- `83561bb` **feat: NVIDIA fix for gaming mode (kernel parameters and early modules)**
|
|
||||||
- `ca027cb` **chore: Version 2.9.7**
|
|
||||||
- `3d20a7e` **chore: Version 2.10.0**
|
|
||||||
- `71bb2e7` **chore: Version 2.10.0**
|
|
||||||
|
|
||||||
## 2.9.6 - 2026-09-30
|
## 2.9.6 - 2026-09-30
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
# Steamify CachyOS
|
# Steamify CachyOS
|
||||||
|
|
||||||
The Steamify app's menu. On a Steam Machine (or any PC with an AMD or Intel
|
The Steamify app's menu, on a Steam Machine. On a PC with an NVIDIA graphics card (GTX 16 / RTX 20 series or
|
||||||
graphics card) it offers the full SteamOS conversion, on the left. On a PC with
|
newer) the same SteamOS conversion is offered; Steamify installs a patched gamescope for it.
|
||||||
an NVIDIA graphics card gamescope's gaming mode shows a corrupted picture, so the
|
|
||||||
menu offers **Gaming on NVIDIA** instead (Steam on the desktop, started at login,
|
|
||||||
optionally in Big Picture), on the right.
|
|
||||||
|
|
||||||
| On a Steam Machine | On a PC with an NVIDIA graphics card |
|

|
||||||
|---|---|
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
|
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
|
||||||
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
|
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
|
||||||
@@ -27,20 +22,28 @@ Steam Machine.
|
|||||||
on the desktop too.
|
on the desktop too.
|
||||||
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
||||||
the default.
|
the default.
|
||||||
|
- **Start Steam silently in desktop mode** (off by default) - Steam starts
|
||||||
|
at login on the desktop, in the tray without a window. It is Steam's own
|
||||||
|
autostart entry, so Steam's setting "Run Steam when my computer starts"
|
||||||
|
follows it (the Linux Steam client has no silent option of its own).
|
||||||
- Steam's **System** settings show the SteamOS release Steamify follows
|
- Steam's **System** settings show the SteamOS release Steamify follows
|
||||||
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
||||||
Steamify's version as OS Variant. The OS name stays CachyOS
|
Steamify's version as OS Variant. The OS name stays CachyOS
|
||||||
([details](TECHNICAL.md#what-steams-system-settings-show)).
|
([details](TECHNICAL.md#what-steams-system-settings-show)).
|
||||||
- **NVIDIA graphics cards:** gamescope's gaming mode shows a corrupted
|
- **NVIDIA graphics cards** (GTX 16 / RTX 20 series or newer): stock gamescope shows a corrupted
|
||||||
picture there (an open NVIDIA driver bug), so the conversion isn't
|
picture on them (an open NVIDIA driver bug), so on an NVIDIA PC Steamify installs a **patched gamescope**
|
||||||
offered. **Gaming on NVIDIA** takes its place: Steam on the desktop,
|
(GBM scan-out, from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia))
|
||||||
installed if it's missing and started at login, in **Big Picture** or its
|
and sets up the rest: the gaming session starts on the monitor's own resolution and refresh rate, with
|
||||||
normal window as you choose
|
Steam's interface at that size. It is the same conversion as everywhere else, with one extra step.
|
||||||
([details](TECHNICAL.md#gaming-on-nvidia)).
|
The newest patched build for your CPU is downloaded from GitHub (checked, with a built-in fallback if GitHub
|
||||||
|
can't be reached), and a newer one shows up as an **Update** in the menu. Tested on an RTX 5080 only
|
||||||
|
([details](TECHNICAL.md#nvidia-graphics-cards)).
|
||||||
|
The old **Gaming on NVIDIA** option (Steam on the desktop) is gone: a PC that had it on is moved to the
|
||||||
|
conversion, and keeps starting Steam in Big Picture if that was on.
|
||||||
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
||||||
**Add to Steam** in right-click menus
|
**Add to Steam** in right-click menus
|
||||||
([details](TECHNICAL.md#steamos-desktop-look)).
|
([details](TECHNICAL.md#steamos-desktop-look)).
|
||||||
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode.
|
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode (an option of the SteamOS conversion).
|
||||||
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
||||||
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
||||||
controller is no fun
|
controller is no fun
|
||||||
@@ -51,7 +54,7 @@ Steam Machine.
|
|||||||
With **Add as non-Steam game** (on by default) it's in your Steam library
|
With **Add as non-Steam game** (on by default) it's in your Steam library
|
||||||
too: started from Steam it gets your controller (a Steam Controller only
|
too: started from Steam it gets your controller (a Steam Controller only
|
||||||
talks to Steam), in gaming mode as well. Steam closes for a moment while
|
talks to Steam), in gaming mode as well. Steam closes for a moment while
|
||||||
it's added, so that's done from the desktop. Not offered on PCs with an NVIDIA graphics card, which have no gaming mode.
|
it's added, so that's done from the desktop. Not offered on PCs with an NVIDIA graphics card yet (not tested there).
|
||||||
6. **Update notifications** - on by default: a notification and a tray icon
|
6. **Update notifications** - on by default: a notification and a tray icon
|
||||||
when there's a new Steamify, with Open Steamify and Skip this version. It
|
when there's a new Steamify, with Open Steamify and Skip this version. It
|
||||||
never updates anything by itself
|
never updates anything by itself
|
||||||
@@ -183,6 +186,18 @@ Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md).
|
|||||||
|
|
||||||
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
||||||
|
|
||||||
|
### Code from other projects
|
||||||
|
|
||||||
|
Some files in `patches/` are not MIT. They keep their own license, and each file says where it comes from:
|
||||||
|
|
||||||
|
| File | What | License and source |
|
||||||
|
|---|---|---|
|
||||||
|
| `steamify-fremont-poweroff.c` | Kernel module for the Steam Machine's power-off fix. It does what Valve's Steam Machine kernel does for this (clears the S4 wake bit of GPIO pin 18 at probe), but at power-off, for kernels without Valve's change. Valve's kernel: [evlaV/linux-integration](https://github.com/evlaV/linux-integration). | GPL-2.0, like the Linux kernel it is built into |
|
||||||
|
| `cros-ec-cec.c` | Valve's Steam Machine HDMI-CEC driver (ChromeOS EC CEC, Copyright BayLibre; Valve's version of it), at a pinned commit of [evlaV/linux-integration](https://github.com/evlaV/linux-integration). Used when it can't be downloaded. | GPL-2.0+, unmodified (Steamify's `cros-ec-cec-single-port.patch` is applied when it is built) |
|
||||||
|
| `gamescope-gbm-scanout.patch` | GBM scan-out for gamescope on NVIDIA: nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) on [ValveSoftware/gamescope](https://github.com/ValveSoftware/gamescope). | gamescope's license (BSD-2-Clause) |
|
||||||
|
| `gamescope-ui-native.patch` | Keeps Steam's interface at the display's size in gamescope on NVIDIA (a small patch after the one above). | gamescope's license (BSD-2-Clause) |
|
||||||
|
| `gamescope-nvidia.PKGBUILD` | The recipe for the patched gamescope package, used only when it can't be downloaded. | MIT, like Steamify |
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Steamify CachyOS is an unofficial community project. It is not affiliated
|
Steamify CachyOS is an unofficial community project. It is not affiliated
|
||||||
|
|||||||
+88
-23
@@ -43,7 +43,7 @@ user wallet, with anything saved in it meanwhile, is kept as
|
|||||||
`kdewallet.kwl.steamify-single-user` and used again the next time it's on.
|
`kdewallet.kwl.steamify-single-user` and used again the next time it's on.
|
||||||
Passwords aren't shared between the two wallets.
|
Passwords aren't shared between the two wallets.
|
||||||
|
|
||||||
**Without the conversion (NVIDIA PCs, where gamescope's session is broken)** nothing else logs in by itself, so single user mode
|
**Without the conversion** (any PC with it off; on NVIDIA that is before 2.12.0 or after turning it off) nothing else logs in by itself, so single user mode
|
||||||
does that too: `single_login_enable` (`lib/single-user.sh`) switches to SDDM and writes
|
does that too: `single_login_enable` (`lib/single-user.sh`) switches to SDDM and writes
|
||||||
`/etc/sddm.conf.d/zzz-steamify-autologin.conf` (`User=`, `Session=plasma.desktop`, `Relogin=true`; named to sort after
|
`/etc/sddm.conf.d/zzz-steamify-autologin.conf` (`User=`, `Session=plasma.desktop`, `Relogin=true`; named to sort after
|
||||||
`steam-set-session`'s `zz-steamos-autologin.conf`, which may still say gamescope from an earlier conversion), and drops any
|
`steam-set-session`'s `zz-steamos-autologin.conf`, which may still say gamescope from an earlier conversion), and drops any
|
||||||
@@ -108,9 +108,11 @@ tools write to the conf.d fragment into the base config.
|
|||||||
(never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
|
(never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
|
||||||
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
||||||
`sync-steamos-session.path`/`.service`;
|
`sync-steamos-session.path`/`.service`;
|
||||||
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a
|
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
|
||||||
`steam-desktop-autostart` systemd user service that starts Steam silently
|
("Start Steam silently in desktop mode", opt-in, always shown) writes
|
||||||
in Plasma only;
|
`~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the
|
||||||
|
file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older
|
||||||
|
`steam-desktop-autostart` user unit is removed;
|
||||||
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
||||||
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
||||||
restart the login manager without a password prompt.
|
restart the login manager without a password prompt.
|
||||||
@@ -124,7 +126,8 @@ The conversion also sets what Steam's System settings show, see
|
|||||||
|
|
||||||
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
||||||
in `~/.config/environment.d/` (and gamescope-session's own environment
|
in `~/.config/environment.d/` (and gamescope-session's own environment
|
||||||
file), which makes Steam show Steam Deck button glyphs in gaming mode.
|
file), which makes Steam show Steam Deck button glyphs in gaming mode. It is a sub-option of the SteamOS conversion (`gaming`):
|
||||||
|
it does nothing without gaming mode, ticking it ticks the conversion and turning the conversion off turns it off.
|
||||||
|
|
||||||
## SteamOS desktop look
|
## SteamOS desktop look
|
||||||
|
|
||||||
@@ -224,25 +227,84 @@ DKMS modules, built for every installed kernel, so `install_kernel_headers` (`li
|
|||||||
headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
|
headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
|
||||||
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
||||||
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
||||||
plugged in again, or the controller reconnected. `tests/controllers-test.sh` tests it with a stub `pacman`.
|
plugged in again, or the controller reconnected. Its test is in steamify-cachyos-dev (`tests/controllers-test.sh`).
|
||||||
|
|
||||||
## Gaming on NVIDIA
|
## NVIDIA graphics cards
|
||||||
|
|
||||||
gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards: NVIDIA's open bug 5240452 (flicker and
|
**The problem.** gamescope's gaming mode shows a corrupted picture on NVIDIA graphics cards: NVIDIA's open bug 5240452 (flicker
|
||||||
artifacts in the DRM session at modes above 2560x1440@120, seen up to driver 595 and on RTX 3070 Ti, 4090, 5090 and 5080;
|
and artifacts in the DRM session at modes above 2560x1440@120, seen up to driver 595 and on RTX 3070 Ti, 4090, 5090 and 5080; also
|
||||||
no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loading the NVIDIA modules early don't change it
|
[gamescope#2309](https://github.com/ValveSoftware/gamescope/issues/2309)). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1`
|
||||||
(the driver already reports both `Y`), and gamescope started nested inside KDE artifacts too when KWin hands its fullscreen
|
and loading the NVIDIA modules early don't change it, and gamescope nested inside KDE artifacts too.
|
||||||
window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of
|
|
||||||
the Plasma desktop session, smooth and clean.
|
|
||||||
|
|
||||||
So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS
|
**The fix.** gamescope with GBM-allocated scan-out buffers, opt-in through the environment variable
|
||||||
conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned
|
`gamescope_drm_gbm_scanout=1`. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope)
|
||||||
off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start
|
(`nvidia-gbm-wayland`). A second small patch keeps Steam's UI server (Steam with `-steamos3` asks gamescope for 1920x1080) at the
|
||||||
Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
display's size. Both are built into one package, `steamify-gamescope-nvidia` (it provides and conflicts with `gamescope`), in
|
||||||
|
[theupriser/steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia): the patches, the PKGBUILD, and CI.
|
||||||
|
Tested on an RTX 5080 (driver 615.78.08, 3440x1440@175): clean picture, widescreen and sharp Steam UI, Proton games start.
|
||||||
|
Everything below is `lib/gamescope-nvidia.sh` unless named otherwise.
|
||||||
|
|
||||||
|
**What the SteamOS conversion does on an NVIDIA PC** (`gaming_enable` calls `gsn_enable`; `nvidia_present`: PCI vendor 0x10de,
|
||||||
|
display class, its driver providing `nvidia_drm`; `nvidia_supported`: GTX 16 / RTX 20 series or newer, Turing and later):
|
||||||
|
1. `gsn_preflight`: no pacman lock, at least 1.5 GB free on `/`. A failure stops before anything changes.
|
||||||
|
2. `nvidia_swap_out`: turns "Gaming on NVIDIA" off if it was on (see below).
|
||||||
|
3. On a supported card the kernel parameters, early modules, suspend memory and 32-bit libraries (`nvidia_kernel_enable`,
|
||||||
|
`nvidia_extras_enable`, `lib/nvidia.sh`, described below).
|
||||||
|
4. `gsn_install_package`: the patched gamescope (next paragraph).
|
||||||
|
5. `gsn_env_enable`: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and
|
||||||
|
`~/.config/environment.d/99-steamify-gamescope-nvidia.conf`.
|
||||||
|
6. `gsn_display_enable`: the display wrapper. `patches/gamescope-display-wrapper.sh` is installed as `gamescope` in Steamify's bin
|
||||||
|
folder and put first in the gaming session's PATH with a drop-in of `gamescope-session.service` (`steamify-display.conf`). It
|
||||||
|
starts gamescope on the mode KDE has saved for the connected display (`~/.config/kwinoutputconfig.json`, modes from
|
||||||
|
`modetest`), else the biggest mode at the highest refresh rate; with several displays connected it passes nothing and gamescope
|
||||||
|
chooses. `--print-args` shows what it would use.
|
||||||
|
7. `single_login_release` (`lib/single-user.sh`): single user mode's `zzz-steamify-autologin.conf` is read last and would pin the
|
||||||
|
Plasma session, so it goes (turning the conversion off sets it up again). `python_hid_shim_ensure` (`lib/packages.sh`): the
|
||||||
|
conversion's dependency jupiter-hw-support wants `python-hid`, which conflicts with `python-hidapi` (liquidctl needs it): an
|
||||||
|
empty package providing `python-hid` (`patches/python-hid-shim.PKGBUILD`) makes both work.
|
||||||
|
Turning the conversion off removes the setting, the wrapper and the kernel settings, and keeps the packages. When the setup
|
||||||
|
fails, `gsn_fail_mark` records it (state `gamescope_nvidia`, key `failed`) and sends a desktop notification; the menu reminds
|
||||||
|
(`gsn_fail_note`) until a setup works. A failed option's sub-options aren't applied.
|
||||||
|
|
||||||
|
**Getting the package, and keeping it current.** gamescope changes every few weeks, so the package is downloaded, not carried.
|
||||||
|
CI builds it in CachyOS's container, once per CPU level like CachyOS's repositories: generic, x86-64-v3, v4 and znver4, each with an
|
||||||
|
explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checked for instructions beyond its level and for both
|
||||||
|
patches. A release is `<gamescope version>-<package release>` (for example `3.16.31-3`) with `SHA256SUMS`. `gsn_cpu_variant`
|
||||||
|
picks the build for this CPU (the dynamic loader's x86-64 level; AMD with `avx512_bf16` is znver4) and generic is the fallback.
|
||||||
|
`gsn_fetch_package` tries, for the CPU's variant and then generic: the newest release on GitHub (if newer than the pin), the release
|
||||||
|
Steamify was tested with (`GSN_VERSION`, hashes in `GSN_SHA256`: from GitHub, the cache, or the copy the ISO leaves in
|
||||||
|
`/usr/local/share/steamify/gamescope`); only files with the expected sha256 count (newer releases: their `.sha256`). If nothing is
|
||||||
|
reachable, `gsn_build_package` builds from `patches/gamescope-nvidia.PKGBUILD` and the two patches (`makepkg` as the user in
|
||||||
|
`~/.cache/steamify`). `gsn_install_package` installs with `pacman -U --ask 4`; `gsn_smoke_test` then starts gamescope headless
|
||||||
|
and installs the generic build instead if it doesn't start. Nothing else changes before a package is installed. A newer release than
|
||||||
|
the installed package shows the conversion as an update (`gsn_update_pending`, looked up at most every six hours, quiet offline).
|
||||||
|
A new pin = the release's tag and each variant's sha256 in `GSN_VERSION` and `GSN_SHA256` plus the PKGBUILD's pkgver/pkgrel; the patches in `patches/` must
|
||||||
|
stay identical to that repository's. New gamescope versions: the repository's daily check bumps the version when the patch still
|
||||||
|
applies, or opens an issue when it needs a rebase; a person merges and tags the release.
|
||||||
|
|
||||||
|
**What the kernel side does** (`lib/nvidia.sh`; a supported card only): `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` on the kernel command
|
||||||
|
line (Limine, systemd-boot or GRUB; the file is backed up first; on Limine into the existing `KERNEL_CMDLINE[default]="..."` or
|
||||||
|
`+="..."` line, never an extra appended line, which ends up as text), and `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`
|
||||||
|
(`MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)`), then the initramfs and boot entries are rebuilt and checked. The
|
||||||
|
early-load drop-in is only there while every installed kernel has the NVIDIA modules (mkinitcpio fails on a missing module): a
|
||||||
|
pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`) runs `/usr/local/libexec/steamify-nvidia-initramfs` at every
|
||||||
|
kernel or driver change and decides again. `nvidia_extras_enable` adds `NVreg_PreserveVideoMemoryAllocations=1`
|
||||||
|
(`/etc/modprobe.d/90-steamify-nvidia.conf`), enables `nvidia-suspend`/`resume`/`hibernate` and installs `lib32-nvidia-utils` and
|
||||||
|
`lib32-libxkbcommon`. Takes effect at the next boot. The tests are in steamify-cachyos-dev: `tests/nvidia-test.sh` (a fake GPU, a
|
||||||
|
stub `pacman` and `systemctl`, a temp home) and `tests/nvidia-hardware-test.sh` (a real NVIDIA PC).
|
||||||
|
|
||||||
|
**Limits.** Tested on one PC (RTX 5080, Ryzen). The "Add as non-Steam game" option isn't offered on NVIDIA PCs yet. Steam must keep
|
||||||
|
running with `-steamos3` (the Display settings' "Maximum Game Resolution" exists only with it, and dropping it or setting
|
||||||
|
`XWAYLAND_COUNT=1` stopped games from launching). If upstream fixes the bug, the patched package and this section go, and Steamify
|
||||||
|
goes back to the stock gamescope.
|
||||||
|
|
||||||
|
**"Gaming on NVIDIA" (before 2.12.0).** With an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless
|
||||||
|
it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
||||||
unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
|
unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
|
||||||
`bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets
|
`bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets
|
||||||
`ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session
|
`ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session
|
||||||
(Discord, a browser) aren't restored on top of Big Picture; unticked, Steam starts in its normal window. The PC always boots into the desktop: there is no gamescope session. Takes effect at the next
|
(Discord, a browser) aren't restored on top of Big Picture; unticked, Steam starts in its normal window. The opt-in sub-option `nvsilent` ("Start Steam silently") rewrites the unit with `-silent`
|
||||||
|
(tray only); it and `bigpicture` exclude each other. The PC always boots into the desktop: there is no gamescope session. Takes effect at the next
|
||||||
login.
|
login.
|
||||||
|
|
||||||
On a supported card (RTX 20 series or newer: not on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids`, the VRAM booster's
|
On a supported card (RTX 20 series or newer: not on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids`, the VRAM booster's
|
||||||
@@ -255,7 +317,7 @@ and boot entries are rebuilt and checked for the parameters. The early-load drop
|
|||||||
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
||||||
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
|
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
|
||||||
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
|
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
|
||||||
all of it. `tests/nvidia-hardware-test.sh check|apply|visual` is for a real NVIDIA PC (writes `~/steamify-nvidia-report.txt`). `tests/nvidia-test.sh` tests it against a fake GPU, a stub `pacman` and `systemctl`, and a temp home.
|
all of it. The tests are in steamify-cachyos-dev: `tests/nvidia-test.sh` (a fake GPU, a stub `pacman` and `systemctl`, a temp home) and `tests/nvidia-hardware-test.sh` (a real NVIDIA PC).
|
||||||
|
|
||||||
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
|
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
|
||||||
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
||||||
@@ -343,8 +405,7 @@ desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X =
|
|||||||
Steam's keyboard), in gaming mode as a gamepad.
|
Steam's keyboard), in gaming mode as a gamepad.
|
||||||
|
|
||||||
Steam reads the list only at startup and writes it back on exit, so Steam is
|
Steam reads the list only at startup and writes it back on exit, so Steam is
|
||||||
closed (`steam -shutdown`) for the edit and started again (through
|
closed (`steam -shutdown`) for the edit and started again (`steam -silent`). That's refused in gaming
|
||||||
`steam-desktop-autostart.service` when it's there). That's refused in gaming
|
|
||||||
mode and when Steamify itself was started from Steam (`SteamGameId`), since
|
mode and when Steamify itself was started from Steam (`SteamGameId`), since
|
||||||
closing Steam would end it. An entry for the start script that's already
|
closing Steam would end it. An entry for the start script that's already
|
||||||
there (added by hand, or with the path from before 2.5.0) is updated, not
|
there (added by hand, or with the path from before 2.5.0) is updated, not
|
||||||
@@ -489,7 +550,8 @@ In the home folder, everything is under `steamify`:
|
|||||||
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
|
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
|
||||||
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
|
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
|
||||||
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
|
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
|
||||||
| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` |
|
| `~/.config/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") |
|
||||||
|
| `~/.config/systemd/user/` | `steamify-update-check.*` |
|
||||||
|
|
||||||
System-wide: `/usr/local/lib/steamify/` (kernel headers script),
|
System-wide: `/usr/local/lib/steamify/` (kernel headers script),
|
||||||
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
|
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
|
||||||
@@ -535,7 +597,9 @@ steamify.sh --defaults --list # what --defaults can se
|
|||||||
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
||||||
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
||||||
`bios` in the list: exit code 1 before anything changes. What needs a
|
`bios` in the list: exit code 1 before anything changes. What needs a
|
||||||
Plasma session waits for the first login (`lib/first-login.sh`).
|
Plasma session waits for the first login (`lib/first-login.sh`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover
|
||||||
|
(not installed on CachyOS: a blank icon), by CachyOS's own (`taskbar_drop_discover` in `lib/vapor-theme.sh`; skipped when Discover is
|
||||||
|
installed or the taskbar already has its own `launchers`).
|
||||||
|
|
||||||
With `Relogin=true`, a gamescope session that fails to start is restarted
|
With `Relogin=true`, a gamescope session that fails to start is restarted
|
||||||
immediately, which can turn into a loop - see
|
immediately, which can turn into a loop - see
|
||||||
@@ -566,6 +630,7 @@ immediately, which can turn into a loop - see
|
|||||||
| `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer |
|
| `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/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/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
|
| `lib/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
|
||||||
|
| `lib/gamescope-nvidia.sh` | gamescope on NVIDIA: builds and installs the patched gamescope (GBM scan-out) from steamify-gamescope-nvidia and sets `gamescope_drm_gbm_scanout=1` for the SteamOS conversion |
|
||||||
| `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) |
|
| `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) |
|
||||||
| `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) |
|
| `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 |
|
| `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README |
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 225 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 465 KiB After Width: | Height: | Size: 322 KiB |
+12
-2
@@ -50,6 +50,7 @@ backend_status() {
|
|||||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
||||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
||||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")"
|
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")"
|
||||||
|
items+=",\"needs\":\"\""
|
||||||
items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)"
|
items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)"
|
||||||
items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)"
|
items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)"
|
||||||
items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)"
|
items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)"
|
||||||
@@ -146,7 +147,6 @@ backend_apply() {
|
|||||||
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
|
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
|
||||||
done
|
done
|
||||||
# The same rules as the menu's toggles.
|
# The same rules as the menu's toggles.
|
||||||
# (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.)
|
|
||||||
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||||
if component_available gaming; then
|
if component_available gaming; then
|
||||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
|
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
|
||||||
@@ -154,7 +154,11 @@ backend_apply() {
|
|||||||
WANTED[boot]=0
|
WANTED[boot]=0
|
||||||
fi
|
fi
|
||||||
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1
|
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1
|
||||||
[[ "${WANTED[nvidia]:-0}" == 0 ]] && WANTED[bigpicture]=0
|
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
|
||||||
|
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
|
||||||
|
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; WANTED[nvsilent]=0; }
|
||||||
|
[[ "${WANTED[silent]:-0}" == 1 || "${WANTED[glyphs]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||||
|
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
|
||||||
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
|
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
|
||||||
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
|
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
|
||||||
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
|
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
|
||||||
@@ -181,6 +185,12 @@ backend_apply() {
|
|||||||
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
for c in "${TO_ENABLE[@]}"; do
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
|
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
||||||
|
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
||||||
|
backend_event log "\"id\":$(json_str "$c"),\"line\":$(json_str "Skipped: ${LABEL[${PARENT[$c]}]%%:*} didn't work.")"
|
||||||
|
failed+=("$c")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
feature_record_unticked
|
feature_record_unticked
|
||||||
|
|||||||
+9
-4
@@ -73,11 +73,16 @@ cec_driver_enable() {
|
|||||||
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
||||||
else
|
else
|
||||||
info "Downloading Valve's Steam Machine CEC driver..."
|
info "Downloading Valve's Steam Machine CEC driver..."
|
||||||
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
if ! curl -fsL --retry 2 --max-time 60 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||||
rm -rf "$tmp"
|
# GitHub is down, rate-limits us, or sent something else: Steamify carries the same file (checked the same way).
|
||||||
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
warn "Downloading Valve's CEC driver failed (or its checksum didn't match): using the copy Steamify carries."
|
||||||
return 1
|
patch_file cros-ec-cec.c > "$tmp/cros-ec-cec.c"
|
||||||
|
if ! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
err "Steamify's own copy of Valve's CEC driver doesn't match the pinned checksum (a new pin needs a new copy in patches/)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
||||||
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
||||||
|
|||||||
+17
-6
@@ -7,13 +7,25 @@
|
|||||||
|
|
||||||
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
||||||
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
||||||
|
FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh"
|
||||||
|
|
||||||
first_login_schedule() {
|
first_login_schedule() {
|
||||||
|
# The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with
|
||||||
|
# steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead.
|
||||||
|
# (Only a single-file bundle can be copied; SCRIPT_DIR doesn't exist in one.)
|
||||||
|
local run self="${BASH_SOURCE[0]:-}"
|
||||||
|
if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$self" ]] && grep -q '^# Single-file build' "$self"; then
|
||||||
|
install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$self"
|
||||||
|
run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\""
|
||||||
|
else
|
||||||
|
run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login"
|
||||||
|
fi
|
||||||
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
|
mkdir -p ~/.cache
|
||||||
|
{ $run; } > ~/.cache/steamify-first-login.log 2>&1
|
||||||
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
||||||
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
||||||
EOF2
|
EOF2
|
||||||
@@ -31,10 +43,9 @@ first_login_run() {
|
|||||||
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
if single_status; then
|
stop_plasmashell_for_edit
|
||||||
stop_plasmashell_for_edit
|
taskbar_drop_discover
|
||||||
single_launcher
|
single_status && single_launcher
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
fi
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures
|
||||||
|
# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch is opt-in: gamescope reads
|
||||||
|
# `gamescope_drm_gbm_scanout=1` from its environment, which is set for the gaming session (gamescope-session's
|
||||||
|
# environment file, and environment.d).
|
||||||
|
#
|
||||||
|
# gamescope changes every few weeks, so the package is not carried but downloaded: the newest release of
|
||||||
|
# https://github.com/theupriser/steamify-gamescope-nvidia (CI builds it in CachyOS's container, a person merges the
|
||||||
|
# version bump), and a newer one than the installed package shows as an update of the SteamOS conversion
|
||||||
|
# (`gsn_update_pending`). What this Steamify release was tested with is the fallback: the pinned package (sha256 below),
|
||||||
|
# a copy that came with the ISO, and last a build here from the recipe and patch in patches/. Simple files that don't change
|
||||||
|
# stay in patches/ and are used as they are.
|
||||||
|
#
|
||||||
|
# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel
|
||||||
|
# parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or
|
||||||
|
# newer (Turing and later, what NVIDIA's open kernel driver supports). Tested on an RTX 5080 only.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
GSN_PKG=steamify-gamescope-nvidia
|
||||||
|
GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}"
|
||||||
|
# The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the
|
||||||
|
# fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel.
|
||||||
|
GSN_VERSION=3.16.31-3
|
||||||
|
# One build per CPU level, like CachyOS's repositories: generic is the one every x86-64 PC can run.
|
||||||
|
declare -A GSN_SHA256=(
|
||||||
|
[generic]=4c7995694d2726c356785d9aec12a11c98419b4d2e139617f03bb46c758ced56
|
||||||
|
[v3]=43c6928ca9fa67c063c4e1b993b686145e94e68de1bd46645782d3186779fa2d
|
||||||
|
[v4]=b6d4621e4b98d9aa5c600fe9a5a1cae164fef6bbf93d259fb8a6af666b098f9f
|
||||||
|
[znver4]=60f45da74a0b96d776219f6e6aa22c5d23e48b08233b3fa12b6c4d7aa6812dd9
|
||||||
|
)
|
||||||
|
# Where the ISO leaves a copy of the pinned package, for installs without GitHub.
|
||||||
|
GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}"
|
||||||
|
# How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time.
|
||||||
|
GSN_CHECK_EVERY="${GSN_CHECK_EVERY:-21600}"
|
||||||
|
GSN_ENV_LINE='gamescope_drm_gbm_scanout=1'
|
||||||
|
GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}"
|
||||||
|
GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}"
|
||||||
|
|
||||||
|
gsn_package_installed() { pacman -Q "$GSN_PKG" >/dev/null 2>&1; }
|
||||||
|
|
||||||
|
gsn_installed_version() { pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}'; }
|
||||||
|
|
||||||
|
gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV"; }
|
||||||
|
|
||||||
|
gsn_status() { gsn_package_installed && gsn_env_set; }
|
||||||
|
|
||||||
|
gsn_newer() {
|
||||||
|
# gsn_newer <a> <b>: version a is newer than b (pacman's own comparison).
|
||||||
|
[[ "$(vercmp "$1" "$2" 2>/dev/null)" == 1 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_latest_tag() {
|
||||||
|
# The newest release's tag (<gamescope version>-<package release>), from GitHub; nothing when it can't be reached or
|
||||||
|
# there is no release. Follows the redirect of /releases/latest: no API, no rate limit, no JSON. gsn_latest_tag [seconds]
|
||||||
|
local url
|
||||||
|
url="$(curl -fsL --connect-timeout 4 --max-time "${1:-10}" -o /dev/null -w '%{url_effective}' "$GSN_RELEASES/latest" 2>/dev/null)" || return 1
|
||||||
|
url="${url##*/}"
|
||||||
|
[[ "$url" =~ ^[0-9][0-9A-Za-z._]*-[0-9]+$ ]] || return 1
|
||||||
|
echo "$url"
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_update_pending() {
|
||||||
|
# The patched gamescope is installed and GitHub has a newer release: the menu shows the conversion as an update.
|
||||||
|
# Looked up at most every GSN_CHECK_EVERY seconds (the answer is kept in the state), quickly, and silently when
|
||||||
|
# offline: no network is never a reason to show or hide anything.
|
||||||
|
gsn_package_installed || return 1
|
||||||
|
local now checked latest
|
||||||
|
now="$(date +%s)"; checked="$(state_get gamescope_nvidia checked 0)"
|
||||||
|
if (( now - ${checked:-0} > GSN_CHECK_EVERY )); then
|
||||||
|
state_set gamescope_nvidia checked "$now"
|
||||||
|
latest="$(gsn_latest_tag 5)" && state_set gamescope_nvidia latest "$latest"
|
||||||
|
fi
|
||||||
|
latest="$(state_get gamescope_nvidia latest)"
|
||||||
|
[[ -n "$latest" ]] && gsn_newer "$latest" "$(gsn_installed_version)"
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_cpu_variant() {
|
||||||
|
# The best build this CPU can run: znver4 (Ryzen 7000/9000: AMD with AVX-512 BF16), v4, v3, else generic. The
|
||||||
|
# dynamic loader knows the CPU level best ("x86-64-v4 (supported, searched)").
|
||||||
|
local help; help="$(/lib64/ld-linux-x86-64.so.2 --help 2>/dev/null)"
|
||||||
|
if grep -q 'x86-64-v4 (supported' <<< "$help"; then
|
||||||
|
if grep -q AuthenticAMD /proc/cpuinfo && grep -qw avx512_bf16 /proc/cpuinfo; then echo znver4; else echo v4; fi
|
||||||
|
elif grep -q 'x86-64-v3 (supported' <<< "$help"; then echo v3
|
||||||
|
else echo generic; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_sha_of() {
|
||||||
|
# The hash a release file is expected to have: the pinned one for the pinned version, else the .sha256 next to the
|
||||||
|
# package in the same release (it shows the download wasn't damaged, not who made it). gsn_sha_of <tag> <file> <variant>
|
||||||
|
local tag="$1" file="$2" variant="$3"
|
||||||
|
if [[ "$tag" == "$GSN_VERSION" ]]; then echo "${GSN_SHA256[$variant]}"; return 0; fi
|
||||||
|
curl -fsL --connect-timeout 10 --max-time 30 "$GSN_RELEASES/download/$tag/$file.sha256" 2>/dev/null | awk 'NR==1 {print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_download() {
|
||||||
|
# gsn_download <tag> <variant>: the release's package, verified, in the cache; prints its path.
|
||||||
|
local tag="$1" variant="$2" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got
|
||||||
|
file="$GSN_PKG-$tag-$variant.pkg.tar.zst"
|
||||||
|
mkdir -p "$cache" || return 1
|
||||||
|
want="$(gsn_sha_of "$tag" "$file" "$variant")"
|
||||||
|
[[ "$want" =~ ^[0-9a-f]{64}$ ]] || return 1
|
||||||
|
if [[ -f "$cache/$file" ]] && [[ "$(sha256sum "$cache/$file" | awk '{print $1}')" == "$want" ]]; then echo "$cache/$file"; return 0; fi
|
||||||
|
curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_RELEASES/download/$tag/$file" || { rm -f "$cache/$file.part"; return 1; }
|
||||||
|
got="$(sha256sum "$cache/$file.part" | awk '{print $1}')"
|
||||||
|
if [[ "$got" != "$want" ]]; then rm -f "$cache/$file.part"; return 1; fi
|
||||||
|
mv -f "$cache/$file.part" "$cache/$file"
|
||||||
|
echo "$cache/$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_fetch_package() {
|
||||||
|
# The package to install, as a path: the build for this CPU, then the generic one, each from the newest release on
|
||||||
|
# GitHub (not older than the pinned one), else the pinned release (GitHub, the cache, or the copy that came with the
|
||||||
|
# ISO). Only files with the expected sha256 count. gsn_fetch_package [variant]
|
||||||
|
local tag pkg v cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file copy
|
||||||
|
local -a variants=("${1:-$(gsn_cpu_variant)}"); [[ "${variants[0]}" == generic ]] || variants+=(generic)
|
||||||
|
tag="$(gsn_latest_tag)" || tag=""
|
||||||
|
for v in "${variants[@]}"; do
|
||||||
|
if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then
|
||||||
|
info "Downloading the newest patched gamescope ($tag, $v)..." >&2
|
||||||
|
if pkg="$(gsn_download "$tag" "$v")"; then echo "$pkg"; return 0; fi
|
||||||
|
warn "Downloading the newest patched gamescope ($tag, $v) failed: trying the version this Steamify was tested with ($GSN_VERSION)." >&2
|
||||||
|
fi
|
||||||
|
info "Downloading the patched gamescope ($GSN_VERSION, $v)..." >&2
|
||||||
|
if pkg="$(gsn_download "$GSN_VERSION" "$v")"; then echo "$pkg"; return 0; fi
|
||||||
|
file="$GSN_PKG-$GSN_VERSION-$v.pkg.tar.zst"
|
||||||
|
for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do
|
||||||
|
if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "${GSN_SHA256[$v]}" ]]; then
|
||||||
|
info "Using the copy that came with Steamify: $copy" >&2
|
||||||
|
echo "$copy"; return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_smoke_test() {
|
||||||
|
# The installed gamescope must start (headless, no screen needed): a build that crashes would leave gaming mode in a loop.
|
||||||
|
# It segfaults while shutting down headless (also unpatched builds), so what counts is that it ran the program.
|
||||||
|
timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true 2>&1 | grep -q 'Primary child shut down'
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_build_package() {
|
||||||
|
# Last resort: builds the pinned package from the recipe and patch Steamify carries (patches/), as the user. It
|
||||||
|
# downloads gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a
|
||||||
|
# few minutes. Prints the package's path.
|
||||||
|
local dir cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
||||||
|
info "Building the patched gamescope here instead (a few minutes)..." >&2
|
||||||
|
sudo pacman -S --needed --noconfirm base-devel git >&2 || { err "Installing the build tools failed." >&2; return 1; }
|
||||||
|
# On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB.
|
||||||
|
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1
|
||||||
|
patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" &&
|
||||||
|
patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" &&
|
||||||
|
patch_file gamescope-ui-native.patch > "$dir/gamescope-ui-native.patch" || {
|
||||||
|
err "Couldn't write the build files." >&2
|
||||||
|
rm -rf "$dir"; return 1
|
||||||
|
}
|
||||||
|
if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck >&2); then
|
||||||
|
err "Building the patched gamescope failed (see above)." >&2
|
||||||
|
rm -rf "$dir"; return 1
|
||||||
|
fi
|
||||||
|
# Moved out, so the build folder can go.
|
||||||
|
local f built=""
|
||||||
|
for f in "$dir"/"$GSN_PKG"-*.pkg.tar.*; do
|
||||||
|
[[ -e "$f" && "$f" != *-debug-* ]] && { built="$f"; break; }
|
||||||
|
done
|
||||||
|
[[ -n "$built" ]] && mv "$built" "$cache/gamescope-local-build.pkg.tar.zst" || { rm -rf "$dir"; return 1; }
|
||||||
|
rm -rf "$dir"
|
||||||
|
echo "$cache/gamescope-local-build.pkg.tar.zst"
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_install_package() {
|
||||||
|
# The patched gamescope, newest first, each step only when the one before failed: the newest release from GitHub, the
|
||||||
|
# pinned package (GitHub, cache or the copy that came with the ISO), a build here. A package that downloaded fine but
|
||||||
|
# doesn't install (its libraries differ from this PC's) goes on to the next step too. Nothing else changes before one of
|
||||||
|
# them is installed, so a failure leaves the PC as it was, with what it had. --ask 4 lets pacman replace the stock
|
||||||
|
# gamescope it conflicts with, and an older patched one.
|
||||||
|
local pkg latest have
|
||||||
|
have="$(gsn_installed_version)"
|
||||||
|
latest="$(gsn_latest_tag)" || latest=""
|
||||||
|
# Already the newest (or, offline, the pinned version or newer): nothing to do.
|
||||||
|
if [[ -n "$have" ]]; then
|
||||||
|
if [[ -n "$latest" ]] && ! gsn_newer "$latest" "$have"; then return 0; fi
|
||||||
|
if [[ -z "$latest" ]] && ! gsn_newer "$GSN_VERSION" "$have"; then return 0; fi
|
||||||
|
fi
|
||||||
|
if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
||||||
|
if ! gsn_smoke_test; then
|
||||||
|
warn "The patched gamescope for this CPU doesn't start: installing the generic build instead."
|
||||||
|
pkg="$(gsn_fetch_package generic)" && sudo pacman -U --noconfirm --ask 4 "$pkg" && gsn_smoke_test ||
|
||||||
|
{ err "The patched gamescope doesn't start on this PC."; return 1; }
|
||||||
|
fi
|
||||||
|
ok "Patched gamescope installed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
warn "The ready-made patched gamescope couldn't be installed."
|
||||||
|
[[ -n "$have" ]] && { warn "The installed one ($have) stays."; return 0; }
|
||||||
|
if pkg="$(gsn_build_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
||||||
|
ok "Patched gamescope built and installed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
err "The patched gamescope couldn't be installed. The stock gamescope stays."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_env_enable() {
|
||||||
|
mkdir -p "$(dirname "$GSN_ENV_D")" "$(dirname "$GSN_SESSION_ENV")"
|
||||||
|
echo "$GSN_ENV_LINE" > "$GSN_ENV_D"
|
||||||
|
touch "$GSN_SESSION_ENV"
|
||||||
|
grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV" || echo "$GSN_ENV_LINE" >> "$GSN_SESSION_ENV"
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_env_disable() {
|
||||||
|
rm -f "$GSN_ENV_D"
|
||||||
|
[[ -f "$GSN_SESSION_ENV" ]] && sed -i "/^${GSN_ENV_LINE}\$/d" "$GSN_SESSION_ENV"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- The session starts gamescope on the display's own mode
|
||||||
|
#
|
||||||
|
# gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode, which
|
||||||
|
# many monitors declare as 60 Hz while the desktop runs them at their highest. patches/gamescope-display-wrapper.sh (put
|
||||||
|
# first in the gaming session's PATH by a drop-in of gamescope-session.service) starts it on the mode KDE has saved for
|
||||||
|
# the connected display, else the biggest mode at the highest refresh rate, read at every session start.
|
||||||
|
GSN_DISPLAY_WRAPPER="${GSN_DISPLAY_WRAPPER:-$STEAMIFY_BIN/gamescope}"
|
||||||
|
GSN_DISPLAY_DROPIN="${GSN_DISPLAY_DROPIN:-$HOME/.config/systemd/user/gamescope-session.service.d/steamify-display.conf}"
|
||||||
|
|
||||||
|
gsn_display_status() { [[ -x "$GSN_DISPLAY_WRAPPER" && -f "$GSN_DISPLAY_DROPIN" ]]; }
|
||||||
|
|
||||||
|
gsn_display_pending() {
|
||||||
|
# The patched gamescope is in use but the session still starts it on the display's preferred mode: a normal run sets it up.
|
||||||
|
gsn_package_installed && gsn_env_set && ! gsn_display_status
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_display_enable() {
|
||||||
|
patch_file gamescope-display-wrapper.sh | install_executable "$GSN_DISPLAY_WRAPPER" 755 || return 1
|
||||||
|
mkdir -p "$(dirname "$GSN_DISPLAY_DROPIN")"
|
||||||
|
cat > "$GSN_DISPLAY_DROPIN" << EOF
|
||||||
|
# Steamify: the gaming session starts gamescope on the display's own mode (see lib/gamescope-nvidia.sh). Turning the
|
||||||
|
# SteamOS conversion off removes this file.
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=/usr/bin/bash -c 'PATH="$(dirname "$GSN_DISPLAY_WRAPPER"):\$PATH" exec /usr/lib/steamos/gamescope-session'
|
||||||
|
EOF
|
||||||
|
user_systemctl daemon-reload
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_display_disable() {
|
||||||
|
# Only our own files: the wrapper is recognised by its first comment line.
|
||||||
|
grep -qs "^# Steamify: gamescope-session starts gamescope" "$GSN_DISPLAY_WRAPPER" && rm -f "$GSN_DISPLAY_WRAPPER"
|
||||||
|
[[ -f "$GSN_DISPLAY_DROPIN" ]] && rm -f "$GSN_DISPLAY_DROPIN" && rmdir "$(dirname "$GSN_DISPLAY_DROPIN")" 2>/dev/null
|
||||||
|
user_systemctl daemon-reload
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_preflight() {
|
||||||
|
# Before anything changes: what would make the install fail half way. Prints the reason and fails, or passes.
|
||||||
|
if [[ -e /var/lib/pacman/db.lck ]]; then
|
||||||
|
echo "another package manager is running (/var/lib/pacman/db.lck): finish or close it and try again"; return 1
|
||||||
|
fi
|
||||||
|
local free; free="$(df --output=avail -BM / 2>/dev/null | tail -1 | tr -dc 0-9)"
|
||||||
|
if [[ -n "$free" ]] && (( free < 1500 )); then
|
||||||
|
echo "less than 1.5 GB free on /: free some space and try again"; return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_fail_mark() {
|
||||||
|
# Remember a failed setup so the menu says so on the next start, and tell the user now (desktop notification).
|
||||||
|
state_set gamescope_nvidia failed "$(date '+%Y-%m-%d %H:%M'): $1"
|
||||||
|
command -v notify-send >/dev/null 2>&1 &&
|
||||||
|
notify-send -a Steamify -i dialog-warning "Steamify: gaming mode setup failed" "$1. Open Steamify and apply again." 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_fail_note() {
|
||||||
|
# The menu's reminder of a failed setup (nothing when the last one worked).
|
||||||
|
local f; f="$(state_get gamescope_nvidia failed)"
|
||||||
|
[[ -n "$f" ]] && warn "The last gaming mode setup for NVIDIA failed ($f). Apply the conversion again to retry."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_enable() {
|
||||||
|
# Only on a supported NVIDIA card; elsewhere the stock gamescope is right.
|
||||||
|
nvidia_present || return 0
|
||||||
|
local why
|
||||||
|
if ! why="$(gsn_preflight)"; then err "Gaming mode for NVIDIA can't be set up: $why."; gsn_fail_mark "$why"; return 1; fi
|
||||||
|
# A PC that had "Gaming on NVIDIA" on: Steam must not also start on the desktop.
|
||||||
|
nvidia_swap_out
|
||||||
|
# What NVIDIA's DRM stack wants (lib/nvidia.sh; a supported card only, the functions check): modeset/fbdev on the
|
||||||
|
# kernel command line, the modules in the initramfs, video memory kept over suspend, the 32-bit libraries. Takes
|
||||||
|
# effect at the next boot, like the session.
|
||||||
|
nvidia_kernel_enable || return 1
|
||||||
|
nvidia_extras_enable || return 1
|
||||||
|
gsn_install_package || { gsn_fail_mark "the patched gamescope couldn't be installed"; return 1; }
|
||||||
|
state_set gamescope_nvidia failed ""
|
||||||
|
gsn_env_enable
|
||||||
|
gsn_display_enable || warn "Couldn't set up the display mode for gaming mode: gamescope takes the display's preferred mode."
|
||||||
|
ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start."
|
||||||
|
}
|
||||||
|
|
||||||
|
gsn_disable() {
|
||||||
|
# The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like
|
||||||
|
# the other packages of the conversion (steam, gamescope-session-cachyos).
|
||||||
|
gsn_env_disable
|
||||||
|
gsn_display_disable
|
||||||
|
nvidia_present || return 0
|
||||||
|
nvidia_extras_disable
|
||||||
|
nvidia_kernel_disable
|
||||||
|
}
|
||||||
@@ -94,6 +94,8 @@ gaming_enable() {
|
|||||||
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
|
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
|
||||||
# menu. Re-running with the other value switches over cleanly.
|
# menu. Re-running with the other value switches over cleanly.
|
||||||
install_required_packages || return 1
|
install_required_packages || return 1
|
||||||
|
# NVIDIA: gamescope's picture is corrupted unless it is the patched one (no-op elsewhere).
|
||||||
|
gsn_enable || return 1
|
||||||
case "$LOGIN_MANAGER" in
|
case "$LOGIN_MANAGER" in
|
||||||
sddm)
|
sddm)
|
||||||
switch_to_sddm || return 1
|
switch_to_sddm || return 1
|
||||||
@@ -107,6 +109,8 @@ gaming_enable() {
|
|||||||
install_session_sync
|
install_session_sync
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
# (NVIDIA with single user mode from before the conversion: its desktop autologin would pin the Plasma session.)
|
||||||
|
single_login_release
|
||||||
create_desktop_shortcut
|
create_desktop_shortcut
|
||||||
steam_enable
|
steam_enable
|
||||||
os_name_enable || return 1
|
os_name_enable || return 1
|
||||||
@@ -122,8 +126,11 @@ gaming_disable() {
|
|||||||
switch_to_plasmalogin
|
switch_to_plasmalogin
|
||||||
remove_desktop_shortcut
|
remove_desktop_shortcut
|
||||||
steam_disable
|
steam_disable
|
||||||
|
gsn_disable
|
||||||
krevert gaming
|
krevert gaming
|
||||||
os_name_disable
|
os_name_disable
|
||||||
|
# NVIDIA with single user mode still on: nothing else logs in by itself any more.
|
||||||
|
nvidia_present && single_status && single_login_enable
|
||||||
ok "The PC boots to the normal login screen again (from the next boot)."
|
ok "The PC boots to the normal login screen again (from the next boot)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-12
@@ -5,19 +5,19 @@
|
|||||||
|
|
||||||
# Menu order. Components are turned on in this order and off in reverse;
|
# Menu order. Components are turned on in this order and off in reverse;
|
||||||
# gaming must come first (single user builds on it).
|
# gaming must come first (single user builds on it).
|
||||||
COMPONENTS=(gaming boot nvidia bigpicture theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
||||||
# One-off actions rather than on/off components: never preselected, never
|
# One-off actions rather than on/off components: never preselected, never
|
||||||
# re-applied, not listed as on or off.
|
# re-applied, not listed as on or off.
|
||||||
ACTIONS=(bios)
|
ACTIONS=(bios)
|
||||||
# Sub-options, shown indented under their parent and only while it's ticked.
|
# Sub-options, shown indented under their parent and only while it's ticked.
|
||||||
declare -A PARENT=([boot]=gaming [bigpicture]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
||||||
# Never preselected on a first run: booting into the desktop is a choice,
|
# Never preselected on a first run: booting into the desktop is a choice,
|
||||||
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
||||||
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
||||||
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the
|
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the
|
||||||
# screen to confirm each step. Extended controller support builds kernel modules for
|
# screen to confirm each step. Extended controller support builds kernel modules for
|
||||||
# every installed kernel: opt-in.
|
# every installed kernel: opt-in.
|
||||||
NO_PRESELECT=(boot cec kpin hdmi extended_controller_support)
|
NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
||||||
# Feature versions: the Steamify version in which what a component's enable
|
# Feature versions: the Steamify version in which what a component's enable
|
||||||
# sets up last changed; set it to the new VERSION whenever you change one.
|
# sets up last changed; set it to the new VERSION whenever you change one.
|
||||||
# Each successful run records it (state "features"); a component that's on
|
# Each successful run records it (state "features"); a component that's on
|
||||||
@@ -26,7 +26,7 @@ NO_PRESELECT=(boot cec kpin hdmi extended_controller_support)
|
|||||||
# FEATURE_BASELINE.
|
# FEATURE_BASELINE.
|
||||||
FEATURE_BASELINE=2.1.0
|
FEATURE_BASELINE=2.1.0
|
||||||
declare -A FEATURE_VERSION=(
|
declare -A FEATURE_VERSION=(
|
||||||
[gaming]=2.9.0 [boot]=2.1.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.12.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
||||||
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
|
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
|
||||||
[kpin]=2.1.0 [hdmi]=2.1.0
|
[kpin]=2.1.0 [hdmi]=2.1.0
|
||||||
)
|
)
|
||||||
@@ -35,6 +35,8 @@ declare -A LABEL=(
|
|||||||
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
|
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
|
||||||
[boot]="Boot into the desktop instead of gaming mode"
|
[boot]="Boot into the desktop instead of gaming mode"
|
||||||
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
|
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
|
||||||
|
[silent]="Start Steam silently in desktop mode: in the tray at login on the desktop, no window"
|
||||||
|
[nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)"
|
||||||
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
|
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
|
||||||
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
||||||
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
||||||
@@ -55,11 +57,9 @@ declare -A CURRENT WANTED
|
|||||||
|
|
||||||
component_available() {
|
component_available() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
# gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown
|
# The SteamOS conversion is offered on NVIDIA PCs too: it installs the patched gamescope there (lib/gamescope-nvidia.sh)
|
||||||
# anyway when it's already on, so it can be turned off).
|
# and turns off "Gaming on NVIDIA" (lib/nvidia.sh), which is not offered any more (nvidia_available).
|
||||||
gaming|boot|glyphs) ! nvidia_present || gaming_status ;;
|
nvidia|bigpicture|nvsilent) nvidia_available ;;
|
||||||
nvidia) nvidia_available ;;
|
|
||||||
bigpicture) bigpicture_available ;;
|
|
||||||
machine|poweroff) machine_available ;;
|
machine|poweroff) machine_available ;;
|
||||||
vram) vram_available ;;
|
vram) vram_available ;;
|
||||||
# Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
|
# Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
|
||||||
@@ -83,6 +83,8 @@ menu_visible() {
|
|||||||
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
||||||
# while its parent is ticked.
|
# while its parent is ticked.
|
||||||
component_available "$1" || return 1
|
component_available "$1" || return 1
|
||||||
|
# Silent start is hidden while Steam starts in Big Picture.
|
||||||
|
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
||||||
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +113,11 @@ feature_outdated() {
|
|||||||
# On, but set up by an older version of that feature (compared as
|
# On, but set up by an older version of that feature (compared as
|
||||||
# versions: 2.10.0 is newer than 2.9.0).
|
# versions: 2.10.0 is newer than 2.9.0).
|
||||||
local have want
|
local have want
|
||||||
|
# "Gaming on NVIDIA" is on: the SteamOS conversion replaces it, as an update of what the PC has (lib/nvidia.sh).
|
||||||
|
[[ "$1" == gaming ]] && nvidia_migration_pending && return 0
|
||||||
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
||||||
|
# NVIDIA: a newer patched gamescope is out (lib/gamescope-nvidia.sh): a normal run installs it.
|
||||||
|
[[ "$1" == gaming ]] && nvidia_present && { gsn_update_pending || gsn_display_pending; } && return 0
|
||||||
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
||||||
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
||||||
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
||||||
@@ -180,6 +186,17 @@ detect_components() {
|
|||||||
component_available "$c" || continue
|
component_available "$c" || continue
|
||||||
{ feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1
|
{ feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1
|
||||||
done
|
done
|
||||||
|
# "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run, and the
|
||||||
|
# PC starts the way it did: Steam in Big Picture at login becomes booting into gaming mode, any other Steam start
|
||||||
|
# (a normal window, or silent in the tray) becomes booting into the desktop, with the silent start kept.
|
||||||
|
if nvidia_migration_pending; then
|
||||||
|
WANTED[glyphs]=1
|
||||||
|
if bigpicture_status; then WANTED[boot]=0
|
||||||
|
else
|
||||||
|
WANTED[boot]=1
|
||||||
|
nvsilent_status && WANTED[silent]=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# The kernel pin is no longer needed (the power-off fix), and HDMI
|
# The kernel pin is no longer needed (the power-off fix), and HDMI
|
||||||
# refresh boost needed the pin: whatever is left of either is unticked,
|
# refresh boost needed the pin: whatever is left of either is unticked,
|
||||||
# so a normal run removes it.
|
# so a normal run removes it.
|
||||||
@@ -282,7 +299,7 @@ defaults_list() {
|
|||||||
[[ "$c" == cec ]] && machine_available && on=true
|
[[ "$c" == cec ]] && machine_available && on=true
|
||||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
||||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
||||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"on\":$on,\"selectable\":$sel}"
|
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":\"\",\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
||||||
done
|
done
|
||||||
printf '[%s]\n' "$items"
|
printf '[%s]\n' "$items"
|
||||||
}
|
}
|
||||||
@@ -292,14 +309,19 @@ toggle_component() {
|
|||||||
component_selectable "$c" || return 1
|
component_selectable "$c" || return 1
|
||||||
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
||||||
# Single user mode only makes sense on top of the SteamOS conversion.
|
# Single user mode only makes sense on top of the SteamOS conversion.
|
||||||
# (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.)
|
|
||||||
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi
|
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi
|
||||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
|
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
|
||||||
# Where to boot to is part of the conversion, too.
|
# Where to boot to is part of the conversion, too.
|
||||||
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi
|
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
# Big Picture is opt-out: ticked along with "Gaming on NVIDIA".
|
# Big Picture is opt-out: ticked along with "Gaming on NVIDIA".
|
||||||
if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi
|
if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi
|
||||||
if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; fi
|
if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[nvsilent]=0; fi
|
||||||
|
# Silent and Big Picture exclude each other.
|
||||||
|
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi
|
||||||
|
if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi
|
||||||
|
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi
|
||||||
|
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
|
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
# The power-off fix is opt-out: ticked along with Steam Machine support.
|
# The power-off fix is opt-out: ticked along with Steam Machine support.
|
||||||
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi
|
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi
|
||||||
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi
|
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi
|
||||||
@@ -315,6 +337,7 @@ toggle_component() {
|
|||||||
show_menu() {
|
show_menu() {
|
||||||
local i=0 c now want
|
local i=0 c now want
|
||||||
echo
|
echo
|
||||||
|
gsn_fail_note
|
||||||
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
||||||
MENU_ITEMS=()
|
MENU_ITEMS=()
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
@@ -489,6 +512,11 @@ apply_changes() {
|
|||||||
if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi
|
if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
for c in "${TO_ENABLE[@]}"; do
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
|
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
||||||
|
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
||||||
|
warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
||||||
elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
|
elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
|
||||||
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
|
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
|
||||||
|
|||||||
+97
-7
@@ -13,6 +13,11 @@ NVIDIA_INITRAMFS_CONF=${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamif
|
|||||||
# The script and pacman hook that keep the initramfs file right at every kernel change.
|
# 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_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs}
|
||||||
NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook}
|
NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook}
|
||||||
|
# Keeps video memory over suspend (with the nvidia-suspend/resume services).
|
||||||
|
NVIDIA_MODPROBE=${NVIDIA_MODPROBE:-/etc/modprobe.d/90-steamify-nvidia.conf}
|
||||||
|
NVIDIA_SLEEP_UNITS="nvidia-suspend.service nvidia-resume.service nvidia-hibernate.service"
|
||||||
|
# 32-bit parts Steam games and the 32-bit MangoHud preload need.
|
||||||
|
NVIDIA_LIB32_PKGS="lib32-nvidia-utils lib32-libxkbcommon"
|
||||||
# The running kernel's command line; the tests point this at a file.
|
# The running kernel's command line; the tests point this at a file.
|
||||||
NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline}
|
NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline}
|
||||||
# The DRM devices in sysfs; the tests point this at a fake tree.
|
# The DRM devices in sysfs; the tests point this at a fake tree.
|
||||||
@@ -32,9 +37,27 @@ nvidia_present() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Shown on NVIDIA PCs, unless the SteamOS conversion is already on there (it
|
# Not offered any more (2.12.0): the SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) covers NVIDIA PCs.
|
||||||
# has to be turned off first: both would start Steam at login).
|
# A PC that has this on keeps it until the conversion is turned on, which calls nvidia_swap_out.
|
||||||
nvidia_available() { nvidia_present && ! gaming_status 2>/dev/null; }
|
nvidia_available() { return 1; }
|
||||||
|
|
||||||
|
nvidia_migration_pending() {
|
||||||
|
# "Gaming on NVIDIA" is on (set up before 2.12.0) and the SteamOS conversion that replaces it isn't: the menu ticks the
|
||||||
|
# conversion and shows it as an update, so a normal run moves the PC over (nvidia_swap_out in gsn_enable).
|
||||||
|
nvidia_present && nvidia_status && ! gaming_status 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
nvidia_swap_out() {
|
||||||
|
# The conversion takes over: Steam no longer starts by itself on the desktop at login (both would start it). Steam, the
|
||||||
|
# packages and the NVIDIA settings stay: the conversion needs them too. The state stays for the conversion's own disable.
|
||||||
|
nvidia_status || return 0
|
||||||
|
info "Gaming on NVIDIA is replaced by the SteamOS conversion: Steam no longer starts on the desktop at login."
|
||||||
|
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
||||||
|
rm -f "$(nvidia_unit_file)"
|
||||||
|
user_systemctl daemon-reload
|
||||||
|
krevert bigpicture
|
||||||
|
return 0
|
||||||
|
}
|
||||||
bigpicture_available() { nvidia_available; }
|
bigpicture_available() { nvidia_available; }
|
||||||
|
|
||||||
nvidia_status() {
|
nvidia_status() {
|
||||||
@@ -57,10 +80,12 @@ nvidia_enable() {
|
|||||||
state_set nvidia installed_pkgs steam
|
state_set nvidia installed_pkgs steam
|
||||||
fi
|
fi
|
||||||
# Keeps what the Big Picture option set up; a first run starts Steam normally.
|
# Keeps what the Big Picture option set up; a first run starts Steam normally.
|
||||||
local args=""; bigpicture_status && args=-gamepadui
|
local unit_args=""
|
||||||
nvidia_write_unit "$args" || return 1
|
if bigpicture_status; then unit_args=-gamepadui; elif nvsilent_status; then unit_args=-silent; fi
|
||||||
|
nvidia_write_unit "$unit_args" || return 1
|
||||||
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
|
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
|
||||||
nvidia_kernel_enable || return 1
|
nvidia_kernel_enable || return 1
|
||||||
|
nvidia_extras_enable || return 1
|
||||||
ok "Steam starts at your next login."
|
ok "Steam starts at your next login."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +94,19 @@ nvidia_disable() {
|
|||||||
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
||||||
rm -f "$unit"
|
rm -f "$unit"
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
|
# Swapped for the SteamOS conversion (turned on first, in the same run): it needs the same settings, they stay.
|
||||||
|
gaming_status 2>/dev/null || nvidia_extras_disable
|
||||||
pkgs="$(state_get nvidia installed_pkgs)"
|
pkgs="$(state_get nvidia installed_pkgs)"
|
||||||
|
if gaming_status 2>/dev/null; then
|
||||||
|
local p; pkgs=" $pkgs "
|
||||||
|
for p in $NVIDIA_LIB32_PKGS; do pkgs="${pkgs// $p / }"; done
|
||||||
|
fi
|
||||||
# Only what Steamify installed; games and the Steam folder stay.
|
# Only what Steamify installed; games and the Steam folder stay.
|
||||||
# shellcheck disable=SC2086 # a list of package names
|
# shellcheck disable=SC2086 # a list of package names
|
||||||
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
|
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
|
||||||
state_clear nvidia
|
state_clear nvidia
|
||||||
krevert bigpicture
|
krevert bigpicture
|
||||||
nvidia_kernel_disable
|
gaming_status 2>/dev/null || nvidia_kernel_disable
|
||||||
ok "Steam no longer starts at login."
|
ok "Steam no longer starts at login."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,11 +127,28 @@ bigpicture_disable() {
|
|||||||
nvidia_write_unit "" && ok "Steam starts in its normal window at your next login."
|
nvidia_write_unit "" && ok "Steam starts in its normal window at your next login."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Sub-option: Steam starts silently (tray only, no window). Big Picture and
|
||||||
|
# a silent start exclude each other (the menus untick one when the other is
|
||||||
|
# ticked); a first run with both gets Big Picture.
|
||||||
|
nvsilent_status() { grep -qs -- '-silent' "$(nvidia_unit_file)"; }
|
||||||
|
|
||||||
|
nvsilent_enable() {
|
||||||
|
[[ -f "$(nvidia_unit_file)" ]] || return 0
|
||||||
|
bigpicture_status && return 0
|
||||||
|
nvidia_write_unit -silent || return 1
|
||||||
|
ok "Steam starts silently at your next login."
|
||||||
|
}
|
||||||
|
|
||||||
|
nvsilent_disable() {
|
||||||
|
nvsilent_status || return 0
|
||||||
|
nvidia_write_unit "" && ok "Steam starts in its normal window at your next login."
|
||||||
|
}
|
||||||
|
|
||||||
# --- Kernel parameters and early modules (a supported card only)
|
# --- Kernel parameters and early modules (a supported card only)
|
||||||
|
|
||||||
nvidia_supported() {
|
nvidia_supported() {
|
||||||
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
|
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
|
||||||
# driver installed, and not older than the RTX 20 series, decided like the
|
# driver installed, and not older than Turing (GTX 16 / RTX 20 series: the cards NVIDIA's open kernel driver supports), decided like the
|
||||||
# VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every
|
# 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.
|
# other card runs NVIDIA's open modules). Older cards are left alone.
|
||||||
local d
|
local d
|
||||||
@@ -236,6 +284,48 @@ nvidia_kernel_enable() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nvidia_extras_enable() {
|
||||||
|
# Video memory kept over sleep, the matching services and the 32-bit libraries (a supported card only).
|
||||||
|
nvidia_supported || return 0
|
||||||
|
local pkg u units="" prev missing=()
|
||||||
|
if [[ ! -f "$NVIDIA_MODPROBE" ]]; then
|
||||||
|
info "Keeping video memory over suspend (NVreg_PreserveVideoMemoryAllocations=1)..."
|
||||||
|
printf '%s\n' '# Added by Steamify (Gaming on NVIDIA)' 'options nvidia NVreg_PreserveVideoMemoryAllocations=1' |
|
||||||
|
sudo tee "$NVIDIA_MODPROBE" >/dev/null || { err "Writing $NVIDIA_MODPROBE failed."; return 1; }
|
||||||
|
# The NVIDIA modules load from the initramfs, which carries modprobe.d.
|
||||||
|
nvidia_rebuild_boot || warn "Rebuilding the initramfs failed: the suspend setting applies once it is rebuilt."
|
||||||
|
fi
|
||||||
|
for u in $NVIDIA_SLEEP_UNITS; do
|
||||||
|
systemctl is-enabled -q "$u" 2>/dev/null && continue
|
||||||
|
sudo systemctl enable "$u" >/dev/null 2>&1 && units+="${units:+ }$u"
|
||||||
|
done
|
||||||
|
if [[ -n "$units" ]]; then
|
||||||
|
prev="$(state_get nvidia enabled_units)"
|
||||||
|
state_set nvidia enabled_units "${prev:+$prev }$units"
|
||||||
|
fi
|
||||||
|
for pkg in $NVIDIA_LIB32_PKGS; do pacman -Q "$pkg" >/dev/null 2>&1 || missing+=("$pkg"); done
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
info "Installing the 32-bit libraries games need: ${missing[*]}"
|
||||||
|
if sudo pacman -S --needed --noconfirm "${missing[@]}"; then
|
||||||
|
prev="$(state_get nvidia installed_pkgs)"
|
||||||
|
state_set nvidia installed_pkgs "${prev:+$prev }${missing[*]}"
|
||||||
|
else
|
||||||
|
warn "Installing ${missing[*]} failed (is [multilib] enabled in /etc/pacman.conf?): 32-bit games may not start."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
nvidia_extras_disable() {
|
||||||
|
# Only what Steamify enabled; the 32-bit packages go with installed_pkgs.
|
||||||
|
local u
|
||||||
|
for u in $(state_get nvidia enabled_units); do sudo systemctl disable "$u" >/dev/null 2>&1; done
|
||||||
|
if [[ -f "$NVIDIA_MODPROBE" ]]; then
|
||||||
|
sudo rm -f "$NVIDIA_MODPROBE"
|
||||||
|
nvidia_rebuild_boot || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
nvidia_kernel_disable() {
|
nvidia_kernel_disable() {
|
||||||
local f changed=0; f="$(nvidia_boot_file)"
|
local f changed=0; f="$(nvidia_boot_file)"
|
||||||
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
|
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
|
||||||
|
|||||||
@@ -58,6 +58,30 @@ bootstrap_yay() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
python_hid_shim_ensure() {
|
||||||
|
# jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid, which conflicts with python-hidapi, and
|
||||||
|
# a PC can need python-hidapi (liquidctl does). Only Valve's Steam Deck controller firmware updater uses python-hid, which
|
||||||
|
# a PC doesn't run: so a placeholder package that provides python-hid keeps python-hidapi and satisfies the dependency
|
||||||
|
# (also at later updates, which a one-time --assume-installed wouldn't). It stays when the conversion goes off:
|
||||||
|
# jupiter-hw-support, which stays, depends on it.
|
||||||
|
pacman -Q python-hidapi >/dev/null 2>&1 || return 0
|
||||||
|
pacman -Q python-hid steamify-python-hid-shim >/dev/null 2>&1 && return 0
|
||||||
|
local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
||||||
|
warn "python-hidapi is installed (liquidctl and others need it) and conflicts with python-hid, which Steam Deck's tools ask for: keeping python-hidapi, with a small placeholder package for python-hid."
|
||||||
|
sudo pacman -S --needed --noconfirm base-devel >/dev/null || { err "Installing the build tools failed."; return 1; }
|
||||||
|
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" hid-shim.XXXXXX)" || return 1
|
||||||
|
patch_file python-hid-shim.PKGBUILD > "$dir/PKGBUILD" || { rm -rf "$dir"; return 1; }
|
||||||
|
if ! (cd "$dir" && makepkg -f --noconfirm >/dev/null) ||
|
||||||
|
! pkg="$(ls "$dir"/steamify-python-hid-shim-*.pkg.tar.* 2>/dev/null | head -1)" ||
|
||||||
|
! sudo pacman -U --noconfirm "$pkg"; then
|
||||||
|
rm -rf "$dir"
|
||||||
|
err "Couldn't set up the python-hid placeholder: python-hidapi and python-hid conflict, so the packages can't be installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
rm -rf "$dir"
|
||||||
|
ok "python-hidapi kept; python-hid is covered by a placeholder."
|
||||||
|
}
|
||||||
|
|
||||||
install_required_packages() {
|
install_required_packages() {
|
||||||
# Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses.
|
# Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses.
|
||||||
local -a MISSING
|
local -a MISSING
|
||||||
@@ -65,6 +89,7 @@ install_required_packages() {
|
|||||||
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
|
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
|
||||||
|
|
||||||
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
||||||
|
python_hid_shim_ensure || return 1
|
||||||
info "Installing missing packages: ${MISSING[*]}"
|
info "Installing missing packages: ${MISSING[*]}"
|
||||||
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
|
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -140,6 +140,15 @@ EOF
|
|||||||
remove_sddm_base_autologin
|
remove_sddm_base_autologin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_login_release() {
|
||||||
|
# The SteamOS conversion logs in by itself, and picks the session (gamescope, or the desktop with "Boot into"): the
|
||||||
|
# desktop autologin above, which sorts last, would pin the Plasma session and "Return to Gaming Mode" would open KDE
|
||||||
|
# again. Called when the conversion is turned on; turning it off sets it up again (gaming_disable).
|
||||||
|
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
||||||
|
info "The SteamOS conversion logs in by itself: removing the desktop autologin of single user mode."
|
||||||
|
sudo rm -f "$SINGLE_AUTOLOGIN"
|
||||||
|
}
|
||||||
|
|
||||||
single_login_disable() {
|
single_login_disable() {
|
||||||
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
||||||
sudo rm -f "$SINGLE_AUTOLOGIN"
|
sudo rm -f "$SINGLE_AUTOLOGIN"
|
||||||
|
|||||||
+43
-15
@@ -5,35 +5,63 @@
|
|||||||
|
|
||||||
steam_enable() {
|
steam_enable() {
|
||||||
info "Applying non-optional SteamOS environment & keyboard fixes..."
|
info "Applying non-optional SteamOS environment & keyboard fixes..."
|
||||||
local steam_env_dir systemd_user_dir
|
local steam_env_dir
|
||||||
steam_env_dir="$HOME/.config/environment.d"
|
steam_env_dir="$HOME/.config/environment.d"
|
||||||
mkdir -p "$steam_env_dir"
|
mkdir -p "$steam_env_dir"
|
||||||
|
|
||||||
# 2. Prevent KDE Wayland from blocking the virtual keyboard overlay
|
# 2. Prevent KDE Wayland from blocking the virtual keyboard overlay
|
||||||
echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf"
|
echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf"
|
||||||
|
|
||||||
# 3. Setup robust background systemd service for Steam autostart on Desktop Mode
|
ok "Steam UI parameters and keyboard fix deployed successfully."
|
||||||
systemd_user_dir="$HOME/.config/systemd/user"
|
}
|
||||||
mkdir -p "$systemd_user_dir"
|
|
||||||
|
|
||||||
service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service"
|
# Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
|
||||||
|
# no window) on the Plasma desktop. It is Steam's own autostart entry, the file
|
||||||
|
# Steam's setting "Run Steam when my computer starts" creates and removes, so
|
||||||
|
# that setting shows what Steamify did (and the other way around). Steam's copy
|
||||||
|
# is the system steam.desktop; ours has -silent in its Exec line.
|
||||||
|
STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop"
|
||||||
|
STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop
|
||||||
|
|
||||||
# Clean out old .desktop shortcut so they don't fight
|
silent_status() {
|
||||||
rm -f "$HOME/.config/autostart/steam.desktop"
|
# The old systemd unit counts as on too (until it is migrated by an update of this option).
|
||||||
|
grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" ||
|
||||||
|
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
||||||
|
}
|
||||||
|
|
||||||
# Reload user systemd context and activate the background loop
|
silent_old_unit_remove() {
|
||||||
|
# Before 2.11.0 the option was a systemd user unit: it would start Steam a second time.
|
||||||
|
local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||||
|
[[ -f "$unit" ]] || return 0
|
||||||
|
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
||||||
|
rm -f "$unit"
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
user_systemctl enable --now steam-desktop-autostart.service
|
}
|
||||||
|
|
||||||
ok "Steam UI parameters and keyboard autostart deployed successfully."
|
silent_enable() {
|
||||||
|
silent_old_unit_remove
|
||||||
|
mkdir -p "$(dirname "$STEAM_AUTOSTART")"
|
||||||
|
if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then
|
||||||
|
sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART"
|
||||||
|
fi
|
||||||
|
silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \
|
||||||
|
'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART"
|
||||||
|
ok "Steam starts silently on the desktop from the next login."
|
||||||
|
}
|
||||||
|
|
||||||
|
silent_disable() {
|
||||||
|
silent_old_unit_remove
|
||||||
|
silent_status && rm -f "$STEAM_AUTOSTART"
|
||||||
|
ok "Steam no longer starts by itself on the desktop."
|
||||||
}
|
}
|
||||||
|
|
||||||
steam_disable() {
|
steam_disable() {
|
||||||
info "Removing Steam desktop autostart..."
|
info "Removing Steam desktop settings..."
|
||||||
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
# The autostart entry is the `silent` option's: removed with it, and here
|
||||||
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \
|
# too for when the conversion goes off by itself.
|
||||||
"$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
silent_status && silent_disable
|
||||||
user_systemctl daemon-reload
|
silent_old_unit_remove
|
||||||
|
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
||||||
ok "Steam desktop settings removed (takes full effect at next login)."
|
ok "Steam desktop settings removed (takes full effect at next login)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-6
@@ -56,7 +56,7 @@ steamgame_steam_busy() {
|
|||||||
|
|
||||||
steamgame_edit() {
|
steamgame_edit() {
|
||||||
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
||||||
# again if it was running (through our autostart unit when that's there).
|
# again if it was running (silently, in the tray).
|
||||||
local was_running=false i
|
local was_running=false i
|
||||||
if pgrep -x steam >/dev/null; then
|
if pgrep -x steam >/dev/null; then
|
||||||
steamgame_steam_busy && return 1
|
steamgame_steam_busy && return 1
|
||||||
@@ -72,11 +72,7 @@ steamgame_edit() {
|
|||||||
fi
|
fi
|
||||||
"$1"; local rc=$?
|
"$1"; local rc=$?
|
||||||
if [[ "$was_running" == true ]]; then
|
if [[ "$was_running" == true ]]; then
|
||||||
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
|
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
||||||
user_systemctl start steam-desktop-autostart.service
|
|
||||||
else
|
|
||||||
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
info "Steam is starting again."
|
info "Steam is starting again."
|
||||||
fi
|
fi
|
||||||
return "$rc"
|
return "$rc"
|
||||||
|
|||||||
@@ -407,9 +407,12 @@ wifi_backend_disable() {
|
|||||||
|
|
||||||
serial_enable() {
|
serial_enable() {
|
||||||
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
||||||
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null &&
|
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null ||
|
||||||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
|
||||||
{ err "Making the serial number readable for Steam failed."; return 1; }
|
{ err "Making the serial number readable for Steam failed."; return 1; }
|
||||||
|
# The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot).
|
||||||
|
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" 2>/dev/null ||
|
||||||
|
info "The serial number becomes readable for Steam at the next boot."
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_disable() {
|
serial_disable() {
|
||||||
|
|||||||
+22
-7
@@ -106,17 +106,32 @@ theme_enable() {
|
|||||||
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
||||||
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
|
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
|
||||||
{ err "lookandfeeltool failed."; return 1; }
|
{ err "lookandfeeltool failed."; return 1; }
|
||||||
# The new layout has a new launcher, without single user's settings.
|
# The new layout has a new launcher, without single user's settings, and the default taskbar pins.
|
||||||
if single_status; then
|
sleep 3
|
||||||
sleep 3
|
stop_plasmashell_for_edit
|
||||||
stop_plasmashell_for_edit
|
taskbar_drop_discover
|
||||||
single_launcher
|
single_status && single_launcher
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
fi
|
|
||||||
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
||||||
ok "Vapor theme active."
|
ok "Vapor theme active."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskbar_drop_discover() {
|
||||||
|
# Plasma's default taskbar pins Discover, which CachyOS doesn't install: the pin shows as a
|
||||||
|
# blank icon. Pin what CachyOS's own layout pins (/etc/skel) instead. Not when Discover is
|
||||||
|
# installed, and only on a taskbar that still has the default pins (no launchers key).
|
||||||
|
# Edit only while plasmashell is stopped.
|
||||||
|
[[ -e /usr/share/applications/org.kde.discover.desktop ]] && return 0
|
||||||
|
local applet grp
|
||||||
|
for applet in $(plasma_applets org.kde.plasma.icontasks); do
|
||||||
|
grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General"
|
||||||
|
[[ -n "$(kreadconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
|
||||||
|
--group Applets --group "${applet#*:}" --group Configuration --group General --key launchers)" ]] && continue
|
||||||
|
kset theme plasma-org.kde.plasma.desktop-appletsrc "$grp" launchers \
|
||||||
|
'applications:systemsettings.desktop,preferred://filemanager,preferred://browser'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
theme_disable() {
|
theme_disable() {
|
||||||
extras_disable
|
extras_disable
|
||||||
info "Restoring the previous desktop look and layout..."
|
info "Restoring the previous desktop look and layout..."
|
||||||
|
|||||||
@@ -16,3 +16,9 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
|
|||||||
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
||||||
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
||||||
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
||||||
|
| `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file |
|
||||||
|
| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (CI builds it per CPU level; here it is only the local-build fallback) (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` |
|
||||||
|
| `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) |
|
||||||
|
| `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages |
|
||||||
|
| `gamescope-ui-native.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Small patch after the GBM one: keeps Steam's UI X server at the display's size when Steam (with `-steamos3`) asks for 1920x1080; `gamescope_xwayland_ui_native=0` turns it off |
|
||||||
|
| `gamescope-display-wrapper.sh` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Installed as `gamescope` in Steamify's bin folder and put first in the gaming session's PATH: starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate (modetest + `kwinoutputconfig.json`) |
|
||||||
@@ -0,0 +1,621 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* CEC driver for ChromeOS Embedded Controller
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 BayLibre, SAS
|
||||||
|
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/cec.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_data/cros_ec_commands.h>
|
||||||
|
#include <linux/platform_data/cros_ec_proto.h>
|
||||||
|
#include <media/cec.h>
|
||||||
|
#include <media/cec-notifier.h>
|
||||||
|
|
||||||
|
#define DRV_NAME "cros-ec-cec"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cros_ec_cec_port - Driver data for a single EC CEC port
|
||||||
|
*
|
||||||
|
* @port_num: port number
|
||||||
|
* @adap: CEC adapter
|
||||||
|
* @notify: CEC notifier pointer
|
||||||
|
* @rx_msg: storage for a received message
|
||||||
|
* @cros_ec_cec: pointer to the parent struct
|
||||||
|
*/
|
||||||
|
struct cros_ec_cec_port {
|
||||||
|
int port_num;
|
||||||
|
struct cec_adapter *adap;
|
||||||
|
struct cec_notifier *notify;
|
||||||
|
struct cec_msg rx_msg;
|
||||||
|
struct cros_ec_cec *cros_ec_cec;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cros_ec_cec - Driver data for EC CEC
|
||||||
|
*
|
||||||
|
* @cros_ec: Pointer to EC device
|
||||||
|
* @notifier: Notifier info for responding to EC events
|
||||||
|
* @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.
|
||||||
|
* @num_ports: Number of CEC ports
|
||||||
|
* @ports: Array of ports
|
||||||
|
*/
|
||||||
|
struct cros_ec_cec {
|
||||||
|
struct cros_ec_device *cros_ec;
|
||||||
|
struct notifier_block notifier;
|
||||||
|
int write_cmd_version;
|
||||||
|
int num_ports;
|
||||||
|
struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,
|
||||||
|
uint8_t *msg, uint8_t len)
|
||||||
|
{
|
||||||
|
if (len > CEC_MAX_MSG_SIZE)
|
||||||
|
len = CEC_MAX_MSG_SIZE;
|
||||||
|
|
||||||
|
port->rx_msg.len = len;
|
||||||
|
memcpy(port->rx_msg.msg, msg, len);
|
||||||
|
|
||||||
|
cec_received_msg(port->adap, &port->rx_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
|
||||||
|
{
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
uint8_t *cec_message = cros_ec->event_data.data.cec_message;
|
||||||
|
unsigned int len = cros_ec->event_size;
|
||||||
|
struct cros_ec_cec_port *port;
|
||||||
|
/*
|
||||||
|
* There are two ways of receiving CEC messages:
|
||||||
|
* 1. Old EC firmware which only supports one port sends the data in a
|
||||||
|
* cec_message MKBP event.
|
||||||
|
* 2. New EC firmware which supports multiple ports uses
|
||||||
|
* EC_MKBP_CEC_HAVE_DATA to notify that data is ready and
|
||||||
|
* EC_CMD_CEC_READ_MSG to read it.
|
||||||
|
* Check that the EC only has one CEC port, and then we can assume the
|
||||||
|
* message is from port 0.
|
||||||
|
*/
|
||||||
|
if (cros_ec_cec->num_ports != 1) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"received cec_message on device with %d ports\n",
|
||||||
|
cros_ec_cec->num_ports);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
port = cros_ec_cec->ports[0];
|
||||||
|
|
||||||
|
cros_ec_cec_received_message(port, cec_message, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)
|
||||||
|
{
|
||||||
|
struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;
|
||||||
|
struct ec_params_cec_read params = {
|
||||||
|
.port = port->port_num,
|
||||||
|
};
|
||||||
|
struct ec_response_cec_read response;
|
||||||
|
int ret = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
/* NOTE read as many messages as we can, return value from cros_ec_cmd
|
||||||
|
* here should either equal to the bytes transferred or a negative
|
||||||
|
* error code, so as long as we get positive integers we are
|
||||||
|
* reading messages!
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms,
|
||||||
|
sizeof(params), &response, sizeof(response));
|
||||||
|
if (ret > 0) {
|
||||||
|
++count;
|
||||||
|
cros_ec_cec_received_message(port, response.msg, response.msg_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ret > 0);
|
||||||
|
|
||||||
|
if (ret < 0 && count == 0) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"error reading CEC message on EC: %d\n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
|
||||||
|
{
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
uint32_t cec_events = cros_ec->event_data.data.cec_events;
|
||||||
|
uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
|
||||||
|
uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
|
||||||
|
struct cros_ec_cec_port *port;
|
||||||
|
|
||||||
|
if (port_num >= cros_ec_cec->num_ports) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"received CEC event for invalid port %d\n", port_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
port = cros_ec_cec->ports[port_num];
|
||||||
|
|
||||||
|
if (events & EC_MKBP_CEC_SEND_OK)
|
||||||
|
cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
|
||||||
|
|
||||||
|
/* FW takes care of all retries, tell core to avoid more retries */
|
||||||
|
if (events & EC_MKBP_CEC_SEND_FAILED)
|
||||||
|
cec_transmit_attempt_done(port->adap,
|
||||||
|
CEC_TX_STATUS_MAX_RETRIES |
|
||||||
|
CEC_TX_STATUS_NACK);
|
||||||
|
|
||||||
|
if (events & EC_MKBP_CEC_HAVE_DATA)
|
||||||
|
cros_ec_cec_read_message(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_event(struct notifier_block *nb,
|
||||||
|
unsigned long queued_during_suspend,
|
||||||
|
void *_notify)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec *cros_ec_cec;
|
||||||
|
struct cros_ec_device *cros_ec;
|
||||||
|
|
||||||
|
cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier);
|
||||||
|
cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
|
||||||
|
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) {
|
||||||
|
handle_cec_event(cros_ec_cec);
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) {
|
||||||
|
handle_cec_message(cros_ec_cec);
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec_port *port = adap->priv;
|
||||||
|
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
struct ec_params_cec_set params = {
|
||||||
|
.cmd = CEC_CMD_LOGICAL_ADDRESS,
|
||||||
|
.port = port->port_num,
|
||||||
|
.val = logical_addr,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
||||||
|
NULL, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"error setting CEC logical address on EC: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
||||||
|
u32 signal_free_time, struct cec_msg *cec_msg)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec_port *port = adap->priv;
|
||||||
|
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
struct ec_params_cec_write params;
|
||||||
|
struct ec_params_cec_write_v1 params_v1;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cros_ec_cec->write_cmd_version == 0) {
|
||||||
|
memcpy(params.msg, cec_msg->msg, cec_msg->len);
|
||||||
|
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms,
|
||||||
|
cec_msg->len, NULL, 0);
|
||||||
|
} else {
|
||||||
|
params_v1.port = port->port_num;
|
||||||
|
params_v1.msg_len = cec_msg->len;
|
||||||
|
memcpy(params_v1.msg, cec_msg->msg, cec_msg->len);
|
||||||
|
ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version,
|
||||||
|
EC_CMD_CEC_WRITE_MSG, ¶ms_v1,
|
||||||
|
sizeof(params_v1), NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"error writing CEC msg on EC: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec_port *port = adap->priv;
|
||||||
|
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
struct ec_params_cec_set params = {
|
||||||
|
.cmd = CEC_CMD_ENABLE,
|
||||||
|
.port = port->port_num,
|
||||||
|
.val = enable,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
||||||
|
NULL, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"error %sabling CEC on EC: %d\n",
|
||||||
|
(enable ? "en" : "dis"), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct cec_adap_ops cros_ec_cec_ops = {
|
||||||
|
.adap_enable = cros_ec_cec_adap_enable,
|
||||||
|
.adap_log_addr = cros_ec_cec_set_log_addr,
|
||||||
|
.adap_transmit = cros_ec_cec_transmit,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int cros_ec_cec_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
enable_irq_wake(cros_ec_cec->cros_ec->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
disable_irq_wake(cros_ec_cec->cros_ec->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
|
||||||
|
cros_ec_cec_suspend, cros_ec_cec_resume);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Specify the DRM device name handling the HDMI output and the HDMI connector
|
||||||
|
* corresponding to each CEC port. The order of connectors must match the order
|
||||||
|
* in the EC (first connector is EC port 0, ...), and the number of connectors
|
||||||
|
* must match the number of ports in the EC (which can be queried using the
|
||||||
|
* EC_CMD_CEC_PORT_COUNT host command).
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct cec_dmi_match {
|
||||||
|
const char *sys_vendor;
|
||||||
|
const char *product_name;
|
||||||
|
const char *devname;
|
||||||
|
const char *const *conns;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const port_b_conns[] = { "Port B", NULL };
|
||||||
|
static const char *const port_c_conns[] = { "Port C", NULL };
|
||||||
|
static const char *const port_db_conns[] = { "Port D", "Port B", NULL };
|
||||||
|
static const char *const port_ba_conns[] = { "Port B", "Port A", NULL };
|
||||||
|
static const char *const port_ab_conns[] = { "Port A", "Port B", NULL };
|
||||||
|
static const char *const port_d_conns[] = { "Port D", NULL };
|
||||||
|
|
||||||
|
static const struct cec_dmi_match cec_dmi_match_table[] = {
|
||||||
|
/* AMD Lilac */
|
||||||
|
{ "AMD", "Lilac", "0000:03:00.0", port_c_conns },
|
||||||
|
/* Valve Fremont */
|
||||||
|
{ "OEM", "F7F", "0000:03:00.0", port_c_conns },
|
||||||
|
{ "Valve", "Fremont", "0000:03:00.0", port_c_conns },
|
||||||
|
/* Google Fizz */
|
||||||
|
{ "Google", "Fizz", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Brask */
|
||||||
|
{ "Google", "Brask", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Moli */
|
||||||
|
{ "Google", "Moli", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Kinox */
|
||||||
|
{ "Google", "Kinox", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Kuldax */
|
||||||
|
{ "Google", "Kuldax", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Aurash */
|
||||||
|
{ "Google", "Aurash", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Gladios */
|
||||||
|
{ "Google", "Gladios", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Lisbon */
|
||||||
|
{ "Google", "Lisbon", "0000:00:02.0", port_b_conns },
|
||||||
|
/* Google Dibbi */
|
||||||
|
{ "Google", "Dibbi", "0000:00:02.0", port_db_conns },
|
||||||
|
/* Google Constitution */
|
||||||
|
{ "Google", "Constitution", "0000:00:02.0", port_ba_conns },
|
||||||
|
/* Google Boxy */
|
||||||
|
{ "Google", "Boxy", "0000:00:02.0", port_d_conns },
|
||||||
|
/* Google Taranza */
|
||||||
|
{ "Google", "Taranza", "0000:00:02.0", port_db_conns },
|
||||||
|
/* Google Dexi */
|
||||||
|
{ "Google", "Dexi", "0000:00:02.0", port_db_conns },
|
||||||
|
/* Google Dita */
|
||||||
|
{ "Google", "Dita", "0000:00:02.0", port_db_conns },
|
||||||
|
/* Google Dirks */
|
||||||
|
{ "Google", "Dirks", "0000:00:02.0", port_ab_conns },
|
||||||
|
/* Google Moxie */
|
||||||
|
{ "Google", "Moxie", "0000:00:02.0", port_b_conns },
|
||||||
|
/* AMD Lilac */
|
||||||
|
{ "AMD", "Lilac", "0000:06:00.0", port_c_conns },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
||||||
|
const char * const **conns)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) {
|
||||||
|
const struct cec_dmi_match *m = &cec_dmi_match_table[i];
|
||||||
|
|
||||||
|
if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
|
||||||
|
dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
|
||||||
|
struct device *d;
|
||||||
|
|
||||||
|
/* Find the device, bail out if not yet registered */
|
||||||
|
d = bus_find_device_by_name(&pci_bus_type, NULL,
|
||||||
|
m->devname);
|
||||||
|
if (!d)
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
put_device(d);
|
||||||
|
*conns = m->conns;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hardware support must be added in the cec_dmi_match_table */
|
||||||
|
dev_warn(dev, "CEC notifier not configured for this hardware\n");
|
||||||
|
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
||||||
|
const char * const **conns)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec)
|
||||||
|
{
|
||||||
|
struct ec_response_cec_port_count response;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL,
|
||||||
|
0, &response, sizeof(response));
|
||||||
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* Old EC firmware only supports one port and does not support
|
||||||
|
* the port count command, so fall back to assuming one port.
|
||||||
|
*/
|
||||||
|
cros_ec_cec->num_ports = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.port_count == 0) {
|
||||||
|
dev_err(cros_ec_cec->cros_ec->dev,
|
||||||
|
"EC reports 0 CEC ports\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.port_count > EC_CEC_MAX_PORTS) {
|
||||||
|
dev_err(cros_ec_cec->cros_ec->dev,
|
||||||
|
"EC reports too many ports: %d\n", response.port_count);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cros_ec_cec->num_ports = response.port_count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
|
||||||
|
{
|
||||||
|
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||||
|
struct ec_params_get_cmd_versions_v1 params = {
|
||||||
|
.cmd = EC_CMD_CEC_WRITE_MSG,
|
||||||
|
};
|
||||||
|
struct ec_response_get_cmd_versions response;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms,
|
||||||
|
sizeof(params), &response, sizeof(response));
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"error getting CEC write command version: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.version_mask & EC_VER_MASK(1)) {
|
||||||
|
cros_ec_cec->write_cmd_version = 1;
|
||||||
|
} else {
|
||||||
|
if (cros_ec_cec->num_ports != 1) {
|
||||||
|
dev_err(cros_ec->dev,
|
||||||
|
"v0 write command only supports 1 port, %d reported\n",
|
||||||
|
cros_ec_cec->num_ports);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
cros_ec_cec->write_cmd_version = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_init_port(struct device *dev,
|
||||||
|
struct cros_ec_cec *cros_ec_cec,
|
||||||
|
int port_num, struct device *hdmi_dev,
|
||||||
|
const char * const *conns)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec_port *port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||||
|
if (!port)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
port->cros_ec_cec = cros_ec_cec;
|
||||||
|
port->port_num = port_num;
|
||||||
|
|
||||||
|
port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME,
|
||||||
|
CEC_CAP_DEFAULTS |
|
||||||
|
CEC_CAP_CONNECTOR_INFO, 1);
|
||||||
|
if (IS_ERR(port->adap))
|
||||||
|
return PTR_ERR(port->adap);
|
||||||
|
|
||||||
|
if (!conns[port_num]) {
|
||||||
|
dev_err(dev, "no conn for port %d\n", port_num);
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto out_probe_adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
|
||||||
|
port->adap);
|
||||||
|
if (!port->notify) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_probe_adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cec_register_adapter(port->adap, dev);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_probe_notify;
|
||||||
|
|
||||||
|
cros_ec_cec->ports[port_num] = port;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_probe_notify:
|
||||||
|
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||||
|
out_probe_adapter:
|
||||||
|
cec_delete_adapter(port->adap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_ec_cec_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
|
||||||
|
struct cros_ec_cec *cros_ec_cec;
|
||||||
|
struct cros_ec_cec_port *port;
|
||||||
|
struct device *hdmi_dev;
|
||||||
|
const char * const *conns = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
|
||||||
|
if (IS_ERR(hdmi_dev))
|
||||||
|
return PTR_ERR(hdmi_dev);
|
||||||
|
|
||||||
|
cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!cros_ec_cec)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, cros_ec_cec);
|
||||||
|
cros_ec_cec->cros_ec = cros_ec;
|
||||||
|
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
|
ret = cros_ec_cec_get_num_ports(cros_ec_cec);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||||
|
ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
|
||||||
|
hdmi_dev, conns);
|
||||||
|
if (ret)
|
||||||
|
goto unregister_ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get CEC events from the EC. */
|
||||||
|
cros_ec_cec->notifier.notifier_call = cros_ec_cec_event;
|
||||||
|
ret = blocking_notifier_chain_register(&cros_ec->event_notifier,
|
||||||
|
&cros_ec_cec->notifier);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to register notifier\n");
|
||||||
|
goto unregister_ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unregister_ports:
|
||||||
|
/*
|
||||||
|
* Unregister any adapters which have been registered. We don't add the
|
||||||
|
* port to the array until the adapter has been registered successfully,
|
||||||
|
* so any non-NULL ports must have been registered.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||||
|
port = cros_ec_cec->ports[i];
|
||||||
|
if (!port)
|
||||||
|
break;
|
||||||
|
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||||
|
cec_unregister_adapter(port->adap);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cros_ec_cec_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct cros_ec_cec_port *port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blocking_notifier_chain_unregister() only fails if the notifier isn't
|
||||||
|
* in the list. We know it was added to it by .probe(), so there should
|
||||||
|
* be no need for error checking. Be cautious and still check.
|
||||||
|
*/
|
||||||
|
ret = blocking_notifier_chain_unregister(
|
||||||
|
&cros_ec_cec->cros_ec->event_notifier,
|
||||||
|
&cros_ec_cec->notifier);
|
||||||
|
if (ret)
|
||||||
|
dev_err(dev, "failed to unregister notifier\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||||
|
port = cros_ec_cec->ports[i];
|
||||||
|
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||||
|
cec_unregister_adapter(port->adap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct platform_device_id cros_ec_cec_id[] = {
|
||||||
|
{ DRV_NAME, 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
|
||||||
|
|
||||||
|
static struct platform_driver cros_ec_cec_driver = {
|
||||||
|
.probe = cros_ec_cec_probe,
|
||||||
|
.remove = cros_ec_cec_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = DRV_NAME,
|
||||||
|
.pm = &cros_ec_cec_pm_ops,
|
||||||
|
},
|
||||||
|
.id_table = cros_ec_cec_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(cros_ec_cec_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");
|
||||||
|
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Steamify: gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode,
|
||||||
|
# which many monitors declare as 60 Hz (the faster modes sit in an extension block of the EDID). This starts it the way the
|
||||||
|
# desktop runs that display: the mode KDE has saved for the connected display (System Settings > Display), when the display
|
||||||
|
# still has it, else its biggest mode at the highest refresh rate.
|
||||||
|
# Read at every session start (modetest, part of libdrm which gamescope needs, and KDE's ~/.config/kwinoutputconfig.json), so
|
||||||
|
# changing the resolution in KDE, another monitor or a TV just works. Anything unclear (no modetest output, no modes, more than
|
||||||
|
# one display connected: gamescope chooses which one it uses) leaves gamescope's own choice alone.
|
||||||
|
real=/usr/bin/gamescope
|
||||||
|
|
||||||
|
modes() {
|
||||||
|
# One line per mode of every connected connector: "<connector> <width> <height> <refresh>"
|
||||||
|
local m
|
||||||
|
for m in nvidia-drm amdgpu i915 xe nouveau radeon; do
|
||||||
|
timeout 10 modetest -M "$m" -c 2>/dev/null | awk '
|
||||||
|
/^[0-9]+[ \t]+[0-9]+[ \t]+(connected|disconnected|unknown)/ { conn = ($3 == "connected") ? $4 : ""; next }
|
||||||
|
conn != "" && /^[ \t]+#[0-9]+ [0-9]+x[0-9]+ [0-9.]+ / && !/interlace/ {
|
||||||
|
split($2, wh, "x"); printf "%s %d %d %.0f\n", conn, wh[1], wh[2], $3
|
||||||
|
}'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
kde_mode() {
|
||||||
|
# kde_mode <connector>: "<width> <height> <refresh>" as KDE has it saved for that connector, or nothing.
|
||||||
|
python3 -I - "$1" "${XDG_CONFIG_HOME:-$HOME/.config}/kwinoutputconfig.json" 2>/dev/null << 'EOF'
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
for block in json.load(open(sys.argv[2])):
|
||||||
|
if block.get("name") == "outputs":
|
||||||
|
for o in block.get("data", []):
|
||||||
|
m = o.get("mode")
|
||||||
|
if o.get("connectorName") == sys.argv[1] and m:
|
||||||
|
print(m["width"], m["height"], round(m["refreshRate"] / 1000))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
args=()
|
||||||
|
all="$(modes)"
|
||||||
|
conn="$(awk '{print $1}' <<< "$all" | sort -u)"
|
||||||
|
if [[ -n "$conn" && "$(wc -l <<< "$conn")" == 1 ]]; then
|
||||||
|
read -r w h r <<< "$(kde_mode "$conn")"
|
||||||
|
# KDE's mode only counts when the display really has it (a refresh rate within 1 Hz).
|
||||||
|
if [[ -z "${w:-}" ]] || ! awk -v w="$w" -v h="${h:-0}" -v r="${r:-0}" '$2 == w && $3 == h && ($4 - r < 2 && r - $4 < 2) {f = 1} END {exit !f}' <<< "$all"; then
|
||||||
|
read -r _ w h r < <(awk '{print $2 * $3, $2, $3, $4}' <<< "$all" | sort -k1,1nr -k4,4nr | head -1 | awk '{print "x", $2, $3, $4}')
|
||||||
|
fi
|
||||||
|
[[ "${w:-0}" -gt 0 && "${h:-0}" -gt 0 && "${r:-0}" -gt 0 ]] && args=(-W "$w" -H "$h" -r "$r")
|
||||||
|
fi
|
||||||
|
if [[ "${1:-}" == --print-args ]]; then echo "${args[*]}"; exit 0; fi
|
||||||
|
exec "$real" "${args[@]}" "$@"
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,128 @@
|
|||||||
|
# Maintainer: theupriser
|
||||||
|
# Based on Arch Linux's gamescope PKGBUILD (Maxime Gauduin, Giancarlo Razzolini, Sven-Hendrik Haase and contributors).
|
||||||
|
#
|
||||||
|
# gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1).
|
||||||
|
# The patches are gamescope-gbm-scanout.patch and gamescope-ui-native.patch (next to this file, applied in this order); see the
|
||||||
|
# README for where they come from.
|
||||||
|
# UPSTREAM_VERSION (next to this file) names the gamescope tag the patches are made for.
|
||||||
|
|
||||||
|
pkgname=steamify-gamescope-nvidia
|
||||||
|
_srcname=gamescope
|
||||||
|
pkgver=3.16.31
|
||||||
|
pkgrel=3
|
||||||
|
pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)'
|
||||||
|
arch=(x86_64)
|
||||||
|
url=https://github.com/theupriser/steamify-gamescope-nvidia
|
||||||
|
license=(
|
||||||
|
BSD-2-Clause
|
||||||
|
BSD-3-Clause
|
||||||
|
LicenseRef-Reshade
|
||||||
|
)
|
||||||
|
provides=("gamescope=$pkgver")
|
||||||
|
conflicts=(gamescope gamescope-nvidia-gbm)
|
||||||
|
replaces=(gamescope-nvidia-gbm)
|
||||||
|
depends=(
|
||||||
|
glibc
|
||||||
|
mesa
|
||||||
|
libstdc++
|
||||||
|
libgcc
|
||||||
|
lcms2
|
||||||
|
libavif
|
||||||
|
libcap.so
|
||||||
|
libdecor
|
||||||
|
libdrm
|
||||||
|
libei
|
||||||
|
libinput
|
||||||
|
libpipewire-0.3.so
|
||||||
|
libx11
|
||||||
|
libxcb
|
||||||
|
libxcomposite
|
||||||
|
libxcursor
|
||||||
|
libxdamage
|
||||||
|
libxext
|
||||||
|
libxfixes
|
||||||
|
libxi
|
||||||
|
libxkbcommon.so
|
||||||
|
libxmu
|
||||||
|
libxrender
|
||||||
|
libxres
|
||||||
|
libxtst
|
||||||
|
libxxf86vm
|
||||||
|
luajit
|
||||||
|
pixman
|
||||||
|
sdl2
|
||||||
|
seatd
|
||||||
|
systemd-libs
|
||||||
|
vulkan-icd-loader
|
||||||
|
wayland
|
||||||
|
xcb-util-errors
|
||||||
|
xcb-util-wm
|
||||||
|
xorg-server-xwayland
|
||||||
|
)
|
||||||
|
makedepends=(
|
||||||
|
benchmark
|
||||||
|
cmake
|
||||||
|
git
|
||||||
|
glslang
|
||||||
|
meson
|
||||||
|
ninja
|
||||||
|
vulkan-headers
|
||||||
|
wayland-protocols
|
||||||
|
catch2
|
||||||
|
)
|
||||||
|
source=(
|
||||||
|
gamescope::git+https://github.com/ValveSoftware/gamescope.git#commit=${pkgver}
|
||||||
|
gamescope-gbm-scanout.patch
|
||||||
|
gamescope-ui-native.patch
|
||||||
|
git+https://gitlab.freedesktop.org/emersion/libdisplay-info.git
|
||||||
|
git+https://gitlab.freedesktop.org/emersion/libliftoff.git
|
||||||
|
git+https://github.com/ValveSoftware/openvr.git
|
||||||
|
git+https://github.com/Joshua-Ashton/reshade.git
|
||||||
|
git+https://github.com/KhronosGroup/SPIRV-Headers.git
|
||||||
|
git+https://github.com/Joshua-Ashton/vkroots.git
|
||||||
|
git+https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||||
|
)
|
||||||
|
b2sums=('SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP'
|
||||||
|
'SKIP')
|
||||||
|
|
||||||
|
prepare() {
|
||||||
|
cd gamescope
|
||||||
|
|
||||||
|
# GBM scan-out for NVIDIA. If it no longer applies to this gamescope version, stop here: the build must not
|
||||||
|
# silently produce an unpatched gamescope under this package's name.
|
||||||
|
git apply --check ../gamescope-gbm-scanout.patch || { echo "gbm patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
||||||
|
git apply ../gamescope-gbm-scanout.patch
|
||||||
|
git apply --check ../gamescope-ui-native.patch || { echo "ui-native patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
||||||
|
git apply ../gamescope-ui-native.patch
|
||||||
|
|
||||||
|
meson subprojects download
|
||||||
|
|
||||||
|
for submodule in src/reshade subprojects/{libdisplay-info,libliftoff,openvr,vkroots,wlroots} thirdparty/SPIRV-Headers; do
|
||||||
|
git submodule init ${submodule}
|
||||||
|
git config submodule.${submodule}.url ../${submodule##*/}
|
||||||
|
done
|
||||||
|
git -c protocol.file.allow=always submodule update
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
arch-meson gamescope build \
|
||||||
|
-Dforce_fallback_for=glm,stb,libdisplay-info,libliftoff,vkroots \
|
||||||
|
-Dpipewire=enabled
|
||||||
|
meson compile -C build
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
DESTDIR="${pkgdir}" meson install -C build \
|
||||||
|
--skip-subprojects
|
||||||
|
install -Dm 644 gamescope/LICENSE -t "${pkgdir}"/usr/share/licenses/${pkgname}/
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ts=2 sw=2 et:
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
Keeps Steam's UI X server (server 0) at the output size when Steam asks for a smaller one.
|
||||||
|
|
||||||
|
With -steamos3 (what gamescope-session-cachyos passes) Steam sets its UI to 1920x1080 right after it starts
|
||||||
|
(GAMESCOPE_XWAYLAND_MODE_CONTROL), so on a bigger display, and on one that isn't 16:9, the whole interface is a scaled-up
|
||||||
|
1080p picture. Games already run at the display's size. With this the server stays at the output size and Steam draws its
|
||||||
|
window to match; Steam's SteamOS features (settings pages, game launching) keep working. Written for Steamify on an NVIDIA
|
||||||
|
PC (RTX 5080, 3440x1440@175, tested with Steam's UI and a Proton game); not part of the farnoy patch. On by default; the
|
||||||
|
setting gamescope_xwayland_ui_native=0 (in gamescope's environment) turns it off.
|
||||||
|
Applies with `git apply` after gamescope-gbm-scanout.patch (it ignores these lines).
|
||||||
|
|
||||||
|
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
||||||
|
index 2cb5eb5..ce14c8d 100644
|
||||||
|
--- a/src/steamcompmgr.cpp
|
||||||
|
+++ b/src/steamcompmgr.cpp
|
||||||
|
@@ -129,6 +129,8 @@ LogScope g_WaitableLog("waitable");
|
||||||
|
|
||||||
|
gamescope::ConVar<bool> cv_overlay_unmultiplied_alpha{ "overlay_unmultiplied_alpha", false };
|
||||||
|
|
||||||
|
+gamescope::ConVar<bool> cv_xwayland_ui_native( "xwayland_ui_native", true, "Keep the Steam UI X server (server 0) at the output size when Steam asks for a smaller one." );
|
||||||
|
+
|
||||||
|
gamescope::ConVar<bool> cv_vr_show_forwarded_overlays{ "vr_show_forwarded_overlays", false };
|
||||||
|
|
||||||
|
std::string *g_pVROverlayKey = nullptr;
|
||||||
|
@@ -7240,6 +7242,15 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
|
||||||
|
height = std::min<int>(height, currentOutputHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Steam asks for a smaller size for its own UI (server 0, 1920x1080 with -steamos3), which makes the whole
|
||||||
|
+ // interface a scaled-up picture on a bigger display, and on one that isn't 16:9 as well. The UI server
|
||||||
|
+ // stays at the output size: Steam sizes its window to the server.
|
||||||
|
+ if ( server_idx == 0 && cv_xwayland_ui_native )
|
||||||
|
+ {
|
||||||
|
+ width = currentOutputWidth;
|
||||||
|
+ height = currentOutputHeight;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
gamescope_xwayland_server_t *server = wlserver_get_xwayland_server( server_idx );
|
||||||
|
if ( server )
|
||||||
|
{
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Maintainer: theupriser
|
||||||
|
# An empty package that only tells pacman "python-hid is there". For a PC that keeps python-hidapi (liquidctl needs it):
|
||||||
|
# the real python-hid conflicts with it, and jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid.
|
||||||
|
# Only Valve's Steam Deck controller firmware updater in jupiter-hw-support uses it, which a PC doesn't run.
|
||||||
|
# Steamify (lib/packages.sh) builds it with makepkg and installs it before the conversion's packages.
|
||||||
|
pkgname=steamify-python-hid-shim
|
||||||
|
pkgver=1
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc='Placeholder: python-hid for PCs that keep python-hidapi (they conflict)'
|
||||||
|
arch=(any)
|
||||||
|
license=(MIT)
|
||||||
|
depends=(python-hidapi)
|
||||||
|
provides=('python-hid=99')
|
||||||
|
|
||||||
|
package() {
|
||||||
|
:
|
||||||
|
}
|
||||||
@@ -7,6 +7,11 @@
|
|||||||
* leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off.
|
* leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off.
|
||||||
* Valve's kernel clears that bit at probe on Fremont (not for upstream);
|
* Valve's kernel clears that bit at probe on Fremont (not for upstream);
|
||||||
* this does the same right before power-off, for kernels without it.
|
* this does the same right before power-off, for kernels without it.
|
||||||
|
*
|
||||||
|
* What it does follows Valve's Steam Machine kernel
|
||||||
|
* (https://github.com/evlaV/linux-integration, GPL-2.0 like the rest of the
|
||||||
|
* Linux kernel); this module is Steamify's own implementation of it, also
|
||||||
|
* GPL-2.0. Not affiliated with or endorsed by Valve Corporation.
|
||||||
*/
|
*/
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
|
|||||||
@@ -12,6 +12,5 @@ in the shell code.
|
|||||||
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
|
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
|
||||||
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
|
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
|
||||||
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
|
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
|
||||||
| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (user unit) |
|
|
||||||
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
|
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
|
||||||
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
|
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Steam Background Autostart for Virtual Keyboard
|
|
||||||
After=graphical-session.target
|
|
||||||
PartOf=graphical-session.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
# Only in the Plasma desktop session; gamescope-session starts its own Steam.
|
|
||||||
ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]'
|
|
||||||
ExecStart=/usr/bin/steam -silent
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=graphical-session.target
|
|
||||||
+2
-2
@@ -15,11 +15,11 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
# Release version, see CHANGELOG.md.
|
# Release version, see CHANGELOG.md.
|
||||||
VERSION=2.10.0
|
VERSION=2.12.0
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia gamescope-nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
source "$SCRIPT_DIR/lib/$lib.sh"
|
source "$SCRIPT_DIR/lib/$lib.sh"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Tests lib/controllers.sh (extended controller support: xone, the Xbox wireless dongle, and xpadneo, Xbox Bluetooth) with a stub pacman
|
|
||||||
# and a temp home. No root, VM or hardware needed: bash tests/controllers-test.sh
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
||||||
fail=0
|
|
||||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
|
||||||
|
|
||||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
|
||||||
source lib/common.sh; source lib/state.sh; source lib/controllers.sh; source lib/menu.sh
|
|
||||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
|
||||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
|
||||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
|
||||||
kwriteconfig6() { local f="" k="" v=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; *) v="$1" ;; esac; shift; done; mkdir -p "$(dirname "$f")"; sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; }
|
|
||||||
kreadconfig6() { local f="" k=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group|--default) shift ;; esac; shift; done; sed -n "s/^$k=//p" "$f" 2>/dev/null; }
|
|
||||||
# A pretend package database.
|
|
||||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; PACMAN_FAIL=0
|
|
||||||
pacman() {
|
|
||||||
case "$1" in
|
|
||||||
-Q) local p; for p in "${@:2}"; do [[ " $PKGS " == *" $p "* ]] || return 1; done ;;
|
|
||||||
-S) [[ $PACMAN_FAIL == 1 ]] && return 1; echo "S ${*:4}" >> "$PACMAN_LOG"; PKGS+=" ${*:4}" ;;
|
|
||||||
-Rns) echo "R ${*:3}" >> "$PACMAN_LOG"; local p; for p in ${*:3}; do PKGS=" ${PKGS// $p / } "; done ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
HEADERS=0; install_kernel_headers() { HEADERS=$((HEADERS + 1)); }
|
|
||||||
|
|
||||||
check "off to begin with" '! extended_controller_support_status'
|
|
||||||
extended_controller_support_enable
|
|
||||||
check "installs the repo's xpadneo-dkms, xone-dkms and the dongle firmware" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware'
|
|
||||||
check "kernel headers are made sure of first" '[[ $HEADERS == 1 ]]'
|
|
||||||
check "what we installed is recorded" '[[ "$(state_get extended_controller_support installed_pkgs)" == "xpadneo-dkms xone-dkms xone-dongle-firmware" ]]'
|
|
||||||
check "it is on" extended_controller_support_status
|
|
||||||
n="$(wc -l < "$PACMAN_LOG")"; extended_controller_support_enable
|
|
||||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
|
||||||
extended_controller_support_disable
|
|
||||||
check "off: the three packages are removed again" '! pacman -Q xpadneo-dkms 2>/dev/null && ! pacman -Q xone-dkms 2>/dev/null && ! pacman -Q xone-dongle-firmware 2>/dev/null && [[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
|
||||||
|
|
||||||
# The AUR's xone-dkms-git conflicts with the repo's xone-dkms: it counts, and is kept.
|
|
||||||
PKGS=" xone-dkms-git xone-dongle-firmware xpadneo-dkms"; : > "$PACMAN_LOG"
|
|
||||||
check "xone-dkms-git counts as xone: already on" extended_controller_support_status
|
|
||||||
extended_controller_support_enable; extended_controller_support_disable
|
|
||||||
check "with xone-dkms-git: nothing installed and nothing removed" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q xone-dkms-git xpadneo-dkms xone-dongle-firmware'
|
|
||||||
PKGS=" xone-dkms-git"
|
|
||||||
extended_controller_support_enable
|
|
||||||
check "xone-dkms-git present: only the missing ones are installed, never xone-dkms" 'grep -q "^S xpadneo-dkms xone-dongle-firmware$" "$PACMAN_LOG" && ! pacman -Q xone-dkms 2>/dev/null'
|
|
||||||
extended_controller_support_disable
|
|
||||||
check "and off removes only those two, xone-dkms-git stays" 'pacman -Q xone-dkms-git && ! pacman -Q xpadneo-dkms 2>/dev/null'
|
|
||||||
|
|
||||||
# A failed install is an error and records nothing.
|
|
||||||
PKGS=""; PACMAN_FAIL=1
|
|
||||||
check "a failed pacman is an error" '! extended_controller_support_enable >/dev/null'
|
|
||||||
check "...and records nothing" '[[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
|
||||||
PACMAN_FAIL=0
|
|
||||||
|
|
||||||
# Packages that were already there are never removed by turning it off.
|
|
||||||
PKGS=" xpadneo-dkms xone-dkms xone-dongle-firmware"; : > "$PACMAN_LOG"
|
|
||||||
extended_controller_support_enable; extended_controller_support_disable
|
|
||||||
check "packages you had before stay" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware && [[ ! -s "$PACMAN_LOG" ]]'
|
|
||||||
|
|
||||||
# The menu.
|
|
||||||
check "offered on every PC" 'component_available extended_controller_support'
|
|
||||||
check "not preselected: it builds kernel modules for every kernel" '[[ " ${NO_PRESELECT[*]} " == *" extended_controller_support "* ]]'
|
|
||||||
check "a top-level item with a label" '[[ -z "${PARENT[extended_controller_support]:-}" && -n "${LABEL[extended_controller_support]}" ]]'
|
|
||||||
|
|
||||||
# The "new" badge: an opt-in option added after setup shows it, but is never ticked for you.
|
|
||||||
component_selectable() { return 0; }
|
|
||||||
declare -A CURRENT=([gaming]=1 [nvidia]=0 [extended_controller_support]=0 [vram]=0 [boot]=0)
|
|
||||||
rm -f "$STATE_DIR/features.state"
|
|
||||||
check "new opt-in option (conversion on, no record): the new badge" 'feature_new_optin extended_controller_support'
|
|
||||||
check "...but it is not ticked for you (not a new default option)" '! feature_new extended_controller_support'
|
|
||||||
check "...and the menu label says (new)" '[[ "$(menu_label extended_controller_support)" == *"(new)"* ]]'
|
|
||||||
check "a new default option is still ticked for you, and is not the opt-in kind" 'feature_new vram && ! feature_new_optin vram'
|
|
||||||
check "Boot into never gets the badge (it is a choice row)" '! feature_new_optin boot'
|
|
||||||
state_set_features() { kwriteconfig6 --file "$STATE_DIR/features.state" --group State --key "$1" "$2"; }
|
|
||||||
state_set_features extended_controller_support off
|
|
||||||
check "once a run recorded it as off, the badge is gone" '! feature_new_optin extended_controller_support'
|
|
||||||
rm -f "$STATE_DIR/features.state"
|
|
||||||
CURRENT[gaming]=0; CURRENT[nvidia]=1
|
|
||||||
check "on an NVIDIA PC (Gaming on NVIDIA on, no conversion) it shows too" 'feature_new_optin extended_controller_support'
|
|
||||||
CURRENT[nvidia]=0
|
|
||||||
check "with neither the conversion nor Gaming on NVIDIA on (a fresh PC) nothing is new" '! feature_new_optin extended_controller_support && ! feature_new vram'
|
|
||||||
CURRENT[gaming]=1; CURRENT[extended_controller_support]=1
|
|
||||||
check "already on: not new" '! feature_new_optin extended_controller_support'
|
|
||||||
exit $fail
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
|
|
||||||
# one: tests/nvidia-test.sh). Run from the Steamify checkout:
|
|
||||||
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
|
|
||||||
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
|
|
||||||
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
|
|
||||||
# Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help.
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
# patch_file (lib/common.sh) reads the hook script from $SCRIPT_DIR/patches.
|
|
||||||
SCRIPT_DIR="$PWD"
|
|
||||||
REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}"
|
|
||||||
source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
|
|
||||||
mode="${1:-check}"
|
|
||||||
fail=0
|
|
||||||
say() { echo "$*" | tee -a "$REPORT"; }
|
|
||||||
pass() { say "PASS $*"; }
|
|
||||||
bad() { say "FAIL $*"; fail=1; }
|
|
||||||
note() { say " $*"; }
|
|
||||||
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
|
|
||||||
|
|
||||||
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
|
|
||||||
|
|
||||||
report_system() {
|
|
||||||
say "-- GPU and software"
|
|
||||||
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
|
|
||||||
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
|
|
||||||
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
|
|
||||||
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
|
|
||||||
done
|
|
||||||
note "boot loader file: $(nvidia_boot_file || true)"
|
|
||||||
note "cmdline: $(cat /proc/cmdline)"
|
|
||||||
}
|
|
||||||
|
|
||||||
check_state() {
|
|
||||||
say "-- Steamify's view"
|
|
||||||
if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected"
|
|
||||||
elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied"
|
|
||||||
else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi
|
|
||||||
for c in /sys/class/drm/card[0-9]*/device; do
|
|
||||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')"
|
|
||||||
done
|
|
||||||
ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported"
|
|
||||||
local p
|
|
||||||
for p in $NVIDIA_PARAMS; do
|
|
||||||
if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line"
|
|
||||||
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
|
|
||||||
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
|
|
||||||
done
|
|
||||||
say "-- the live NVIDIA driver"
|
|
||||||
local m
|
|
||||||
for m in modeset fbdev; do
|
|
||||||
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
|
|
||||||
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
|
|
||||||
done
|
|
||||||
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
|
|
||||||
local c found=0
|
|
||||||
for c in /sys/class/drm/card[0-9]*/device; do
|
|
||||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
|
|
||||||
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
|
|
||||||
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
|
|
||||||
done
|
|
||||||
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
|
|
||||||
say "-- initramfs"
|
|
||||||
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
|
|
||||||
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
|
|
||||||
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
|
|
||||||
say "-- what apply would change"
|
|
||||||
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
|
|
||||||
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$mode" in
|
|
||||||
check)
|
|
||||||
report_system; check_state ;;
|
|
||||||
apply)
|
|
||||||
report_system
|
|
||||||
say "-- applying"
|
|
||||||
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
|
|
||||||
else bad "nvidia_enable failed (output above)"; fi
|
|
||||||
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
|
|
||||||
visual)
|
|
||||||
report_system
|
|
||||||
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
|
|
||||||
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
|
|
||||||
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
|
|
||||||
say "visual result: $a: $what"
|
|
||||||
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
|
|
||||||
say "-- gamescope and NVIDIA lines from this boot's log"
|
|
||||||
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
|
|
||||||
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
|
|
||||||
note "(more in $REPORT)" ;;
|
|
||||||
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
|
|
||||||
esac
|
|
||||||
say ""; say "Report: $REPORT"
|
|
||||||
exit $fail
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Tests lib/nvidia.sh ("Gaming on NVIDIA" and its Big Picture option) and the menu rules around it, against a fake RTX 5080
|
|
||||||
# (PCI 10de:2c02) beside an Intel iGPU, a stub modinfo, pacman and systemctl, and a temp home. No root, VM or NVIDIA
|
|
||||||
# hardware needed: bash tests/nvidia-test.sh
|
|
||||||
cd "$(dirname "$0")/.." || exit 1
|
|
||||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
||||||
fail=0
|
|
||||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
|
||||||
|
|
||||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
|
||||||
source lib/common.sh; source lib/state.sh; source lib/login-manager.sh; source lib/single-user.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; source lib/menu.sh
|
|
||||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
|
||||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
|
||||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
|
||||||
# KDE's config tools on plain files under the temp home (a relative file name is relative to ~/.config, as in KDE).
|
|
||||||
kwriteconfig6() {
|
|
||||||
local f="" k="" v="" del=0
|
|
||||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; --delete) del=1 ;; *) v="$1" ;; esac; shift; done
|
|
||||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"; mkdir -p "$(dirname "$f")"
|
|
||||||
if [[ $del == 1 ]]; then sed -i "/^$k=/d" "$f" 2>/dev/null; else sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; fi
|
|
||||||
}
|
|
||||||
kreadconfig6() {
|
|
||||||
local f="" k="" d="" r
|
|
||||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --default) d="$2"; shift ;; --group) shift ;; esac; shift; done
|
|
||||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"
|
|
||||||
r="$(sed -n "s/^$k=//p" "$f" 2>/dev/null)"; printf '%s\n' "${r:-$d}"
|
|
||||||
}
|
|
||||||
# A pretend package database and systemd: what the tests assert on.
|
|
||||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; ENABLED=0
|
|
||||||
pacman() {
|
|
||||||
case "$1" in
|
|
||||||
-Q) [[ " $PKGS " == *" $2 "* ]] ;;
|
|
||||||
-S) echo "S $*" >> "$PACMAN_LOG"; PKGS+=" ${*: -1}" ;;
|
|
||||||
-Rns) echo "R $*" >> "$PACMAN_LOG"; PKGS=" ${PKGS//${*: -1}/} " ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
user_systemctl() {
|
|
||||||
case "$1" in
|
|
||||||
enable) ENABLED=1 ;;
|
|
||||||
disable) ENABLED=0 ;;
|
|
||||||
is-enabled) [[ $ENABLED == 1 ]] ;;
|
|
||||||
esac
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
FAKE_DRIVER=1; modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
|
|
||||||
GAMING_ON=0; gaming_status() { [[ "$GAMING_ON" == 1 ]]; }
|
|
||||||
UNIT="$HOME/.config/systemd/user/$NVIDIA_UNIT"
|
|
||||||
|
|
||||||
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
|
|
||||||
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
|
|
||||||
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
|
|
||||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
|
|
||||||
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
|
|
||||||
: > "$T/cmdline"; NVIDIA_CMDLINE="$T/cmdline" # the running kernel's command line: without the parameters
|
|
||||||
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
|
|
||||||
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
|
|
||||||
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
|
|
||||||
NVIDIA_MODULES_DIR="$T/mods"
|
|
||||||
NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked
|
|
||||||
mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd"
|
|
||||||
# The component's kernel step edits this boot loader file (systemd-boot's) in the tests, never a real one.
|
|
||||||
printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot-manage.conf"; nvidia_boot_file() { echo "$T/sdboot-manage.conf"; }
|
|
||||||
|
|
||||||
# --- detection
|
|
||||||
check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
|
|
||||||
FAKE_DRIVER=0; check "no nvidia_drm module (nouveau): not an NVIDIA PC" '! nvidia_present'
|
|
||||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA GPU: not an NVIDIA PC" '! nvidia_present'
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- which items the menu shows
|
|
||||||
check "NVIDIA PC: the SteamOS conversion and its gamescope options are hidden" '! component_available gaming && ! component_available boot && ! component_available glyphs'
|
|
||||||
check "NVIDIA PC: Gaming on NVIDIA and Big Picture are shown" 'component_available nvidia && component_available bigpicture'
|
|
||||||
GAMING_ON=1
|
|
||||||
check "NVIDIA PC with the conversion already on: it is shown, so it can be turned off" 'component_available gaming && component_available boot'
|
|
||||||
check "...and Gaming on NVIDIA is hidden (both would start Steam)" '! component_available nvidia && ! component_available bigpicture'
|
|
||||||
GAMING_ON=0; NVIDIA_DRM_DIR="$T/none"
|
|
||||||
check "no NVIDIA: the conversion is shown as before" 'component_available gaming && component_available boot'
|
|
||||||
check "...and Gaming on NVIDIA is hidden" '! component_available nvidia && ! component_available bigpicture'
|
|
||||||
NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- "Add as non-Steam game" is for gaming mode's controller: not offered on an NVIDIA PC (unless already on)
|
|
||||||
steamgame_available() { return 0; }; STEAMGAME_ON=0; steamgame_status() { [[ "$STEAMGAME_ON" == 1 ]]; }
|
|
||||||
check "NVIDIA PC: Add as non-Steam game is hidden" '! component_available steamgame'
|
|
||||||
STEAMGAME_ON=1; check "...unless it is already on (so it can be turned off)" 'component_available steamgame'; STEAMGAME_ON=0
|
|
||||||
NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA: it is offered as before" 'component_available steamgame'
|
|
||||||
steamgame_available() { return 1; }; check "no NVIDIA, no Steam account yet: still not offered" '! component_available steamgame'
|
|
||||||
steamgame_available() { return 0; }; NVIDIA_DRM_DIR="$T/drm"
|
|
||||||
|
|
||||||
# --- turning it on
|
|
||||||
check "off to begin with" '! nvidia_status && ! bigpicture_status'
|
|
||||||
nvidia_enable
|
|
||||||
check "Steam is installed when missing, and recorded as ours" 'grep -q "^S " "$PACMAN_LOG" && [[ "$(state_get nvidia installed_pkgs)" == steam ]]'
|
|
||||||
check "the autostart unit is written: Steam without arguments" 'grep -q "^ExecStart=/usr/bin/steam $" "$UNIT"'
|
|
||||||
check "it is on" 'nvidia_status && ! bigpicture_status'
|
|
||||||
n="$(wc -l < "$PACMAN_LOG")"; nvidia_enable
|
|
||||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
|
||||||
|
|
||||||
# --- Big Picture
|
|
||||||
bigpicture_enable
|
|
||||||
check "Big Picture: Steam starts with -gamepadui" 'grep -q "^ExecStart=/usr/bin/steam -gamepadui$" "$UNIT" && bigpicture_status'
|
|
||||||
nvidia_enable
|
|
||||||
check "turning Gaming on NVIDIA on again keeps Big Picture" 'bigpicture_status'
|
|
||||||
check "Big Picture: Plasma starts with an empty session" '[[ "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" == emptySession ]]'
|
|
||||||
bigpicture_disable
|
|
||||||
check "Big Picture off: Steam's normal window again" '! bigpicture_status && nvidia_status'
|
|
||||||
check "...and the session setting is back as it was (not set)" '[[ -z "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" ]]'
|
|
||||||
|
|
||||||
# --- turning it off
|
|
||||||
bigpicture_enable; nvidia_disable
|
|
||||||
check "off: the unit is gone and Steam, which we installed, is removed" '! nvidia_status && [[ ! -e "$UNIT" ]] && ! pacman -Q steam && [[ -z "$(state_get nvidia installed_pkgs)" ]]'
|
|
||||||
check "Big Picture without the unit does nothing" 'bigpicture_enable && bigpicture_disable && [[ ! -e "$UNIT" ]]'
|
|
||||||
|
|
||||||
# --- Steam that was there already is never removed
|
|
||||||
PKGS=" steam"; : > "$PACMAN_LOG"
|
|
||||||
nvidia_enable; nvidia_disable
|
|
||||||
check "Steam installed before is kept, and not installed again" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q steam'
|
|
||||||
|
|
||||||
# --- kernel parameters and early modules (a supported card only: RTX 20 series or newer)
|
|
||||||
check "RTX 5080 (2c02) is supported: no chwd legacy lists" nvidia_supported
|
|
||||||
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
|
|
||||||
check "RTX 5080 is not on a legacy list" 'nvidia_supported && ! nvidia_legacy_gpu'
|
|
||||||
echo 0x1c03 > "$T/drm/card1/device/device"
|
|
||||||
check "GTX 1060 (older than RTX 20): no kernel setup, but still an NVIDIA PC" '! nvidia_supported && nvidia_legacy_gpu && nvidia_present'
|
|
||||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
|
||||||
|
|
||||||
for loader in limine limineplus sdboot grub; do
|
|
||||||
case $loader in
|
|
||||||
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
|
|
||||||
# CachyOS writes its line as "+=" and may already have nvidia_drm.modeset=1 in it.
|
|
||||||
limineplus) F="$T/limine"; printf 'KERNEL_CMDLINE[default]+="quiet splash nvidia_drm.modeset=1"\n' > "$F" ;;
|
|
||||||
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
|
|
||||||
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
|
|
||||||
esac
|
|
||||||
nvidia_boot_file() { echo "$F"; }
|
|
||||||
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
|
|
||||||
nvidia_kernel_enable
|
|
||||||
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
|
|
||||||
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
|
|
||||||
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
|
|
||||||
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
|
|
||||||
SUM="$(cat "$F")"; nvidia_kernel_enable
|
|
||||||
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
|
|
||||||
nvidia_kernel_disable
|
|
||||||
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
|
|
||||||
done
|
|
||||||
|
|
||||||
# A missing patches/ file must be an error, never an empty script or hook.
|
|
||||||
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
|
|
||||||
# The pacman hook's script decides again at every kernel change.
|
|
||||||
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
|
|
||||||
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
|
|
||||||
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
|
|
||||||
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
|
|
||||||
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
|
|
||||||
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
|
||||||
rm -rf "$T/mods/5.0.0-leftover"; nvidia_kernel_disable
|
|
||||||
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
|
|
||||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
|
|
||||||
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_kernel_enable
|
|
||||||
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
|
|
||||||
rm -rf "$T/mods/6.6.0-lts"
|
|
||||||
# Generated boot entries without the parameters (the initramfs build failed): an error.
|
|
||||||
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
|
|
||||||
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
|
|
||||||
check "boot entries without the parameters: error" '! nvidia_kernel_enable >/dev/null'
|
|
||||||
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
|
|
||||||
# A config file without the setting to edit: an error, not "applied".
|
|
||||||
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
|
|
||||||
check "no setting to edit: error, nothing rebuilt" '! nvidia_kernel_enable >/dev/null && [[ $REBUILDS == 0 ]]'
|
|
||||||
FAKE_DRIVER=0; NVIDIA_DRM_DIR="$T/drm"; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_kernel_enable
|
|
||||||
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
|
|
||||||
|
|
||||||
# --- single user mode on NVIDIA: its own login step (SDDM, autologin into Plasma) without the conversion
|
|
||||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/drm" # an earlier section ended without the driver
|
|
||||||
SW="$T/switches.log"; : > "$SW"; TARGET_USER=tester; SINGLE_AUTOLOGIN="$T/sddm.conf.d/zzz-steamify-autologin.conf"
|
|
||||||
switch_to_sddm() { echo sddm >> "$SW"; }; switch_to_plasmalogin() { echo plasmalogin >> "$SW"; }
|
|
||||||
remove_sddm_base_autologin() { :; } # would look at the real /etc/sddm.conf
|
|
||||||
GAMING_ON=0
|
|
||||||
check "single user mode is offered on NVIDIA without the conversion..." 'component_available single'
|
|
||||||
GAMING_ON=1; check "...and with it" 'component_available single'; GAMING_ON=0
|
|
||||||
single_login_enable
|
|
||||||
check "single user: SDDM, autologin of the user into the Plasma session" 'grep -qx "User=tester" "$SINGLE_AUTOLOGIN" && grep -qx "Session=plasma.desktop" "$SINGLE_AUTOLOGIN" && grep -qx "Relogin=true" "$SINGLE_AUTOLOGIN" && grep -qx sddm "$SW"'
|
|
||||||
c1="$(cat "$SINGLE_AUTOLOGIN")"; single_login_enable
|
|
||||||
check "single user login: a second run changes nothing" '[[ "$(cat "$SINGLE_AUTOLOGIN")" == "$c1" ]]'
|
|
||||||
single_login_disable
|
|
||||||
check "single user off: the file is gone and plasma-login-manager is the login manager again" '[[ ! -e "$SINGLE_AUTOLOGIN" ]] && grep -qx plasmalogin "$SW"'
|
|
||||||
: > "$SW"; GAMING_ON=1; single_login_enable
|
|
||||||
check "with the conversion on, single user mode leaves the login to it" '[[ ! -e "$SINGLE_AUTOLOGIN" && ! -s "$SW" ]]'
|
|
||||||
GAMING_ON=0
|
|
||||||
# --- the menu rules
|
|
||||||
declare -A WANTED=([nvidia]=1 [bigpicture]=1 [gaming]=0 [boot]=0 [single]=0 [machine]=0 [poweroff]=0 [launcher]=0 [steamgame]=0)
|
|
||||||
component_selectable() { return 0; }
|
|
||||||
toggle_component nvidia
|
|
||||||
check "unticking Gaming on NVIDIA unticks Big Picture" '[[ "${WANTED[nvidia]}" == 0 && "${WANTED[bigpicture]}" == 0 ]]'
|
|
||||||
toggle_component bigpicture
|
|
||||||
check "ticking Big Picture ticks Gaming on NVIDIA" '[[ "${WANTED[nvidia]}" == 1 && "${WANTED[bigpicture]}" == 1 ]]'
|
|
||||||
WANTED[single]=0; WANTED[gaming]=0; toggle_component single
|
|
||||||
check "ticking single user mode does not tick the conversion where it isn't offered" '[[ "${WANTED[single]}" == 1 && "${WANTED[gaming]}" == 0 ]]'
|
|
||||||
check "Big Picture follows Gaming on NVIDIA in the menu" '[[ " ${COMPONENTS[*]} " == *" nvidia bigpicture "* && "${PARENT[bigpicture]}" == nvidia ]]'
|
|
||||||
|
|
||||||
exit $fail
|
|
||||||
+15
-6
@@ -38,7 +38,9 @@ Item {
|
|||||||
|
|
||||||
readonly property var status: backend.status || ({})
|
readonly property var status: backend.status || ({})
|
||||||
readonly property var items: status.items || []
|
readonly property var items: status.items || []
|
||||||
readonly property var rows: items.filter(function (i) { return !i.parent || want[i.parent]; })
|
// Hidden: Big Picture excludes a silent start.
|
||||||
|
function hidden(i) { return i.id === "nvsilent" && want.bigpicture; }
|
||||||
|
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
|
||||||
readonly property var bios: status.bios || null
|
readonly property var bios: status.bios || null
|
||||||
|
|
||||||
signal passwordRequested()
|
signal passwordRequested()
|
||||||
@@ -63,7 +65,8 @@ Item {
|
|||||||
var w = {};
|
var w = {};
|
||||||
for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted;
|
for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted;
|
||||||
want = w;
|
want = w;
|
||||||
boot = nowOn("boot") ? "desktop" : "gamescope";
|
// (What the PC has, or what the backend ticked: "Gaming on NVIDIA" moving to the conversion keeps how Steam started.)
|
||||||
|
boot = want.boot ? "desktop" : "gamescope";
|
||||||
if (sel > rows.length) sel = 0;
|
if (sel > rows.length) sel = 0;
|
||||||
}
|
}
|
||||||
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
||||||
@@ -76,10 +79,14 @@ Item {
|
|||||||
w[id] = !w[id];
|
w[id] = !w[id];
|
||||||
// The same rules as the terminal menu (toggle_component).
|
// The same rules as the terminal menu (toggle_component).
|
||||||
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
||||||
if (id === "gaming" && !w.gaming) w.single = false;
|
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; }
|
||||||
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
||||||
if (id === "nvidia") w.bigpicture = w.nvidia;
|
if (id === "nvidia") w.bigpicture = w.nvidia;
|
||||||
if (id === "bigpicture" && w.bigpicture) w.nvidia = true;
|
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
||||||
|
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
||||||
|
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
||||||
|
if (id === "silent" && w.silent) w.gaming = true;
|
||||||
|
if (id === "glyphs" && w.glyphs) w.gaming = true;
|
||||||
if (id === "machine") w.poweroff = w.machine;
|
if (id === "machine") w.poweroff = w.machine;
|
||||||
if (id === "poweroff" && w.poweroff) w.machine = true;
|
if (id === "poweroff" && w.poweroff) w.machine = true;
|
||||||
if (id === "machine" && !w.machine) w.kpin = false;
|
if (id === "machine" && !w.machine) w.kpin = false;
|
||||||
@@ -93,8 +100,10 @@ Item {
|
|||||||
for (var i = 0; i < items.length; i++) {
|
for (var i = 0; i < items.length; i++) {
|
||||||
var it = items[i];
|
var it = items[i];
|
||||||
if (it.kind !== "toggle") continue;
|
if (it.kind !== "toggle") continue;
|
||||||
|
if (hidden(it)) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
|
||||||
if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
|
if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
|
||||||
if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] });
|
// (An item that is off but flagged "update" replaces what the PC has: the conversion for "Gaming on NVIDIA".)
|
||||||
|
if (want[it.id] && !it.on) p.push({ id: it.id, action: it.update ? "update" : "on", isNew: !!it["new"] });
|
||||||
else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" });
|
else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" });
|
||||||
else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" });
|
else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" });
|
||||||
}
|
}
|
||||||
@@ -109,7 +118,7 @@ Item {
|
|||||||
function wantedIds() {
|
function wantedIds() {
|
||||||
var ids = [];
|
var ids = [];
|
||||||
for (var i = 0; i < items.length; i++)
|
for (var i = 0; i < items.length; i++)
|
||||||
if (items[i].kind === "toggle" && want[items[i].id] && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id);
|
if (items[i].kind === "toggle" && want[items[i].id] && !hidden(items[i]) && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id);
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -6,16 +6,22 @@ QtObject {
|
|||||||
readonly property var items: ({
|
readonly property var items: ({
|
||||||
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
|
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
|
||||||
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
|
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
|
||||||
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] },
|
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut"] },
|
||||||
boot: { label: "Boot into", hint: "Where the PC starts",
|
boot: { label: "Boot into", hint: "Where the PC starts",
|
||||||
body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
|
body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
|
||||||
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
|
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
|
||||||
|
silent: { label: "Start Steam silently in desktop mode", hint: "In the tray at login on the desktop, no window",
|
||||||
|
body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.",
|
||||||
|
changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] },
|
||||||
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
||||||
body: "gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards (an open NVIDIA driver bug), so it isn't offered here. This puts Steam on the Plasma desktop instead and starts it when you log in.",
|
body: "gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards (an open NVIDIA driver bug), so it isn't offered here. This puts Steam on the Plasma desktop instead and starts it when you log in.",
|
||||||
changes: ["Steam is installed when it's missing", "Steam starts at login (a systemd user service)", "Off: the service is removed again; Steam is only removed if Steamify installed it"] },
|
changes: ["Steam is installed when it's missing", "Steam starts at login (a systemd user service)", "Off: the service is removed again; Steam is only removed if Steamify installed it"] },
|
||||||
bigpicture: { label: "Steam starts in Big Picture", hint: "The controller-friendly Steam, or the normal window",
|
bigpicture: { label: "Steam starts in Big Picture", hint: "The controller-friendly Steam, or the normal window",
|
||||||
body: "Steam opens in Big Picture at login, which works well with a controller on the TV. Untick it for Steam's normal window.",
|
body: "Steam opens in Big Picture at login, which works well with a controller on the TV. Untick it for Steam's normal window.",
|
||||||
changes: ["Steam is started with -gamepadui", "Plasma starts with an empty session, so old windows don't cover Big Picture", "Off: Steam starts in its normal window"] },
|
changes: ["Steam is started with -gamepadui", "Plasma starts with an empty session, so old windows don't cover Big Picture", "Off: Steam starts in its normal window"] },
|
||||||
|
nvsilent: { label: "Start Steam silently", hint: "In the tray at login, no window",
|
||||||
|
body: "Steam starts in the tray at login without a window. Not together with Big Picture: ticking one unticks the other.",
|
||||||
|
changes: ["Steam is started with -silent", "Off: Steam starts in its normal window"] },
|
||||||
theme: { label: "SteamOS theme", hint: "Vapor look for the desktop, Add to Steam",
|
theme: { label: "SteamOS theme", hint: "Vapor look for the desktop, Add to Steam",
|
||||||
body: "The Vapor look of SteamOS for the desktop, with its panel, launcher icon and wallpaper.",
|
body: "The Vapor look of SteamOS for the desktop, with its panel, launcher icon and wallpaper.",
|
||||||
changes: ["cachyos-vapor global theme", "Add to Steam in right-click menus", "Nested Desktop, Steam keyboard window rule"] },
|
changes: ["cachyos-vapor global theme", "Add to Steam in right-click menus", "Nested Desktop, Steam keyboard window rule"] },
|
||||||
|
|||||||
Reference in new issue
Block a user