]> git.donarmstrong.com Git - deb_pkgs/autorandr.git/blobdiff - autorandr.py
New upstream version 1.14
[deb_pkgs/autorandr.git] / autorandr.py
index a23d1a6089911b758fd5a13572584f539d95e635..93b4e79ca09a13ac621bffa92f6302d508d60bdf 100755 (executable)
@@ -44,17 +44,13 @@ from collections import OrderedDict
 from functools import reduce
 from itertools import chain
 
-try:
-    from packaging.version import Version
-except ModuleNotFoundError:
-    from distutils.version import LooseVersion as Version
 
 if sys.version_info.major == 2:
     import ConfigParser as configparser
 else:
     import configparser
 
-__version__ = "1.12.1"
+__version__ = "1.14"
 
 try:
     input = raw_input
@@ -104,7 +100,7 @@ Usage: autorandr [options]
 --dry-run               don't change anything, only print the xrandr commands
 --fingerprint           fingerprint your current hardware setup
 --ignore-lid            treat outputs as connected even if their lids are closed
---match-edid            match diplays based on edid instead of name
+--match-edid            match displays based on edid instead of name
 --force                 force (re)loading of a profile / overwrite exiting files
 --list                  list configurations
 --skip-options <option> comma separated list of xrandr arguments (e.g. "gamma")
@@ -122,6 +118,35 @@ Usage: autorandr [options]
 """.strip()
 
 
+class Version(object):
+    def __init__(self, version):
+        self._version = version
+        self._version_parts = re.split("([0-9]+)", version)
+
+    def __eq__(self, other):
+        return self._version_parts == other._version_parts
+
+    def __lt__(self, other):
+        for my, theirs in zip(self._version_parts, other._version_parts):
+            if my.isnumeric() and theirs.isnumeric():
+                my = int(my)
+                theirs = int(theirs)
+            if my < theirs:
+                return True
+        return len(theirs) > len(my)
+
+    def __ge__(self, other):
+        return not (self < other)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def __le__(self, other):
+        return (self < other) or (self == other)
+
+    def __gt__(self, other):
+        return self >= other and not (self == other)
+
 def is_closed_lid(output):
     if not re.match(r'(eDP(-?[0-9]\+)*|LVDS(-?[0-9]\+)*)', output):
         return False
@@ -321,7 +346,7 @@ class XrandrOutput(object):
         return x + 10000 * y
 
     def __init__(self, output, edid, options):
-        "Instanciate using output name, edid and a dictionary of XRandR command line parameters"
+        "Instantiate using output name, edid and a dictionary of XRandR command line parameters"
         self.output = output
         self.edid = edid
         self.options = options
@@ -334,6 +359,8 @@ class XrandrOutput(object):
         if self.edid:
             if self.EDID_UNAVAILABLE in self.edid:
                 return
+            if "*" in self.edid:
+                return
             # Thx to pyedid project, the following code was
             # copied (and modified) from pyedid/__init__py:21 [parse_edid()]
             raw = bytes.fromhex(self.edid)
@@ -359,7 +386,7 @@ class XrandrOutput(object):
         self.ignored_options = list(options)
 
     def remove_default_option_values(self):
-        "Remove values from the options dictionary that are superflous"
+        "Remove values from the options dictionary that are superfluous"
         if "off" in self.options and len(self.options.keys()) > 1:
             self.options = {"off": None}
             return
@@ -369,7 +396,7 @@ class XrandrOutput(object):
 
     @classmethod
     def from_xrandr_output(cls, xrandr_output):
-        """Instanciate an XrandrOutput from the output of `xrandr --verbose'
+        """Instantiate an XrandrOutput from the output of `xrandr --verbose'
 
         This method also returns a list of modes supported by the output.
         """
@@ -476,7 +503,7 @@ class XrandrOutput(object):
 
     @classmethod
     def from_config_file(cls, profile, edid_map, configuration):
-        "Instanciate an XrandrOutput from the contents of a configuration file"
+        "Instantiate an XrandrOutput from the contents of a configuration file"
         options = {}
         for line in configuration.split("\n"):
             if line:
@@ -601,7 +628,7 @@ def parse_xrandr_output(
     # We are not interested in screens
     xrandr_output = re.sub("(?m)^Screen [0-9].+", "", xrandr_output).strip()
 
-    # Split at output boundaries and instanciate an XrandrOutput per output
+    # Split at output boundaries and instantiate an XrandrOutput per output
     split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output)
     if len(split_xrandr_output) < 2:
         raise AutorandrException("No output boundaries found", report_bug=True)
@@ -708,7 +735,7 @@ def update_profiles_edid(profiles, config):
                 if profile_config[c].fingerprint != fingerprint or c == fp_map[fingerprint]:
                     continue
 
-                print("%s: renaming display %s to %s" % (p, c, fp_map[fingerprint]))
+                print("%s: renaming display %s to %s" % (p, c, fp_map[fingerprint]), file=sys.stderr)
 
                 tmp_disp = profile_config[c]
 
@@ -978,7 +1005,7 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False)
     # If we did not find a candidate, we might need to inject a call
     # If there is no output to disable, we will enable 0x and x0 at the same time
     if not found_top_left_monitor and len(disable_outputs) > 0:
-        # If the call to 0x and x0 is splitted, inject one of them
+        # If the call to 0x and x0 is split, inject one of them
         if found_top_monitor and found_left_monitor:
             enable_outputs.insert(0, enable_outputs[0])
 
@@ -989,6 +1016,13 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False)
         if call_and_retry(argv, dry_run=dry_run) != 0:
             raise AutorandrException("Command failed: %s" % " ".join(map(shlex.quote, argv)))
 
+    # Adjust the frame buffer to match (see #319)
+    if fb_args:
+        argv = base_argv
+        if call_and_retry(argv, dry_run=dry_run) != 0:
+            raise AutorandrException("Command failed: %s" % " ".join(map(shlex.quote, argv)))
+
+
 
 def is_equal_configuration(source_configuration, target_configuration):
     """
@@ -1054,7 +1088,7 @@ def generate_virtual_profile(configuration, modes, profile_name):
                     configuration[output].options["off"] = None
     elif profile_name in ("horizontal", "vertical", "horizontal-reverse", "vertical-reverse"):
         shift = 0
-        if profile_name == "horizontal":
+        if profile_name.startswith("horizontal"):
             shift_index = "width"
             pos_specifier = "%sx0"
         else:
@@ -1185,8 +1219,8 @@ def exec_scripts(profile_path, script_name, meta_information=None):
             if os.access(script, os.X_OK | os.F_OK):
                 try:
                     all_ok &= subprocess.call(script, env=env) != 0
-                except:
-                    raise AutorandrException("Failed to execute user command: %s" % (script,))
+                except Exception as e:
+                    raise AutorandrException("Failed to execute user command: %s. Error: %s" % (script, str(e)))
                 ran_scripts.add(script_name)
 
         script_folder = os.path.join(folder, "%s.d" % script_name)
@@ -1198,8 +1232,8 @@ def exec_scripts(profile_path, script_name, meta_information=None):
                     if os.access(script, os.X_OK | os.F_OK):
                         try:
                             all_ok &= subprocess.call(script, env=env) != 0
-                        except:
-                            raise AutorandrException("Failed to execute user command: %s" % (script,))
+                        except Exception as e:
+                            raise AutorandrException("Failed to execute user command: %s. Error: %s" % (script, str(e)))
                         ran_scripts.add(check_name)
 
     return all_ok
@@ -1291,6 +1325,11 @@ def dispatch_call_to_sessions(argv):
             # Cannot work with this environment, skip.
             continue
 
+        if "WAYLAND_DISPLAY" in process_environ and process_environ["WAYLAND_DISPLAY"]:
+            if "--debug" in argv:
+                print("Detected Wayland session '{0}'. Skipping.".format(process_environ["WAYLAND_DISPLAY"]))
+            continue
+
         # To allow scripts to detect batch invocation (especially useful for predetect)
         process_environ["AUTORANDR_BATCH_PID"] = str(os.getpid())
         process_environ["UID"] = str(uid)
@@ -1403,6 +1442,9 @@ def main(argv):
         user = pwd.getpwuid(os.getuid())
         user = user.pw_name if user else "#%d" % os.getuid()
         print("autorandr running as user %s (started from batch instance)" % user)
+    if ("WAYLAND_DISPLAY" in os.environ and os.environ["WAYLAND_DISPLAY"]):
+        print("Detected Wayland session '{0}'. Exiting.".format(os.environ["WAYLAND_DISPLAY"]), file=sys.stderr)
+        sys.exit(1)
 
     profiles = {}
     profile_symlinks = {}