From fd9d6dafd12348e7ecd0aab216dfeda1fe13a088 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 9 Nov 2026 19:43:48 +0100 Subject: feat: paint the virtual monitor with the first monitor's swaybg wallpaper --- deckit/display.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'deckit') diff --git a/deckit/display.py b/deckit/display.py index f4d85f4..50fa3f6 100644 --- a/deckit/display.py +++ b/deckit/display.py @@ -1,8 +1,10 @@ """The virtual monitor half: a headless Hyprland output sized to the tablet.""" import json +import os import re import shutil +import signal import subprocess import sys import time @@ -35,8 +37,35 @@ def hypr_lua(cfg: dict) -> bool: return mode == "lua" -def setup_display(cfg: dict, run_cmd=None) -> None: +def _swaybg_for(output: str, proc: Path = Path("/proc")): + """(pid, image, mode) of the swaybg process painting `output`, from /proc.""" + for cmdline in proc.glob("[0-9]*/cmdline"): + try: + argv = cmdline.read_bytes().decode(errors="replace").split("\0") + except OSError: + continue + if not argv or not argv[0].endswith("swaybg"): + continue + out = image = None + mode = "fill" + for i, arg in enumerate(argv): + if i + 1 >= len(argv): + break + if arg == "-o": + out = argv[i + 1] + elif arg == "-i": + image = argv[i + 1] + elif arg == "-m": + mode = argv[i + 1] + if out == output and image: + return int(cmdline.parent.name), image, mode + return None + + +def setup_display(cfg: dict, run_cmd=None, popen=None) -> None: run_cmd = run_cmd or run + popen = popen or (lambda cmd: subprocess.Popen( + cmd, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)) d = cfg.get("display", {}) mon = d.get("name", "TAB") monitors = json.loads(run_cmd(["hyprctl", "monitors", "-j"]) or "[]") @@ -51,11 +80,23 @@ def setup_display(cfg: dict, run_cmd=None) -> None: f'hl.monitor({{output="{mon}", mode="{mode}", position="{pos}", scale={scale}}})']) else: run_cmd(["hyprctl", "keyword", "monitor", f"{mon},{mode},{pos},{scale}"]) - tool = shutil.which("awww") or shutil.which("swww") - if d.get("wallpaper", True) and tool: + if d.get("wallpaper", True): others = [m["name"] for m in monitors if m["name"] != mon] - for line in run_cmd([tool, "query"]).splitlines(): - if others and others[0] in line and "image: " in line: - run_cmd([tool, "img", "-o", mon, line.split("image: ", 1)[1]], timeout=10) - break + tool = shutil.which("awww") or shutil.which("swww") + if tool: + for line in run_cmd([tool, "query"]).splitlines(): + if others and others[0] in line and "image: " in line: + run_cmd([tool, "img", "-o", mon, line.split("image: ", 1)[1]], timeout=10) + break + elif shutil.which("swaybg"): + # swaybg runs one process per output; copy the first monitor's image. + source = next((found for name in others if (found := _swaybg_for(name))), None) + if source: + existing = _swaybg_for(mon) + if existing: + try: + os.kill(existing[0], signal.SIGTERM) + except OSError: + pass + popen(["swaybg", "-o", mon, "-i", source[1], "-m", source[2]]) print(f"{mon}: {mode} at {pos}") -- cgit v1.2.3