Skip to content

Instantly share code, notes, and snippets.

@mic-e
Created January 15, 2019 11:23
Show Gist options
  • Save mic-e/481a1dd86146ace2224d08afe701dfc3 to your computer and use it in GitHub Desktop.
Save mic-e/481a1dd86146ace2224d08afe701dfc3 to your computer and use it in GitHub Desktop.
Monitor autoconfiguration script
#!/usr/bin/env python3
"""
CLI script for setting display modes through xrandr.
"""
from argparse import ArgumentParser
from collections import OrderedDict
import re
from subprocess import call, Popen, PIPE
from shlex import quote
from time import sleep
import pyudev
DISPLAYS = [
"HDMI2",
"eDP1",
"DP1"
]
MODES = {
"nb": {
"eDP1": ["--auto"]
},
"1ext": {
"eDP1": ["--auto"],
"HDMI2": ["--auto", "--left-of", "eDP1"]
},
"ext": {
"DP1": ["--auto"],
"HDMI2": ["--auto", "--left-of", "DP1"]
},
}
AUTO = {
"eDP1": "nb",
"HDMI2, eDP1": "1ext",
"DP1, HDMI2, eDP1": "ext",
}
def get_displays():
"""
Lists the names of the currently-connected displays
"""
proc = Popen(['xrandr', '-q'], stdout=PIPE)
output = proc.communicate()[0].decode(errors='replace')
connected_re = re.compile("^([a-zA-Z0-9]+) connected ")
connected = []
for line in output.split('\n'):
match = connected_re.match(line)
if match is None:
continue
connected.append(match.groups()[0])
yield connected[-1]
def get_automatic_mode():
"""
Returns the suitable mode for the currently-connected displays
"""
displays = ", ".join(sorted(get_displays()))
print("connected displays: " + displays)
result = AUTO.get(displays)
print("automatic mode: %r" % result)
return result
def configure_displays(mode):
"""
Configures the displays to the given mode
"""
displays = OrderedDict()
displays["HDMI2"] = ["--off"]
displays["eDP1"] = ["--off"]
displays["DP1"] = ["--off"]
mode_info = MODES.get(mode)
if mode_info is None:
raise ValueError("unknown mode %r" % mode)
invocation = ["xrandr"]
for displayname in DISPLAYS:
invocation.append("--output")
invocation.append(displayname)
invocation.extend(mode_info.get(displayname, ["--off"]))
print(" ".join(quote(x) for x in invocation))
call(invocation)
def main():
""" CLI entry point """
cli = ArgumentParser()
cli.add_argument("mode")
args = cli.parse_args()
mode = args.mode
if mode == "daemon":
context = pyudev.Context()
udev_monitor = pyudev.Monitor.from_netlink(context)
udev_monitor.filter_by(subsystem='drm')
while True:
try:
configure_displays(get_automatic_mode())
except ValueError as exc:
print(exc)
# wait for next udev hotplug event
hotplug_device = udev_monitor.poll()
if hotplug_device is None:
return
print("hotplug: %r" % hotplug_device)
sleep(0.5)
else:
# run once
if mode == "auto":
mode = get_automatic_mode()
try:
configure_displays(mode)
except ValueError as exc:
cli.error(str(exc))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment