aboutsummaryrefslogtreecommitdiffstats
path: root/bin/udt-accent
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-07 09:48:15 +0200
committerDanilo M. <danix@danix.xyz>2026-10-07 09:48:15 +0200
commit205633a064a560c84989d50cb92237d9173e4d6a (patch)
tree157de2c3b024d0559c3b4a04d5fc4af84d508ecb /bin/udt-accent
parent2d6bc39e822bd691e1393f7ae8af7098b56d658d (diff)
downloadunified-desktop-theme-205633a064a560c84989d50cb92237d9173e4d6a.tar.gz
unified-desktop-theme-205633a064a560c84989d50cb92237d9173e4d6a.zip
feat(accent): hand SDDM each screen's wallpaper
Write background_<output>= into the SDDM theme config for every screen wallp manages, read from wallp.conf's OUTPUT_H/OUTPUT_V and the saved wall_h/wall_v. The greeter shows each monitor its own wallpaper instead of the horizontal one on both. Missing wallp state writes no keys, so the greeter falls back to the shared background. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'bin/udt-accent')
-rwxr-xr-xbin/udt-accent53
1 files changed, 51 insertions, 2 deletions
diff --git a/bin/udt-accent b/bin/udt-accent
index 2dfc9a0..17a225d 100755
--- a/bin/udt-accent
+++ b/bin/udt-accent
@@ -99,6 +99,11 @@ POWER_ICONS = {
# The sddm user reaches it through the 0711 home, so it has to stay 0644.
AVATAR = Path.home() / ".user-icon.jpg"
+# wallp's config and state: which output each logical screen (H, V) is, and
+# the wallpaper on it. Read so the greeter can show each monitor its own
+# wallpaper, as the desktop does.
+WALLP = Path.home() / ".config" / "wallp"
+
def write_atomic(path, content, mode=None, dir_mode=None):
"""Write a file atomically, so no reader ever sees it half-written.
@@ -502,7 +507,32 @@ def power_icons():
return {key: find_icon(theme, names) for key, names in POWER_ICONS.items()}
-def sddm_conf(palette, name, image, icons=None, avatar=""):
+def screen_wallpapers(conf=WALLP):
+ """Each output's wallpaper, {output: path}, from wallp's conf and state.
+
+ Empty when wallp is not set up; a screen with no saved wallpaper is left
+ out. Either way the greeter falls back to `background` for that screen.
+ """
+ outputs = {}
+ try:
+ for line in (conf / "wallp.conf").read_text().splitlines():
+ key, _, val = line.partition("=")
+ if key in ("OUTPUT_H", "OUTPUT_V") and val:
+ outputs[key[-1]] = val
+ except OSError:
+ return {}
+ walls = {}
+ for side, output in outputs.items():
+ try:
+ path = (conf / f"wall_{side.lower()}").read_text().strip()
+ except OSError:
+ continue
+ if path:
+ walls[output] = os.path.realpath(path)
+ return walls
+
+
+def sddm_conf(palette, name, image, icons=None, avatar="", walls=None):
"""The SDDM theme config, as an INI fragment.
theme.conf.user overrides theme.conf and is exposed to the theme as the
@@ -516,6 +546,9 @@ def sddm_conf(palette, name, image, icons=None, avatar=""):
f"background={os.path.realpath(image)}",
f"accent={ACCENTS[name]}",
]
+ # Per-screen wallpapers, keyed by output name. The greeter prefers these
+ # over `background` on the screen they name.
+ lines += [f"background_{out}={path}" for out, path in (walls or {}).items()]
lines += [f"{key}={palette.get(key, '#000000')}" for key in SDDM_KEYS]
icons = icons or {}
lines += [f"{key}={icons.get(key, '')}" for key in POWER_ICONS]
@@ -539,7 +572,8 @@ def write_sddm(name, image):
file=sys.stderr)
return
write_atomic(SDDM_OUTPUT, sddm_conf(palette, name, image, power_icons(),
- str(AVATAR) if AVATAR.is_file() else ""),
+ str(AVATAR) if AVATAR.is_file() else "",
+ screen_wallpapers()),
mode=0o644, dir_mode=0o755)
@@ -780,6 +814,21 @@ def selftest():
assert "\navatar=/tmp/me.jpg\n" in "\n" + text
assert f"\navatarUser={getpass.getuser()}\n" in "\n" + text
+ # Per-screen wallpapers come from wallp's output names and saved state; a
+ # screen with no saved wallpaper is left out, and no wallp at all gives none.
+ with tempfile.TemporaryDirectory() as tmpdir:
+ conf = Path(tmpdir)
+ assert screen_wallpapers(conf) == {}
+ (conf / "wallp.conf").write_text("# c\nOUTPUT_H=DP-1\nOUTPUT_V=DP-3\nDEFAULT_H=~/x\n")
+ (conf / "wall_h").write_text("/tmp/h.jpg\n")
+ assert screen_wallpapers(conf) == {"DP-1": "/tmp/h.jpg"}
+ (conf / "wall_v").write_text("/tmp/v.png\n")
+ walls = screen_wallpapers(conf)
+ assert walls == {"DP-1": "/tmp/h.jpg", "DP-3": "/tmp/v.png"}, walls
+ text = sddm_conf({}, FALLBACK, "/tmp/h.jpg", walls=walls)
+ assert "\nbackground_DP-1=/tmp/h.jpg\n" in text
+ assert "\nbackground_DP-3=/tmp/v.png\n" in text
+
got = power_icons()
assert set(got) == {"powerIcon", "rebootIcon", "suspendIcon", "hibernateIcon"}