diff options
Diffstat (limited to 'monitor-menu.py')
-rwxr-xr-x | monitor-menu.py | 148 |
1 files changed, 0 insertions, 148 deletions
diff --git a/monitor-menu.py b/monitor-menu.py deleted file mode 100755 index d450ba8..0000000 --- a/monitor-menu.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import dataclasses -import json -import logging -from os.path import expanduser -import subprocess -from typing import Any - -import dialog - - -class NoMatchingProfile(ValueError): - pass - - -class LogLevel: - def __init__(self, value: str) -> None: - try: - self.numerical_level = logging.getLevelNamesMapping()[value.upper()] - except KeyError: - raise ValueError("invalid value") - - -@dataclasses.dataclass -class Monitor: - output: str - - xrandr_opts: list[str] = dataclasses.field(default_factory=list) - position: str | None = None - background: str | None = None - primary: bool = False - - @classmethod - def from_json_dict(cls, json_dict: dict[str, Any]) -> "Monitor": - def convert_key_name(name: str) -> str: - return name.replace("-", "_") - - return cls(**{convert_key_name(key): value for key, value in json_dict.items()}) - - -@dataclasses.dataclass -class Profile: - name: str - monitors: list[Monitor] = dataclasses.field(default_factory=list) - - identifier: str | None = None - xrandr_opts: list[str] = dataclasses.field(default_factory=list) - - @classmethod - def from_json_dict(cls, json_dict: dict[str, Any]) -> "Profile": - def convert_key_name(name: str) -> str: - return name.replace("-", "_") - - kwargs = {} - for key, value in json_dict.items(): - key = convert_key_name(key) - if key == "monitors": - value = [Monitor.from_json_dict(item) for item in value] - kwargs[key] = value - return cls(**kwargs) - - def apply(self): - # We build the command line starting from just "xrandr" and adding - # arguments. - xrandr_cmd = ['xrandr'] - feh_cmd = ['feh', '--bg-fill'] - - try: - xrandr_cmd += self.xrandr_opts - except KeyError: - pass - - for monitor in self.monitors: - xrandr_cmd.extend(monitor.xrandr_opts) - - if monitor.background is not None: - feh_cmd.append(monitor.background) - - logging.debug("Executing: %s", xrandr_cmd) - subprocess.run(xrandr_cmd, check=False) - logging.debug("Executing: %s", feh_cmd) - subprocess.run(feh_cmd, check=False) - - -class MonitorMenu: - def __init__(self, profiles: list[Profile]) -> None: - self.profiles = profiles - self.d = dialog.Dialog(autowidgetsize=True) - - def run(self): - choices = [] - - i = 0 - for p in self.profiles: - choices.append((str(i), p.name)) - i += 1 - - code, profile_idx = self.d.menu( - 'Select the profile you want to use.', - choices=choices) - - if code in (self.d.ESC, self.d.CANCEL): - return - - try: - self.profiles[int(profile_idx)].apply() - except IndexError: - raise NoMatchingProfile from None - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--log-level", "--loglevel", type=LogLevel, default="info") - subparser = parser.add_subparsers(dest="command") - subparser.add_parser("run") - apply_parser = subparser.add_parser("apply") - identifier_group = apply_parser.add_mutually_exclusive_group(required=True) - identifier_group.add_argument("--index", type=int) - identifier_group.add_argument("--id", type=str) - - args = parser.parse_args() - logging.basicConfig(level=args.log_level.numerical_level) - - config_file = '~/.config/monitor-profiles.json' - with open(expanduser(config_file)) as fh: - data = json.load(fh) - profiles = [Profile.from_json_dict(item) for item in data] - - match args.command: - case "run" | None: - MonitorMenu(profiles).run() - case "apply": - if args.index is not None: - try: - profiles[args.index].apply() - except IndexError: - raise NoMatchingProfile from None - else: - try: - next(filter(lambda p: p.identifier == args.id, profiles)).apply() - except StopIteration: - raise NoMatchingProfile from None - - -if __name__ == '__main__': - main() |