103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
" The monitors plugin "
|
|
import subprocess
|
|
from typing import Any
|
|
from .interface import Plugin
|
|
|
|
from ..ipc import hyprctlJSON
|
|
|
|
|
|
def configure_monitors(monitors, screenid: str, pos_x: int, pos_y: int) -> None:
|
|
"Apply the configuration change"
|
|
x_offset = -pos_x if pos_x < 0 else 0
|
|
y_offset = -pos_y if pos_y < 0 else 0
|
|
|
|
min_x = pos_x
|
|
min_y = pos_y
|
|
|
|
command = ["wlr-randr"]
|
|
other_monitors = [mon for mon in monitors if mon["name"] != screenid]
|
|
for mon in other_monitors:
|
|
min_x = min(min_x, mon["x"])
|
|
min_y = min(min_y, mon["y"])
|
|
x_offset = -min_x
|
|
y_offset = -min_y
|
|
for mon in other_monitors:
|
|
command.extend(
|
|
[
|
|
"--output",
|
|
mon["name"],
|
|
"--pos",
|
|
f"{mon['x']+x_offset},{mon['y']+y_offset}",
|
|
]
|
|
)
|
|
|
|
command.extend(
|
|
["--output", screenid, "--pos", f"{pos_x+x_offset},{pos_y+y_offset}"]
|
|
)
|
|
subprocess.call(command)
|
|
|
|
|
|
class Extension(Plugin): # pylint: disable=missing-class-docstring
|
|
async def load_config(self, config) -> None:
|
|
await super().load_config(config)
|
|
monitors = await hyprctlJSON("monitors")
|
|
for monitor in monitors:
|
|
await self.event_monitoradded(
|
|
monitor["name"], no_default=True, monitors=monitors
|
|
)
|
|
|
|
async def event_monitoradded(
|
|
self, monitor_name, no_default=False, monitors: list | None = None
|
|
) -> None:
|
|
"Triggers when a monitor is plugged"
|
|
monitor_name = monitor_name.strip()
|
|
|
|
if not monitors:
|
|
monitors = await hyprctlJSON("monitors")
|
|
|
|
assert monitors
|
|
|
|
for mon in monitors:
|
|
if mon["name"].startswith(monitor_name):
|
|
mon_description = mon["description"]
|
|
break
|
|
else:
|
|
self.log.info("Monitor %s not found", monitor_name)
|
|
return
|
|
|
|
if self._place_monitors(monitor_name, mon_description, monitors):
|
|
return
|
|
|
|
if not no_default:
|
|
default_command = self.config.get("unknown")
|
|
if default_command:
|
|
subprocess.call(default_command, shell=True)
|
|
|
|
def _place_monitors(
|
|
self, monitor_name: str, mon_description: str, monitors: list[dict[str, Any]]
|
|
):
|
|
"place a given monitor according to config"
|
|
mon_by_name = {m["name"]: m for m in monitors}
|
|
newmon = mon_by_name[monitor_name]
|
|
for mon_pattern, conf in self.config["placement"].items():
|
|
if mon_pattern in mon_description:
|
|
for placement, other_mon_description in conf.items():
|
|
ref = mon_by_name[other_mon_description]
|
|
if ref:
|
|
place = placement.lower()
|
|
if place == "topof":
|
|
x: int = ref["x"]
|
|
y: int = ref["y"] - newmon["height"]
|
|
elif place == "bottomof":
|
|
x: int = ref["x"]
|
|
y: int = ref["y"] + ref["height"]
|
|
elif place == "leftof":
|
|
x: int = ref["x"] - newmon["width"]
|
|
y: int = ref["y"]
|
|
else: # rightof
|
|
x: int = ref["x"] + ref["width"]
|
|
y: int = ref["y"]
|
|
|
|
configure_monitors(monitors, monitor_name, x, y)
|
|
return True
|
|
return False
|