X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=autorandr.py;h=d54ade89fc27895153d8568fd1d3f8256b40d4ff;hb=bc032ec25e998d3cbd958cf0f6179b4fe2fe28d2;hp=ca35ba93a80225e1e1ed1667497d02d443b79dba;hpb=6813f53f8fdd577c21f379bc26247083af1ed95f;p=deb_pkgs%2Fautorandr.git diff --git a/autorandr.py b/autorandr.py index ca35ba9..d54ade8 100755 --- a/autorandr.py +++ b/autorandr.py @@ -26,6 +26,7 @@ from __future__ import print_function import binascii import copy +import fnmatch import getopt import hashlib import os @@ -42,6 +43,11 @@ from distutils.version import LooseVersion as Version from functools import reduce from itertools import chain +if sys.version_info.major == 2: + import ConfigParser as configparser +else: + import configparser + try: input = raw_input except NameError: @@ -49,6 +55,7 @@ except NameError: virtual_profiles = [ # (name, description, callback) + ("off", "Disable all outputs", None), ("common", "Clone all connected outputs at the largest common resolution", None), ("clone-largest", "Clone all connected outputs with the largest resolution (scaled down if necessary)", None), ("horizontal", "Stack all connected outputs horizontally at their largest resolution", None), @@ -65,8 +72,10 @@ Usage: autorandr [options] -s, --save save your current setup to profile -r, --remove remove profile --batch run autorandr for all users with active X11 sessions +--current only list current (active) configuration(s) --config dump your current xrandr setup --debug enable verbose output +--detected only list detected (available) configuration(s) --dry-run don't change anything, only print the xrandr commands --fingerprint fingerprint your current hardware setup --force force (re)loading of a profile @@ -391,6 +400,10 @@ class XrandrOutput(object): return hashlib.md5(binascii.unhexlify(other.edid)).hexdigest() == self.edid if len(self.edid) != 32 and len(other.edid) == 32 and not self.edid.startswith(XrandrOutput.EDID_UNAVAILABLE): return hashlib.md5(binascii.unhexlify(self.edid)).hexdigest() == other.edid + if "*" in self.edid: + return fnmatch.fnmatch(other.edid, self.edid) + elif "*" in other.edid: + return fnmatch.fnmatch(self.edid, other.edid) return self.edid == other.edid def __ne__(self, other): @@ -762,13 +775,13 @@ def generate_virtual_profile(configuration, modes, profile_name): for output in configuration: configuration[output].options = {} if output in modes and configuration[output].edid: - def key(a, b): + def key(a): score = int(a["width"]) * int(a["height"]) if a["preferred"]: score += 10**6 return score - modes = sorted(modes[output], key=key) - mode = modes[-1] + output_modes = sorted(modes[output], key=key) + mode = output_modes[-1] configuration[output].options["mode"] = mode["name"] configuration[output].options["rate"] = mode["rate"] configuration[output].options["pos"] = pos_specifier % shift @@ -782,13 +795,13 @@ def generate_virtual_profile(configuration, modes, profile_name): for output in configuration: configuration[output].options = {} if output in modes and configuration[output].edid: - def key(a, b): + def key(a): score = int(a["width"]) * int(a["height"]) if a["preferred"]: score += 10**6 return score - modes = sorted(modes[output], key=key) - mode = modes[-1] + output_modes = sorted(modes[output], key=key) + mode = output_modes[-1] configuration[output].options["mode"] = mode["name"] configuration[output].options["rate"] = mode["rate"] configuration[output].options["pos"] = "0x0" @@ -799,6 +812,11 @@ def generate_virtual_profile(configuration, modes, profile_name): configuration[output].options["transform"] = "{},0,{},0,{},{},0,0,1".format(scale, mov_x, scale, mov_y) else: configuration[output].options["off"] = None + elif profile_name == "off": + for output in configuration: + for key in list(configuration[output].options.keys()): + del configuration[output].options[key] + configuration[output].options["off"] = None return configuration @@ -806,18 +824,18 @@ def print_profile_differences(one, another): "Print the differences between two profiles for debugging" if one == another: return - print("| Differences between the two profiles:", file=sys.stderr) + print("| Differences between the two profiles:") for output in set(chain.from_iterable((one.keys(), another.keys()))): if output not in one: if "off" not in another[output].options: - print("| Output `%s' is missing from the active configuration" % output, file=sys.stderr) + print("| Output `%s' is missing from the active configuration" % output) elif output not in another: if "off" not in one[output].options: - print("| Output `%s' is missing from the new configuration" % output, file=sys.stderr) + print("| Output `%s' is missing from the new configuration" % output) else: for line in one[output].verbose_diff(another[output]): - print("| [Output %s] %s" % (output, line), file=sys.stderr) - print("\\-", file=sys.stderr) + print("| [Output %s] %s" % (output, line)) + print("\\-") def exit_help(): @@ -865,12 +883,11 @@ def exec_scripts(profile_path, script_name, meta_information=None): candidate_directories = [user_profile_path] for config_dir in os.environ.get("XDG_CONFIG_DIRS", "/etc/xdg").split(":"): - candidate_directories += os.path.join(config_dir, "autorandr") + candidate_directories.append(os.path.join(config_dir, "autorandr")) if profile_path: - candidate_directories += profile_path + candidate_directories.append(profile_path) for folder in candidate_directories: - if script_name not in ran_scripts: script = os.path.join(folder, script_name) if os.access(script, os.X_OK | os.F_OK): @@ -957,8 +974,8 @@ def dispatch_call_to_sessions(argv): process_environ = {} for environ_entry in open(environ_file).read().split("\0"): - if "=" in environ_entry: - name, value = environ_entry.split("=", 1) + name, sep, value = environ_entry.partition("=") + if name and sep: if name == "DISPLAY" and "." in value: value = value[:value.find(".")] process_environ[name] = value @@ -1003,11 +1020,21 @@ def dispatch_call_to_sessions(argv): X11_displays_done.add(display) +def read_config(options, directory): + """Parse a configuration config.ini from directory and merge it into + the options dictionary""" + config = configparser.ConfigParser() + config.read(os.path.join(directory, "settings.ini")) + if config.has_section("config"): + for key, value in config.items("config"): + options.setdefault("--%s" % key, value) + def main(argv): try: opts, args = getopt.getopt(argv[1:], "s:r:l:d:cfh", ["batch", "dry-run", "change", "default=", "save=", "remove=", "load=", - "force", "fingerprint", "config", "debug", "skip-options=", "help"]) + "force", "fingerprint", "config", "debug", "skip-options=", "help", + "current", "detected"]) except getopt.GetoptError as e: print("Failed to parse options: {0}.\n" "Use --help to get usage information.".format(str(e)), @@ -1019,6 +1046,10 @@ def main(argv): if "-h" in options or "--help" in options: exit_help() + if "--current" in options and "--detected" in options: + print("--current and --detected are mutually exclusive.", file=sys.stderr) + sys.exit(posix.EX_USAGE) + # Batch mode if "--batch" in options: if ("DISPLAY" not in os.environ or not os.environ["DISPLAY"]) and os.getuid() == 0: @@ -1041,6 +1072,7 @@ def main(argv): if os.path.isdir(system_profile_path): profiles.update(load_profiles(system_profile_path)) profile_symlinks.update(get_symlinks(system_profile_path)) + read_config(options, system_profile_path) # For the user's profiles, prefer the legacy ~/.autorandr if it already exists # profile_path is also used later on to store configurations profile_path = os.path.expanduser("~/.autorandr") @@ -1050,6 +1082,7 @@ def main(argv): if os.path.isdir(profile_path): profiles.update(load_profiles(profile_path)) profile_symlinks.update(get_symlinks(profile_path)) + read_config(options, profile_path) # Sort by descending mtime profiles = OrderedDict(sorted(profiles.items(), key=lambda x: -x[1]["config-mtime"])) except Exception as e: @@ -1144,16 +1177,24 @@ def main(argv): for profile_name in profiles.keys(): if profile_blocked(os.path.join(profile_path, profile_name), block_script_metadata): - print("%s (blocked)" % profile_name, file=sys.stderr) + if "--current" not in options and "--detected" not in options: + print("%s (blocked)" % profile_name) continue props = [] if profile_name in detected_profiles: props.append("(detected)") if ("-c" in options or "--change" in options) and not load_profile: load_profile = profile_name + elif "--detected" in options: + continue if profile_name in current_profiles: props.append("(current)") - print("%s%s%s" % (profile_name, " " if props else "", " ".join(props)), file=sys.stderr) + elif "--current" in options: + continue + if "--current" in options or "--detected" in options: + print("%s" % (profile_name, )) + else: + print("%s%s%s" % (profile_name, " " if props else "", " ".join(props))) if not configs_are_equal and "--debug" in options and profile_name in detected_profiles: print_profile_differences(config, profiles[profile_name]["config"])