+ return self.edid_equals(other) and self.output == other.output and self.filtered_options == other.filtered_options
+
+ def verbose_diff(self, other):
+ "Compare to another XrandrOutput and return a list of human readable differences"
+ diffs = []
+ if not self.edid_equals(other):
+ diffs.append("EDID `%s' differs from `%s'" % (self.short_edid, other.short_edid))
+ if self.output != other.output:
+ diffs.append("Output name `%s' differs from `%s'" % (self.output, other.output))
+ if "off" in self.options and "off" not in other.options:
+ diffs.append("The output is disabled currently, but active in the new configuration")
+ elif "off" in other.options and "off" not in self.options:
+ diffs.append("The output is currently enabled, but inactive in the new configuration")
+ else:
+ for name in set(chain.from_iterable((self.options.keys(), other.options.keys()))):
+ if name not in other.options:
+ diffs.append("Option --%s %sis not present in the new configuration" % (name, "(= `%s') " % self.options[name] if self.options[name] else ""))
+ elif name not in self.options:
+ diffs.append("Option --%s (`%s' in the new configuration) is not present currently" % (name, other.options[name]))
+ elif self.options[name] != other.options[name]:
+ diffs.append("Option --%s %sis `%s' in the new configuration" % (name, "(= `%s') " % self.options[name] if self.options[name] else "", other.options[name]))
+ return diffs
+
+def xrandr_version():
+ "Return the version of XRandR that this system uses"
+ if getattr(xrandr_version, "version", False) is False:
+ version_string = os.popen("xrandr -v").read()
+ try:
+ version = re.search("xrandr program version\s+([0-9\.]+)", version_string).group(1)
+ xrandr_version.version = Version(version)
+ except AttributeError:
+ xrandr_version.version = Version("1.3.0")
+
+ return xrandr_version.version
+
+def debug_regexp(pattern, string):
+ "Use the partial matching functionality of the regex module to display debug info on a non-matching regular expression"
+ try:
+ import regex
+ bounds = ( 0, len(string) )
+ while bounds[0] != bounds[1]:
+ half = int((bounds[0] + bounds[1]) / 2)
+ if half == bounds[0]:
+ break
+ bounds = (half, bounds[1]) if regex.search(pattern, string[:half], partial=True) else (bounds[0], half - 1)
+ partial_length = bounds[0]
+ return ("Regular expression matched until position "
+ "%d, ..'%s', and did not match from '%s'.." % (partial_length, string[max(0, partial_length-20):partial_length],
+ string[partial_length:partial_length+10]))
+ except ImportError:
+ pass
+ return "Debug information would be available if the `regex' module was installed."