]> git.donarmstrong.com Git - deb_pkgs/autorandr.git/blobdiff - autorandr.py
Merge pull request #85 from christophgysin/load-shorthand
[deb_pkgs/autorandr.git] / autorandr.py
index f8b3ae8a5a96e006052243797950c824963c2d4b..e5ab42fdd0308695e720b6ada0415ccdd8751c0e 100755 (executable)
@@ -90,6 +90,7 @@ Usage: autorandr [options]
  The following virtual configurations are available:
 """.strip()
 
+
 class AutorandrException(Exception):
     def __init__(self, message, original_exception=None, report_bug=False):
         self.message = message
@@ -116,7 +117,7 @@ class AutorandrException(Exception):
             self.file_name = None
 
     def __str__(self):
-        retval = [ self.message ]
+        retval = [self.message]
         if self.line:
             retval.append(" (line %d%s)" % (self.line, ("; %s" % self.file_name) if self.file_name else ""))
         if self.original_exception:
@@ -125,9 +126,10 @@ class AutorandrException(Exception):
         if self.report_bug:
             retval.append("\nThis appears to be a bug. Please help improving autorandr by reporting it upstream:"
                           "\nhttps://github.com/phillipberndt/autorandr/issues"
-                         "\nPlease attach the output of `xrandr --verbose` to your bug report if appropriate.")
+                          "\nPlease attach the output of `xrandr --verbose` to your bug report if appropriate.")
         return "".join(retval)
 
+
 class XrandrOutput(object):
     "Represents an XRandR output"
 
@@ -206,12 +208,12 @@ class XrandrOutput(object):
         if xrandr_version() >= Version("1.2"):
             options.update(self.XRANDR_12_DEFAULTS)
         options.update(self.options)
-        return { a: b for a, b in options.items() if a not in self.ignored_options }
+        return {a: b for a, b in options.items() if a not in self.ignored_options}
 
     @property
     def filtered_options(self):
         "Return a dictionary of options without ignored options"
-        return { a: b for a, b in self.options.items() if a not in self.ignored_options }
+        return {a: b for a, b in self.options.items() if a not in self.ignored_options}
 
     @property
     def option_vector(self):
@@ -221,7 +223,7 @@ class XrandrOutput(object):
     @property
     def option_string(self):
         "Return the command line parameters in the configuration file format"
-        return "\n".join([ " ".join(option) if option[1] else option[0] for option in chain((("output", self.output),), sorted(self.filtered_options.items()))])
+        return "\n".join([" ".join(option) if option[1] else option[0] for option in chain((("output", self.output),), sorted(self.filtered_options.items()))])
 
     @property
     def sort_key(self):
@@ -251,7 +253,7 @@ class XrandrOutput(object):
     def remove_default_option_values(self):
         "Remove values from the options dictionary that are superflous"
         if "off" in self.options and len(self.options.keys()) > 1:
-            self.options = { "off": None }
+            self.options = {"off": None}
             return
         for option, default_value in self.XRANDR_DEFAULTS.items():
             if option in self.options and self.options[option] == default_value:
@@ -267,20 +269,20 @@ class XrandrOutput(object):
             xrandr_output = xrandr_output.replace("\r\n", "\n")
             match_object = re.search(XrandrOutput.XRANDR_OUTPUT_REGEXP, xrandr_output)
         except:
-            raise AutorandrException("Parsing XRandR output failed, there is an error in the regular expression.", report_bug = True)
+            raise AutorandrException("Parsing XRandR output failed, there is an error in the regular expression.", report_bug=True)
         if not match_object:
             debug = debug_regexp(XrandrOutput.XRANDR_OUTPUT_REGEXP, xrandr_output)
-            raise AutorandrException("Parsing XRandR output failed, the regular expression did not match: %s" % debug, report_bug = True)
+            raise AutorandrException("Parsing XRandR output failed, the regular expression did not match: %s" % debug, report_bug=True)
         remainder = xrandr_output[len(match_object.group(0)):]
         if remainder:
             raise AutorandrException(("Parsing XRandR output failed, %d bytes left unmatched after regular expression, "
-                                "starting at byte %d with ..'%s'.") % (len(remainder), len(match_object.group(0)), remainder[:10]), report_bug=True)
+                                      "starting at byte %d with ..'%s'.") % (len(remainder), len(match_object.group(0)), remainder[:10]), report_bug=True)
 
         match = match_object.groupdict()
 
         modes = []
         if match["modes"]:
-            modes = [ x.groupdict() for x in re.finditer(XrandrOutput.XRANDR_OUTPUT_MODES_REGEXP, match["modes"]) if x.group("name") ]
+            modes = [x.groupdict() for x in re.finditer(XrandrOutput.XRANDR_OUTPUT_MODES_REGEXP, match["modes"]) if x.group("name")]
             if not modes:
                 raise AutorandrException("Parsing XRandR output failed, couldn't find any display modes", report_bug=True)
 
@@ -313,11 +315,11 @@ class XrandrOutput(object):
                 options["reflect"] = "xy"
             options["pos"] = "%sx%s" % (match["x"], match["y"])
             if match["panning"]:
-                panning = [ match["panning"] ]
+                panning = [match["panning"]]
                 if match["tracking"]:
-                    panning += [ "/", match["tracking"] ]
+                    panning += ["/", match["tracking"]]
                     if match["border"]:
-                        panning += [ "/", match["border"] ]
+                        panning += ["/", match["border"]]
                 options["panning"] = "".join(panning)
             if match["transform"]:
                 transformation = ",".join(match["transform"].strip().split())
@@ -332,7 +334,7 @@ class XrandrOutput(object):
                 # xrandr prints different values in --verbose than it accepts as a parameter value for --gamma
                 # Also, it is not able to work with non-standard gamma ramps. Finally, it auto-corrects 0 to 1,
                 # so we approximate by 1e-10.
-                gamma = ":".join([ str(max(1e-10, round(1./float(x), 3))) for x in gamma.split(":") ])
+                gamma = ":".join([str(max(1e-10, round(1. / float(x), 3))) for x in gamma.split(":")])
                 options["gamma"] = gamma
             if match["rate"]:
                 options["rate"] = match["rate"]
@@ -356,7 +358,7 @@ class XrandrOutput(object):
             edid = edid_map[options["output"]]
         else:
             # This fuzzy matching is for legacy autorandr that used sysfs output names
-            fuzzy_edid_map = [ re.sub("(card[0-9]+|-)", "", x) for x in edid_map.keys() ]
+            fuzzy_edid_map = [re.sub("(card[0-9]+|-)", "", x) for x in edid_map.keys()]
             fuzzy_output = re.sub("(card[0-9]+|-)", "", options["output"])
             if fuzzy_output in fuzzy_edid_map:
                 edid = edid_map[list(edid_map.keys())[fuzzy_edid_map.index(fuzzy_output)]]
@@ -403,6 +405,7 @@ class XrandrOutput(object):
                     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:
@@ -415,11 +418,12 @@ def xrandr_version():
 
     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) )
+        bounds = (0, len(string))
         while bounds[0] != bounds[1]:
             half = int((bounds[0] + bounds[1]) / 2)
             if half == bounds[0]:
@@ -427,12 +431,13 @@ def debug_regexp(pattern, string):
             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]))
+                "%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."
 
+
 def parse_xrandr_output():
     "Parse the output of `xrandr --verbose' into a list of outputs"
     xrandr_output = os.popen("xrandr -q --verbose").read()
@@ -450,31 +455,32 @@ def parse_xrandr_output():
     modes = OrderedDict()
     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]))
+        output, output_modes = XrandrOutput.from_xrandr_output("".join(split_xrandr_output[i:i + 2]))
         outputs[output_name] = output
         if output_modes:
             modes[output_name] = output_modes
 
     return outputs, modes
 
+
 def load_profiles(profile_path):
     "Load the stored profiles"
 
     profiles = {}
     for profile in os.listdir(profile_path):
         config_name = os.path.join(profile_path, profile, "config")
-        setup_name  = os.path.join(profile_path, profile, "setup")
+        setup_name = os.path.join(profile_path, profile, "setup")
         if not os.path.isfile(config_name) or not os.path.isfile(setup_name):
             continue
 
-        edids = dict([ x.split() for x in (y.strip() for y in open(setup_name).readlines()) if x and x[0] != "#" ])
+        edids = dict([x.split() for x in (y.strip() for y in open(setup_name).readlines()) if x and x[0] != "#"])
 
         config = {}
         buffer = []
         for line in chain(open(config_name).readlines(), ["output"]):
             if line[:6] == "output" and buffer:
                 config[buffer[0].strip().split()[-1]] = XrandrOutput.from_config_file(edids, "".join(buffer))
-                buffer = [ line ]
+                buffer = [line]
             else:
                 buffer.append(line)
 
@@ -482,10 +488,11 @@ def load_profiles(profile_path):
             if config[output_name].edid is None:
                 del config[output_name]
 
-        profiles[profile] = { "config": config, "path": os.path.join(profile_path, profile), "config-mtime": os.stat(config_name).st_mtime }
+        profiles[profile] = {"config": config, "path": os.path.join(profile_path, profile), "config-mtime": os.stat(config_name).st_mtime}
 
     return profiles
 
+
 def get_symlinks(profile_path):
     "Load all symlinks from a directory"
 
@@ -497,6 +504,7 @@ def get_symlinks(profile_path):
 
     return symlinks
 
+
 def find_profiles(current_config, profiles):
     "Find profiles matching the currently connected outputs"
     detected_profiles = []
@@ -509,12 +517,13 @@ def find_profiles(current_config, profiles):
             if name not in current_config or not output.edid_equals(current_config[name]):
                 matches = False
                 break
-        if not matches or any(( name not in config.keys() for name in current_config.keys() if current_config[name].edid )):
+        if not matches or any((name not in config.keys() for name in current_config.keys() if current_config[name].edid)):
             continue
         if matches:
             detected_profiles.append(profile_name)
     return detected_profiles
 
+
 def profile_blocked(profile_path, meta_information=None):
     """Check if a profile is blocked.
 
@@ -523,12 +532,14 @@ def profile_blocked(profile_path, meta_information=None):
     """
     return not exec_scripts(profile_path, "block", meta_information)
 
+
 def output_configuration(configuration, config):
     "Write a configuration file"
     outputs = sorted(configuration.keys(), key=lambda x: configuration[x].sort_key)
     for output in outputs:
         print(configuration[output].option_string, file=config)
 
+
 def output_setup(configuration, setup):
     "Write a setup (fingerprint) file"
     outputs = sorted(configuration.keys())
@@ -536,6 +547,7 @@ def output_setup(configuration, setup):
         if configuration[output].edid:
             print(output, configuration[output].edid, file=setup)
 
+
 def save_configuration(profile_path, configuration):
     "Save a configuration into a profile"
     if not os.path.isdir(profile_path):
@@ -545,6 +557,7 @@ def save_configuration(profile_path, configuration):
     with open(os.path.join(profile_path, "setup"), "w") as setup:
         output_setup(configuration, setup)
 
+
 def update_mtime(filename):
     "Update a file's mtime"
     try:
@@ -553,6 +566,7 @@ def update_mtime(filename):
     except:
         return False
 
+
 def call_and_retry(*args, **kwargs):
     """Wrapper around subprocess.call that retries failed calls.
 
@@ -578,13 +592,14 @@ def call_and_retry(*args, **kwargs):
         retval = subprocess.call(*args, **kwargs)
     return retval
 
+
 def apply_configuration(new_configuration, current_configuration, dry_run=False):
     "Apply a configuration"
     outputs = sorted(new_configuration.keys(), key=lambda x: new_configuration[x].sort_key)
     if dry_run:
-        base_argv = [ "echo", "xrandr" ]
+        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
@@ -625,8 +640,8 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False)
                     else:
                         try:
                             option_index = option_vector.index("--%s" % option)
-                            if option_vector[option_index+1] == XrandrOutput.XRANDR_DEFAULTS[option]:
-                                option_vector = option_vector[:option_index] + option_vector[option_index+2:]
+                            if option_vector[option_index + 1] == XrandrOutput.XRANDR_DEFAULTS[option]:
+                                option_vector = option_vector[:option_index] + option_vector[option_index + 2:]
                         except ValueError:
                             pass
 
@@ -659,10 +674,11 @@ def apply_configuration(new_configuration, current_configuration, dry_run=False)
     # Enable the remaining outputs in pairs of two operations
     operations = disable_outputs + enable_outputs
     for index in range(0, len(operations), 2):
-        argv = base_argv + list(chain.from_iterable(operations[index:index+2]))
+        argv = base_argv + list(chain.from_iterable(operations[index:index + 2]))
         if call_and_retry(argv, dry_run=dry_run) != 0:
             raise AutorandrException("Command failed: %s" % " ".join(argv))
 
+
 def is_equal_configuration(source_configuration, target_configuration):
     "Check if all outputs from target are already configured correctly in source"
     for output in target_configuration.keys():
@@ -670,11 +686,13 @@ def is_equal_configuration(source_configuration, target_configuration):
             return False
     return True
 
+
 def add_unused_outputs(source_configuration, target_configuration):
     "Add outputs that are missing in target to target, in 'off' state"
     for output_name, output in source_configuration.items():
         if output_name not in target_configuration:
-            target_configuration[output_name] = XrandrOutput(output_name, output.edid, { "off": None })
+            target_configuration[output_name] = XrandrOutput(output_name, output.edid, {"off": None})
+
 
 def remove_irrelevant_outputs(source_configuration, target_configuration):
     "Remove outputs from target that ought to be 'off' and already are"
@@ -682,18 +700,19 @@ def remove_irrelevant_outputs(source_configuration, target_configuration):
         if "off" in output.options and output_name in target_configuration and "off" in target_configuration[output_name].options:
             del target_configuration[output_name]
 
+
 def generate_virtual_profile(configuration, modes, profile_name):
     "Generate one of the virtual profiles"
     configuration = copy.deepcopy(configuration)
     if profile_name == "common":
-        common_resolution = [ set(( ( mode["width"], mode["height"] ) for mode in output_modes )) for output, output_modes in modes.items() if configuration[output].edid ]
+        common_resolution = [set(((mode["width"], mode["height"]) for mode in output_modes)) for output, output_modes in modes.items() if configuration[output].edid]
         common_resolution = reduce(lambda a, b: a & b, common_resolution[1:], common_resolution[0])
-        common_resolution = sorted(common_resolution, key=lambda a: int(a[0])*int(a[1]))
+        common_resolution = sorted(common_resolution, key=lambda a: int(a[0]) * int(a[1]))
         if common_resolution:
             for output in configuration:
                 configuration[output].options = {}
                 if output in modes and configuration[output].edid:
-                    configuration[output].options["mode"] = [ x["name"] for x in sorted(modes[output], key=lambda x: 0 if x["preferred"] else 1) if x["width"] == common_resolution[-1][0] and x["height"] == common_resolution[-1][1] ][0]
+                    configuration[output].options["mode"] = [x["name"] for x in sorted(modes[output], key=lambda x: 0 if x["preferred"] else 1) if x["width"] == common_resolution[-1][0] and x["height"] == common_resolution[-1][1]][0]
                     configuration[output].options["pos"] = "0x0"
                 else:
                     configuration[output].options["off"] = None
@@ -709,7 +728,7 @@ def generate_virtual_profile(configuration, modes, profile_name):
         for output in configuration:
             configuration[output].options = {}
             if output in modes and configuration[output].edid:
-                mode = sorted(modes[output], key=lambda a: int(a["width"])*int(a["height"]) + (10**6 if a["preferred"] else 0))[-1]
+                mode = sorted(modes[output], key=lambda a: int(a["width"]) * int(a["height"]) + (10**6 if a["preferred"] else 0))[-1]
                 configuration[output].options["mode"] = mode["name"]
                 configuration[output].options["rate"] = mode["rate"]
                 configuration[output].options["pos"] = pos_specifier % shift
@@ -717,22 +736,23 @@ def generate_virtual_profile(configuration, modes, profile_name):
             else:
                 configuration[output].options["off"] = None
     elif profile_name == "clone-largest":
-        biggest_resolution = sorted([output_modes[0] for output, output_modes in modes.items()], key=lambda x: int(x["width"])*int(x["height"]), reverse=True)[0]
+        biggest_resolution = sorted([output_modes[0] for output, output_modes in modes.items()], key=lambda x: int(x["width"]) * int(x["height"]), reverse=True)[0]
         for output in configuration:
             configuration[output].options = {}
             if output in modes and configuration[output].edid:
-                mode = sorted(modes[output], key=lambda a: int(a["width"])*int(a["height"]) + (10**6 if a["preferred"] else 0))[-1]
+                mode = sorted(modes[output], key=lambda a: int(a["width"]) * int(a["height"]) + (10**6 if a["preferred"] else 0))[-1]
                 configuration[output].options["mode"] = mode["name"]
                 configuration[output].options["rate"] = mode["rate"]
                 configuration[output].options["pos"] = "0x0"
-                scale = max(float(biggest_resolution["width"]) / float(mode["width"]) ,float(biggest_resolution["height"]) / float(mode["height"]))
-                mov_x = (float(mode["width"])*scale-float(biggest_resolution["width"]))/-2
-                mov_y = (float(mode["height"])*scale-float(biggest_resolution["height"]))/-2
+                scale = max(float(biggest_resolution["width"]) / float(mode["width"])float(biggest_resolution["height"]) / float(mode["height"]))
+                mov_x = (float(mode["width"]) * scale - float(biggest_resolution["width"])) / -2
+                mov_y = (float(mode["height"]) * scale - float(biggest_resolution["height"])) / -2
                 configuration[output].options["transform"] = "{},0,{},0,{},{},0,0,1".format(scale, mov_x, scale, mov_y)
             else:
                 configuration[output].options["off"] = None
     return configuration
 
+
 def print_profile_differences(one, another):
     "Print the differences between two profiles for debugging"
     if one == another:
@@ -748,15 +768,16 @@ def print_profile_differences(one, another):
         else:
             for line in one[output].verbose_diff(another[output]):
                 print("| [Output %s] %s" % (output, line), file=sys.stderr)
-    print ("\\-", file=sys.stderr)
+    print("\\-", file=sys.stderr)
+
 
 def exit_help():
     "Print help and exit"
     print(help_text)
     for profile in virtual_profiles:
         name, description = profile[:2]
-        description = [ description ]
-        max_width = 78-18
+        description = [description]
+        max_width = 78 - 18
         while len(description[0]) > max_width + 1:
             left_over = description[0][max_width:]
             description[0] = description[0][:max_width] + "-"
@@ -765,6 +786,7 @@ def exit_help():
         print("  %-15s %s" % (name, description))
     sys.exit(0)
 
+
 def exec_scripts(profile_path, script_name, meta_information=None):
     """"Run userscripts
 
@@ -782,7 +804,7 @@ def exec_scripts(profile_path, script_name, meta_information=None):
     all_ok = True
     if meta_information:
         env = os.environ.copy()
-        env.update({ "AUTORANDR_%s" % str(key).upper(): str(value) for (key, value) in meta_information.items() })
+        env.update({"AUTORANDR_%s" % str(key).upper(): str(value) for (key, value) in meta_information.items()})
     else:
         env = os.environ.copy()
 
@@ -823,6 +845,7 @@ def exec_scripts(profile_path, script_name, meta_information=None):
 
     return all_ok
 
+
 def dispatch_call_to_sessions(argv):
     """Invoke autorandr for each open local X11 session with the given options.
 
@@ -929,22 +952,25 @@ def dispatch_call_to_sessions(argv):
             fork_child_autorandr(pwent, process_environ)
             X11_displays_done.add(display)
 
+
 def main(argv):
     try:
-        options = dict(getopt.getopt(argv[1:], "s:r:l:d:cfh", [ "batch", "dry-run", "change", "default=", "save=", "remove=", "load=", "force", "fingerprint", "config", "debug", "skip-options=", "help" ])[0])
+        opts, args = getopt.getopt(argv[1:], "s:r:l:d:cfh", ["batch", "dry-run", "change", "default=", "save=", "remove=", "load=", "force", "fingerprint", "config", "debug", "skip-options=", "help"])
     except getopt.GetoptError as e:
         print("Failed to parse options: {0}.\n"
               "Use --help to get usage information.".format(str(e)),
               file=sys.stderr)
         sys.exit(posix.EX_USAGE)
 
+    options = dict(opts)
+
     if "-h" in options or "--help" in options:
         exit_help()
 
     # Batch mode
     if "--batch" in options:
         if ("DISPLAY" not in os.environ or not os.environ["DISPLAY"]) and os.getuid() == 0:
-            dispatch_call_to_sessions([ x for x in argv if x != "--batch" ])
+            dispatch_call_to_sessions([x for x in argv if x != "--batch"])
         else:
             print("--batch mode can only be used by root and if $DISPLAY is unset")
         return
@@ -977,7 +1003,7 @@ def main(argv):
     except Exception as e:
         raise AutorandrException("Failed to load profiles", e)
 
-    profile_symlinks = { k: v for k, v in profile_symlinks.items() if v in (x[0] for x in virtual_profiles) or v in profiles }
+    profile_symlinks = {k: v for k, v in profile_symlinks.items() if v in (x[0] for x in virtual_profiles) or v in profiles}
 
     exec_scripts(None, "predetect")
     config, modes = parse_xrandr_output()
@@ -991,7 +1017,7 @@ def main(argv):
         sys.exit(0)
 
     if "--skip-options" in options:
-        skip_options = [ y[2:] if y[:2] == "--" else y for y in ( x.strip() for x in options["--skip-options"].split(",") ) ]
+        skip_options = [y[2:] if y[:2] == "--" else y for y in (x.strip() for x in options["--skip-options"].split(","))]
         for profile in profiles.values():
             for output in profile["config"].values():
                 output.set_ignored_options(skip_options)
@@ -1001,7 +1027,7 @@ def main(argv):
     if "-s" in options:
         options["--save"] = options["-s"]
     if "--save" in options:
-        if options["--save"] in ( x[0] for x in virtual_profiles ):
+        if options["--save"] in (x[0] for x in virtual_profiles):
             raise AutorandrException("Cannot save current configuration as profile '%s':\nThis configuration name is a reserved virtual configuration." % options["--save"])
         try:
             profile_folder = os.path.join(profile_path, options["--save"])
@@ -1015,7 +1041,7 @@ def main(argv):
     if "-r" in options:
         options["--remove"] = options["-r"]
     if "--remove" in options:
-        if options["--remove"] in ( x[0] for x in virtual_profiles ):
+        if options["--remove"] in (x[0] for x in virtual_profiles):
             raise AutorandrException("Cannot remove profile '%s':\nThis configuration name is a reserved virtual configuration." % options["--remove"])
         if options["--remove"] not in profiles.keys():
             raise AutorandrException("Cannot remove profile '%s':\nThis profile does not exist." % options["--remove"])
@@ -1046,6 +1072,8 @@ def main(argv):
         options["--load"] = options["-l"]
     if "--load" in options:
         load_profile = options["--load"]
+    elif len(args) == 1:
+        load_profile = args[0]
     else:
         # Find the active profile(s) first, for the block script (See #42)
         current_profiles = []
@@ -1054,7 +1082,7 @@ def main(argv):
             if configs_are_equal:
                 current_profiles.append(profile_name)
         block_script_metadata = {
-            "CURRENT_PROFILE":  "".join(current_profiles[:1]),
+            "CURRENT_PROFILE": "".join(current_profiles[:1]),
             "CURRENT_PROFILES": ":".join(current_profiles)
         }
 
@@ -1084,7 +1112,7 @@ def main(argv):
                 print("'%s' symlinked to '%s'" % (load_profile, profile_symlinks[load_profile]))
             load_profile = profile_symlinks[load_profile]
 
-        if load_profile in ( x[0] for x in virtual_profiles ):
+        if load_profile in (x[0] for x in virtual_profiles):
             load_config = generate_virtual_profile(config, modes, load_profile)
             scripts_path = os.path.join(profile_path, load_profile)
         else:
@@ -1097,7 +1125,7 @@ def main(argv):
             if load_profile in detected_profiles and detected_profiles[0] != load_profile:
                 update_mtime(os.path.join(scripts_path, "config"))
         add_unused_outputs(config, load_config)
-        if load_config == dict(config) and not "-f" in options and not "--force" in options:
+        if load_config == dict(config) and "-f" not in options and "--force" not in options:
             print("Config already loaded", file=sys.stderr)
             sys.exit(0)
         if "--debug" in options and load_config != dict(config):
@@ -1133,6 +1161,7 @@ def main(argv):
 
     sys.exit(0)
 
+
 def exception_handled_main(argv=sys.argv):
     try:
         main(sys.argv)
@@ -1147,5 +1176,6 @@ def exception_handled_main(argv=sys.argv):
         print("Unhandled exception ({0}). Please report this as a bug at https://github.com/phillipberndt/autorandr/issues.".format(e), file=sys.stderr)
         raise
 
+
 if __name__ == '__main__':
     exception_handled_main()