From 9b0c9c573a971f72d82a6e40d450f3aed08a691a Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Wed, 15 May 2024 11:54:22 +0100 Subject: [PATCH] Various improvements --- notes | 18 ++++++++++++++++ toggle.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ watch.py | 24 ++++++++++++++------- 3 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 notes create mode 100755 toggle.py diff --git a/notes b/notes new file mode 100644 index 0000000..9ae131d --- /dev/null +++ b/notes @@ -0,0 +1,18 @@ +output DP-3 Dell Inc. DELL U3219Q 9JKK413 1.0 270 +output HDMI-A-1 Sony SONY TV 0x00000101 1.0 normal +output eDP-1 Unknown 0x1403 0x00000000 None None + +tags = [ + "", + "master-of-seat", + "mutter-device-disable-kms-modifiers", + "seat", + "snap_slack_slack", + "uaccess", +] + +Watcher is generating too many events. Should consider the state of the laptop lid. If the lid is closed that is significant. + +Use MonitorObserver to monitor for events in a background thread. + +There can be a short delay before acting on an event. diff --git a/toggle.py b/toggle.py new file mode 100755 index 0000000..266f3ed --- /dev/null +++ b/toggle.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +import json +import os +import subprocess +import time +import typing + + +def run_swaymsg() -> bytes: + """Run swaymsg to get list of outputs.""" + p = subprocess.run(["swaymsg", "-r", "-t", "get_outputs"], capture_output=True) + return p.stdout + + +def parse_json(outputs: bytes) -> dict[str, dict[str, typing.Any]]: + """Parse get_outputs JSON.""" + try: + json_data = json.loads(outputs) + except json.decoder.JSONDecodeError: + print("JSON parse error") + print(outputs) + raise + + return {o["name"]: o for o in json_data} + + +def sony_tv_connected() -> None: + """Run command when HDMI is connected.""" + subprocess.run([os.path.expanduser("~/bin/desk")]) + + +def hdmi_disconnected() -> None: + """Run command when HDMI is disconnected.""" + subprocess.run([os.path.expanduser("~/bin/unplugged")]) + + +def get_outputs(attempts: int = 10) -> dict[str, dict[str, typing.Any]] | None: + """Ask sway for the current list of outputs.""" + for attempt in range(attempts): + outputs = run_swaymsg() + if outputs.strip() == b"": + return None + try: + return parse_json(outputs) + except json.decoder.JSONDecodeError: + if attempt == attempts - 1: + raise + time.sleep(1) + return None + + +def main() -> None: + outputs = get_outputs() + assert outputs + if outputs["eDP-1"]["active"]: + sony_tv_connected() + else: + hdmi_disconnected() + + +if __name__ == "__main__": + main() diff --git a/watch.py b/watch.py index 17381ea..c16889c 100755 --- a/watch.py +++ b/watch.py @@ -29,6 +29,18 @@ def run_swaymsg() -> bytes: return p.stdout +def parse_json(outputs: bytes) -> dict[str, dict[str, Any]]: + """Parse get_outputs JSON.""" + try: + json_data = json.loads(outputs) + except json.decoder.JSONDecodeError: + print("JSON parse error") + print(outputs) + raise + + return {o["name"]: o for o in json_data} + + def get_outputs(attempts: int = 10) -> dict[str, dict[str, Any]] | None: """Ask sway for the current list of outputs.""" for attempt in range(attempts): @@ -36,16 +48,12 @@ def get_outputs(attempts: int = 10) -> dict[str, dict[str, Any]] | None: if outputs.strip() == b"": return None try: - json_data = json.loads(outputs) - break + return parse_json(outputs) except json.decoder.JSONDecodeError: - print("JSON parse error") - print(outputs) if attempt == attempts - 1: raise time.sleep(1) - - return {o["name"]: o for o in json_data} + return None def is_sony_tv(output: dict[str, Any]) -> bool: @@ -80,7 +88,9 @@ def handle_state_change() -> str: hdmi_disconnected() return "HDMI disconnected, switching to laptop screen." - hdmi = get_outputs().get(hdmi_name) + outputs = get_outputs() + + hdmi = outputs and outputs.get(hdmi_name) if hdmi and is_sony_tv(hdmi): sony_tv_connected()