summaryrefslogtreecommitdiff
path: root/monitor-menu.py
diff options
context:
space:
mode:
authorOlivier Gayot <olivier.gayot@sigexec.com>2023-02-11 19:47:01 +0100
committerOlivier Gayot <olivier.gayot@sigexec.com>2023-02-11 19:52:47 +0100
commitc35ac6f8e56f042f0188a284d85a4700ccf37773 (patch)
tree5222411542830e5959bd3affa0ed8388b0b7250d /monitor-menu.py
parentff3c765f1c33f3adbda07f2d828542099f9cbb26 (diff)
Make it a debian package
Signed-off-by: Olivier Gayot <olivier.gayot@sigexec.com>
Diffstat (limited to 'monitor-menu.py')
-rwxr-xr-xmonitor-menu.py148
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()