Python version: Virtual profile support (common, horizontal, vertical)

This commit is contained in:
Phillip Berndt 2015-01-07 12:56:28 +01:00
parent aeb5b97b28
commit 9b0570824f
1 changed files with 69 additions and 17 deletions

View File

@ -25,6 +25,7 @@
# This also requires to load all resolutions into the XrandrOutputs
from __future__ import print_function
import copy
import getopt
import binascii
@ -35,6 +36,14 @@ import subprocess
import sys
from itertools import chain
from collections import OrderedDict
virtual_profiles = [
# (name, description, callback)
("common", "Clone all connected outputs at the largest common resolution", None),
("horizontal", "Stack all connected outputs horizontally at their largest resolution", None),
("vertical", "Stack all connected outputs vertically at their largest resolution", None),
]
help_text = """
Usage: autorandr [options]
@ -63,7 +72,6 @@ Usage: autorandr [options]
after a mode switch has taken place and can notify window managers.
The following virtual configurations are available:
TODO
""".strip()
class XrandrOutput(object):
@ -239,13 +247,14 @@ def parse_xrandr_output():
# Split at output boundaries and instanciate an XrandrOutput per output
split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output)
outputs = {}
modes = {}
outputs = OrderedDict()
modes = OrderedDict()
for i in range(1, len(split_xrandr_output), 2):
output_name = split_xrandr_output[i].split()[0]
output, output_modes = XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i+2]))
outputs[output_name] = output
modes[output_name] = output_modes
if output_modes:
modes[output_name] = output_modes
return outputs, modes
@ -313,7 +322,6 @@ def save_configuration(profile_path, configuration):
"Save a configuration into a profile"
if not os.path.isdir(profile_path):
os.makedirs(profile_path)
outputs = sorted(configuration.keys(), key=lambda x: configuration[x].sort_key)
with open(os.path.join(profile_path, "config"), "w") as config:
output_configuration(configuration, config)
with open(os.path.join(profile_path, "setup"), "w") as setup:
@ -341,9 +349,47 @@ def apply_configuration(configuration, dry_run=False):
if subprocess.call((base_argv[:] + configuration[remaining_outputs[index]].option_vector + (configuration[remaining_outputs[index + 1]].option_vector if index < len(remaining_outputs) - 1 else []))) != 0:
return False
def generate_virtual_profile(configuration, modes, profile_name):
"Generate one of the virtual profiles"
configuration = copy.deepcopy(configuration)
if profile_name == "common":
common_resolution = [ set(( ( mode["width"], mode["height"] ) for mode in output )) for output in modes.values() ]
common_resolution = reduce(lambda a, b: a & b, common_resolution[1:], common_resolution[0])
common_resolution = sorted(common_resolution, key=lambda a: int(a[0])*int(a[1]))
if common_resolution:
for output in configuration:
configuration[output].options = {}
if output in modes:
configuration[output].options["mode"] = "%sx%s" % common_resolution[-1]
configuration[output].options["pos"] = "0x0"
else:
configuration[output].options["off"] = None
elif profile_name in ("horizontal", "vertical"):
shift = 0
if profile_name == "horizontal":
shift_index = "width"
pos_specifier = "%sx0"
else:
shift_index = "height"
pos_specifier = "0x%s"
for output in configuration:
configuration[output].options = {}
if output in modes:
mode = sorted(modes[output], key=lambda a: int(a["width"])*int(a["height"]) + (10**6 if a["preferred"] else 0))[-1]
configuration[output].options["mode"] = "%sx%s" % (mode["width"], mode["height"])
configuration[output].options["rate"] = mode["rate"]
configuration[output].options["pos"] = pos_specifier % shift
shift += int(mode[shift_index])
else:
configuration[output].options["off"] = None
return configuration
def exit_help():
"Print help and exit"
print(help_text)
for profile in virtual_profiles:
print(" %-10s %s" % profile[:2])
sys.exit(0)
def exec_scripts(profile_path, script_name):
@ -370,6 +416,9 @@ def main(argv):
if "-s" in options:
options["--save"] = options["-s"]
if "--save" in options:
if options["--save"] in ( x[0] for x in virtual_profiles ):
print("Cannot save current configuration as profile '%s': This configuration name is a reserved virtual configuration." % options["--save"])
sys.exit(1)
save_configuration(os.path.join(profile_path, options["--save"]), config)
print("Saved current configuration as profile '%s'" % options["--save"])
sys.exit(0)
@ -384,17 +433,17 @@ def main(argv):
options["--load"] = options["-l"]
if "--load" in options:
load_profile = options["--load"]
for profile_name in profiles.keys():
if profile_blocked(os.path.join(profile_path, profile_name)):
print("%s (blocked)" % profile_name)
continue
if detected_profile == profile_name:
print("%s (detected)" % profile_name)
if "-c" in options or "--change" in options:
load_profile = detected_profile
else:
print(profile_name)
else:
for profile_name in profiles.keys():
if profile_blocked(os.path.join(profile_path, profile_name)):
print("%s (blocked)" % profile_name)
continue
if detected_profile == profile_name:
print("%s (detected)" % profile_name)
if "-c" in options or "--change" in options:
load_profile = detected_profile
else:
print(profile_name)
if "-d" in options:
options["--default"] = options["-d"]
@ -402,7 +451,10 @@ def main(argv):
load_profile = options["--default"]
if load_profile:
profile = profiles[load_profile]
if load_profile in ( x[0] for x in virtual_profiles ):
profile = generate_virtual_profile(config, modes, load_profile)
else:
profile = profiles[load_profile]
if profile == config and not "-f" in options and not "--force" in options:
print("Config already loaded")
sys.exit(0)