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
This commit is contained in:
Giovanni Campagna 2013-09-16 14:27:08 +02:00 committed by Giovanni Campagna
parent baa6d808c2
commit 2fc9e1af58

View File

@ -74,7 +74,8 @@ typedef struct
guint64 timeout_msec; guint64 timeout_msec;
/* x11 */ /* x11 */
XSyncAlarm xalarm; XSyncAlarm xalarm;
int idle_source_id;
} MetaIdleMonitorWatch; } MetaIdleMonitorWatch;
enum enum
@ -110,6 +111,12 @@ fire_watch (MetaIdleMonitorWatch *watch)
monitor = watch->monitor; monitor = watch->monitor;
g_object_ref (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; id = watch->id;
is_user_active_watch = (watch->timeout_msec == 0); is_user_active_watch = (watch->timeout_msec == 0);
@ -281,6 +288,12 @@ idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
monitor = watch->monitor; monitor = watch->monitor;
if (watch->idle_source_id)
{
g_source_remove (watch->idle_source_id);
watch->idle_source_id = 0;
}
if (watch->notify != NULL) if (watch->notify != NULL)
watch->notify (watch->user_data); watch->notify (watch->user_data);
@ -449,6 +462,17 @@ meta_idle_monitor_get_for_device (int device_id)
return device_monitors[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 * static MetaIdleMonitorWatch *
make_watch (MetaIdleMonitor *monitor, make_watch (MetaIdleMonitor *monitor,
guint64 timeout_msec, guint64 timeout_msec,
@ -471,6 +495,9 @@ make_watch (MetaIdleMonitor *monitor,
watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); 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 else
{ {