import posix
import pwd
import re
+import shlex
import subprocess
import sys
import shutil
("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]
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
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*
"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
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
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
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):
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