aboutsummaryrefslogtreecommitdiffstats
path: root/deckit
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-09 19:43:48 +0100
committerDanilo M. <danix@danix.xyz>2026-11-09 19:43:48 +0100
commitfd9d6dafd12348e7ecd0aab216dfeda1fe13a088 (patch)
tree737877d6057d7ed08e85ee0ca64846afb728f9e5 /deckit
parent05b01ce3ec09302fe1a47ff71540c91a92d1cab6 (diff)
downloaddeck-it-fd9d6dafd12348e7ecd0aab216dfeda1fe13a088.tar.gz
deck-it-fd9d6dafd12348e7ecd0aab216dfeda1fe13a088.zip
feat: paint the virtual monitor with the first monitor's swaybg wallpaper
Diffstat (limited to 'deckit')
-rw-r--r--deckit/display.py55
1 files changed, 48 insertions, 7 deletions
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}")