diff --git a/data/gala.gschema.xml b/data/gala.gschema.xml
index ea079697a..a726ae8bb 100644
--- a/data/gala.gschema.xml
+++ b/data/gala.gschema.xml
@@ -204,6 +204,16 @@
The shortcut to enable picture-in-picture window
The shortcut to show the selection area to choose a window.
+
+
+ Monitor brightness up
+ Increase monitor brightness on supported panels
+
+
+
+ Monitor brightness down
+ Decrease monitor brightness on supported panels
+
diff --git a/src/DBus.vala b/src/DBus.vala
index 5541df51c..612754b22 100644
--- a/src/DBus.vala
+++ b/src/DBus.vala
@@ -22,6 +22,9 @@ public class Gala.DBus {
(connection, name) => {
try {
connection.register_object ("/io/elementary/gala", WindowDragProvider.get_instance ());
+#if HAS_MUTTER50
+ connection.register_object ("/io/elementary/gala/BrightnessManager", new BrightnessManager (wm.get_display ()));
+#endif
} catch (Error e) {
warning (e.message);
}
diff --git a/src/Misc/BrightnessManager.vala b/src/Misc/BrightnessManager.vala
new file mode 100644
index 000000000..e7d98903f
--- /dev/null
+++ b/src/Misc/BrightnessManager.vala
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2026 elementary, Inc. (https://elementary.io)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Authored by: Denis Garaev
+ */
+
+#if HAS_MUTTER50
+public struct Gala.Monitor {
+ unowned Meta.Monitor meta_mointor;
+ unowned Meta.Backlight backlight;
+ ulong connection_id;
+}
+
+[DBus (name = "io.elementary.gala.BrightnessManager")]
+public class Gala.BrightnessManager : GLib.Object {
+ public signal void monitors_changed ();
+ public signal void monitor_brightness_changed (uint index, uint value);
+
+ [DBus (visible = false)]
+ public unowned Meta.Display display { private get; construct; }
+
+ private unowned Meta.MonitorManager monitor_manager;
+ private GLib.List monitors;
+
+ public BrightnessManager (Meta.Display display) {
+ Object (
+ display: display
+ );
+ }
+
+ construct {
+ monitor_manager = display.get_context ().get_backend ().get_monitor_manager ();
+ monitor_manager.monitors_changed.connect (monitors_changed_cb);
+ monitors = new GLib.List ();
+ monitors_changed_cb ();
+
+ var keybinding_settings = new GLib.Settings ("io.elementary.desktop.wm.keybindings");
+ display.add_keybinding ("brightness-brighter", keybinding_settings, Meta.KeyBindingFlags.NONE, () => {
+ try {
+ set_monitor_brightness (0, get_monitor_brightness (0) + 5);
+ } catch {}
+ });
+ display.add_keybinding ("brightness-dimmer", keybinding_settings, Meta.KeyBindingFlags.NONE, () => {
+ try {
+ int delta = get_monitor_brightness (0) - 5;
+ if (delta < 0)
+ delta = 0;
+
+ set_monitor_brightness (0, delta);
+ } catch {}
+ });
+ }
+
+ public void set_monitor_brightness (uint index, uint value) throws GLib.Error {
+ if (index < monitors.length ()) {
+ var backlight = monitors.nth_data (index).backlight;
+ int min, max;
+ backlight.get_brightness_info (out min, out max);
+ backlight.set_brightness ((int) (value * (max - min) / 100) + min);
+ }
+ }
+
+ public int get_monitor_brightness (uint index) throws GLib.Error {
+ if (index < monitors.length ()) {
+ var backlight = monitors.nth_data (index).backlight;
+ int min, max;
+ int value;
+ backlight.get_brightness_info (out min, out max);
+ value = backlight.get_brightness ();
+ return (((value - min) * 100) / (max - min)).clamp (0, 100);
+ } else
+ return -1;
+ }
+
+ public string get_monitor_data (uint index) throws GLib.Error {
+ if (index < monitors.length ())
+ return monitors.nth_data (index).meta_mointor.get_display_name ();
+ else
+ return "";
+ }
+
+ public uint get_monitor_count () throws GLib.Error {
+ return monitors.length ();
+ }
+
+ private void monitors_changed_cb () {
+ foreach (var data in monitors) {
+ data.backlight.disconnect (data.connection_id);
+ monitors.remove (data);
+ }
+
+ var meta_monitors = monitor_manager.get_monitors ().copy ();
+ foreach (var meta_monitor in meta_monitors) {
+ var backlight = meta_monitor.get_backlight ();
+ var connection_id = backlight.notify["brightness"].connect (monitor_brightness_changed_cb);
+ if (meta_monitor.is_primary ())
+ monitors.insert ({ meta_monitor, backlight, connection_id }, 0);
+ else
+ monitors.append ({ meta_monitor, backlight, connection_id });
+ }
+
+ monitors_changed ();
+ }
+
+ private void monitor_brightness_changed_cb (GLib.Object sender, GLib.ParamSpec prop) {
+ var backlight = (Meta.Backlight) sender;
+ var list = monitors.search (backlight, (monitor, backlight) => {
+ if (monitor.backlight == backlight)
+ return 0;
+ else
+ return -1;
+ }).copy ();
+
+ if (list == null || list.is_empty ())
+ return;
+
+ var index = monitors.index (list.data);
+ monitor_brightness_changed (index, get_monitor_brightness (index));
+ }
+}
+#endif
diff --git a/src/meson.build b/src/meson.build
index 6b941f249..cfc0fd2d9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -25,6 +25,7 @@ gala_bin_sources = files(
'HotCorners/HotCorner.vala',
'HotCorners/HotCornerManager.vala',
'Misc/BlurManager.vala',
+ 'Misc/BrightnessManager.vala',
'Misc/DaemonManager.vala',
'Misc/DBusAccelerator.vala',
'Misc/DesktopIntegration.vala',
diff --git a/vapi/Meta-18.metadata b/vapi/Meta-18.metadata
index 05cf306ee..d85250716 100644
--- a/vapi/Meta-18.metadata
+++ b/vapi/Meta-18.metadata
@@ -12,6 +12,7 @@ BackgroundContent cheader_filename="meta/meta-background-content.h"
BackgroundGroup cheader_filename="meta/meta-background-group.h"
BackgroundImage cheader_filename="meta/meta-background-image.h"
BackgroundImageCache cheader_filename="meta/meta-background-image.h"
+Backlight cheader_filename="meta/meta-backlight.h"
Barrier cheader_filename="meta/barrier.h"
BarrierDirection cheader_filename="meta/barrier.h"
BarrierEvent cheader_filename="meta/barrier.h"
@@ -56,6 +57,7 @@ KeyHandlerFunc.window nullable
LaunchContext cheader_filename="meta/meta-launch-context.h"
Laters cheader_filename="meta/types.h"
LaterType cheader_filename="meta/util.h"
+LogicalMonitor cheader_filename="meta/meta-logical-monitor.h"
MaximizeFlags cheader_filename="meta/window.h"
MultiTexture cheader_filename="meta/meta-multi-texture.h"
MultiTextureAlphaMode.n_meta_multi_texture_alpha_modes name="N_MODES"
@@ -67,6 +69,7 @@ MultiTextureCoefficients cheader_filename="meta/meta-multi-texture-format.h" cpr
MultiTextureFormat.n_meta_multi_texture_formats name="N_FORMATS"
MultiTextureFormat.meta_multi_texture_format_* name="meta_multi_texture_format_(.+)"
MultiTextureFormat cheader_filename="meta/meta-multi-texture-format.h" cprefix="META_MULTI_TEXTURE_FORMAT_"
+Monitor cheader_filename="meta/meta-monitor.h"
MonitorManager cheader_filename="meta/meta-monitor-manager.h"
MonitorSwitchConfigType cheader_filename="meta/meta-monitor-manager.h"
MotionDirection cheader_filename="meta/common.h"
diff --git a/vapi/libmutter.vapi b/vapi/libmutter.vapi
index 9b6a81576..ff133b5fa 100644
--- a/vapi/libmutter.vapi
+++ b/vapi/libmutter.vapi
@@ -276,7 +276,7 @@ namespace Meta {
public void purge (GLib.File file);
}
#if HAS_MUTTER49
- [CCode (cheader_filename = "meta/main.h", type_id = "meta_backlight_get_type ()")]
+ [CCode (cheader_filename = "meta/meta-backlight.h", type_id = "meta_backlight_get_type ()")]
public abstract class Backlight : GLib.Object {
[CCode (has_construct_function = false)]
protected Backlight ();
@@ -647,14 +647,14 @@ namespace Meta {
public Meta.Workspace workspace { owned get; set; }
}
#if HAS_MUTTER49
- [CCode (cheader_filename = "meta/main.h", type_id = "meta_logical_monitor_get_type ()")]
+ [CCode (cheader_filename = "meta/meta-logical-monitor.h", type_id = "meta_logical_monitor_get_type ()")]
public class LogicalMonitor : GLib.Object {
[CCode (has_construct_function = false)]
protected LogicalMonitor ();
public unowned GLib.List get_monitors ();
public int get_number ();
}
- [CCode (cheader_filename = "meta/main.h", type_id = "meta_monitor_get_type ()")]
+ [CCode (cheader_filename = "meta/meta-monitor.h", type_id = "meta_monitor_get_type ()")]
public class Monitor : GLib.Object {
[CCode (has_construct_function = false)]
protected Monitor ();