From 389e04c715b290f8e8fab58dc8a2669e9329e3b7 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Mon, 16 Sep 2013 14:27:08 +0200 Subject: [PATCH] MetaIdleMonitor: fire immediately watches that are already expired The XSync semantics mandate that alarms already expired will not fire until the counter is reset and the alarm triggered again, so clients traditionally called get_idle_time() first to see if they should install the alarm. This is inherently racy, as by the time the call is handled by mutter and the reply received the idle time could be different. Instead, if we see that the watch would have fired in the past, fire it immediately. This is a behavior change, but it's a compatible one, as all legacy clients are calling get_idle_time() first, and it was perfectly possible for the idle time counter to trigger the alarm right after the get_idle_time() call. https://bugzilla.gnome.org/show_bug.cgi?id=707302 --- src/core/meta-idle-monitor.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/core/meta-idle-monitor.c b/src/core/meta-idle-monitor.c index 01c4cb303..3c0d31ee6 100644 --- a/src/core/meta-idle-monitor.c +++ b/src/core/meta-idle-monitor.c @@ -77,7 +77,8 @@ typedef struct guint64 timeout_msec; /* x11 */ - XSyncAlarm xalarm; + XSyncAlarm xalarm; + int idle_source_id; /* wayland */ GSource *timeout_source; @@ -116,6 +117,12 @@ fire_watch (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); @@ -287,6 +294,12 @@ idle_monitor_watch_free (MetaIdleMonitorWatch *watch) monitor = watch->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); @@ -480,6 +493,17 @@ static GSourceFuncs wayland_source_funcs = { NULL, /* finalize */ }; +static gboolean +fire_watch_idle (gpointer data) +{ + MetaIdleMonitorWatch *watch = data; + + watch->idle_source_id = 0; + fire_watch (watch); + + return FALSE; +} + static MetaIdleMonitorWatch * make_watch (MetaIdleMonitor *monitor, guint64 timeout_msec, @@ -518,6 +542,9 @@ make_watch (MetaIdleMonitor *monitor, watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); + + if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) + watch->idle_source_id = g_idle_add (fire_watch_idle, watch); } else {