aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-29 13:08:06 +0100
committerDanilo M. <danix@danix.xyz>2026-10-29 13:08:06 +0100
commit66f8c77b853bb67166aac8ca9c3b31abe6468426 (patch)
tree670dcce6dc7e3627320fde57784c36f58dc8ec4c
parent55d00cc44fcb3ae89d3ad27a236fa30f167d80a2 (diff)
downloadunified-desktop-theme-66f8c77b853bb67166aac8ca9c3b31abe6468426.tar.gz
unified-desktop-theme-66f8c77b853bb67166aac8ca9c3b31abe6468426.zip
accent: UDT_ROTATION, a light run for timed wallpaper changes
The wallpaper engine changes wallpapers on a timer and runs wallp, which runs udt-accent. Nobody sees GRUB, the homepage or SDDM mid-session, and GRUB costs a rebuild and the homepage an scp on every change. With UDT_ROTATION set and non-empty, write_sddm, write_grub, write_homepage and the udt-grub and udt-homepage helpers are skipped; everything else still runs. A manual change is a full run and brings them level. The selftest swaps every writer and both subprocess calls for recorders and checks the exact set of calls with the variable empty and set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--AGENTS.md3
-rwxr-xr-xbin/udt-accent63
2 files changed, 63 insertions, 3 deletions
diff --git a/AGENTS.md b/AGENTS.md
index f30ea9d..c25f2db 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -221,6 +221,9 @@ pasting into a root shell.
One colour moves: `@accent`. `bin/udt-accent` reads the current wallpaper,
extracts its signature colour, and snaps it to the nearest of ten Catppuccin
accents by perceptual hue in CIELAB. `wallp` calls it on every wallpaper change.
+With `UDT_ROTATION` set and non-empty (keystone's wallpaper engine, on its timer
+changes), GRUB, the homepage and SDDM are skipped, and `udt-grub` and
+`udt-homepage` do not start; a manual change is a full run.
It writes ten things: `~/.cache/udt/udt-accent.rasi` (rofi),
`~/.cache/udt/udt-border.lua` (Hyprland), `~/.cache/udt/hyprlock-border.conf`
diff --git a/bin/udt-accent b/bin/udt-accent
index aabbdec..cfca6ac 100755
--- a/bin/udt-accent
+++ b/bin/udt-accent
@@ -9,6 +9,9 @@ Usage: udt-accent [--no-helpers] <wallpaper-path>
udt-accent --selftest
udt-accent --help
+With UDT_ROTATION set and non-empty (keystone's wallpaper engine), GRUB, the
+homepage and SDDM are left alone, and udt-grub and udt-homepage do not start.
+
The extraction reads the image's pixels itself rather than running `wal -i`,
because `wal -i` rewrites the whole ~/.cache/wal directory (which this no
longer writes to, but pywal still would) including the terminal's ANSI colors.
@@ -624,7 +627,15 @@ def write_sddm(name, image):
mode=0o644, dir_mode=0o755)
+# Set by keystone's wallpaper engine on its timer changes. They recolour the
+# live desktop and leave the boot and login surfaces alone: nobody sees GRUB,
+# the homepage or SDDM mid-session, and GRUB costs a rebuild and the homepage
+# an scp on every change. A manual change is a full run and brings them level.
+LIGHT_SKIPS_HELPERS = ("udt-homepage", "udt-grub")
+
+
def main(image, helpers=True):
+ light = bool(os.environ.get("UDT_ROTATION"))
try:
color = signature_color(image)
name = snap(color) if color else FALLBACK
@@ -638,12 +649,14 @@ def main(image, helpers=True):
write_hyprlock_border(name)
write_qml(name)
write_sublime(name)
- write_sddm(name, image)
+ if not light:
+ write_sddm(name, image)
write_colors_json(name, image)
write_firefox(image)
# Before the helpers below start, which build and stage these two.
- write_grub(name)
- write_homepage(name)
+ if not light:
+ write_grub(name)
+ write_homepage(name)
write_conky(name)
# Hyprland only rereads its config on request, and may not be running.
@@ -659,6 +672,8 @@ def main(image, helpers=True):
# udt-tv is a single UDP datagram to the TV launcher.
# --no-helpers is install.sh's: it runs each of them as a consumer itself.
for helper in ("udt-homepage", "udt-grub", "udt-keyboard", "udt-ledstrip", "udt-bulb", "udt-tv") if helpers else ():
+ if light and helper in LIGHT_SKIPS_HELPERS:
+ continue
subprocess.Popen([Path(__file__).resolve().parent / helper],
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, start_new_session=True)
@@ -913,6 +928,48 @@ def selftest():
finally:
os.environ["HOME"] = home
+ # UDT_ROTATION is the wallpaper engine's light run: GRUB, the homepage and
+ # SDDM and their helpers are skipped, everything else still runs. Every
+ # writer and both process calls are swapped for recorders, so nothing on
+ # disk is touched and no helper starts.
+ every = ("write_accent", "write_border", "write_hyprlock_border",
+ "write_qml", "write_sublime", "write_sddm", "write_colors_json",
+ "write_firefox", "write_grub", "write_homepage", "write_conky")
+ helpers = {"udt-homepage", "udt-grub", "udt-keyboard", "udt-ledstrip",
+ "udt-bulb", "udt-tv"}
+ calls = []
+
+ class FakeSubprocess:
+ DEVNULL = None
+
+ @staticmethod
+ def run(*a, **k):
+ pass
+
+ @staticmethod
+ def Popen(cmd, **k):
+ calls.append(Path(cmd[0]).name)
+
+ saved, saved_env = dict(globals()), os.environ.get("UDT_ROTATION")
+ try:
+ for fn in every:
+ globals()[fn] = (lambda n: lambda *a: calls.append(n))(fn)
+ globals()["signature_color"] = lambda image: None
+ globals()["subprocess"] = FakeSubprocess
+ skipped = {"write_sddm", "write_grub", "write_homepage",
+ "udt-grub", "udt-homepage"}
+ for env, want in (("", set(every) | helpers),
+ ("1", (set(every) | helpers) - skipped)):
+ calls.clear()
+ os.environ["UDT_ROTATION"] = env
+ main("unused.png")
+ assert set(calls) == want, (env, sorted(set(calls) ^ want))
+ finally:
+ globals().update(saved)
+ if saved_env is None:
+ os.environ.pop("UDT_ROTATION", None)
+ else:
+ os.environ["UDT_ROTATION"] = saved_env
print("selftest OK")