[gnome-flashback] idle-monitor: use GSource to detect idle time
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] idle-monitor: use GSource to detect idle time
- Date: Tue, 24 May 2022 20:48:10 +0000 (UTC)
commit 5a6887294809a21791e366ad2b03c9977aa87494
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Tue May 24 21:29:25 2022 +0300
idle-monitor: use GSource to detect idle time
Based on mutter commits:
https://gitlab.gnome.org/GNOME/mutter/-/commit/7945ee5bebbc84340e1a
https://gitlab.gnome.org/GNOME/mutter/-/commit/84e575be775c49f1e13c
https://gitlab.gnome.org/GNOME/mutter/-/commit/23a8ea2821f21697a39d
https://gitlab.gnome.org/GNOME/mutter/-/commit/1ca0fdc928511edea57b
https://gitlab.gnome.org/GNOME/mutter/-/commit/0e69fe07819a289f3156
daemons/idle-monitor/flashback-idle-monitor.c | 124 ++++++++++-
daemons/idle-monitor/meta-idle-monitor.c | 291 +++++++-------------------
daemons/idle-monitor/meta-idle-monitor.h | 7 +-
3 files changed, 187 insertions(+), 235 deletions(-)
---
diff --git a/daemons/idle-monitor/flashback-idle-monitor.c b/daemons/idle-monitor/flashback-idle-monitor.c
index c726004..e229993 100644
--- a/daemons/idle-monitor/flashback-idle-monitor.c
+++ b/daemons/idle-monitor/flashback-idle-monitor.c
@@ -23,6 +23,7 @@
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
#include <X11/extensions/sync.h>
#include "flashback-idle-monitor.h"
@@ -33,6 +34,10 @@ struct _FlashbackIdleMonitor
{
GObject parent;
+ Display *xdisplay;
+ XSyncCounter counter;
+ XSyncAlarm user_active_alarm;
+
MetaIdleMonitor *monitor;
gint dbus_name_id;
@@ -252,6 +257,32 @@ on_name_lost (GDBusConnection *connection,
{
}
+static void
+ensure_alarm_rescheduled (Display *dpy,
+ XSyncAlarm alarm)
+{
+ XSyncAlarmAttributes attr;
+
+ /* Some versions of Xorg have an issue where alarms aren't
+ * always rescheduled. Calling XSyncChangeAlarm, even
+ * without any attributes, will reschedule the alarm.
+ */
+ XSyncChangeAlarm (dpy, alarm, 0, &attr);
+}
+
+static void
+handle_alarm_notify (FlashbackIdleMonitor *self,
+ XSyncAlarmNotifyEvent *alarm_event)
+{
+ if (alarm_event->state != XSyncAlarmActive ||
+ alarm_event->alarm != self->user_active_alarm)
+ return;
+
+ ensure_alarm_rescheduled (self->xdisplay, self->user_active_alarm);
+
+ meta_idle_monitor_reset_idletime (self->monitor);
+}
+
static GdkFilterReturn
filter_func (GdkXEvent *xevent,
GdkEvent *event,
@@ -264,12 +295,64 @@ filter_func (GdkXEvent *xevent,
xev = (XEvent *) xevent;
if (xev->type == (monitor->xsync_event_base + XSyncAlarmNotify))
+ handle_alarm_notify (monitor, (XSyncAlarmNotifyEvent *) xev);
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+uint64_to_xsync_value (uint64_t value,
+ XSyncValue *xsync_value)
+{
+ XSyncIntsToValue (xsync_value, value & 0xffffffff, value >> 32);
+}
+
+static XSyncAlarm
+_xsync_alarm_set (FlashbackIdleMonitor *self,
+ XSyncTestType test_type,
+ guint64 interval,
+ gboolean want_events)
+{
+ XSyncAlarmAttributes attr;
+ XSyncValue delta;
+ guint flags;
+
+ flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
+ XSyncCAValue | XSyncCADelta | XSyncCAEvents;
+
+ XSyncIntToValue (&delta, 0);
+ attr.trigger.counter = self->counter;
+ attr.trigger.value_type = XSyncAbsolute;
+ attr.trigger.test_type = test_type;
+ attr.delta = delta;
+ attr.events = want_events;
+
+ uint64_to_xsync_value (interval, &attr.trigger.wait_value);
+
+ return XSyncCreateAlarm (self->xdisplay, flags, &attr);
+}
+
+static XSyncCounter
+find_idletime_counter (FlashbackIdleMonitor *self)
+{
+ int i;
+ int ncounters;
+ XSyncSystemCounter *counters;
+ XSyncCounter counter = None;
+
+ counters = XSyncListSystemCounters (self->xdisplay, &ncounters);
+ for (i = 0; i < ncounters; i++)
{
- meta_idle_monitor_handle_xevent (monitor->monitor,
- (XSyncAlarmNotifyEvent*) xev);
+ if (g_strcmp0 (counters[i].name, "IDLETIME") == 0)
+ {
+ counter = counters[i].counter;
+ break;
+ }
}
- return GDK_FILTER_CONTINUE;
+ XSyncFreeSystemCounterList (counters);
+
+ return counter;
}
static void
@@ -303,6 +386,12 @@ flashback_idle_monitor_finalize (GObject *object)
gdk_window_remove_filter (NULL, (GdkFilterFunc) filter_func, monitor);
+ if (monitor->user_active_alarm != None)
+ {
+ XSyncDestroyAlarm (monitor->xdisplay, monitor->user_active_alarm);
+ monitor->user_active_alarm = None;
+ }
+
g_object_unref (monitor->monitor);
G_OBJECT_CLASS (flashback_idle_monitor_parent_class)->finalize (object);
@@ -312,7 +401,6 @@ static void
flashback_idle_monitor_init (FlashbackIdleMonitor *monitor)
{
GdkDisplay *display;
- Display *xdisplay;
gint event_base;
gint error_base;
gint major;
@@ -331,16 +419,34 @@ flashback_idle_monitor_init (FlashbackIdleMonitor *monitor)
monitor, NULL);
display = gdk_display_get_default ();
- xdisplay = gdk_x11_display_get_xdisplay (display);
+ monitor->xdisplay = gdk_x11_display_get_xdisplay (display);
- if (!XSyncQueryExtension (xdisplay, &event_base, &error_base))
- g_critical ("Could not query XSync extension");
+ if (!XSyncQueryExtension (monitor->xdisplay, &event_base, &error_base))
+ {
+ g_critical ("Could not query XSync extension");
+ return;
+ }
monitor->xsync_event_base = event_base;
monitor->xsync_error_base = error_base;
- if (!XSyncInitialize (xdisplay, &major, &minor))
- g_critical ("Could not initialize XSync");
+ if (!XSyncInitialize (monitor->xdisplay, &major, &minor))
+ {
+ g_critical ("Could not initialize XSync");
+ return;
+ }
+
+ monitor->counter = find_idletime_counter (monitor);
+ if (monitor->counter == None)
+ {
+ g_critical ("IDLETIME counter not found");
+ return;
+ }
+
+ monitor->user_active_alarm = _xsync_alarm_set (monitor,
+ XSyncNegativeTransition,
+ 1,
+ TRUE);
gdk_window_add_filter (NULL, (GdkFilterFunc) filter_func, monitor);
}
diff --git a/daemons/idle-monitor/meta-idle-monitor.c b/daemons/idle-monitor/meta-idle-monitor.c
index b264e48..feb0322 100644
--- a/daemons/idle-monitor/meta-idle-monitor.c
+++ b/daemons/idle-monitor/meta-idle-monitor.c
@@ -26,7 +26,6 @@
#include "config.h"
-#include <gdk/gdkx.h>
#include <string.h>
#include "meta-idle-monitor.h"
@@ -37,10 +36,7 @@ struct _MetaIdleMonitor
GHashTable *watches;
- GHashTable *alarms;
- Display *display;
- XSyncCounter counter;
- XSyncAlarm user_active_alarm;
+ guint64 last_event_time;
};
typedef struct
@@ -51,8 +47,7 @@ typedef struct
gpointer user_data;
GDestroyNotify notify;
guint64 timeout_msec;
- int idle_source_id;
- XSyncAlarm xalarm;
+ GSource *timeout_source;
} MetaIdleMonitorWatch;
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
@@ -69,12 +64,6 @@ meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
monitor = watch->monitor;
g_object_ref (monitor);
- if (watch->idle_source_id)
- {
- g_source_remove (watch->idle_source_id);
- watch->idle_source_id = 0;
- }
-
id = watch->id;
is_user_active_watch = (watch->timeout_msec == 0);
@@ -87,13 +76,6 @@ meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
g_object_unref (monitor);
}
-static gint64
-_xsyncvalue_to_int64 (XSyncValue value)
-{
- return ((guint64) XSyncValueHigh32 (value)) << 32 |
- (guint64) XSyncValueLow32 (value);
-}
-
static void
free_watch (gpointer data)
{
@@ -102,104 +84,16 @@ free_watch (gpointer data)
g_object_ref (monitor);
- if (watch->idle_source_id)
- {
- g_source_remove (watch->idle_source_id);
- watch->idle_source_id = 0;
- }
-
if (watch->notify != NULL)
watch->notify (watch->user_data);
- if (watch->xalarm != monitor->user_active_alarm &&
- watch->xalarm != None)
- {
- XSyncDestroyAlarm (monitor->display, watch->xalarm);
- g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm);
- }
+ if (watch->timeout_source != NULL)
+ g_source_destroy (watch->timeout_source);
g_object_unref (monitor);
g_free (watch);
}
-#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >>
32)
-
-static XSyncAlarm
-_xsync_alarm_set (MetaIdleMonitor *self,
- XSyncTestType test_type,
- guint64 interval,
- gboolean want_events)
-{
- XSyncAlarmAttributes attr;
- XSyncValue delta;
- guint flags;
-
- flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
- XSyncCAValue | XSyncCADelta | XSyncCAEvents;
-
- XSyncIntToValue (&delta, 0);
- attr.trigger.counter = self->counter;
- attr.trigger.value_type = XSyncAbsolute;
- attr.delta = delta;
- attr.events = want_events;
-
- GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
- attr.trigger.test_type = test_type;
- return XSyncCreateAlarm (self->display, flags, &attr);
-}
-
-static XSyncCounter
-find_idletime_counter (MetaIdleMonitor *self)
-{
- int i;
- int ncounters;
- XSyncSystemCounter *counters;
- XSyncCounter counter = None;
-
- counters = XSyncListSystemCounters (self->display, &ncounters);
- for (i = 0; i < ncounters; i++)
- {
- if (counters[i].name != NULL && strcmp (counters[i].name, "IDLETIME") == 0)
- {
- counter = counters[i].counter;
- break;
- }
- }
- XSyncFreeSystemCounterList (counters);
-
- return counter;
-}
-
-static void
-init_xsync (MetaIdleMonitor *self)
-{
- self->counter = find_idletime_counter (self);
-
- /* IDLETIME counter not found? */
- if (self->counter == None)
- {
- g_warning ("IDLETIME counter not found\n");
- return;
- }
-
- self->user_active_alarm = _xsync_alarm_set (self, XSyncNegativeTransition, 1, FALSE);
-}
-
-static void
-meta_idle_monitor_constructed (GObject *object)
-{
- MetaIdleMonitor *self;
- GdkDisplay *display;
-
- self = META_IDLE_MONITOR (object);
-
- G_OBJECT_CLASS (meta_idle_monitor_parent_class)->constructed (object);
-
- display = gdk_display_get_default ();
- self->display = gdk_x11_display_get_xdisplay (display);
- init_xsync (self);
-}
-
static void
meta_idle_monitor_dispose (GObject *object)
{
@@ -207,14 +101,6 @@ meta_idle_monitor_dispose (GObject *object)
g_clear_pointer (&monitor->watches, g_hash_table_destroy);
- if (monitor->user_active_alarm != None)
- {
- XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm);
- monitor->user_active_alarm = None;
- }
-
- g_clear_pointer (&monitor->alarms, g_hash_table_destroy);
-
G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
}
@@ -223,7 +109,6 @@ meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->constructed = meta_idle_monitor_constructed;
object_class->dispose = meta_idle_monitor_dispose;
}
@@ -231,84 +116,7 @@ static void
meta_idle_monitor_init (MetaIdleMonitor *monitor)
{
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
- monitor->alarms = g_hash_table_new (NULL, NULL);
-}
-
-static void
-check_x11_watches (MetaIdleMonitor *self,
- XSyncAlarm alarm)
-{
- GList *node, *watch_ids;
-
- /* we get the keys and do explicit look ups in case
- * an early iteration of the loop ends up leading
- * to watches from later iterations getting invalidated
- */
- watch_ids = g_hash_table_get_keys (self->watches);
-
- for (node = watch_ids; node != NULL; node = node->next)
- {
- guint watch_id = GPOINTER_TO_UINT (node->data);
- MetaIdleMonitorWatch *watch;
-
- watch = g_hash_table_lookup (self->watches, GUINT_TO_POINTER (watch_id));
-
- if (watch && watch->xalarm == alarm)
- meta_idle_monitor_watch_fire (watch);
- }
-
- g_list_free (watch_ids);
-}
-
-static void
-ensure_alarm_rescheduled (Display *dpy,
- XSyncAlarm alarm)
-{
- XSyncAlarmAttributes attr;
-
- /* Some versions of Xorg have an issue where alarms aren't
- * always rescheduled. Calling XSyncChangeAlarm, even
- * without any attributes, will reschedule the alarm. */
- XSyncChangeAlarm (dpy, alarm, 0, &attr);
-}
-
-static void
-set_alarm_enabled (Display *dpy,
- XSyncAlarm alarm,
- gboolean enabled)
-{
- XSyncAlarmAttributes attr;
- attr.events = enabled;
- XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
-}
-
-void
-meta_idle_monitor_handle_xevent (MetaIdleMonitor *self,
- XSyncAlarmNotifyEvent *alarm_event)
-{
- XSyncAlarm alarm;
- gboolean has_alarm;
-
- if (alarm_event->state != XSyncAlarmActive)
- return;
-
- alarm = alarm_event->alarm;
-
- has_alarm = FALSE;
-
- if (alarm == self->user_active_alarm)
- {
- set_alarm_enabled (self->display, alarm, FALSE);
- has_alarm = TRUE;
- }
- else if (g_hash_table_contains (self->alarms, (gpointer) alarm))
- {
- ensure_alarm_rescheduled (self->display, alarm);
- has_alarm = TRUE;
- }
-
- if (has_alarm)
- check_x11_watches (self, alarm);
+ monitor->last_event_time = g_get_monotonic_time ();
}
static guint32
@@ -320,16 +128,33 @@ get_next_watch_serial (void)
}
static gboolean
-fire_watch_idle (gpointer data)
+idle_monitor_dispatch_timeout (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
{
- MetaIdleMonitorWatch *watch = data;
+ MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data;
+ int64_t now;
+ int64_t ready_time;
+
+ now = g_source_get_time (source);
+ ready_time = g_source_get_ready_time (source);
+ if (ready_time > now)
+ return G_SOURCE_CONTINUE;
- watch->idle_source_id = 0;
+ g_source_set_ready_time (watch->timeout_source, -1);
meta_idle_monitor_watch_fire (watch);
- return FALSE;
+ return G_SOURCE_CONTINUE;
}
+static GSourceFuncs idle_monitor_source_funcs =
+ {
+ .prepare = NULL,
+ .check = NULL,
+ .dispatch = idle_monitor_dispatch_timeout,
+ .finalize = NULL,
+ };
+
static MetaIdleMonitorWatch *
make_watch (MetaIdleMonitor *monitor,
guint64 timeout_msec,
@@ -348,26 +173,21 @@ make_watch (MetaIdleMonitor *monitor,
watch->notify = notify;
watch->timeout_msec = timeout_msec;
- if (monitor->user_active_alarm != None)
+ if (timeout_msec != 0)
{
- if (timeout_msec != 0)
- {
- watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
+ GSource *source;
- g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm);
+ source = g_source_new (&idle_monitor_source_funcs, sizeof (GSource));
- if (meta_idle_monitor_get_idletime (monitor) > (gint64) timeout_msec)
- {
- watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
- g_source_set_name_by_id (watch->idle_source_id, "[mutter] fire_watch_idle");
- }
- }
- else
- {
- watch->xalarm = monitor->user_active_alarm;
+ g_source_set_callback (source, NULL, watch, NULL);
+ g_source_set_ready_time (source,
+ monitor->last_event_time +
+ timeout_msec * 1000);
- set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE);
- }
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ watch->timeout_source = source;
}
g_hash_table_insert (monitor->watches,
@@ -484,10 +304,39 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
gint64
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
{
- XSyncValue value;
+ return (g_get_monotonic_time () - monitor->last_event_time) / 1000;
+}
+
+void
+meta_idle_monitor_reset_idletime (MetaIdleMonitor *self)
+{
+ GList *node, *watch_ids;
+
+ self->last_event_time = g_get_monotonic_time ();
+
+ watch_ids = g_hash_table_get_keys (self->watches);
+
+ for (node = watch_ids; node != NULL; node = node->next)
+ {
+ guint watch_id = GPOINTER_TO_UINT (node->data);
+ MetaIdleMonitorWatch *watch;
+
+ watch = g_hash_table_lookup (self->watches,
+ GUINT_TO_POINTER (watch_id));
+ if (!watch)
+ continue;
- if (!XSyncQueryCounter (monitor->display, monitor->counter, &value))
- return -1;
+ if (watch->timeout_msec == 0)
+ {
+ meta_idle_monitor_watch_fire (watch);
+ }
+ else
+ {
+ g_source_set_ready_time (watch->timeout_source,
+ self->last_event_time +
+ watch->timeout_msec * 1000);
+ }
+ }
- return _xsyncvalue_to_int64 (value);
+ g_list_free (watch_ids);
}
diff --git a/daemons/idle-monitor/meta-idle-monitor.h b/daemons/idle-monitor/meta-idle-monitor.h
index a1c4b7a..e756ff9 100644
--- a/daemons/idle-monitor/meta-idle-monitor.h
+++ b/daemons/idle-monitor/meta-idle-monitor.h
@@ -19,8 +19,6 @@
#define META_IDLE_MONITOR_H
#include <glib-object.h>
-#include <X11/Xlib.h>
-#include <X11/extensions/sync.h>
#define META_TYPE_IDLE_MONITOR (meta_idle_monitor_get_type ())
#define META_IDLE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR,
MetaIdleMonitor))
@@ -43,9 +41,6 @@ struct _MetaIdleMonitorClass
GType meta_idle_monitor_get_type (void);
-void meta_idle_monitor_handle_xevent (MetaIdleMonitor *self,
- XSyncAlarmNotifyEvent *xevent);
-
guint meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor,
guint64 interval_msec,
MetaIdleMonitorWatchFunc callback,
@@ -61,4 +56,6 @@ void meta_idle_monitor_remove_watch (MetaIdleMonitor
guint id);
gint64 meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor);
+void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
+
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]