1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
"""Hyprland windows, workspaces, and launching config-declared commands."""
import json
import re
import subprocess
from pathlib import Path
from ..module import Module, ModuleError
ADDR = re.compile(r"0x[0-9a-f]{1,16}")
def _run(cmd, timeout=2):
try:
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout).stdout.strip()
except (OSError, subprocess.TimeoutExpired):
return ""
def _popen(cmd):
subprocess.Popen(cmd, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def hypr_lua(cfg: dict) -> bool:
mode = cfg.get("hyprland", "auto")
if mode == "auto":
return (Path.home() / ".config/hypr/hyprland.lua").is_file()
return mode == "lua"
def workspace_cmd(n: int, lua: bool):
if lua:
return ["hyprctl", "eval", f'hl.dispatch(hl.dsp.focus({{workspace = "{n}"}}))']
return ["hyprctl", "dispatch", "workspace", str(n)]
def window_cmd(verb: str, addr: str, lua: bool):
if lua:
dsp = "hl.dsp.focus" if verb == "focus" else "hl.dsp.window.close"
return ["hyprctl", "eval", f'{dsp}({{window = "address:{addr}"}})']
return ["hyprctl", "dispatch", "focuswindow" if verb == "focus" else "closewindow", f"address:{addr}"]
def _state(run):
try:
clients = json.loads(run(["hyprctl", "clients", "-j"]) or "[]")
active = json.loads(run(["hyprctl", "activewindow", "-j"]) or "{}").get("address")
workspaces = json.loads(run(["hyprctl", "workspaces", "-j"]) or "[]")
except json.JSONDecodeError:
return {"windows": [], "workspaces": [], "activeClass": None}
wins = sorted(
({"address": c["address"], "class": c["class"], "title": c["title"],
"workspace": c["workspace"]["id"], "active": c["address"] == active}
for c in clients if c.get("mapped", True) and c["workspace"]["id"] > 0),
key=lambda w: (w["workspace"], w["class"]))
active_class = next((w["class"] for w in wins if w["active"]), None)
return {"windows": wins,
"workspaces": sorted(w["id"] for w in workspaces if w.get("id", 0) > 0),
"activeClass": active_class}
def make(cfg: dict) -> Module:
run = cfg.get("run", _run)
lua = hypr_lua(cfg)
launch = cfg.get("launch", {})
workspaces = cfg.get("windows", {}).get("workspaces", list(range(1, 11)))
def launch_spec(spec):
if isinstance(spec, dict):
return spec.get("command"), spec.get("icon"), spec.get("label")
return spec, None, None
def workspace(body):
n = body.get("n")
if not isinstance(n, int) or not 1 <= n <= 99:
raise ModuleError("workspace must be a number from 1 to 99")
_popen(workspace_cmd(n, lua))
def focus(body):
addr = str(body.get("address", ""))
if not ADDR.fullmatch(addr):
raise ModuleError("bad window address")
_popen(window_cmd("focus", addr, lua))
def close(body):
addr = str(body.get("address", ""))
if not ADDR.fullmatch(addr):
raise ModuleError("bad window address")
_popen(window_cmd("close", addr, lua))
def launch_key(body):
key = str(body.get("key", ""))
command, _, _ = launch_spec(launch.get(key))
if command is None:
raise ModuleError("unknown launch key")
_popen(["sh", "-c", command] if isinstance(command, str) else command)
def state():
st = _state(run)
known = sorted(set(int(n) for n in workspaces) | set(st["workspaces"]))
launches = []
for key, spec in launch.items():
_, icon, label = launch_spec(spec)
launches.append({"key": key, "icon": icon, "label": label or key})
return {**st, "workspaces": known, "launches": launches}
return Module(name="windows", title="Windows", state=state,
actions={"workspace": workspace, "focus": focus, "close": close, "launch": launch_key})
|