summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiovanni Campagna <gcampagn@redhat.com>2013-09-16 14:27:08 +0200
committerGiovanni Campagna <gcampagna@src.gnome.org>2013-09-16 22:38:55 +0200
commit2fc9e1af58cd344d0c12c3a05365f52894e18b03 (patch)
treed0d149e63251d8bcfdfb6ea5e3610ae34a431d21
parentbaa6d808c2350770a0b00c947e69b5c0a9dffbf5 (diff)
downloadmutter-2fc9e1af58cd344d0c12c3a05365f52894e18b03.tar.gz
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
-rw-r--r--src/core/meta-idle-monitor.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/src/core/meta-idle-monitor.c b/src/core/meta-idle-monitor.c
index 00b6ddb8e..d351e65a9 100644
--- a/src/core/meta-idle-monitor.c
+++ b/src/core/meta-idle-monitor.c
@@ -74,7 +74,8 @@ typedef struct
guint64 timeout_msec;
/* x11 */
- XSyncAlarm xalarm;
+ XSyncAlarm xalarm;
+ int idle_source_id;
} MetaIdleMonitorWatch;
enum
@@ -110,6 +111,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);
@@ -281,6 +288,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);
@@ -449,6 +462,17 @@ meta_idle_monitor_get_for_device (int device_id)
return device_monitors[device_id];
}
+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,
@@ -471,6 +495,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
{