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 # This also requires to load all resolutions into the XrandrOutputs
from __future__ import print_function from __future__ import print_function
import copy
import getopt import getopt
import binascii import binascii
@ -35,6 +36,14 @@ import subprocess
import sys import sys
from itertools import chain 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 = """ help_text = """
Usage: autorandr [options] Usage: autorandr [options]
@ -63,7 +72,6 @@ Usage: autorandr [options]
after a mode switch has taken place and can notify window managers. after a mode switch has taken place and can notify window managers.
The following virtual configurations are available: The following virtual configurations are available:
TODO
""".strip() """.strip()
class XrandrOutput(object): class XrandrOutput(object):
@ -239,13 +247,14 @@ def parse_xrandr_output():
# Split at output boundaries and instanciate an XrandrOutput per output # Split at output boundaries and instanciate an XrandrOutput per output
split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output) split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output)
outputs = {} outputs = OrderedDict()
modes = {} modes = OrderedDict()
for i in range(1, len(split_xrandr_output), 2): for i in range(1, len(split_xrandr_output), 2):
output_name = split_xrandr_output[i].split()[0] output_name = split_xrandr_output[i].split()[0]
output, output_modes = XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i+2])) output, output_modes = XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i+2]))
outputs[output_name] = output outputs[output_name] = output
modes[output_name] = output_modes if output_modes:
modes[output_name] = output_modes
return outputs, modes return outputs, modes
@ -313,7 +322,6 @@ def save_configuration(profile_path, configuration):
"Save a configuration into a profile" "Save a configuration into a profile"
if not os.path.isdir(profile_path): if not os.path.isdir(profile_path):
os.makedirs(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: with open(os.path.join(profile_path, "config"), "w") as config:
output_configuration(configuration, config) output_configuration(configuration, config)
with open(os.path.join(profile_path, "setup"), "w") as setup: 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: 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 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(): def exit_help():
"Print help and exit" "Print help and exit"
print(help_text) print(help_text)
for profile in virtual_profiles:
print(" %-10s %s" % profile[:2])
sys.exit(0) sys.exit(0)
def exec_scripts(profile_path, script_name): def exec_scripts(profile_path, script_name):
@ -370,6 +416,9 @@ def main(argv):
if "-s" in options: if "-s" in options:
options["--save"] = options["-s"] options["--save"] = options["-s"]
if "--save" in options: 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) save_configuration(os.path.join(profile_path, options["--save"]), config)
print("Saved current configuration as profile '%s'" % options["--save"]) print("Saved current configuration as profile '%s'" % options["--save"])
sys.exit(0) sys.exit(0)
@ -384,17 +433,17 @@ def main(argv):
options["--load"] = options["-l"] options["--load"] = options["-l"]
if "--load" in options: if "--load" in options:
load_profile = options["--load"] load_profile = options["--load"]
else:
for profile_name in profiles.keys(): for profile_name in profiles.keys():
if profile_blocked(os.path.join(profile_path, profile_name)): if profile_blocked(os.path.join(profile_path, profile_name)):
print("%s (blocked)" % profile_name) print("%s (blocked)" % profile_name)
continue continue
if detected_profile == profile_name: if detected_profile == profile_name:
print("%s (detected)" % profile_name) print("%s (detected)" % profile_name)
if "-c" in options or "--change" in options: if "-c" in options or "--change" in options:
load_profile = detected_profile load_profile = detected_profile
else: else:
print(profile_name) print(profile_name)
if "-d" in options: if "-d" in options:
options["--default"] = options["-d"] options["--default"] = options["-d"]
@ -402,7 +451,10 @@ def main(argv):
load_profile = options["--default"] load_profile = options["--default"]
if load_profile: 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: if profile == config and not "-f" in options and not "--force" in options:
print("Config already loaded") print("Config already loaded")
sys.exit(0) sys.exit(0)