Python version: Support reflections, parse output modes (for virtual profiles)

This commit is contained in:
Phillip Berndt 2015-01-07 11:25:20 +01:00
parent 2d0a702e25
commit aeb5b97b28
1 changed files with 52 additions and 13 deletions

View File

@ -79,7 +79,9 @@ class XrandrOutput(object):
(?P<primary>primary\ )? # Might be primary screen (?P<primary>primary\ )? # Might be primary screen
(?P<width>[0-9]+)x(?P<height>[0-9]+) # Resolution (?P<width>[0-9]+)x(?P<height>[0-9]+) # Resolution
\+(?P<x>[0-9]+)\+(?P<y>[0-9]+)\s+ # Position \+(?P<x>[0-9]+)\+(?P<y>[0-9]+)\s+ # Position
(?P<rotation>[^(]\S+)? # Has a value if the output is rotated (?:\(0x[0-9a-fA-F]+\)\s+)? # XID
(?P<rotate>(?:normal|left|right|inverted))\s+ # Rotation
(?:(?P<reflect>X\ and\ Y|X|Y)\ axis)? # Reflection
).* ).*
(?:\s*(?: # Properties of the output (?:\s*(?: # Properties of the output
Gamma: (?P<gamma>[0-9\.:\s]+) | # Gamma value Gamma: (?P<gamma>[0-9\.:\s]+) | # Gamma value
@ -88,12 +90,20 @@ class XrandrOutput(object):
(?![0-9])[^:\s][^:\n]+:.*(?:\s\\t[\\t ].+)* # Other properties (?![0-9])[^:\s][^:\n]+:.*(?:\s\\t[\\t ].+)* # Other properties
))+ ))+
\s* \s*
(?: [0-9]+x[0-9]+.+?\*current.+\s+h:.+\s+v:.+clock\s+(?P<rate>[0-9\.]+)Hz\s* | # Interesting (current) resolution: Extract rate (?P<modes>(?:
[0-9]+x[0-9]+.+?\*current.+\s+h:.+\s+v:.+clock\s+(?P<rate>[0-9\.]+)Hz\s* | # Interesting (current) resolution: Extract rate
[0-9]+x[0-9]+.+\s+h:.+\s+v:.+\s* # Other resolutions [0-9]+x[0-9]+.+\s+h:.+\s+v:.+\s* # Other resolutions
)* )*)
$ $
""" """
XRANDR_OUTPUT_MODES_REGEXP = """(?x)
(?P<width>[0-9]+)x(?P<height>[0-9]+)
.*?(?P<preferred>\+preferred)?
\s+h:.+
\s+v:.+clock\s+(?P<rate>[0-9\.]+)Hz
"""
def __repr__(self): def __repr__(self):
return "<%s%s %s>" % (self.output, (" %s..%s" % (self.edid[:5], self.edid[-5:])) if self.edid else "", " ".join(self.option_vector)) return "<%s%s %s>" % (self.output, (" %s..%s" % (self.edid[:5], self.edid[-5:])) if self.edid else "", " ".join(self.option_vector))
@ -126,22 +136,45 @@ class XrandrOutput(object):
@classmethod @classmethod
def from_xrandr_output(cls, xrandr_output): def from_xrandr_output(cls, xrandr_output):
"Instanciate an XrandrOutput from the output of `xrandr --verbose'" """Instanciate an XrandrOutput from the output of `xrandr --verbose'
This method also returns a list of modes supported by the output.
"""
try:
match_object = re.search(XrandrOutput.XRANDR_OUTPUT_REGEXP, xrandr_output) match_object = re.search(XrandrOutput.XRANDR_OUTPUT_REGEXP, xrandr_output)
except:
raise RuntimeError("Parsing XRandR output failed, there is an error in the regular expression.")
if not match_object:
raise RuntimeError("Parsing XRandR output failed, the regular expression did not match.")
remainder = xrandr_output[len(match_object.group(0)):] remainder = xrandr_output[len(match_object.group(0)):]
if remainder: if remainder:
raise RuntimeError("Parsing XRandR output failed, %d bytes left." % len(remainder)) raise RuntimeError("Parsing XRandR output failed, %d bytes left unmatched after regular expression." % len(remainder))
match = match_object.groupdict() match = match_object.groupdict()
modes = []
if match["modes"]:
modes = [ x.groupdict() for x in re.finditer(XrandrOutput.XRANDR_OUTPUT_MODES_REGEXP, match["modes"]) ]
options = {} options = {}
if not match["connected"]: if not match["connected"]:
options["off"] = None options["off"] = None
edid = None edid = None
else: else:
if not match["rotation"]: if match["rotate"] not in ("left", "right"):
options["mode"] = "%sx%s" % (match["width"], match["height"]) options["mode"] = "%sx%s" % (match["width"], match["height"])
else: else:
options["mode"] = "%sx%s" % (match["height"], match["width"]) options["mode"] = "%sx%s" % (match["height"], match["width"])
options["rotate"] = match["rotate"]
options["reflect"] = "normal"
if "reflect" in match:
if match["reflect"] == "X":
options["reflect"] = "x"
elif match["reflect"] == "Y":
options["reflect"] = "y"
elif match["reflect"] == "X and Y":
options["reflect"] = "xy"
options["pos"] = "%sx%s" % (match["x"], match["y"]) options["pos"] = "%sx%s" % (match["x"], match["y"])
if match["transform"]: if match["transform"]:
transformation = ",".join(match["transform"].strip().split()) transformation = ",".join(match["transform"].strip().split())
@ -157,7 +190,7 @@ class XrandrOutput(object):
options["rate"] = match["rate"] options["rate"] = match["rate"]
edid = "".join(match["edid"].strip().split()) edid = "".join(match["edid"].strip().split())
return XrandrOutput(match["output"], edid, options) return XrandrOutput(match["output"], edid, options), modes
@classmethod @classmethod
def from_config_file(cls, edid_map, configuration): def from_config_file(cls, edid_map, configuration):
@ -206,9 +239,15 @@ def parse_xrandr_output():
# Split at output boundaries and instanciate an XrandrOutput per output # Split at output boundaries and instanciate an XrandrOutput per output
split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output) split_xrandr_output = re.split("(?m)^([^ ]+ (?:(?:dis)?connected|unknown connection).*)$", xrandr_output)
outputs = { split_xrandr_output[i].split()[0]: XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i+2])) for i in range(1, len(split_xrandr_output), 2) } outputs = {}
modes = {}
for i in range(1, len(split_xrandr_output), 2):
output_name = split_xrandr_output[i].split()[0]
output, output_modes = XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i+2]))
outputs[output_name] = output
modes[output_name] = output_modes
return outputs return outputs, modes
def load_profiles(profile_path): def load_profiles(profile_path):
"Load the stored profiles" "Load the stored profiles"
@ -318,7 +357,7 @@ def main(argv):
profile_path = os.path.expanduser("~/.autorandr") profile_path = os.path.expanduser("~/.autorandr")
profiles = load_profiles(profile_path) profiles = load_profiles(profile_path)
config = parse_xrandr_output() config, modes = parse_xrandr_output()
if "--fingerprint" in options: if "--fingerprint" in options:
output_setup(config, sys.stdout) output_setup(config, sys.stdout)