# Wallpaper engine: wallpapers on a timer Date: 2026-10-29 ## Goal Change the wallpapers on a timer, from a list per screen picked with a heart in the wallpaper picker. Timer changes recolour the live desktop but leave the boot and login surfaces alone; the user's own picks keep doing everything. ## Lists One plain-text file per screen, one absolute path per line: `~/.config/keystone/wallpapers/h.list` (DP-1) and `v.list` (DP-3). There are no portrait images in the gallery, so a screen's list is the user's choice, not derived from aspect ratio. A path whose file is missing stays in the list and is skipped by the timer. ## Heart Back on every thumbnail in `WallpaperTab.qml`, with the glyphs it had before the companion was removed: outline `\u{F02D5}` on hover, filled `\u{F02D1}` in `Theme.red` when listed. It reads and toggles the list of the screen the picker targets (`Wallpapers.target`, H or V). A toggle writes the file at once. It sits after the pick `MouseArea`, so it takes its own click. ## Engine section A section on the existing Wallpaper page, not a new page: - an on/off switch; - the interval, in minutes; - the two lists with their counts, each entry removable, a missing file dimmed; - a Next button that ticks now. On/off, the interval and the two home wallpapers (below) live in `Prefs`, so they survive a restart. A running engine is running again after a restart. ## Tick A `Timer` in the `Wallpapers` singleton, repeating at the interval while the engine is on. - Each screen with a non-empty list takes the next path from a shuffle bag: the list shuffled, drawn without repeats until empty, then reshuffled, with the path just shown never first in the new round. The bag is not persisted; a restart reshuffles. - Both screens go in one `wallp --set` call, through the same path as Apply, so the burn transition plays. A screen with an empty list is left alone. - A tick while a `wallp` run is in progress is skipped. - A tick does not touch staged picks (`pendingH`, `pendingV`). - The call runs with `UDT_ROTATION=1` in its environment (light run, below). ## Manual picks and the home wallpaper A manual Apply is always the full run, engine on or off. Each screen has a home wallpaper, kept in `Prefs`: - switching the engine on sets each home to what that screen shows; - a manual Apply while the engine is on sets the home of each screen it applied, and restarts the timer, so the pick stays up a full interval; - switching the engine off sets each screen whose current wallpaper differs from its home back to the home, in one full `wallp --set`. Both equal, or a home whose file is gone, changes nothing. The shuffle continues where it was after a manual pick. ## Light run: udt-accent In `unified-desktop-theme/bin/udt-accent`: with `UDT_ROTATION` set and non-empty, skip `write_grub`, `write_homepage` and `write_sddm`, and do not start the `udt-grub` and `udt-homepage` helpers. Everything else runs: the accent, Hyprland borders, hyprlock, QML palette, Sublime, colors.json, Firefox, conky, and the keyboard, LED strip, bulb and TV helpers. `wallp` needs no change: it runs `udt-accent` as a child, which inherits the variable. ## Conky, separately Conky reloads `conky.conf` in place on an accent change, recreating its window, and the `dash-workspace` rule in hypr-theme's `sections/dashboard.lua` then sends the new window to `special:dash` without `silent`, which shows the special workspace. The rule becomes `workspace = WS .. " silent"`. To be confirmed by eye on the next accent change. ## Checks - A runnable check for the shuffle bag, in a `.js` file beside it: no repeat within a round, a refill after the last, and the last path never first in the next round (a one-item list excepted). - A check in `udt-accent`'s selftest that the three writes and two helpers are skipped with `UDT_ROTATION=1`, against temporary paths. - By eye: heart, engine section, a tick with the burn, switching off returning home, conky staying hidden. ## Out of scope Sequential order, per-screen intervals, persisting the shuffle, rotation from a terminal `wallp` without the desktop shell. ## Changes during implementation - The lists live in `Prefs` (`wallEngine` in `desktop.json`), not in `~/.config/keystone/wallpapers/*.list`: a list can be empty, and an empty `FileView` write writes nothing. - The engine has a page of its own in the Appearance group rather than a section on the Wallpaper page, so the picker keeps its height. - Each screen can draw from one gallery folder instead of its hearts (`folderH`, `folderV`), asked for once the gallery turned out to hold only wide images. - The page commits like the other settings pages: interval and sources are a draft, and the header has Reset, Stop and Start (Apply while running) in place of an on/off switch. Start changes the wallpapers at once. - `Wallpapers.run()` holds wallp until the burn's covers are drawing, which removed a flash of the new picture before the burn.