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:
Pierre Kisters committed 2026-09-29 01:33:16 +02:00
1 parent a5ecbad76d
commit b3d93e8526
8 files changed
+43 -69

No files matched your search

+10 -4
View File
@@ -4,9 +4,9 @@
Valve Steam Frame (SteamOS, `aarch64-linux`, standalone home-manager). They
work around quirks of the Frame's [two graphical sessions](#two-sessions)
(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,
"+" menu, dashboard windows, Steam close button, window curvature, window
controls).
video decoding in Jellyfin, run rootless Docker, and extend Steam's and
SteamVR's UIs at runtime (VR keyboard, "+" menu, dashboard windows, Steam
close button, window curvature, window controls).
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
@@ -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.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.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.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. |
+3 -9
View File
@@ -44,12 +44,6 @@ Port: `VRWebHelper/DebuggerPort`, default 8087.
- when SteamVR stops, the key goes back to its previous value (removed if
it wasn't there) and `.armed` is removed.
The runtime files don't need Nix, which is why rollback and uninstall are
covered; they are gone at reboot, and `.armed` (the only trace after a
power loss) is resolved by the next SteamVR start or
`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.
The runtime files need no Nix (rollback, uninstall) and are gone at reboot;
`.armed`, the only trace after a power loss, is resolved by the next
SteamVR start or `steam-frame-nix-cleanup`.
+10 -17
View File
@@ -65,16 +65,8 @@ it runs. What they have in common:
## Defining a patch
`steamFrame.uiPatches.patches` entries:
| 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). |
A `steamFrame.uiPatches.patches` entry (fields:
[README, Options](../README.md#options)):
```nix
steamFrame.uiPatches.patches = [ {
@@ -128,9 +120,11 @@ patches never use them. `modules/lib/finders.js` (like Decky Loader's
`findInReactTree`).
Every signature must match exactly once, otherwise the patch changes nothing
and reports it (e.g. `signature not found, Steam left unpatched:
layouts.currentLayout (module 40222): ambiguous export, candidates r_, xy`).
Results are cached per page.
and reports it: `resolvePatch` returns e.g. `signature not found, Steam left
unpatched: layouts.currentLayout (module 40222): ambiguous export,
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
offline checker. An entry can also list `expects` (strings the patch relies
@@ -164,10 +158,9 @@ steamFrame.uiPatches.patches = [ {
```js
((find, sigs, opts, hooks) => {
let mods;
try { mods = find.resolveAll(find.getWebpackRequire('webpackChunksteamui'), sigs); }
catch (e) { return `not patched: ${e.message}`; }
const Thing = mods.thing.exports.Thing; // SteamVR dashboard: 'webpackChunkvrwebui'
const mods = find.resolvePatch('webpackChunksteamui', sigs); // SteamVR dashboard: 'webpackChunkvrwebui'
if (typeof mods === 'string') return mods; // signature not found
const Thing = mods.thing.exports.Thing;
…
})
```
-6
View File
@@ -591,12 +591,6 @@ cmd_debugger_arm() {
local cur tmp
need_not_root
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 $VRSETTINGS ]]; then
cur="$(jq -r 'if (.VRWebHelper | type) == "object" and (.VRWebHelper | has("DebuggerEnabled"))
-2
View File
@@ -203,11 +203,9 @@ pkgs.runCommand "cleanup-check" { nativeBuildInputs = [ cleanup pkgs.jq ]; } ''
arm() { bash ${../../install.sh} steamvr-debugger-arm; }
fresh e
printf '{\n "steamvr" : {}\n}\n' > $V
touch $S/steamvr-debugger # old marker: migrated
echo activating > $STUB/state
res=$(arm); echo "$res"
[ "$(cat $S/steamvr-debugger.armed)" = absent ] || fail "armed"
gone $S/steamvr-debugger
[ "$(jq -c .VRWebHelper $V)" = '{"DebuggerEnabled":true}' ] || fail "arm: $(cat $V)"
there $root/run/steam-frame-nix/steamvr-debugger-restore
[ "$(grep -c daemon-reload $STUB/log)" = 1 ] || fail "arm reload"
+10 -17
View File
@@ -1,25 +1,18 @@
# Firefox Flatpak (org.mozilla.firefox) launcher.
# - prefs and vrFullscreenFix are default prefs (pref(), the default branch:
# never written to prefs.js, so removing one leaves nothing behind). Firefox
# reads defaults/pref/*.js from its system config dir, /app/etc/firefox in
# the Flatpak, the mount point of the org.mozilla.firefox.systemconfig
# extension. The user installation's "unmaintained extension" dir
# ($XDG_DATA_HOME/flatpak/extension/<id>/<arch>/<branch>) provides it: a
# home-manager link to a store dir, which Flatpak mounts itself (the
# sandbox needn't see /nix).
# - prefs and vrFullscreenFix are default prefs (pref(): never written to
# prefs.js, so removing one leaves nothing behind) in defaults/pref/ of the
# org.mozilla.firefox.systemconfig extension (/app/etc/firefox), provided
# as the user installation's "unmaintained extension"
# ($XDG_DATA_HOME/flatpak/extension/<id>/<arch>/<branch>): a Home Manager
# link to a store dir, which Flatpak mounts itself (the sandbox needn't see
# /nix).
# - vrFullscreenFix: in the Steam session gamescope focuses a fullscreen X11
# window but never shows it (Firefox looks frozen). ignore-widgets keeps
# fullscreen inside the window.
# - desktopProfile: the sessions have separate buses/displays, so a second
# 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).
# Fullscreen works there, so the launcher undoes the fix in that profile
# 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).
# desktop gets its own profile, where fullscreen works: the launcher undoes
# the fix there while its Firefox runs (firefox/launcher.nix).
# The entry shadows the Flatpak's (same ID), keeping MIME associations, and is
# seen by the "+" menu (which reads only ~/.local/share/applications).
# 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
# 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;
} // {
"applications/org.mozilla.firefox.desktop".text = ''
+3 -2
View File
@@ -26,14 +26,15 @@ writeShellScript "firefox-launcher" (''
'' + lib.optionalString desktopFix ''
js=${lib.escapeShellArg desktopJs}
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
# the profile at the same path).
inUse() { find /proc/[0-9]*/fd -lname "$prof/.parentlock" -print -quit 2>/dev/null | grep -q .; }
ours() { [ -L "$u" ] && [ "$(readlink "$u")" = "$js" ]; }
sfn_unlink() {
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
grep -vF -f <(printf '%s\n' ${lib.escapeShellArgs (map (k: "user_pref(${builtins.toJSON k},") desktopKeys)}) "$prof/prefs.js" > "$prof/prefs.js.sfn" || true
if [ -f "$prof/prefs.js" ] && grep -qF "$pats" "$prof/prefs.js"; then
grep -vF "$pats" "$prof/prefs.js" > "$prof/prefs.js.sfn" || true
cat "$prof/prefs.js.sfn" > "$prof/prefs.js"
rm -f "$prof/prefs.js.sfn"
fi
+7 -12
View File
@@ -70,15 +70,10 @@ let
default = false;
description = ''
Give the patch one persistent JSON value (e.g. choices made in its
UI), kept by the service in
$XDG_STATE_HOME/steam-frame-nix/ui-patches/<name>.json across
SteamVR restarts and reboots: the page reads it with
`window.__sfuiStore.get(name)` and writes it with
`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`).
UI): `window.__sfuiStore.get(name)` / `.set(name, value)` in the
page, kept in $XDG_STATE_HOME/steam-frame-nix/ui-patches/<name>.json
across SteamVR restarts, reboots and disabling the patch; removed
by `steam-frame-nix-cleanup --all`.
'';
};
};
@@ -106,9 +101,9 @@ in {
defaultText = lib.literalMD "the helpers of `modules/lib`";
description = ''
Patch helpers from modules/lib/default.nix: `mkPatch { name, src,
signatures ? …, opts ? { } }` (calls `src` as
`(find, sigs, opts, hooks) => …`; see there), plus `finders`, `hooks`
(paths) and `signatures` (parsed signatures.json).
signatures ? …, opts ? { }, extraArgs ? [ ] }` (calls `src` as
`(find, sigs, opts, hooks, ...extraArgs) => …`; see there), plus
`finders`, `hooks` (paths) and `signatures` (parsed signatures.json).
'';
};