mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 01:00:13 +02:00
README: full user documentation again, docs/ only technical
The README is the complete user documentation again: features, install, two sessions, usage, the full options table (and renamed options), every feature with problem, usage, limitations, security and "remove when", UI patches at user level (DevTools on the LAN, after a Steam update), changes outside Nix, rollback and uninstall. docs/ keeps only the technical side (how the patches work, writing patches, signatures and the update procedure, the SteamVR debugger mechanics, cleanup and installer internals), linked from each feature. docs/options.md, two-sessions.md and desktop-integration.md are gone (their content is in the README).
This commit is contained in:
1 parent
23b79e9499
commit
5a3d0b9d05
13 files changed
+1126
-856
No files matched your search
+41
-86
@@ -1,51 +1,41 @@
|
||||
# Changes outside Nix
|
||||
# Cleanup and installer: how they work
|
||||
|
||||
Everything not listed here is a Home Manager link into the Nix store or
|
||||
lives in memory (the [UI patches](ui-patches.md)).
|
||||
|
||||
## Written at runtime
|
||||
|
||||
| Path | Feature | Lifetime | Removed by |
|
||||
|---|---|---|---|
|
||||
| `VRWebHelper.DebuggerEnabled` in `~/.config/openvr/config/steamvr.vrsettings` | [SteamVR debugger](steamvr-debugger.md) | only while SteamVR runs | SteamVR stopping (runtime drop-in below); `steam-frame-nix-cleanup` while SteamVR is stopped |
|
||||
| `~/.local/state/steam-frame-nix/steamvr-debugger.armed` | SteamVR debugger: the key's previous value | while SteamVR runs; after a power loss until the next SteamVR start or cleanup | SteamVR stopping; `steam-frame-nix-cleanup` |
|
||||
| `/run/user/1000/systemd/user/steamvr.service.d/50-steam-frame-nix-debugger.conf`, `/run/user/1000/steam-frame-nix/steamvr-debugger-restore` | SteamVR debugger: puts the key back when SteamVR stops, without Nix | until reboot (tmpfs) | reboot; `steam-frame-nix-cleanup` while SteamVR is stopped and the debugger is off |
|
||||
| `~/.local/state/steam-frame-nix/ui-patches/<name>.json` | [persistent state](ui-patches.md#persistent-state) of dashboard patches: window control bar placements (`frame-controls`), "Steam hidden" (`steam-close-button`). SteamOS's `steamvr.service` deletes `~/.cache/SteamVR` (the dashboard's own browser storage) on every SteamVR start. | until removed: kept when a patch is disabled (the choices come back when you enable it again) | `steam-frame-nix-cleanup --all`, `install.sh uninstall` |
|
||||
| mtime of `~/.local/share/icons/hicolor` | [icon fallbacks](launcher-menu.md#icon-fallbacks): a running Steam rescans icons | only the directory's timestamp | nothing to remove |
|
||||
|
||||
## Only while running
|
||||
|
||||
- The UI patches (Steam, SteamVR dashboard, VR keyboard) live in the pages'
|
||||
memory; stopping `steam-ui-patches` / `steam-keyboard-patch` reverts them.
|
||||
- clipboard-sync runs from KDE autostart (a Home Manager link).
|
||||
- Firefox: the desktop profile's `user.js` link exists only while its
|
||||
Firefox runs (see [Firefox](firefox.md#how-it-works)).
|
||||
- Jellyfin: the hardware decoding permissions are `flatpak run` options of
|
||||
the desktop entry, not a Flatpak override.
|
||||
What steam-frame-nix writes outside the Nix store, how to remove it, and
|
||||
rollback/uninstall: README,
|
||||
[Changes outside Nix](../README.md#changes-outside-nix-exceptions),
|
||||
[Rollback](../README.md#rollback), [Uninstall](../README.md#uninstall).
|
||||
|
||||
## Cleanup
|
||||
|
||||
**`steam-frame-nix-cleanup`** (`install.sh cleanup`,
|
||||
`steamFrame.cleanup.package`) knows everything any version of
|
||||
steam-frame-nix wrote outside the store, removes only what is provably its
|
||||
own (everything else is reported as "left alone") and can be run again
|
||||
safely; `--dry-run` shows what it would do.
|
||||
`steam-frame-nix-cleanup` (`steamFrame.cleanup.package`, module `cleanup`,
|
||||
imported by every module) is `install.sh cleanup`, so the same code runs
|
||||
with Nix (on every switch: `cleanup --orphans --keep <what the configuration
|
||||
still uses>`) and without it, from the script (bash, coreutils, findutils,
|
||||
jq, all in SteamOS' `/usr/bin`). Home Manager's `uninstall = true;` runs
|
||||
`cleanup --all` from the activation.
|
||||
|
||||
- On every switch, `cleanup --orphans` removes what the configuration no
|
||||
longer uses (never the saved patch state).
|
||||
- `steam-frame-nix-cleanup --all` removes everything, also the saved patch
|
||||
state. SteamVR's key can't be changed while SteamVR runs: it is then left
|
||||
to the runtime drop-in (restored when SteamVR stops).
|
||||
- Without Nix or after a rollback it runs from the script
|
||||
(bash, coreutils, findutils, jq, all in SteamOS' `/usr/bin`):
|
||||
`curl -fsSL https://steam-frame-nix.lhns.de | bash -s -- cleanup --all`.
|
||||
- It also removes what older versions left: the icon fallback links and
|
||||
their list (`~/.local/state/steam-frame-nix/icon-fallbacks`), the
|
||||
debugger marker `steamvr-debugger`, Firefox `user.js` copies and links
|
||||
and their `prefs.js` values, the Jellyfin hwdec entries of
|
||||
`~/.local/share/flatpak/overrides/org.jellyfin.JellyfinDesktop` (an empty
|
||||
override file too) and the old shim copy in
|
||||
`~/.var/app/org.jellyfin.JellyfinDesktop`.
|
||||
It knows everything any version wrote outside the store and removes an
|
||||
artifact only when it is proven to be its own; anything else is reported as
|
||||
"left alone" and never touched:
|
||||
|
||||
| Artifact | Proof / rule |
|
||||
|---|---|
|
||||
| `debugger`: `VRWebHelper.DebuggerEnabled` in `steamvr.vrsettings` | `~/.local/state/steam-frame-nix/steamvr-debugger.armed` holds the value before (older versions: the empty marker `steamvr-debugger`, value before = absent). Restored once SteamVR is stopped; while it runs the runtime drop-in restores it when SteamVR stops. Also the runtime drop-in and restore script themselves. |
|
||||
| `icons`: `hicolor/scalable/apps/<name>.svg` | links to Breeze in the store, listed in `~/.local/state/steam-frame-nix/icon-fallbacks` (the icon-fallbacks script of 2026-09) |
|
||||
| `firefox`: `user.js` in Firefox profiles | links to `/app/etc/firefox/steam-frame-nix-desktop-user.js` (left alone while the profile is in use), older links to `*-firefox-*user.js` and copies starting with the steam-frame-nix marker comment, and the values they left in `prefs.js` (only with Firefox closed) |
|
||||
| `jellyfin` | the hwdec shim entries in the Jellyfin Flatpak's user override `~/.local/share/flatpak/overrides/org.jellyfin.JellyfinDesktop` (nix-flatpak), an empty override file, and the shim copy of earlier versions in `~/.var/app/org.jellyfin.JellyfinDesktop` (marker `~/.local/state/steam-frame-nix/jellyfin-hwdec-shim`) |
|
||||
| `ui-state`: `~/.local/state/steam-frame-nix/ui-patches/<name>.json` | the dashboard patches' saved choices; `--all` only, never `--orphans`; stray `*.json.tmp` files |
|
||||
| `dirs` | `~/.local/state/steam-frame-nix` and `/run/user/1000/steam-frame-nix` when empty |
|
||||
|
||||
### Left by older versions
|
||||
|
||||
The rows above include what only older versions wrote: the icon fallback
|
||||
links and their list (`~/.local/state/steam-frame-nix/icon-fallbacks`), the
|
||||
debugger marker `steamvr-debugger`, Firefox `user.js` copies and links and
|
||||
their `prefs.js` values, the Jellyfin hwdec entries of
|
||||
`~/.local/share/flatpak/overrides/org.jellyfin.JellyfinDesktop` (an empty
|
||||
override file too) and the old shim copy in
|
||||
`~/.var/app/org.jellyfin.JellyfinDesktop`.
|
||||
|
||||
## Set up by install.sh
|
||||
|
||||
@@ -61,52 +51,17 @@ safely; `--dry-run` shows what it would do.
|
||||
- `experimental-features = nix-command flakes` in `~/.config/nix/nix.conf`
|
||||
if Nix was already there without flakes;
|
||||
- `~/nix-config` (your configuration, a git repository, from the template
|
||||
with your user name) and the link `~/.config/home-manager` to it, unless
|
||||
`~/.config/home-manager` exists or `--flake <dir-or-flakeref>` is given;
|
||||
uninstall removes the link, never the configuration;
|
||||
with your user name filled into `flake.nix`) and the link
|
||||
`~/.config/home-manager` to it, unless `~/.config/home-manager` exists or
|
||||
`--flake <dir-or-flakeref>` is given; uninstall removes the link, never
|
||||
the configuration;
|
||||
- dotfiles Home Manager found in its way, renamed to `*.hm-backup-<time>`
|
||||
(kept by uninstall);
|
||||
- `~/.local/state/home-manager` and `~/.local/state/nix` (profiles,
|
||||
generations), `~/.nix-profile`, `~/.nix-defexpr`, `~/.nix-channels`,
|
||||
`~/.cache/nix`.
|
||||
|
||||
## App data you create
|
||||
|
||||
Not steam-frame-nix's to remove: the Firefox desktop profile
|
||||
(`~/.var/app/org.mozilla.firefox/config/mozilla/firefox/desktop`, browser
|
||||
data), and whatever apps keep in `~/.var/app/*`, Flatpak apps and their
|
||||
runtimes.
|
||||
|
||||
## Rollback
|
||||
|
||||
`home-manager generations` lists previous generations; run
|
||||
`<store path>/activate` of the one you want. Generations with
|
||||
steam-frame-nix clean up after themselves on activation (orphans). After
|
||||
rolling back to a generation **without** steam-frame-nix, or to one older
|
||||
than `steam-frame-nix-cleanup` (2026-09-29), remove what the newer one wrote
|
||||
outside the store:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://steam-frame-nix.lhns.de | bash -s -- cleanup --all
|
||||
# or: nix run github:lhns/steam-frame-nix#cleanup -- --all
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
|
||||
```sh
|
||||
curl -fsSL https://steam-frame-nix.lhns.de | bash -s -- uninstall # --keep-nix keeps Nix
|
||||
```
|
||||
|
||||
stops Home Manager's user services (reverting the UI patches), runs
|
||||
`cleanup --all`, runs `home-manager uninstall`, then removes Nix and the
|
||||
per-user Nix state (see [Set up by install.sh](#set-up-by-installsh)). If
|
||||
SteamVR is running, its key is restored when SteamVR stops (the closing
|
||||
message says so). Your configuration, `*.hm-backup-*` files, app data and
|
||||
Flatpaks stay.
|
||||
|
||||
To drop steam-frame-nix from a Home Manager configuration you keep, first
|
||||
run `steam-frame-nix-cleanup --all`, then remove it and switch. Or set Home
|
||||
Manager's `uninstall = true;` in the configuration that still imports
|
||||
steam-frame-nix and switch: its activation runs `cleanup --all` while Home
|
||||
Manager removes its files. (`home-manager uninstall` alone doesn't load
|
||||
steam-frame-nix's modules, so it can't clean up after them.)
|
||||
The installer runs `systemctl --user` against the outer session's user
|
||||
manager (the nested desktop can't reach it with its own environment) and
|
||||
uses the installed `home-manager` if there is one, else Home Manager's
|
||||
`master`.
|
||||
+69
-133
@@ -1,122 +1,89 @@
|
||||
# SteamVR dashboard
|
||||
# SteamVR dashboard patches: how they work
|
||||
|
||||
Four patches of SteamVR's dashboard (`systemui` page): [window size and
|
||||
distance](#dashboard-windows), [Steam close button](#steam-close-button),
|
||||
[window curvature](#window-curvature), [window control bar](#window-control-bar).
|
||||
Options: [options.md#dashboard](options.md#dashboard).
|
||||
Technical details of the four dashboard patches. What they do and how to
|
||||
configure them: README, [dashboard windows](../README.md#dashboard-windows-dashboardwindows),
|
||||
[Steam close button](../README.md#steam-close-button-dashboardsteamclosebuttonenable),
|
||||
[window curvature](../README.md#window-curvature-dashboardwindowcurvature),
|
||||
[window control bar](../README.md#window-control-bar-dashboardframecontrols).
|
||||
|
||||
All are [UI patches](ui-patches.md) and turn on the
|
||||
All four are `mkPatch` [UI patches](ui-patches.md) of SteamVR's dashboard
|
||||
(`vrwebhelper`, page title `systemui`, DevTools `127.0.0.1:8087`, webpack
|
||||
chunk `webpackChunkvrwebui`), registered only when enabled; they turn on the
|
||||
[SteamVR debugger](steamvr-debugger.md). Each is found by signature (its
|
||||
entry in `signatures.json` has the patch's name); on mismatch the dashboard
|
||||
stays stock. Tested with SteamVR build 11008059.
|
||||
entry in `modules/lib/signatures.json` has the patch's name); on mismatch
|
||||
the dashboard stays stock. Sources: `modules/<name>/patch.js`, whose header
|
||||
comments go into more detail.
|
||||
|
||||
## Dashboard windows
|
||||
|
||||
`dashboard.windows.*`.
|
||||
`dashboard-windows`. `systemui` sends its scene graph to vrcompositor via
|
||||
`mailbox.SendMessage("vrcompositor_systemlayer", { type: "update_scene_graph", scene_graph })`,
|
||||
and vrcompositor enforces the limits in it:
|
||||
|
||||
**Problem:** dashboard windows can only be enlarged to 2x, and grabbed
|
||||
windows pushed back only to 5 m (6 m in theater), too close for a big
|
||||
screen.
|
||||
- `frame-resize-scale-min` / `-max` on window frames;
|
||||
- `min-distance` / `max-distance` on grab nodes: `grab-scale` for world
|
||||
windows, `grab-transform` for the theater screen and the dashboard (the
|
||||
keyboard's `grab-transform`, 0.2 / 1 m, is left alone).
|
||||
|
||||
**What it does:** raises these limits, which the dashboard sends to the
|
||||
compositor in its scene graph. `null` keeps stock:
|
||||
They are literals in the bundle, so the patch hooks `SendMessage` on the
|
||||
mailbox prototype ([shared hooks](ui-patches.md#shared-method-hooks), shared
|
||||
with window curvature) and edits outgoing scene graphs in place. Grab nodes
|
||||
are matched by type plus exact stock values, so if SteamVR changes them the
|
||||
distance rewrite becomes a no-op. A scene-graph resend applies new limits at
|
||||
once.
|
||||
|
||||
| Option | Stock |
|
||||
|---|---|
|
||||
| `maxScale` | 2 (relative to the window's default size; the theater screen's default is 2.8x larger) |
|
||||
| `distance.world.{min,max}` | 0.25-5 m |
|
||||
| `distance.theater.{min,max}` | 1-6 m |
|
||||
| `distance.dashboard.{min,max}` | 0.3-4 m |
|
||||
|
||||
Distances limit pulling in / pushing back a grabbed window (thumbstick or
|
||||
scroll while dragging). Changes apply immediately; turning options off
|
||||
reverts on the next switch. The keyboard's range is not patched.
|
||||
|
||||
```nix
|
||||
steamFrame.dashboard.windows = {
|
||||
maxScale = 4.0; # resize up to 4x (theater: 11.2x)
|
||||
distance.world.max = 10.0; # push windows back up to 10 m
|
||||
distance.theater.max = 12.0;
|
||||
};
|
||||
```
|
||||
|
||||
**Caveat:** grab nodes are recognized by their exact stock values, so if
|
||||
SteamVR changes them the distance options silently do nothing. State:
|
||||
`window.__sfuiDashboardWindows`.
|
||||
State: `window.__sfuiDashboardWindows` (counters in `.hits`).
|
||||
|
||||
## Steam close button
|
||||
|
||||
`dashboard.steamCloseButton.enable`.
|
||||
`steam-close-button`, with [persistent state](ui-patches.md#persistent-state)
|
||||
(`{ schema: 1, steamHidden }`).
|
||||
|
||||
**Problem:** every dashboard window has a close (X) button except Steam's
|
||||
own, and with no other window open the dashboard always shows it.
|
||||
- **Button:** the frame's `closing` component shows X when
|
||||
`componentProps.onCloseRequested` exists; the Steam window's instance
|
||||
(overlay `valve.steam.gamepadui.main`) gets one and its props are
|
||||
re-assigned so the MobX computed re-evaluates.
|
||||
- **Staying hidden:** while hidden, stock fallbacks to Steam go to the
|
||||
previous window or bar-only instead: `Dashboard.autoSwitchOverlayIfNeeded`
|
||||
(instance override) and the mailbox handler `dashboard_overlay_destroyed`.
|
||||
Mailbox show/switch requests for Steam with reason `SetDockLocation` (the
|
||||
echo of X docking Steam) are dropped, "theater frame destroyed" ones are
|
||||
passed on without the Steam key. Explicit requests (tab click, Steam menu
|
||||
pick, `SwitchToDashboardOverlay`) show Steam again.
|
||||
- **Restarts:** a restored hidden state stays pending (`restorePending`)
|
||||
until Steam's frame is seen, since the injector attaches within ~5 s of
|
||||
the page appearing.
|
||||
|
||||
**What it does:** gives the Steam window an X that hides Steam: it docks the
|
||||
window back if it was in the world, theater or on a hand, then shows the
|
||||
most recently active other dashboard window, or **just the dashboard bar**
|
||||
if there is none.
|
||||
|
||||
Steam stays hidden until you bring it back (Steam tab, a Steam menu pick,
|
||||
SteamVR asking for it): closing the active window, or a theater window, then
|
||||
goes to the previous window or the bar instead of Steam. This survives
|
||||
dashboard reopens, patch-service restarts, SteamVR restarts and reboots
|
||||
("Steam hidden" is saved in
|
||||
`~/.local/state/steam-frame-nix/ui-patches/steam-close-button.json`, see
|
||||
[persistent state](ui-patches.md#persistent-state)). After a restart the
|
||||
patch attaches a few seconds after the dashboard appears, possibly after
|
||||
SteamVR has already shown Steam: if Steam is (or first becomes) the active
|
||||
window then, it is hidden once like with X (only the bar at that point);
|
||||
otherwise it just stays hidden.
|
||||
|
||||
**Limitations:** SteamVR's rarer "go home" paths (Now Playing after a game
|
||||
quits, message overlays) still show Steam; no effect with a VRLink remote
|
||||
dashboard; turning the option off while bar-only leaves no active window
|
||||
until the next tab click or dashboard open.
|
||||
|
||||
Debugging: `window.__sfuiSteamClose.plan()` / `homePlan()` and
|
||||
`window.__sfuiSteamCloseState`.
|
||||
Debugging: `window.__sfuiSteamClose.plan()` / `homePlan()`; state in
|
||||
`window.__sfuiSteamCloseState` (survives re-injection; teardown restores all
|
||||
overrides and never switches frames).
|
||||
|
||||
## Window curvature
|
||||
|
||||
`dashboard.windowCurvature.*`.
|
||||
`window-curvature`. Stock curvature: the frame renders a transform
|
||||
`frame:<id>:curvature-origin` at `z = DashboardStore.curvatureDistance` when
|
||||
curved, else 1000; its panels reference it as `curvature-origin-id` and
|
||||
vrcompositor bends them onto a cylinder around it (curvature = 1/radius).
|
||||
Those MobX properties are non-configurable, so the patch hooks the mailbox
|
||||
`SendMessage` (shared with dashboard windows) and rewrites the origin's z
|
||||
in outgoing scene graphs to stock / value. On/off stays the stock toggle
|
||||
state, so stock toggle and wheel always agree.
|
||||
|
||||
**Problem:** dashboard windows are either curved (fixed radius) or flat, and
|
||||
world windows start flat.
|
||||
|
||||
**What it does:** turns the "Toggle Curvature" row of a window's three-dot
|
||||
menu into a control showing the window's value; the same control in the
|
||||
bottom bar (see [window control bar](#window-control-bar)) works without the
|
||||
value, with haptic steps.
|
||||
|
||||
- **click:** curved → flat, flat → stock (1);
|
||||
- **drag up/down** with the laser: curvature from 0 (flat) to `max`,
|
||||
relative to stock (2 = half the radius), rounded to `step`, with a detent
|
||||
of `detentPixels` of drag at each of `detentPoints` (no values skipped),
|
||||
and haptics (`haptics`) for detents, edges and steps. Drag distance:
|
||||
`dragPixelsPerUnit` in the menu, `barDragPixelsPerUnit` on the bar button,
|
||||
after `dragThresholdPixels`.
|
||||
|
||||
A window without its own value is shown at `initial` once curved in the
|
||||
world or on a hand, at 1 in the dashboard or theater. Values are kept per
|
||||
window until SteamVR restarts.
|
||||
|
||||
**Limitations:**
|
||||
|
||||
- Laser only; with gamepad navigation the row is the stock toggle.
|
||||
- No thumbstick scrolling (SteamVR sends no wheel events to the menu).
|
||||
- The laser stops at the menu's edge (~190 px above the row): with the
|
||||
default 120 px per 1.0, 0 → 1 fits into one drag, 0 → 3 takes two. Lower
|
||||
`dragPixelsPerUnit` (≤ 60) for the full range in one drag.
|
||||
Values are kept per window (key: first overlay key) in
|
||||
`window.__sfuiWindowCurvatureState`, across re-patch and unpatch, not across
|
||||
a dashboard reload. The bar button uses the coordinates SteamVR keeps
|
||||
sending past the pressed panel's edge while the trigger is held; the bar
|
||||
panel is never resized.
|
||||
|
||||
Debugging: `window.__sfuiWindowCurvature.dump()` (`.log` recent events).
|
||||
|
||||
### Contract for other patches
|
||||
|
||||
For patches handling presses on the curvature controls: every
|
||||
element the patch drives has class `sfui-curv-ctl`; when a press becomes a
|
||||
drag, a bubbling `CustomEvent` `sfui-curv-dragstart` (detail
|
||||
`{ frameID, where: 'menu' | 'bar' }`) is dispatched on it, and
|
||||
`sfui-curv-dragend` when it ends;
|
||||
For patches handling presses on the curvature controls (e.g. the window
|
||||
control bar's long press): every element the patch drives has class
|
||||
`sfui-curv-ctl`; when a press becomes a drag, a bubbling `CustomEvent`
|
||||
`sfui-curv-dragstart` (detail `{ frameID, where: 'menu' | 'bar' }`) is
|
||||
dispatched on it, and `sfui-curv-dragend` when it ends;
|
||||
`window.__sfuiWindowCurvature.scalePressDragThreshold(factor)` sets the
|
||||
current press's drag threshold to `factor` × `dragThresholdPixels` (from the
|
||||
press start; returns whether it applied, i.e. a press that is not yet a
|
||||
@@ -124,46 +91,15 @@ drag); `window.__sfuiWindowCurvature.cancelPress()` ends a press without its
|
||||
click. A patch with its own gesture lets `mousemove` through while
|
||||
undecided, drops its gesture on `sfui-curv-dragstart`, may raise the
|
||||
threshold while its gesture is under way, and calls `cancelPress()` when it
|
||||
takes the press over.
|
||||
takes the press over. The window control bar uses factor 3 once its
|
||||
progress ring shows.
|
||||
|
||||
## Window control bar
|
||||
|
||||
`dashboard.frameControls.*`.
|
||||
|
||||
**Problem:** the controls under a dashboard window are fixed: some in the
|
||||
bottom bar, others only in the three-dot menu (curvature, dock to a
|
||||
controller), and theater windows have no "Float".
|
||||
|
||||
**What it does:**
|
||||
|
||||
- **long press** a bar icon or menu row (`longPressMs`; a progress ring
|
||||
shows from half the time, at most after 1 s), then **Show in bar** in the
|
||||
popup moves that control between bar and menu **for all windows**.
|
||||
Placements survive SteamVR restarts and reboots (saved in
|
||||
`~/.local/state/steam-frame-nix/ui-patches/frame-controls.json`, see
|
||||
[persistent state](ui-patches.md#persistent-state)).
|
||||
- `inBar` / `inMenu` set where controls start; a popup choice wins until
|
||||
that control's entry changes.
|
||||
- `floatInTheater` gives theater windows the "Float" control.
|
||||
|
||||
```nix
|
||||
steamFrame.dashboard.frameControls = {
|
||||
enable = true;
|
||||
# longPressMs = 1500;
|
||||
# inBar = [ "curvature" ]; inMenu = [ "theater" ];
|
||||
# floatInTheater = true;
|
||||
};
|
||||
```
|
||||
|
||||
With [window curvature](#window-curvature), a drag on the curvature control
|
||||
adjusts curvature and cancels the long press, also after the ring shows;
|
||||
once the ring shows, the drag needs 3× the usual travel
|
||||
(`dragThresholdPixels`, counted from where the press started), so laser
|
||||
drift during the hold doesn't cancel it.
|
||||
|
||||
**Limitations:** laser only (no right-click or thumbstick click reaches the
|
||||
dashboard; gamepad navigation sees stock controls); placements are per
|
||||
control type, not per window.
|
||||
`frame-controls`, with [persistent state](ui-patches.md#persistent-state)
|
||||
(placements). Short presses stay stock; the three-dot button can't be
|
||||
moved. Works with window curvature through the
|
||||
[contract](#contract-for-other-patches) above.
|
||||
|
||||
Debugging: `window.__sfuiFrameControls.dump()`, `.placement()`, `.reset()`
|
||||
(forget choices), `.log`, `window.__sfuiFrameControlsState`.
|
||||
@@ -1,54 +0,0 @@
|
||||
# Session, portal and clipboard
|
||||
|
||||
Plumbing between the Frame's [two sessions](two-sessions.md). Options:
|
||||
[Session](options.md#session), [Clipboard sync](options.md#clipboard-sync).
|
||||
|
||||
## Session settings and services
|
||||
|
||||
Module `session.nix`, used by the other modules; normally nothing to set.
|
||||
|
||||
- `session.runtimeDir` / `session.bus` point at the Steam session's runtime
|
||||
dir and bus (services, KDE wallet), which the nested desktop can't see.
|
||||
`session.busEnv` is a launcher prefix to reach them:
|
||||
|
||||
```nix
|
||||
xdg.dataFile."applications/org.example.App.desktop".text = ''
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Example
|
||||
Exec=${config.steamFrame.session.busEnv} flatpak run org.example.App %U
|
||||
'';
|
||||
```
|
||||
|
||||
- Switching from the nested desktop, Home Manager can't reach the service
|
||||
manager ("User systemd daemon not running"). So after every switch this
|
||||
module reloads the Steam session's user manager and applies
|
||||
`session.services.start` / `stop` / `restart`, which other modules fill.
|
||||
|
||||
## Portal
|
||||
|
||||
`session.portalFix.enable`, on by default.
|
||||
|
||||
**Problem:** the Frame image (SteamOS 0.3.0, build 20260922) points the Steam
|
||||
session's `xdg-desktop-portal` at `/usr/share/xdg-desktop-portal/gamescope-portals`,
|
||||
which lacks `gamescope-portals.conf`: no backend, no OpenURI, so no app in
|
||||
the Steam session can open links.
|
||||
|
||||
**Fix:** a portal dir in `~/.local/share` linking Valve's `.portal` files plus
|
||||
a config (`default=holo;gamescope`), and a drop-in on
|
||||
`xdg-desktop-portal.service`. The desktop's portal is unaffected.
|
||||
|
||||
**Remove when** SteamOS ships `gamescope-portals.conf`.
|
||||
|
||||
## Clipboard sync
|
||||
|
||||
`clipboardSync.enable`, on by default.
|
||||
|
||||
**Problem:** the Steam session's X displays and the nested desktop have
|
||||
separate clipboards.
|
||||
|
||||
**Fix:** [clipboard-sync](https://github.com/dnut/clipboard-sync), built from
|
||||
source (its flake is x86-only; `clipboardSync.package` to replace it),
|
||||
started via KDE autostart (the desktop can't reach the user manager, and
|
||||
`:2` must exist first). Each switch restarts it if outdated, so switch from a
|
||||
desktop terminal.
|
||||
+12
-28
@@ -1,31 +1,9 @@
|
||||
# Firefox
|
||||
# Firefox: how it works
|
||||
|
||||
`firefox.enable`: a launcher for the Flathub Firefox Flatpak
|
||||
(`org.mozilla.firefox`, stable). It shadows the Flatpak's own entry (same
|
||||
ID), so default-browser associations keep working. Options:
|
||||
[options.md#firefox](options.md#firefox).
|
||||
`firefox.*` (module `firefox`). What it does and how to configure it:
|
||||
README, [Firefox](../README.md#firefox-firefox).
|
||||
|
||||
## Options
|
||||
|
||||
- **`vrFullscreenFix`** (on): gamescope never shows fullscreen windows, so
|
||||
Firefox looks frozen. `full-screen-api.ignore-widgets` makes fullscreen
|
||||
fill just the window. Not applied in the desktop profile. **Remove when**
|
||||
gamescope shows fullscreen X11 windows in VR.
|
||||
- **`disableAv1`** (off): `media.av1.enabled = false`. The Frame's decoder
|
||||
driver (`iris`) has no AV1, only H.264, HEVC and VP9, so YouTube and co.
|
||||
send VP9/H.264, decoded in hardware, instead of software AV1. **Remove
|
||||
when** a SteamOS kernel adds AV1 to `iris`.
|
||||
- **`prefs`:** further `about:config` values for every profile; they can
|
||||
also override the fixes above.
|
||||
- **`desktopProfile`** (`"desktop"`): the sessions can't see each other's
|
||||
Firefox, so a second instance stops at the locked profile; in the nested
|
||||
desktop the launcher uses this separate profile (a normal Firefox profile
|
||||
with its own browser data, created on first use). `null`: the default
|
||||
profile in both sessions.
|
||||
|
||||
Changes take effect at the next start of Firefox.
|
||||
|
||||
## How it works
|
||||
## Default prefs
|
||||
|
||||
`prefs` and the fixes are *default* values (`pref()`), not user values:
|
||||
`about:config` can still change them per profile, and nothing is written to
|
||||
@@ -38,8 +16,12 @@ extension as a link from
|
||||
to a store directory; Flatpak mounts it itself, so the sandbox doesn't get
|
||||
`/nix`. (A systemconfig extension of your own would conflict with it.)
|
||||
|
||||
The desktop profile undoes the fullscreen fix only while its Firefox runs:
|
||||
the launcher links the profile's `user.js` to
|
||||
## Desktop profile
|
||||
|
||||
The launcher (a desktop entry with the Flatpak's ID, shadowing its entry)
|
||||
picks `desktopProfile` when started in the nested desktop. The desktop
|
||||
profile undoes the fullscreen fix only while its Firefox runs: the launcher
|
||||
links the profile's `user.js` to
|
||||
`/app/etc/firefox/steam-frame-nix-desktop-user.js` (a sandbox path) right
|
||||
before starting Firefox, waits for it, and once it has exited and the
|
||||
profile is no longer in use removes the link and the value Firefox stored
|
||||
@@ -48,6 +30,8 @@ Firefox leaves both in place. A `user.js` of your own is never touched (the
|
||||
fix then stays on in that profile). After a crash, the next launch or
|
||||
`steam-frame-nix-cleanup` (on switch) removes them.
|
||||
|
||||
## Older versions
|
||||
|
||||
Older versions linked or copied a `user.js` into every profile; those and
|
||||
the values they left in `prefs.js` are removed by `steam-frame-nix-cleanup`
|
||||
on switch, for each profile not in use at that moment.
|
||||
+25
-46
@@ -1,13 +1,13 @@
|
||||
# Jellyfin hardware decoding
|
||||
# Jellyfin hardware decoding: how it works
|
||||
|
||||
`jellyfin.hardwareDecoding.enable`, for the Flathub
|
||||
[Jellyfin Desktop](https://github.com/jellyfin/jellyfin-desktop) Flatpak
|
||||
(`org.jellyfin.JellyfinDesktop`), which plays video with libmpv. Options:
|
||||
[options.md#jellyfin](options.md#jellyfin).
|
||||
`jellyfin.hardwareDecoding.*` (module `jellyfin`). What it does, how to
|
||||
configure it and its caveats: README,
|
||||
[Jellyfin hardware decoding](../README.md#jellyfin-hardware-decoding-jellyfinhardwaredecoding).
|
||||
|
||||
**Problem:** video is decoded in software (1080p H.264: ~40 % CPU). The
|
||||
Frame's hardware decoder is a V4L2 memory-to-memory device (`qcom-iris`,
|
||||
`/dev/video*`), which
|
||||
## Why mpv doesn't use the decoder
|
||||
|
||||
The Frame's hardware decoder is a V4L2 memory-to-memory device
|
||||
(`qcom-iris`, `/dev/video*`), which
|
||||
|
||||
- the Flatpak can't open: its `devices=dri` covers only the GPU, and Flatpak
|
||||
has nothing between that and `devices=all`;
|
||||
@@ -15,43 +15,23 @@ Frame's hardware decoder is a V4L2 memory-to-memory device (`qcom-iris`,
|
||||
probing leaves out V4L2 M2M on purpose (its quality varies by SoC).
|
||||
Jellyfin has no way to pass mpv options.
|
||||
|
||||
**What it does:** device access (`devices=all`) and an `LD_PRELOAD` shim
|
||||
that rewrites an `hwdec` value starting with `auto` (set through libmpv's
|
||||
`mpv_set_*` functions) to `$SFN_MPV_HWDEC` (the `hwdec` option, default
|
||||
`v4l2m2m-copy,auto-copy`); explicit values such as `no` stay. mpv tries the
|
||||
listed decoders in order and falls back to software decoding per stream.
|
||||
With the default, 1080p H.264 plays through `v4l2m2m-copy` at ~15-20 % CPU.
|
||||
Changes take effect at the next start of Jellyfin.
|
||||
## The shim
|
||||
|
||||
Installing the Flatpak is up to you, e.g.
|
||||
`flatpak install --user flathub org.jellyfin.JellyfinDesktop`, or with
|
||||
nix-flatpak:
|
||||
An `LD_PRELOAD` shim (`modules/jellyfin/mpv-hwdec-shim.c`, a few libmpv
|
||||
wrappers, only libc) rewrites an `hwdec` value starting with `auto` (set
|
||||
through libmpv's `mpv_set_*` functions) to `$SFN_MPV_HWDEC` (the `hwdec`
|
||||
option); explicit values such as `no` stay. It is preloaded from the Nix
|
||||
store; only its store path is exposed (read-only) to the sandbox. It would
|
||||
work for any libmpv app that sets `hwdec=auto*`, but only Jellyfin Desktop
|
||||
is set up here.
|
||||
|
||||
```nix
|
||||
services.flatpak.packages = [ "org.jellyfin.JellyfinDesktop" ];
|
||||
```
|
||||
|
||||
**Caveats:**
|
||||
|
||||
- `devices=all` gives the app all of `/dev` (cameras, input devices, ...),
|
||||
not just the decoder.
|
||||
- V4L2 M2M decoding quality varies with drivers and codecs. Tested: 8-bit
|
||||
H.264; 10-bit HEVC is untested. mpv falls back to software only when the
|
||||
decoder fails; for streams that decode with artifacts, disable the option
|
||||
(or set `hwdec = "auto-copy"`, Jellyfin's own value).
|
||||
|
||||
## How it works
|
||||
|
||||
The shim (a few libmpv wrappers, only libc) is preloaded from the Nix store;
|
||||
only its store path is exposed (read-only) to the sandbox. It would work for
|
||||
any libmpv app that sets `hwdec=auto*`, but only Jellyfin Desktop is set up
|
||||
here.
|
||||
## The desktop entry
|
||||
|
||||
Nothing is written to Flatpak's overrides: a desktop entry shadowing the
|
||||
Flatpak's (`~/.local/share/applications/org.jellyfin.JellyfinDesktop.desktop`,
|
||||
same ID, so the KDE menu and the "+" menu start it) passes them as
|
||||
`flatpak run` options, so they apply to launches from that entry and are
|
||||
gone with it. From a terminal:
|
||||
same ID, so the KDE menu and the "+" menu start it) passes device access and
|
||||
the shim as `flatpak run` options, so they apply to launches from that entry
|
||||
and are gone with it:
|
||||
|
||||
```sh
|
||||
flatpak run --branch=stable --arch=aarch64 --command=jellyfin-desktop \
|
||||
@@ -60,11 +40,10 @@ flatpak run --branch=stable --arch=aarch64 --command=jellyfin-desktop \
|
||||
--env=SFN_MPV_HWDEC=v4l2m2m-copy,auto-copy org.jellyfin.JellyfinDesktop
|
||||
```
|
||||
|
||||
The exact line with the store path: `grep ^Exec=
|
||||
~/.local/share/applications/org.jellyfin.JellyfinDesktop.desktop`, or the
|
||||
read-only option `steamFrame.jellyfin.hardwareDecoding.command`. In its
|
||||
output: `mpv-hwdec-shim: hwdec "auto-copy" -> "v4l2m2m-copy,auto-copy"`,
|
||||
then mpv's `Using hardware decoding (v4l2m2m-copy)`.
|
||||
(The exact line with the store path is the read-only option
|
||||
`steamFrame.jellyfin.hardwareDecoding.command`.)
|
||||
|
||||
Older versions used a Flatpak override (via nix-flatpak or a Home Manager
|
||||
link); `steam-frame-nix-cleanup` removes their entries from it.
|
||||
link) and a shim copy in `~/.var/app/org.jellyfin.JellyfinDesktop`;
|
||||
`steam-frame-nix-cleanup` removes their entries from the override and the
|
||||
copy.
|
||||
+40
-117
@@ -1,133 +1,56 @@
|
||||
# Keyboard
|
||||
# VR keyboard: how it works
|
||||
|
||||
Keyboard layout of the Steam session, and two patches of Steam's VR
|
||||
keyboard: [extra keys](#extra-keys) and [swipe and suggestions](#swipe-and-suggestions).
|
||||
All options: [options.md#keyboard](options.md#keyboard).
|
||||
|
||||
## Layout
|
||||
|
||||
`keyboard.layout`, `keyboard.variant`.
|
||||
|
||||
**Problem:** gamescope and its Xwayland displays use US unless
|
||||
`XKB_DEFAULT_*` is set; KDE's layout only affects the nested desktop, and
|
||||
`~/.config/environment.d` isn't read on the Frame.
|
||||
|
||||
**Fix:** a drop-in on `gamescope-session.service` setting
|
||||
`XKB_DEFAULT_LAYOUT`/`VARIANT`; applies at the next Steam session start.
|
||||
|
||||
`keyboard.variant` picks a variant of the layout, e.g. for `de`: `null`
|
||||
(standard, with dead keys: `^`, `` ` ``, `´` wait for the next key),
|
||||
`"nodeadkeys"` (those are typed immediately), `"mac"`, `"neo"`, `"e1"`, `"us"`
|
||||
(German letters on a US layout). List them with
|
||||
`localectl list-x11-keymap-variants <layout>`.
|
||||
|
||||
**Remove when** SteamOS applies a layout setting to gamescope.
|
||||
Technical details of the two VR keyboard patches. What they do and how to
|
||||
configure them: README, [extra keys](../README.md#steam-keyboard-patch-keyboardvrextrakeysenable)
|
||||
and [swipe and suggestions](../README.md#vr-keyboard-swipe-and-suggestions-keyboardvr).
|
||||
|
||||
## Extra keys
|
||||
|
||||
`keyboard.vr.extraKeys.enable`.
|
||||
`keyboard.vr.extraKeys.enable`, module `steam-keyboard-patch`.
|
||||
|
||||
**Problem:** Steam's VR keyboard has no Ctrl, Alt or Esc, can't press real
|
||||
keys, and its text emulation only maps plain ASCII: non-ASCII and
|
||||
AltGr/dead-key characters on the German keymap (`| @ { [ ] } \ ~ ^`,
|
||||
backtick, `ä ö ü €`) come out as `1`.
|
||||
|
||||
**What it does:**
|
||||
|
||||
- Bottom row: `Esc Ctrl Alt [Space] AltGr ← ↑ ↓ → Close`, stable with Shift
|
||||
or AltGr.
|
||||
- AltGr + arrows: Home, End, Page Up, Page Down (hinted on the keys);
|
||||
Shift + arrows select text.
|
||||
- AltGr + the key left of Backspace (`´` on German, `=` on US): Delete,
|
||||
labelled like Steam's Delete key in its language (`Entf`; `Del` if that is
|
||||
longer), hinted on the key without AltGr; repeats while held. Layouts with
|
||||
an AltGr character on that key get none.
|
||||
- Layouts without AltGr (US, Dvorak, Colemak, Bulgarian, Chinese, Japanese,
|
||||
Korean) get an `Fn` key right of the space bar: Steam's AltGr toggle
|
||||
(tap: once, tap twice: locked, hold), for Delete and Home/End/Page Up/Down.
|
||||
- The `steam-keyboard-patch` user service (`helper.mjs`) injects a patch
|
||||
into Steam's `SharedJSContext` over DevTools (`127.0.0.1:8080`) and
|
||||
re-injects it after Steam restarts; stopping it (or disabling the option)
|
||||
runs the unpatch, so no reboot or Steam restart is needed.
|
||||
- Ctrl/Alt chords and Esc are sent with `xdotool key` on `:0` (focus follows
|
||||
the VR-selected window); a toggled Ctrl/Alt is held down while the
|
||||
keyboard is open (e.g. Ctrl+scroll).
|
||||
- Problem characters are typed with `xdotool type`; everything else goes
|
||||
through Steam.
|
||||
- Enter always types Return (stock Steam may send it to a Steam search box).
|
||||
the VR-selected window); a toggled Ctrl/Alt is held down with `xdotool`
|
||||
while the keyboard is open.
|
||||
- Problem characters (non-ASCII, AltGr/dead-key characters on the German
|
||||
keymap) are typed with `xdotool type`; everything else goes through
|
||||
Steam's own text emulation. On other keymaps those characters are still
|
||||
typed by xdotool, which is why the routing is harmless there.
|
||||
- The helper's command set is deliberately narrow (see the README's
|
||||
security note): single-key Ctrl/Alt chords, the extra keys, Ctrl/Alt
|
||||
hold/release and single non-ASCII/AltGr characters.
|
||||
|
||||
**Layouts:** the character routing targets the German keymap; on others it
|
||||
is harmless (those characters are typed by xdotool), and Esc/Ctrl/Alt/arrows
|
||||
work regardless.
|
||||
|
||||
**Security:** the helper only accepts single-key Ctrl/Alt chords, the extra
|
||||
keys, Ctrl/Alt hold/release and single non-ASCII/AltGr characters; it cannot
|
||||
type ASCII text or press Enter.
|
||||
|
||||
**How it works:** the `steam-keyboard-patch` user service (`helper.mjs`)
|
||||
injects a patch over DevTools (`127.0.0.1:8080`) and re-injects it after
|
||||
Steam restarts; stopping it (or disabling the option) reverts the patch. No
|
||||
reboot or Steam restart needed.
|
||||
|
||||
**Caveat:** found by signature (see
|
||||
[finders and signatures](ui-patches.md#finders-and-signatures)); if one stops
|
||||
matching, the keyboard stays stock and the journal says why (see
|
||||
[after a Steam update](ui-patches.md#after-a-steam-update)). Tested with
|
||||
Steam client 1790377368 (UI build 11041156).
|
||||
|
||||
**Remove when** Steam's VR keyboard gets these keys.
|
||||
Found by signature (see [finders and signatures](ui-patches.md#finders-and-signatures));
|
||||
if one stops matching, the keyboard stays stock and the journal says why
|
||||
(see [after a Steam update](ui-patches.md#after-a-steam-update)).
|
||||
|
||||
## Swipe and suggestions
|
||||
|
||||
`keyboard.vr.enable`; the sub-features (`swipe`, `autocorrect`,
|
||||
`completions`, `backspaceDrag`, `haptics`) are on by default.
|
||||
`keyboard.vr.*`, module `vr-keyboard`.
|
||||
|
||||
**Problem:** Steam's VR keyboard is tap-only: no swipe typing, no
|
||||
suggestions, and deleting more than a few characters means many Backspace
|
||||
taps.
|
||||
- A Steam UI patch (`vr-keyboard`, injected by `steam-ui-patches` like the
|
||||
other [UI patches](ui-patches.md)).
|
||||
- Swiped words are matched by shape (SHARK2-style template matching)
|
||||
against a dictionary built at build time from wordfreq frequency lists
|
||||
and Hunspell, both from nixpkgs (`dictionary.*`: per language the `words`
|
||||
most frequent wordfreq entries, shifted by `frequencyOffset`, filtered by
|
||||
Hunspell except words at or above `keepFrequentAbove`).
|
||||
- The strip below/above the keyboard is a SteamVR dashboard panel
|
||||
(`panel.js`, a patch of SteamVR's `systemui` page on port 8087, via the
|
||||
[SteamVR debugger](steamvr-debugger.md)), fed by the `vr-keyboard-relay`
|
||||
user service (`relay.mjs`) between the two pages. With `inside` neither
|
||||
the panel nor the relay runs.
|
||||
- With `extraKeys`, non-ASCII words are typed via its xdotool helper.
|
||||
|
||||
**What it does:**
|
||||
|
||||
- **Swipe:** press the trigger on the first letter, sweep over the others,
|
||||
release on the last. The word is typed with a space before it if needed
|
||||
(`text.autoSpace`); alternatives show in the strip. `'` and `-` are typed,
|
||||
not swiped.
|
||||
- **Suggestions** never change text by themselves: a finished tapped word
|
||||
that isn't in the dictionary gets corrections (itself first; `autocorrect`),
|
||||
a word being tapped gets completions (the typed letters first;
|
||||
`completions`). A pick replaces exactly what it typed and can be switched
|
||||
again.
|
||||
- **Backspace drag:** drag Backspace left to delete one character per
|
||||
`pixelsPerChar`, with a detent (`wordDetentPixels`) at each word border
|
||||
and at the start of what the keyboard typed; drag back right to retype.
|
||||
- **Strip** (`suggestions.position`): a SteamVR dashboard panel below or
|
||||
above the keyboard, or inside the keyboard over its number row. Its
|
||||
buttons take the keyboard's key style.
|
||||
- **Haptics:** light ticks for drag steps and picks, a Snap at word detents.
|
||||
|
||||
**Dictionary** (`dictionary.*`): built from wordfreq frequency lists and
|
||||
Hunspell, both from nixpkgs. By default the `keyboard.layout` language (de,
|
||||
fr, es, it, nl, pt, sv) plus English, else English only; add or exclude
|
||||
words and word lists, see [options](options.md#keyboard).
|
||||
|
||||
**Text memory:** the keyboard can't read the text field, so it remembers
|
||||
what it typed itself (`text.bufferChars`); anything it can't follow (Enter,
|
||||
arrows, extraKeys' xdotool keys, another field,
|
||||
`text.resetAfterIdleSeconds`) resets that, and suggestions only replace text
|
||||
the memory proves intact. Works with and without `keyboard.vr.extraKeys`
|
||||
(with it, non-ASCII words are typed via its xdotool helper).
|
||||
|
||||
**Caveats:** found by signature (entries `vr-keyboard`, `vr-keyboard-panel`);
|
||||
if one stops matching the keyboard stays stock. Accented words of other
|
||||
languages are in the dictionary but only swipable where the layout has the
|
||||
letters.
|
||||
|
||||
**How it works:** a Steam UI patch (`vr-keyboard`, injected like the other
|
||||
[UI patches](ui-patches.md)). Words are matched by shape (SHARK2-style
|
||||
template matching). The strip below/above is a patch of SteamVR's
|
||||
`systemui`, with the `vr-keyboard-relay` user service carrying it between
|
||||
the two pages.
|
||||
Found by signature (entries `vr-keyboard`, `vr-keyboard-panel`); if one
|
||||
stops matching the keyboard stays stock.
|
||||
|
||||
**Tests:** `nix flake check` (checks `vr-keyboard`: text model, corrector,
|
||||
decoder accuracy on German + English) and `keyboard.vr.checks` for the
|
||||
configured dictionary. Debugging: `window.__sfuiSwipeLog` and
|
||||
`__sfuiSwipePaths` in Steam's SharedJSContext (replay swipes with
|
||||
`scripts/vr-keyboard-replay.mjs`).
|
||||
configured dictionary.
|
||||
|
||||
**Remove when** Steam's VR keyboard gets swipe typing and suggestions.
|
||||
**Debugging:** `window.__sfuiSwipeLog` and `__sfuiSwipePaths` in Steam's
|
||||
SharedJSContext (replay swipes with `scripts/vr-keyboard-replay.mjs`).
|
||||
+26
-60
@@ -1,78 +1,44 @@
|
||||
# Launcher menu
|
||||
# Launcher menu: how it works
|
||||
|
||||
The VR dashboard's "+" menu (non-Steam programs). Options:
|
||||
[options.md#launcher-menu](options.md#launcher-menu).
|
||||
Technical details of the "+" menu features. What they do and how to
|
||||
configure them: README, [launcher menu](../README.md#launcher-menu-launchermenu),
|
||||
[hidden apps](../README.md#hidden-apps-launchermenuhiddenapps),
|
||||
[icon fallbacks](../README.md#icon-fallbacks-launchermenuiconfallbacks).
|
||||
|
||||
## Menu patches
|
||||
|
||||
`launcherMenu.*`.
|
||||
`launcherMenu.*` (module `launcher-menu`): [UI patches](ui-patches.md) in
|
||||
Steam's `SharedJSContext` (`modules/launcher-menu/`), each registered only
|
||||
when its option is set and reverted by its unpatch when unset (next switch):
|
||||
|
||||
**Problem:** the menu is in random order with "Desktop" somewhere in a
|
||||
scrolling list, and a click shows no feedback until the window appears, so
|
||||
programs often get started twice.
|
||||
- `order/`: sorts `ScanForInstalledNonSteamApps()` by name (Steam lists the
|
||||
programs in GLib hash-table order);
|
||||
- `pinned-desktop/`: hides Desktop in the list and pins a proxy above/below
|
||||
it;
|
||||
- `launch/`: wraps `LaunchNonSteamApp` (menu-only) to close the menu and/or
|
||||
debounce repeated launches;
|
||||
- `grid/`: restyles Steam's own items as tiles, which is why launching,
|
||||
sounds and controller navigation keep working;
|
||||
- `show-all/`: empties the list Steam hides without Developer Mode.
|
||||
|
||||
**What it does:**
|
||||
|
||||
- `sort`: programs sorted by name (case-insensitive), Desktop included.
|
||||
- `pinDesktop = "top"` / `"bottom"`: Desktop pinned above/below the list,
|
||||
always visible.
|
||||
- `closeOnLaunch`: the menu closes on click.
|
||||
- `launchDebounceSeconds = <seconds>`: a repeat launch of the same command
|
||||
within that time is ignored (and logged); a program that exits right away
|
||||
can only be restarted once the time is up.
|
||||
- `grid.enable`: the programs section becomes a grid of tiles (icon, name
|
||||
below); "Add desktop window" stays a list. Only restyles Steam's items, so
|
||||
launching, sounds and controller navigation keep working. The popup is
|
||||
300 px wide, so `grid.columns` sets the tile size (3 ≈ 92 px, 4 ≈ 68 px,
|
||||
5 ≈ 53 px); `grid.maxRows` limits visible rows, the rest scrolls.
|
||||
- `showAllApps`: without Developer Mode Steam hides `konsole`,
|
||||
`systemsettings`, `dolphin`, `plasma-discover`, `vlc`, `firewall-config`,
|
||||
`cmake-gui`, `qrenderdoc`, `lxterminal` and `sh`; this lifts that filter
|
||||
only, so Developer Mode (sshd, xrdp, LAN DevTools forwards) can stay off.
|
||||
Hide single programs with [`hiddenApps`](#hidden-apps).
|
||||
|
||||
**Steam Developer Mode** (a Steam setting, not managed here) also makes the
|
||||
menu list every desktop entry; `showAllApps` does the same without it.
|
||||
|
||||
**Limitation:** the pinned Desktop works with the laser but not with
|
||||
thumbstick / D-pad navigation.
|
||||
|
||||
**How it works:** [UI patches](ui-patches.md) in Steam's `SharedJSContext`.
|
||||
All revert when turned off (next switch). The anchors (APIs, React props,
|
||||
CSS) are verified by the offline checker. Tested with Steam client
|
||||
1790377368.
|
||||
Their anchors (APIs, React props, CSS) are in `modules/lib/signatures.json`
|
||||
and verified by the [offline checker](ui-patches.md#after-a-steam-update).
|
||||
|
||||
## Hidden apps
|
||||
|
||||
`launcherMenu.hiddenApps`: desktop entry ids (no `.desktop`).
|
||||
|
||||
**Problem:** with Developer Mode or `showAllApps`, the "+" menu lists every
|
||||
desktop entry, including system tools.
|
||||
|
||||
**Fix:** a user entry with `Hidden=true` in `~/.local/share/applications`
|
||||
masks the system one (also in the KDE menu). The "+" menu always hides
|
||||
`steam` and `vrurlhandler`; for Konsole in VR use
|
||||
[`showAllApps`](#menu-patches).
|
||||
`launcherMenu.hiddenApps` (module `hidden-apps`): a Home Manager-linked
|
||||
desktop entry with `Hidden=true` per id in `~/.local/share/applications`,
|
||||
which masks the system entry of the same id for Steam and KDE alike.
|
||||
|
||||
## Icon fallbacks
|
||||
|
||||
`launcherMenu.iconFallbacks.enable` (on by default), `iconFallbacks.extra`.
|
||||
|
||||
**Problem:** Steam resolves `Icon=` only in the hicolor theme (and
|
||||
`pixmaps`), so Konsole and KDE System Settings, whose icons only Breeze has,
|
||||
show without icon.
|
||||
|
||||
**Fix:** Home Manager links nixpkgs' Breeze SVGs of `utilities-terminal`
|
||||
and `preferences-system` (plus `extra`) into
|
||||
`~/.local/share/icons/hicolor/scalable/apps/`; a name Breeze doesn't have
|
||||
fails the build, `enable = false` provides none. When the set of links
|
||||
`launcherMenu.iconFallbacks.*`: Home Manager links nixpkgs' Breeze SVGs
|
||||
into `~/.local/share/icons/hicolor/scalable/apps/`. When the set of links
|
||||
changes, the switch bumps the mtime of `~/.local/share/icons/hicolor`, so a
|
||||
running Steam rescans (GTK only rereads a theme whose directory changed).
|
||||
Each switch also prints hints: icons of programs Steam can't find that
|
||||
Breeze has (add them to `extra`), and fallbacks hicolor has anyway.
|
||||
The switch's hints come from `icon-fallbacks.sh`.
|
||||
|
||||
**Migration:** until 2026-09 a script made these links on switch and listed
|
||||
them in `~/.local/state/steam-frame-nix/icon-fallbacks`; the first switch
|
||||
replaces them with Home Manager's and `steam-frame-nix-cleanup` removes the
|
||||
rest. `iconFallbacks` used to be a list; a list now fails with a hint (use
|
||||
`extra`, or `enable = false` for `[ ]`).
|
||||
rest.
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
# Options
|
||||
|
||||
All options live under `steamFrame.*`. The portal fix and clipboard sync
|
||||
are on by default; everything else is opt-in.
|
||||
|
||||
## Session
|
||||
|
||||
Details: [desktop-integration.md](desktop-integration.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.session.runtimeDir` | str | `"/run/user/1000"` | `XDG_RUNTIME_DIR` of the outer (Steam/VR) session. |
|
||||
| `steamFrame.session.bus` | str | `"unix:path=${runtimeDir}/bus"` | Outer session D-Bus (user manager, `kwalletd6`). |
|
||||
| `steamFrame.session.busEnv` | str, read-only | `"env DBUS_SESSION_BUS_ADDRESS=${bus}"` | Prefix for launchers that must use the outer bus. |
|
||||
| `steamFrame.session.services.start` | list of str | `[ ]` | User units started on switch if not running. |
|
||||
| `steamFrame.session.services.restart` | list of str | `[ ]` | User units restarted on every switch. |
|
||||
| `steamFrame.session.services.stop` | list of str | `[ ]` | User units stopped on switch if running (e.g. of a disabled feature). |
|
||||
| `steamFrame.session.portalFix.enable` | bool | `true` | Working portal config (OpenURI) for the Steam session. |
|
||||
|
||||
## Keyboard
|
||||
|
||||
Details: [keyboard.md](keyboard.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.keyboard.layout` | null or str | `null` | XKB layout for the Steam session, e.g. `"de"`; `null`: US. |
|
||||
| `steamFrame.keyboard.variant` | null or str | `null` | XKB variant for the Steam session, e.g. `"nodeadkeys"`; see [Keyboard layout](keyboard.md#layout). |
|
||||
| `steamFrame.keyboard.vr.extraKeys.enable` | bool | `false` | VR keyboard with Esc/Ctrl/Alt, arrows, real chords, AltGr/non-ASCII. |
|
||||
| `steamFrame.keyboard.vr.enable` | bool | `false` | Swipe typing, suggestions and Backspace drag on the VR keyboard; the sub-features below are on by default, see [VR keyboard](keyboard.md#swipe-and-suggestions). |
|
||||
| `steamFrame.keyboard.vr.swipe.enable` | bool | `true` | Swipe typing. |
|
||||
| `steamFrame.keyboard.vr.dictionary.languages` | list of submodules | layout language + English | `{ language; hunspell; words; frequencyOffset; keepFrequentAbove; }`: wordfreq language, `pkgs.hunspellDicts` name (or `null`), most frequent words taken, zipf offset, keep words Hunspell rejects from this zipf on (default `4.0`). Default: the `keyboard.layout` language (de, fr, es, it, nl, pt, sv; 60000) + English (40000, `-0.3`), else English (60000). |
|
||||
| `steamFrame.keyboard.vr.dictionary.contractions` | bool | `true` | Words with apostrophes (`couldn't`, `geht's`), swiped by their letters. |
|
||||
| `steamFrame.keyboard.vr.dictionary.extraWords` | list of str | `[ ]` | Words always included, casing as given. |
|
||||
| `steamFrame.keyboard.vr.dictionary.extraWordsFrequency` | number | `5.0` | Zipf frequency of extra words. |
|
||||
| `steamFrame.keyboard.vr.dictionary.extraWordFiles` | list of paths | `[ ]` | Word lists, `word` or `word<TAB>zipf` per line. |
|
||||
| `steamFrame.keyboard.vr.dictionary.excludeWords` | list of str | `[ ]` | Words never suggested. |
|
||||
| `steamFrame.keyboard.vr.text.bufferChars` | int | `128` | Characters of typed text the keyboard remembers. |
|
||||
| `steamFrame.keyboard.vr.text.resetAfterIdleSeconds` | int | `30` | Forget it after this long without typing (`0`: never). |
|
||||
| `steamFrame.keyboard.vr.text.autoSpace` | bool | `true` | Space before a swiped word after a known non-space character. |
|
||||
| `steamFrame.keyboard.vr.suggestions.position` | `"below"`, `"above"`, `"inside"` | `"above"` | Suggestion strip: SteamVR panel below/above the keyboard, or over its number row. |
|
||||
| `steamFrame.keyboard.vr.suggestions.count` | int | `6` | Suggestions shown. |
|
||||
| `steamFrame.keyboard.vr.autocorrect.enable` | bool | `true` | Correction suggestions for finished tapped words not in the dictionary. |
|
||||
| `steamFrame.keyboard.vr.autocorrect.maxEditDistance` | int | `2` | Largest edit distance (neighbouring keys and swaps count 0.5). |
|
||||
| `steamFrame.keyboard.vr.completions.enable` | bool | `true` | Completions of the tapped word. |
|
||||
| `steamFrame.keyboard.vr.completions.minPrefix` | int | `2` | Letters typed before completions show. |
|
||||
| `steamFrame.keyboard.vr.backspaceDrag.enable` | bool | `true` | Backspace drag: left deletes, back right retypes. |
|
||||
| `steamFrame.keyboard.vr.backspaceDrag.pixelsPerChar` | int | `25` | Travel per character (keyboard px; a key is ~60). |
|
||||
| `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. |
|
||||
|
||||
## UI patches
|
||||
|
||||
Details: [ui-patches.md](ui-patches.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.uiPatches.patches` | list of submodules | `[ ]` | Runtime patches of Steam's web UIs, see [UI patches](ui-patches.md). |
|
||||
| `steamFrame.uiPatches.lib` | attrs, read-only | | Patch helpers (`mkPatch`), see [Finders and signatures](ui-patches.md#mkpatch). |
|
||||
|
||||
## Launcher menu
|
||||
|
||||
Details: [launcher-menu.md](launcher-menu.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `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.closeOnLaunch` | bool | `false` | Close the "+" menu when a program is clicked. |
|
||||
| `steamFrame.launcherMenu.launchDebounceSeconds` | unsigned int (s) | `0` | Ignore repeat launches of a program within this time; `0`: off. |
|
||||
| `steamFrame.launcherMenu.grid.enable` | bool | `false` | Show the "+" menu's programs as a grid of tiles. |
|
||||
| `steamFrame.launcherMenu.grid.columns` | int, 1-8 | `4` | Tiles per row (3 ≈ 92 px, 4 ≈ 68 px, 5 ≈ 53 px). |
|
||||
| `steamFrame.launcherMenu.grid.maxRows` | null or positive int | `null` | Visible rows, the rest scrolls; `null`: up to 600 px. |
|
||||
| `steamFrame.launcherMenu.showAllApps` | bool | `false` | List all programs without Developer Mode, see [Launcher menu](launcher-menu.md#menu-patches). |
|
||||
| `steamFrame.launcherMenu.iconFallbacks.enable` | bool | `true` | Breeze icons of Konsole and KDE System Settings in hicolor, so the "+" menu shows them, see [Icon fallbacks](launcher-menu.md#icon-fallbacks). |
|
||||
| `steamFrame.launcherMenu.iconFallbacks.extra` | list of str | `[ ]` | Further Breeze app icon names to provide (a name Breeze lacks fails the build). |
|
||||
| `steamFrame.launcherMenu.hiddenApps` | list of str | `[ ]` | Desktop entry ids (no `.desktop`) hidden from the "+" and KDE menus. |
|
||||
|
||||
## Dashboard
|
||||
|
||||
Details: [dashboard.md](dashboard.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.dashboard.windows.maxScale` | null or positive number | `null` | Max resize scale of dashboard windows; `null`: stock (2), see [Dashboard windows](dashboard.md#dashboard-windows). |
|
||||
| `steamFrame.dashboard.windows.distance.{world,theater,dashboard}.{min,max}` | null or positive number (m) | `null` | Pull-in / push-back limits of grabbed windows; `null`: stock (world 0.25-5, theater 1-6, dashboard 0.3-4 m). |
|
||||
| `steamFrame.dashboard.steamCloseButton.enable` | bool | `false` | X button on the dashboard's Steam window, see [Steam close button](dashboard.md#steam-close-button). |
|
||||
| `steamFrame.dashboard.windowCurvature.enable` | bool | `false` | Adjustable curvature per window, see [Window curvature](dashboard.md#window-curvature). |
|
||||
| `steamFrame.dashboard.windowCurvature.initial` | non-negative number | `1.0` | Curvature of curved world/hand windows without own value (1 = stock, 0 = flat). |
|
||||
| `steamFrame.dashboard.windowCurvature.max` | positive number | `3.0` | Largest curvature. |
|
||||
| `steamFrame.dashboard.windowCurvature.step` | positive number | `0.05` | Rounding step while dragging (at most `max`). |
|
||||
| `steamFrame.dashboard.windowCurvature.detentPixels` | unsigned int (px) | `24` | Detent at each detent point in drag pixels: the value holds there, then continues (nothing skipped); `0`: none. |
|
||||
| `steamFrame.dashboard.windowCurvature.detentPoints` | list of non-negative numbers | `[ 0 1.0 ]` | Detent points (flat, stock), at most `max`. |
|
||||
| `steamFrame.dashboard.windowCurvature.dragThresholdPixels` | unsigned int (px) | `8` | Vertical travel before a press becomes a drag. |
|
||||
| `steamFrame.dashboard.windowCurvature.dragPixelsPerUnit` | positive number (px) | `120` | Drag distance per 1.0 in the menu (6 px per 0.05 step). |
|
||||
| `steamFrame.dashboard.windowCurvature.barDragPixelsPerUnit` | positive number (px) | `60` | Drag distance per 1.0 on the bar button. |
|
||||
| `steamFrame.dashboard.windowCurvature.haptics` | bool | `true` | Controller haptics while dragging (steps, detents, edges); the dashboard's hover clicks are muted during a drag. |
|
||||
| `steamFrame.dashboard.frameControls.enable` | bool | `false` | Move window controls between bar and three-dot menu, see [Window control bar](dashboard.md#window-control-bar). |
|
||||
| `steamFrame.dashboard.frameControls.longPressMs` | int, 300-10000 (ms) | `1500` | Long-press duration. |
|
||||
| `steamFrame.dashboard.frameControls.inBar` | list of control names | `[ ]` | Controls that start in the bar: `keyboard`, `float`, `dashboard`, `theater`, `dockLeft`, `dockRight`, `close`, `curvature`, `"icon:<n>"`. |
|
||||
| `steamFrame.dashboard.frameControls.inMenu` | list of control names | `[ ]` | Controls that start in the three-dot menu. |
|
||||
| `steamFrame.dashboard.frameControls.floatInTheater` | bool | `false` | "Float" control on theater windows. |
|
||||
|
||||
## SteamVR debugger
|
||||
|
||||
Details: [steamvr-debugger.md](steamvr-debugger.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.steamvrDebugger.enable` | bool | automatic | SteamVR dashboard DevTools on `127.0.0.1:8087` (set only while SteamVR runs); on when a dashboard patch is, see [SteamVR debugger](steamvr-debugger.md). |
|
||||
|
||||
## Clipboard sync
|
||||
|
||||
Details: [desktop-integration.md](desktop-integration.md#clipboard-sync).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.clipboardSync.enable` | bool | `true` | Clipboard bridge between the Steam session and the nested desktop. |
|
||||
| `steamFrame.clipboardSync.package` | package | built from `dnut/clipboard-sync` | The clipboard-sync package. |
|
||||
|
||||
## Firefox
|
||||
|
||||
Details: [firefox.md](firefox.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.firefox.enable` | bool | `false` | Launcher for the Flathub Firefox Flatpak with the fixes below. |
|
||||
| `steamFrame.firefox.vrFullscreenFix` | bool | `true` | Default `full-screen-api.ignore-widgets` to `true` (not in the desktop profile). |
|
||||
| `steamFrame.firefox.disableAv1` | bool | `false` | Default `media.av1.enabled` to `false`: the Frame's decoder driver has no AV1, so sites send VP9/H.264, decoded in hardware. |
|
||||
| `steamFrame.firefox.prefs` | attrs of bool, int or str | `{ }` | Further `about:config` default values for every profile (override the fixes too). |
|
||||
| `steamFrame.firefox.desktopProfile` | null or str | `"desktop"` | Separate profile (directory name) for the nested desktop; `null`: the default profile in both sessions. |
|
||||
|
||||
## Jellyfin
|
||||
|
||||
Details: [jellyfin.md](jellyfin.md).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.jellyfin.hardwareDecoding.enable` | bool | `false` | Hardware video decoding in the Jellyfin Desktop Flatpak, see [Jellyfin](jellyfin.md). |
|
||||
| `steamFrame.jellyfin.hardwareDecoding.hwdec` | str | `"v4l2m2m-copy,auto-copy"` | mpv `hwdec` used instead of Jellyfin's automatic one. |
|
||||
| `steamFrame.jellyfin.hardwareDecoding.command` | str, read-only | | The `flatpak run …` command line of the desktop entry, for a terminal. |
|
||||
|
||||
## Cleanup
|
||||
|
||||
Details: [changes-outside-nix.md](changes-outside-nix.md#cleanup).
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `steamFrame.cleanup.package` | package, read-only | | `steam-frame-nix-cleanup` (on `PATH` too), see [Changes outside Nix](changes-outside-nix.md#cleanup). |
|
||||
|
||||
## Renamed options
|
||||
|
||||
Renamed options still work under their old names, with a warning:
|
||||
|
||||
| Old | New |
|
||||
|---|---|
|
||||
| `keyboardLayout`, `keyboardVariant` | `keyboard.layout`, `keyboard.variant` |
|
||||
| `steamKeyboardPatch.enable` | `keyboard.vr.extraKeys.enable` |
|
||||
| `hiddenApps` | `launcherMenu.hiddenApps` |
|
||||
| `launcherMenu.launchDebounce` | `launcherMenu.launchDebounceSeconds` |
|
||||
| `runtimeDir`, `userBus`, `outerBusEnv` | `session.runtimeDir`, `session.bus`, `session.busEnv` |
|
||||
| `userServices.{start,restart,stop}` | `session.services.{start,restart,stop}` |
|
||||
| `portalFix.enable` | `session.portalFix.enable` |
|
||||
| `dashboard.windowMaxScale` | `dashboard.windows.maxScale` |
|
||||
| `dashboard.windowDistance.*` | `dashboard.windows.distance.*` |
|
||||
| `dashboard.windowCurvature.default` | `dashboard.windowCurvature.initial` |
|
||||
| `dashboard.windowCurvature.snapPixels`, `snapPoints` | `detentPixels`, `detentPoints` |
|
||||
| `dashboard.windowCurvature.dragThreshold` | `dragThresholdPixels` |
|
||||
+21
-21
@@ -1,18 +1,22 @@
|
||||
# SteamVR debugger
|
||||
# SteamVR debugger: how it works
|
||||
|
||||
`steamvrDebugger.enable`, automatic: on when any patch in
|
||||
`steamFrame.uiPatches.patches` uses port 8087 (all [dashboard](dashboard.md)
|
||||
patches and the VR keyboard's strip below/above the keyboard).
|
||||
`steamvrDebugger.enable` (module `steamvr-debugger`). What it is for and
|
||||
what you need to do: README,
|
||||
[SteamVR debugger](../README.md#steamvr-debugger-steamvrdebuggerenable).
|
||||
|
||||
**Problem:** dashboard patches need SteamVR's DevTools port, opened only
|
||||
with `VRWebHelper/DebuggerEnabled` (port `VRWebHelper/DebuggerPort`, default
|
||||
8087). SteamVR rewrites `~/.config/openvr/config/steamvr.vrsettings` from
|
||||
memory, so the key can't be a link and can't be edited while SteamVR runs.
|
||||
Enabled automatically when any patch in `steamFrame.uiPatches.patches` has
|
||||
an `endpoint` on port 8087 (all [dashboard](dashboard.md) patches and the VR
|
||||
keyboard's strip below/above the keyboard).
|
||||
|
||||
**What it does:** sets the key only while SteamVR runs:
|
||||
SteamVR opens its DevTools port only with `VRWebHelper/DebuggerEnabled`
|
||||
(port `VRWebHelper/DebuggerPort`, default 8087). SteamVR rewrites
|
||||
`~/.config/openvr/config/steamvr.vrsettings` from memory, so the key can't
|
||||
be a link and can't be edited while SteamVR runs. It is set only while
|
||||
SteamVR runs:
|
||||
|
||||
- before every SteamVR start, the `steamvr-webhelper-debugger` oneshot
|
||||
(a drop-in on `steamvr.service`) stores the key's value in
|
||||
(a drop-in on `steamvr.service`, running `install.sh steamvr-debugger-arm`)
|
||||
stores the key's value in
|
||||
`~/.local/state/steam-frame-nix/steamvr-debugger.armed`, sets the key
|
||||
(with `jq`) and writes a runtime drop-in,
|
||||
`/run/user/1000/systemd/user/steamvr.service.d/50-steam-frame-nix-debugger.conf`,
|
||||
@@ -22,15 +26,11 @@ memory, so the key can't be a link and can't be edited while SteamVR runs.
|
||||
it wasn't there) and `.armed` is removed.
|
||||
|
||||
The runtime files don't need Nix, so this also works after a rollback or
|
||||
uninstall; they are gone at reboot. A key you set to `true` yourself is
|
||||
never touched. Disabled, there is no unit; the switch restores the key if
|
||||
SteamVR is stopped, otherwise the runtime drop-in does when it stops.
|
||||
uninstall; 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`. A key set to `true` by the user is never touched.
|
||||
Disabled, there is no unit; the switch (cleanup) restores the key if SteamVR
|
||||
is stopped, otherwise the runtime drop-in does when it stops.
|
||||
|
||||
**The first time, restart SteamVR once** (e.g. reboot); until then
|
||||
`steam-ui-patches` keeps polling.
|
||||
|
||||
**Security:** the port listens on `127.0.0.1` only; keep Developer Mode off
|
||||
(see [DevTools on the LAN](ui-patches.md#devtools-on-the-lan)).
|
||||
|
||||
What it writes and when it is removed:
|
||||
[changes outside Nix](changes-outside-nix.md).
|
||||
Until SteamVR has been restarted once with the drop-in, the port is closed
|
||||
and `steam-ui-patches` keeps polling it.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Two sessions
|
||||
|
||||
The Frame runs two graphical sessions at once; most workarounds exist because
|
||||
of their differences:
|
||||
|
||||
| | Steam / VR session | Nested Plasma desktop |
|
||||
|---|---|---|
|
||||
| Compositor | gamescope | KWin (nested, shown as a VR window) |
|
||||
| Displays | X display `:0` (apps show as floating VR windows) | own Wayland + Xwayland `:2` |
|
||||
| D-Bus | the outer session bus, `/run/user/1000/bus` | a private bus |
|
||||
| `XDG_RUNTIME_DIR` | `/run/user/1000` | its own |
|
||||
| systemd user manager | yes | not reachable |
|
||||
|
||||
Consequences:
|
||||
|
||||
- **Wallet:** there should be one `kwalletd6`, on the outer bus; apps started
|
||||
from the desktop would otherwise start a second one whose secrets VR can't
|
||||
see. Prefix launchers' `Exec=` with `steamFrame.session.busEnv`
|
||||
([session settings](desktop-integration.md#session-settings-and-services)).
|
||||
- **User services:** home-manager skips `reloadSystemd` when switching from
|
||||
the desktop terminal, so `steamFrame.session.services` talks to the outer
|
||||
user manager directly.
|
||||
- **Launchers:** the "+" menu only sees `~/.local/share/applications` (not
|
||||
`~/.nix-profile/share`), so entries are written there, shadowing
|
||||
Flatpak/package entries with the same ID.
|
||||
- **Keyboard layout:** KDE's layout only affects the nested desktop
|
||||
([keyboard layout](keyboard.md#layout)).
|
||||
- **Clipboard:** separate per session ([clipboard sync](desktop-integration.md#clipboard-sync)).
|
||||
- **Firefox:** the sessions can't see each other's Firefox, so a second
|
||||
instance stops at the locked profile ([desktop profile](firefox.md#options)).
|
||||
|
||||
Switch (`home-manager switch`) from a terminal **in the nested desktop**, so
|
||||
clipboard-sync restarts with the desktop's environment.
|
||||
+10
-16
@@ -1,7 +1,8 @@
|
||||
# UI patches
|
||||
|
||||
For patch authors, and for fixing patches after a Steam update. Options:
|
||||
[options.md#ui-patches](options.md#ui-patches).
|
||||
For patch authors, and for fixing patches after a Steam update. User-level
|
||||
overview: README, [UI patches](../README.md#ui-patches-uipatchespatches);
|
||||
options `steamFrame.uiPatches.patches` and `steamFrame.uiPatches.lib`.
|
||||
|
||||
Steam's UI and SteamVR's dashboard (`vrwebhelper`) are CEF web pages with a
|
||||
local DevTools port: `127.0.0.1:8080` for Steam (SteamOS passes
|
||||
@@ -9,8 +10,12 @@ local DevTools port: `127.0.0.1:8080` for Steam (SteamOS passes
|
||||
[its debugger](steamvr-debugger.md) is on. The `steam-ui-patches` user
|
||||
service (`injector.mjs`) patches the running pages through them; Steam's
|
||||
files are never modified. The [launcher menu](launcher-menu.md),
|
||||
[dashboard](dashboard.md) and [VR keyboard](keyboard.md#swipe-and-suggestions)
|
||||
features are such patches, and you can add your own.
|
||||
[dashboard](dashboard.md) and [VR keyboard](keyboard.md) features are such
|
||||
patches (the extra keys have their own injector, `steam-keyboard-patch`),
|
||||
and you can add your own.
|
||||
|
||||
Don't expose these ports: see
|
||||
[DevTools on the LAN](../README.md#devtools-on-the-lan).
|
||||
|
||||
**Caveat:** patches depend on Steam UI internals and can break with an
|
||||
update; find modules by signature, not id ([below](#finders-and-signatures)).
|
||||
@@ -66,18 +71,7 @@ Used by the [window control bar](dashboard.md#window-control-bar) and the
|
||||
data, not generated by Nix: it is kept when the patch is disabled or removed
|
||||
(the choices come back when you enable it again) and removed only by
|
||||
`steam-frame-nix-cleanup --all` or `install.sh uninstall`; see
|
||||
[changes outside Nix](changes-outside-nix.md).
|
||||
|
||||
## DevTools on the LAN
|
||||
|
||||
Steam's Developer Mode enables `steam-web-debug-portforward`
|
||||
(`0.0.0.0:8081` → `8080`) and `steamvr-web-debug-portforward`
|
||||
(`0.0.0.0:8088` → `8087`), and firewalld allows ports 1024-65535, so anyone
|
||||
on the network could run code in Steam's UI. No patch needs Developer Mode,
|
||||
so keep it off. If it was on while those units were masked, they may stay
|
||||
enabled: check with
|
||||
`systemctl is-enabled steam-web-debug-portforward steamvr-web-debug-portforward`
|
||||
and `sudo systemctl disable` them.
|
||||
[changes outside Nix](../README.md#changes-outside-nix-exceptions).
|
||||
|
||||
## Finders and signatures
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# trace after a power loss) is resolved by the next start or
|
||||
# steam-frame-nix-cleanup.
|
||||
# Off: no unit and no drop-in; cleanup restores the key once SteamVR is
|
||||
# stopped. Developer Mode forwards the port to 0.0.0.0:8088 (docs/ui-patches.md,
|
||||
# stopped. Developer Mode forwards the port to 0.0.0.0:8088 (README,
|
||||
# "DevTools on the LAN"); our patches use 127.0.0.1 only.
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
|
||||
Reference in new issue
Block a user