aboutsummaryrefslogtreecommitdiffstats
path: root/desktop
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-29 17:20:28 +0100
committerDanilo M. <danix@danix.xyz>2026-10-29 17:20:28 +0100
commitafa0e6e7402ba19688348ab1c41b30bdf14d2d49 (patch)
tree545a3bae8a870a3ed5b90c5e509a914f0f9ab138 /desktop
parent6b875524f57d7bbbe4e7c6b6554a4aa929eef567 (diff)
downloadquickshell-afa0e6e7402ba19688348ab1c41b30bdf14d2d49.tar.gz
quickshell-afa0e6e7402ba19688348ab1c41b30bdf14d2d49.zip
docs: the wallpaper engine and the burn
The appearance README gains the burn (the cover, the covered() handshake and why, the shader cache trap) and the engine (sources, shuffle, light run, homes, the draft page, where its state lives and what starts it). The spec records what changed while building it: Prefs instead of list files, a page of its own, folder sources, the header buttons, the cover handshake. AGENTS.md gains the Field.edited trap, which applies to every page with a field and a button: a click does not end editing, so the value a button acts on must be read on every change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop')
-rw-r--r--desktop/modules/appearance/README.md54
1 files changed, 51 insertions, 3 deletions
diff --git a/desktop/modules/appearance/README.md b/desktop/modules/appearance/README.md
index 65132c3..f933ac0 100644
--- a/desktop/modules/appearance/README.md
+++ b/desktop/modules/appearance/README.md
@@ -1,12 +1,12 @@
# appearance
-Six pages of the settings window: Wallpaper, Theme, Theme status, Icons &
-cursor, HyprSunset and HyprIdle. Until October 2026 they were the tabs of a separate `appearance/`
+Seven pages of the settings window: Wallpaper, Wallpaper engine, Theme,
+Theme status, Icons & cursor, HyprSunset and HyprIdle. Until October 2026 they were the tabs of a separate `appearance/`
shell with an overlay of its own; they moved into the desktop process when
the settings window gave them the room that shell existed to provide.
Each page is a `*Module.qml` here wrapping a `*Tab.qml`, and the work is done
-by singletons (`Wallpapers`, `Udt`, `Icons`, `Hyprsunset`, `Hypridle`,
+by singletons (`Wallpapers`, `WallEngine`, `Udt`, `Icons`, `Hyprsunset`, `Hypridle`,
`Steps`). The window's open calls each module's `refresh()`, which rescans:
schemes, wallpapers and themes can all change during a session, and a scan
done only at startup would go stale.
@@ -126,6 +126,54 @@ which screen is targeted. Their proportions come from the pane **width**, not
its height. Scaling the stand off height gave the wide monitor a 20px stand
that was invisible and would have given the vertical one an absurd long neck.
+### The burn
+
+Apply, and every engine change, burns the old picture away over the new
+one (`WallpaperSpread.qml`, `burn.frag`). swaybg has no transitions, and
+wallp kills one and starts another, so a surface on the bottom layer of each
+screen, above swaybg and below every window, holds the old picture over the
+swap. `Wallpapers.run()` emits `swapping`, then waits for each cover to call
+`covered()` (both its pictures decoded, then 50ms for a few frames) before
+it starts wallp, with a 1.5s fallback for a cover that never comes. Started
+any earlier, the new picture showed through for a moment before the burn.
+The images stay hidden until both are decoded for the same reason: the new
+one usually lands first. A set from a terminal gets no burn. After editing
+`burn.frag`, recompile with `qsb --qt6 -o burn.frag.qsb burn.frag` under a
+new name or restart the shell: a running shell keeps a shader by URL.
+
+## Wallpaper engine
+
+Both wallpapers on a timer (`WallEngine.qml`). Each screen draws from its
+hearted list, toggled with the heart on a thumbnail for the screen the
+picker targets, or from one gallery folder picked on the engine's page. The
+order is a shuffle bag (`Shuffle.js`, `node desktop/modules/appearance/test_shuffle.js`):
+every image once per round, never the same twice running.
+
+Timer changes are the light run: `Wallpapers.run(h, v, "tick")` runs wallp
+with `UDT_ROTATION=1`, which udt-accent reads to skip GRUB, the homepage and
+SDDM and not start `udt-grub` and `udt-homepage`. The rest of the theme,
+lights and keyboard included, follows each change. A manual Apply is always
+the full run.
+
+Each screen has a home: what it showed when the engine started, then each
+manual Apply. Stop puts the homes back with a full run, so the boot and login
+surfaces match the desktop again. A Stop during a run waits for that run.
+
+The page commits like the other settings pages: the interval and the sources
+are a draft, and the header carries the state with Reset, Stop and Start
+(Apply while running). Start changes the wallpapers at once; the first timer
+change would otherwise be a whole interval away. The minutes field updates
+the draft on every keystroke, because `Field.edited` waits for Enter or a
+focus change and clicking Start takes neither. Hearts are not drafted.
+
+State is `wallEngine` in `$XDG_STATE_HOME/keystone/desktop.json`: `on`,
+`minutes`, `h` and `v` (the hearts), `folderH` and `folderV` (a
+`Wallpapers.groups` key, "" for the hearts), `homeH` and `homeV`. In Prefs
+rather than in list files because a list can be empty, and an empty
+`FileView` write writes nothing. The engine runs from the start of the
+session because `WallEngineModule` references it: a singleton is built on
+first use.
+
## Themes
Each scheme shows its real colours, parsed from the pair of files