From 024fdd1dd8d67c79d55853ea4b96934e6d740844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:36 +0200 Subject: [PATCH 01/17] gitignore: Ignore wraplock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther Part-of: --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 48b8c7928..994b71025 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ vgdump *~ \#*# .\#* +/subprojects/.wraplock /subprojects/glib /subprojects/gmobile /subprojects/gvc -- GitLab From 6d7d8ffefe674d4f9fa3c73af6d84047fd38cbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:37 +0200 Subject: [PATCH 02/17] torch-manager: Fix comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gbp-Dch: Ignore Signed-off-by: Guido Günther Part-of: --- src/torch-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/torch-manager.c b/src/torch-manager.c index b1ca45e43..a4f23d2b6 100644 --- a/src/torch-manager.c +++ b/src/torch-manager.c @@ -28,7 +28,7 @@ /** * PhoshTorchManager: * - * Interacts with torch via UPower + * Interacts with torch via sysfs and logind * * #PhoshTorchManager tracks the torch status and * allows to set the brightness. -- GitLab From 021c9cd850e368b6f35be75cf9a8b0ec7393f9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:37 +0200 Subject: [PATCH 03/17] torch-manager: Robustify callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid the callback cast and rather cast the arguments making it match other places in the code. Gbp-Dch: Ignore Signed-off-by: Guido Günther Part-of: --- src/torch-manager.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/torch-manager.c b/src/torch-manager.c index a4f23d2b6..005c37956 100644 --- a/src/torch-manager.c +++ b/src/torch-manager.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2020 Purism SPC + * 2025 Phosh.mobi e.V. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -89,11 +90,12 @@ apply_brightness (PhoshTorchManager *self) g_object_thaw_notify (G_OBJECT (self)); } + static void -on_brightness_set (PhoshDBusLoginSession *proxy, - GAsyncResult *res, - PhoshTorchManager *self) +on_brightness_set (GObject *source_object, GAsyncResult *res, gpointer user_data) { + PhoshDBusLoginSession *proxy = PHOSH_DBUS_LOGIN_SESSION (source_object); + PhoshTorchManager *self = PHOSH_TORCH_MANAGER (user_data); g_autoptr (GError) err = NULL; g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); @@ -123,7 +125,7 @@ set_brightness (PhoshTorchManager *self, int brightness) g_udev_device_get_name (self->udev_device), (guint) brightness, NULL, - (GAsyncReadyCallback) on_brightness_set, + on_brightness_set, self); } -- GitLab From 07796da0ce6f4646d54fd31313d2d1dd5061ea3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 26 Sep 2025 15:34:03 +0200 Subject: [PATCH 04/17] torch-manager: Fix indent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unrelated to our changes but let's clean up while at that Gbp-Dch: Ignore Signed-off-by: Guido Günther Part-of: --- src/torch-manager.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/torch-manager.c b/src/torch-manager.c index 005c37956..57c7b90ee 100644 --- a/src/torch-manager.c +++ b/src/torch-manager.c @@ -118,7 +118,7 @@ set_brightness (PhoshTorchManager *self, int brightness) if (self->brightness == brightness) return; - g_debug("Setting brightness to %d", brightness); + g_debug ("Setting brightness to %d", brightness); phosh_dbus_login_session_call_set_brightness (self->proxy, TORCH_SUBSYSTEM, @@ -199,8 +199,8 @@ find_torch_device (PhoshTorchManager *self) self->max_brightness = g_udev_device_get_sysfs_attr_as_int (self->udev_device, "max_brightness"); - g_debug("Found torch device '%s' with max brightness %d", - g_udev_device_get_name (self->udev_device), self->max_brightness); + g_debug ("Found torch device '%s' with max brightness %d", + g_udev_device_get_name (self->udev_device), self->max_brightness); self->can_scale = self->max_brightness > 1; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CAN_SCALE]); @@ -261,7 +261,7 @@ phosh_torch_manager_idle_init (PhoshManager *manager) static void phosh_torch_manager_dispose (GObject *object) { - PhoshTorchManager *self = PHOSH_TORCH_MANAGER(object); + PhoshTorchManager *self = PHOSH_TORCH_MANAGER (object); g_cancellable_cancel (self->cancel); g_clear_object (&self->cancel); -- GitLab From 1df2bf20feb89db5926d7964521f84b6b03de113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:39 +0200 Subject: [PATCH 05/17] monitor-manager: Drop change_backlight helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No longer invoked by g-s-d Signed-off-by: Guido Günther Part-of: --- src/monitor-manager.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/monitor-manager.c b/src/monitor-manager.c index 0a3a97dac..5801bc106 100644 --- a/src/monitor-manager.c +++ b/src/monitor-manager.c @@ -297,21 +297,6 @@ phosh_monitor_manager_handle_get_resources (PhoshDBusDisplayConfig *skeleton, } -static gboolean -phosh_monitor_manager_handle_change_backlight (PhoshDBusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation, - guint serial, - guint output_index, - int value) -{ - g_debug ("Unimplemented DBus call %s", __func__); - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, - G_DBUS_ERROR_NOT_SUPPORTED, - "Changing backlight not supported"); - return TRUE; -} - - static gboolean phosh_monitor_manager_handle_get_crtc_gamma (PhoshDBusDisplayConfig *skeleton, GDBusMethodInvocation *invocation, @@ -853,7 +838,6 @@ static void phosh_monitor_manager_display_config_init (PhoshDBusDisplayConfigIface *iface) { iface->handle_get_resources = phosh_monitor_manager_handle_get_resources; - iface->handle_change_backlight = phosh_monitor_manager_handle_change_backlight; iface->handle_get_crtc_gamma = phosh_monitor_manager_handle_get_crtc_gamma; iface->handle_set_crtc_gamma = phosh_monitor_manager_handle_set_crtc_gamma; iface->handle_get_current_state = phosh_monitor_manager_handle_get_current_state; -- GitLab From 822d59a80f61ee0c7841be182ffdd2dad45ab333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:39 +0200 Subject: [PATCH 06/17] keyboard-events: Drop protocol version check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We require a recent enough version since ages Signed-off-by: Guido Günther Part-of: --- src/keyboard-events.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/keyboard-events.c b/src/keyboard-events.c index f729179ac..a99e94eea 100644 --- a/src/keyboard-events.c +++ b/src/keyboard-events.c @@ -203,16 +203,6 @@ initable_init (GInitable *initable, return FALSE; } - if (phosh_private_get_version (phosh_private) < PHOSH_PRIVATE_GET_KEYBOARD_EVENT_SINCE_VERSION) { - g_warning ("Skipping grab manager due to mismatch of phosh_private protocol version"); - g_set_error (error, - G_IO_ERROR, G_IO_ERROR_FAILED, - "Protocol version mismatch. Need %d, got %d", - PHOSH_PRIVATE_GET_KEYBOARD_EVENT_SINCE_VERSION, - phosh_private_get_version (phosh_private)); - return FALSE; - } - if ((self->kbevent = phosh_private_get_keyboard_event (phosh_private)) == NULL) { g_warning ("Skipping grab manager because of an unknown phosh_private protocol error"); g_set_error (error, -- GitLab From 5990b61d09c747251946614f82a91943cc980d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:40 +0200 Subject: [PATCH 07/17] shell: Init settings early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to do as little as possible in constructed Signed-off-by: Guido Günther Part-of: --- src/shell.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shell.c b/src/shell.c index 2cb66ca8c..6b5967cb7 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1017,8 +1017,6 @@ phosh_shell_constructed (GObject *object) G_OBJECT_CLASS (phosh_shell_parent_class)->constructed (object); - priv->settings = g_settings_new ("sm.puri.phosh"); - /* We bind this early since a wl_display_roundtrip () would make us miss existing toplevels */ priv->toplevel_manager = phosh_toplevel_manager_new (); @@ -1357,6 +1355,7 @@ phosh_shell_init (PhoshShell *self) priv->style_manager = phosh_style_manager_new (); priv->shell_state = PHOSH_STATE_SETTINGS; priv->action_map = g_simple_action_group_new (); + priv->settings = g_settings_new ("sm.puri.phosh"); } /* }}} */ -- GitLab From 2e92690c17def2140ed469d732f73d46aebe1b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:41 +0200 Subject: [PATCH 08/17] shell: Move toplevel manager to init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to do as little as possible in constructed Signed-off-by: Guido Günther Part-of: --- src/shell.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shell.c b/src/shell.c index 6b5967cb7..f831d04a0 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1017,10 +1017,6 @@ phosh_shell_constructed (GObject *object) G_OBJECT_CLASS (phosh_shell_parent_class)->constructed (object); - /* We bind this early since a wl_display_roundtrip () would make us miss - existing toplevels */ - priv->toplevel_manager = phosh_toplevel_manager_new (); - priv->monitor_manager = phosh_monitor_manager_new (NULL); g_signal_connect_swapped (priv->monitor_manager, "monitor-added", @@ -1356,6 +1352,10 @@ phosh_shell_init (PhoshShell *self) priv->shell_state = PHOSH_STATE_SETTINGS; priv->action_map = g_simple_action_group_new (); priv->settings = g_settings_new ("sm.puri.phosh"); + + /* We bind this early since a wl_display_roundtrip () would make us miss + existing toplevels */ + priv->toplevel_manager = phosh_toplevel_manager_new (); } /* }}} */ -- GitLab From 0eb170db991ceb761a31bc2300f917cf5ecb4bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:42 +0200 Subject: [PATCH 09/17] shell: Set resource path in init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to do as little as possible in constructed Signed-off-by: Guido Günther Part-of: --- src/shell.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/shell.c b/src/shell.c index f831d04a0..001198373 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1052,9 +1052,6 @@ phosh_shell_constructed (GObject *object) g_error ("Need at least one monitor"); } - gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), - "/mobi/phosh/icons"); - priv->calls_manager = phosh_calls_manager_new (); priv->launcher_entry_manager = phosh_launcher_entry_manager_new (); @@ -1338,6 +1335,7 @@ phosh_shell_init (PhoshShell *self) PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); cui_init (TRUE); + gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/mobi/phosh/icons"); priv->overview_visible = TRUE; -- GitLab From 43ee450bc861442a79d6585935c423fcab6b82ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:42 +0200 Subject: [PATCH 10/17] udev-manager: New class to handle udev interaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need a client for torch and backlight. Track it in a common class and add the helpers we'll need for backlight handling. Signed-off-by: Guido Günther Part-of: --- src/meson.build | 2 + src/udev-manager.c | 200 +++++++++++++++++++++++++++++++++++++++++++++ src/udev-manager.h | 25 ++++++ 3 files changed, 227 insertions(+) create mode 100644 src/udev-manager.c create mode 100644 src/udev-manager.h diff --git a/src/meson.build b/src/meson.build index fb39dee9d..a523b88dc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -178,6 +178,7 @@ phosh_tool_headers = files( 'swipe-away-bin.h', 'system-modal-dialog.h', 'system-modal.h', + 'udev-manager.h', 'util.h', 'vpn-info.h', 'vpn-manager.h', @@ -260,6 +261,7 @@ phosh_tool_sources = files( 'swipe-away-bin.c', 'system-modal-dialog.c', 'system-modal.c', + 'udev-manager.c', 'util.c', 'vpn-info.c', 'vpn-manager.c', diff --git a/src/udev-manager.c b/src/udev-manager.c new file mode 100644 index 000000000..9dbd14d77 --- /dev/null +++ b/src/udev-manager.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-udev-manager" + +#include "phosh-config.h" + +#include "monitor/monitor.h" +#include "udev-manager.h" + +#define BACKLIGHT_SUBSYSTEM "backlight" + +/** + * PhoshUdevManager: + * + * Manage a udev client for the subsystems we're interested in + */ + +enum { + BACKLIGHT_CHANGED, + N_SIGNALS +}; +static guint signals[N_SIGNALS]; + +struct _PhoshUdevManager { + GObject parent; + + GUdevClient *udev_client; +}; + +G_DEFINE_TYPE (PhoshUdevManager, phosh_udev_manager, G_TYPE_OBJECT) + + +static GUdevDevice * +phosh_backlight_sysfs_udev_get_type (GList *devices, const char *type) +{ + for (GList *d = devices; d != NULL; d = d->next) { + GUdevDevice *device = d->data; + const char *t; + + t = g_udev_device_get_sysfs_attr (device, "type"); + if (g_strcmp0 (t, type) == 0) + return g_object_ref (device); + } + return NULL; +} + + +static GUdevDevice * +phosh_backlight_sysfs_udev_get_raw (GList *devices, + const char *connector_name) +{ + for (GList *d = devices; d != NULL; d = d->next) { + g_autoptr (GUdevDevice) parent = NULL; + GUdevDevice *device = d->data; + const char *attr = g_udev_device_get_sysfs_attr (device, "type"); + const char *prop; + + if (g_strcmp0 (attr, "raw") != 0) + continue; + + parent = g_udev_device_get_parent (device); + if (!parent) + continue; + + prop = g_udev_device_get_subsystem (parent); + if (g_strcmp0 (prop, "drm") != 0) + continue; + + /* The drm-connector name `card[n]-[connector-name]` */ + prop = g_udev_device_get_name (parent); + if (!prop || !g_str_has_suffix (prop, connector_name)) + continue; + + attr = g_udev_device_get_sysfs_attr (parent, "enabled"); + if (g_strcmp0 (attr, "enabled") != 0) + continue; + + return g_object_ref (device); + } + + return NULL; +} + + +static void +on_uevent (PhoshUdevManager *self, const char *action, GUdevDevice *device) +{ + if (g_str_equal (g_udev_device_get_subsystem (device), BACKLIGHT_SUBSYSTEM) && + g_str_equal (action, "change")) { + g_signal_emit (self, signals[BACKLIGHT_CHANGED], 0, device); + } +} + + +static void +phosh_udev_manager_finalize (GObject *object) +{ + PhoshUdevManager *self = PHOSH_UDEV_MANAGER (object); + + g_clear_object (&self->udev_client); + + G_OBJECT_CLASS (phosh_udev_manager_parent_class)->finalize (object); +} + + +static void +phosh_udev_manager_class_init (PhoshUdevManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = phosh_udev_manager_finalize; + + signals[BACKLIGHT_CHANGED] = g_signal_new ("backlight-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 1, + G_UDEV_TYPE_DEVICE); +} + + +static void +phosh_udev_manager_init (PhoshUdevManager *self) +{ + const char * const subsystems[] = { BACKLIGHT_SUBSYSTEM, NULL }; + + self->udev_client = g_udev_client_new (subsystems); + g_signal_connect_object (self->udev_client, + "uevent", + G_CALLBACK (on_uevent), + self, + G_CONNECT_SWAPPED); +} + + +PhoshUdevManager * +phosh_udev_manager_get_default (void) +{ + static PhoshUdevManager *instance; + + if (instance == NULL) { + instance = g_object_new (PHOSH_TYPE_UDEV_MANAGER, NULL); + g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance); + } + return instance; +} + +/** + * phosh_udev_manager_find_backlight: + * @self: The udev maanger + * @connector_name: The connector name + * + * Get the backlight corresponding to the given connector name + * + * Returns:(transfer full): The list of torch devices + */ +GUdevDevice * +phosh_udev_manager_find_backlight (PhoshUdevManager *self, const char *connector_name) +{ + g_autolist (GUdevDevice) devices = NULL; + PhoshMonitorConnectorType connector_type; + GUdevDevice *device; + gboolean is_builtin; + + g_return_val_if_fail (PHOSH_IS_UDEV_MANAGER (self), NULL); + + connector_type = phosh_monitor_connector_type_from_name (connector_name); + is_builtin = phosh_monitor_connector_is_builtin (connector_type); + + devices = g_udev_client_query_by_subsystem (self->udev_client, BACKLIGHT_SUBSYSTEM); + if (!devices) + return NULL; + + /* Prefer the types firmware -> platform -> raw (see g-s-d < 49) */ + if (is_builtin) { + device = phosh_backlight_sysfs_udev_get_type (devices, "firmware"); + if (device) + return device; + + device = phosh_backlight_sysfs_udev_get_type (devices, "platform"); + if (device) + return device; + } + + device = phosh_backlight_sysfs_udev_get_raw (devices, connector_name); + if (device) + return device; + + if (is_builtin) + device = phosh_backlight_sysfs_udev_get_type (devices, "raw"); + + return device; +} diff --git a/src/udev-manager.h b/src/udev-manager.h new file mode 100644 index 000000000..5d76a05d5 --- /dev/null +++ b/src/udev-manager.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "dbus/login1-session-dbus.h" + +#include + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_UDEV_MANAGER (phosh_udev_manager_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshUdevManager, phosh_udev_manager, PHOSH, UDEV_MANAGER, GObject) + +PhoshUdevManager * phosh_udev_manager_get_default (void); +GUdevDevice * phosh_udev_manager_find_backlight (PhoshUdevManager *self, + const char *connector_name); + +G_END_DECLS -- GitLab From 61a6c0c7a636e21e06fbe6a93cc8f78a73839d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:43 +0200 Subject: [PATCH 11/17] udev-manager: Get us a login session proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While not strictly udev related torch and backlight both need it and there's no point in introducing yet another class. We might want to turn that into a more generic "ShellBackend" class that could e.g. also track gsettings. Signed-off-by: Guido Günther Part-of: --- src/udev-manager.c | 38 ++++++++++++++++++++++++++++++++++++++ src/udev-manager.h | 1 + 2 files changed, 39 insertions(+) diff --git a/src/udev-manager.c b/src/udev-manager.c index 9dbd14d77..95eaee8d5 100644 --- a/src/udev-manager.c +++ b/src/udev-manager.c @@ -10,9 +10,13 @@ #include "phosh-config.h" +#include "dbus/login1-session-dbus.h" #include "monitor/monitor.h" #include "udev-manager.h" +#define BUS_NAME "org.freedesktop.login1" +#define OBJECT_PATH "/org/freedesktop/login1/session/auto" + #define BACKLIGHT_SUBSYSTEM "backlight" /** @@ -31,6 +35,8 @@ struct _PhoshUdevManager { GObject parent; GUdevClient *udev_client; + + PhoshDBusLoginSession *session_proxy; }; G_DEFINE_TYPE (PhoshUdevManager, phosh_udev_manager, G_TYPE_OBJECT) @@ -103,6 +109,7 @@ phosh_udev_manager_finalize (GObject *object) { PhoshUdevManager *self = PHOSH_UDEV_MANAGER (object); + g_clear_object (&self->session_proxy); g_clear_object (&self->udev_client); G_OBJECT_CLASS (phosh_udev_manager_parent_class)->finalize (object); @@ -130,6 +137,7 @@ static void phosh_udev_manager_init (PhoshUdevManager *self) { const char * const subsystems[] = { BACKLIGHT_SUBSYSTEM, NULL }; + g_autoptr (GError) err = NULL; self->udev_client = g_udev_client_new (subsystems); g_signal_connect_object (self->udev_client, @@ -137,6 +145,17 @@ phosh_udev_manager_init (PhoshUdevManager *self) G_CALLBACK (on_uevent), self, G_CONNECT_SWAPPED); + + /* This happens before any UI is up so a sync call is o.k. */ + self->session_proxy = + phosh_dbus_login_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + BUS_NAME, + OBJECT_PATH, + NULL, + &err); + if (!self->session_proxy) + g_debug ("Failed to get login1 session proxy: %s", err->message); } @@ -198,3 +217,22 @@ phosh_udev_manager_find_backlight (PhoshUdevManager *self, const char *connector return device; } + +/** + * phosh_udev_manager_get_session_proxy: + * @self: The manager + * + * Get Logind's session manager. + * + * Returns: (transfer full)(nullable): The session manager + */ +PhoshDBusLoginSession * +phosh_udev_manager_get_session_proxy (PhoshUdevManager *self) +{ + g_return_val_if_fail (PHOSH_IS_UDEV_MANAGER (self), NULL); + + if (self->session_proxy) + return g_object_ref (self->session_proxy); + + return NULL; +} diff --git a/src/udev-manager.h b/src/udev-manager.h index 5d76a05d5..961b6763d 100644 --- a/src/udev-manager.h +++ b/src/udev-manager.h @@ -21,5 +21,6 @@ G_DECLARE_FINAL_TYPE (PhoshUdevManager, phosh_udev_manager, PHOSH, UDEV_MANAGER, PhoshUdevManager * phosh_udev_manager_get_default (void); GUdevDevice * phosh_udev_manager_find_backlight (PhoshUdevManager *self, const char *connector_name); +PhoshDBusLoginSession *phosh_udev_manager_get_session_proxy (PhoshUdevManager *self); G_END_DECLS -- GitLab From 738097d5339ac72551d03f2e75d3f74d0c59afc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:45 +0200 Subject: [PATCH 12/17] shell: Instantiate udev manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a singleton but lets give it clear life cycle Signed-off-by: Guido Günther Part-of: --- src/shell.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shell.c b/src/shell.c index 001198373..1a8dac02f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -92,6 +92,7 @@ #include "top-panel-bg.h" #include "torch-manager.h" #include "torch-info.h" +#include "udev-manager.h" #include "util.h" #include "vpn-info.h" #include "wifi-info.h" @@ -144,6 +145,7 @@ typedef struct GtkWidget *notification_banner; + PhoshUdevManager *udev_manager; PhoshAppTracker *app_tracker; PhoshSessionManager *session_manager; PhoshBackgroundManager *background_manager; @@ -588,6 +590,7 @@ phosh_shell_dispose (GObject *object) g_clear_object (&priv->suspend_manager); g_clear_object (&priv->layout_manager); g_clear_object (&priv->style_manager); + g_clear_object (&priv->udev_manager); /* sensors */ g_clear_object (&priv->proximity); @@ -1354,6 +1357,7 @@ phosh_shell_init (PhoshShell *self) /* We bind this early since a wl_display_roundtrip () would make us miss existing toplevels */ priv->toplevel_manager = phosh_toplevel_manager_new (); + priv->udev_manager = phosh_udev_manager_get_default (); } /* }}} */ -- GitLab From 8706e679146dd6d9fdef94e4e36cc4d3fe672e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 17:11:38 +0200 Subject: [PATCH 13/17] packaging: Version g-s-d dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want one entity to control brightness Signed-off-by: Guido Günther Part-of: --- debian/control | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 826e24fe0..e69089c76 100644 --- a/debian/control +++ b/debian/control @@ -79,7 +79,7 @@ Recommends: fonts-cantarell, gnome-session-bin, gnome-session-common, - gnome-settings-daemon, + gnome-settings-daemon (>= 49), iio-sensor-proxy, librsvg2-common, network-manager-config-connectivity-debian, @@ -94,6 +94,7 @@ Provides: Breaks: gnome-calls (<< 42), gnome-control-center (<< 42), + gnome-settings-daemon (<< 49), libgtk-3-0 (<< 3.24.30), xdg-desktop-portal-phosh (<< 0.44~), Description: Pure Wayland shell for mobile devices -- GitLab From aaf3d42142507126fc305c95607cba16feaeb42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:46 +0200 Subject: [PATCH 14/17] backlight-sysfs: New class to manage sysfs based backlights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There might be others later, e.g. ddc and thus introduce a `PhocBacklight` base class. This is inspired by what g-s-d 48 did and what mutter 49 does now so we can continue to interact with g-s-d power. Signed-off-by: Guido Günther Part-of: --- src/backlight-priv.h | 33 +++++ src/backlight-sysfs.c | 305 ++++++++++++++++++++++++++++++++++++++++++ src/backlight-sysfs.h | 20 +++ src/backlight.c | 273 +++++++++++++++++++++++++++++++++++++ src/backlight.h | 24 ++++ src/meson.build | 4 + 6 files changed, 659 insertions(+) create mode 100644 src/backlight-priv.h create mode 100644 src/backlight-sysfs.c create mode 100644 src/backlight-sysfs.h create mode 100644 src/backlight.c create mode 100644 src/backlight.h diff --git a/src/backlight-priv.h b/src/backlight-priv.h new file mode 100644 index 000000000..c84f06817 --- /dev/null +++ b/src/backlight-priv.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "backlight.h" + +#include + +G_BEGIN_DECLS + +struct _PhoshBacklightClass { + GObjectClass parent_class; + + void (* set_brightness) (PhoshBacklight *backlight, + int brightness_target, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + + int (* set_brightness_finish) (PhoshBacklight *backlight, + GAsyncResult *result, + GError **error); +}; + +void phosh_backlight_backend_update_brightness (PhoshBacklight *self, int brightness); +void phosh_backlight_set_range (PhoshBacklight *self, int min, int max); +void phosh_backlight_set_name (PhoshBacklight *self, const char *name); + +G_END_DECLS diff --git a/src/backlight-sysfs.c b/src/backlight-sysfs.c new file mode 100644 index 000000000..f58b9a12c --- /dev/null +++ b/src/backlight-sysfs.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + * + * Somewhat based on gsd-backlight which is + * Copyright (C) 2018 Red Hat Inc. + */ + +#define G_LOG_DOMAIN "phosh-backlight-sysfs" + +#include "phosh-config.h" + +#include "backlight-sysfs.h" +#include "dbus/login1-session-dbus.h" +#include "udev-manager.h" + +#include + +/** + * PhoshBacklightSysfs: + * + * A backlight managed via sysfs / logind + */ + +enum { + PROP_0, + PROP_CONNECTOR_NAME, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +struct _PhoshBacklightSysfs { + PhoshBacklight parent; + + char *connector_name; + + char *device_name; + char *device_path; + char *brightness_path; + + GUdevDevice *device; + PhoshDBusLoginSession *session_proxy; +}; + +static void initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (PhoshBacklightSysfs, phosh_backlight_sysfs, PHOSH_TYPE_BACKLIGHT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) + +static void +on_dbus_login_session_brightness_set (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PhoshDBusLoginSession *session_proxy = PHOSH_DBUS_LOGIN_SESSION (source_object); + g_autoptr (GTask) task = G_TASK (user_data); + int brightness; + g_autoptr (GError) error = NULL; + + brightness = GPOINTER_TO_INT (g_task_get_task_data (task)); + if (!phosh_dbus_login_session_call_set_brightness_finish (session_proxy, + res, + &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_int (task, brightness); +} + + +static int +phosh_backlight_sysfs_set_brightness_finish (PhoshBacklight *backlight, + GAsyncResult *result, + GError **error) +{ + PhoshBacklightSysfs *self = PHOSH_BACKLIGHT_SYSFS (backlight); + + g_return_val_if_fail (g_task_is_valid (result, self), -1); + + return g_task_propagate_int (G_TASK (result), error); +} + + +static void +phosh_backlight_sysfs_set_brightness (PhoshBacklight *backlight, + int brightness, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PhoshBacklightSysfs *self = PHOSH_BACKLIGHT_SYSFS (backlight); + g_autoptr (GTask) task = NULL; + + g_return_if_fail (PHOSH_IS_BACKLIGHT_SYSFS (self)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, GINT_TO_POINTER (brightness), NULL); + g_task_set_source_tag (task, phosh_backlight_sysfs_set_brightness); + + if (!self->session_proxy) + return; + + g_debug ("Setting brightness via logind: %d", brightness); + phosh_dbus_login_session_call_set_brightness (self->session_proxy, + "backlight", + self->device_name, + brightness, + cancellable, + on_dbus_login_session_brightness_set, + g_steal_pointer (&task)); +} + + +static void +phosh_backlight_sysfs_update (PhoshBacklightSysfs *self) +{ + g_autoptr (GError) err = NULL; + g_autofree char *contents = NULL; + int brightness; + + if (!g_file_get_contents (self->brightness_path, &contents, NULL, &err)) { + g_warning ("Backlight %s: Could not get brightness from sysfs: %s", + self->connector_name, + err->message); + return; + } + + brightness = g_ascii_strtoll (contents, NULL, 0); + phosh_backlight_backend_update_brightness (PHOSH_BACKLIGHT (self), brightness); +} + + +static void +on_backlight_changed (PhoshBacklightSysfs *self, + GUdevDevice *udev_device, + PhoshUdevManager *udev_manager) +{ + g_assert (PHOSH_IS_BACKLIGHT_SYSFS (self)); + g_assert (PHOSH_IS_UDEV_MANAGER (udev_manager)); + + if (g_strcmp0 (g_udev_device_get_sysfs_path (udev_device), self->device_path) != 0) + return; + + phosh_backlight_sysfs_update (self); +} + + +static gboolean +phosh_backlight_sysfs_get_udev_info (GUdevDevice *device, int *minout, int *maxout, GError **err) +{ + int min, max; + const char *device_type; + + max = g_udev_device_get_sysfs_attr_as_int (device, "max_brightness"); + min = MAX (1, max / 100); + + /* If the interface has less than 100 possible values, and it is of type + * raw, then assume that 0 does not turn off the backlight completely. */ + device_type = g_udev_device_get_sysfs_attr (device, "type"); + if (max < 99 && g_strcmp0 (device_type, "raw") == 0) + min = 0; + + /* Ignore a backlight which has no steps. */ + if (min >= max) { + g_set_error (err, G_IO_ERROR, G_IO_ERROR_FAILED, + "Backlight has an invalid maximum brightness [%d,%d]", min, max); + return FALSE; + } + + if (minout) + *minout = min; + if (maxout) + *maxout = max; + + return TRUE; +} + + +static gboolean +initable_init (GInitable *initable, GCancellable *cancel, GError **error) +{ + PhoshBacklightSysfs *self = PHOSH_BACKLIGHT_SYSFS (initable); + PhoshUdevManager *udev_manager = phosh_udev_manager_get_default (); + int min = 0, max = 0; + + if (!self->connector_name) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No connector name given"); + return FALSE; + } + + self->device = phosh_udev_manager_find_backlight (udev_manager, self->connector_name); + if (!self->device) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "No matching backlight device found"); + return FALSE; + } + + if (!phosh_backlight_sysfs_get_udev_info (self->device, &min, &max, error)) + return FALSE; + + phosh_backlight_set_range (PHOSH_BACKLIGHT (self), min, max); + + self->device_name = g_strdup (g_udev_device_get_name (self->device)); + self->device_path = realpath (g_udev_device_get_sysfs_path (self->device), NULL); + if (!self->device_path) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "Could not get real path for %s", self->device_name); + return FALSE; + } + self->brightness_path = g_build_filename (self->device_path, "brightness", NULL); + self->session_proxy = phosh_udev_manager_get_session_proxy (udev_manager); + + g_signal_connect_object (udev_manager, "backlight-changed", + G_CALLBACK (on_backlight_changed), + self, + G_CONNECT_SWAPPED); + phosh_backlight_sysfs_update (self); + + return TRUE; +} + + +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = initable_init; +} + + +static void +phosh_backlight_sysfs_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshBacklightSysfs *self = PHOSH_BACKLIGHT_SYSFS (object); + + switch (property_id) { + case PROP_CONNECTOR_NAME: + self->connector_name = g_value_dup_string (value); + phosh_backlight_set_name (PHOSH_BACKLIGHT (self), self->connector_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_backlight_sysfs_dispose (GObject *object) +{ + PhoshBacklightSysfs *self = PHOSH_BACKLIGHT_SYSFS (object); + + g_clear_pointer (&self->brightness_path, g_free); + g_clear_pointer (&self->device_path, g_free); + g_clear_pointer (&self->device_name, g_free); + g_clear_pointer (&self->connector_name, g_free); + g_clear_object (&self->device); + g_clear_object (&self->session_proxy); + + G_OBJECT_CLASS (phosh_backlight_sysfs_parent_class)->dispose (object); +} + + +static void +phosh_backlight_sysfs_class_init (PhoshBacklightSysfsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshBacklightClass *backlight_class = PHOSH_BACKLIGHT_CLASS (klass); + + object_class->set_property = phosh_backlight_sysfs_set_property; + object_class->dispose = phosh_backlight_sysfs_dispose; + + backlight_class->set_brightness = phosh_backlight_sysfs_set_brightness; + backlight_class->set_brightness_finish = phosh_backlight_sysfs_set_brightness_finish; + + props[PROP_CONNECTOR_NAME] = + g_param_spec_string ("connector-name", "", "", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_backlight_sysfs_init (PhoshBacklightSysfs *self) +{ +} + + +PhoshBacklightSysfs * +phosh_backlight_sysfs_new (const char *connector_name, GError **error) +{ + return g_initable_new (PHOSH_TYPE_BACKLIGHT_SYSFS, NULL, error, + "connector-name", connector_name, + NULL); +} diff --git a/src/backlight-sysfs.h b/src/backlight-sysfs.h new file mode 100644 index 000000000..2387f583a --- /dev/null +++ b/src/backlight-sysfs.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "backlight-priv.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_BACKLIGHT_SYSFS (phosh_backlight_sysfs_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshBacklightSysfs, phosh_backlight_sysfs, PHOSH, BACKLIGHT_SYSFS, + PhoshBacklight) + +PhoshBacklightSysfs *phosh_backlight_sysfs_new (const char *connector_name, GError **error); + +G_END_DECLS diff --git a/src/backlight.c b/src/backlight.c new file mode 100644 index 000000000..7a0400364 --- /dev/null +++ b/src/backlight.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-backlight" + +#include "phosh-config.h" + +#include "backlight-priv.h" + +#include + +/** + * PhoshBacklight: + * + * A `PhoshMonitor`'s backlight. Derived classes implement the actual + * backlight handling. + */ + +enum { + PROP_0, + PROP_BRIGHTNESS, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +typedef struct _PhoshBacklightPrivate { + GObject parent; + + char *name; + + gboolean pending; + int min_brightness; + int max_brightness; + int target_brightness; + + GCancellable *cancel; +} PhoshBacklightPrivate; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PhoshBacklight, phosh_backlight, G_TYPE_OBJECT) + + +static void +phosh_backlight_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshBacklight *self = PHOSH_BACKLIGHT (object); + + switch (property_id) { + case PROP_BRIGHTNESS: + phosh_backlight_set_brightness (self, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_backlight_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshBacklight *self = PHOSH_BACKLIGHT (object); + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + switch (property_id) { + case PROP_BRIGHTNESS: + g_value_set_int (value, priv->target_brightness); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_backlight_dispose (GObject *object) +{ + PhoshBacklight *self = PHOSH_BACKLIGHT (object); + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + g_cancellable_cancel (priv->cancel); + g_clear_object (&priv->cancel); + + g_clear_pointer (&priv->name, g_free); + + G_OBJECT_CLASS (phosh_backlight_parent_class)->dispose (object); +} + + +static void +phosh_backlight_class_init (PhoshBacklightClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = phosh_backlight_get_property; + object_class->set_property = phosh_backlight_set_property; + object_class->dispose = phosh_backlight_dispose; + + props[PROP_BRIGHTNESS] = + g_param_spec_int ("brightness", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_backlight_init (PhoshBacklight *self) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + priv->cancel = g_cancellable_new (); +} + +/** + * phosh_backlight_backend_update_brightness: + * @self: The backlight + * @brightness: the brightness + * + * This is invoked by the concrete backend implementation when the + * hardware changed brightness. + */ +void +phosh_backlight_backend_update_brightness (PhoshBacklight *self, int brightness) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + int new_brightness; + + if (priv->target_brightness == brightness) + return; + + new_brightness = CLAMP (brightness, priv->min_brightness, priv->max_brightness); + + if (brightness != new_brightness) + g_warning ("Trying to set out-of-range brightness %d on %s", brightness, priv->name); + + priv->target_brightness = new_brightness; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BRIGHTNESS]); +} + + +void +phosh_backlight_get_range (PhoshBacklight *self, int *min_brightness, int *max_brightness) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + g_return_if_fail (PHOSH_IS_BACKLIGHT (self)); + + if (min_brightness) + *min_brightness = priv->min_brightness; + + if (max_brightness) + *max_brightness = priv->max_brightness; +} + + +void +phosh_backlight_set_range (PhoshBacklight *self, int min, int max) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + priv->min_brightness = min; + priv->max_brightness = max; +} + + +int +phosh_backlight_get_brightness (PhoshBacklight *self) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + g_return_val_if_fail (PHOSH_IS_BACKLIGHT (self), -1); + + return priv->target_brightness; +} + + +static void +on_brightness_set (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + PhoshBacklight *self = PHOSH_BACKLIGHT (source_object); + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + g_autoptr (GError) err = NULL; + int brightness; + + priv->pending = FALSE; + + brightness = PHOSH_BACKLIGHT_GET_CLASS (self)->set_brightness_finish (self, res, &err); + if (brightness < 0) { + if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_warning ("Setting backlight on %s failed: %s", priv->name, err->message); + return; + } + + /* Brightness got updated from the system and we tried to set it at + * the same time. Let's try to set the brightness the system was + * setting to make sure we're in the correct state. */ + if (priv->target_brightness != brightness) { + priv->pending = TRUE; + + PHOSH_BACKLIGHT_GET_CLASS (self)->set_brightness (self, + priv->target_brightness, + priv->cancel, + on_brightness_set, + NULL); + } +} + + +void +phosh_backlight_set_brightness (PhoshBacklight *self, int brightness) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + int new_brightness; + + g_return_if_fail (PHOSH_IS_BACKLIGHT (self)); + + new_brightness = CLAMP (brightness, priv->min_brightness, priv->max_brightness); + + if (brightness != new_brightness) + g_warning ("Trying to set out-of-range brightness %d on %s", brightness, priv->name); + + if (priv->target_brightness == new_brightness) + return; + + g_debug ("Setting target brightness to %d", brightness); + priv->target_brightness = new_brightness; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BRIGHTNESS]); + + if (!priv->pending) { + priv->pending = TRUE; + + PHOSH_BACKLIGHT_GET_CLASS (self)->set_brightness (self, + priv->target_brightness, + priv->cancel, + on_brightness_set, + NULL); + } +} + + +const char * +phosh_backlight_get_name (PhoshBacklight *self) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + g_return_val_if_fail (PHOSH_IS_BACKLIGHT (self), NULL); + + return priv->name; +} + + +void +phosh_backlight_set_name (PhoshBacklight *self, const char *name) +{ + PhoshBacklightPrivate *priv = phosh_backlight_get_instance_private (self); + + g_set_str (&priv->name, name); +} diff --git a/src/backlight.h b/src/backlight.h new file mode 100644 index 000000000..b92d437d5 --- /dev/null +++ b/src/backlight.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_BACKLIGHT (phosh_backlight_get_type ()) + +G_DECLARE_DERIVABLE_TYPE (PhoshBacklight, phosh_backlight, PHOSH, BACKLIGHT, GObject) + +int phosh_backlight_get_brightness (PhoshBacklight *self); +void phosh_backlight_set_brightness (PhoshBacklight *self, int brightness); +void phosh_backlight_get_range (PhoshBacklight *self, + int *min_brightness, + int *max_brightness); +const char * phosh_backlight_get_name (PhoshBacklight *self); + +G_END_DECLS diff --git a/src/meson.build b/src/meson.build index a523b88dc..b03b6e7cb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -201,6 +201,8 @@ phosh_tool_sources = files( 'background-cache.c', 'background-image.c', 'background.c', + 'backlight-sysfs.c', + 'backlight.c', 'bidi.c', 'call-notification.c', 'call.c', @@ -298,6 +300,8 @@ phosh_headers = files( 'arrow.h', 'auth.h', 'background-manager.h', + 'backlight-sysfs.h', + 'backlight.h', 'batteryinfo.h', 'bt-device-row.h', 'bt-info.h', -- GitLab From 49336975883167dc2889863230359a9d0c72ffbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:46 +0200 Subject: [PATCH 15/17] monitor: Create backlight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backlight is attached to the monitor so we can look it up for brightness handling. Signed-off-by: Guido Günther Part-of: --- src/monitor/monitor.c | 10 ++++++++++ src/monitor/monitor.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 0156a4ee8..413e70025 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -80,12 +80,19 @@ output_handle_done (void *data, struct wl_output *wl_output) { PhoshMonitor *self = PHOSH_MONITOR (data); + g_autoptr (GError) err = NULL; if (phosh_monitor_is_configured (self)) return; self->wl_output_done = TRUE; + if (!self->backlight && self->name) { + self->backlight = PHOSH_BACKLIGHT (phosh_backlight_sysfs_new (self->name, &err)); + if (!self->backlight) + g_debug ("Failed to get backlight for %s: %s", self->name, err->message); + } + g_signal_emit (self, signals[SIGNAL_CONFIGURED], 0); } @@ -352,6 +359,8 @@ phosh_monitor_dispose (GObject *object) g_clear_pointer (&self->wlr_output_power, zwlr_output_power_v1_destroy); g_clear_pointer (&self->gamma_control, zwlr_gamma_control_v1_destroy); + g_clear_object (&self->backlight); + G_OBJECT_CLASS (phosh_monitor_parent_class)->dispose (object); } @@ -376,6 +385,7 @@ phosh_monitor_constructed (GObject *object) { PhoshMonitor *self = PHOSH_MONITOR (object); struct zwlr_output_power_manager_v1 *zwlr_output_power_manager_v1; + g_autoptr (GError) err = NULL; wl_output_add_listener (self->wl_output, &output_listener, self); diff --git a/src/monitor/monitor.h b/src/monitor/monitor.h index fe3df06da..30763dd8c 100644 --- a/src/monitor/monitor.h +++ b/src/monitor/monitor.h @@ -9,6 +9,7 @@ #include "phosh-enums.h" #include "phosh-wayland.h" +#include "backlight-sysfs.h" #include #include @@ -139,6 +140,8 @@ struct _PhoshMonitor { struct zwlr_gamma_control_v1 *gamma_control; guint32 n_gamma_entries; + + PhoshBacklight *backlight; }; G_DECLARE_FINAL_TYPE (PhoshMonitor, phosh_monitor, PHOSH, MONITOR, GObject) -- GitLab From aa0066c5a5df8dc1c6aaec924ee412c1f5ae3b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:47 +0200 Subject: [PATCH 16/17] settings/brightness: Use built in brightness handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes: https://gitlab.gnome.org/World/Phosh/phosh/-/issues/1261 Signed-off-by: Guido Günther Part-of: --- src/settings/brightness.c | 136 ++++++++++++++------------------------ 1 file changed, 51 insertions(+), 85 deletions(-) diff --git a/src/settings/brightness.c b/src/settings/brightness.c index 9ae69c134..bd34316b5 100644 --- a/src/settings/brightness.c +++ b/src/settings/brightness.c @@ -11,35 +11,35 @@ #include #include +#include "backlight.h" +#include "monitor/monitor.h" +#include "shell-priv.h" #include "settings/brightness.h" -#include "util.h" -static GDBusProxy *brightness_proxy; -static GCancellable *gsd_power_cancel; +static PhoshBacklight *backlight; static gboolean setting_brightness; static gulong scale_handler_id; static void -brightness_changed_cb (GDBusProxy *proxy, - GVariant *changed_props, - GVariant *invalidated_props, - gpointer *user_data) +on_brightness_changed (PhoshBacklight *backlight_, + GParamSpec *pspec, + gpointer user_data) { GtkScale *scale = GTK_SCALE (user_data); - int value; - gboolean ret; + int brightness, min = 0, max = 0; + double value; + + g_assert (backlight == backlight_); if (setting_brightness) return; - ret = g_variant_lookup (changed_props, - "Brightness", - "i", &value); - g_return_if_fail (ret); - if (value < 0 || value > 100) - value = 100.0; + brightness = phosh_backlight_get_brightness (backlight); + phosh_backlight_get_range (backlight, &min, &max); + + value = 100.0 * (brightness - min) / (max - min); g_signal_handler_block (G_OBJECT (scale), scale_handler_id); gtk_range_set_value (GTK_RANGE (scale), value); @@ -47,36 +47,20 @@ brightness_changed_cb (GDBusProxy *proxy, } -static void -brightness_init_cb (GObject *source_object, - GAsyncResult *res, - GtkScale *scale) +static PhoshBacklight * +find_backlight (void) { - g_autoptr (GError) err = NULL; - g_autoptr (GVariant) var = NULL; - int value; + PhoshShell *shell = phosh_shell_get_default (); + PhoshMonitor *monitor = phosh_shell_get_primary_monitor (shell); - brightness_proxy = g_dbus_proxy_new_finish (res, &err); - if (brightness_proxy == NULL) { - phosh_async_error_warn (err, "Could not connect to brightness service"); - return; - } + if (monitor->backlight) + return g_object_ref (PHOSH_BACKLIGHT (monitor->backlight)); - g_return_if_fail (GTK_IS_SCALE (scale)); + monitor = phosh_shell_get_builtin_monitor (shell); + if (monitor && monitor->backlight) + return g_object_ref (PHOSH_BACKLIGHT (monitor->backlight)); - /* Set scale to current brightness */ - var = g_dbus_proxy_get_cached_property (brightness_proxy, "Brightness"); - if (var) { - g_variant_get (var, "i", &value); - setting_brightness = TRUE; - gtk_range_set_value (GTK_RANGE (scale), value); - setting_brightness = FALSE; - } - - g_signal_connect (brightness_proxy, - "g-properties-changed", - G_CALLBACK (brightness_changed_cb), - scale); + return NULL; } @@ -85,73 +69,55 @@ brightness_init (GtkScale *scale, gulong handler_id) { g_autoptr (GError) err = NULL; g_autoptr (GDBusConnection) session_con = NULL; + int brightness; scale_handler_id = handler_id; - session_con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err); - if (err != NULL) { - g_warning ("Can not connect to session bus: %s", err->message); + backlight = find_backlight (); + if (!backlight) { + /* TODO: should hide UI element in that case */ return; } - gsd_power_cancel = g_cancellable_new (); - g_dbus_proxy_new (session_con, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.gnome.SettingsDaemon.Power", - "/org/gnome/SettingsDaemon/Power", - "org.gnome.SettingsDaemon.Power.Screen", - gsd_power_cancel, - (GAsyncReadyCallback)brightness_init_cb, - scale); -} - - -static void -on_brightness_set_ready (GDBusProxy *proxy, GAsyncResult *res, gpointer unused) -{ - g_autoptr (GError) err = NULL; - g_autoptr (GVariant) var = NULL; + g_debug ("Found backlight %s", phosh_backlight_get_name (backlight)); + brightness = phosh_backlight_get_brightness (backlight); + setting_brightness = TRUE; + gtk_range_set_value (GTK_RANGE (scale), brightness); + setting_brightness = FALSE; - var = g_dbus_proxy_call_finish (proxy, res, &err); - if (err) { - g_warning ("Could not set brightness %s", err->message); - return; - } + g_signal_connect (backlight, + "notify::brightness", + G_CALLBACK (on_brightness_changed), + scale); + on_brightness_changed (backlight, NULL, scale); - setting_brightness = FALSE; + /* TODO: Need to track monitor changes */ } void -brightness_set (int brightness) +brightness_set (int value) { - if (!brightness_proxy) + int brightness, min = 0, max = 0; + + if (!backlight) return; if (setting_brightness) return; setting_brightness = TRUE; - g_dbus_proxy_call (brightness_proxy, - "org.freedesktop.DBus.Properties.Set", - g_variant_new ( - "(ssv)", - "org.gnome.SettingsDaemon.Power.Screen", - "Brightness", - g_variant_new ("i", brightness)), - G_DBUS_CALL_FLAGS_NONE, - 2000, - NULL, - (GAsyncReadyCallback)on_brightness_set_ready, - NULL); + + phosh_backlight_get_range (backlight, &min, &max); + + brightness = min + ((max - min) * (value * 0.01)); + phosh_backlight_set_brightness (backlight, brightness); + setting_brightness = FALSE; } void brightness_dispose (void) { - g_cancellable_cancel (gsd_power_cancel); - g_clear_object (&gsd_power_cancel); - g_clear_object (&brightness_proxy); + g_clear_object (&backlight); } -- GitLab From b52befe9b0f2c86fab012d80cb4c64623015a11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 25 Sep 2025 15:37:48 +0200 Subject: [PATCH 17/17] udev-manager: Support torch subsystem too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use that from the torch-manager Signed-off-by: Guido Günther Part-of: --- src/torch-manager.c | 72 +++++++++++---------------------------------- src/udev-manager.c | 31 ++++++++++++++++++- src/udev-manager.h | 1 + 3 files changed, 48 insertions(+), 56 deletions(-) diff --git a/src/torch-manager.c b/src/torch-manager.c index 57c7b90ee..a8773db5e 100644 --- a/src/torch-manager.c +++ b/src/torch-manager.c @@ -14,12 +14,10 @@ #include #include "torch-manager.h" -#include "shell-priv.h" -#include "util.h" +#include "udev-manager.h" #include "dbus/login1-session-dbus.h" -#define BUS_NAME "org.freedesktop.login1" -#define OBJECT_PATH "/org/freedesktop/login1/session/auto" +#include #define TORCH_SUBSYSTEM "leds" @@ -57,10 +55,9 @@ struct _PhoshTorchManager { int max_brightness; int last_brightness; - GUdevClient *udev_client; GUdevDevice *udev_device; - PhoshDBusLoginSession *proxy; + PhoshDBusLoginSession *session_proxy; GCancellable *cancel; }; G_DEFINE_TYPE (PhoshTorchManager, phosh_torch_manager, PHOSH_TYPE_MANAGER); @@ -120,7 +117,7 @@ set_brightness (PhoshTorchManager *self, int brightness) g_debug ("Setting brightness to %d", brightness); - phosh_dbus_login_session_call_set_brightness (self->proxy, + phosh_dbus_login_session_call_set_brightness (self->session_proxy, TORCH_SUBSYSTEM, g_udev_device_get_name (self->udev_device), (guint) brightness, @@ -171,27 +168,22 @@ get_first_torch_device (gpointer data, gpointer manager) self->udev_device = g_object_ref (device); } + static gboolean -find_torch_device (PhoshTorchManager *self) +find_torch_device (PhoshTorchManager *self, PhoshUdevManager *udev_manager) { - g_autoptr (GUdevEnumerator) udev_enumerator = NULL; g_autolist (GUdevDevice) device_list = NULL; + g_autoptr (GError) err = NULL; - self->udev_device = NULL; - - udev_enumerator = g_udev_enumerator_new (self->udev_client); - g_udev_enumerator_add_match_subsystem (udev_enumerator, TORCH_SUBSYSTEM); - g_udev_enumerator_add_match_name (udev_enumerator, "*:torch"); - g_udev_enumerator_add_match_name (udev_enumerator, "*:flash"); + g_clear_object (&self->udev_device); - device_list = g_udev_enumerator_execute (udev_enumerator); + device_list = phosh_udev_manager_find_torches (udev_manager, &err); if (!device_list) { - g_debug ("Failed to find a torch device"); + g_debug ("Failed to find a torch device: %s", err->message); return FALSE; } g_list_foreach (device_list, get_first_torch_device, self); - if (!self->udev_device) { g_warning ("Failed to find a usable torch device"); return FALSE; @@ -210,23 +202,14 @@ find_torch_device (PhoshTorchManager *self) static void -on_proxy_new_for_bus_finish (GObject *source_object, - GAsyncResult *res, - PhoshTorchManager *self) +phosh_torch_manager_idle_init (PhoshManager *manager) { - g_autoptr (GError) err = NULL; - PhoshDBusLoginSession *proxy; - - proxy = phosh_dbus_login_session_proxy_new_for_bus_finish (res, &err); - if (!proxy) { - phosh_async_error_warn (err, "Failed to get login1 session proxy"); - return; - } + PhoshTorchManager *self = PHOSH_TORCH_MANAGER (manager); + PhoshUdevManager *udev_manager = phosh_udev_manager_get_default (); - g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - self->proxy = proxy; + self->session_proxy = phosh_udev_manager_get_session_proxy (udev_manager); + self->present = find_torch_device (self, udev_manager); - self->present = find_torch_device (self); if (self->present) { g_object_freeze_notify (G_OBJECT (self)); @@ -238,26 +221,6 @@ on_proxy_new_for_bus_finish (GObject *source_object, } -static void -phosh_torch_manager_idle_init (PhoshManager *manager) -{ - PhoshTorchManager *self = PHOSH_TORCH_MANAGER (manager); - const char * const subsystems[] = { TORCH_SUBSYSTEM, NULL }; - - self->udev_client = g_udev_client_new (subsystems); - g_return_if_fail (self->udev_client != NULL); - - self->cancel = g_cancellable_new (); - phosh_dbus_login_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - BUS_NAME, - OBJECT_PATH, - self->cancel, - (GAsyncReadyCallback) on_proxy_new_for_bus_finish, - self); -} - - static void phosh_torch_manager_dispose (GObject *object) { @@ -266,9 +229,8 @@ phosh_torch_manager_dispose (GObject *object) g_cancellable_cancel (self->cancel); g_clear_object (&self->cancel); - g_clear_object (&self->proxy); + g_clear_object (&self->session_proxy); - g_clear_object (&self->udev_client); g_clear_object (&self->udev_device); G_OBJECT_CLASS (phosh_torch_manager_parent_class)->dispose (object); @@ -451,7 +413,7 @@ void phosh_torch_manager_toggle (PhoshTorchManager *self) { g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - g_return_if_fail (PHOSH_DBUS_IS_LOGIN_SESSION (self->proxy)); + g_return_if_fail (PHOSH_DBUS_IS_LOGIN_SESSION (self->session_proxy)); if (self->brightness) { g_debug ("Disabling torch"); diff --git a/src/udev-manager.c b/src/udev-manager.c index 95eaee8d5..3b23ed129 100644 --- a/src/udev-manager.c +++ b/src/udev-manager.c @@ -18,6 +18,7 @@ #define OBJECT_PATH "/org/freedesktop/login1/session/auto" #define BACKLIGHT_SUBSYSTEM "backlight" +#define LEDS_SUBSYSTEM "leds" /** * PhoshUdevManager: @@ -136,7 +137,7 @@ phosh_udev_manager_class_init (PhoshUdevManagerClass *klass) static void phosh_udev_manager_init (PhoshUdevManager *self) { - const char * const subsystems[] = { BACKLIGHT_SUBSYSTEM, NULL }; + const char * const subsystems[] = { BACKLIGHT_SUBSYSTEM, LEDS_SUBSYSTEM, NULL }; g_autoptr (GError) err = NULL; self->udev_client = g_udev_client_new (subsystems); @@ -218,6 +219,34 @@ phosh_udev_manager_find_backlight (PhoshUdevManager *self, const char *connector return device; } +/** + * phosh_udev_manager_find_torches: + * @self: The udev maanger + * + * Get the torch devices in the the system + * + * Returns:(transfer full): The list of torch devices + */ +GList * +phosh_udev_manager_find_torches (PhoshUdevManager *self, GError **err) +{ + g_autoptr (GUdevEnumerator) udev_enumerator = NULL; + g_autolist (GUdevDevice) device_list = NULL; + + udev_enumerator = g_udev_enumerator_new (self->udev_client); + g_udev_enumerator_add_match_subsystem (udev_enumerator, LEDS_SUBSYSTEM); + g_udev_enumerator_add_match_name (udev_enumerator, "*:torch"); + g_udev_enumerator_add_match_name (udev_enumerator, "*:flash"); + + device_list = g_udev_enumerator_execute (udev_enumerator); + if (!device_list) { + g_set_error (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Failed to enumerate LED devices"); + return NULL; + } + + return g_steal_pointer (&device_list); +} + /** * phosh_udev_manager_get_session_proxy: * @self: The manager diff --git a/src/udev-manager.h b/src/udev-manager.h index 961b6763d..44bac37ef 100644 --- a/src/udev-manager.h +++ b/src/udev-manager.h @@ -21,6 +21,7 @@ G_DECLARE_FINAL_TYPE (PhoshUdevManager, phosh_udev_manager, PHOSH, UDEV_MANAGER, PhoshUdevManager * phosh_udev_manager_get_default (void); GUdevDevice * phosh_udev_manager_find_backlight (PhoshUdevManager *self, const char *connector_name); +GList * phosh_udev_manager_find_torches (PhoshUdevManager *self, GError **err); PhoshDBusLoginSession *phosh_udev_manager_get_session_proxy (PhoshUdevManager *self); G_END_DECLS -- GitLab