mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-03 17:41:58 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d44f29956a | ||
|
|
2858d13429 | ||
|
|
48cf3c7c7c | ||
|
|
619ef1f714 | ||
|
|
b6240539e6 | ||
|
|
7d6df21627 | ||
|
|
3cad70dcc4 | ||
|
|
b8742a5642 | ||
|
|
7f5d29c997 | ||
|
|
cfe3ce7bd0 | ||
|
|
3e4133c14a | ||
|
|
c4b8db85dc | ||
|
|
350011877b | ||
|
|
b1d79d48a6 | ||
|
|
5b42036786 | ||
|
|
4a64232fad | ||
|
|
4ec92f4d89 | ||
|
|
fe4f3f43be | ||
|
|
4bacc3b2e6 | ||
|
|
cc0ca1c35e | ||
|
|
580cc71b57 | ||
|
|
c87e6c763f | ||
|
|
fc05725a91 | ||
|
|
90bc5e4408 | ||
|
|
d99ff652dc | ||
|
|
2aa3068b60 | ||
|
|
1a6ddcfc0d | ||
|
|
11668db91c | ||
|
|
3316c1de28 | ||
|
|
d9365dac81 | ||
|
|
853a3926ee | ||
|
|
66ea63cf7e | ||
|
|
f560f332a9 | ||
|
|
9b86cd1a6c | ||
|
|
a72a4def71 | ||
|
|
ea051c77f6 | ||
|
|
4e829c6111 | ||
|
|
d73e71d4eb | ||
|
|
8f2d2be2aa | ||
|
|
53b72c8e33 | ||
|
|
3b4f3b2313 | ||
|
|
a72d848e78 | ||
|
|
3a58c72d16 | ||
|
|
27a40702ce | ||
|
|
8ab066f034 | ||
|
|
44bfe071d6 | ||
|
|
e281d5e879 | ||
|
|
435f69c151 | ||
|
|
9319cbca1e | ||
|
|
cf6bee1c86 | ||
|
|
16487ba00c | ||
|
|
07a94cd274 | ||
|
|
ce71b34b0d | ||
|
|
d30d505f7d | ||
|
|
9755cc3ac3 | ||
|
|
6f26e74229 | ||
|
|
2a01583b8f | ||
|
|
c40aa1f7d9 | ||
|
|
d204efb59d | ||
|
|
12f6cc0b3a | ||
|
|
b01e2c5221 | ||
|
|
affb5f79b0 | ||
|
|
58e43d4c4a | ||
|
|
23f265b02f | ||
|
|
ced4a45d2f | ||
|
|
6ad686a8b2 | ||
|
|
b1adacbcb3 | ||
|
|
8dd2db3a97 | ||
|
|
501c0ba425 | ||
|
|
bee18b76a8 | ||
|
|
eadbdda271 | ||
|
|
c4ec755a4a | ||
|
|
14aa7c0b54 | ||
|
|
5bf9da411d | ||
|
|
4f6e6fd0aa | ||
|
|
a79eeedbc4 | ||
|
|
b948c2020b | ||
|
|
0c96bed448 | ||
|
|
e3f7cc9773 | ||
|
|
353de489d7 | ||
|
|
d8b2e812c5 | ||
|
|
3a0692fdf2 | ||
|
|
e86ddcc4af | ||
|
|
389bc3346e | ||
|
|
c6c1150836 | ||
|
|
98e2effcff | ||
|
|
431515b60f |
No files matched your search
+106
-23
@@ -5,18 +5,16 @@
|
|||||||
# release are moved to it, so both of these always get the newest version:
|
# release are moved to it, so both of these always get the newest version:
|
||||||
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
||||||
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/latest/steamify.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/latest/steamify.sh | bash
|
||||||
# Each release also has the app (v2): steamify-app.tar.gz (ui/, steamify.sh,
|
# Each release also has the app: steamify-app.tar.gz (ui/, steamify.sh,
|
||||||
# lib/, patches/, services/, the icon) and its launcher, run with:
|
# lib/, patches/, services/, the icon) and its launcher, run with:
|
||||||
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
|
||||||
# A push to feat/v2-ui (the app, not released yet) updates the pre-release
|
# Pushes to release/** build and check it like pull requests; only main publishes.
|
||||||
# v2-ui-preview instead, whose launcher gets that build:
|
|
||||||
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/download/v2-ui-preview/steamify-app.sh | bash
|
|
||||||
# Pull requests only build and check it, and warn when VERSION is already released.
|
# Pull requests only build and check it, and warn when VERSION is already released.
|
||||||
name: Single-file build
|
name: Single-file build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main, feat/v2-ui]
|
branches: [main, 'release/**']
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -42,12 +40,39 @@ jobs:
|
|||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
bash -n dist/steamify.sh
|
bash -n dist/steamify.sh
|
||||||
# SC2034/SC2154: variables used across the inlined modules.
|
|
||||||
shellcheck -S warning -e SC2034,SC2154 dist/steamify.sh
|
|
||||||
shellcheck -S warning dist/steamify-app.sh
|
|
||||||
python3 -m py_compile ui/steamify-ui
|
python3 -m py_compile ui/steamify-ui
|
||||||
|
|
||||||
|
# shellcheck through an action that brings its own binary: GitHub's runner has it installed,
|
||||||
|
# Gitea's act_runner image doesn't. One file per run, as before (the exceptions are the bundle's).
|
||||||
|
- name: shellcheck the bundle
|
||||||
|
uses: ludeeus/action-shellcheck@2.0.0
|
||||||
|
env:
|
||||||
|
# SC2034/SC2154: variables used across the inlined modules.
|
||||||
|
SHELLCHECK_OPTS: -e SC2034 -e SC2154
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
scandir: dist
|
||||||
|
ignore_names: steamify-app.sh
|
||||||
|
- name: shellcheck the app launcher
|
||||||
|
uses: ludeeus/action-shellcheck@2.0.0
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
scandir: dist
|
||||||
|
ignore_names: steamify.sh
|
||||||
|
|
||||||
|
# The build as an artifact on GitHub and on the mirror (Gitea); releases stay GitHub's.
|
||||||
|
# Gitea's artifact server doesn't speak upload-artifact@v4's protocol, and GitHub fails a workflow
|
||||||
|
# that merely mentions the deprecated @v3: Gitea gets christopherhx's fork of v4 for Gitea.
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: github.server_url == 'https://github.com'
|
||||||
|
with:
|
||||||
|
name: steamify
|
||||||
|
path: |
|
||||||
|
dist/steamify.sh
|
||||||
|
dist/steamify-app.tar.gz
|
||||||
|
dist/steamify-app.sh
|
||||||
|
- uses: christopherhx/gitea-upload-artifact@v4
|
||||||
|
if: github.server_url != 'https://github.com'
|
||||||
with:
|
with:
|
||||||
name: steamify
|
name: steamify
|
||||||
path: |
|
path: |
|
||||||
@@ -57,6 +82,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Version
|
- name: Version
|
||||||
id: version
|
id: version
|
||||||
|
if: github.server_url == 'https://github.com'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
@@ -71,6 +97,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish the v${{ steps.version.outputs.version }} release
|
- name: Publish the v${{ steps.version.outputs.version }} release
|
||||||
if: >-
|
if: >-
|
||||||
|
github.server_url == 'https://github.com' &&
|
||||||
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
|
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
|
||||||
steps.version.outputs.released == 'false'
|
steps.version.outputs.released == 'false'
|
||||||
env:
|
env:
|
||||||
@@ -107,22 +134,78 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
gh release upload latest dist/steamify.sh dist/steamify-app.sh dist/steamify-app.tar.gz assets/steam-gaming-settings.svg --clobber
|
gh release upload latest dist/steamify.sh dist/steamify-app.sh dist/steamify-app.tar.gz assets/steam-gaming-settings.svg --clobber
|
||||||
|
|
||||||
- name: Publish the v2-ui-preview pre-release
|
# The mirror (Gitea) publishes its own release per version too, the same way: never overwrites one,
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/feat/v2-ui'
|
# notes from the changelog. gh can't talk to Gitea: its API for the check, a Gitea release action to
|
||||||
|
# publish. The token is the run's own (repository write); a secret RELEASE_TOKEN overrides it.
|
||||||
|
- name: Version (mirror)
|
||||||
|
id: mirror_version
|
||||||
|
if: github.server_url != 'https://github.com'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
|
||||||
run: |
|
run: |
|
||||||
# Its launcher downloads this pre-release, not the newest release.
|
version="$(grep -oP '^VERSION=\K.*' steamify.sh)"
|
||||||
sed -i 's/STEAMIFY_RELEASE:-latest/STEAMIFY_RELEASE:-v2-ui-preview/' dist/steamify-app.sh
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
grep -q 'STEAMIFY_RELEASE:-v2-ui-preview' dist/steamify-app.sh
|
if curl -fsS -o /dev/null -H "Authorization: token $TOKEN" \
|
||||||
git tag -f v2-ui-preview "$GITHUB_SHA" && git push -f origin v2-ui-preview
|
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/tags/v$version"; then
|
||||||
notes="Preview of the Steamify app (v2) from feat/v2-ui ($(git describe --always), $(git log -1 --format='%cs %s')). Not a release.
|
echo "released=true" >> "$GITHUB_OUTPUT"
|
||||||
Run it with:
|
echo "::warning::v$version is already released on this server and won't be overwritten."
|
||||||
|
|
||||||
curl -fsSL https://github.com/${{ github.repository }}/releases/download/v2-ui-preview/steamify-app.sh | bash"
|
|
||||||
if gh release view v2-ui-preview >/dev/null 2>&1; then
|
|
||||||
gh release edit v2-ui-preview --title "Steamify app (v2) preview" --notes "$notes" --prerelease --latest=false
|
|
||||||
else
|
else
|
||||||
gh release create v2-ui-preview --target "$GITHUB_SHA" --title "Steamify app (v2) preview" --notes "$notes" --prerelease --latest=false
|
echo "released=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
gh release upload v2-ui-preview dist/steamify-app.sh dist/steamify-app.tar.gz --clobber
|
|
||||||
|
- name: Release notes (mirror)
|
||||||
|
if: >-
|
||||||
|
github.server_url != 'https://github.com' &&
|
||||||
|
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
|
||||||
|
steps.mirror_version.outputs.released == 'false'
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.mirror_version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
changes="$(awk -v v="$VERSION" '
|
||||||
|
$0 ~ "^## " { if (found) exit; if (index($0, "## " v " ") == 1) { found = 1; next } }
|
||||||
|
found' CHANGELOG.md)"
|
||||||
|
cat > dist/release-notes.md <<NOTES
|
||||||
|
Single-file build of v$VERSION ($(git describe --always), $(git log -1 --format=%cs)).
|
||||||
|
Run this version with:
|
||||||
|
|
||||||
|
curl -fsSL ${{ github.server_url }}/${{ github.repository }}/releases/download/v$VERSION/steamify.sh | bash
|
||||||
|
|
||||||
|
## Changes in v$VERSION
|
||||||
|
$changes
|
||||||
|
NOTES
|
||||||
|
|
||||||
|
- name: Publish the v${{ steps.mirror_version.outputs.version }} release (mirror)
|
||||||
|
if: >-
|
||||||
|
github.server_url != 'https://github.com' &&
|
||||||
|
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
|
||||||
|
steps.mirror_version.outputs.released == 'false'
|
||||||
|
uses: akkuman/gitea-release-action@v1.3.7
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN || github.token }}
|
||||||
|
tag_name: v${{ steps.mirror_version.outputs.version }}
|
||||||
|
target_commitish: ${{ github.sha }}
|
||||||
|
name: Steamify CachyOS v${{ steps.mirror_version.outputs.version }}
|
||||||
|
body_path: dist/release-notes.md
|
||||||
|
files: |
|
||||||
|
dist/steamify.sh
|
||||||
|
dist/steamify-app.sh
|
||||||
|
dist/steamify-app.tar.gz
|
||||||
|
assets/steam-gaming-settings.svg
|
||||||
|
|
||||||
|
# A new Steamify release starts the Steamify ISO's release with it (a test build from the ISO repo's
|
||||||
|
# feat/steamify, until that is its master): its iso-release.yml names it after this version, tags it,
|
||||||
|
# and the Gitea mirror builds and attaches the ISO. Needs a fine-grained token for that repo
|
||||||
|
# (Actions: read and write) as the secret ISO_DISPATCH_TOKEN; without it, this is skipped.
|
||||||
|
- name: Start the Steamify ISO's release
|
||||||
|
if: >-
|
||||||
|
github.server_url == 'https://github.com' &&
|
||||||
|
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
|
||||||
|
steps.version.outputs.released == 'false'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.ISO_DISPATCH_TOKEN }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$GH_TOKEN" ]; then
|
||||||
|
echo "::notice::No ISO_DISPATCH_TOKEN: the Steamify ISO isn't released with this version."; exit 0
|
||||||
|
fi
|
||||||
|
gh workflow run iso-release.yml -R theupriser/steammachine-cachyos-live-iso --ref feat/steamify
|
||||||
|
echo "Started the Steamify ISO's release (theupriser/steammachine-cachyos-live-iso, feat/steamify)"
|
||||||
@@ -68,6 +68,13 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
the entry point's `for lib in ...; do` source loop and wraps everything
|
the entry point's `for lib in ...; do` source loop and wraps everything
|
||||||
after that loop in `main()`. Keep that loop on one line, keep all logic in
|
after that loop in `main()`. Keep that loop on one line, keep all logic in
|
||||||
functions, and don't rely on `SCRIPT_DIR` for anything but sourcing.
|
functions, and don't rely on `SCRIPT_DIR` for anything but sourcing.
|
||||||
|
The workflow is one file for GitHub and a Gitea mirror (`github.server_url`): build and check run on both
|
||||||
|
(shellcheck through `ludeeus/action-shellcheck`, which brings its own binary; the artifact with
|
||||||
|
`upload-artifact@v4` on GitHub and `christopherhx/gitea-upload-artifact@v4` elsewhere: never mention
|
||||||
|
`upload-artifact@v3`, GitHub fails a workflow for a deprecated version even in a skipped step); the
|
||||||
|
release is `gh` on GitHub and `akkuman/gitea-release-action` on Gitea. A new release on GitHub also starts the
|
||||||
|
Steamify ISO's release (`gh workflow run iso-release.yml` in steammachine-cachyos-live-iso, secret
|
||||||
|
`ISO_DISPATCH_TOKEN`; skipped without it): the ISO repo's GitHub tag names it, the Gitea mirror builds it.
|
||||||
CI (`.github/workflows/bundle.yml`) publishes the bundle as release
|
CI (`.github/workflows/bundle.yml`) publishes the bundle as release
|
||||||
`v$VERSION` on pushes to `main`; an existing version is never overwritten,
|
`v$VERSION` on pushes to `main`; an existing version is never overwritten,
|
||||||
so bump `VERSION` for every release.
|
so bump `VERSION` for every release.
|
||||||
@@ -98,11 +105,36 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
+ subject; a commit can't contain its own hash, so fill it in with the
|
+ subject; a commit can't contain its own hash, so fill it in with the
|
||||||
next commit). The section heading must be `## <VERSION> - <date>`: CI
|
next commit). The section heading must be `## <VERSION> - <date>`: CI
|
||||||
cuts the release notes out of the changelog by that heading.
|
cuts the release notes out of the changelog by that heading.
|
||||||
- Every PR that should be released bumps `VERSION` and adds its section.
|
- **Branches: one release branch per version.** Work for a release goes
|
||||||
A push to `main` publishes release `v$VERSION` (tag + bundle + that
|
into `release/X.Y.Z` (e.g. `release/2.7.0`), branched from `main` when
|
||||||
|
that version starts. That branch bumps `VERSION` to `X.Y.Z` and adds the
|
||||||
|
`## X.Y.Z - <date>` changelog section (first commit on it).
|
||||||
|
- Every change gets its own branch from the release branch:
|
||||||
|
`feature/<name>` (new behaviour) or `bugfix/<name>` (a fix), and a
|
||||||
|
pull request **into the release branch**, not into `main`. Its commits
|
||||||
|
add their changelog lines to that version's section.
|
||||||
|
- When the release is done and tested (the test plan in
|
||||||
|
steamify-cachyos-dev, `TESTPLAN.md`), the release branch gets a pull
|
||||||
|
request **into `main`**. Merging it publishes the release (below).
|
||||||
|
- A fix for a released version: a new `release/X.Y.Z+1` from `main`,
|
||||||
|
with the `bugfix/` branch into it; don't reopen an old release branch.
|
||||||
|
- Up to the release branch, the agent manages it: create the
|
||||||
|
`feature/`/`bugfix/` branches, commit, push, and merge them into the
|
||||||
|
release branch itself once tested (with `gh`: `gh pr create --base
|
||||||
|
release/X.Y.Z` + `gh pr merge --merge`; no review needed). Without
|
||||||
|
`gh` (`command -v gh`), ask the user to install it (Ubuntu:
|
||||||
|
`sudo apt install gh`, then `gh auth login`) instead of working around
|
||||||
|
it. Only the
|
||||||
|
release branch's pull request into `main` is the user's: never commit
|
||||||
|
or merge to `main`, the user merges that one.
|
||||||
|
Keep a feature/bugfix branch up to date by merging (or rebasing on)
|
||||||
|
its release branch, the release branch by merging `main` when that
|
||||||
|
moved.
|
||||||
|
- A push to `main` publishes release `v$VERSION` (tag + bundle + that
|
||||||
changelog section) and marks it latest. An existing version is never
|
changelog section) and marks it latest. An existing version is never
|
||||||
overwritten: without a bump nothing is released, and pull requests show
|
overwritten: without a bump nothing is released, and pull requests show
|
||||||
a warning.
|
a warning when `VERSION` is a version that's already released (so a
|
||||||
|
release branch that forgot its bump shows it on every PR).
|
||||||
- A release that adds, removes or renames a menu row also retakes the
|
- A release that adds, removes or renames a menu row also retakes the
|
||||||
README screenshot (`assets/screenshot-menu.png`): the app from the
|
README screenshot (`assets/screenshot-menu.png`): the app from the
|
||||||
branch on a Steam Machine, every row visible (window 1280 wide, tall
|
branch on a Steam Machine, every row visible (window 1280 wide, tall
|
||||||
@@ -227,6 +259,11 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
kernel only pairs that with a named lookup ("Port C") when the CEC driver
|
kernel only pairs that with a named lookup ("Port C") when the CEC driver
|
||||||
registered first, which never happens since amdgpu loads from the
|
registered first, which never happens since amdgpu loads from the
|
||||||
initramfs. Without it `/dev/cec0` exists but stays at `f.f.f.f`.
|
initramfs. Without it `/dev/cec0` exists but stays at `f.f.f.f`.
|
||||||
|
The source comes from one raw.githubusercontent.com download, which GitHub rate-limits (HTTP 429 after a
|
||||||
|
day of test installs, per address): it's kept in `/var/cache/steamify/cros-ec-cec-<sha256:12>.c` and reused
|
||||||
|
while its checksum matches. The name carries the checksum, so a new pin (commit + SHA-256 in `lib/cec.sh`)
|
||||||
|
downloads its own file once and removes the old one. The repo is an unofficial mirror of Valve's kernel
|
||||||
|
without releases: if it ever disappears, ship the file with Steamify. The test VMs share the host's cache.
|
||||||
- Power-off fix (`poweroff`, `lib/fremont-poweroff.sh`, a default sub-option
|
- Power-off fix (`poweroff`, `lib/fremont-poweroff.sh`, a default sub-option
|
||||||
of `machine`): recent kernels (7.2 and the 6.x/7.0/7.1 updates with the
|
of `machine`): recent kernels (7.2 and the 6.x/7.0/7.1 updates with the
|
||||||
backport) keep the firmware's S4/S5 wake bit on GPIO
|
backport) keep the firmware's S4/S5 wake bit on GPIO
|
||||||
@@ -243,6 +280,15 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
`linux-cachyos` is clang-built, `-bore` GCC-built: let DKMS pick the
|
`linux-cachyos` is clang-built, `-bore` GCC-built: let DKMS pick the
|
||||||
compiler, never pass `LLVM=1`. Test shutdown on the real machine for every
|
compiler, never pass `LLVM=1`. Test shutdown on the real machine for every
|
||||||
new major kernel.
|
new major kernel.
|
||||||
|
- Add as non-Steam game (`steamgame`, `lib/steam-game.sh`, sub-option of
|
||||||
|
`launcher`, ticked along with it, 2.5.1): edits Steam's `shortcuts.vdf`
|
||||||
|
with `patches/steam-shortcuts.py` only while Steam is closed (Steam
|
||||||
|
rewrites it on exit), then starts Steam again. Never close Steam in gaming
|
||||||
|
mode or when `SteamGameId` is set (the run is a Steam game). An existing
|
||||||
|
entry for the start script is updated, not doubled; removal takes every
|
||||||
|
entry for it. Controller input through Steam's desktop layout arrives as
|
||||||
|
keys: Enter must select (A), Esc must never quit (B); the app re-execs
|
||||||
|
without Steam's overlay preload.
|
||||||
- Update notifications (`notify`, `lib/update-notifier.sh`, top-level,
|
- Update notifications (`notify`, `lib/update-notifier.sh`, top-level,
|
||||||
ticked by default, 2.5.0): a user timer (daily, and the service is wanted
|
ticked by default, 2.5.0): a user timer (daily, and the service is wanted
|
||||||
by `plasma-workspace.target`) runs `patches/steamify-notifier.py`, which
|
by `plasma-workspace.target`) runs `patches/steamify-notifier.py`, which
|
||||||
@@ -260,6 +306,38 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
|||||||
latter only starts with `kcgroupsrc [Foreground Booster] autostart=true`
|
latter only starts with `kcgroupsrc [Foreground Booster] autostart=true`
|
||||||
(set with `kset`). Disable removes only the packages it installed
|
(set with `kset`). Disable removes only the packages it installed
|
||||||
(`state_get vram installed_pkgs`).
|
(`state_get vram installed_pkgs`).
|
||||||
|
- Install-time mode (`steamify.sh --defaults`, 2.6.0): applies what the menu
|
||||||
|
would preselect, no menu or prompts (needs passwordless sudo). The Steam
|
||||||
|
Machine ISO ([steammachine-cachyos-live-iso](https://github.com/theupriser/steammachine-cachyos-live-iso))
|
||||||
|
runs it in the installer for a user who has never logged in: no session
|
||||||
|
bus, user systemd or plasmashell. So every `systemctl --user` goes through
|
||||||
|
`user_systemctl` (`lib/common.sh`; without a session only unit files change,
|
||||||
|
via `--root=/`), and the theme, when the layout is still `/etc/skel`'s,
|
||||||
|
removes it so Plasma builds Vapor's layout at the first login. What needs
|
||||||
|
that layout (single user's launcher) runs then, from a one-time autostart
|
||||||
|
(`lib/first-login.sh`, `--first-login`) that also opens the app.
|
||||||
|
`--options <id>,...` (exactly these on, the rest off; an item on brings its
|
||||||
|
parent) and `--boot gamescope|desktop` (desktop only with `gaming`) (2.7.0,
|
||||||
|
`defaults_options` in `lib/menu.sh`); the ISO's installer page passes them.
|
||||||
|
Items this PC can't use are left off with a warning, not an error.
|
||||||
|
`steamify.sh --boot gamescope|desktop` on its own (2.7.0, for scripts) only
|
||||||
|
switches `boot` on an installed conversion: `WANTED` is `CURRENT` plus
|
||||||
|
that, so no updates or removals a normal run would pick.
|
||||||
|
- What Steam's System settings show (SteamOS conversion, 2.9.0): the OS name
|
||||||
|
stays CachyOS's everywhere (legal clarity; Steam's OS Name is
|
||||||
|
`lsb_release -d`, not touched). `/etc/os-release` gets `VERSION_ID=steamos-X.Y`
|
||||||
|
(Steam's OS Version: Valve's newest jupiter repo; offline, the previous
|
||||||
|
value), `VERSION_CODENAME=steam-machine`, `VARIANT="Steamify <version>"` and
|
||||||
|
`VARIANT_ID=steamify-<version>` (Steam shows VARIANT_ID as OS Variant),
|
||||||
|
refreshed by `os_version_refresh` after every run that changes something; a
|
||||||
|
pacman hook (`zz-steamify-os-release`) runs after cachyos-hooks. KDE's About
|
||||||
|
this System would show VERSION_ID after the name: `kcm-about-distrorc`
|
||||||
|
`UseOSReleaseVersion=true` (kset) makes it show os-release's VERSION, which
|
||||||
|
CachyOS doesn't have. Never `NAME` or `PRETTY_NAME`: limine-snapper-sync
|
||||||
|
finds the boot entries by the OS name ("Target OS name ... not found in
|
||||||
|
/boot/limine.conf"); `/etc/default/limine` gets `TARGET_OS_NAME="CachyOS"`
|
||||||
|
when it has none, as a guard. The serial number (tmpfiles rule) is Steam
|
||||||
|
Machine support's, so Fremont only.
|
||||||
- `Relogin=true` means a gamescope that fails to start is relaunched in a
|
- `Relogin=true` means a gamescope that fails to start is relaunched in a
|
||||||
tight loop; keep that in mind when changing session handling.
|
tight loop; keep that in mind when changing session handling.
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,78 @@ 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.9.4 - 2026-09-29
|
||||||
|
|
||||||
|
- `619ef1f` **docs: AGENTS.md and TECHNICAL.md: the CEC driver cache, the one workflow for GitHub and a Gitea mirror, and that a new release starts the Steamify ISO's release**
|
||||||
|
- `b624053` **chore: Version 2.9.4**
|
||||||
|
|
||||||
|
## 2.9.3 - 2026-09-29
|
||||||
|
|
||||||
|
- `7f5d29c` **feat(ci): a new Steamify release starts the Steamify ISO's release (a test build from the ISO repo's feat/steamify; secret ISO_DISPATCH_TOKEN)**
|
||||||
|
- `cfe3ce7` **chore: Version 2.9.3**
|
||||||
|
|
||||||
|
## 2.9.2 - 2026-09-29
|
||||||
|
|
||||||
|
- **feat(ci): a Gitea mirror publishes its own release per version (akkuman/gitea-release-action; never overwrites one, notes from the changelog, links to the mirror)**
|
||||||
|
- **fix(ci): the build also runs on a Gitea mirror (act_runner): shellcheck through ludeeus/action-shellcheck, which brings its own binary; the artifact goes up there with christopherhx/gitea-upload-artifact (GitHub refuses a workflow that mentions the deprecated upload-artifact@v3); releases are only published on GitHub**
|
||||||
|
- `fe4f3f4` **chore: Version 2.9.2**
|
||||||
|
|
||||||
|
## 2.9.1 - 2026-09-29
|
||||||
|
|
||||||
|
- `c87e6c7` **docs: changelog for the CEC driver cache**
|
||||||
|
- `fc05725` **fix: HDMI-CEC: an older cached CEC driver is removed when a new pin is downloaded**
|
||||||
|
- `90bc5e4` **fix: HDMI-CEC: Valve's CEC driver is downloaded once and kept in /var/cache/steamify (GitHub rate-limits repeated downloads with HTTP 429, which left CEC off); turning CEC on again needs no network**
|
||||||
|
- `d99ff65` **chore: Version 2.9.1**
|
||||||
|
|
||||||
|
## 2.9.0 - 2026-09-28
|
||||||
|
|
||||||
|
- `d30d505` **chore: Version 2.9.0**
|
||||||
|
- `66ea63c` **docs: KDE Plasma only: other desktops and display managers "are not supported" (README, was "don't work yet")**
|
||||||
|
- `9b86cd1` **docs: KDE Plasma only: other desktops don't work yet (README)**
|
||||||
|
- `d73e71d` **docs: README, TECHNICAL and TROUBLESHOOTING for 2.9.0: Steam's System settings, serial number and Wi-Fi backend, --defaults --list, the Steamify ISO**
|
||||||
|
- `a72d848` **feat: Steam's OS Version is the SteamOS release Steamify follows (steamos-3.9), its OS Codename steam-machine; About this System keeps "CachyOS Linux" (UseOSReleaseVersion)**
|
||||||
|
- `27a4070` **fix: Steam's OS Variant shows Steamify's version (VARIANT_ID=steamify-2.9.0; Steam shows VARIANT_ID, not VARIANT)**
|
||||||
|
- `44bfe07` **fix: No VERSION_ID in os-release: About this System said "CachyOS Linux 2.9.0"; the version is in VARIANT ("Steamify 2.9.0")**
|
||||||
|
- `435f69c` **feat: Steam's System settings: the OS name stays CachyOS (no renaming, also not in About this System), Steamify <version> as the variant, the SteamOS release it follows as the codename (steamos-3.9)**
|
||||||
|
- `ce71b34` **feat: Steam's System settings and About this System like on SteamOS: OS name "CachyOS with Steamify" (lsb-release, kept through CachyOS updates by a pacman hook), Steamify as OS variant and version (os-release VARIANT/VERSION_ID; NAME/PRETTY_NAME stay CachyOS's for limine, TARGET_OS_NAME pinned), "CachyOS Linux with Steamify" in About this System; on a Steam Machine the serial number and Steam's Wi-Fi backend setting (existing installs get it as an update)**
|
||||||
|
- `07a94cd` **fix(ui): The progress screen's ✓ and ! stand upright: only a dot on the circle spins while a step runs (they kept the spinner's last angle)**
|
||||||
|
|
||||||
|
## 2.8.0 - 2026-09-28
|
||||||
|
|
||||||
|
- **chore: Version 2.8.0**
|
||||||
|
- **feat: steamify.sh --defaults --list: what --defaults can set up here, as JSON, for an installer page**
|
||||||
|
|
||||||
|
## 2.7.0 - 2026-09-28
|
||||||
|
|
||||||
|
- `4f6e6fd` **feat: --defaults takes --skip <ids> and --boot gamescope|desktop, for the Steam Machine ISO's installer pages**
|
||||||
|
- `5bf9da4` **fix: HDMI-CEC enables cec-audio-control.socket (the TV remote's volume keys); existing installs get it as an update**
|
||||||
|
- `14aa7c0` **fix: the app's progress screen says "Boot into desktop", not "Boot into Boot into"**
|
||||||
|
- `c4ec755` **feat: --defaults --options <ids> (exactly these on) replaces --skip; steamify.sh --boot gamescope|desktop on its own switches where an installed conversion starts**
|
||||||
|
- `eadbdda` **docs: release branches (release/X.Y.Z, feature/ and bugfix/ branches into it, the release into main); CI builds release/** pushes**
|
||||||
|
- `bee18b7` **docs: the agent merges feature/bugfix branches into the release branch; the release into main stays the user's**
|
||||||
|
- `501c0ba` **docs: gh or git for merging into the release branch**
|
||||||
|
- `b1adacb` **docs: gh is required for the release-branch pull requests; ask the user to install it**
|
||||||
|
- `ced4a45` **chore: the v2 app preview is gone (it is the released app): no preview pre-release step in CI, no mention in steamify-app.sh**
|
||||||
|
- **fix: turning the theme off no longer brings back single user's launcher restriction when single user was turned off in between**
|
||||||
|
|
||||||
|
## 2.6.0 - 2026-09-27
|
||||||
|
|
||||||
|
- `b948c20` **feat: --defaults applies the default setup without the menu, also from an installer (no session): the base for a Steam Machine ISO**
|
||||||
|
|
||||||
|
## 2.5.2 - 2026-09-27
|
||||||
|
|
||||||
|
- `0c96bed` **docs: README screenshot at 2.5.2: everything on, nothing to update**
|
||||||
|
|
||||||
|
## 2.5.1 - 2026-09-27
|
||||||
|
|
||||||
|
- **fix: Add as non-Steam game asks Steam to close again every 15 s (a Steam that was still starting ignored it)**
|
||||||
|
- `3a0692f` **docs: README screenshot at 2.5.1 with Add as non-Steam game**
|
||||||
|
- `e86ddcc` **feat: Add as non-Steam game: Steamify in the Steam library, under the shortcut; controller works when started from Steam**
|
||||||
|
- `389bc33` **fix(ui): B never quits (Steam sends Esc for it), Ctrl+Q does; started from Steam, the hints show the Steam Controller's buttons**
|
||||||
|
- `c6c1150` **fix(ui): Enter selects (a Steam Controller's A in Steam's desktop layout); Ctrl+Enter reviews and applies**
|
||||||
|
- `98e2eff` **fix(ui): Started from Steam, the app runs without Steam's overlay (Qt aborted) and stays in the foreground, so Steam Input gives it the controller**
|
||||||
|
- `431515b` **feat(ui): Review & apply greyed out while nothing would change; the Done screen shows why a run stopped**
|
||||||
|
|
||||||
## 2.5.0 - 2026-09-27
|
## 2.5.0 - 2026-09-27
|
||||||
|
|
||||||
- **docs: README: what the VRAM booster says with NVIDIA's closed driver; shorter unsupported text in the app**
|
- **docs: README: what the VRAM booster says with NVIDIA's closed driver; shorter unsupported text in the app**
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ Steam Machine.
|
|||||||
on the desktop too.
|
on the desktop too.
|
||||||
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
||||||
the default.
|
the default.
|
||||||
|
- Steam's **System** settings show the SteamOS release Steamify follows
|
||||||
|
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
||||||
|
Steamify's version as OS Variant. The OS name stays CachyOS
|
||||||
|
([details](TECHNICAL.md#what-steams-system-settings-show)).
|
||||||
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
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)).
|
||||||
@@ -30,6 +34,10 @@ Steam Machine.
|
|||||||
5. **Steamify shortcut** - "Steamify CachyOS" on the desktop and in the
|
5. **Steamify shortcut** - "Steamify CachyOS" on the desktop and in the
|
||||||
launcher opens the newest Steamify app, so you don't need the install
|
launcher opens the newest Steamify app, so you don't need the install
|
||||||
command again. "Steamify Terminal" in the launcher opens the terminal menu.
|
command again. "Steamify Terminal" in the launcher opens the terminal menu.
|
||||||
|
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
|
||||||
|
talks to Steam), in gaming mode as well. Steam closes for a moment while
|
||||||
|
it's added, so that's done from the desktop.
|
||||||
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
|
||||||
@@ -58,7 +66,8 @@ What Steamify can do on a Valve Steam Machine:
|
|||||||
([details](TECHNICAL.md#hdmi-cec)).
|
([details](TECHNICAL.md#hdmi-cec)).
|
||||||
- **Steam Machine support** - the front **LED bar** works, Steam's
|
- **Steam Machine support** - the front **LED bar** works, Steam's
|
||||||
**hardware settings** (fan, performance) work, and the power button puts
|
**hardware settings** (fan, performance) work, and the power button puts
|
||||||
it to sleep like a console.
|
it to sleep like a console. Steam's System settings show the serial
|
||||||
|
number, and Steam's **Wi-Fi backend** setting works.
|
||||||
- **Power-off fix** - on by default: shutting down really turns the Steam
|
- **Power-off fix** - on by default: shutting down really turns the Steam
|
||||||
Machine off, also with the newest CachyOS kernel
|
Machine off, also with the newest CachyOS kernel
|
||||||
([details](TECHNICAL.md#power-off-fix-steam-machine)).
|
([details](TECHNICAL.md#power-off-fix-steam-machine)).
|
||||||
@@ -69,6 +78,11 @@ What Steamify can do on a Valve Steam Machine:
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- CachyOS with the KDE Plasma desktop (the default CachyOS Desktop edition)
|
- CachyOS with the KDE Plasma desktop (the default CachyOS Desktop edition)
|
||||||
|
|
||||||
|
> **KDE Plasma only.** Steamify works with KDE Plasma and its login managers
|
||||||
|
> (plasma-login-manager or SDDM). Other desktops (GNOME, Hyprland, Cosmic,
|
||||||
|
> ...) and other display managers are not supported: the switching between gaming mode
|
||||||
|
> and the desktop, the theme and the shortcuts are all built for Plasma.
|
||||||
- Your normal user account, with permission to use `sudo`
|
- Your normal user account, with permission to use `sudo`
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@@ -79,6 +93,11 @@ Open **Konsole** on your Plasma desktop and run:
|
|||||||
curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Installing CachyOS on a Steam Machine? The
|
||||||
|
[Steamify CachyOS ISO](https://github.com/theupriser/steammachine-cachyos-live-iso)
|
||||||
|
has Steamify built into the installer: pick the options there, and the
|
||||||
|
first boot is already set up.
|
||||||
|
|
||||||
Prefer to look at the script first? Clone the repository and run
|
Prefer to look at the script first? Clone the repository and run
|
||||||
[`./steamify.sh`](steamify.sh) (keep the whole folder: it needs
|
[`./steamify.sh`](steamify.sh) (keep the whole folder: it needs
|
||||||
[`lib/`](lib/)).
|
[`lib/`](lib/)).
|
||||||
@@ -121,6 +140,14 @@ steamos-session-select persistent # start where you left off last time
|
|||||||
steamos-session-select oneshot # always start in gaming mode (default)
|
steamos-session-select oneshot # always start in gaming mode (default)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Where the PC starts after a restart can also be set from a script, once the
|
||||||
|
SteamOS conversion is on (only that changes; `sudo` may ask for your password):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
steamify.sh --boot desktop # start in the desktop from the next boot on
|
||||||
|
steamify.sh --boot gamescope # start in gaming mode again (default)
|
||||||
|
```
|
||||||
|
|
||||||
## Something wrong?
|
## Something wrong?
|
||||||
|
|
||||||
Stuck on a black screen in gaming mode: press **Ctrl+Alt+F3**, log in, and run
|
Stuck on a black screen in gaming mode: press **Ctrl+Alt+F3**, log in, and run
|
||||||
|
|||||||
+98
-3
@@ -111,6 +111,9 @@ Turning it off restores `/etc/plasmalogin.conf` from its backup, removes the
|
|||||||
SDDM autologin, sync bridge, shortcut, sudoers rule and Steam autostart, and
|
SDDM autologin, sync bridge, shortcut, sudoers rule and Steam autostart, and
|
||||||
switches back to plasma-login-manager.
|
switches back to plasma-login-manager.
|
||||||
|
|
||||||
|
The conversion also sets what Steam's System settings show, see
|
||||||
|
[below](#what-steams-system-settings-show).
|
||||||
|
|
||||||
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
**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.
|
||||||
@@ -139,6 +142,33 @@ taken from the newest `steamdeck-kde-presets` on Valve's SteamOS mirror
|
|||||||
Turning it off restores your previous look and panel layout, and removes `cachyos-vapor` again
|
Turning it off restores your previous look and panel layout, and removes `cachyos-vapor` again
|
||||||
if the wizard installed it (and nothing else, like `cachyos-handheld`, needs it).
|
if the wizard installed it (and nothing else, like `cachyos-handheld`, needs it).
|
||||||
|
|
||||||
|
## What Steam's System settings show
|
||||||
|
|
||||||
|
With the SteamOS conversion on, `/etc/os-release` gets:
|
||||||
|
|
||||||
|
| Key | Value | Shown in Steam as |
|
||||||
|
|---|---|---|
|
||||||
|
| `VERSION_ID` | `steamos-3.9`: the newest SteamOS release in Valve's repo (offline: the previous value) | OS Version |
|
||||||
|
| `VERSION_CODENAME` | `steam-machine` | OS Codename |
|
||||||
|
| `VARIANT` / `VARIANT_ID` | `Steamify 2.9.0` / `steamify-2.9.0` | OS Variant (`VARIANT_ID`) |
|
||||||
|
|
||||||
|
The OS name stays CachyOS everywhere: Steam's OS Name comes from
|
||||||
|
`lsb_release -d`, which isn't touched, and `NAME`/`PRETTY_NAME` stay
|
||||||
|
CachyOS's. limine-snapper-sync finds the boot entries by that name, so
|
||||||
|
changing it would break snapshot boot entries; `/etc/default/limine` gets
|
||||||
|
`TARGET_OS_NAME="CachyOS"` as a guard when it has none.
|
||||||
|
|
||||||
|
KDE's About this System would show `VERSION_ID` after the name
|
||||||
|
("CachyOS Linux steamos-3.9"); `UseOSReleaseVersion=true` in
|
||||||
|
`~/.config/kcm-about-distrorc` makes it show `VERSION`, which CachyOS doesn't
|
||||||
|
have, so it keeps saying "CachyOS Linux".
|
||||||
|
|
||||||
|
CachyOS's own hooks (`cachyos-hooks`) reset os-release on updates of
|
||||||
|
`filesystem`; the pacman hook `zz-steamify-os-release` runs after them and
|
||||||
|
sets the keys again (`/usr/local/libexec/steamify-os-release`). The values are
|
||||||
|
refreshed after every Steamify run that changes something. Turning the
|
||||||
|
conversion off removes the hook and runs CachyOS's `cachyos-branding` again.
|
||||||
|
|
||||||
## Front LED bar (Steam Machine)
|
## Front LED bar (Steam Machine)
|
||||||
|
|
||||||
The **Steam Machine support** component, only shown on Fremont hardware
|
The **Steam Machine support** component, only shown on Fremont hardware
|
||||||
@@ -156,7 +186,14 @@ The **Steam Machine support** component, only shown on Fremont hardware
|
|||||||
- installs and enables `steamos-manager`, the service Steam in gaming mode
|
- installs and enables `steamos-manager`, the service Steam in gaming mode
|
||||||
uses for hardware settings (fan, performance, and the HDMI-CEC settings
|
uses for hardware settings (fan, performance, and the HDMI-CEC settings
|
||||||
when [HDMI-CEC](#hdmi-cec) is on); it recognises the Steam Machine from its
|
when [HDMI-CEC](#hdmi-cec) is on); it recognises the Steam Machine from its
|
||||||
DMI data.
|
DMI data;
|
||||||
|
- makes the serial number readable for Steam, which shows it in its System
|
||||||
|
settings (`/etc/tmpfiles.d/steamify-serial.conf`: `product_serial` is
|
||||||
|
root-only by default);
|
||||||
|
- makes Steam's Wi-Fi backend setting work: steamos-manager switches it in
|
||||||
|
`/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf`, which is created
|
||||||
|
with `wifi.backend=wpa_supplicant` (NetworkManager's default) when no
|
||||||
|
backend is set anywhere yet.
|
||||||
|
|
||||||
Turning it off removes all of that again (the AUR helper is kept).
|
Turning it off removes all of that again (the AUR helper is kept).
|
||||||
|
|
||||||
@@ -180,7 +217,9 @@ SHA-256 in Valve's package index:
|
|||||||
- `cecd`, Valve's CEC daemon (a user service started with the desktop and
|
- `cecd`, Valve's CEC daemon (a user service started with the desktop and
|
||||||
gaming mode): TV remote keys become normal key presses (arrows, Enter,
|
gaming mode): TV remote keys become normal key presses (arrows, Enter,
|
||||||
Back), and it turns the TV on and off with the PC;
|
Back), and it turns the TV on and off with the PC;
|
||||||
- `cec-audio-control`: volume of the TV or receiver;
|
- `cec-audio-control`: volume of the TV or receiver (the TV remote's volume
|
||||||
|
keys); its user socket is enabled by Steamify, since SteamOS enables it
|
||||||
|
through a preset that pacman doesn't apply;
|
||||||
- `inputattach-cec-units` (with `linuxconsole` from CachyOS for
|
- `inputattach-cec-units` (with `linuxconsole` from CachyOS for
|
||||||
`inputattach`): attaches USB CEC adapters (Pulse-Eight, RainShadow).
|
`inputattach`): attaches USB CEC adapters (Pulse-Eight, RainShadow).
|
||||||
|
|
||||||
@@ -236,6 +275,35 @@ Where Steam Machine support was set up before 2.2.0, the menu ticks the
|
|||||||
power-off fix as a new default sub-option (see feature versions below), so a
|
power-off fix as a new default sub-option (see feature versions below), so a
|
||||||
normal run adds it.
|
normal run adds it.
|
||||||
|
|
||||||
|
## Add as non-Steam game
|
||||||
|
|
||||||
|
A sub-option of the Steamify shortcut (`steamgame`, `lib/steam-game.sh`, new
|
||||||
|
in 2.5.1, ticked along with the shortcut): Steamify CachyOS in every Steam
|
||||||
|
account's non-Steam games (`~/.local/share/Steam/userdata/<id>/config/shortcuts.vdf`,
|
||||||
|
binary VDF, edited by `patches/steam-shortcuts.py`), starting the shortcut's
|
||||||
|
`run-app`, with the icon rendered as PNG (`~/.local/share/steamify/steamify.png`;
|
||||||
|
Steam shows no SVG). Why: while Steam runs, a Steam Controller only talks to
|
||||||
|
Steam, which gives its input to the game it started (Steam Input); on the
|
||||||
|
desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X =
|
||||||
|
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
|
||||||
|
closed (`steam -shutdown`) for the edit and started again (through
|
||||||
|
`steam-desktop-autostart.service` when it's there). That's refused in gaming
|
||||||
|
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
|
||||||
|
there (added by hand, or with the path from before 2.5.0) is updated, not
|
||||||
|
added twice; what was done is recorded per account (state `steamgame`:
|
||||||
|
`<account>=<appid> added|updated`) and a copy of each list is kept in the
|
||||||
|
state directory before the first change. Turning it off (or the shortcut)
|
||||||
|
removes every entry for the start script, since it can't start anything
|
||||||
|
without it.
|
||||||
|
|
||||||
|
Started from Steam, the app re-executes itself without Steam's overlay
|
||||||
|
(`LD_PRELOAD` of `gameoverlayrenderer.so` makes Qt abort) and
|
||||||
|
`steamify-app.sh` keeps it in the foreground (`SteamGameId`), or Steam
|
||||||
|
counts the game as ended right away and stops giving it the controller.
|
||||||
|
|
||||||
## Update notifications
|
## Update notifications
|
||||||
|
|
||||||
The **Update notifications** option (new in 2.5.0, ticked by default)
|
The **Update notifications** option (new in 2.5.0, ticked by default)
|
||||||
@@ -389,6 +457,31 @@ steamos-session-select persistent # remember the last-used session across reboo
|
|||||||
steamos-session-select oneshot # always start in gamescope (default, like a Deck)
|
steamos-session-select oneshot # always start in gamescope (default, like a Deck)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`steamify.sh --boot gamescope|desktop` sets where the PC starts after a
|
||||||
|
restart (the menu's Boot into row) from a script: it needs the SteamOS
|
||||||
|
conversion and changes nothing else, not even the updates a normal run would
|
||||||
|
apply. Exit code 1 without the conversion or with another value.
|
||||||
|
|
||||||
|
## Install-time mode (`--defaults`)
|
||||||
|
|
||||||
|
For an installer (the Steam Machine ISO), without a session or prompts
|
||||||
|
(passwordless sudo required):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
steamify.sh --defaults # what the menu would preselect
|
||||||
|
steamify.sh --defaults --options gaming,theme,cec,machine --boot desktop
|
||||||
|
steamify.sh --defaults --list # what --defaults can set up here, as JSON
|
||||||
|
```
|
||||||
|
|
||||||
|
`--options` turns on exactly the listed items (the menu's ids: `gaming`,
|
||||||
|
`theme`, `glyphs`, `single`, `launcher`, `notify`, `vram`, `cec`, `machine`,
|
||||||
|
`poweroff`), everything else off; an item that's on brings its parent
|
||||||
|
(single user the conversion, the power-off fix Steam Machine support). An
|
||||||
|
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
||||||
|
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
||||||
|
`bios` in the list: exit code 1 before anything changes. What needs a
|
||||||
|
Plasma session waits for the first login (`lib/first-login.sh`).
|
||||||
|
|
||||||
With `Relogin=true`, a gamescope session that fails to start is restarted
|
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
|
||||||
[TROUBLESHOOTING.md](TROUBLESHOOTING.md) for the way out.
|
[TROUBLESHOOTING.md](TROUBLESHOOTING.md) for the way out.
|
||||||
@@ -414,12 +507,14 @@ immediately, which can turn into a loop - see
|
|||||||
| `lib/cec.sh` | HDMI-CEC: Valve's `cecd` and friends from its `holo` repository |
|
| `lib/cec.sh` | HDMI-CEC: Valve's `cecd` and friends from its `holo` repository |
|
||||||
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager |
|
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager |
|
||||||
| `lib/fremont-poweroff.sh` | Steam Machine support: the power-off fix (DKMS module from `patches/`) |
|
| `lib/fremont-poweroff.sh` | Steam Machine support: the power-off fix (DKMS module from `patches/`) |
|
||||||
|
| `lib/steam-game.sh` | Add as non-Steam game: Steamify in the Steam library (`patches/steam-shortcuts.py`) |
|
||||||
| `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer |
|
| `lib/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/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 |
|
||||||
| `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README |
|
| `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README |
|
||||||
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`), with `patches/` and `services/` embedded |
|
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`), with `patches/` and `services/` embedded |
|
||||||
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
|
| `.github/workflows/bundle.yml` | Builds and checks it on every push (GitHub and a Gitea mirror); publishes it on `main`, and starts the Steamify ISO's release |
|
||||||
|
|
||||||
The single-file version is generated: on every push to `main`, GitHub
|
The single-file version is generated: on every push to `main`, GitHub
|
||||||
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
|
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ restarted right away (`Relogin=true`), which is why it can loop.
|
|||||||
Run the wizard again and press `a` in the menu to re-apply everything that's
|
Run the wizard again and press `a` in the menu to re-apply everything that's
|
||||||
on (also useful after a CachyOS update). To undo a part, untick it.
|
on (also useful after a CachyOS update). To undo a part, untick it.
|
||||||
|
|
||||||
|
## "Target OS name ... not found in /boot/limine.conf"
|
||||||
|
|
||||||
|
limine-snapper-sync finds the boot entries by the OS name. Steamify never
|
||||||
|
changes that name (it only adds version keys to `/etc/os-release`), and pins
|
||||||
|
`TARGET_OS_NAME="CachyOS"` in `/etc/default/limine`. If you see this message,
|
||||||
|
check that `PRETTY_NAME` in `/etc/os-release` still says `CachyOS`, or set
|
||||||
|
`TARGET_OS_NAME` in `/etc/default/limine` to the name your boot entries use.
|
||||||
|
|
||||||
## The LED bar on the Steam Machine stays dark
|
## The LED bar on the Steam Machine stays dark
|
||||||
|
|
||||||
Restart once more; a freshly installed driver often needs a reboot. The menu
|
Restart once more; a freshly installed driver often needs a reboot. The menu
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 492 KiB After Width: | Height: | Size: 519 KiB |
@@ -177,6 +177,7 @@ backend_apply() {
|
|||||||
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
|
||||||
|
os_version_refresh
|
||||||
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " =~ \ (gaming|single|boot|kpin)\ ]] && RESTART_FOR_LOGIN=true
|
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " =~ \ (gaming|single|boot|kpin)\ ]] && RESTART_FOR_LOGIN=true
|
||||||
backend_event finished "\"failed\":$(json_list "${failed[@]}"),\"restart\":$(restart_needed && echo true || echo false)"
|
backend_event finished "\"failed\":$(json_list "${failed[@]}"),\"restart\":$(restart_needed && echo true || echo false)"
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-21
@@ -26,6 +26,10 @@ CEC_DKMS_VER=1
|
|||||||
CEC_DKMS_SRC="/usr/src/$CEC_DKMS_NAME-$CEC_DKMS_VER"
|
CEC_DKMS_SRC="/usr/src/$CEC_DKMS_NAME-$CEC_DKMS_VER"
|
||||||
CEC_DRIVER_URL="https://raw.githubusercontent.com/evlaV/linux-integration/10c8c8800ccd3ae359203b4eefb6479f613b3b8e/drivers/media/cec/platform/cros-ec/cros-ec-cec.c"
|
CEC_DRIVER_URL="https://raw.githubusercontent.com/evlaV/linux-integration/10c8c8800ccd3ae359203b4eefb6479f613b3b8e/drivers/media/cec/platform/cros-ec/cros-ec-cec.c"
|
||||||
CEC_DRIVER_SHA256=e89fd4e87fceb32d713ffc59b64794779b3c2b3c012b0e2f2e9f0c40b42f4373
|
CEC_DRIVER_SHA256=e89fd4e87fceb32d713ffc59b64794779b3c2b3c012b0e2f2e9f0c40b42f4373
|
||||||
|
# Downloaded once, then kept: raw.githubusercontent.com rate-limits (HTTP 429) repeated downloads
|
||||||
|
# from one address, and turning CEC off and on again needs no network then. Named after its
|
||||||
|
# checksum, so a new pin (a new commit and checksum above) downloads its file once by itself.
|
||||||
|
CEC_DRIVER_CACHE="/var/cache/steamify/cros-ec-cec-${CEC_DRIVER_SHA256:0:12}.c"
|
||||||
|
|
||||||
cec_link_steamos_manager() {
|
cec_link_steamos_manager() {
|
||||||
# On a Steam Machine: steamos-manager writes cecd's config from Steam's
|
# On a Steam Machine: steamos-manager writes cecd's config from Steam's
|
||||||
@@ -34,11 +38,11 @@ cec_link_steamos_manager() {
|
|||||||
# called by Steam Machine support, which installs steamos-manager after
|
# called by Steam Machine support, which installs steamos-manager after
|
||||||
# this item ran.
|
# this item ran.
|
||||||
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
|
pacman -Q steamos-manager >/dev/null 2>&1 || return 0
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
systemctl --user enable steamos-manager-configure-cecd.service 2>/dev/null
|
user_systemctl enable steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
systemctl --user start steamos-manager-configure-cecd.service 2>/dev/null
|
user_systemctl start steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
systemctl --user restart cecd.service 2>/dev/null
|
user_systemctl restart cecd.service 2>/dev/null
|
||||||
systemctl --user restart steamos-manager.service 2>/dev/null
|
user_systemctl restart steamos-manager.service 2>/dev/null
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,10 +55,10 @@ cec_status() { cec_installed && [[ -f "$CEC_STEAM_DROPIN" ]] && cec_driver_ok; }
|
|||||||
|
|
||||||
cec_reload_driver() {
|
cec_reload_driver() {
|
||||||
# cecd keeps /dev/cec0 open, so the old module can't be unloaded under it.
|
# cecd keeps /dev/cec0 open, so the old module can't be unloaded under it.
|
||||||
systemctl --user stop cecd.service 2>/dev/null
|
user_systemctl stop cecd.service 2>/dev/null
|
||||||
sudo modprobe -r cros_ec_cec 2>/dev/null
|
sudo modprobe -r cros_ec_cec 2>/dev/null
|
||||||
sudo modprobe cros_ec_cec 2>/dev/null
|
sudo modprobe cros_ec_cec 2>/dev/null
|
||||||
systemctl --user start cecd.service 2>/dev/null
|
user_systemctl start cecd.service 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
cec_driver_enable() {
|
cec_driver_enable() {
|
||||||
@@ -65,12 +69,19 @@ cec_driver_enable() {
|
|||||||
fi
|
fi
|
||||||
install_kernel_headers || return 1
|
install_kernel_headers || return 1
|
||||||
tmp="$(mktemp -d)"
|
tmp="$(mktemp -d)"
|
||||||
info "Downloading Valve's Steam Machine CEC driver..."
|
if [[ -f "$CEC_DRIVER_CACHE" ]] && echo "$CEC_DRIVER_SHA256 $CEC_DRIVER_CACHE" | sha256sum -c --quiet - 2>/dev/null; then
|
||||||
if ! curl -fsL "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
||||||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
else
|
||||||
rm -rf "$tmp"
|
info "Downloading Valve's Steam Machine CEC driver..."
|
||||||
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||||
return 1
|
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
||||||
|
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
||||||
|
sudo install -Dm644 "$tmp/cros-ec-cec.c" "$CEC_DRIVER_CACHE"
|
||||||
fi
|
fi
|
||||||
# So it finds amdgpu's HDMI port (see the patch for why).
|
# So it finds amdgpu's HDMI port (see the patch for why).
|
||||||
patch_file cros-ec-cec-single-port.patch | patch -s -d "$tmp" -p1 ||
|
patch_file cros-ec-cec-single-port.patch | patch -s -d "$tmp" -p1 ||
|
||||||
@@ -154,10 +165,13 @@ cec_enable() {
|
|||||||
sudo tee "$CEC_STEAM_ENV" >/dev/null
|
sudo tee "$CEC_STEAM_ENV" >/dev/null
|
||||||
printf '%s\n' "# Written by Steamify: overrides STEAM_ENABLE_CEC=0 from the gaming mode script." \
|
printf '%s\n' "# Written by Steamify: overrides STEAM_ENABLE_CEC=0 from the gaming mode script." \
|
||||||
'[Service]' "EnvironmentFile=-$CEC_STEAM_ENV" | sudo tee "$CEC_STEAM_DROPIN" >/dev/null
|
'[Service]' "EnvironmentFile=-$CEC_STEAM_ENV" | sudo tee "$CEC_STEAM_DROPIN" >/dev/null
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
|
# The TV remote's volume keys: SteamOS enables this socket through its
|
||||||
|
# preset, which pacman doesn't apply, so nothing else does on CachyOS.
|
||||||
|
user_systemctl enable --now cec-audio-control.socket 2>/dev/null
|
||||||
cec_link_steamos_manager
|
cec_link_steamos_manager
|
||||||
if compgen -G "/dev/cec*" >/dev/null; then
|
if compgen -G "/dev/cec*" >/dev/null; then
|
||||||
systemctl --user restart cecd.service 2>/dev/null
|
user_systemctl restart cecd.service 2>/dev/null
|
||||||
ok "HDMI-CEC on ($(cd /dev && echo cec*)); Steam shows its settings from the next gaming mode start."
|
ok "HDMI-CEC on ($(cd /dev && echo cec*)); Steam shows its settings from the next gaming mode start."
|
||||||
info "Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
|
info "Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
|
||||||
else
|
else
|
||||||
@@ -168,20 +182,20 @@ cec_enable() {
|
|||||||
|
|
||||||
cec_disable() {
|
cec_disable() {
|
||||||
info "Removing HDMI-CEC..."
|
info "Removing HDMI-CEC..."
|
||||||
systemctl --user disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
|
user_systemctl disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
|
||||||
systemctl --user disable steamos-manager-configure-cecd.service 2>/dev/null
|
user_systemctl disable steamos-manager-configure-cecd.service 2>/dev/null
|
||||||
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
|
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
|
||||||
cec_driver_disable
|
cec_driver_disable
|
||||||
sudo rm -f "$CEC_ORDER_DROPIN" "$CEC_STEAM_DROPIN" "$CEC_STEAM_ENV"
|
sudo rm -f "$CEC_ORDER_DROPIN" "$CEC_STEAM_DROPIN" "$CEC_STEAM_ENV"
|
||||||
sudo rmdir "$(dirname "$CEC_ORDER_DROPIN")" "$(dirname "$CEC_STEAM_DROPIN")" "$(dirname "$CEC_STEAM_ENV")" 2>/dev/null
|
sudo rmdir "$(dirname "$CEC_ORDER_DROPIN")" "$(dirname "$CEC_STEAM_DROPIN")" "$(dirname "$CEC_STEAM_ENV")" 2>/dev/null
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
|
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
|
||||||
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
|
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
|
||||||
state_clear cec
|
state_clear cec
|
||||||
fi
|
fi
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
systemctl --user is-active -q steamos-manager.service 2>/dev/null &&
|
user_systemctl is-active -q steamos-manager.service 2>/dev/null &&
|
||||||
systemctl --user restart steamos-manager.service
|
user_systemctl restart steamos-manager.service
|
||||||
ok "HDMI-CEC removed."
|
ok "HDMI-CEC removed."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,5 +203,5 @@ cec_overview() {
|
|||||||
# For the menu's kernel overview.
|
# For the menu's kernel overview.
|
||||||
local dev="none"
|
local dev="none"
|
||||||
compgen -G "/dev/cec*" >/dev/null && dev="$(cd /dev && echo cec*)"
|
compgen -G "/dev/cec*" >/dev/null && dev="$(cd /dev && echo cec*)"
|
||||||
echo "CEC devices: $dev cecd: $(systemctl --user is-active cecd 2>/dev/null)"
|
echo "CEC devices: $dev cecd: $(user_systemctl is-active cecd 2>/dev/null)"
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,30 @@ require_root_helper() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user_session() {
|
||||||
|
# A running user systemd and session bus. Not in the installer's chroot,
|
||||||
|
# where the ISO applies Steamify for a user who has never logged in.
|
||||||
|
[[ -S "${XDG_RUNTIME_DIR:-/nonexistent}/bus" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
user_systemctl() {
|
||||||
|
# systemctl --user, also without a session: then only the unit files
|
||||||
|
# change (enable/disable through --root); starting and stopping is left
|
||||||
|
# to the first login, which starts what's enabled anyway.
|
||||||
|
if user_session; then systemctl --user "$@"; return; fi
|
||||||
|
local a verb="" args=()
|
||||||
|
for a in "$@"; do
|
||||||
|
[[ "$a" == --now ]] && continue
|
||||||
|
[[ -z "$verb" && "$a" != -* ]] && verb="$a"
|
||||||
|
args+=("$a")
|
||||||
|
done
|
||||||
|
case "$verb" in
|
||||||
|
enable|disable|is-enabled|mask|unmask) systemctl --user --root=/ "${args[@]}" ;;
|
||||||
|
is-active) return 1 ;;
|
||||||
|
*) return 0 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
plasma_applets() {
|
plasma_applets() {
|
||||||
# Print "containment:applet" for every applet of plugin $1 in the
|
# Print "containment:applet" for every applet of plugin $1 in the
|
||||||
# user's Plasma layout, for kwriteconfig6 --group paths.
|
# user's Plasma layout, for kwriteconfig6 --group paths.
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# The ISO applies Steamify in the installer, before the user ever logged
|
||||||
|
# in (steamify.sh --defaults without a session). What needs Plasma's first
|
||||||
|
# layout is finished at the first desktop login, by a one-time autostart
|
||||||
|
# that then opens the app, next to CachyOS Hello.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
||||||
|
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
||||||
|
|
||||||
|
first_login_schedule() {
|
||||||
|
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
||||||
|
#!/bin/bash
|
||||||
|
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
||||||
|
set -o pipefail
|
||||||
|
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
|
||||||
|
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
||||||
|
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
||||||
|
EOF2
|
||||||
|
printf '%s\n' '[Desktop Entry]' 'Type=Application' 'Name=Steamify first login' \
|
||||||
|
"Exec=$FIRST_LOGIN_SCRIPT" 'OnlyShowIn=KDE;' 'X-KDE-autostart-phase=2' 'NoDisplay=true' |
|
||||||
|
install_executable "$FIRST_LOGIN_ENTRY" 644
|
||||||
|
}
|
||||||
|
|
||||||
|
first_login_run() {
|
||||||
|
# plasmashell has just laid out the desktop from the look-and-feel
|
||||||
|
# package; wait for its config, then put single user's launcher
|
||||||
|
# settings on the new launcher.
|
||||||
|
local _
|
||||||
|
for _ in $(seq 30); do
|
||||||
|
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
if single_status; then
|
||||||
|
stop_plasmashell_for_edit
|
||||||
|
single_launcher
|
||||||
|
restart_plasmashell_if_stopped
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -18,6 +18,78 @@ gaming_status() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# What Steam shows in its System settings besides the OS name (which stays
|
||||||
|
# CachyOS's, for legal clarity and because limine-snapper-sync finds the boot
|
||||||
|
# entries by it): the SteamOS release as the OS version, steam-machine as the
|
||||||
|
# codename, Steamify with its version as the variant (os-release VERSION_ID,
|
||||||
|
# VERSION_CODENAME, VARIANT_ID; see patches/steamify-os-release.sh).
|
||||||
|
OS_NAME_SCRIPT=/usr/local/libexec/steamify-os-release
|
||||||
|
OS_NAME_HOOK=/etc/pacman.d/hooks/zz-steamify-os-release.hook
|
||||||
|
# limine's tools take the OS name from TARGET_OS_NAME, else os-release's
|
||||||
|
# PRETTY_NAME: pinned to CachyOS, the boot entries never depend on os-release.
|
||||||
|
LIMINE_DEFAULTS=/etc/default/limine
|
||||||
|
|
||||||
|
steamos_release() {
|
||||||
|
# The SteamOS release Steamify follows: Valve's newest jupiter-X.Y repo
|
||||||
|
# (where the SteamOS extras come from), as an os-release ID (no spaces or
|
||||||
|
# capitals: steamos-3.9). Offline (e.g. in the installer): the one set
|
||||||
|
# before, if any.
|
||||||
|
local v
|
||||||
|
v="$(curl -fsL --max-time 15 "$VALVE_MIRROR/" 2>/dev/null | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
|
||||||
|
if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}"
|
||||||
|
else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
os_name_enable() {
|
||||||
|
# 2.9.0 pre-releases renamed the OS itself; the name stays CachyOS's.
|
||||||
|
if grep -q '^DISTRIB_DESCRIPTION=.*with Steamify' /etc/lsb-release 2>/dev/null &&
|
||||||
|
[[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then
|
||||||
|
sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release
|
||||||
|
fi
|
||||||
|
[[ -n "$(kreadconfig6 --file kcm-about-distrorc --group General --key Name 2>/dev/null)" ]] &&
|
||||||
|
kset gaming kcm-about-distrorc General Name --delete
|
||||||
|
# About this System: os-release's VERSION (CachyOS has none) instead of
|
||||||
|
# VERSION_ID, which is the SteamOS release now.
|
||||||
|
kset gaming kcm-about-distrorc General UseOSReleaseVersion true
|
||||||
|
patch_file steamify-os-release.sh | fill VERSION="$VERSION" STEAMOS="$(steamos_release)" |
|
||||||
|
sudo install -Dm755 /dev/stdin "$OS_NAME_SCRIPT" &&
|
||||||
|
patch_file steamify-os-release.hook | fill SCRIPT="$OS_NAME_SCRIPT" |
|
||||||
|
sudo install -Dm644 /dev/stdin "$OS_NAME_HOOK" &&
|
||||||
|
sudo "$OS_NAME_SCRIPT" || { err "Setting Steamify's version for Steam failed."; return 1; }
|
||||||
|
if [[ -f "$LIMINE_DEFAULTS" ]] && ! grep -q '^TARGET_OS_NAME=' "$LIMINE_DEFAULTS"; then
|
||||||
|
backup_file "$LIMINE_DEFAULTS"
|
||||||
|
printf '%s\n' 'TARGET_OS_NAME="CachyOS"' | sudo tee -a "$LIMINE_DEFAULTS" > /dev/null
|
||||||
|
state_set gaming limine_target 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
os_name_disable() {
|
||||||
|
sudo rm -f "$OS_NAME_HOOK" "$OS_NAME_SCRIPT"
|
||||||
|
[[ -f /etc/os-release ]] && sudo sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release
|
||||||
|
# CachyOS's own values back, the way its hooks write them.
|
||||||
|
if [[ -x /usr/share/libalpm/scripts/cachyos-branding ]]; then
|
||||||
|
sudo /usr/share/libalpm/scripts/cachyos-branding os-release
|
||||||
|
# Undoes 2.9.0 pre-releases, which changed lsb-release's name too.
|
||||||
|
sudo /usr/share/libalpm/scripts/cachyos-branding lsb-release
|
||||||
|
fi
|
||||||
|
if [[ -n "$(state_get gaming limine_target)" ]]; then
|
||||||
|
sudo sed -i '/^TARGET_OS_NAME="CachyOS"$/d' "$LIMINE_DEFAULTS"
|
||||||
|
state_set gaming limine_target ""
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
os_version_refresh() {
|
||||||
|
# After every run that changed something (sudo is at hand then): Steam's
|
||||||
|
# OS version follows Steamify's, not just the one that set it up. Silent:
|
||||||
|
# the app reads the backend's stdout as JSON.
|
||||||
|
gaming_status 2>/dev/null || return 0
|
||||||
|
grep -qx "VARIANT_ID=steamify-$VERSION" /etc/os-release 2>/dev/null && return 0
|
||||||
|
os_name_enable > /dev/null 2>&1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
gaming_enable() {
|
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.
|
||||||
@@ -37,6 +109,7 @@ gaming_enable() {
|
|||||||
esac
|
esac
|
||||||
create_desktop_shortcut
|
create_desktop_shortcut
|
||||||
steam_enable
|
steam_enable
|
||||||
|
os_name_enable || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
gaming_disable() {
|
gaming_disable() {
|
||||||
@@ -49,6 +122,8 @@ gaming_disable() {
|
|||||||
switch_to_plasmalogin
|
switch_to_plasmalogin
|
||||||
remove_desktop_shortcut
|
remove_desktop_shortcut
|
||||||
steam_disable
|
steam_disable
|
||||||
|
krevert gaming
|
||||||
|
os_name_disable
|
||||||
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)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+93
-4
@@ -5,12 +5,12 @@
|
|||||||
|
|
||||||
# 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 theme glyphs single launcher notify vram cec machine poweroff kpin hdmi bios)
|
COMPONENTS=(gaming boot theme glyphs single launcher steamgame notify 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 [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
declare -A PARENT=([boot]=gaming [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,
|
||||||
@@ -25,8 +25,8 @@ NO_PRESELECT=(boot cec kpin hdmi)
|
|||||||
# FEATURE_BASELINE.
|
# FEATURE_BASELINE.
|
||||||
FEATURE_BASELINE=2.1.0
|
FEATURE_BASELINE=2.1.0
|
||||||
declare -A FEATURE_VERSION=(
|
declare -A FEATURE_VERSION=(
|
||||||
[gaming]=2.1.0 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
[gaming]=2.9.0 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
||||||
[launcher]=2.1.0 [cec]=2.1.0 [machine]=2.2.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0
|
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1
|
||||||
[kpin]=2.1.0 [hdmi]=2.1.0
|
[kpin]=2.1.0 [hdmi]=2.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,6 +37,7 @@ declare -A LABEL=(
|
|||||||
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
|
||||||
[single]="Single user mode: no password, lock screen or log out (SDDM)"
|
[single]="Single user mode: no password, lock screen or log out (SDDM)"
|
||||||
[launcher]="Steamify shortcut: the app on the desktop, Steamify Terminal in the launcher"
|
[launcher]="Steamify shortcut: the app on the desktop, Steamify Terminal in the launcher"
|
||||||
|
[steamgame]="Add as non-Steam game: Steamify in your Steam library, for the controller and gaming mode"
|
||||||
[notify]="Update notifications: a notification when there's a new Steamify, never updates by itself"
|
[notify]="Update notifications: a notification when there's a new Steamify, never updates by itself"
|
||||||
[vram]="VRAM booster: the game in front keeps its VRAM, background apps make room"
|
[vram]="VRAM booster: the game in front keeps its VRAM, background apps make room"
|
||||||
[cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)"
|
[cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)"
|
||||||
@@ -52,6 +53,7 @@ component_available() {
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
machine|poweroff) machine_available ;;
|
machine|poweroff) machine_available ;;
|
||||||
vram) vram_available ;;
|
vram) vram_available ;;
|
||||||
|
steamgame) steamgame_available ;;
|
||||||
kpin) kpin_available ;;
|
kpin) kpin_available ;;
|
||||||
hdmi) hdmi_available ;;
|
hdmi) hdmi_available ;;
|
||||||
bios) bios_available ;;
|
bios) bios_available ;;
|
||||||
@@ -177,6 +179,88 @@ detect_components() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaults_options() {
|
||||||
|
# defaults_options [--options <id>[,<id>...]] [--boot gamescope|desktop]:
|
||||||
|
# what --defaults sets up, from the Steam Machine ISO's installer page.
|
||||||
|
# --options: exactly these items on, every other off (without it, the
|
||||||
|
# menu's preselection). An item that's on brings its parent (single user
|
||||||
|
# the conversion, like ticking it in the menu); one this PC can't use is
|
||||||
|
# left off with a warning. --boot desktop needs the conversion. Returns 1
|
||||||
|
# on an unknown option, item or value.
|
||||||
|
local c ids list=false boot=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
# Both take a value: without one, shift 2 fails and never shifts, so
|
||||||
|
# the loop would spin forever.
|
||||||
|
[[ "$1" == --options || "$1" == --boot ]] && [[ $# -lt 2 ]] && { err "$1 needs a value"; return 1; }
|
||||||
|
case "$1" in
|
||||||
|
--options)
|
||||||
|
list=true
|
||||||
|
IFS=, read -ra ids <<< "$2"
|
||||||
|
shift 2 ;;
|
||||||
|
--boot)
|
||||||
|
case "$2" in
|
||||||
|
gamescope|desktop) boot="$2" ;;
|
||||||
|
*) err "--boot takes gamescope or desktop"; return 1 ;;
|
||||||
|
esac
|
||||||
|
shift 2 ;;
|
||||||
|
*) err "Unknown option: $1"; return 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ "$list" == true ]]; then
|
||||||
|
for c in "${ids[@]}"; do
|
||||||
|
[[ -n "$c" ]] || continue
|
||||||
|
[[ -n "${LABEL[$c]:-}" ]] || { err "Unknown item: $c"; return 1; }
|
||||||
|
[[ "$c" == boot ]] && { err "Where to start is --boot, not an item."; return 1; }
|
||||||
|
is_action "$c" && { err "$c can't be part of the install."; return 1; }
|
||||||
|
done
|
||||||
|
for c in "${COMPONENTS[@]}"; do WANTED[$c]=0; done
|
||||||
|
for c in "${ids[@]}"; do
|
||||||
|
[[ -n "$c" ]] || continue
|
||||||
|
if component_available "$c" && component_selectable "$c"; then
|
||||||
|
WANTED[$c]=1
|
||||||
|
else
|
||||||
|
warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[[ "${WANTED[single]}" == 1 ]] && WANTED[gaming]=1
|
||||||
|
for c in "${COMPONENTS[@]}"; do
|
||||||
|
[[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
case "$boot" in
|
||||||
|
desktop)
|
||||||
|
[[ "${WANTED[gaming]}" == 1 ]] || { err "--boot desktop needs the SteamOS conversion (gaming)."; return 1; }
|
||||||
|
WANTED[boot]=1 ;;
|
||||||
|
gamescope) WANTED[boot]=0 ;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults_list() {
|
||||||
|
# --defaults --list: what --defaults can set up on this PC, as one JSON
|
||||||
|
# array, for an installer page (the Steam Machine ISO builds its Steamify
|
||||||
|
# page from it, so new items show up without a new ISO). Per item: id,
|
||||||
|
# label, hint, kind (toggle, or choice for boot: on = desktop), parent,
|
||||||
|
# on (preselected like a first run) and selectable. Actions, retired
|
||||||
|
# items and items this PC can't use (e.g. no Steam account yet) are
|
||||||
|
# left out. Read-only: no sudo, no state.
|
||||||
|
local c kind on sel items=""
|
||||||
|
for c in "${COMPONENTS[@]}"; do
|
||||||
|
component_available "$c" || continue
|
||||||
|
is_action "$c" && continue
|
||||||
|
[[ "$c" == kpin || "$c" == hdmi ]] && continue
|
||||||
|
kind=toggle; [[ "$c" == boot ]] && kind=choice
|
||||||
|
sel=false; component_selectable "$c" && sel=true
|
||||||
|
on=false
|
||||||
|
[[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true
|
||||||
|
[[ "$c" == cec ]] && machine_available && on=true
|
||||||
|
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
||||||
|
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
||||||
|
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"on\":$on,\"selectable\":$sel}"
|
||||||
|
done
|
||||||
|
printf '[%s]\n' "$items"
|
||||||
|
}
|
||||||
|
|
||||||
toggle_component() {
|
toggle_component() {
|
||||||
local c="$1"
|
local c="$1"
|
||||||
component_selectable "$c" || return 1
|
component_selectable "$c" || return 1
|
||||||
@@ -192,6 +276,10 @@ toggle_component() {
|
|||||||
if [[ "$c" == machine && "${WANTED[machine]}" == 0 ]]; then WANTED[kpin]=0; WANTED[bios]=0; fi
|
if [[ "$c" == machine && "${WANTED[machine]}" == 0 ]]; then WANTED[kpin]=0; WANTED[bios]=0; fi
|
||||||
if [[ "$c" == kpin && "${WANTED[kpin]}" == 1 ]]; then WANTED[machine]=1; fi
|
if [[ "$c" == kpin && "${WANTED[kpin]}" == 1 ]]; then WANTED[machine]=1; fi
|
||||||
if [[ "$c" == bios && "${WANTED[bios]}" == 1 ]]; then WANTED[machine]=1; fi
|
if [[ "$c" == bios && "${WANTED[bios]}" == 1 ]]; then WANTED[machine]=1; fi
|
||||||
|
# Steam starts Steamify through the shortcut's start script.
|
||||||
|
# Opt-out, like the power-off fix: ticked along with the shortcut.
|
||||||
|
if [[ "$c" == launcher ]] && component_available steamgame; then WANTED[steamgame]=${WANTED[launcher]}; fi
|
||||||
|
if [[ "$c" == steamgame && "${WANTED[steamgame]}" == 1 ]]; then WANTED[launcher]=1; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
@@ -377,5 +465,6 @@ apply_changes() {
|
|||||||
if "${c}_enable"; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
if "${c}_enable"; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
feature_record_unticked
|
feature_record_unticked
|
||||||
|
os_version_refresh
|
||||||
FAILED=("${failed[@]}")
|
FAILED=("${failed[@]}")
|
||||||
}
|
}
|
||||||
@@ -101,6 +101,24 @@ single_launcher() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_launcher_drop() {
|
||||||
|
# The theme's layout backup is taken when it's turned on: with single
|
||||||
|
# user on then, it holds single's launcher keys, and restoring it after
|
||||||
|
# single was turned off brings them back. Drop exactly single's values
|
||||||
|
# (a launcher set up differently by the user is left alone).
|
||||||
|
local applet
|
||||||
|
local -a kick_args
|
||||||
|
for applet in $(plasma_applets org.kde.plasma.kickoff); do
|
||||||
|
kick_args=(--file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}"
|
||||||
|
--group Applets --group "${applet#*:}" --group Configuration --group General)
|
||||||
|
[[ "$(kreadconfig6 "${kick_args[@]}" --key primaryActions)" == 3 ]] &&
|
||||||
|
kwriteconfig6 "${kick_args[@]}" --key primaryActions --delete
|
||||||
|
[[ "$(kreadconfig6 "${kick_args[@]}" --key systemFavorites)" == 'suspend,reboot,shutdown' ]] &&
|
||||||
|
kwriteconfig6 "${kick_args[@]}" --key systemFavorites --delete
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
single_enable() {
|
single_enable() {
|
||||||
info "Turning off the lock screen, user switching and logging out..."
|
info "Turning off the lock screen, user switching and logging out..."
|
||||||
stop_plasmashell_for_edit
|
stop_plasmashell_for_edit
|
||||||
|
|||||||
+1
-1
@@ -123,7 +123,7 @@ migrate_layout() {
|
|||||||
"$(wizard_desktop_dir)/$WIZARD_DESKTOP_NAME"; do
|
"$(wizard_desktop_dir)/$WIZARD_DESKTOP_NAME"; do
|
||||||
[[ -f "$f" ]] && sed -i "s|$old_bin/|$STEAMIFY_BIN/|g" "$f"
|
[[ -f "$f" ]] && sed -i "s|$old_bin/|$STEAMIFY_BIN/|g" "$f"
|
||||||
done
|
done
|
||||||
systemctl --user daemon-reload 2>/dev/null
|
user_systemctl daemon-reload 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [[ -f "$old_icon" ]]; then
|
if [[ -f "$old_icon" ]]; then
|
||||||
if [[ -e "$WIZARD_ICON" ]]; then rm -f "$old_icon"; else mv "$old_icon" "$WIZARD_ICON"; fi
|
if [[ -e "$WIZARD_ICON" ]]; then rm -f "$old_icon"; else mv "$old_icon" "$WIZARD_ICON"; fi
|
||||||
|
|||||||
@@ -22,18 +22,18 @@ steam_enable() {
|
|||||||
rm -f "$HOME/.config/autostart/steam.desktop"
|
rm -f "$HOME/.config/autostart/steam.desktop"
|
||||||
|
|
||||||
# Reload user systemd context and activate the background loop
|
# Reload user systemd context and activate the background loop
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
systemctl --user enable --now steam-desktop-autostart.service
|
user_systemctl enable --now steam-desktop-autostart.service
|
||||||
|
|
||||||
ok "Steam UI parameters and keyboard autostart deployed successfully."
|
ok "Steam UI parameters and keyboard autostart deployed successfully."
|
||||||
}
|
}
|
||||||
|
|
||||||
steam_disable() {
|
steam_disable() {
|
||||||
info "Removing Steam desktop autostart..."
|
info "Removing Steam desktop autostart..."
|
||||||
systemctl --user disable --now steam-desktop-autostart.service 2>/dev/null
|
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
||||||
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \
|
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \
|
||||||
"$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
"$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
ok "Steam desktop settings removed (takes full effect at next login)."
|
ok "Steam desktop settings removed (takes full effect at next login)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# "Add as non-Steam game" (steamgame), a sub-option of the Steamify shortcut:
|
||||||
|
# Steamify CachyOS in the Steam library, so Steam can start it: with Steam
|
||||||
|
# Input it then gets the controller (a Steam Controller only talks to Steam
|
||||||
|
# while Steam runs), in gaming mode too. Steam reads its non-Steam games
|
||||||
|
# (userdata/<id>/config/shortcuts.vdf, binary; patches/steam-shortcuts.py)
|
||||||
|
# only at startup and writes them back on exit, so Steam is closed for the
|
||||||
|
# edit and started again. That's refused while a Steam session depends on it:
|
||||||
|
# in gaming mode, or with this run started from Steam itself. What it did is
|
||||||
|
# recorded per Steam account (state steamgame, "<account>": "<appid> added"
|
||||||
|
# or "<appid> updated", for an entry that was there already): Steam rewrites
|
||||||
|
# the file on exit, so a mark inside the entry could be lost; the start
|
||||||
|
# script's path in it is the other sign it's ours.
|
||||||
|
# Sourced by steamify.sh; not meant to be run on its own.
|
||||||
|
|
||||||
|
STEAM_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/Steam"
|
||||||
|
STEAMGAME_NAME="Steamify CachyOS"
|
||||||
|
# Steam shows no SVG icons: the shortcut's icon rendered as PNG.
|
||||||
|
STEAMGAME_ICON="$STEAMIFY_DATA/steamify.png"
|
||||||
|
|
||||||
|
steamgame_files() {
|
||||||
|
# Every Steam account's shortcuts.vdf (the file may not exist yet).
|
||||||
|
local d
|
||||||
|
for d in "$STEAM_ROOT"/userdata/*/config; do
|
||||||
|
[[ -d "$d" && "$(basename "$(dirname "$d")")" != 0 ]] && echo "$d/shortcuts.vdf"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_tool() {
|
||||||
|
python3 <(patch_file steam-shortcuts.py) "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_available() { [[ -n "$(steamgame_files)" ]]; }
|
||||||
|
|
||||||
|
steamgame_status() {
|
||||||
|
local f
|
||||||
|
while IFS= read -r f; do
|
||||||
|
[[ -f "$f" ]] && steamgame_tool find "$f" "$WIZARD_APP_LAUNCHER" >/dev/null && return 0
|
||||||
|
done < <(steamgame_files)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_steam_busy() {
|
||||||
|
# Closing Steam would end what's running: gaming mode is Steam's own
|
||||||
|
# session, and a run started from Steam is one of its games.
|
||||||
|
if [[ -n "${SteamGameId:-}" ]]; then
|
||||||
|
err "Steamify was started from Steam, which has to close for this. Start it from the desktop icon, or run Steamify Terminal."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if pgrep -x gamescope >/dev/null || pgrep -f gamescope-session >/dev/null; then
|
||||||
|
err "Steam has to close for this, which would end gaming mode. Do it from the desktop."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_edit() {
|
||||||
|
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
||||||
|
# again if it was running (through our autostart unit when that's there).
|
||||||
|
local was_running=false i
|
||||||
|
if pgrep -x steam >/dev/null; then
|
||||||
|
steamgame_steam_busy && return 1
|
||||||
|
was_running=true
|
||||||
|
info "Closing Steam for a moment (it only reads its games list at startup)..."
|
||||||
|
# A Steam that's still starting ignores the request: ask again.
|
||||||
|
for ((i = 0; i < 90; i++)); do
|
||||||
|
((i % 15 == 0)) && steam -shutdown >/dev/null 2>&1
|
||||||
|
pgrep -x steam >/dev/null || break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
pgrep -x steam >/dev/null && { err "Steam didn't close; nothing changed."; return 1; }
|
||||||
|
fi
|
||||||
|
"$1"; local rc=$?
|
||||||
|
if [[ "$was_running" == true ]]; then
|
||||||
|
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
|
||||||
|
user_systemctl start steam-desktop-autostart.service
|
||||||
|
else
|
||||||
|
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
info "Steam is starting again."
|
||||||
|
fi
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_icon() {
|
||||||
|
# The PNG, or the SVG when it can't be rendered (librsvg comes with KDE).
|
||||||
|
if [[ -f "$WIZARD_ICON" ]] && command -v rsvg-convert >/dev/null &&
|
||||||
|
mkdir -p "$STEAMIFY_DATA" && rsvg-convert -w 256 -h 256 -o "$STEAMGAME_ICON" "$WIZARD_ICON" 2>/dev/null; then
|
||||||
|
echo "$STEAMGAME_ICON"
|
||||||
|
else
|
||||||
|
echo "$WIZARD_ICON"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_add_all() {
|
||||||
|
local f out icon
|
||||||
|
icon="$(steamgame_icon)"
|
||||||
|
while IFS= read -r f; do
|
||||||
|
# A copy of each account's list before the first change.
|
||||||
|
[[ -f "$f" && ! -f "$STATE_DIR/shortcuts-$(basename "$(dirname "$(dirname "$f")")").vdf" ]] &&
|
||||||
|
mkdir -p "$STATE_DIR" && cp -a "$f" "$STATE_DIR/shortcuts-$(basename "$(dirname "$(dirname "$f")")").vdf"
|
||||||
|
out="$(steamgame_tool add "$f" "$STEAMGAME_NAME" "$WIZARD_APP_LAUNCHER" "$icon" "$WIZARD_APP_ENTRY")" ||
|
||||||
|
{ err "Couldn't add Steamify to $f."; return 1; }
|
||||||
|
state_set steamgame "$(basename "$(dirname "$(dirname "$f")")")" "${out#* } ${out%% *}"
|
||||||
|
info "Steam library ($(basename "$(dirname "$(dirname "$f")")")): ${out%% *} $STEAMGAME_NAME."
|
||||||
|
done < <(steamgame_files)
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_remove_all() {
|
||||||
|
local f id
|
||||||
|
while IFS= read -r f; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
# Any entry for our start script: it can't start anything without it.
|
||||||
|
while id="$(steamgame_tool find "$f" "$WIZARD_APP_LAUNCHER")"; do
|
||||||
|
steamgame_tool remove "$f" "$id" || return 1
|
||||||
|
done
|
||||||
|
done < <(steamgame_files)
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_enable() {
|
||||||
|
[[ -x "$WIZARD_APP_LAUNCHER" ]] || { err "The Steamify shortcut isn't set up; turn that on first."; return 1; }
|
||||||
|
info "Adding $STEAMGAME_NAME to your Steam library..."
|
||||||
|
steamgame_edit steamgame_add_all || return 1
|
||||||
|
ok "Steamify is in your Steam library (non-Steam games): start it from there for the controller, in gaming mode too."
|
||||||
|
}
|
||||||
|
|
||||||
|
steamgame_disable() {
|
||||||
|
info "Removing $STEAMGAME_NAME from your Steam library..."
|
||||||
|
steamgame_edit steamgame_remove_all || return 1
|
||||||
|
state_clear steamgame
|
||||||
|
rm -f "$STEAMGAME_ICON"
|
||||||
|
ok "Steamify removed from your Steam library."
|
||||||
|
}
|
||||||
+46
-2
@@ -378,6 +378,46 @@ machine_status() {
|
|||||||
pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 && pacman -Qi steamos-manager >/dev/null 2>&1
|
pacman -Qi leds-valve-dkms-git >/dev/null 2>&1 && pacman -Qi steamos-manager >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Steam (steamwebhelper) reads the serial number for its System settings
|
||||||
|
# straight from DMI, which the kernel makes root-only; SteamOS makes it
|
||||||
|
# readable. A tmpfiles rule does that at every boot.
|
||||||
|
SERIAL_TMPFILES=/etc/tmpfiles.d/steamify-serial.conf
|
||||||
|
|
||||||
|
# Steam's Wi-Fi backend switch goes through steamos-manager, which reads and
|
||||||
|
# writes the backend in this file (SteamOS ships it); without it, it fails
|
||||||
|
# with "Wi-Fi backend not found in config". wpa_supplicant is what
|
||||||
|
# NetworkManager uses on CachyOS anyway. Not written when someone set a
|
||||||
|
# backend themselves.
|
||||||
|
WIFI_BACKEND_CONF=/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf
|
||||||
|
|
||||||
|
wifi_backend_enable() {
|
||||||
|
[[ -f "$WIFI_BACKEND_CONF" ]] && return 0
|
||||||
|
grep -rqs '^wifi.backend=' /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/conf.d && return 0
|
||||||
|
printf '%s\n' "# Written by Steamify: Steam's Wi-Fi backend setting (steamos-manager)." \
|
||||||
|
'[device]' 'wifi.backend=wpa_supplicant' | sudo install -Dm644 /dev/stdin "$WIFI_BACKEND_CONF" ||
|
||||||
|
{ err "Writing the Wi-Fi backend setting failed."; return 1; }
|
||||||
|
state_set machine wifi_backend 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_backend_disable() {
|
||||||
|
[[ -n "$(state_get machine wifi_backend)" ]] || return 0
|
||||||
|
sudo rm -f "$WIFI_BACKEND_CONF"
|
||||||
|
state_clear machine
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_enable() {
|
||||||
|
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
||||||
|
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null &&
|
||||||
|
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
||||||
|
{ err "Making the serial number readable for Steam failed."; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_disable() {
|
||||||
|
sudo rm -f "$SERIAL_TMPFILES"
|
||||||
|
sudo chmod 0400 /sys/class/dmi/id/product_serial 2>/dev/null
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
machine_enable() {
|
machine_enable() {
|
||||||
# The pinned kernel first when it's wanted too, so DKMS builds the LED
|
# The pinned kernel first when it's wanted too, so DKMS builds the LED
|
||||||
# driver for it once, instead of for the current kernel and then again.
|
# driver for it once, instead of for the current kernel and then again.
|
||||||
@@ -403,9 +443,11 @@ EOF
|
|||||||
# for hardware and controller settings; it knows the Steam Machine from its DMI data.
|
# for hardware and controller settings; it knows the Steam Machine from its DMI data.
|
||||||
info "Installing hardware manager packages (steamos-manager & inputplumber)..."
|
info "Installing hardware manager packages (steamos-manager & inputplumber)..."
|
||||||
sudo pacman -S --needed --noconfirm steamos-manager inputplumber || { err "Installing hardware manager packages failed."; return 1; }
|
sudo pacman -S --needed --noconfirm steamos-manager inputplumber || { err "Installing hardware manager packages failed."; return 1; }
|
||||||
|
serial_enable || return 1
|
||||||
|
wifi_backend_enable || return 1
|
||||||
sudo systemctl enable --now inputplumber.service
|
sudo systemctl enable --now inputplumber.service
|
||||||
sudo systemctl enable --now steamos-manager.service
|
sudo systemctl enable --now steamos-manager.service
|
||||||
systemctl --user enable steamos-manager.service 2>/dev/null
|
user_systemctl enable steamos-manager.service 2>/dev/null
|
||||||
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
|
# HDMI-CEC ran before this and couldn't link cecd to steamos-manager yet.
|
||||||
cec_status && cec_link_steamos_manager
|
cec_status && cec_link_steamos_manager
|
||||||
|
|
||||||
@@ -422,10 +464,12 @@ EOF
|
|||||||
|
|
||||||
machine_disable() {
|
machine_disable() {
|
||||||
info "Removing Steam Machine support..."
|
info "Removing Steam Machine support..."
|
||||||
systemctl --user disable --now steamos-manager.service 2>/dev/null
|
user_systemctl disable --now steamos-manager.service 2>/dev/null
|
||||||
sudo systemctl disable --now steamos-manager.service 2>/dev/null
|
sudo systemctl disable --now steamos-manager.service 2>/dev/null
|
||||||
sudo systemctl disable --now inputplumber.service 2>/dev/null
|
sudo systemctl disable --now inputplumber.service 2>/dev/null
|
||||||
sudo pacman -Rns --noconfirm steamos-manager inputplumber 2>/dev/null
|
sudo pacman -Rns --noconfirm steamos-manager inputplumber 2>/dev/null
|
||||||
|
serial_disable
|
||||||
|
wifi_backend_disable
|
||||||
sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf
|
sudo rm -f "$LED_UDEV_RULE" /etc/modules-load.d/leds-valve.conf
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
sudo modprobe -r leds-valve 2>/dev/null
|
sudo modprobe -r leds-valve 2>/dev/null
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ NOTIFY_NAME=steamify-update-check
|
|||||||
|
|
||||||
notify_status() {
|
notify_status() {
|
||||||
[[ -f "$NOTIFY_SCRIPT" ]] &&
|
[[ -f "$NOTIFY_SCRIPT" ]] &&
|
||||||
systemctl --user is-enabled -q "$NOTIFY_NAME.timer" 2>/dev/null &&
|
user_systemctl is-enabled -q "$NOTIFY_NAME.timer" 2>/dev/null &&
|
||||||
systemctl --user is-enabled -q "$NOTIFY_NAME.service" 2>/dev/null
|
user_systemctl is-enabled -q "$NOTIFY_NAME.service" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_seen() {
|
notify_seen() {
|
||||||
@@ -40,19 +40,19 @@ notify_enable() {
|
|||||||
mkdir -p "$NOTIFY_UNITS"
|
mkdir -p "$NOTIFY_UNITS"
|
||||||
service_file "$NOTIFY_NAME.service" NOTIFY_SCRIPT="$NOTIFY_SCRIPT" > "$NOTIFY_UNITS/$NOTIFY_NAME.service"
|
service_file "$NOTIFY_NAME.service" NOTIFY_SCRIPT="$NOTIFY_SCRIPT" > "$NOTIFY_UNITS/$NOTIFY_NAME.service"
|
||||||
service_file "$NOTIFY_NAME.timer" > "$NOTIFY_UNITS/$NOTIFY_NAME.timer"
|
service_file "$NOTIFY_NAME.timer" > "$NOTIFY_UNITS/$NOTIFY_NAME.timer"
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
systemctl --user enable "$NOTIFY_NAME.service" >/dev/null 2>&1 &&
|
user_systemctl enable "$NOTIFY_NAME.service" >/dev/null 2>&1 &&
|
||||||
systemctl --user enable --now "$NOTIFY_NAME.timer" >/dev/null 2>&1 ||
|
user_systemctl enable --now "$NOTIFY_NAME.timer" >/dev/null 2>&1 ||
|
||||||
{ err "Enabling the update check failed."; return 1; }
|
{ err "Enabling the update check failed."; return 1; }
|
||||||
state_set notify seen "$VERSION"
|
state_set notify seen "$VERSION"
|
||||||
ok "Update notifications on: you'll get a notification when there's a new Steamify."
|
ok "Update notifications on: you'll get a notification when there's a new Steamify."
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_disable() {
|
notify_disable() {
|
||||||
systemctl --user disable --now "$NOTIFY_NAME.timer" "$NOTIFY_NAME.service" >/dev/null 2>&1
|
user_systemctl disable --now "$NOTIFY_NAME.timer" "$NOTIFY_NAME.service" >/dev/null 2>&1
|
||||||
rm -f "$NOTIFY_UNITS/$NOTIFY_NAME.service" "$NOTIFY_UNITS/$NOTIFY_NAME.timer" "$NOTIFY_SCRIPT"
|
rm -f "$NOTIFY_UNITS/$NOTIFY_NAME.service" "$NOTIFY_UNITS/$NOTIFY_NAME.timer" "$NOTIFY_SCRIPT"
|
||||||
rmdir "$STEAMIFY_BIN" 2>/dev/null || true
|
rmdir "$STEAMIFY_BIN" 2>/dev/null || true
|
||||||
systemctl --user daemon-reload
|
user_systemctl daemon-reload
|
||||||
state_clear notify
|
state_clear notify
|
||||||
ok "Update notifications off."
|
ok "Update notifications off."
|
||||||
}
|
}
|
||||||
+21
-3
@@ -54,9 +54,17 @@ theme_enable() {
|
|||||||
# Only remove it again on disable if we were the ones installing it.
|
# Only remove it again on disable if we were the ones installing it.
|
||||||
state_set theme installed_pkg 1
|
state_set theme installed_pkg 1
|
||||||
fi
|
fi
|
||||||
|
# Without a session (the ISO's installer), for a user who has never
|
||||||
|
# logged in: the layout still CachyOS's default from /etc/skel is
|
||||||
|
# removed (after the backup below), and Plasma builds its first layout
|
||||||
|
# from the look-and-feel package, as --resetLayout does below.
|
||||||
|
local offline=false layout=~/.config/plasma-org.kde.plasma.desktop-appletsrc
|
||||||
if [[ -z "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]]; then
|
if [[ -z "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]]; then
|
||||||
err "Run this from the Plasma desktop: applying the Vapor layout needs a running Plasma session."
|
if [[ -e "$layout" ]] && ! cmp -s "$layout" "/etc/skel/.config/${layout##*/}"; then
|
||||||
return 1
|
err "Run this from the Plasma desktop: applying the Vapor layout needs a running Plasma session."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
offline=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Only the first time, so a re-apply doesn't overwrite the originals.
|
# Only the first time, so a re-apply doesn't overwrite the originals.
|
||||||
@@ -87,6 +95,12 @@ theme_enable() {
|
|||||||
kset theme kdeglobals General ColorScheme --delete
|
kset theme kdeglobals General ColorScheme --delete
|
||||||
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
|
plasma-apply-colorscheme Vapor >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
if [[ "$offline" == true ]]; then
|
||||||
|
rm -f ~/.config/plasma-org.kde.plasma.desktop-appletsrc ~/.config/plasmashellrc
|
||||||
|
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
||||||
|
ok "Vapor theme set; Plasma lays out the Vapor desktop at the first login."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
info "Applying the Vapor theme with its desktop and window layout..."
|
info "Applying the Vapor theme with its desktop and window layout..."
|
||||||
# --resetLayout is "Desktop and window layout" in System Settings: the
|
# --resetLayout is "Desktop and window layout" in System Settings: the
|
||||||
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
||||||
@@ -120,7 +134,11 @@ theme_disable() {
|
|||||||
fi
|
fi
|
||||||
# After the tools above, so keys that weren't set before are removed again.
|
# After the tools above, so keys that weren't set before are removed again.
|
||||||
krevert theme
|
krevert theme
|
||||||
single_status && single_launcher
|
if single_status; then
|
||||||
|
single_launcher
|
||||||
|
else
|
||||||
|
single_launcher_drop
|
||||||
|
fi
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true
|
qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -101,7 +101,7 @@ vram_selectable() { vram_supported || vram_status; }
|
|||||||
vram_status() {
|
vram_status() {
|
||||||
pacman -Q "${VRAM_PKGS[@]}" >/dev/null 2>&1 &&
|
pacman -Q "${VRAM_PKGS[@]}" >/dev/null 2>&1 &&
|
||||||
systemctl is-enabled -q dmemcg-booster-system.service 2>/dev/null &&
|
systemctl is-enabled -q dmemcg-booster-system.service 2>/dev/null &&
|
||||||
systemctl --user is-enabled -q dmemcg-booster-user.service 2>/dev/null
|
user_systemctl is-enabled -q dmemcg-booster-user.service 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
vram_enable() {
|
vram_enable() {
|
||||||
@@ -115,18 +115,18 @@ vram_enable() {
|
|||||||
fi
|
fi
|
||||||
sudo systemctl enable --now dmemcg-booster-system.service >/dev/null 2>&1 ||
|
sudo systemctl enable --now dmemcg-booster-system.service >/dev/null 2>&1 ||
|
||||||
{ err "Starting dmemcg-booster failed."; return 1; }
|
{ err "Starting dmemcg-booster failed."; return 1; }
|
||||||
systemctl --user enable --now dmemcg-booster-user.service >/dev/null 2>&1 ||
|
user_systemctl enable --now dmemcg-booster-user.service >/dev/null 2>&1 ||
|
||||||
{ err "Starting dmemcg-booster for $USER failed."; return 1; }
|
{ err "Starting dmemcg-booster for $USER failed."; return 1; }
|
||||||
kset vram kcgroupsrc "Foreground Booster" autostart true
|
kset vram kcgroupsrc "Foreground Booster" autostart true
|
||||||
# Started by the Plasma session from now on; start it in this one too.
|
# Started by the Plasma session from now on; start it in this one too.
|
||||||
[[ "${XDG_CURRENT_DESKTOP:-}" == KDE ]] &&
|
[[ "${XDG_CURRENT_DESKTOP:-}" == KDE ]] &&
|
||||||
systemctl --user start plasma-foreground-booster.service >/dev/null 2>&1
|
user_systemctl start plasma-foreground-booster.service >/dev/null 2>&1
|
||||||
ok "VRAM booster on: the game in front keeps its VRAM."
|
ok "VRAM booster on: the game in front keeps its VRAM."
|
||||||
}
|
}
|
||||||
|
|
||||||
vram_disable() {
|
vram_disable() {
|
||||||
local pkgs
|
local pkgs
|
||||||
systemctl --user disable --now plasma-foreground-booster.service dmemcg-booster-user.service >/dev/null 2>&1
|
user_systemctl disable --now plasma-foreground-booster.service dmemcg-booster-user.service >/dev/null 2>&1
|
||||||
sudo systemctl disable --now dmemcg-booster-system.service >/dev/null 2>&1
|
sudo systemctl disable --now dmemcg-booster-system.service >/dev/null 2>&1
|
||||||
krevert vram
|
krevert vram
|
||||||
pkgs="$(state_get vram installed_pkgs)"
|
pkgs="$(state_get vram installed_pkgs)"
|
||||||
|
|||||||
@@ -11,5 +11,7 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
|
|||||||
| `ensure-kernel-headers.sh` | `lib/steam-machine.sh` (Steam Machine support) | Run at boot: installs missing headers for every installed kernel |
|
| `ensure-kernel-headers.sh` | `lib/steam-machine.sh` (Steam Machine support) | Run at boot: installs missing headers for every installed kernel |
|
||||||
| `leds-valve-dkms.conf` | `lib/steam-machine.sh` (Steam Machine support) | `/etc/dkms` override: build the LED driver for DKMS's target kernel; appended to someone's own override, which is backed up and restored |
|
| `leds-valve-dkms.conf` | `lib/steam-machine.sh` (Steam Machine support) | `/etc/dkms` override: build the LED driver for DKMS's target kernel; appended to someone's own override, which is backed up and restored |
|
||||||
| `steamify-fremont-poweroff.dkms.conf`, `steamify-cros-ec-cec.dkms.conf` | `lib/fremont-poweroff.sh`, `lib/cec.sh` | The DKMS modules' `dkms.conf` (`fill NAME=... VERSION=...`) |
|
| `steamify-fremont-poweroff.dkms.conf`, `steamify-cros-ec-cec.dkms.conf` | `lib/fremont-poweroff.sh`, `lib/cec.sh` | The DKMS modules' `dkms.conf` (`fill NAME=... VERSION=...`) |
|
||||||
|
| `steam-shortcuts.py` | `lib/steam-game.sh` (Add as non-Steam game) | Reads and writes Steam's binary `shortcuts.vdf` (find, add or update, remove) |
|
||||||
| `steamify-notifier.py` | `lib/update-notifier.sh` (Update notifications) | The daily check: notification and tray icon when there's a new release |
|
| `steamify-notifier.py` | `lib/update-notifier.sh` (Update notifications) | The daily check: notification and tray icon when there's a new release |
|
||||||
|
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
||||||
| `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 |
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Steamify CachyOS: Steam's non-Steam games list (userdata/<id>/config/
|
||||||
|
# shortcuts.vdf, binary VDF), for "Add as non-Steam game". Steam reads it only
|
||||||
|
# at startup and writes it back on exit, so it's edited while Steam is closed.
|
||||||
|
# steam-shortcuts.py find <vdf> <exe> -> appid of an entry for exe
|
||||||
|
# steam-shortcuts.py add <vdf> <name> <exe> <icon> <desktop file>
|
||||||
|
# -> "added <appid>" / "updated <appid>"
|
||||||
|
# steam-shortcuts.py remove <vdf> <appid>
|
||||||
|
# An entry counts as ours when its Exe is <exe>, or a Steamify start script
|
||||||
|
# (run-app, also under the pre-2.5.0 path): that one is updated, not doubled.
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
MAP, STR, INT, END = 0, 1, 2, 8
|
||||||
|
|
||||||
|
|
||||||
|
def parse(data):
|
||||||
|
pos = 0
|
||||||
|
|
||||||
|
def cstr():
|
||||||
|
nonlocal pos
|
||||||
|
end = data.index(b"\0", pos)
|
||||||
|
s = data[pos:end].decode("utf-8", "surrogateescape")
|
||||||
|
pos = end + 1
|
||||||
|
return s
|
||||||
|
|
||||||
|
def block():
|
||||||
|
nonlocal pos
|
||||||
|
items = []
|
||||||
|
while True:
|
||||||
|
t = data[pos]
|
||||||
|
pos += 1
|
||||||
|
if t == END:
|
||||||
|
return items
|
||||||
|
key = cstr()
|
||||||
|
if t == MAP:
|
||||||
|
items.append((key, block()))
|
||||||
|
elif t == STR:
|
||||||
|
items.append((key, cstr()))
|
||||||
|
elif t == INT:
|
||||||
|
items.append((key, struct.unpack_from("<I", data, pos)[0]))
|
||||||
|
pos += 4
|
||||||
|
else:
|
||||||
|
raise ValueError(f"unknown VDF type {t} at {pos}")
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return [("shortcuts", [])]
|
||||||
|
root = block()
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
def dump(items):
|
||||||
|
out = bytearray()
|
||||||
|
for key, value in items:
|
||||||
|
k = key.encode("utf-8", "surrogateescape") + b"\0"
|
||||||
|
if isinstance(value, list):
|
||||||
|
out += bytes([MAP]) + k + dump(value)
|
||||||
|
elif isinstance(value, int):
|
||||||
|
out += bytes([INT]) + k + struct.pack("<I", value & 0xFFFFFFFF)
|
||||||
|
else:
|
||||||
|
out += bytes([STR]) + k + value.encode("utf-8", "surrogateescape") + b"\0"
|
||||||
|
return bytes(out) + bytes([END])
|
||||||
|
|
||||||
|
|
||||||
|
def get(entry, key, default=None):
|
||||||
|
# Steam's key names vary in case between versions (appid/AppName/Exe).
|
||||||
|
for k, v in entry:
|
||||||
|
if k.lower() == key.lower():
|
||||||
|
return v
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def put(entry, key, value):
|
||||||
|
for i, (k, _) in enumerate(entry):
|
||||||
|
if k.lower() == key.lower():
|
||||||
|
entry[i] = (k, value)
|
||||||
|
return
|
||||||
|
entry.append((key, value))
|
||||||
|
|
||||||
|
|
||||||
|
def shortcuts(root):
|
||||||
|
for k, v in root:
|
||||||
|
if k.lower() == "shortcuts":
|
||||||
|
return v
|
||||||
|
raise ValueError("no shortcuts block")
|
||||||
|
|
||||||
|
|
||||||
|
def ours(entry, exe):
|
||||||
|
have = get(entry, "Exe", "").strip('"')
|
||||||
|
return have == exe or (have.endswith("/run-app") and
|
||||||
|
("/steamify/" in have or "/cachyos-gamescope-boot/" in have))
|
||||||
|
|
||||||
|
|
||||||
|
def load(path):
|
||||||
|
try:
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
return parse(f.read())
|
||||||
|
except FileNotFoundError:
|
||||||
|
return [("shortcuts", [])]
|
||||||
|
|
||||||
|
|
||||||
|
def save(path, root):
|
||||||
|
tmp = path + ".steamify-tmp"
|
||||||
|
with open(tmp, "wb") as f:
|
||||||
|
f.write(dump(root))
|
||||||
|
os.replace(tmp, path)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
cmd, path = argv[1], argv[2]
|
||||||
|
root = load(path)
|
||||||
|
entries = shortcuts(root)
|
||||||
|
if cmd == "find":
|
||||||
|
for _, e in entries:
|
||||||
|
if ours(e, argv[3]):
|
||||||
|
print(get(e, "appid", 0))
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
if cmd == "add":
|
||||||
|
name, exe, icon, desktop = argv[3:7]
|
||||||
|
for _, e in entries:
|
||||||
|
if ours(e, exe):
|
||||||
|
put(e, "AppName", name)
|
||||||
|
put(e, "Exe", f'"{exe}"')
|
||||||
|
put(e, "StartDir", f'"{os.path.dirname(exe)}/"')
|
||||||
|
put(e, "icon", icon)
|
||||||
|
put(e, "ShortcutPath", desktop)
|
||||||
|
save(path, root)
|
||||||
|
print("updated", get(e, "appid", 0))
|
||||||
|
return 0
|
||||||
|
# Steam's own id for a shortcut: CRC32 of exe and name, top bit set.
|
||||||
|
appid = (zlib.crc32(f'"{exe}"{name}'.encode()) | 0x80000000) & 0xFFFFFFFF
|
||||||
|
entry = [("appid", appid), ("AppName", name), ("Exe", f'"{exe}"'),
|
||||||
|
("StartDir", f'"{os.path.dirname(exe)}/"'), ("icon", icon),
|
||||||
|
("ShortcutPath", desktop), ("LaunchOptions", ""), ("IsHidden", 0),
|
||||||
|
("AllowDesktopConfig", 1), ("AllowOverlay", 1), ("OpenVR", 0),
|
||||||
|
("Devkit", 0), ("DevkitGameID", ""), ("DevkitOverrideAppID", 0),
|
||||||
|
("LastPlayTime", 0), ("FlatpakAppID", ""), ("tags", [])]
|
||||||
|
entries.append((str(len(entries)), entry))
|
||||||
|
if os.path.dirname(path):
|
||||||
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||||
|
save(path, root)
|
||||||
|
print("added", appid)
|
||||||
|
return 0
|
||||||
|
if cmd == "remove":
|
||||||
|
keep = [e for _, e in entries if str(get(e, "appid", "")) != argv[3]]
|
||||||
|
if len(keep) == len(entries):
|
||||||
|
return 0
|
||||||
|
entries[:] = [(str(i), e) for i, e in enumerate(keep)]
|
||||||
|
save(path, root)
|
||||||
|
return 0
|
||||||
|
print(f"unknown command {cmd}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Installed by Steamify CachyOS (SteamOS conversion): runs after
|
||||||
|
# cachyos-hooks' os-release/cachyos-branding hooks (hooks run in file name
|
||||||
|
# order).
|
||||||
|
[Trigger]
|
||||||
|
Operation = Install
|
||||||
|
Operation = Upgrade
|
||||||
|
Type = Package
|
||||||
|
Target = filesystem
|
||||||
|
Target = cachyos-hooks
|
||||||
|
|
||||||
|
[Action]
|
||||||
|
Description = Steamify: the OS variant and version Steam shows
|
||||||
|
When = PostTransaction
|
||||||
|
Exec = @SCRIPT@
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Installed by Steamify CachyOS (SteamOS conversion): what Steam shows in its
|
||||||
|
# System settings besides the OS name, which stays CachyOS's: the SteamOS
|
||||||
|
# release Steamify follows as the OS version (VERSION_ID, e.g. steamos-3.9),
|
||||||
|
# steam-machine as the codename, and Steamify with its version as the variant
|
||||||
|
# (VARIANT_ID, which Steam shows). KDE's About this System would show
|
||||||
|
# VERSION_ID after the name: the conversion sets its UseOSReleaseVersion, so it
|
||||||
|
# shows os-release's VERSION instead, which CachyOS doesn't have. NAME and
|
||||||
|
# PRETTY_NAME are never touched: limine-snapper-sync finds the boot entries by
|
||||||
|
# the OS name. The zz-steamify-os-release hook runs this after cachyos-hooks.
|
||||||
|
sed -i -e '/^VARIANT=/d' -e '/^VARIANT_ID=/d' -e '/^VERSION_ID=/d' -e '/^VERSION_CODENAME=/d' /etc/os-release
|
||||||
|
printf '%s\n' 'VARIANT="Steamify @VERSION@"' 'VARIANT_ID=steamify-@VERSION@' 'VERSION_CODENAME=steam-machine' >> /etc/os-release
|
||||||
|
[ -n "@STEAMOS@" ] && echo 'VERSION_ID=@STEAMOS@' >> /etc/os-release
|
||||||
|
exit 0
|
||||||
+65
-3
@@ -15,11 +15,11 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
# Release version, see CHANGELOG.md.
|
# Release version, see CHANGELOG.md.
|
||||||
VERSION=2.5.0
|
VERSION=2.9.4
|
||||||
|
|
||||||
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 cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut update-notifier menu backend; do
|
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh 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
|
||||||
@@ -28,8 +28,21 @@ require_root_helper
|
|||||||
|
|
||||||
BACKEND=false
|
BACKEND=false
|
||||||
[[ "${1:-}" == --backend ]] && BACKEND=true
|
[[ "${1:-}" == --backend ]] && BACKEND=true
|
||||||
|
# --defaults [--options <id>,...] [--boot gamescope|desktop]: apply what the
|
||||||
|
# menu would preselect (or exactly the listed items), without the menu or any
|
||||||
|
# prompt (the Steam Machine ISO's first login runs this; sudo must not ask).
|
||||||
|
DEFAULTS=false
|
||||||
|
[[ "${1:-}" == --defaults ]] && DEFAULTS=true
|
||||||
|
# --defaults --list: what --defaults can set up here, as JSON (an installer
|
||||||
|
# page is built from it); nothing else on stdout.
|
||||||
|
LIST=false
|
||||||
|
[[ "$DEFAULTS" == true && "${2:-}" == --list ]] && LIST=true
|
||||||
|
# --boot gamescope|desktop: only change where an installed conversion
|
||||||
|
# starts, everything else stays as it is (for scripts; no menu).
|
||||||
|
BOOT_ONLY=false
|
||||||
|
[[ "${1:-}" == --boot ]] && BOOT_ONLY=true
|
||||||
|
|
||||||
if [[ "$BACKEND" == false ]]; then
|
if [[ "$BACKEND" == false && "$LIST" == false ]]; then
|
||||||
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
|
echo -e "${c_bold}Steamify CachyOS${c_reset} v$VERSION"
|
||||||
echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
|
echo "Turn the SteamOS-style parts on or off. The menu shows what is on now;"
|
||||||
echo "anything you turn off is put back the way it was."
|
echo "anything you turn off is put back the way it was."
|
||||||
@@ -114,6 +127,55 @@ if [[ "$BACKEND" == true ]]; then
|
|||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${1:-}" == --first-login ]]; then
|
||||||
|
first_login_run
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$LIST" == true ]]; then
|
||||||
|
defaults_list
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DEFAULTS" == true ]]; then
|
||||||
|
RESTART_FOR_LOGIN=false
|
||||||
|
REAPPLY=false
|
||||||
|
sudo -n true 2>/dev/null || { err "--defaults needs sudo without a password."; exit 1; }
|
||||||
|
detect_components
|
||||||
|
defaults_options "${@:2}" || exit 1
|
||||||
|
plan_changes
|
||||||
|
apply_changes
|
||||||
|
# Run by the installer: the rest waits for the first desktop login.
|
||||||
|
user_session || first_login_schedule
|
||||||
|
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
|
||||||
|
ok "Done; the changes take effect after a restart."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$BOOT_ONLY" == true ]]; then
|
||||||
|
RESTART_FOR_LOGIN=false
|
||||||
|
REAPPLY=false
|
||||||
|
case "${2:-}" in
|
||||||
|
gamescope|desktop) ;;
|
||||||
|
*) err "--boot takes gamescope or desktop"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
detect_components
|
||||||
|
[[ "${CURRENT[gaming]}" == 1 ]] || { err "--boot needs the SteamOS conversion; turn it on first."; exit 1; }
|
||||||
|
# What is on stays on, and nothing else changes: not the updates or
|
||||||
|
# removals a normal run would pick.
|
||||||
|
for c in "${COMPONENTS[@]}"; do WANTED[$c]=${CURRENT[$c]:-0}; done
|
||||||
|
WANTED[boot]=0; [[ "$2" == desktop ]] && WANTED[boot]=1
|
||||||
|
plan_changes
|
||||||
|
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
|
||||||
|
ok "Already starting in $2."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
apply_changes
|
||||||
|
[[ ${#FAILED[@]} -eq 0 ]] || { warn "These had problems (see above): ${FAILED[*]}"; exit 1; }
|
||||||
|
ok "Starts in $2 from the next boot on."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Menu loop: after each run the menu comes back with the new state, until
|
# Menu loop: after each run the menu comes back with the new state, until
|
||||||
# the user quits; the restart question comes then, once, for everything.
|
# the user quits; the restart question comes then, once, for everything.
|
||||||
RESTART_FOR_LOGIN=false
|
RESTART_FOR_LOGIN=false
|
||||||
|
|||||||
+22
-5
@@ -18,6 +18,10 @@ Item {
|
|||||||
property var steps: ({}) // id -> "wait"|"run"|"ok"|"fail"
|
property var steps: ({}) // id -> "wait"|"run"|"ok"|"fail"
|
||||||
property var failed: []
|
property var failed: []
|
||||||
property bool restartNeeded: false
|
property bool restartNeeded: false
|
||||||
|
// Review & apply only when something would change; "Re-apply what's on"
|
||||||
|
// is for when nothing did.
|
||||||
|
readonly property bool canApply: computePlan().length > 0
|
||||||
|
onCanApplyChanged: if (!canApply && sel === rows.length) sel = Math.max(0, rows.length - 1)
|
||||||
property string runError: ""
|
property string runError: ""
|
||||||
property bool wrongPassword: false
|
property bool wrongPassword: false
|
||||||
property bool typing: false // a text field has the keys
|
property bool typing: false // a text field has the keys
|
||||||
@@ -77,6 +81,8 @@ Item {
|
|||||||
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;
|
||||||
if (id === "kpin" && w.kpin) w.machine = true;
|
if (id === "kpin" && w.kpin) w.machine = true;
|
||||||
|
if (id === "launcher" && items.some(function (i) { return i.id === "steamgame"; })) w.steamgame = w.launcher;
|
||||||
|
if (id === "steamgame" && w.steamgame) w.launcher = true;
|
||||||
want = w;
|
want = w;
|
||||||
}
|
}
|
||||||
function computePlan() {
|
function computePlan() {
|
||||||
@@ -93,7 +99,10 @@ Item {
|
|||||||
if (want.gaming && boot !== bootNow) p.push({ id: "boot", action: boot === "desktop" ? "desktop" : "gaming" });
|
if (want.gaming && boot !== bootNow) p.push({ id: "boot", action: boot === "desktop" ? "desktop" : "gaming" });
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
function goReview(again) { reapply = again; plan = computePlan(); screen = "review"; }
|
function goReview(again) {
|
||||||
|
if (!again && !canApply) return;
|
||||||
|
reapply = again; plan = computePlan(); screen = "review";
|
||||||
|
}
|
||||||
function wantedIds() {
|
function wantedIds() {
|
||||||
var ids = [];
|
var ids = [];
|
||||||
for (var i = 0; i < items.length; i++)
|
for (var i = 0; i < items.length; i++)
|
||||||
@@ -195,7 +204,8 @@ Item {
|
|||||||
if (screen === "menu") {
|
if (screen === "menu") {
|
||||||
if (biosChecking) return;
|
if (biosChecking) return;
|
||||||
if (a === "up") sel = Math.max(0, sel - 1);
|
if (a === "up") sel = Math.max(0, sel - 1);
|
||||||
else if (a === "down") sel = Math.min(rows.length, sel + 1);
|
// The greyed-out Apply button can't be selected.
|
||||||
|
else if (a === "down") sel = Math.min(canApply ? rows.length : rows.length - 1, sel + 1);
|
||||||
else if (a === "accept") {
|
else if (a === "accept") {
|
||||||
if (sel === rows.length) { goReview(false); return; }
|
if (sel === rows.length) { goReview(false); return; }
|
||||||
var r = rows[sel];
|
var r = rows[sel];
|
||||||
@@ -207,7 +217,9 @@ Item {
|
|||||||
boot = a === "left" ? "gamescope" : "desktop";
|
boot = a === "left" ? "gamescope" : "desktop";
|
||||||
else if (a === "apply") goReview(false);
|
else if (a === "apply") goReview(false);
|
||||||
else if (a === "reapply") goReview(true);
|
else if (a === "reapply") goReview(true);
|
||||||
else if (a === "back") Qt.quit();
|
// B/Esc/Back don't quit: Steam's desktop layout sends Esc for a
|
||||||
|
// Steam Controller's B, which should only ever go back.
|
||||||
|
else if (a === "quit") Qt.quit();
|
||||||
} else if (screen === "review") {
|
} else if (screen === "review") {
|
||||||
if (a === "accept" || a === "apply") onApplyPressed();
|
if (a === "accept" || a === "apply") onApplyPressed();
|
||||||
else if (a === "back") { reapply = false; screen = "menu"; }
|
else if (a === "back") { reapply = false; screen = "menu"; }
|
||||||
@@ -246,16 +258,21 @@ Item {
|
|||||||
if (screen === "bios2" && Input.type !== "keyboard" && (e.key === Qt.Key_Return || e.key === Qt.Key_Enter)) {
|
if (screen === "bios2" && Input.type !== "keyboard" && (e.key === Qt.Key_Return || e.key === Qt.Key_Enter)) {
|
||||||
if (!e.isAutoRepeat) act("hold"); e.accepted = true; return;
|
if (!e.isAutoRepeat) act("hold"); e.accepted = true; return;
|
||||||
}
|
}
|
||||||
if (!fromRemote) Input.type = "keyboard";
|
if (!fromRemote) Input.type = Input.fromSteam ? "steam" : "keyboard";
|
||||||
var k = e.key;
|
var k = e.key;
|
||||||
if (k === Qt.Key_Up) act("up");
|
if (k === Qt.Key_Up) act("up");
|
||||||
else if (k === Qt.Key_Down) act("down");
|
else if (k === Qt.Key_Down) act("down");
|
||||||
else if (k === Qt.Key_Left) act("left");
|
else if (k === Qt.Key_Left) act("left");
|
||||||
else if (k === Qt.Key_Right) act("right");
|
else if (k === Qt.Key_Right) act("right");
|
||||||
else if (k === Qt.Key_Space) act("accept");
|
else if (k === Qt.Key_Space) act("accept");
|
||||||
else if (k === Qt.Key_Return || k === Qt.Key_Enter) act(Input.type === "remote" || screen !== "menu" ? "accept" : "apply");
|
// Enter selects, like A on a controller: Steam's desktop layout sends
|
||||||
|
// Enter for a Steam Controller's A (and Space for Y). Ctrl+Enter
|
||||||
|
// goes straight to Review & apply.
|
||||||
|
else if ((k === Qt.Key_Return || k === Qt.Key_Enter) && (e.modifiers & Qt.ControlModifier)) act("apply");
|
||||||
|
else if (k === Qt.Key_Return || k === Qt.Key_Enter) act("accept");
|
||||||
else if (k === Qt.Key_Escape || k === Qt.Key_Back || k === Qt.Key_Backspace) { if (!e.isAutoRepeat) act("back"); }
|
else if (k === Qt.Key_Escape || k === Qt.Key_Back || k === Qt.Key_Backspace) { if (!e.isAutoRepeat) act("back"); }
|
||||||
else if (k === Qt.Key_R) act("reapply");
|
else if (k === Qt.Key_R) act("reapply");
|
||||||
|
else if (k === Qt.Key_Q && (e.modifiers & Qt.ControlModifier)) act("quit");
|
||||||
else return;
|
else return;
|
||||||
e.accepted = true;
|
e.accepted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,15 @@ Item {
|
|||||||
border.width: step.st === "wait" || step.st === "run" ? 2 : 0; border.color: step.st === "run" ? Theme.accent : "#343f50"
|
border.width: step.st === "wait" || step.st === "run" ? 2 : 0; border.color: step.st === "run" ? Theme.accent : "#343f50"
|
||||||
Text { anchors.centerIn: parent; text: step.st === "ok" ? "✓" : (step.st === "fail" ? "!" : ""); color: step.st === "ok" ? Theme.good : Theme.bad
|
Text { anchors.centerIn: parent; text: step.st === "ok" ? "✓" : (step.st === "fail" ? "!" : ""); color: step.st === "ok" ? Theme.good : Theme.bad
|
||||||
font.pixelSize: 13; font.weight: Font.Bold }
|
font.pixelSize: 13; font.weight: Font.Bold }
|
||||||
RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } }
|
// Only this dot turns while the step runs: ✓ and ! never rotate
|
||||||
|
// (an animator leaves its item at whatever angle it stopped).
|
||||||
|
Item { anchors.fill: parent; visible: step.st === "run"
|
||||||
|
Rectangle { width: 6; height: 6; radius: 3; color: Theme.accent; x: parent.width / 2 - 3; y: -3 }
|
||||||
|
RotationAnimator on rotation { running: step.st === "run"; from: 0; to: 360; duration: 1000; loops: Animation.Infinite } } }
|
||||||
Row { width: 380; anchors.verticalCenter: parent.verticalCenter; spacing: 10
|
Row { width: 380; anchors.verticalCenter: parent.verticalCenter; spacing: 10
|
||||||
Text { text: (Texts.actions[step.modelData.action] || [])[3] + Texts.label(step.modelData.id)
|
// Boot into's label is its prefix already: "Boot into desktop", not "Boot into Boot into".
|
||||||
|
Text { text: step.modelData.id === "boot" ? (Texts.actions[step.modelData.action] || [])[3] + Texts.actions[step.modelData.action][0].toLowerCase()
|
||||||
|
: (Texts.actions[step.modelData.action] || [])[3] + Texts.label(step.modelData.id)
|
||||||
color: step.st === "wait" ? Theme.faint : Theme.textHi; font.family: Theme.body; font.pixelSize: 16; font.weight: Font.DemiBold
|
color: step.st === "wait" ? Theme.faint : Theme.textHi; font.family: Theme.body; font.pixelSize: 16; font.weight: Font.DemiBold
|
||||||
anchors.verticalCenter: parent.verticalCenter; elide: Text.ElideRight
|
anchors.verticalCenter: parent.verticalCenter; elide: Text.ElideRight
|
||||||
width: Math.min(implicitWidth, parent.width - (badge.visible ? badge.width + parent.spacing : 0)) }
|
width: Math.min(implicitWidth, parent.width - (badge.visible ? badge.width + parent.spacing : 0)) }
|
||||||
|
|||||||
+4
-2
@@ -10,11 +10,13 @@ Rectangle {
|
|||||||
signal clicked
|
signal clicked
|
||||||
height: 48; radius: 12; width: row.implicitWidth + 36
|
height: 48; radius: 12; width: row.implicitWidth + 36
|
||||||
color: primary ? Theme.accent : Theme.button
|
color: primary ? Theme.accent : Theme.button
|
||||||
border.width: focusRing ? 2 : 0; border.color: Theme.textHi
|
border.width: focusRing && enabled ? 2 : 0; border.color: Theme.textHi
|
||||||
|
// Greyed out while there's nothing to do.
|
||||||
|
opacity: enabled ? 1 : 0.4
|
||||||
Row { id: row; anchors.centerIn: parent; spacing: 10
|
Row { id: row; anchors.centerIn: parent; spacing: 10
|
||||||
Glyph { k: btn.k; visible: btn.k !== ""; dark: btn.primary; anchors.verticalCenter: parent.verticalCenter }
|
Glyph { k: btn.k; visible: btn.k !== ""; dark: btn.primary; anchors.verticalCenter: parent.verticalCenter }
|
||||||
Text { text: btn.text; color: btn.primary ? Theme.ink : Theme.text; font.family: Theme.body; font.pixelSize: 15; font.weight: Font.DemiBold
|
Text { text: btn.text; color: btn.primary ? Theme.ink : Theme.text; font.family: Theme.body; font.pixelSize: 15; font.weight: Font.DemiBold
|
||||||
anchors.verticalCenter: parent.verticalCenter }
|
anchors.verticalCenter: parent.verticalCenter }
|
||||||
}
|
}
|
||||||
MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: btn.clicked() }
|
MouseArea { anchors.fill: parent; enabled: btn.enabled; cursorShape: Qt.PointingHandCursor; onClicked: btn.clicked() }
|
||||||
}
|
}
|
||||||
+12
-2
@@ -1,5 +1,8 @@
|
|||||||
// The result of a run: all done, a problem, or nothing changed.
|
// The result of a run: all done, a problem, or nothing changed. With a
|
||||||
|
// problem, the run's output is shown below it (a BIOS check has no progress
|
||||||
|
// screen, so this is the only place to read why it stopped).
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls.Basic
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
required property AppState app
|
required property AppState app
|
||||||
@@ -20,7 +23,14 @@ Item {
|
|||||||
Text { width: parent.width; horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap; color: Theme.soft; font.family: Theme.body; font.pixelSize: 17; text: message }
|
Text { width: parent.width; horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap; color: Theme.soft; font.family: Theme.body; font.pixelSize: 17; text: message }
|
||||||
Rectangle { visible: app.failed.length > 0; anchors.horizontalCenter: parent.horizontalCenter; width: ft.implicitWidth + 32; height: 44; radius: 12; color: Theme.warnBg
|
Rectangle { visible: app.failed.length > 0; anchors.horizontalCenter: parent.horizontalCenter; width: ft.implicitWidth + 32; height: 44; radius: 12; color: Theme.warnBg
|
||||||
Text { id: ft; anchors.centerIn: parent; color: "#f2c27a"; font.family: Theme.body; font.pixelSize: 14
|
Text { id: ft; anchors.centerIn: parent; color: "#f2c27a"; font.family: Theme.body; font.pixelSize: 14
|
||||||
text: "Had a problem: " + app.failed.map(function (id) { return Texts.label(id); }).join(", ") + ". See the details." } }
|
text: "Had a problem: " + app.failed.map(function (id) { return Texts.label(id); }).join(", ") + (app.log.count ? ". Details below." : ".") } }
|
||||||
|
Rectangle { visible: app.failed.length > 0 && app.log.count > 0; width: parent.width; height: 190; radius: 14; color: Theme.card
|
||||||
|
ListView { id: details; anchors.fill: parent; anchors.margins: 16; clip: true; model: app.log
|
||||||
|
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||||
|
// The end is where it stopped.
|
||||||
|
onCountChanged: positionViewAtEnd()
|
||||||
|
onVisibleChanged: if (visible) positionViewAtEnd()
|
||||||
|
delegate: Text { required property string line; width: details.width - 12; text: line; color: "#aab5c4"; font.family: Theme.mono; font.pixelSize: 13; wrapMode: Text.WrapAnywhere } } }
|
||||||
Row { anchors.horizontalCenter: parent.horizontalCenter; spacing: 14; topPadding: 8
|
Row { anchors.horizontalCenter: parent.horizontalCenter; spacing: 14; topPadding: 8
|
||||||
Btn { k: Input.g.back; text: "Back to the menu"; height: 52; onClicked: app.act("back") }
|
Btn { k: Input.g.back; text: "Back to the menu"; height: 52; onClicked: app.act("back") }
|
||||||
Btn { visible: app.restartNeeded; k: Input.g.ok; text: "Restart now"; primary: true; height: 52; onClicked: app.backend.restart() } }
|
Btn { visible: app.restartNeeded; k: Input.g.ok; text: "Restart now"; primary: true; height: 52; onClicked: app.backend.restart() } }
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ Rectangle {
|
|||||||
property string k
|
property string k
|
||||||
property bool dark: false
|
property bool dark: false
|
||||||
height: 26; width: Math.max(26, gt.implicitWidth + 14)
|
height: 26; width: Math.max(26, gt.implicitWidth + 14)
|
||||||
radius: Input.type === "controller" && k.length === 1 ? 13 : 7
|
radius: (Input.type === "controller" || Input.type === "steam") && k.length === 1 ? 13 : 7
|
||||||
color: dark ? Theme.ink : Theme.key
|
color: dark ? Theme.ink : Theme.key
|
||||||
Text { id: gt; anchors.centerIn: parent; text: glyph.k; color: glyph.dark ? Theme.accent : Theme.textHi
|
Text { id: gt; anchors.centerIn: parent; text: glyph.k; color: glyph.dark ? Theme.accent : Theme.textHi
|
||||||
font.family: Theme.body; font.pixelSize: 12; font.weight: Font.DemiBold }
|
font.family: Theme.body; font.pixelSize: 12; font.weight: Font.DemiBold }
|
||||||
|
|||||||
+8
-3
@@ -5,10 +5,15 @@ import QtQuick
|
|||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property string type: "keyboard"
|
property string type: "keyboard"
|
||||||
|
// Started from Steam: keys come from a Steam Controller through Steam's
|
||||||
|
// desktop layout (A = Enter, B = Esc, Y = Space, X = Steam's keyboard),
|
||||||
|
// shown as "steam" with the controller's buttons.
|
||||||
|
property bool fromSteam: false
|
||||||
readonly property var glyphs: ({
|
readonly property var glyphs: ({
|
||||||
controller: { toggle: "A", choose: "◀ ▶", reapply: "Y", quit: "B", apply: "X", ok: "A", back: "B" },
|
controller: { toggle: "A", choose: "◀ ▶", reapply: "Y", quit: "", apply: "X", ok: "A", back: "B" },
|
||||||
keyboard: { toggle: "Space", choose: "← →", reapply: "R", quit: "Esc", apply: "Enter", ok: "Enter", back: "Esc" },
|
keyboard: { toggle: "Enter", choose: "← →", reapply: "R", quit: "Ctrl+Q", apply: "Ctrl+Enter", ok: "Enter", back: "Esc" },
|
||||||
remote: { toggle: "OK", choose: "◀ ▶", reapply: "Red", quit: "Back", apply: "↓ Apply", ok: "OK", back: "Back" }
|
steam: { toggle: "A", choose: "◀ ▶", reapply: "", quit: "", apply: "↓ A", ok: "A", back: "B" },
|
||||||
|
remote: { toggle: "OK", choose: "◀ ▶", reapply: "Red", quit: "", apply: "↓ Apply", ok: "OK", back: "Back" }
|
||||||
})
|
})
|
||||||
readonly property var g: glyphs[type]
|
readonly property var g: glyphs[type]
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,8 @@ ApplicationWindow {
|
|||||||
required property var gamepad
|
required property var gamepad
|
||||||
required property bool fullscreen
|
required property bool fullscreen
|
||||||
required property string iconUrl
|
required property string iconUrl
|
||||||
|
required property bool fromSteam
|
||||||
|
Component.onCompleted: Input.fromSteam = fromSteam
|
||||||
|
|
||||||
width: 1280; height: 720
|
width: 1280; height: 720
|
||||||
minimumWidth: 960; minimumHeight: 540
|
minimumWidth: 960; minimumHeight: 540
|
||||||
|
|||||||
@@ -59,7 +59,10 @@ Item {
|
|||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left; anchors.leftMargin: 40; anchors.verticalCenter: parent.verticalCenter; spacing: 28
|
anchors.left: parent.left; anchors.leftMargin: 40; anchors.verticalCenter: parent.verticalCenter; spacing: 28
|
||||||
Repeater {
|
Repeater {
|
||||||
|
// Quit only has a key on a keyboard (Ctrl+Q), and re-apply has
|
||||||
|
// none through Steam's layout; a controller quits through Steam.
|
||||||
model: [[screen.g.toggle, "Toggle"], [screen.g.choose, "Choose"], [screen.g.reapply, "Re-apply what's on"], [screen.g.quit, "Quit"]]
|
model: [[screen.g.toggle, "Toggle"], [screen.g.choose, "Choose"], [screen.g.reapply, "Re-apply what's on"], [screen.g.quit, "Quit"]]
|
||||||
|
.filter(function (h) { return h[0] !== ""; })
|
||||||
Row { required property var modelData; spacing: 8
|
Row { required property var modelData; spacing: 8
|
||||||
Glyph { k: parent.modelData[0]; anchors.verticalCenter: parent.verticalCenter }
|
Glyph { k: parent.modelData[0]; anchors.verticalCenter: parent.verticalCenter }
|
||||||
Text { text: parent.modelData[1]; color: Theme.label; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter } }
|
Text { text: parent.modelData[1]; color: Theme.label; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter } }
|
||||||
@@ -70,7 +73,8 @@ Item {
|
|||||||
Text { readonly property int n: app.computePlan().length
|
Text { readonly property int n: app.computePlan().length
|
||||||
text: n === 0 ? "Everything is the way you want it" : n + (n === 1 ? " change" : " changes")
|
text: n === 0 ? "Everything is the way you want it" : n + (n === 1 ? " change" : " changes")
|
||||||
color: Theme.faint; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter }
|
color: Theme.faint; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter }
|
||||||
Btn { k: screen.g.apply; text: "Review & apply"; primary: true; focusRing: app.sel === app.rows.length; height: 44; onClicked: app.goReview(false) }
|
Btn { k: screen.g.apply; text: "Review & apply"; primary: true; enabled: app.canApply
|
||||||
|
focusRing: app.sel === app.rows.length; height: 44; onClicked: app.goReview(false) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ Rectangle {
|
|||||||
Text { visible: app.wrongPassword; text: "That password didn't work. Try again."; color: Theme.bad; font.family: Theme.body; font.pixelSize: 14 }
|
Text { visible: app.wrongPassword; text: "That password didn't work. Try again."; color: Theme.bad; font.family: Theme.body; font.pixelSize: 14 }
|
||||||
Rectangle { width: parent.width; height: 46; radius: 12; color: Theme.note
|
Rectangle { width: parent.width; height: 46; radius: 12; color: Theme.note
|
||||||
Text { anchors.verticalCenter: parent.verticalCenter; x: 14; color: Theme.soft; font.family: Theme.body; font.pixelSize: 14
|
Text { anchors.verticalCenter: parent.verticalCenter; x: 14; color: Theme.soft; font.family: Theme.body; font.pixelSize: 14
|
||||||
text: ({ controller: "Press Steam + X for the on-screen keyboard.", keyboard: "Type your password and press Enter.", remote: "Select the field for the on-screen keyboard." })[Input.type] } }
|
text: ({ controller: "Press Steam + X for the on-screen keyboard.", keyboard: "Type your password and press Enter.", steam: "Press X for Steam's on-screen keyboard, type your password and press A.", remote: "Select the field for the on-screen keyboard." })[Input.type] } }
|
||||||
Item { width: parent.width; height: 48
|
Item { width: parent.width; height: 48
|
||||||
Btn { k: Input.g.back; text: "Back"; onClicked: app.act("back") }
|
Btn { k: Input.g.back; text: "Back"; onClicked: app.act("back") }
|
||||||
Btn { anchors.right: parent.right; k: Input.g.ok; text: "Apply"; primary: true; onClicked: screen.submit() } }
|
Btn { anchors.right: parent.right; k: Input.g.ok; text: "Apply"; primary: true; onClicked: screen.submit() } }
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ QtObject {
|
|||||||
launcher: { label: "Steamify shortcut", hint: "The app on the desktop and in the launcher",
|
launcher: { label: "Steamify shortcut", hint: "The app on the desktop and in the launcher",
|
||||||
body: "Opens the newest Steamify app, so you never need the install command again. Steamify Terminal in the launcher opens the terminal menu.",
|
body: "Opens the newest Steamify app, so you never need the install command again. Steamify Terminal in the launcher opens the terminal menu.",
|
||||||
changes: ["Steamify CachyOS on the desktop and in the launcher (the app)", "Steamify Terminal in the launcher"] },
|
changes: ["Steamify CachyOS on the desktop and in the launcher (the app)", "Steamify Terminal in the launcher"] },
|
||||||
|
steamgame: { label: "Add as non-Steam game", hint: "Steamify in your Steam library",
|
||||||
|
body: "Adds Steamify to your Steam library as a non-Steam game. Started from Steam it gets your controller (a Steam Controller only talks to Steam while Steam runs), and you can open it in gaming mode. Steam closes for a moment and starts again, since it only reads its games list at startup: so this is done from the desktop, not from gaming mode or with Steamify started from Steam.",
|
||||||
|
changes: ["Steamify CachyOS in your Steam library, with its icon", "An entry that's already there is updated, not added twice", "Off (or the shortcut off): removed from the library again"] },
|
||||||
notify: { label: "Update notifications", hint: "A notification when there's a new Steamify",
|
notify: { label: "Update notifications", hint: "A notification when there's a new Steamify",
|
||||||
body: "Checks once a day and when you log in to the desktop. When there's a new Steamify you get a notification and a tray icon: open the app to see what's new and choose what to update, or skip that version. It never updates anything by itself.",
|
body: "Checks once a day and when you log in to the desktop. When there's a new Steamify you get a notification and a tray icon: open the app to see what's new and choose what to update, or skip that version. It never updates anything by itself.",
|
||||||
changes: ["A daily check (systemd user timer), only on the desktop", "Tray icon only while an update is waiting", "Skip this version: quiet until the next one"] },
|
changes: ["A daily check (systemd user timer), only on the desktop", "Tray icon only while an update is waiting", "Skip this version: quiet until the next one"] },
|
||||||
|
|||||||
+9
-4
@@ -1,12 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Steamify CachyOS - get and start the app (v2), for `curl | bash`:
|
# Steamify CachyOS - get and start the app, for `curl | bash`:
|
||||||
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
|
# curl -fsSL https://github.com/theupriser/steamify-cachyos/releases/latest/download/steamify-app.sh | bash
|
||||||
# Downloads the newest release's app package (steamify-app.tar.gz: the app,
|
# Downloads the newest release's app package (steamify-app.tar.gz: the app,
|
||||||
# steamify.sh, lib/, patches/ and services/) to ~/.local/share/steamify/app, installs PySide6 if
|
# steamify.sh, lib/, patches/ and services/) to ~/.local/share/steamify/app, installs PySide6 if
|
||||||
# it's missing, adds a launcher entry, and starts the app.
|
# it's missing, adds a launcher entry, and starts the app.
|
||||||
# STEAMIFY_RELEASE=<tag> takes that release instead of the newest (the
|
# STEAMIFY_RELEASE=<tag> takes that release instead of the newest.
|
||||||
# v2-ui-preview build's copy of this script sets it). STEAMIFY_BRANCH=<branch>
|
# STEAMIFY_BRANCH=<branch> takes that branch's source instead (for testing
|
||||||
# takes that branch's source instead (for testing before a build).
|
# before a build).
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPO="theupriser/steamify-cachyos"
|
REPO="theupriser/steamify-cachyos"
|
||||||
@@ -71,4 +71,9 @@ EOF
|
|||||||
command -v update-desktop-database >/dev/null && update-desktop-database "$APPS" 2>/dev/null || true
|
command -v update-desktop-database >/dev/null && update-desktop-database "$APPS" 2>/dev/null || true
|
||||||
|
|
||||||
say "Starting Steamify..."
|
say "Starting Steamify..."
|
||||||
|
# Started from Steam: stay in the foreground, or Steam counts the game as
|
||||||
|
# ended right away and stops giving it the controller.
|
||||||
|
if [[ -n "${SteamGameId:-}" ]]; then
|
||||||
|
exec "$DEST/ui/steamify-ui" < /dev/null
|
||||||
|
fi
|
||||||
setsid "$DEST/ui/steamify-ui" >/dev/null 2>&1 < /dev/null &
|
setsid "$DEST/ui/steamify-ui" >/dev/null 2>&1 < /dev/null &
|
||||||
@@ -20,6 +20,14 @@ import tempfile
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
# Started from Steam (a non-Steam game, so Steam Input hands it the
|
||||||
|
# controller): Steam preloads its overlay into every game, and Qt aborts with
|
||||||
|
# it loaded. Start again without it, before Qt is imported.
|
||||||
|
if "gameoverlayrenderer" in os.environ.get("LD_PRELOAD", ""):
|
||||||
|
os.environ["LD_PRELOAD"] = ":".join(p for p in os.environ["LD_PRELOAD"].split(":")
|
||||||
|
if p and "gameoverlayrenderer" not in p)
|
||||||
|
os.execv(sys.executable, [sys.executable] + sys.argv)
|
||||||
|
|
||||||
HERE = os.path.dirname(os.path.realpath(__file__))
|
HERE = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -365,6 +373,9 @@ def main():
|
|||||||
engine = QQmlApplicationEngine()
|
engine = QQmlApplicationEngine()
|
||||||
engine.setInitialProperties({"backend": backend, "gamepad": pad,
|
engine.setInitialProperties({"backend": backend, "gamepad": pad,
|
||||||
"fullscreen": fullscreen,
|
"fullscreen": fullscreen,
|
||||||
|
# Started from Steam: its keys are a Steam
|
||||||
|
# Controller's buttons (desktop layout).
|
||||||
|
"fromSteam": bool(os.environ.get("SteamGameId")),
|
||||||
"iconUrl": QUrl.fromLocalFile(os.path.realpath(icon)).toString()})
|
"iconUrl": QUrl.fromLocalFile(os.path.realpath(icon)).toString()})
|
||||||
engine.load(os.path.join(HERE, "qml", "Main.qml"))
|
engine.load(os.path.join(HERE, "qml", "Main.qml"))
|
||||||
if not engine.rootObjects():
|
if not engine.rootObjects():
|
||||||
|
|||||||
Reference in new issue
Block a user