From 5e0840a59d48f4557e1981390537c4b29243236a Mon Sep 17 00:00:00 2001 From: Dawson Matthews Date: Sun, 8 Mar 2026 18:38:37 -0600 Subject: [PATCH] all attributes apply together --- kde-display-profile-manager.py | 86 +++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/kde-display-profile-manager.py b/kde-display-profile-manager.py index 7b9b82c..c35f13d 100755 --- a/kde-display-profile-manager.py +++ b/kde-display-profile-manager.py @@ -85,6 +85,7 @@ def load_profile(profile_path): raise e outputs = profile.get('outputs', []) + commands = [] # Maps from JSON values to kscreen-doctor options bool_enable_map = {"true": "enable", "false": "disable"} @@ -99,96 +100,105 @@ def load_profile(profile_path): "never": "never", "always": "always", "automatic": "automatic" } - # 1. Handle Enable/Disable (Enable first to avoid no-output state) - log("Enabling enabled outputs...") - for out in outputs: - if out.get('enabled'): - run_command(f"kscreen-doctor output.{out['name']}.enable") - - log("Disabling disabled outputs...") - for out in outputs: - if not out.get('enabled'): - run_command(f"kscreen-doctor output.{out['name']}.disable") + def add_attr(output_name, attribute, value, value_map=None): + if value is None: + return + if isinstance(value, (list, dict)): + return + + str_value = str(value).lower() + if value_map: + if str_value in value_map: + value = value_map[str_value] + + commands.append(f"output.{output_name}.{attribute}.{value}") - # 2. Apply other attributes + # 1. Handle Enable/Disable + for out in outputs: + status = "enable" if out.get('enabled') else "disable" + commands.append(f"output.{out['name']}.{status}") + + # 2. Collect other attributes for out in outputs: name = out['name'] - log(f"Configuring output: {name}") - + # WCG - apply_attribute(name, "wcg", out.get('wcg'), bool_enable_map) - + add_attr(name, "wcg", out.get('wcg'), bool_enable_map) # SDR Brightness - apply_attribute(name, "sdr-brightness", out.get('sdr-brightness')) - + add_attr(name, "sdr-brightness", out.get('sdr-brightness')) # VRR Policy - apply_attribute(name, "vrrpolicy", out.get('vrrPolicy'), vrr_policy_map) - + add_attr(name, "vrrpolicy", out.get('vrrPolicy'), vrr_policy_map) # RGB Range - apply_attribute(name, "rgbrange", out.get('rgbRange'), rgb_range_map) - + add_attr(name, "rgbrange", out.get('rgbRange'), rgb_range_map) # Overscan - apply_attribute(name, "overscan", out.get('overscan')) - + add_attr(name, "overscan", out.get('overscan')) # HDR - apply_attribute(name, "hdr", out.get('hdr'), bool_enable_map) + add_attr(name, "hdr", out.get('hdr'), bool_enable_map) - # Brightness (0.0-1.0 to 0-100) + # Brightness brightness = out.get('brightness') if brightness is not None: - apply_attribute(name, "brightness", int(float(brightness) * 100)) + add_attr(name, "brightness", int(float(brightness) * 100)) # Max BPC max_bpc = out.get('maxBpc') if max_bpc == 0: max_bpc = "automatic" - apply_attribute(name, "maxbpc", max_bpc) + add_attr(name, "maxbpc", max_bpc) # DDC/CI - apply_attribute(name, "ddcCi", out.get('ddcCiAllowed'), bool_allow_map) + add_attr(name, "ddcCi", out.get('ddcCiAllowed'), bool_allow_map) # Mirroring replication_source_id = out.get('replicationSource', 0) if replication_source_id != 0: - # Find the name of the replication source source_name = "none" for other_out in outputs: if other_out.get('id') == replication_source_id: source_name = other_out['name'] break - apply_attribute(name, "mirror", source_name) + add_attr(name, "mirror", source_name) else: - apply_attribute(name, "mirror", "none") + add_attr(name, "mirror", "none") # ICC Profile icc_path = out.get('iccProfilePath') if icc_path: - apply_attribute(name, "iccProfilePath", icc_path) + add_attr(name, "iccProfilePath", icc_path) # Mode mode_id = out.get('currentModeId') if mode_id: mode_str = get_mode_string(out, mode_id) if mode_str: - apply_attribute(name, "mode", mode_str) + add_attr(name, "mode", mode_str) # Position pos = out.get('pos') if pos: - apply_attribute(name, "position", f"{pos['x']},{pos['y']}") + add_attr(name, "position", f"{pos['x']},{pos['y']}") # Scale - apply_attribute(name, "scale", out.get('scale')) + add_attr(name, "scale", out.get('scale')) # Rotation - apply_attribute(name, "rotation", out.get('rotation'), rotation_map) + add_attr(name, "rotation", out.get('rotation'), rotation_map) # Priority and Primary priority = out.get('priority') if priority is not None: if priority == 1: - run_command(f"kscreen-doctor output.{name}.primary") - run_command(f"kscreen-doctor output.{name}.priority.{priority}") + commands.append(f"output.{name}.primary") + commands.append(f"output.{name}.priority.{priority}") + + if commands: + full_cmd = ["kscreen-doctor"] + commands + log(f"Running atomic command: {' '.join(full_cmd)}") + try: + subprocess.run(full_cmd, check=True) + except subprocess.CalledProcessError as e: + log(f"Error executing kscreen-doctor: {e}") + raise e log("Display configuration restored.")