]> git.donarmstrong.com Git - deb_pkgs/autorandr.git/blobdiff - autorandr.py
Fix modified dictionary iteration as 1.12.1
[deb_pkgs/autorandr.git] / autorandr.py
index 24d8b3a9df0674291c91ac88756975fc08223315..6d0163c0a4dc9fd1f207865101206dae00915ec1 100755 (executable)
@@ -32,6 +32,7 @@ import os
 import posix
 import pwd
 import re
+import shlex
 import subprocess
 import sys
 import shutil
@@ -52,7 +53,7 @@ if sys.version_info.major == 2:
 else:
     import configparser
 
-__version__ = "1.11"
+__version__ = "1.12.1"
 
 try:
     input = raw_input
@@ -68,6 +69,20 @@ virtual_profiles = [
     ("vertical", "Stack all connected outputs vertically at their largest resolution", None),
 ]
 
+properties = [
+    "Colorspace",
+    "max bpc",
+    "aspect ratio",
+    "Broadcast RGB",
+    "audio",
+    "non-desktop",
+    "TearFree",
+    "underscan vborder",
+    "underscan hborder",
+    "underscan",
+    "scaling mode",
+]
+
 help_text = """
 Usage: autorandr [options]
 
@@ -157,6 +172,11 @@ class AutorandrException(Exception):
 class XrandrOutput(object):
     "Represents an XRandR output"
 
+    XRANDR_PROPERTIES_REGEXP = "|".join(
+        [r"{}:\s*(?P<{}>[\S ]*\S+)"
+         .format(re.sub(r"\s", r"\\\g<0>", p), re.sub(r"\W+", "_", p.lower()))
+            for p in properties])
+
     # This regular expression is used to parse an output in `xrandr --verbose'
     XRANDR_OUTPUT_REGEXP = """(?x)
         ^\s*(?P<output>\S[^ ]*)\s+                                                      # Line starts with output name
@@ -183,6 +203,7 @@ class XrandrOutput(object):
             CRTC:\s*(?P<crtc>[0-9]) |                                                   # CRTC value
             Transform: (?P<transform>(?:[\-0-9\. ]+\s+){3}) |                           # Transformation matrix
             EDID: (?P<edid>\s*?(?:\\n\\t\\t[0-9a-f]+)+) |                               # EDID of the output
+            """ + XRANDR_PROPERTIES_REGEXP + """ |                                      # Properties to include in the profile
             (?![0-9])[^:\s][^:\n]+:.*(?:\s\\t[\\t ].+)*                                 # Other properties
         ))+
         \s*
@@ -245,7 +266,22 @@ class XrandrOutput(object):
         "Return the command line parameters for XRandR for this instance"
         args = ["--output", self.output]
         for option, arg in sorted(self.options_with_defaults.items()):
-            args.append("--%s" % option)
+            if option.startswith("x-prop-"):
+                prop_found = False
+                for prop, xrandr_prop in [(re.sub(r"\W+", "_", p.lower()), p) for p in properties]:
+                    if prop == option[7:]:
+                        args.append("--set")
+                        args.append(xrandr_prop)
+                        prop_found = True
+                        break
+                if not prop_found:
+                    print("Warning: Unknown property `%s' in config file. Skipping." % option[7:], file=sys.stderr)
+                    continue
+            elif option.startswith("x-"):
+                print("Warning: Unknown option `%s' in config file. Skipping." % option, file=sys.stderr)
+                continue
+            else:
+                args.append("--%s" % option)
             if arg:
                 args.append(arg)
         return args
@@ -394,6 +430,9 @@ class XrandrOutput(object):
                 options["crtc"] = match["crtc"]
             if match["rate"]:
                 options["rate"] = match["rate"]
+            for prop in [re.sub(r"\W+", "_", p.lower()) for p in properties]:
+                if match[prop]:
+                    options["x-prop-" + prop] = match[prop]
 
         return XrandrOutput(match["output"], edid, options), modes
 
@@ -610,7 +649,7 @@ def update_profiles_edid(profiles, config):
         profile_config = profiles[p]["config"]
 
         for edid in edid_map:
-            for c in profile_config.keys():
+            for c in list(profile_config.keys()):
                 if profile_config[c].edid != edid or c == edid_map[edid]:
                     continue
 
@@ -645,7 +684,8 @@ def find_profiles(current_config, profiles):
         if not matches or any((name not in config.keys() for name in current_config.keys() if current_config[name].edid)):
             continue
         if matches:
-            closeness = max(match_asterisk(output.edid, current_config[name].edid), match_asterisk(current_config[name].edid, output.edid))
+            closeness = max(match_asterisk(output.edid, current_config[name].edid), match_asterisk(
+                current_config[name].edid, output.edid))
             detected_profiles.append((closeness, profile_name))
     detected_profiles = [o[1] for o in sorted(detected_profiles, key=lambda x: -x[0])]
     return detected_profiles
@@ -719,23 +759,22 @@ def call_and_retry(*args, **kwargs):
     waits a second and then retries once. This mitigates #47,
     a timing issue with some drivers.
     """
-    if "dry_run" in kwargs:
-        dry_run = kwargs["dry_run"]
-        del kwargs["dry_run"]
+    if kwargs.pop("dry_run", False):
+        for arg in args[0]:
+            print(shlex.quote(arg), end=" ")
+        print()
+        return 0
     else:
-        dry_run = False
-    kwargs_redirected = dict(kwargs)
-    if not dry_run:
         if hasattr(subprocess, "DEVNULL"):
-            kwargs_redirected["stdout"] = getattr(subprocess, "DEVNULL")
+            kwargs["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)
+            kwargs["stdout"] = open(os.devnull, "w")
+        kwargs["stderr"] = kwargs["stdout"]
         retval = subprocess.call(*args, **kwargs)
-    return retval
+        if retval != 0:
+            time.sleep(1)
+            retval = subprocess.call(*args, **kwargs)
+        return retval
 
 
 def get_fb_dimensions(configuration):
@@ -780,10 +819,7 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False)
     found_left_monitor = False
     found_top_monitor = False
     outputs = sorted(new_configuration.keys(), key=lambda x: new_configuration[x].sort_key)
-    if dry_run:
-        base_argv = ["echo", "xrandr"]
-    else:
-        base_argv = ["xrandr"]
+    base_argv = ["xrandr"]
 
     # There are several xrandr / driver bugs we need to take care of here:
     # - We cannot enable more than two screens at the same time