This commit is contained in:
2026-06-08 02:40:00 -05:00
commit 601c0b5cc5
19 changed files with 1038 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env python3
import json
import subprocess
from pathlib import Path
out = Path("./mute/monitors.conf")
DIRECT = {
"left": (-1, 0),
"right": (1, 0),
"above": (0, -1),
"below": (0, 1),
"primary": (0, 0)
}
def get_sway_data(target_type):
cmd = ["swaymsg", "-t", f"get_{target_type}", "-r"]
return json.loads(subprocess.check_output(cmd, text=True))
def get_best_mode(output):
modes = output.get("modes", [])
if not modes:
return (1920, 1080)
for m in modes:
if m.get("preferred"):
return m["width"], m["height"]
best = max(modes, key=lambda m: m["width"] * m["height"])
return best["width"], best["height"]
def ask(prompt, default=None):
prompt_str = f"{prompt} [{default}]: " if default else f"{prompt}: "
val = input(prompt_str).strip()
return val if val else default
def compute_positions(monitors, layout, outputs):
positions = {}
output_map = {o["name"]: o for o in outputs}
primary_name = next((name for name, dist in layout.items() if dist == "primary"), None)
if not primary_name and monitors:
primary_name = monitors[0]["name"]
layout[primary_name] = "primary"
logical_sizes = {}
for m in monitors:
name = m["name"]
try:
res_w, res_h = map(int, m["res"].lower().split("x"))
except ValueError:
res_w, res_h = get_best_mode(output_map[name])
scale = float(m["scale"])
logical_sizes[name] = {
"width": res_w / scale,
"height": res_h / scale
}
for m in monitors:
name = m["name"]
direction = layout[name]
if direction == "primary":
positions[name] = (0, 0)
continue
dx, dy = DIRECT.get(direction, (1, 0))
ref_w = logical_sizes[name]["width"] if dx < 0 else logical_sizes[primary_name]["width"]
ref_h = logical_sizes[name]["height"] if dy < 0 else logical_sizes[primary_name]["height"]
positions[name] = (int(ref_w * dx), int(ref_h * dy))
return positions
def build_config(monitors, positions):
lines = ["# generated config\n"]
for m in monitors:
name = m["name"]
mode = f"{m['res']}@{m['refresh']}" if m["refresh"] else m["res"]
x, y = positions[name]
lines.append(
f"output {name} mode {mode}\n"
f"output {name} scale {m['scale']}\n"
f"output {name} position {x} {y}\n"
)
return "\n".join(lines)
def main():
Path("mute").mkdir(exist_ok=True)
outputs = get_sway_data("outputs")
workspaces = get_sway_data("workspaces")
monitors = []
layout_map = {}
for o in outputs:
name = o["name"]
ws = [str(w["name"]) for w in workspaces if w.get("output") == name]
w, h = get_best_mode(o)
best_res = f"{w}x{h}"
print(f"\nMONITOR: {name}\nWORKSPACES: {ws}")
layout_map[name] = ask(
"Position relative to primary (primary/left/right/above/below)",
"right"
)
res_input = ask("Resolution (optional press enter for best)", "")
monitors.append({
"name": name,
"res": res_input if res_input else best_res,
"refresh": ask("Refresh rate (optional)", ""),
"scale": ask("Scale", "1")
})
positions = compute_positions(monitors, layout_map, outputs)
out.write_text(build_config(monitors, positions))
if __name__ == "__main__":
main()