diff --git a/README.md b/README.md index 89ba36e..691c9c5 100644 --- a/README.md +++ b/README.md @@ -330,8 +330,10 @@ binding `window.__sfuiStoreSave`; the service writes the file atomically, only on change, only for that page's `state` patches, at most 64 KiB. Used by the [window control bar](#window-control-bar-dashboardframecontrols) and the [Steam close button](#steam-close-button-dashboardsteamclosebuttonenable). -The file is user data, not generated by Nix; see -[Changes outside Nix](#changes-outside-nix). +The file is user 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). **DevTools on the LAN:** Steam's Developer Mode enables `steam-web-debug-portforward` (`0.0.0.0:8081` → `8080`) and @@ -764,8 +766,7 @@ controller), and theater windows have no "Float". 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-uipatchespatches); version 4 kept them in - localStorage, which SteamVR wipes on every start, and is migrated once). + [persistent state](#ui-patches-uipatchespatches)). - `inBar` / `inMenu` set where controls start; a popup choice wins until that control's entry changes. - `floatInTheater` gives theater windows the "Float" control. @@ -930,7 +931,7 @@ the feature off: | Path | What, why | Cleanup | |---|---|---| -| `~/.local/state/steam-frame-nix/ui-patches/.json` | Choices made in the dashboard: window control bar placements (`frame-controls.json`), "Steam hidden" (`steam-close-button.json`). Written by `steam-ui-patches` because SteamOS's `steamvr.service` deletes `~/.cache/SteamVR` (the dashboard's own browser storage) on every SteamVR start. Kept when a feature is disabled (your choices come back when you re-enable it). | `rm -rf ~/.local/state/steam-frame-nix/ui-patches` (also done by `install.sh uninstall`) | +| `~/.local/state/steam-frame-nix/ui-patches/.json` | Choices made in the dashboard: window control bar placements (`frame-controls.json`), "Steam hidden" (`steam-close-button.json`). Written by `steam-ui-patches` because SteamOS's `steamvr.service` deletes `~/.cache/SteamVR` (the dashboard's own browser storage) on every SteamVR start. Kept when a feature is disabled (your choices come back when you re-enable it). | `steam-frame-nix-cleanup --all` (also run by `install.sh uninstall`) | ## Rollback diff --git a/modules/frame-controls/patch.js b/modules/frame-controls/patch.js index 019caf0..8574770 100644 --- a/modules/frame-controls/patch.js +++ b/modules/frame-controls/patch.js @@ -30,8 +30,7 @@ // ~/.local/state/steam-frame-nix/ui-patches/frame-controls.json), which // seeds a fresh page (SteamVR restart, reboot, reload). localStorage can't // do that: steamvr.service deletes ~/.cache/SteamVR (vrwebhelper's profile) -// on every start. Version 4's localStorage copy is read once as a fallback -// (migration) and removed once the file has the state. +// on every start (which also took version 4's localStorage copy with it). // // Long press: the dashboard only gets primary-button laser input (no right // click; thumbstick click arrives as nothing). Holding changes nothing; the @@ -69,9 +68,8 @@ // setPlacement(name or "icon:N", 'bar' | 'menu' | null), reset(). ((find, sigs, opts) => { const NAME = 'frame-controls'; - const VERSION = 5; + const VERSION = 6; const T_SPACER = 1, T_ACTION = 2; - const LS_KEY = 'sfui.frameControls.v1'; // version <= 4 (migration only) // Action icon enums (sigs.controls anchors them): names for the options. const NAMES = { keyboard: 22, float: 26, dashboard: 27, theater: 28, dockLeft: 29, dockRight: 30, close: 31, curvature: 40 }; const ICON = { more: 38, float: 26, dashboard: 27 }; @@ -118,13 +116,9 @@ const store = window.__sfuiStore; // injector's persistent store (absent: in-page only) let S = window.__sfuiFrameControlsState, restored = null; if (S?.schema !== 1) { - let saved = store?.get(NAME), from = 'file'; - if (saved?.schema !== 1) { - from = 'localStorage'; - try { saved = JSON.parse(localStorage.getItem(LS_KEY) ?? 'null'); } catch { saved = null; } - } + const saved = store?.get(NAME); const ok = saved?.schema === 1 && saved.placement && typeof saved.placement === 'object'; - restored = ok ? from : 'nothing'; + restored = ok ? 'file' : 'nothing'; S = window.__sfuiFrameControlsState = { schema: 1, placement: ok ? { ...saved.placement } : {}, nixSeen: ok ? { ...saved.nixSeen } : {}, log: [] }; } const logBuf = S.log ??= []; @@ -136,7 +130,6 @@ let unsaved = true; // last save not sent (no injector binding): retried by check() const save = () => { unsaved = !store?.set?.(NAME, { schema: 1, placement: { ...S.placement }, nixSeen: { ...S.nixSeen } }); - if (!unsaved) { try { localStorage.removeItem(LS_KEY); } catch { /* none */ } } }; for (const k of new Set([...Object.keys(optMap), ...Object.keys(S.nixSeen)])) { if (S.nixSeen[k] !== optMap[k] && k in S.placement) { diff --git a/modules/steam-ui-patches.nix b/modules/steam-ui-patches.nix index 8408013..5f8be44 100644 --- a/modules/steam-ui-patches.nix +++ b/modules/steam-ui-patches.nix @@ -6,7 +6,9 @@ # It exists while `patches` is non-empty, restarts on every switch (the old # instance reverts removed patches) and is stopped once the list is empty. # Patches with `state = true` get a persistent JSON value (injector.mjs: -# "Persistent state"). Patch calling convention (mkPatch): lib/default.nix. +# "Persistent state"), kept when the patch goes and removed by +# steam-frame-nix-cleanup --all. Patch calling convention (mkPatch): +# lib/default.nix. { config, pkgs, lib, ... }: let cfg = config.steamFrame.uiPatches; @@ -73,7 +75,10 @@ let 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 user data and stays when the patch is removed. + 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`). ''; }; }; diff --git a/modules/steam-ui-patches/injector.mjs b/modules/steam-ui-patches/injector.mjs index 9f1a380..9daab8e 100644 --- a/modules/steam-ui-patches/injector.mjs +++ b/modules/steam-ui-patches/injector.mjs @@ -34,7 +34,9 @@ // authoritative from then on. set() goes through the CDP binding // window.__sfuiStoreSave('{"name","value"}'), which this process writes to the // file (atomically, only on change, only for "state" patches of that target, -// at most 64 KiB). The file is user data: nothing deletes it. +// at most 64 KiB). The file is user data: kept when the patch is disabled or +// removed, deleted only by steam-frame-nix-cleanup --all (install.sh +// uninstall). import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'; import { join } from 'node:path';