mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-12 18:10:56 +01:00
Six text-free styles (gradient, flow/Voronoi, habit heatmap, shutdown clock, Earth day/night, plasma) replace the white i3 root. A 15-minute systemd user timer picks a new random style per monitor every 3 hours, unlike its previous one and the other monitor's; live styles refresh in between. Also syncs i3/config with the live config and prunes the oldest evidence artifact for the 60-file cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWX51FMD58yKUC1eYWf
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""Compose per-monitor images into one root image and hand it to feh."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from typing import TYPE_CHECKING, cast
|
|
|
|
from PIL import Image
|
|
|
|
from python_pkg.wallpaper_rotator import _palette
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Mapping, Sequence
|
|
from pathlib import Path
|
|
|
|
Rect = tuple[int, int, int, int]
|
|
|
|
|
|
def layout(outputs: Sequence[Mapping[str, object]]) -> dict[str, Rect]:
|
|
"""Map each active output from ``i3-msg -t get_outputs`` to (x, y, w, h)."""
|
|
rects: dict[str, Rect] = {}
|
|
for output in outputs:
|
|
if not output.get("active"):
|
|
continue
|
|
rect = cast("Mapping[str, int]", output["rect"])
|
|
rects[str(output["name"])] = (
|
|
rect["x"],
|
|
rect["y"],
|
|
rect["width"],
|
|
rect["height"],
|
|
)
|
|
return rects
|
|
|
|
|
|
def compose(
|
|
rects: Mapping[str, Rect], images: Mapping[str, Image.Image]
|
|
) -> Image.Image:
|
|
"""Paste each output's image at its position on one root-sized canvas."""
|
|
width = max((x + w for x, _, w, _ in rects.values()), default=1)
|
|
height = max((y + h for _, y, _, h in rects.values()), default=1)
|
|
root = Image.new("RGB", (width, height), _palette.DEEP)
|
|
for name, (x, y, _, _) in rects.items():
|
|
if name in images:
|
|
root.paste(images[name], (x, y))
|
|
return root
|
|
|
|
|
|
def apply(root: Image.Image, target: Path) -> None:
|
|
"""Write the root image and set it as the X background with feh.
|
|
|
|
One image spanning the whole root avoids relying on feh's Xinerama
|
|
screen order matching i3's output names.
|
|
"""
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
root.save(target, compress_level=1)
|
|
subprocess.run(
|
|
["/usr/bin/feh", "--no-fehbg", "--no-xinerama", "--bg-tile", str(target)],
|
|
check=True,
|
|
)
|