X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=autorandr.py;h=41e27b6962ae7dc2a86bf9cd6869e822923aa5dd;hb=6ed624aaa094dc18af447c5603f448481b5c745d;hp=0b16695befb639a8b25a4d298f6f689db974bed0;hpb=da23930cdbb8de7d77ac2df4f526557d4983bd53;p=deb_pkgs%2Fautorandr.git diff --git a/autorandr.py b/autorandr.py index 0b16695..41e27b6 100755 --- a/autorandr.py +++ b/autorandr.py @@ -34,6 +34,7 @@ import re import subprocess import sys import shutil +import time from collections import OrderedDict from distutils.version import LooseVersion as Version @@ -529,6 +530,25 @@ def update_mtime(filename): except: return False +def call_and_retry(*args, **kwargs): + """Wrapper around subprocess.call that retries failed calls. + + This function calls subprocess.call and on non-zero exit states, + waits a second and then retries once. This mitigates #47, + a timing issue with some drivers. + """ + kwargs_redirected = dict(kwargs) + if hasattr(subprocess, "DEVNULL"): + kwargs_redirected["stdout"] = getattr(subprocess, "DEVNULL") + else: + kwargs_redirected["stdout"] = open(os.devnull, "w") + kwargs_redirected["stderr"] = kwargs_redirected["stdout"] + retval = subprocess.call(*args, **kwargs_redirected) + if retval != 0: + time.sleep(1) + retval = subprocess.call(*args, **kwargs) + return retval + def apply_configuration(new_configuration, current_configuration, dry_run=False): "Apply a configuration" outputs = sorted(new_configuration.keys(), key=lambda x: new_configuration[x].sort_key) @@ -582,13 +602,13 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False) # Perform pe-change auxiliary changes if auxiliary_changes_pre: argv = base_argv + list(chain.from_iterable(auxiliary_changes_pre)) - if subprocess.call(argv) != 0: + if call_and_retry(argv) != 0: raise AutorandrException("Command failed: %s" % " ".join(argv)) # Disable unused outputs, but make sure that there always is at least one active screen disable_keep = 0 if remain_active_count else 1 if len(disable_outputs) > disable_keep: - if subprocess.call(base_argv + list(chain.from_iterable(disable_outputs[:-1] if disable_keep else disable_outputs))) != 0: + if call_and_retry(base_argv + list(chain.from_iterable(disable_outputs[:-1] if disable_keep else disable_outputs))) != 0: # Disabling the outputs failed. Retry with the next command: # Sometimes disabling of outputs fails due to an invalid RRSetScreenSize. # This does not occur if simultaneously the primary screen is reset. @@ -607,7 +627,7 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False) operations = disable_outputs + enable_outputs for index in range(0, len(operations), 2): argv = base_argv + list(chain.from_iterable(operations[index:index+2])) - if subprocess.call(argv) != 0: + if call_and_retry(argv) != 0: raise AutorandrException("Command failed: %s" % " ".join(argv)) def is_equal_configuration(source_configuration, target_configuration): @@ -716,7 +736,7 @@ def exec_scripts(profile_path, script_name, meta_information=None): user_profile_path = os.path.join(os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), "autorandr") for folder in chain((profile_path, os.path.dirname(profile_path), user_profile_path), - (os.path.join(x, "autorandr") for x in os.environ.get("XDG_CONFIG_DIRS", "").split(":"))): + (os.path.join(x, "autorandr") for x in os.environ.get("XDG_CONFIG_DIRS", "/etc/xdg").split(":"))): if script_name not in ran_scripts: script = os.path.join(folder, script_name) @@ -749,7 +769,7 @@ def main(argv): try: # Load profiles from each XDG config directory # The XDG spec says that earlier entries should take precedence, so reverse the order - for directory in reversed(os.environ.get("XDG_CONFIG_DIRS", "").split(":")): + for directory in reversed(os.environ.get("XDG_CONFIG_DIRS", "/etc/xdg").split(":")): system_profile_path = os.path.join(directory, "autorandr") if os.path.isdir(system_profile_path): profiles.update(load_profiles(system_profile_path))