Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package nwg-displays for openSUSE:Factory checked in at 2026-08-28 19:47:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nwg-displays (Old) and /work/SRC/openSUSE:Factory/.nwg-displays.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nwg-displays" Fri Aug 28 19:47:50 2026 rev:11 rq:1374141 version:0.4.4 Changes: -------- --- /work/SRC/openSUSE:Factory/nwg-displays/nwg-displays.changes 2026-07-17 01:42:46.615838771 +0200 +++ /work/SRC/openSUSE:Factory/.nwg-displays.new.1265/nwg-displays.changes 2026-08-28 19:48:22.486057814 +0200 @@ -1,0 +2,7 @@ +Thu Aug 27 13:59:55 UTC 2026 - Nassim Lhadj <[email protected]> + +- Update to version 0.4.4: + * Fixed monitor descriptions with hashes in hyprland lua config #140 + * Implemented Hyprland colorspace + VRR support #137 + +------------------------------------------------------------------- Old: ---- nwg-displays-0.4.3.tar.gz New: ---- nwg-displays-0.4.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nwg-displays.spec ++++++ --- /var/tmp/diff_new_pack.nD6DYp/_old 2026-08-28 19:48:23.678099480 +0200 +++ /var/tmp/diff_new_pack.nD6DYp/_new 2026-08-28 19:48:23.681099585 +0200 @@ -17,7 +17,7 @@ Name: nwg-displays -Version: 0.4.3 +Version: 0.4.4 Release: 0 Summary: Output management utility for sway, Hyprland and Niri License: MIT ++++++ nwg-displays-0.4.3.tar.gz -> nwg-displays-0.4.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/.gitignore new/nwg-displays-0.4.4/.gitignore --- old/nwg-displays-0.4.3/.gitignore 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/.gitignore 2026-08-24 21:48:09.000000000 +0200 @@ -7,3 +7,4 @@ __pycache__/ /result /.vscode +/.direnv \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/README.md new/nwg-displays-0.4.4/README.md --- old/nwg-displays-0.4.3/README.md 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/README.md 2026-08-24 21:48:09.000000000 +0200 @@ -86,7 +86,7 @@ ### Hyprland -[Monitors](https://wiki.hyprland.org/Configuring/Monitors): +[Monitors](https://wiki.hyprland.org/0.54.0/Configuring/Monitors): Instead of configuring as described in Wiki, insert this line: @@ -99,7 +99,7 @@ require("monitors") ``` -[Default workspace](http://wiki.hyprland.org/Configuring/Monitors/#default-workspace) and [Binding workspaces to a monitor](https://wiki.hyprland.org/Configuring/Monitors/#binding-workspaces-to-a-monitor): +[Default workspace](http://wiki.hyprland.org/0.54.0/Configuring/Monitors/#default-workspace) and [Binding workspaces to a monitor](https://wiki.hyprland.org/0.54.0/Configuring/Monitors/#binding-workspaces-to-a-monitor): Insert: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/nwg_displays/langs/en_US.json new/nwg-displays-0.4.4/nwg_displays/langs/en_US.json --- old/nwg-displays-0.4.3/nwg_displays/langs/en_US.json 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/nwg_displays/langs/en_US.json 2026-08-24 21:48:09.000000000 +0200 @@ -6,6 +6,14 @@ "adaptive-sync-tooltip": "Enables or disables adaptive synchronization \n(often referred to as Variable Refresh Rate, \nor by the vendor-specific names FreeSync/G-Sync).", "apply": "Apply", "close": "Close", + "color-management": "Color", + "color-management-tooltip": "Color management preset (Hyprland only).\n'HDR' enables high dynamic range and forces 10-bit depth.\n'Wide' uses a wide color gamut (BT.2020 primaries).\n'EDID' uses the primaries reported by the display.", + "color-default": "Default", + "color-wide": "Wide gamut", + "sdr-brightness": "SDR brightness", + "sdr-brightness-tooltip": "Brightness multiplier for SDR content while in HDR mode \n(Hyprland only). Typical range 1.0–2.0.", + "sdr-saturation": "SDR saturation", + "sdr-saturation-tooltip": "Saturation multiplier for SDR content while in HDR mode \n(Hyprland only).", "custom-mode": "Custom mode", "custom-mode-tooltip": "Adds '--custom' argument to set a mode \nnot listed in the list of available modes.\nUse this ONLY if you know what you're doing.", "dpms-tooltip": "Enables or disables output via DPMS. \nTo turn an output off (ie. blank the screen \nbut keep workspaces as-is), one can set DPMS to off.", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/nwg_displays/main.py new/nwg-displays-0.4.4/nwg_displays/main.py --- old/nwg-displays-0.4.3/nwg_displays/main.py 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/nwg_displays/main.py 2026-08-24 21:48:09.000000000 +0200 @@ -134,6 +134,9 @@ form_version = None form_mirror = None form_ten_bit = None +form_color_mode = None +form_sdr_brightness = None +form_sdr_saturation = None form_profile_wallpapers = None dialog_win = None @@ -353,6 +356,13 @@ form_refresh.set_value(widget.refresh) if form_ten_bit: form_ten_bit.set_active(widget.ten_bit) + if form_color_mode: + form_color_mode.set_active_id(widget.color_mode if widget.color_mode else "") + update_color_dependent_widgets(widget.color_mode) + if form_sdr_brightness: + form_sdr_brightness.set_value(widget.sdr_brightness) + if form_sdr_saturation: + form_sdr_saturation.set_value(widget.sdr_saturation) if form_mirror: form_mirror.remove_all() form_mirror.append("", voc["none"]) @@ -414,6 +424,9 @@ focused, monitor, mirror="", + color_mode="", + sdr_brightness=1.0, + sdr_saturation=1.0, ): super().__init__() # Output properties @@ -441,6 +454,10 @@ self.focused = focused self.mirror = mirror self.ten_bit = ten_bit + # Color management (Hyprland only) + self.color_mode = color_mode + self.sdr_brightness = sdr_brightness + self.sdr_saturation = sdr_saturation # Button properties self.selected = False @@ -535,6 +552,41 @@ selected_output_button.ten_bit = check_btn.get_active() +def is_hdr_mode(color_mode): + return color_mode in ["hdr", "hdredid"] + + +def update_color_dependent_widgets(color_mode): + hdr = is_hdr_mode(color_mode) + # SDR brightness/saturation only take effect in HDR color modes + if form_sdr_brightness: + form_sdr_brightness.set_sensitive(hdr) + if form_sdr_saturation: + form_sdr_saturation.set_sensitive(hdr) + # HDR requires 10-bit: force the toggle on and lock it so the config stays valid + if form_ten_bit: + if hdr: + form_ten_bit.set_active(True) + form_ten_bit.set_sensitive(not hdr) + + +def on_color_mode_changed(widget): + if selected_output_button: + color_mode = widget.get_active_id() or "" + selected_output_button.color_mode = color_mode + update_color_dependent_widgets(color_mode) + + +def on_sdr_brightness_changed(widget): + if selected_output_button: + selected_output_button.sdr_brightness = round(widget.get_value(), 2) + + +def on_sdr_saturation_changed(widget): + if selected_output_button: + selected_output_button.sdr_saturation = round(widget.get_value(), 2) + + def on_dpms_toggled(widget): if selected_output_button: selected_output_button.dpms = widget.get_active() @@ -700,6 +752,9 @@ item["focused"], item["monitor"], mirror=item["mirror"], + color_mode=item.get("color_mode", ""), + sdr_brightness=item.get("sdr_brightness", 1.0), + sdr_saturation=item.get("sdr_saturation", 1.0), ) display_buttons.append(b) @@ -1307,7 +1362,9 @@ global form_adaptive_sync form_adaptive_sync = builder.get_object("adaptive-sync") - if sway: + # sway, Hyprland (vrr) and niri (variable-refresh-rate) all support per-output + # adaptive sync, so the toggle is available on all three. + if sway or hypr or niri: form_adaptive_sync.set_label(voc["adaptive-sync"]) form_adaptive_sync.set_tooltip_text(voc["adaptive-sync-tooltip"]) form_adaptive_sync.connect("toggled", on_adaptive_sync_toggled) @@ -1488,6 +1545,58 @@ form_mirror.connect("changed", on_mirror_selected) grid.attach(form_mirror, 7, 4, 1, 1) + if hypr: + # Color management / HDR controls (Hyprland only) + grid.insert_row(5) + + lbl = Gtk.Label.new("{}:".format(voc["color-management"])) + lbl.set_property("halign", Gtk.Align.END) + grid.attach(lbl, 0, 5, 1, 1) + + global form_color_mode + form_color_mode = Gtk.ComboBoxText() + form_color_mode.set_wrap_width(1) + form_color_mode.set_tooltip_text(voc["color-management-tooltip"]) + for cm_id, cm_label in [ + ("", voc["color-default"]), + ("auto", "Auto"), + ("srgb", "sRGB"), + ("wide", voc["color-wide"]), + ("edid", "EDID"), + ("hdr", "HDR"), + ("hdredid", "HDR (EDID)"), + ]: + form_color_mode.append(cm_id, cm_label) + form_color_mode.set_active_id("") + form_color_mode.connect("changed", on_color_mode_changed) + grid.attach(form_color_mode, 1, 5, 1, 1) + + lbl = Gtk.Label.new("{}:".format(voc["sdr-brightness"])) + lbl.set_property("halign", Gtk.Align.END) + grid.attach(lbl, 2, 5, 1, 1) + + global form_sdr_brightness + adj_b = Gtk.Adjustment( + value=1.0, lower=0.0, upper=2.0, step_increment=0.01, page_increment=0.1 + ) + form_sdr_brightness = Gtk.SpinButton.new(adj_b, 0.01, 2) + form_sdr_brightness.set_tooltip_text(voc["sdr-brightness-tooltip"]) + form_sdr_brightness.connect("value-changed", on_sdr_brightness_changed) + grid.attach(form_sdr_brightness, 3, 5, 1, 1) + + lbl = Gtk.Label.new("{}:".format(voc["sdr-saturation"])) + lbl.set_property("halign", Gtk.Align.END) + grid.attach(lbl, 4, 5, 1, 1) + + global form_sdr_saturation + adj_s = Gtk.Adjustment( + value=1.0, lower=0.0, upper=2.0, step_increment=0.01, page_increment=0.1 + ) + form_sdr_saturation = Gtk.SpinButton.new(adj_s, 0.01, 2) + form_sdr_saturation.set_tooltip_text(voc["sdr-saturation-tooltip"]) + form_sdr_saturation.connect("value-changed", on_sdr_saturation_changed) + grid.attach(form_sdr_saturation, 5, 5, 1, 1) + # Add profile management buttons separator = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL) form_wrapper_box.pack_start(separator, False, False, 10) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/nwg_displays/profiles.py new/nwg-displays-0.4.4/nwg_displays/profiles.py --- old/nwg-displays-0.4.3/nwg_displays/profiles.py 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/nwg_displays/profiles.py 2026-08-24 21:48:09.000000000 +0200 @@ -313,6 +313,9 @@ "custom_mode": db.custom_mode, "mirror": db.mirror, "ten_bit": db.ten_bit, + "color_mode": getattr(db, "color_mode", ""), + "sdr_brightness": getattr(db, "sdr_brightness", 1.0), + "sdr_saturation": getattr(db, "sdr_saturation", 1.0), "active": db.active, } profile_data["displays"].append(display) @@ -398,6 +401,17 @@ if display.get("ten_bit") is not None else False ) + db.color_mode = display.get("color_mode", "") or "" + db.sdr_brightness = float( + display.get("sdr_brightness") + if display.get("sdr_brightness") is not None + else 1.0 + ) + db.sdr_saturation = float( + display.get("sdr_saturation") + if display.get("sdr_saturation") is not None + else 1.0 + ) db.active = ( display.get("active") if display.get("active") is not None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/nwg_displays/settings_applier/settings_applier.py new/nwg-displays-0.4.4/nwg_displays/settings_applier/settings_applier.py --- old/nwg-displays-0.4.3/nwg_displays/settings_applier/settings_applier.py 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/nwg_displays/settings_applier/settings_applier.py 2026-08-24 21:48:09.000000000 +0200 @@ -59,15 +59,14 @@ print(f"[Profile] Applying {len(displays)} displays for Hyprland...") header = SettingsApplier._get_header("Profile Loader") - lines_conf = [header] + lines_conf = [] lines_lua = [header.replace("#", "--")] for d in displays: if not use_desc: name = d["name"] else: - desc_safe = d["description"].replace("#", "##") - name = f"desc:{desc_safe}" + name = f"desc:{d['description']}" lua_props = [f' output = "{name}"'] @@ -98,10 +97,35 @@ conf_line += f",mirror,{d['mirror']}" lua_props.append(f' mirror = "{d["mirror"]}"') - if d.get("ten_bit"): + color_mode = d.get("color_mode") or "" + hdr = color_mode in ("hdr", "hdredid") + + # HDR requires 10-bit; force it even if not explicitly stored + if d.get("ten_bit") or hdr: conf_line += ",bitdepth,10" lua_props.append(" bitdepth = 10") + if color_mode: + conf_line += f",cm,{color_mode}" + lua_props.append(f' cm = "{color_mode}"') + if hdr: + sdr_brightness = d.get("sdr_brightness", 1.0) + sdr_saturation = d.get("sdr_saturation", 1.0) + if sdr_brightness != 1.0: + conf_line += f",sdrbrightness,{sdr_brightness}" + lua_props.append(f" sdrbrightness = {sdr_brightness}") + if sdr_saturation != 1.0: + conf_line += f",sdrsaturation,{sdr_saturation}" + lua_props.append(f" sdrsaturation = {sdr_saturation}") + + # Adaptive sync (VRR). The toggle mirrors the monitor's effective + # state, so writing it explicitly is safe and keeps the toggle working. + # note: hyprland can also accept 2 or 3 to enable fullscreen-only VRR; + # may need to add that in the future + vrr = "1" if d.get("adaptive_sync") else "0" + conf_line += f",vrr,{vrr}" + lua_props.append(f" vrr = {vrr}") + lines_conf.append(conf_line) if d["transform"] != "normal": @@ -121,6 +145,8 @@ else "~/.config/hypr/monitors.lua" ) + lines_conf = [header] + [ln.replace("#", "##") for ln in lines_conf] + save_list_to_text_file(lines_conf, outputs_path) save_list_to_text_file(lines_lua, outputs_path_lua) @@ -426,15 +452,11 @@ } header = SettingsApplier._get_header() - lines_conf = [header] + lines_conf = [] lines_lua = [header.replace("#", "--")] for db in display_buttons: - name = ( - db.name - if not use_desc - else "desc:{}".format(db.description.replace("#", "##")) - ) + name = db.name if not use_desc else "desc:{}".format(db.description) lua_props = [f' output = "{name}"'] @@ -457,10 +479,33 @@ conf_line += f",mirror,{db.mirror}" lua_props.append(f' mirror = "{db.mirror}"') - if db.ten_bit: + color_mode = getattr(db, "color_mode", "") or "" + hdr = color_mode in ("hdr", "hdredid") + + # HDR requires 10-bit; force it even if the checkbox is off + if db.ten_bit or hdr: conf_line += ",bitdepth,10" lua_props.append(" bitdepth = 10") + if color_mode: + conf_line += f",cm,{color_mode}" + lua_props.append(f' cm = "{color_mode}"') + if hdr: + sdr_brightness = getattr(db, "sdr_brightness", 1.0) + sdr_saturation = getattr(db, "sdr_saturation", 1.0) + if sdr_brightness != 1.0: + conf_line += f",sdrbrightness,{sdr_brightness}" + lua_props.append(f" sdrbrightness = {sdr_brightness}") + if sdr_saturation != 1.0: + conf_line += f",sdrsaturation,{sdr_saturation}" + lua_props.append(f" sdrsaturation = {sdr_saturation}") + + # Adaptive sync (VRR). The toggle mirrors the monitor's effective + # state, so writing it explicitly is safe and keeps the toggle working. + vrr = "1" if db.adaptive_sync else "0" + conf_line += f",vrr,{vrr}" + lua_props.append(f" vrr = {vrr}") + lines_conf.append(conf_line) if db.transform != "normal": @@ -488,6 +533,8 @@ if os.path.isfile(outputs_path_lua): backup_lua = load_text_file(outputs_path_lua).splitlines() + lines_conf = [header] + [ln.replace("#", "##") for ln in lines_conf] + save_list_to_text_file(lines_conf, outputs_path) save_list_to_text_file(lines_lua, outputs_path_lua) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/nwg_displays/tools.py new/nwg-displays-0.4.4/nwg_displays/tools.py --- old/nwg-displays-0.4.3/nwg_displays/tools.py 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/nwg_displays/tools.py 2026-08-24 21:48:09.000000000 +0200 @@ -188,6 +188,10 @@ "adaptive_sync_status": "enabled" if mon.get("vrr_enabled", False) else "disabled", "mirror": "", "ten_bit": False, + # Color management is Hyprland-only; keep neutral defaults elsewhere + "color_mode": "", + "sdr_brightness": 1.0, + "sdr_saturation": 1.0, "monitor": None, # Store raw make/model for matching "__niri_make": raw_make, @@ -246,6 +250,10 @@ outputs_dict[item.name]["mirror"] = "" # We only use it on Hyprland outputs_dict[item.name]["ten_bit"] = False # We have no way to check it on sway + # Color management is Hyprland-only; keep neutral defaults elsewhere + outputs_dict[item.name]["color_mode"] = "" + outputs_dict[item.name]["sdr_brightness"] = 1.0 + outputs_dict[item.name]["sdr_saturation"] = 1.0 outputs_dict[item.name]["monitor"] = None elif os.getenv("HYPRLAND_INSTANCE_SIGNATURE"): @@ -317,6 +325,14 @@ outputs_dict[m["name"]]["ten_bit"] = True if m["currentFormat"] in ["XRGB2101010", "XBGR2101010"] else False + # Color management (Hyprland only). "srgb" is the implicit default, so + # treat it (and anything unknown) as "no cm line" to avoid touching configs + # that never opted into color management. + cm = m.get("colorManagementPreset", "") + outputs_dict[m["name"]]["color_mode"] = cm if cm in ["auto", "wide", "edid", "hdr", "hdredid"] else "" + outputs_dict[m["name"]]["sdr_brightness"] = float(m.get("sdrBrightness", 1.0)) + outputs_dict[m["name"]]["sdr_saturation"] = float(m.get("sdrSaturation", 1.0)) + # to identify Gdk.Monitor outputs_dict[m["name"]]["model"] = m["model"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-displays-0.4.3/setup.py new/nwg-displays-0.4.4/setup.py --- old/nwg-displays-0.4.3/setup.py 2026-05-13 03:16:43.000000000 +0200 +++ new/nwg-displays-0.4.4/setup.py 2026-08-24 21:48:09.000000000 +0200 @@ -9,7 +9,7 @@ setup( name="nwg-displays", - version="0.4.3", + version="0.4.4", description="nwg-shell output configuration utility", packages=find_packages(), include_package_data=True,
