mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 02:00:13 +02:00
Trim: firefox launcher, debugger-arm migration, comments and docs
- firefox: the prefs.js patterns built once; the extension link condition without the redundant desktopFix (it implies a pref). - install.sh steamvr-debugger-arm: no second copy of the old-marker migration (cleanup, run on every switch before the arm unit exists, already does it). - steam-ui-patches: shorter state option description; lib's description mentions extraArgs. - README: uiPatches.patches fields in the options table (moved from docs/ui-patches.md); docs/ui-patches.md: the finder helpers; docs/steamvr-debugger.md: repeated sentences removed.
This commit is contained in:
1 parent
a5ecbad76d
commit
b3d93e8526
8 files changed
+43
-69
No files matched your search
@@ -4,9 +4,9 @@
|
|||||||
Valve Steam Frame (SteamOS, `aarch64-linux`, standalone home-manager). They
|
Valve Steam Frame (SteamOS, `aarch64-linux`, standalone home-manager). They
|
||||||
work around quirks of the Frame's [two graphical sessions](#two-sessions)
|
work around quirks of the Frame's [two graphical sessions](#two-sessions)
|
||||||
(portal, keyboard layout, clipboard, KDE wallet, Firefox), enable hardware
|
(portal, keyboard layout, clipboard, KDE wallet, Firefox), enable hardware
|
||||||
video decoding in Jellyfin, run rootless Docker, and extend Steam's and SteamVR's UIs at runtime (VR keyboard,
|
video decoding in Jellyfin, run rootless Docker, and extend Steam's and
|
||||||
"+" menu, dashboard windows, Steam close button, window curvature, window
|
SteamVR's UIs at runtime (VR keyboard, "+" menu, dashboard windows, Steam
|
||||||
controls).
|
close button, window curvature, window controls).
|
||||||
|
|
||||||
Everything is declarative: files are links into the Nix store, UI patches
|
Everything is declarative: files are links into the Nix store, UI patches
|
||||||
live in memory. The few things that have to be written elsewhere at runtime
|
live in memory. The few things that have to be written elsewhere at runtime
|
||||||
@@ -253,7 +253,13 @@ Every module imports `cleanup` (see
|
|||||||
| `steamFrame.keyboard.vr.backspaceDrag.wordDetentPixels` | int | `90` | Extra travel across a word border (`0`: none). |
|
| `steamFrame.keyboard.vr.backspaceDrag.wordDetentPixels` | int | `90` | Extra travel across a word border (`0`: none). |
|
||||||
| `steamFrame.keyboard.vr.haptics` | bool | `true` | Haptic ticks for drag steps, word detents and picks. |
|
| `steamFrame.keyboard.vr.haptics` | bool | `true` | Haptic ticks for drag steps, word detents and picks. |
|
||||||
| `steamFrame.keyboard.vr.checks` | package, read-only | | The tests, built with the configured dictionary. |
|
| `steamFrame.keyboard.vr.checks` | package, read-only | | The tests, built with the configured dictionary. |
|
||||||
| `steamFrame.uiPatches.patches` | list of submodules | `[ ]` | Runtime patches of Steam's web UIs, see [UI patches](docs/ui-patches.md). |
|
| `steamFrame.uiPatches.patches` | list of submodules | `[ ]` | Runtime patches of Steam's web UIs, see [UI patches](docs/ui-patches.md#defining-a-patch). Fields below. |
|
||||||
|
| `steamFrame.uiPatches.patches.*.name` | str | required | Unique name (log). |
|
||||||
|
| `steamFrame.uiPatches.patches.*.endpoint` | str | `"http://127.0.0.1:8080"` | DevTools base URL, `/json/list` polled every 5 s: Steam 8080, SteamVR 8087. |
|
||||||
|
| `steamFrame.uiPatches.patches.*.target.{title,titleRegex,urlRegex}` | null or str | `null` | Pages to patch: exact title, JS regexes; all given ones must match. |
|
||||||
|
| `steamFrame.uiPatches.patches.*.patch` | path | required | JS evaluated (awaited) in every matching page. |
|
||||||
|
| `steamFrame.uiPatches.patches.*.unpatch` | null or path | `null` | JS evaluated when the service stops. |
|
||||||
|
| `steamFrame.uiPatches.patches.*.state` | bool | `false` | One [persistent JSON value](docs/ui-patches.md#persistent-state) for the patch. |
|
||||||
| `steamFrame.uiPatches.lib` | attrs, read-only | | Patch helpers (`mkPatch`), see [Finders and signatures](docs/ui-patches.md#mkpatch). |
|
| `steamFrame.uiPatches.lib` | attrs, read-only | | Patch helpers (`mkPatch`), see [Finders and signatures](docs/ui-patches.md#mkpatch). |
|
||||||
| `steamFrame.launcherMenu.sort` | bool | `false` | Sort the "+" menu alphabetically. |
|
| `steamFrame.launcherMenu.sort` | bool | `false` | Sort the "+" menu alphabetically. |
|
||||||
| `steamFrame.launcherMenu.pinDesktop` | null or `"top"` / `"bottom"` | `null` | Pin "Desktop" above/below the "+" menu's list; `null`: normal entry. |
|
| `steamFrame.launcherMenu.pinDesktop` | null or `"top"` / `"bottom"` | `null` | Pin "Desktop" above/below the "+" menu's list; `null`: normal entry. |
|
||||||
|
|||||||
@@ -44,12 +44,6 @@ Port: `VRWebHelper/DebuggerPort`, default 8087.
|
|||||||
- when SteamVR stops, the key goes back to its previous value (removed if
|
- when SteamVR stops, the key goes back to its previous value (removed if
|
||||||
it wasn't there) and `.armed` is removed.
|
it wasn't there) and `.armed` is removed.
|
||||||
|
|
||||||
The runtime files don't need Nix, which is why rollback and uninstall are
|
The runtime files need no Nix (rollback, uninstall) and are gone at reboot;
|
||||||
covered; they are gone at reboot, and `.armed` (the only trace after a
|
`.armed`, the only trace after a power loss, is resolved by the next
|
||||||
power loss) is resolved by the next SteamVR start or
|
SteamVR start or `steam-frame-nix-cleanup`.
|
||||||
`steam-frame-nix-cleanup`. Disabled, there is no unit; the switch (cleanup)
|
|
||||||
restores the key if SteamVR is stopped, otherwise the runtime drop-in does
|
|
||||||
when it stops.
|
|
||||||
|
|
||||||
Until SteamVR has been restarted once with the drop-in, the port is closed
|
|
||||||
and `steam-ui-patches` keeps polling it.
|
|
||||||
+10
-17
@@ -65,16 +65,8 @@ it runs. What they have in common:
|
|||||||
|
|
||||||
## Defining a patch
|
## Defining a patch
|
||||||
|
|
||||||
`steamFrame.uiPatches.patches` entries:
|
A `steamFrame.uiPatches.patches` entry (fields:
|
||||||
|
[README, Options](../README.md#options)):
|
||||||
| Attribute | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `name` | | Unique name (log). |
|
|
||||||
| `endpoint` | `"http://127.0.0.1:8080"` | DevTools base URL; `/json/list` is polled every 5 s. |
|
|
||||||
| `target.title` / `target.titleRegex` / `target.urlRegex` | `null` | Pages to patch; all given criteria must match (JS regexes). |
|
|
||||||
| `patch` | | JS file evaluated in every matching page (awaited). |
|
|
||||||
| `unpatch` | `null` | JS file evaluated when the service stops. |
|
|
||||||
| `state` | `false` | Give the patch one [persistent JSON value](#persistent-state). |
|
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
steamFrame.uiPatches.patches = [ {
|
steamFrame.uiPatches.patches = [ {
|
||||||
@@ -128,9 +120,11 @@ patches never use them. `modules/lib/finders.js` (like Decky Loader's
|
|||||||
`findInReactTree`).
|
`findInReactTree`).
|
||||||
|
|
||||||
Every signature must match exactly once, otherwise the patch changes nothing
|
Every signature must match exactly once, otherwise the patch changes nothing
|
||||||
and reports it (e.g. `signature not found, Steam left unpatched:
|
and reports it: `resolvePatch` returns e.g. `signature not found, Steam left
|
||||||
layouts.currentLayout (module 40222): ambiguous export, candidates r_, xy`).
|
unpatched: layouts.currentLayout (module 40222): ambiguous export,
|
||||||
Results are cached per page.
|
candidates r_, xy` as the patch's result. Results are cached per page. The
|
||||||
|
library also has `ensureStyle(doc, id, css)` and `logger(buffer)` (a capped
|
||||||
|
debug log).
|
||||||
|
|
||||||
Signatures live in `modules/lib/signatures.json`, shared by patches and the
|
Signatures live in `modules/lib/signatures.json`, shared by patches and the
|
||||||
offline checker. An entry can also list `expects` (strings the patch relies
|
offline checker. An entry can also list `expects` (strings the patch relies
|
||||||
@@ -164,10 +158,9 @@ steamFrame.uiPatches.patches = [ {
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
((find, sigs, opts, hooks) => {
|
((find, sigs, opts, hooks) => {
|
||||||
let mods;
|
const mods = find.resolvePatch('webpackChunksteamui', sigs); // SteamVR dashboard: 'webpackChunkvrwebui'
|
||||||
try { mods = find.resolveAll(find.getWebpackRequire('webpackChunksteamui'), sigs); }
|
if (typeof mods === 'string') return mods; // signature not found
|
||||||
catch (e) { return `not patched: ${e.message}`; }
|
const Thing = mods.thing.exports.Thing;
|
||||||
const Thing = mods.thing.exports.Thing; // SteamVR dashboard: 'webpackChunkvrwebui'
|
|
||||||
…
|
…
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -591,12 +591,6 @@ cmd_debugger_arm() {
|
|||||||
local cur tmp
|
local cur tmp
|
||||||
need_not_root
|
need_not_root
|
||||||
command -v jq >/dev/null 2>&1 || die "jq not found"
|
command -v jq >/dev/null 2>&1 || die "jq not found"
|
||||||
if [[ -f $DEBUGGER_MARKER_V1 ]]; then # marker of older versions: key was absent
|
|
||||||
mkdir -p "$SFN_STATE"
|
|
||||||
[[ -f $DEBUGGER_ARMED ]] || printf 'absent\n' >"$DEBUGGER_ARMED"
|
|
||||||
rm -f -- "$DEBUGGER_MARKER_V1"
|
|
||||||
info "migrated $DEBUGGER_MARKER_V1 to $DEBUGGER_ARMED"
|
|
||||||
fi
|
|
||||||
if [[ ! -f $DEBUGGER_ARMED ]]; then
|
if [[ ! -f $DEBUGGER_ARMED ]]; then
|
||||||
if [[ -f $VRSETTINGS ]]; then
|
if [[ -f $VRSETTINGS ]]; then
|
||||||
cur="$(jq -r 'if (.VRWebHelper | type) == "object" and (.VRWebHelper | has("DebuggerEnabled"))
|
cur="$(jq -r 'if (.VRWebHelper | type) == "object" and (.VRWebHelper | has("DebuggerEnabled"))
|
||||||
|
|||||||
@@ -203,11 +203,9 @@ pkgs.runCommand "cleanup-check" { nativeBuildInputs = [ cleanup pkgs.jq ]; } ''
|
|||||||
arm() { bash ${../../install.sh} steamvr-debugger-arm; }
|
arm() { bash ${../../install.sh} steamvr-debugger-arm; }
|
||||||
fresh e
|
fresh e
|
||||||
printf '{\n "steamvr" : {}\n}\n' > $V
|
printf '{\n "steamvr" : {}\n}\n' > $V
|
||||||
touch $S/steamvr-debugger # old marker: migrated
|
|
||||||
echo activating > $STUB/state
|
echo activating > $STUB/state
|
||||||
res=$(arm); echo "$res"
|
res=$(arm); echo "$res"
|
||||||
[ "$(cat $S/steamvr-debugger.armed)" = absent ] || fail "armed"
|
[ "$(cat $S/steamvr-debugger.armed)" = absent ] || fail "armed"
|
||||||
gone $S/steamvr-debugger
|
|
||||||
[ "$(jq -c .VRWebHelper $V)" = '{"DebuggerEnabled":true}' ] || fail "arm: $(cat $V)"
|
[ "$(jq -c .VRWebHelper $V)" = '{"DebuggerEnabled":true}' ] || fail "arm: $(cat $V)"
|
||||||
there $root/run/steam-frame-nix/steamvr-debugger-restore
|
there $root/run/steam-frame-nix/steamvr-debugger-restore
|
||||||
[ "$(grep -c daemon-reload $STUB/log)" = 1 ] || fail "arm reload"
|
[ "$(grep -c daemon-reload $STUB/log)" = 1 ] || fail "arm reload"
|
||||||
|
|||||||
+10
-17
@@ -1,25 +1,18 @@
|
|||||||
# Firefox Flatpak (org.mozilla.firefox) launcher.
|
# Firefox Flatpak (org.mozilla.firefox) launcher.
|
||||||
# - prefs and vrFullscreenFix are default prefs (pref(), the default branch:
|
# - prefs and vrFullscreenFix are default prefs (pref(): never written to
|
||||||
# never written to prefs.js, so removing one leaves nothing behind). Firefox
|
# prefs.js, so removing one leaves nothing behind) in defaults/pref/ of the
|
||||||
# reads defaults/pref/*.js from its system config dir, /app/etc/firefox in
|
# org.mozilla.firefox.systemconfig extension (/app/etc/firefox), provided
|
||||||
# the Flatpak, the mount point of the org.mozilla.firefox.systemconfig
|
# as the user installation's "unmaintained extension"
|
||||||
# extension. The user installation's "unmaintained extension" dir
|
# ($XDG_DATA_HOME/flatpak/extension/<id>/<arch>/<branch>): a Home Manager
|
||||||
# ($XDG_DATA_HOME/flatpak/extension/<id>/<arch>/<branch>) provides it: a
|
# link to a store dir, which Flatpak mounts itself (the sandbox needn't see
|
||||||
# home-manager link to a store dir, which Flatpak mounts itself (the
|
# /nix).
|
||||||
# sandbox needn't see /nix).
|
|
||||||
# - vrFullscreenFix: in the Steam session gamescope focuses a fullscreen X11
|
# - vrFullscreenFix: in the Steam session gamescope focuses a fullscreen X11
|
||||||
# window but never shows it (Firefox looks frozen). ignore-widgets keeps
|
# window but never shows it (Firefox looks frozen). ignore-widgets keeps
|
||||||
# fullscreen inside the window.
|
# fullscreen inside the window.
|
||||||
# - desktopProfile: the sessions have separate buses/displays, so a second
|
# - desktopProfile: the sessions have separate buses/displays, so a second
|
||||||
# Firefox can't reach the running one and hits the profile lock; the nested
|
# Firefox can't reach the running one and hits the profile lock; the nested
|
||||||
# desktop gets its own profile (a normal Firefox profile: browser data).
|
# desktop gets its own profile, where fullscreen works: the launcher undoes
|
||||||
# Fullscreen works there, so the launcher undoes the fix in that profile
|
# the fix there while its Firefox runs (firefox/launcher.nix).
|
||||||
# only while its Firefox runs: a user.js link to the extension's
|
|
||||||
# steam-frame-nix-desktop-user.js (a sandbox path; dangling on the host),
|
|
||||||
# made right before Firefox starts and removed, with the value Firefox
|
|
||||||
# stored from it in prefs.js, once it has exited (firefox/launcher.nix).
|
|
||||||
# Leftovers (a crash) and what older versions wrote into profiles (user.js
|
|
||||||
# copies and links) are removed by steam-frame-nix-cleanup (on switch).
|
|
||||||
# The entry shadows the Flatpak's (same ID), keeping MIME associations, and is
|
# The entry shadows the Flatpak's (same ID), keeping MIME associations, and is
|
||||||
# seen by the "+" menu (which reads only ~/.local/share/applications).
|
# seen by the "+" menu (which reads only ~/.local/share/applications).
|
||||||
# defaultBrowser: without a default the portal picks the first installed
|
# defaultBrowser: without a default the portal picks the first installed
|
||||||
@@ -122,7 +115,7 @@ in {
|
|||||||
|
|
||||||
# stable: the branch the launcher runs (the extension point has no
|
# stable: the branch the launcher runs (the extension point has no
|
||||||
# version, so it takes the app's branch).
|
# version, so it takes the app's branch).
|
||||||
xdg.dataFile = lib.optionalAttrs (defaultPrefs != { } || desktopFix) {
|
xdg.dataFile = lib.optionalAttrs (defaultPrefs != { }) { # desktopFix implies a pref
|
||||||
"flatpak/extension/org.mozilla.firefox.systemconfig/aarch64/stable".source = sysconfig;
|
"flatpak/extension/org.mozilla.firefox.systemconfig/aarch64/stable".source = sysconfig;
|
||||||
} // {
|
} // {
|
||||||
"applications/org.mozilla.firefox.desktop".text = ''
|
"applications/org.mozilla.firefox.desktop".text = ''
|
||||||
|
|||||||
@@ -26,14 +26,15 @@ writeShellScript "firefox-launcher" (''
|
|||||||
'' + lib.optionalString desktopFix ''
|
'' + lib.optionalString desktopFix ''
|
||||||
js=${lib.escapeShellArg desktopJs}
|
js=${lib.escapeShellArg desktopJs}
|
||||||
u=$prof/user.js
|
u=$prof/user.js
|
||||||
|
pats=${lib.escapeShellArg (lib.concatMapStringsSep "\n" (k: "user_pref(${builtins.toJSON k},") desktopKeys)}
|
||||||
# Firefox holds .parentlock open while it uses a profile (the sandbox sees
|
# Firefox holds .parentlock open while it uses a profile (the sandbox sees
|
||||||
# the profile at the same path).
|
# the profile at the same path).
|
||||||
inUse() { find /proc/[0-9]*/fd -lname "$prof/.parentlock" -print -quit 2>/dev/null | grep -q .; }
|
inUse() { find /proc/[0-9]*/fd -lname "$prof/.parentlock" -print -quit 2>/dev/null | grep -q .; }
|
||||||
ours() { [ -L "$u" ] && [ "$(readlink "$u")" = "$js" ]; }
|
ours() { [ -L "$u" ] && [ "$(readlink "$u")" = "$js" ]; }
|
||||||
sfn_unlink() {
|
sfn_unlink() {
|
||||||
ours && ! inUse || return 0
|
ours && ! inUse || return 0
|
||||||
if [ -f "$prof/prefs.js" ] && grep -qF -f <(printf '%s\n' ${lib.escapeShellArgs (map (k: "user_pref(${builtins.toJSON k},") desktopKeys)}) "$prof/prefs.js"; then
|
if [ -f "$prof/prefs.js" ] && grep -qF "$pats" "$prof/prefs.js"; then
|
||||||
grep -vF -f <(printf '%s\n' ${lib.escapeShellArgs (map (k: "user_pref(${builtins.toJSON k},") desktopKeys)}) "$prof/prefs.js" > "$prof/prefs.js.sfn" || true
|
grep -vF "$pats" "$prof/prefs.js" > "$prof/prefs.js.sfn" || true
|
||||||
cat "$prof/prefs.js.sfn" > "$prof/prefs.js"
|
cat "$prof/prefs.js.sfn" > "$prof/prefs.js"
|
||||||
rm -f "$prof/prefs.js.sfn"
|
rm -f "$prof/prefs.js.sfn"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -70,15 +70,10 @@ let
|
|||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Give the patch one persistent JSON value (e.g. choices made in its
|
Give the patch one persistent JSON value (e.g. choices made in its
|
||||||
UI), kept by the service in
|
UI): `window.__sfuiStore.get(name)` / `.set(name, value)` in the
|
||||||
$XDG_STATE_HOME/steam-frame-nix/ui-patches/<name>.json across
|
page, kept in $XDG_STATE_HOME/steam-frame-nix/ui-patches/<name>.json
|
||||||
SteamVR restarts and reboots: the page reads it with
|
across SteamVR restarts, reboots and disabling the patch; removed
|
||||||
`window.__sfuiStore.get(name)` and writes it with
|
by `steam-frame-nix-cleanup --all`.
|
||||||
`window.__sfuiStore.set(name, value)` (see injector.mjs). The file
|
|
||||||
is kept when the patch is disabled or removed (the choices come
|
|
||||||
back when it is enabled again) and removed by
|
|
||||||
`steam-frame-nix-cleanup --all` (also run by `install.sh
|
|
||||||
uninstall`).
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -106,9 +101,9 @@ in {
|
|||||||
defaultText = lib.literalMD "the helpers of `modules/lib`";
|
defaultText = lib.literalMD "the helpers of `modules/lib`";
|
||||||
description = ''
|
description = ''
|
||||||
Patch helpers from modules/lib/default.nix: `mkPatch { name, src,
|
Patch helpers from modules/lib/default.nix: `mkPatch { name, src,
|
||||||
signatures ? …, opts ? { } }` (calls `src` as
|
signatures ? …, opts ? { }, extraArgs ? [ ] }` (calls `src` as
|
||||||
`(find, sigs, opts, hooks) => …`; see there), plus `finders`, `hooks`
|
`(find, sigs, opts, hooks, ...extraArgs) => …`; see there), plus
|
||||||
(paths) and `signatures` (parsed signatures.json).
|
`finders`, `hooks` (paths) and `signatures` (parsed signatures.json).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user