+ 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 })
+
+def remove_irrelevant_outputs(source_configuration, target_configuration):
+ "Remove outputs from target that ought to be 'off' and already are"
+ for output_name, output in source_configuration.items():
+ 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 = 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]))
+ 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["pos"] = "0x0"
+ else:
+ configuration[output].options["off"] = None
+ elif profile_name in ("horizontal", "vertical"):
+ shift = 0
+ if profile_name == "horizontal":
+ shift_index = "width"
+ pos_specifier = "%sx0"
+ else:
+ shift_index = "height"
+ pos_specifier = "0x%s"
+
+ 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]
+ configuration[output].options["mode"] = mode["name"]
+ configuration[output].options["rate"] = mode["rate"]
+ configuration[output].options["pos"] = pos_specifier % shift
+ shift += int(mode[shift_index])
+ 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:
+ return
+ print("| Differences between the two profiles:", file=sys.stderr)
+ for output in set(chain.from_iterable((one.keys(), another.keys()))):
+ if output not in one:
+ if "off" not in another[output].options:
+ print("| Output `%s' is missing from the active configuration" % output, file=sys.stderr)
+ elif output not in another:
+ if "off" not in one[output].options:
+ print("| Output `%s' is missing from the new configuration" % output, file=sys.stderr)
+ else:
+ for line in one[output].verbose_diff(another[output]):
+ print("| [Output %s] %s" % (output, line), file=sys.stderr)
+ print ("\\-", file=sys.stderr)