From 5dad0034c750cda56b9e36f8132ec6d404ff2a17 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Tue, 14 Jul 2026 17:06:06 +0400 Subject: [PATCH 1/5] backends/idle-monitor: Add support for ignoring inhibitors Introduce meta_idle_monitor_add_idle_watch_full() which allows creating idle watches that ignore active session inhibitors. --- src/backends/meta-idle-monitor-private.h | 8 ++++++ src/backends/meta-idle-monitor.c | 35 ++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/backends/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-private.h index d498f13f9..497d0486d 100644 --- a/src/backends/meta-idle-monitor-private.h +++ b/src/backends/meta-idle-monitor-private.h @@ -36,6 +36,7 @@ typedef struct guint64 timeout_msec; int idle_source_id; GSource *timeout_source; + gboolean ignore_inhibitors; } MetaIdleMonitorWatch; struct _MetaIdleMonitor @@ -56,4 +57,11 @@ struct _MetaIdleMonitorClass void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor); +guint meta_idle_monitor_add_idle_watch_full (MetaIdleMonitor *monitor, + guint64 interval_msec, + gboolean ignore_inhibitors, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify); + #endif /* META_IDLE_MONITOR_PRIVATE_H */ diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c index f2c6c75db..82e9d113f 100644 --- a/src/backends/meta-idle-monitor.c +++ b/src/backends/meta-idle-monitor.c @@ -181,7 +181,7 @@ update_inhibited_watch (gpointer key, if (!watch->timeout_source) return; - if (monitor->inhibited) + if (monitor->inhibited && !watch->ignore_inhibitors) { g_source_set_ready_time (watch->timeout_source, -1); } @@ -337,6 +337,7 @@ make_watch (MetaIdleMonitor *monitor, watch->user_data = user_data; watch->notify = notify; watch->timeout_msec = timeout_msec; + watch->ignore_inhibitors = FALSE; if (timeout_msec != 0) { @@ -498,7 +499,7 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor) } else { - if (monitor->inhibited) + if (monitor->inhibited && !watch->ignore_inhibitors) { g_source_set_ready_time (watch->timeout_source, -1); } @@ -513,3 +514,33 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor) g_list_free (watch_ids); } + +guint +meta_idle_monitor_add_idle_watch_full (MetaIdleMonitor *monitor, + guint64 interval_msec, + gboolean ignore_inhibitors, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); + g_return_val_if_fail (interval_msec > 0, 0); + + watch = make_watch (monitor, + interval_msec, + callback, + user_data, + notify); + + watch->ignore_inhibitors = ignore_inhibitors; + + if (monitor->inhibited && ignore_inhibitors && watch->timeout_source) + { + g_source_set_ready_time (watch->timeout_source, + monitor->last_event_time + + watch->timeout_msec * 1000); + } + return watch->id; +} From 3608b9f79cfabbafe5a66e320e812d285ea684e1 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Tue, 14 Jul 2026 17:21:25 +0400 Subject: [PATCH 2/5] [Wayland] Add initial ext-idle-notify-v1 skeleton --- src/meson.build | 3 + src/wayland/meta-wayland-idle-notify.c | 85 ++++++++++++++++++++++++++ src/wayland/meta-wayland-idle-notify.h | 25 ++++++++ src/wayland/meta-wayland-versions.h | 1 + src/wayland/meta-wayland.c | 2 + 5 files changed, 116 insertions(+) create mode 100644 src/wayland/meta-wayland-idle-notify.c create mode 100644 src/wayland/meta-wayland-idle-notify.h diff --git a/src/meson.build b/src/meson.build index 796282e86..fa15dc4ba 100644 --- a/src/meson.build +++ b/src/meson.build @@ -524,6 +524,8 @@ if have_wayland 'wayland/meta-wayland-layer-shell.c', 'wayland/meta-wayland-layer-shell.h', 'wayland/meta-wayland.h', + 'wayland/meta-wayland-idle-notify.h', + 'wayland/meta-wayland-idle-notify.c', 'wayland/meta-wayland-idle-inhibit.c', 'wayland/meta-wayland-idle-inhibit.h', 'wayland/meta-wayland-inhibit-shortcuts.c', @@ -858,6 +860,7 @@ if have_wayland ['xapp-shell', 'private', ], ['xwayland-keyboard-grab', 'unstable', 'v1', ], ['wayland-drm', 'private', ], + ['ext-idle-notify', 'staging', 'v1', ], ] if have_wayland_eglstream wayland_eglstream_protocols_dir = wayland_eglstream_protocols_dep.get_variable(pkgconfig: 'pkgdatadir') diff --git a/src/wayland/meta-wayland-idle-notify.c b/src/wayland/meta-wayland-idle-notify.c new file mode 100644 index 000000000..008a5ac76 --- /dev/null +++ b/src/wayland/meta-wayland-idle-notify.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2026 Linux Mint + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include "wayland/meta-wayland-idle-notify.h" + +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-versions.h" + +#include "ext-idle-notify-v1-server-protocol.h" + +static void +ext_idle_notifier_get_idle_notification (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + uint32_t timeout, + struct wl_resource *seat) +{ +} + +static void +ext_idle_notifier_get_input_idle_notification (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + uint32_t timeout, + struct wl_resource *seat) +{ +} + +static void +ext_idle_notifier_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct ext_idle_notifier_v1_interface ext_idle_notifier_v1_impl = { + ext_idle_notifier_destroy, + ext_idle_notifier_get_idle_notification, + ext_idle_notifier_get_input_idle_notification, +}; + +static void +bind_ext_idle_notifier (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, + &ext_idle_notifier_v1_interface, + version, + id); + wl_resource_set_implementation (resource, + &ext_idle_notifier_v1_impl, + NULL, + NULL); +} + +void +meta_wayland_idle_notify_init (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &ext_idle_notifier_v1_interface, + META_EXT_IDLE_NOTIFY_V1_VERSION, + NULL, + bind_ext_idle_notifier) == NULL) + g_error ("Failed to register a global ext-idle-notify object"); +} diff --git a/src/wayland/meta-wayland-idle-notify.h b/src/wayland/meta-wayland-idle-notify.h new file mode 100644 index 000000000..4b9f3d04c --- /dev/null +++ b/src/wayland/meta-wayland-idle-notify.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 Linux Mint + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_WAYLAND_EXT_IDLE_NOTIFY_H +#define META_WAYLAND_EXT_IDLE_NOTIFY_H + +#include "wayland/meta-wayland-types.h" + +void meta_wayland_idle_notify_init (MetaWaylandCompositor *compositor); + +#endif diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index b4b3ef2f7..6283bbac0 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -44,6 +44,7 @@ #define META_GTK_SHELL1_VERSION 6 #define META_WL_SUBCOMPOSITOR_VERSION 1 #define META_ZWP_POINTER_GESTURES_V1_VERSION 3 +#define META_EXT_IDLE_NOTIFY_V1_VERSION 1 #define META_ZWP_IDLE_INHIBIT_V1_VERSION 1 #define META_ZXDG_EXPORTER_V1_VERSION 1 #define META_ZXDG_IMPORTER_V1_VERSION 1 diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index f0eba38ed..7bd756c74 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -39,6 +39,7 @@ #include "wayland/meta-wayland-drm.h" #include "wayland/meta-wayland-egl-stream.h" #include "wayland/meta-wayland-idle-inhibit.h" +#include "wayland/meta-wayland-idle-notify.h" #include "wayland/meta-wayland-inhibit-shortcuts-dialog.h" #include "wayland/meta-wayland-inhibit-shortcuts.h" #include "wayland/meta-wayland-legacy-xdg-foreign.h" @@ -478,6 +479,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *wayland_compositor) meta_wayland_input_method_manager_init (compositor); meta_wayland_virtual_keyboard_manager_init (compositor); meta_wayland_activation_init (compositor); + meta_wayland_idle_notify_init (compositor); meta_wayland_idle_inhibit_init (compositor); meta_wayland_init_xdg_wm_dialog (compositor); meta_wayland_xdg_toplevel_tag_init (compositor); From 8b80b3691da431a5f006e9d30e236b58910f68fc Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Tue, 14 Jul 2026 18:02:45 +0400 Subject: [PATCH 3/5] [Wayland] Get idle notifications via ext-idle-notify Implement the ext_idle_notification_v1 interface by connecting it to the MetaIdleMonitor backend. - Add the MetaWaylandIdleNotification struct to manage the lifetime of idle and active watches. - Implement 'idled' and 'resumed' events to correctly notify clients when the system transitions into and out of the idle state. - Handle inhibitor bypass by utilizing the newly introduced meta_idle_monitor_add_idle_watch_full() function when the ignore_inhibitors flag is set. - Ensure proper resource cleanup in ext_idle_notification_destructor to prevent memory and timer leaks when Wayland clients disconnect. --- src/wayland/meta-wayland-idle-notify.c | 135 +++++++++++++++++++++++++ src/wayland/meta-wayland-idle-notify.h | 9 ++ 2 files changed, 144 insertions(+) diff --git a/src/wayland/meta-wayland-idle-notify.c b/src/wayland/meta-wayland-idle-notify.c index 008a5ac76..b2ab3a888 100644 --- a/src/wayland/meta-wayland-idle-notify.c +++ b/src/wayland/meta-wayland-idle-notify.c @@ -24,6 +24,135 @@ #include "ext-idle-notify-v1-server-protocol.h" +typedef struct _MetaWaylandIdleNotification +{ + struct wl_resource *resource; + + MetaIdleMonitor *monitor; + + guint idle_watch_id; + guint active_watch_id; + + guint timeout; + + gboolean ignore_inhibitors; +} MetaWaylandIdleNotification; + +void +active_trigger_cb (MetaIdleMonitor *monitor, + guint id, + gpointer user_data) +{ + MetaWaylandIdleNotification *notification = user_data; + + notification->active_watch_id = 0; + + ext_idle_notification_v1_send_resumed (notification->resource); + + notification->idle_watch_id = + meta_idle_monitor_add_idle_watch_full (notification->monitor, + notification->timeout, + notification->ignore_inhibitors, + idle_trigger_cb, + notification, + NULL); +} + +void +idle_trigger_cb (MetaIdleMonitor *monitor, + guint id, + gpointer user_data) +{ + MetaWaylandIdleNotification *notification = user_data; + + notification->idle_watch_id = 0; + + ext_idle_notification_v1_send_idled (notification->resource); + + notification->active_watch_id = + meta_idle_monitor_add_user_active_watch (notification->monitor, + active_trigger_cb, + notification, + NULL); +} + +static void +ext_idle_notification_destructor (struct wl_resource *resource) +{ + MetaWaylandIdleNotification *notification = wl_resource_get_user_data (resource); + + if (notification->idle_watch_id) + meta_idle_monitor_remove_watch (notification->monitor, + notification->idle_watch_id); + + if (notification->active_watch_id) + meta_idle_monitor_remove_watch (notification->monitor, + notification->active_watch_id); + + g_free (notification); +} + +static void +ext_idle_notification_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct ext_idle_notification_v1_interface ext_idle_notification_v1_impl = { + ext_idle_notification_destroy, +}; + +static void +ext_idle_notification_create (struct wl_client *client, + struct wl_resource *manager_resource, + uint32_t id, + uint32_t timeout, + struct wl_resource *seat_resource, + gboolean ignore_inhibitors) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandIdleNotification *notification; + uint32_t version; + ClutterInputDevice *pointer_device = NULL; + + notification = g_new0 (MetaWaylandIdleNotification, 1); + notification->timeout = timeout; + notification->ignore_inhibitors = ignore_inhibitors; + + if (seat && seat->pointer) + pointer_device = seat->pointer->device; + + if (pointer_device) + { + MetaBackend *backend = meta_get_backend (); + notification->monitor = meta_backend_get_idle_monitor (backend, pointer_device); + } + else + { + notification->monitor = meta_idle_monitor_get_core (); + } + + version = wl_resource_get_version (manager_resource); + notification->resource = wl_resource_create (client, + &ext_idle_notification_v1_interface, + version, + id); + + wl_resource_set_implementation (notification->resource, + &ext_idle_notification_v1_impl, + notification, + ext_idle_notification_destructor); + + notification->idle_watch_id = + meta_idle_monitor_add_idle_watch_full (notification->monitor, + notification->timeout, + notification->ignore_inhibitors, + idle_trigger_cb, + notification, + NULL); +} + static void ext_idle_notifier_get_idle_notification (struct wl_client *client, struct wl_resource *resource, @@ -31,6 +160,9 @@ ext_idle_notifier_get_idle_notification (struct wl_client *client, uint32_t timeout, struct wl_resource *seat) { + ext_idle_notification_create (client, resource, + id, timeout, + seat, FALSE); } static void @@ -40,6 +172,9 @@ ext_idle_notifier_get_input_idle_notification (struct wl_client *client, uint32_t timeout, struct wl_resource *seat) { + ext_idle_notification_create (client, resource, + id, timeout, + seat, TRUE); } static void diff --git a/src/wayland/meta-wayland-idle-notify.h b/src/wayland/meta-wayland-idle-notify.h index 4b9f3d04c..829bb3eb4 100644 --- a/src/wayland/meta-wayland-idle-notify.h +++ b/src/wayland/meta-wayland-idle-notify.h @@ -18,8 +18,17 @@ #ifndef META_WAYLAND_EXT_IDLE_NOTIFY_H #define META_WAYLAND_EXT_IDLE_NOTIFY_H +#include "backends/meta-idle-monitor-private.h" #include "wayland/meta-wayland-types.h" +void idle_trigger_cb (MetaIdleMonitor *monitor, + guint id, + gpointer user_data); + +void active_trigger_cb (MetaIdleMonitor *monitor, + guint id, + gpointer user_data); + void meta_wayland_idle_notify_init (MetaWaylandCompositor *compositor); #endif From 7a1ec672f21c8740d1b22be460c480895619ada4 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Fri, 17 Jul 2026 19:01:31 +0400 Subject: [PATCH 4/5] remove orphaned idle watch --- src/wayland/meta-wayland-idle-notify.c | 5 +++-- src/wayland/meta-wayland-idle-notify.h | 9 --------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/wayland/meta-wayland-idle-notify.c b/src/wayland/meta-wayland-idle-notify.c index b2ab3a888..bd6c53eef 100644 --- a/src/wayland/meta-wayland-idle-notify.c +++ b/src/wayland/meta-wayland-idle-notify.c @@ -38,7 +38,7 @@ typedef struct _MetaWaylandIdleNotification gboolean ignore_inhibitors; } MetaWaylandIdleNotification; -void +static void active_trigger_cb (MetaIdleMonitor *monitor, guint id, gpointer user_data) @@ -58,13 +58,14 @@ active_trigger_cb (MetaIdleMonitor *monitor, NULL); } -void +static void idle_trigger_cb (MetaIdleMonitor *monitor, guint id, gpointer user_data) { MetaWaylandIdleNotification *notification = user_data; + meta_idle_monitor_remove_watch (notification->monitor, id); notification->idle_watch_id = 0; ext_idle_notification_v1_send_idled (notification->resource); diff --git a/src/wayland/meta-wayland-idle-notify.h b/src/wayland/meta-wayland-idle-notify.h index 829bb3eb4..4b9f3d04c 100644 --- a/src/wayland/meta-wayland-idle-notify.h +++ b/src/wayland/meta-wayland-idle-notify.h @@ -18,17 +18,8 @@ #ifndef META_WAYLAND_EXT_IDLE_NOTIFY_H #define META_WAYLAND_EXT_IDLE_NOTIFY_H -#include "backends/meta-idle-monitor-private.h" #include "wayland/meta-wayland-types.h" -void idle_trigger_cb (MetaIdleMonitor *monitor, - guint id, - gpointer user_data); - -void active_trigger_cb (MetaIdleMonitor *monitor, - guint id, - gpointer user_data); - void meta_wayland_idle_notify_init (MetaWaylandCompositor *compositor); #endif From 5f8175b1a4f0f0426e4230271e466b77671d3908 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Fri, 17 Jul 2026 19:25:52 +0400 Subject: [PATCH 5/5] add missing include --- src/wayland/meta-wayland-idle-notify.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland/meta-wayland-idle-notify.c b/src/wayland/meta-wayland-idle-notify.c index bd6c53eef..bd047ff2a 100644 --- a/src/wayland/meta-wayland-idle-notify.c +++ b/src/wayland/meta-wayland-idle-notify.c @@ -19,6 +19,7 @@ #include "wayland/meta-wayland-idle-notify.h" +#include "backends/meta-idle-monitor-private.h" #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-versions.h" @@ -38,6 +39,10 @@ typedef struct _MetaWaylandIdleNotification gboolean ignore_inhibitors; } MetaWaylandIdleNotification; +static void idle_trigger_cb (MetaIdleMonitor *monitor, + guint id, + gpointer user_data); + static void active_trigger_cb (MetaIdleMonitor *monitor, guint id,