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 d02a7595c..ebbb888c3 100644
--- a/src/DBus.vala
+++ b/src/DBus.vala
@@ -11,7 +11,11 @@ public class Gala.DBus {
private static WindowManagerGala wm;
[DBus (visible = false)]
+#if HAS_MUTTER50
+ public static void init (WindowManagerGala _wm, NotificationsManager notifications_manager, ScreenshotManager screenshot_manager, BrightnessManager brightness_manager) {
+#else
public static void init (WindowManagerGala _wm, NotificationsManager notifications_manager, ScreenshotManager screenshot_manager) {
+#endif
wm = _wm;
Bus.own_name (
@@ -19,6 +23,22 @@ 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", brightness_manager);
+ brightness_manager.monitor_added.connect ((monitor_brightness) => {
+ try {
+ var id = connection.register_object (@"/io/elementary/gala/BrightnessManager/$(monitor_brightness.get_monitor_serial ())", monitor_brightness);
+ return id;
+ } catch (Error e) {
+ warning (e.message);
+ return null;
+ }
+ });
+ brightness_manager.monitor_removed.connect ((connection_id) => {
+ connection.unregister_object (connection_id);
+ });
+ brightness_manager.update_available_backlights ();
+#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..ddb950e61
--- /dev/null
+++ b/src/Misc/BrightnessManager.vala
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2026 elementary, Inc. (https://elementary.io)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Authored by: Denis Garaev
+ */
+
+#if HAS_MUTTER50
+[DBus (name = "io.elementary.gala.BrightnessManager")]
+public class Gala.BrightnessManager : GLib.Object {
+ [DBus (visible = false)]
+ public signal uint? monitor_added (MonitorBrightness monitor_brightness);
+ [DBus (visible = false)]
+ public signal void monitor_removed (uint connection_id);
+
+ private int _brightness;
+ public int brightness {
+ get {
+ if (exposed_monitors.size () == 0)
+ return -1;
+
+
+ return _brightness;
+ }
+ set {
+ if (_brightness == value || exposed_monitors.size () == 0)
+ return;
+
+ foreach (var monitor_brightness in exposed_monitors.get_values ())
+ monitor_brightness.brightness = value;
+
+ _brightness = value;
+ }
+ }
+
+ [DBus (visible = false)]
+ public unowned Meta.Display display { private get; construct; }
+
+ private GLib.HashTable exposed_monitors;
+ private GLib.HashTable connection_ids;
+ private unowned Meta.MonitorManager monitor_manager;
+
+ public BrightnessManager (Meta.Display display) {
+ Object (
+ display: display
+ );
+ }
+
+ construct {
+ monitor_manager = display.get_context ().get_backend ().get_monitor_manager ();
+ monitor_manager.monitors_changed.connect (update_available_backlights);
+ exposed_monitors = new GLib.HashTable (null, null);
+ connection_ids = new GLib.HashTable (null, null);
+
+ // TODO: bind to value from gschema
+ _brightness = 100;
+
+ var keybinding_settings = new GLib.Settings ("io.elementary.desktop.wm.keybindings");
+ display.add_keybinding ("brightness-brighter", keybinding_settings, Meta.KeyBindingFlags.NONE, () => {
+ brightness += 5;
+ });
+ display.add_keybinding ("brightness-dimmer", keybinding_settings, Meta.KeyBindingFlags.NONE, () => {
+ brightness -= 5;
+ });
+ }
+
+ [DBus (visible = false)]
+ public void update_available_backlights () {
+ unowned var monitors = monitor_manager.get_monitors ();
+ var new_monitors = monitors.copy ();
+ var old_monitors = exposed_monitors.get_keys ();
+ foreach (unowned var monitor in monitors) {
+ if (monitor.get_backlight () == null)
+ continue;
+
+ if (old_monitors.find (monitor) != null) {
+ old_monitors.remove (monitor);
+ new_monitors.remove (monitor);
+ }
+ }
+
+ if (new_monitors.length () > 0) {
+ foreach (var monitor in new_monitors) {
+ var monitor_brightness = new MonitorBrightness (monitor);
+ var connection_id = monitor_added (monitor_brightness);
+ if (connection_id != null) {
+ exposed_monitors.insert (monitor, monitor_brightness);
+ connection_ids.insert (monitor, connection_id);
+ }
+ }
+ }
+
+ if (old_monitors.length () > 0) {
+ foreach (var monitor in old_monitors) {
+ monitor_removed (connection_ids.get (monitor));
+ exposed_monitors.remove (monitor);
+ connection_ids.remove (monitor);
+ }
+ }
+ }
+}
+#endif
diff --git a/src/Misc/MonitorBrightness.vala b/src/Misc/MonitorBrightness.vala
new file mode 100644
index 000000000..b91f8afa5
--- /dev/null
+++ b/src/Misc/MonitorBrightness.vala
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2026 elementary, Inc. (https://elementary.io)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Authored by: Denis Garaev
+ */
+
+#if HAS_MUTTER50
+[DBus (name = "io.elementary.gala.BrightnessManager.Monitor")]
+public class Gala.MonitorBrightness : GLib.Object {
+ [DBus (visible = false)]
+ public unowned Meta.Monitor monitor { get; construct; }
+
+ public int brightness {
+ get {
+ if (backlight == null)
+ return -1;
+
+ int min, max;
+ int value;
+ backlight.get_brightness_info (out min, out max);
+ value = backlight.get_brightness ();
+ return ((value - min) * 100) / (max - min);
+ }
+ set {
+ if (brightness == value || backlight == null)
+ return;
+
+ int min, max;
+ backlight.get_brightness_info (out min, out max);
+ backlight.set_brightness ((int) (value * (max - min) / 100) + min);
+ }
+ }
+
+ private unowned Meta.Backlight? backlight;
+
+ public MonitorBrightness (Meta.Monitor monitor) {
+ Object (
+ monitor: monitor
+ );
+ }
+
+ construct {
+ backlight = monitor.get_backlight ();
+ }
+
+ [DBus (visible = false)]
+ public string get_monitor_serial () {
+ return monitor.get_serial ();
+ }
+}
+#endif
diff --git a/src/WindowManager.vala b/src/WindowManager.vala
index 7d2aaa775..c03c2e7da 100644
--- a/src/WindowManager.vala
+++ b/src/WindowManager.vala
@@ -114,6 +114,10 @@ namespace Gala {
private LockScreenManager lock_screen_manager;
+#if HAS_MUTTER50
+ private BrightnessManager brightness_manager;
+#endif
+
private Gee.LinkedList modal_stack = new Gee.LinkedList ();
private Gee.HashSet minimizing = new Gee.HashSet ();
@@ -160,7 +164,12 @@ namespace Gala {
filter_manager = new FilterManager (this);
notifications_manager = new NotificationsManager ();
screenshot_manager = new ScreenshotManager (this, notifications_manager, filter_manager);
+#if HAS_MUTTER50
+ brightness_manager = new BrightnessManager (get_display ());
+ DBus.init (this, notifications_manager, screenshot_manager, brightness_manager);
+#else
DBus.init (this, notifications_manager, screenshot_manager);
+#endif
unowned Meta.Display display = get_display ();
display.gl_video_memory_purged.connect (() => {
diff --git a/src/meson.build b/src/meson.build
index f4e36e4c6..7b1ab6f27 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -25,11 +25,13 @@ 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',
'Misc/InputMethod.vala',
'Misc/KeyboardManager.vala',
+ 'Misc/MonitorBrightness.vala',
'Misc/LockScreenManager.vala',
'Misc/NotificationsManager.vala',
'Misc/NotificationStack.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 c474aadf4..c8c56e704 100644
--- a/vapi/libmutter.vapi
+++ b/vapi/libmutter.vapi
@@ -294,7 +294,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 ();
@@ -691,14 +691,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 ();