INIT!
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user