From c3162b92613d68136e30e62b09a51f07bdfe796d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 20 Jan 2023 11:11:25 +0100 Subject: [PATCH 01/12] postinst: Trigger update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther Part-of: --- debian/phosh.postinst.in | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/debian/phosh.postinst.in b/debian/phosh.postinst.in index fc3790d4e..75af5e0c5 100644 --- a/debian/phosh.postinst.in +++ b/debian/phosh.postinst.in @@ -2,6 +2,17 @@ set -e +case "$1" in + configure) + # (used by unattended-upgrades etc.) + touch /var/run/reboot-required || true + + if ! grep -Fqsx dbus /run/reboot-required.pkgs; then + echo phosh >> /run/reboot-required.pkgs || true + fi + ;; +esac + if [ "$1" = triggered ]; then "/usr/lib/#MULTIARCH#/glib-2.0/gio-querymodules" "/usr/lib/#MULTIARCH#/phosh/plugins" || true "/usr/lib/#MULTIARCH#/glib-2.0/gio-querymodules" "/usr/lib/#MULTIARCH#/phosh/plugins/prefs" || true -- GitLab From dfa186939c6cdcba657bb37aacb2c6bb2649e560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 20 Jan 2023 09:43:24 +0100 Subject: [PATCH 02/12] util: Wrap g_clear_fd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to use it on older glib too. Signed-off-by: Guido Günther Part-of: --- src/util.c | 23 +++++++++++++++++++++++ src/util.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/util.c b/src/util.c index 7f089fb69..9b7e1bb8b 100644 --- a/src/util.c +++ b/src/util.c @@ -17,6 +17,7 @@ #include #include +#include #include @@ -538,3 +539,25 @@ phosh_util_get_stylesheet (const char *theme_name) return style; } + + +gboolean +phosh_clear_fd (int *fd, GError **err) +{ + gboolean success; + + g_return_val_if_fail (fd, FALSE); + +#if GLIB_CHECK_VERSION(2, 75, 1) + success = g_clear_fd (fd, err); +#else + if (*fd >= 0) { + success = g_close (*fd, err); + *fd = -1; + } else { + success = TRUE; + } +#endif + + return success; +} diff --git a/src/util.h b/src/util.h index 6e030fe85..39a1b9385 100644 --- a/src/util.h +++ b/src/util.h @@ -36,3 +36,4 @@ gboolean phosh_util_gesture_is_touch (GtkGestureSingle *gesture); gboolean phosh_util_have_gnome_software (gboolean scan); void phosh_util_toggle_style_class (GtkWidget *widget, const char *style_class, gboolean toggle); const char *phosh_util_get_stylesheet (const char *theme_name); +gboolean phosh_clear_fd (int *fd, GError **err); -- GitLab From 2f2b7e9eaeeda463a288e2599a88a199270394b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 5 Mar 2021 14:20:05 +0100 Subject: [PATCH 03/12] screen-saver-manager: Separate locking from blanking Honor org.gnome.desktop.screen-saver lock-enabled so we don't lock the screen if that is disabled and handle lock-delay to not lock immediately. For that we mark screensaver as active/inactive based on the power mode of the primary monitor. We don't use the built-in monitor since that can be disabled in multi-screen setups but the primary is the last one to go off. Part-of: --- src/screen-saver-manager.c | 216 ++++++++++++++++++++++++++++++++----- src/shell.c | 34 +++--- 2 files changed, 213 insertions(+), 37 deletions(-) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index ddc5a4d14..aa8c2c599 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -9,6 +9,7 @@ #define G_LOG_DOMAIN "phosh-screen-saver-manager" #include "screen-saver-manager.h" +#include "session-presence.h" #include "shell.h" #include "idle-manager.h" #include "login1-manager-dbus.h" @@ -36,6 +37,9 @@ enum { PROP_0, PROP_LOCKSCREEN_MANAGER, + PROP_LOCK_ENABLED, + PROP_LOCK_DELAY, + PROP_ACTIVE, PROP_LAST_PROP }; static GParamSpec *props[PROP_LAST_PROP]; @@ -50,6 +54,13 @@ typedef struct _PhoshScreenSaverManager int dbus_name_id; PhoshLockscreenManager *lockscreen_manager; PhoshSessionPresence *presence; /* gnome-session's presence interface */ + gboolean active; + + GSettings *settings; + gboolean lock_enabled; + gboolean lock_delay; + guint lock_delay_timer_id; + PhoshMonitor *primary_monitor; PhoshDBusLoginSession *logind_session_proxy; PhoshDBusLoginManager *logind_manager_proxy; @@ -64,6 +75,62 @@ G_DEFINE_TYPE_WITH_CODE (PhoshScreenSaverManager, PHOSH_DBUS_TYPE_SCREEN_SAVER, phosh_screen_saver_manager_screen_saver_iface_init)); + +static gboolean +on_lock_delay_timer_expired (gpointer data) +{ + PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (data); + + phosh_lockscreen_manager_set_locked (self->lockscreen_manager, TRUE); + + self->lock_delay_timer_id = 0; + return G_SOURCE_REMOVE; +} + +/* Activate or deactivate screen blank based on `active`. If `lock` is %TRUE locking + is also enabled (honoring the configure delay */ +static void +screen_saver_set_active (PhoshScreenSaverManager *self, gboolean active, gboolean lock) +{ + if (self->active == active) + return; + + g_debug ("Activiting screen saver: %d, lock: %d, lock_delay: %d", active, lock, + self->lock_delay); + + phosh_shell_enable_power_save (phosh_shell_get_default (), active); + + /* TODO: move the lock screen timer to the lockscreen-manager as the time is independent + from blank (e.g. we could lock, then blank too */ + if (!active || !lock) { + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); + return; + } + + /* Already locked, no locking to do */ + if (phosh_lockscreen_manager_get_locked (self->lockscreen_manager)) + return; + + /* no delay, lock right away */ + if (self->lock_delay == 0) { + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); + phosh_lockscreen_manager_set_locked (self->lockscreen_manager, TRUE); + return; + } + + /* Timer already ticking, don't rearm */ + if (self->lock_delay_timer_id) + return; + + g_debug ("Arming lock delay timer for %d seconds", self->lock_delay); + self->lock_delay_timer_id = g_timeout_add_seconds (self->lock_delay, + on_lock_delay_timer_expired, + self); + g_source_set_name_by_id (self->lock_delay_timer_id, + "[phosh] lock_delay_timer"); +} + + static void phosh_screen_saver_manager_set_property (GObject *object, guint property_id, @@ -76,6 +143,12 @@ phosh_screen_saver_manager_set_property (GObject *object, case PROP_LOCKSCREEN_MANAGER: self->lockscreen_manager = g_value_dup_object (value); break; + case PROP_LOCK_ENABLED: + self->lock_enabled = g_value_get_boolean (value); + break; + case PROP_LOCK_DELAY: + self->lock_delay = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -95,6 +168,15 @@ phosh_screen_saver_manager_get_property (GObject *object, case PROP_LOCKSCREEN_MANAGER: g_value_set_object (value, self->lockscreen_manager); break; + case PROP_LOCK_ENABLED: + g_value_set_boolean (value, self->lock_enabled); + break; + case PROP_LOCK_DELAY: + g_value_set_int (value, self->lock_delay); + break; + case PROP_ACTIVE: + self->active = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -106,15 +188,13 @@ handle_get_active (PhoshDBusScreenSaver *skeleton, GDBusMethodInvocation *invocation) { PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (skeleton); - gboolean locked; g_return_val_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self), FALSE); g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self->lockscreen_manager), FALSE); - locked = phosh_lockscreen_manager_get_locked (self->lockscreen_manager); - g_debug ("DBus call GetActive: %d", locked); + g_debug ("DBus call GetActive: %d", self->active); - phosh_dbus_screen_saver_complete_get_active (skeleton, invocation, locked); + phosh_dbus_screen_saver_complete_get_active (skeleton, invocation, self->active); return TRUE; } @@ -152,30 +232,27 @@ handle_lock (PhoshDBusScreenSaver *skeleton, g_debug ("DBus call lock"); phosh_lockscreen_manager_set_locked (self->lockscreen_manager, TRUE); + /* TODO: wait a little before blanking */ + screen_saver_set_active (self, TRUE, TRUE); phosh_dbus_screen_saver_complete_lock (skeleton, invocation); return TRUE; } + static gboolean handle_set_active (PhoshDBusScreenSaver *skeleton, GDBusMethodInvocation *invocation, - gboolean lock) + gboolean active) { PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (skeleton); g_return_val_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self), FALSE); g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self->lockscreen_manager), FALSE); - g_debug ("DBus call SetActive: %d", lock); - if (lock) { - phosh_lockscreen_manager_set_locked (self->lockscreen_manager, lock); - } else { - /* Screensaver active and screeen locked is the same so just - discard requests to de-activate the screensaver */ - g_debug ("Ignoring request to deactivate screen saver"); - } + g_debug ("DBus call SetActive: %d, lock-enabled: %d", active, self->lock_enabled); + screen_saver_set_active (self, active, self->lock_enabled); phosh_dbus_screen_saver_complete_set_active (skeleton, invocation); @@ -193,26 +270,21 @@ phosh_screen_saver_manager_screen_saver_iface_init (PhoshDBusScreenSaverIface *i } static void -on_lockscreen_manager_notify_locked (PhoshScreenSaverManager *self, - GParamSpec *pspec, - PhoshLockscreenManager *lockscreen_manager) +notify_active_changed (PhoshScreenSaverManager *self) { - gboolean locked; GDBusInterfaceSkeleton *skeleton; g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); - g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (lockscreen_manager)); skeleton = G_DBUS_INTERFACE_SKELETON (self); - locked = phosh_lockscreen_manager_get_locked(self->lockscreen_manager); - g_debug ("Signaling ActiveChanged: %d", locked); + g_debug ("Signaling ActiveChanged: %d", self->active); g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), NULL, g_dbus_interface_skeleton_get_object_path (skeleton), SCREEN_SAVER_DBUS_NAME, "ActiveChanged", - g_variant_new ("(b)", locked), + g_variant_new ("(b)", self->active), NULL); } @@ -288,8 +360,9 @@ on_presence_status_changed (PhoshScreenSaverManager *self, guint32 status, gpoin g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); g_debug ("Presence status changed: %d", status); + if (status == PHOSH_SESSION_PRESENCE_STATUS_IDLE) - phosh_lockscreen_manager_set_locked (self->lockscreen_manager, TRUE); + screen_saver_set_active (self, TRUE, self->lock_enabled); } @@ -307,11 +380,8 @@ on_name_acquired (GDBusConnection *connection, end up sending out signals early */ g_object_connect ( self->lockscreen_manager, - "swapped-object-signal::notify::locked", G_CALLBACK (on_lockscreen_manager_notify_locked), self, "swapped-object-signal::wakeup-outputs", G_CALLBACK (on_lockscreen_manager_wakeup_outputs), self, NULL); - - on_lockscreen_manager_notify_locked (self, NULL, self->lockscreen_manager); } @@ -346,15 +416,18 @@ phosh_screen_saver_manager_dispose (GObject *object) g_cancellable_cancel (self->cancel); g_clear_object (&self->cancel); + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); g_clear_handle_id (&self->idle_id, g_source_remove); g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + g_clear_object (&self->settings); g_clear_object (&self->lockscreen_manager); g_clear_object (&self->logind_session_proxy); g_clear_object (&self->logind_manager_proxy); + g_clear_object (&self->primary_monitor); g_clear_object (&self->presence); @@ -455,6 +528,56 @@ on_logind_manager_proxy_new_for_bus_finish (GObject *source_obje } +static void +on_primary_monitor_power_mode_changed (PhoshScreenSaverManager *self, + GParamSpec *pspec, + PhoshMonitor *monitor) +{ + gboolean active; + PhoshMonitorPowerSaveMode mode; + + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + + mode = phosh_monitor_get_power_save_mode (monitor); + + active = (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF); + g_debug ("Screensaver marked as %sactive", active ? "" : "in"); + if (active != self->active) { + self->active = active; + g_object_notify_by_pspec(G_OBJECT (self), props[PROP_ACTIVE]); + notify_active_changed (self); + } +} + + +static void +on_primary_monitor_changed (PhoshScreenSaverManager *self, + GParamSpec *psepc, + PhoshShell *shell) +{ + g_return_if_fail (PHOSH_IS_SHELL (shell)); + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + + if (self->primary_monitor) + g_signal_handlers_disconnect_by_data(self->primary_monitor, self); + + g_set_object (&self->primary_monitor, phosh_shell_get_primary_monitor (shell)); + + if (self->primary_monitor == NULL) { + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); + return; + } + + g_signal_connect_object (self->primary_monitor, + "notify::power-mode", + G_CALLBACK (on_primary_monitor_power_mode_changed), + self, + G_CONNECT_SWAPPED); + on_primary_monitor_power_mode_changed (self, NULL, self->primary_monitor); +} + + static gboolean on_idle (PhoshScreenSaverManager *self) { @@ -469,6 +592,13 @@ on_idle (PhoshScreenSaverManager *self) self); self->idle_id = 0; + + g_signal_connect_swapped (phosh_shell_get_default (), + "notify::primary-monitor", + G_CALLBACK (on_primary_monitor_changed), + self); + on_primary_monitor_changed (self, NULL, phosh_shell_get_default ()); + return G_SOURCE_REMOVE; } @@ -491,6 +621,10 @@ phosh_screen_saver_manager_constructed (GObject *object) g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self->lockscreen_manager)); + self->settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_settings_bind (self->settings, "lock-enabled", self, "lock-enabled", G_SETTINGS_BIND_GET); + g_settings_bind (self->settings, "lock-delay", self, "lock-delay", G_SETTINGS_BIND_GET); + self->presence = phosh_session_presence_get_default_failable (); if (self->presence) { g_signal_connect_swapped (self->presence, @@ -521,6 +655,38 @@ phosh_screen_saver_manager_class_init (PhoshScreenSaverManagerClass *klass) PHOSH_TYPE_LOCKSCREEN_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + /** + * PhoshScreenSaverManager:lock-enabled: + * + * Whether activating the screens saver should also lock the screen + */ + props[PROP_LOCK_ENABLED] = + g_param_spec_boolean ("lock-enabled", "", "", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * PhoshScreenSaverManager:lock-delay: + * + * Delay in seconds for screen lock after blank + */ + props[PROP_LOCK_DELAY] = + g_param_spec_int ("lock-delay", "", "", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * PhoshScreenSaverManager:active + * + * Whether the screen saver is active + */ + props[PROP_ACTIVE] = + g_param_spec_boolean ("active", "", "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } diff --git a/src/shell.c b/src/shell.c index d86f56ed3..82638893f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -760,16 +760,26 @@ static void on_builtin_monitor_power_mode_changed (PhoshShell *self, GParamSpec *pspec, PhoshMonitor *monitor) { PhoshMonitorPowerSaveMode mode; - PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); - priv = phosh_shell_get_instance_private (self); + /* + * TODO: this should maybe track the primary monitor, not the built + * in one as that can be blanked while an attached screen (with the + * primary display) is still on however we want to track the + * built-in monitor for the proximity sensor + */ g_object_get (monitor, "power-mode", &mode, NULL); - /* Might be emitted on startup before lockscreen_manager is up */ - if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF && priv->lockscreen_manager) + +#if 0 + /* + * TODO; Phoc currenctly just blanks the screen on power press and expects us to lock, by + * disabling this we fail to do so (but this lets the rest work correctly). + */ + if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF) phosh_shell_lock (self); +#endif phosh_shell_set_state (self, PHOSH_STATE_BLANKED, mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF); } @@ -1642,16 +1652,16 @@ phosh_shell_fade_out (PhoshShell *self, guint timeout) void phosh_shell_enable_power_save (PhoshShell *self, gboolean enable) { - g_debug ("Entering power save mode"); - g_return_if_fail (PHOSH_IS_SHELL (self)); + PhoshShellPrivate *priv; + PhoshMonitorPowerSaveMode ps_mode; - /* - * Locking the outputs instructs g-s-d to tell us to put - * outputs into power save mode via org.gnome.Mutter.DisplayConfig - */ - phosh_shell_set_locked(self, enable); + g_debug ("Entering power save mode: %d", enable); + + g_return_if_fail (PHOSH_IS_SHELL (self)); + priv = phosh_shell_get_instance_private (self); - /* TODO: other means of power saving */ + ps_mode = enable ? PHOSH_MONITOR_POWER_SAVE_MODE_OFF : PHOSH_MONITOR_POWER_SAVE_MODE_ON; + phosh_monitor_manager_set_power_save_mode (priv->monitor_manager, ps_mode); } /** -- GitLab From a145e409fd572ece4e2dc28e0d756efb42181476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 7 Sep 2022 15:28:41 +0200 Subject: [PATCH 04/12] screen-saver-manager: Document what affects blanking and locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther Part-of: --- docs/gettingstarted.md | 5 ++++- src/screen-saver-manager.c | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/gettingstarted.md b/docs/gettingstarted.md index 465f748c3..2c1238223 100644 --- a/docs/gettingstarted.md +++ b/docs/gettingstarted.md @@ -74,7 +74,6 @@ as part GNOME session so the start sequence looks like phoc (compositor) -> gnome-session -> phosh (and other session components) ``` - ## Hints This is a unsorted list of hints when developing for Phosh @@ -99,6 +98,10 @@ e.g. the corresponding DBus service went away). In that case the widget should flip a boolean property so the parent container can hide the object via #g_object_bind_property(). +### Screen locking and blanking + +For details see [class@ScreenSaverManager]. + ### Debugging Since phosh is a GTK application you can use diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index aa8c2c599..c44ccfbc0 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -23,10 +23,23 @@ * * Provides the org.gnome.ScreenSaver DBus interface and handles logind's Session * - * See https://people.gnome.org/~mccann/gnome-screensaver/docs/gnome-screensaver.html - * for a (a bit outdated) interface description. It also handles the login1 session - * parts since those are closely related and this keeps #PhoshLockscreenManager free - * of the DBus handling. + * This handles the `org.gnome.ScreenSaver` DBus API for screen locking and unlocking. + * It also handles the login1 session parts since those are closely related and this + * keeps #PhoshLockscreenManager free of any session related DBus handling. + * + * These settings influence screen blanking and locking: + * + * `org.gnome.desktop.session idle-delay`: The session is considered idle after that many + * seconds of inactivity. This isn't monitored by phosh directly but is done by gnome-session that + * in turn uses `GnomeIdleMonitor` which then uses `/org/gnome/Mutter/IdleMonitor/Core` on DBus. + * `/org/gnome/Mutter/IdleMonitor/Core` is implemented by #PhoshIdleManager which in turn gets + * it from phoc which implements the `org_kde_kwin_idle` wayland protocol. + * + * `org.gnome.desktop.screensaver` `lock-enabled`: Whether the screen should be locked after + * the screen-saver is activated. + * + * `org.gnome.desktop.screensaver` `lock-delay`: How long after screen-saver activation should + * the screen be locked. */ #define SCREEN_SAVER_DBUS_NAME "org.gnome.ScreenSaver" @@ -100,8 +113,6 @@ screen_saver_set_active (PhoshScreenSaverManager *self, gboolean active, gboolea phosh_shell_enable_power_save (phosh_shell_get_default (), active); - /* TODO: move the lock screen timer to the lockscreen-manager as the time is independent - from blank (e.g. we could lock, then blank too */ if (!active || !lock) { g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); return; @@ -126,8 +137,7 @@ screen_saver_set_active (PhoshScreenSaverManager *self, gboolean active, gboolea self->lock_delay_timer_id = g_timeout_add_seconds (self->lock_delay, on_lock_delay_timer_expired, self); - g_source_set_name_by_id (self->lock_delay_timer_id, - "[phosh] lock_delay_timer"); + g_source_set_name_by_id (self->lock_delay_timer_id, "[phosh] lock_delay_timer"); } -- GitLab From a12b7e7df19754eab75a5a5ddc56bdda7aba0eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Mon, 29 Mar 2021 12:21:32 +0200 Subject: [PATCH 05/12] screen-saver-manager: Handle power button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves it out of the compositor allowing us to distinguish lock from blank Signed-off-by: Guido Günther Part-of: --- src/screen-saver-manager.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index c44ccfbc0..133dbbd77 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -141,6 +141,16 @@ screen_saver_set_active (PhoshScreenSaverManager *self, gboolean active, gboolea } +static void +toggle_blank (GSimpleAction *action, GVariant *param, gpointer data) +{ + PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (data); + + g_debug ("Power button press, toggling screensaver %d", !self->active); + screen_saver_set_active (self, !self->active, TRUE); +} + + static void phosh_screen_saver_manager_set_property (GObject *object, guint property_id, @@ -613,6 +623,21 @@ on_idle (PhoshScreenSaverManager *self) } +static void +add_keybindings (PhoshScreenSaverManager *self) +{ + GActionEntry entries[] = { + { "XF86PowerOff", toggle_blank }, + }; + + /* TODO: don't bind power button when g-s-d's power-button-action != 'nothing' */ + phosh_shell_add_global_keyboard_action_entries (phosh_shell_get_default (), + (GActionEntry*)entries, + G_N_ELEMENTS (entries), + self); +} + + static void phosh_screen_saver_manager_constructed (GObject *object) { @@ -635,6 +660,8 @@ phosh_screen_saver_manager_constructed (GObject *object) g_settings_bind (self->settings, "lock-enabled", self, "lock-enabled", G_SETTINGS_BIND_GET); g_settings_bind (self->settings, "lock-delay", self, "lock-delay", G_SETTINGS_BIND_GET); + add_keybindings (self); + self->presence = phosh_session_presence_get_default_failable (); if (self->presence) { g_signal_connect_swapped (self->presence, -- GitLab From 74dc0aa11ad7148c9fb983ee568df61da93277c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sat, 31 Dec 2022 13:06:29 +0100 Subject: [PATCH 06/12] gnome-shell-manager: Don't allow to bind power key This allows us to do the "blank screen" handling until we fixed gsd#703. Part-of: --- src/gnome-shell-manager.c | 19 +++++++++++++++---- src/screen-saver-manager.c | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/gnome-shell-manager.c b/src/gnome-shell-manager.c index e73e95550..89865fd9e 100644 --- a/src/gnome-shell-manager.c +++ b/src/gnome-shell-manager.c @@ -238,10 +238,21 @@ grab_single_accelerator (PhoshGnomeShellManager *self, g_debug ("Using action id %d for accelerator %s", info->action_id, info->accelerator); g_hash_table_insert (self->info_by_action, GUINT_TO_POINTER (info->action_id), info); - phosh_shell_add_global_keyboard_action_entries (phosh_shell_get_default (), - action_entries, - G_N_ELEMENTS (action_entries), - info); + + if (g_strcmp0 (accelerator, "XF86PowerOff")) { + phosh_shell_add_global_keyboard_action_entries (phosh_shell_get_default (), + action_entries, + G_N_ELEMENTS (action_entries), + info); + } else { + /* + * FIXME: Don't allow binding of power keys so we can blank the screen + * See https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/issues/703 + * We don't return an error as we want g-s-d to handle all the other keys + */ + g_debug ("Skipping power key grab"); + } + g_assert (info->action_id > 0); return info->action_id; } diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index 133dbbd77..1997b27fd 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -630,7 +630,7 @@ add_keybindings (PhoshScreenSaverManager *self) { "XF86PowerOff", toggle_blank }, }; - /* TODO: don't bind power button when g-s-d's power-button-action != 'nothing' */ + /* g-s-manager's grab_single_accelerator makes sure g-s-d doesn't bind it */ phosh_shell_add_global_keyboard_action_entries (phosh_shell_get_default (), (GActionEntry*)entries, G_N_ELEMENTS (entries), -- GitLab From a99d47b4a68070447ca94d4a9e963c4227966aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 9 Sep 2022 10:27:13 +0200 Subject: [PATCH 07/12] shell: Track blanked state via primary monitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If that is blanked all other outputs should be blanked too Signed-off-by: Guido Günther Part-of: --- src/shell.c | 71 ++++++++++++++++++++++------------------------------- src/shell.h | 2 +- 2 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/shell.c b/src/shell.c index 82638893f..9e5d042e0 100644 --- a/src/shell.c +++ b/src/shell.c @@ -268,6 +268,20 @@ on_home_state_changed (PhoshShell *self, GParamSpec *pspec, PhoshHome *home) } +static void +on_primary_monitor_power_mode_changed (PhoshShell *self, GParamSpec *pspec, PhoshMonitor *monitor) +{ + PhoshMonitorPowerSaveMode mode; + + g_return_if_fail (PHOSH_IS_SHELL (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + + g_object_get (monitor, "power-mode", &mode, NULL); + + phosh_shell_set_state (self, PHOSH_STATE_BLANKED, mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF); +} + + static void on_primary_monitor_configured (PhoshShell *self, PhoshMonitor *monitor) { @@ -284,9 +298,15 @@ on_primary_monitor_configured (PhoshShell *self, PhoshMonitor *monitor) static void -setup_primary_monitor_configured_handler (PhoshShell *self) +setup_primary_monitor_signal_handlers (PhoshShell *self) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); + + g_signal_connect_swapped (priv->primary_monitor, + "notify::power-mode", + G_CALLBACK (on_primary_monitor_power_mode_changed), + self); + g_signal_connect_object (priv->primary_monitor, "configured", G_CALLBACK (on_primary_monitor_configured), self, @@ -717,7 +737,7 @@ setup_idle_cb (PhoshShell *self) priv->network_auth_manager = phosh_network_auth_manager_new (); priv->portal_access_manager = phosh_portal_access_manager_new (); - setup_primary_monitor_configured_handler (self); + setup_primary_monitor_signal_handlers (self); /* Delay signaling the compositor a bit so that idle handlers get a * chance to run and the user has can unlock right away. Ideally @@ -756,34 +776,6 @@ type_setup (void) } -static void -on_builtin_monitor_power_mode_changed (PhoshShell *self, GParamSpec *pspec, PhoshMonitor *monitor) -{ - PhoshMonitorPowerSaveMode mode; - - g_return_if_fail (PHOSH_IS_SHELL (self)); - g_return_if_fail (PHOSH_IS_MONITOR (monitor)); - - /* - * TODO: this should maybe track the primary monitor, not the built - * in one as that can be blanked while an attached screen (with the - * primary display) is still on however we want to track the - * built-in monitor for the proximity sensor - */ - g_object_get (monitor, "power-mode", &mode, NULL); - -#if 0 - /* - * TODO; Phoc currenctly just blanks the screen on power press and expects us to lock, by - * disabling this we fail to do so (but this lets the rest work correctly). - */ - if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF) - phosh_shell_lock (self); -#endif - - phosh_shell_set_state (self, PHOSH_STATE_BLANKED, mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF); -} - static void phosh_shell_set_builtin_monitor (PhoshShell *self, PhoshMonitor *monitor) { @@ -797,10 +789,6 @@ phosh_shell_set_builtin_monitor (PhoshShell *self, PhoshMonitor *monitor) return; if (priv->builtin_monitor) { - /* Power mode listener */ - g_signal_handlers_disconnect_by_func (priv->builtin_monitor, - G_CALLBACK (on_builtin_monitor_power_mode_changed), - self); g_clear_object (&priv->builtin_monitor); if (priv->rotation_manager) @@ -811,11 +799,6 @@ phosh_shell_set_builtin_monitor (PhoshShell *self, PhoshMonitor *monitor) g_set_object (&priv->builtin_monitor, monitor); if (monitor) { - g_signal_connect_swapped (priv->builtin_monitor, - "notify::power-mode", - G_CALLBACK (on_builtin_monitor_power_mode_changed), - self); - if (priv->rotation_manager) phosh_rotation_manager_set_monitor (priv->rotation_manager, monitor); } @@ -1120,10 +1103,14 @@ phosh_shell_set_primary_monitor (PhoshShell *self, PhoshMonitor *monitor) if (monitor == priv->primary_monitor) return; - if (priv->primary_monitor) + if (priv->primary_monitor) { g_signal_handlers_disconnect_by_func (priv->primary_monitor, G_CALLBACK (on_primary_monitor_configured), self); + g_signal_handlers_disconnect_by_func (priv->builtin_monitor, + G_CALLBACK (on_primary_monitor_power_mode_changed), + self); + } if (monitor != NULL) { /* Make sure the new monitor exists */ @@ -1146,13 +1133,13 @@ phosh_shell_set_primary_monitor (PhoshShell *self, PhoshMonitor *monitor) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRIMARY_MONITOR]); - setup_primary_monitor_configured_handler (self); + setup_primary_monitor_signal_handlers (self); /* All monitors gone or disabled. See if monitor-manager finds a * fallback to enable. Do that in an idle callback so GTK can process * pending wayland events for the gone output */ if (monitor == NULL) { - /* No monitor we're not useful atm */ + /* No monitor - we're not useful atm */ notify_compositor_up_state (self, PHOSH_PRIVATE_SHELL_STATE_UNKNOWN); g_idle_add (select_fallback_monitor, self); } else { diff --git a/src/shell.h b/src/shell.h index 5bd6b8876..cc6c45fcf 100644 --- a/src/shell.h +++ b/src/shell.h @@ -38,7 +38,7 @@ G_BEGIN_DECLS * PhoshShellStateFlags: * @PHOSH_STATE_NONE: No other state * @PHOSH_STATE_MODAL_SYSTEM_PROMPT: any modal prompt shown - * @PHOSH_STATE_BLANKED: built-in display off + * @PHOSH_STATE_BLANKED: primary display off * @PHOSH_STATE_LOCKED: displays locked * @PHOSH_STATE_SETTINGS: settings menu unfolded from top bar * @PHOSH_STATE_OVERVIEW: overview unfolded from bottom bar -- GitLab From b78773a55cfd900b4fed9216f8a779d0058aa621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 28 Dec 2022 19:25:11 +0100 Subject: [PATCH 08/12] screen-saver-manager: Unset idle source close to return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value indicates we want to remove the source so reset the idle_id close to that. Signed-off-by: Guido Günther Part-of: --- src/screen-saver-manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index 1997b27fd..0da820963 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -611,14 +611,13 @@ on_idle (PhoshScreenSaverManager *self) (GAsyncReadyCallback) on_logind_manager_proxy_new_for_bus_finish, self); - self->idle_id = 0; - g_signal_connect_swapped (phosh_shell_get_default (), "notify::primary-monitor", G_CALLBACK (on_primary_monitor_changed), self); on_primary_monitor_changed (self, NULL, phosh_shell_get_default ()); + self->idle_id = 0; return G_SOURCE_REMOVE; } -- GitLab From 873113c63a97fc4fad6b2770ab51aeee5b8dc1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 28 Dec 2022 20:06:55 +0100 Subject: [PATCH 09/12] screen-saver-manager: Inhibit logind actions on power button press MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to handle this ourselves. This will hopefully move to g-s-d (see gsd#703) once there's consensus. Signed-off-by: Guido Günther Part-of: --- src/screen-saver-manager.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index 0da820963..2e67c96b1 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -18,6 +18,9 @@ #include "session-presence.h" #include "util.h" +#include +#include + /** * PhoshScreenSaverManager: * @@ -73,6 +76,7 @@ typedef struct _PhoshScreenSaverManager gboolean lock_enabled; gboolean lock_delay; guint lock_delay_timer_id; + int inhibit_pwr_btn_fd; PhoshMonitor *primary_monitor; PhoshDBusLoginSession *logind_session_proxy; @@ -440,6 +444,8 @@ phosh_screen_saver_manager_dispose (GObject *object) g_clear_handle_id (&self->idle_id, g_source_remove); g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + phosh_clear_fd (&self->inhibit_pwr_btn_fd, NULL); + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); @@ -512,6 +518,44 @@ on_logind_manager_get_session_finished (PhoshDBusLoginManager *object, } +static void +on_inhibit_pwr_button_finished (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean success; + PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (user_data); + PhoshDBusLoginManager *proxy; + g_autoptr (GError) err = NULL; + g_autoptr (GUnixFDList) fd_list = NULL; + g_autoptr (GVariant) out_pipe_fd = NULL; + int idx; + + proxy = PHOSH_DBUS_LOGIN_MANAGER (source_object); + success = phosh_dbus_login_manager_call_inhibit_finish (proxy, + &out_pipe_fd, + &fd_list, + res, + &err); + if (!success) { + g_warning ("Failed to inhibit power button: %s", err->message); + return; + } + + g_return_if_fail (fd_list && g_unix_fd_list_get_length (fd_list) == 1); + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + + g_variant_get (out_pipe_fd, "h", &idx); + self->inhibit_pwr_btn_fd = g_unix_fd_list_get (fd_list, idx, &err); + if (self->inhibit_pwr_btn_fd < 0) { + g_warning ("Failed to get power button inhibit fd: %s", err->message); + return; + } + + g_debug ("Inhibited logind power button handling"); +} + + static void on_logind_manager_proxy_new_for_bus_finish (GObject *source_object, GAsyncResult *res, @@ -545,6 +589,16 @@ on_logind_manager_proxy_new_for_bus_finish (GObject *source_obje } g_debug ("Connected to logind's session interface"); + + phosh_dbus_login_manager_call_inhibit (self->logind_manager_proxy, + "handle-power-key", + g_get_user_name (), + "Phosh handling power key", + "block", + NULL, + self->cancel, + on_inhibit_pwr_button_finished, + self); } -- GitLab From fadcc5a4d6f31927682f5a4e9c428c0c6f13d725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 30 Dec 2022 10:06:09 +0100 Subject: [PATCH 10/12] screen-saver-manager: Disable lock delay timer on unlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther Part-of: --- src/screen-saver-manager.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index 2e67c96b1..3cdb59ed1 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -341,6 +341,22 @@ on_lockscreen_manager_wakeup_outputs (PhoshScreenSaverManager *self, } +static void +on_lockscreen_manager_locked_changed (PhoshScreenSaverManager *self) +{ + gboolean locked; + + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + + locked = phosh_lockscreen_manager_get_locked (self->lockscreen_manager); + if (locked == TRUE) + return; + + g_debug ("Disabling lock delay timer on unlock"); + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); +} + + static void on_logind_lock (PhoshScreenSaverManager *self, PhoshDBusLoginSession *proxy) { @@ -405,6 +421,7 @@ on_name_acquired (GDBusConnection *connection, g_object_connect ( self->lockscreen_manager, "swapped-object-signal::wakeup-outputs", G_CALLBACK (on_lockscreen_manager_wakeup_outputs), self, + "swapped-object-signal::notify::locked", G_CALLBACK (on_lockscreen_manager_locked_changed), self, NULL); } -- GitLab From 6d17a7fee7420d0eb19f84651f5e1014098afef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sat, 31 Dec 2022 13:56:34 +0100 Subject: [PATCH 11/12] screen-saver-manager: Disable lock delay timer when screen becomes active again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther Part-of: --- src/screen-saver-manager.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index 3cdb59ed1..eb5aca768 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -639,6 +639,11 @@ on_primary_monitor_power_mode_changed (PhoshScreenSaverManager *self, g_object_notify_by_pspec(G_OBJECT (self), props[PROP_ACTIVE]); notify_active_changed (self); } + + if (self->active == FALSE) { + g_debug ("Disabling lock delay timer on power mode change"); + g_clear_handle_id (&self->lock_delay_timer_id, g_source_remove); + } } -- GitLab From ff66082188b8a35cb82c1d8c3de1743c3f57963e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bellegarde?= Date: Thu, 19 Jan 2023 22:45:17 +0100 Subject: [PATCH 12/12] screen-saver-manager: Add a suspend delay inhibitor We need to be sure ActiveChanged D-Bus signal is emitted before going to suspend as we'd otherwise blank right after resume. Part-of: --- src/screen-saver-manager.c | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/screen-saver-manager.c b/src/screen-saver-manager.c index eb5aca768..260be011f 100644 --- a/src/screen-saver-manager.c +++ b/src/screen-saver-manager.c @@ -77,6 +77,7 @@ typedef struct _PhoshScreenSaverManager gboolean lock_delay; guint lock_delay_timer_id; int inhibit_pwr_btn_fd; + int inhibit_suspend_fd; PhoshMonitor *primary_monitor; PhoshDBusLoginSession *logind_session_proxy; @@ -310,6 +311,63 @@ notify_active_changed (PhoshScreenSaverManager *self) "ActiveChanged", g_variant_new ("(b)", self->active), NULL); + if (self->active) { + g_debug ("Uninhibited logind suspend handling"); + phosh_clear_fd (&self->inhibit_suspend_fd, NULL); + } +} + +static void +on_inhibit_suspend_finished (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean success; + PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (user_data); + PhoshDBusLoginManager *proxy; + g_autoptr (GError) err = NULL; + g_autoptr (GUnixFDList) fd_list = NULL; + g_autoptr (GVariant) out_pipe_fd = NULL; + int idx; + + proxy = PHOSH_DBUS_LOGIN_MANAGER (source_object); + success = phosh_dbus_login_manager_call_inhibit_finish (proxy, + &out_pipe_fd, + &fd_list, + res, + &err); + if (!success) { + g_warning ("Failed to inhibit suspend: %s", err->message); + return; + } + + g_return_if_fail (fd_list && g_unix_fd_list_get_length (fd_list) == 1); + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + + g_variant_get (out_pipe_fd, "h", &idx); + self->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &err); + if (self->inhibit_suspend_fd < 0) { + g_warning ("Failed to get suspend inhibit fd: %s", err->message); + return; + } + + g_debug ("Inhibited logind suspend handling"); +} + +static void +phosh_screen_saver_manager_inhibit_suspend (PhoshScreenSaverManager *self) +{ + g_return_if_fail (PHOSH_IS_SCREEN_SAVER_MANAGER (self)); + + phosh_dbus_login_manager_call_inhibit (self->logind_manager_proxy, + "sleep", + g_get_user_name (), + "Phosh handling suspend", + "delay", + NULL, + self->cancel, + on_inhibit_suspend_finished, + self); } static void @@ -390,6 +448,7 @@ on_logind_prepare_for_sleep (PhoshScreenSaverManager *self, idle_manager = phosh_idle_manager_get_default (); phosh_idle_manager_reset_timers (idle_manager); + phosh_screen_saver_manager_inhibit_suspend (self); } } @@ -462,6 +521,7 @@ phosh_screen_saver_manager_dispose (GObject *object) g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); phosh_clear_fd (&self->inhibit_pwr_btn_fd, NULL); + phosh_clear_fd (&self->inhibit_suspend_fd, NULL); if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); @@ -616,6 +676,8 @@ on_logind_manager_proxy_new_for_bus_finish (GObject *source_obje self->cancel, on_inhibit_pwr_button_finished, self); + + phosh_screen_saver_manager_inhibit_suspend (self); } @@ -807,6 +869,7 @@ static void phosh_screen_saver_manager_init (PhoshScreenSaverManager *self) { self->cancel = g_cancellable_new (); + self->inhibit_suspend_fd = -1; } -- GitLab