[gnome-desktop] idle-monitor: Change the API to be function-based



commit 1fc10e6d22b70a2e982b16228a1232f85d65a7ad
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Fri Jan 18 00:15:47 2013 -0500

    idle-monitor: Change the API to be function-based
    
    As the current API design has been unknowingly relying on an Xorg server
    bug that may be fixed in the future, we need to modify the API so that
    became-active is explicitly asked for by the user so that we won't get
    flooded with a large number of events for almost every input event.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=688227

 libgnome-desktop/gnome-idle-monitor.c |  168 ++++++++++++++++++---------------
 libgnome-desktop/gnome-idle-monitor.h |   15 ++-
 libgnome-desktop/test-idle-monitor.c  |   59 +++++++-----
 3 files changed, 137 insertions(+), 105 deletions(-)
---
diff --git a/libgnome-desktop/gnome-idle-monitor.c b/libgnome-desktop/gnome-idle-monitor.c
index 3c8ec2a..761ffa9 100644
--- a/libgnome-desktop/gnome-idle-monitor.c
+++ b/libgnome-desktop/gnome-idle-monitor.c
@@ -36,6 +36,8 @@
 
 #define GNOME_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_IDLE_MONITOR, 
GnomeIdleMonitorPrivate))
 
+#define USER_ACTIVE_WATCH_ID 1
+
 struct _GnomeIdleMonitorPrivate
 {
        Display     *display;
@@ -44,7 +46,7 @@ struct _GnomeIdleMonitorPrivate
        int          sync_event_base;
        XSyncCounter counter;
 
-       XSyncAlarm   xalarm_reset;
+       XSyncAlarm   user_active_alarm;
 
        GdkDevice   *device;
 };
@@ -68,16 +70,6 @@ enum
 
 static GParamSpec *obj_props[PROP_LAST];
 
-enum
-{
-       BECAME_ACTIVE,
-       TRIGGERED_IDLE,
-
-       LAST_SIGNAL,
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
 G_DEFINE_TYPE (GnomeIdleMonitor, gnome_idle_monitor, G_TYPE_OBJECT)
 
 static gint64
@@ -100,7 +92,8 @@ _find_alarm (gpointer                    key,
 static XSyncAlarm
 _xsync_alarm_set (GnomeIdleMonitor     *monitor,
                  XSyncTestType          test_type,
-                 guint64                interval)
+                 guint64                interval,
+                 gboolean               want_events)
 {
        XSyncAlarmAttributes attr;
        XSyncValue           delta;
@@ -113,7 +106,7 @@ _xsync_alarm_set (GnomeIdleMonitor  *monitor,
        attr.trigger.counter = monitor->priv->counter;
        attr.trigger.value_type = XSyncAbsolute;
        attr.delta = delta;
-       attr.events = TRUE;
+       attr.events = want_events;
 
        GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
        attr.trigger.test_type = test_type;
@@ -132,6 +125,16 @@ ensure_alarm_rescheduled (Display    *dpy,
        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);
+}
+
 static GnomeIdleMonitorWatch *
 find_watch_for_alarm (GnomeIdleMonitor *monitor,
                      XSyncAlarm        alarm)
@@ -148,30 +151,30 @@ static void
 handle_alarm_notify_event (GnomeIdleMonitor        *monitor,
                           XSyncAlarmNotifyEvent    *alarm_event)
 {
+       GnomeIdleMonitorWatch *watch;
+
        if (alarm_event->state != XSyncAlarmActive) {
                return;
        }
 
-       if (alarm_event->alarm == monitor->priv->xalarm_reset) {
-               g_signal_emit (monitor, signals[BECAME_ACTIVE], 0);
-       } else {
-               GnomeIdleMonitorWatch *watch;
-
-               watch = find_watch_for_alarm (monitor, alarm_event->alarm);
-               if (watch == NULL)
-                       return;
-
-               g_signal_emit (monitor, signals[TRIGGERED_IDLE], 0, watch->id);
-
-               if (watch->callback != NULL) {
-                       watch->callback (monitor,
-                                        watch->id,
-                                        watch->user_data);
-               }
+       watch = find_watch_for_alarm (monitor, alarm_event->alarm);
+       if (watch == NULL)
+               return;
 
+       if (watch->id == USER_ACTIVE_WATCH_ID) {
+               set_alarm_enabled (monitor->priv->display,
+                                  watch->xalarm,
+                                  FALSE);
+       } else {
                ensure_alarm_rescheduled (monitor->priv->display,
                                          watch->xalarm);
        }
+
+       if (watch->callback != NULL) {
+               watch->callback (monitor,
+                                watch->id,
+                                watch->user_data);
+       }
 }
 
 static GdkFilterReturn
@@ -231,23 +234,11 @@ find_idletime_counter (GnomeIdleMonitor *monitor)
 static guint32
 get_next_watch_serial (void)
 {
-       static guint32 serial = 1;
+       static guint32 serial = USER_ACTIVE_WATCH_ID;
        g_atomic_int_inc (&serial);
        return serial;
 }
 
-static GnomeIdleMonitorWatch *
-idle_monitor_watch_new (void)
-{
-       GnomeIdleMonitorWatch *watch;
-
-       watch = g_slice_new0 (GnomeIdleMonitorWatch);
-       watch->id = get_next_watch_serial ();
-       watch->xalarm = None;
-
-       return watch;
-}
-
 static void
 idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
 {
@@ -259,7 +250,7 @@ idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
            watch->notify (watch->user_data);
        }
 
-       if (watch->xalarm != None) {
+       if (watch->id != USER_ACTIVE_WATCH_ID) {
                XSyncDestroyAlarm (watch->display, watch->xalarm);
        }
        g_slice_free (GnomeIdleMonitorWatch, watch);
@@ -293,7 +284,7 @@ init_xsync (GnomeIdleMonitor *monitor)
                return;
        }
 
-       monitor->priv->xalarm_reset = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1);
+       monitor->priv->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
 
        gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
 }
@@ -384,21 +375,6 @@ gnome_idle_monitor_class_init (GnomeIdleMonitorClass *klass)
                                     G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
        g_object_class_install_property (object_class, PROP_DEVICE, obj_props[PROP_DEVICE]);
 
-        signals[BECAME_ACTIVE] =
-                g_signal_new ("became-active",
-                              G_TYPE_FROM_CLASS (klass),
-                              G_SIGNAL_RUN_LAST,
-                              0,
-                             NULL, NULL, NULL,
-                              G_TYPE_NONE, 0);
-        signals[TRIGGERED_IDLE] =
-                g_signal_new ("triggered-idle",
-                              G_TYPE_FROM_CLASS (klass),
-                              G_SIGNAL_RUN_LAST,
-                              0,
-                             NULL, NULL, NULL,
-                              G_TYPE_NONE, 1, G_TYPE_UINT);
-
        g_type_class_add_private (klass, sizeof (GnomeIdleMonitorPrivate));
 }
 
@@ -442,7 +418,7 @@ gnome_idle_monitor_new_for_device (GdkDevice *device)
 }
 
 /**
- * gnome_idle_monitor_add_watch:
+ * gnome_idle_monitor_add_idle_watch:
  * @monitor: A #GnomeIdleMonitor
  * @interval_msec: The idletime interval, in milliseconds
  * @callback: (allow-none): The callback to call when the user has
@@ -458,37 +434,78 @@ gnome_idle_monitor_new_for_device (GdkDevice *device)
  * gnome_idle_monitor_remove_watch(), or can be used to tell idle time
  * watches apart if you have more than one.
  *
- * If you need to check for more than one interval of
- * idle time, it may be more convenient to connect to the
- * #GnomeIdleMonitor::triggered-idle signal, and filter on the
- * watch ID received in the signal handler.
- *
  * Also note that this function will only care about positive transitions
  * (user's idle time exceeding a certain time). If you want to know about
- * negative transitions, connect to the #GnomeIdleMonitor::became-active
- * signal.
+ * when the user has become active, use
+ * gnome_idle_monitor_add_user_active_watch().
+ */
+guint
+gnome_idle_monitor_add_idle_watch (GnomeIdleMonitor           *monitor,
+                                  guint64                      interval_msec,
+                                  GnomeIdleMonitorWatchFunc    callback,
+                                  gpointer                     user_data,
+                                  GDestroyNotify               notify)
+{
+       GnomeIdleMonitorWatch *watch;
+
+       g_return_val_if_fail (GNOME_IS_IDLE_MONITOR (monitor), 0);
+
+       watch = g_slice_new0 (GnomeIdleMonitorWatch);
+       watch->id = get_next_watch_serial ();
+       watch->display = monitor->priv->display;
+       watch->callback = callback;
+       watch->user_data = user_data;
+       watch->notify = notify;
+       watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, interval_msec, TRUE);
+
+       g_hash_table_insert (monitor->priv->watches,
+                            GUINT_TO_POINTER (watch->id),
+                            watch);
+       return watch->id;
+}
+
+/**
+ * gnome_idle_monitor_add_user_active_watch:
+ * @monitor: A #GnomeIdleMonitor
+ * @callback: (allow-none): The callback to call when the user is
+ *     active again.
+ * @user_data: (allow-none): The user data to pass to the callback
+ * @notify: A #GDestroyNotify
+ *
+ * Returns: a watch id
+ *
+ * Add a one-time watch to know when the user is active again.
+ * Note that this watch is one-time and will de-activate after the
+ * function is called, for efficiency purposes. It's most convenient
+ * to call this when an idle watch, as added by
+ * gnome_idle_monitor_add_idle_watch(), has triggered.
  */
 guint
-gnome_idle_monitor_add_watch (GnomeIdleMonitor        *monitor,
-                             guint64                   interval_msec,
-                             GnomeIdleMonitorWatchFunc callback,
-                             gpointer                  user_data,
-                             GDestroyNotify            notify)
+gnome_idle_monitor_add_user_active_watch (GnomeIdleMonitor          *monitor,
+                                         GnomeIdleMonitorWatchFunc  callback,
+                                         gpointer                   user_data,
+                                         GDestroyNotify             notify)
 {
        GnomeIdleMonitorWatch *watch;
 
        g_return_val_if_fail (GNOME_IS_IDLE_MONITOR (monitor), 0);
 
-       watch = idle_monitor_watch_new ();
+       watch = g_slice_new0 (GnomeIdleMonitorWatch);
+       watch->id = USER_ACTIVE_WATCH_ID;
        watch->display = monitor->priv->display;
        watch->callback = callback;
        watch->user_data = user_data;
        watch->notify = notify;
-       watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, interval_msec);
+       watch->xalarm = monitor->priv->user_active_alarm;
+
+       set_alarm_enabled (monitor->priv->display,
+                          monitor->priv->user_active_alarm,
+                          TRUE);
 
        g_hash_table_insert (monitor->priv->watches,
                             GUINT_TO_POINTER (watch->id),
                             watch);
+
        return watch->id;
 }
 
@@ -498,7 +515,8 @@ gnome_idle_monitor_add_watch (GnomeIdleMonitor             *monitor,
  * @id: A watch ID
  *
  * Removes an idle time watcher, previously added by
- * gnome_idle_monitor_add_watch().
+ * gnome_idle_monitor_add_idle_watch() or
+ * gnome_idle_monitor_add_user_active_watch().
  */
 void
 gnome_idle_monitor_remove_watch (GnomeIdleMonitor *monitor,
diff --git a/libgnome-desktop/gnome-idle-monitor.h b/libgnome-desktop/gnome-idle-monitor.h
index 30d181e..523a62f 100644
--- a/libgnome-desktop/gnome-idle-monitor.h
+++ b/libgnome-desktop/gnome-idle-monitor.h
@@ -64,11 +64,16 @@ GType              gnome_idle_monitor_get_type     (void);
 GnomeIdleMonitor * gnome_idle_monitor_new          (void);
 GnomeIdleMonitor * gnome_idle_monitor_new_for_device (GdkDevice *device);
 
-guint              gnome_idle_monitor_add_watch    (GnomeIdleMonitor         *monitor,
-                                                    guint64                   interval_msec,
-                                                    GnomeIdleMonitorWatchFunc callback,
-                                                    gpointer                  user_data,
-                                                    GDestroyNotify            notify);
+guint              gnome_idle_monitor_add_idle_watch    (GnomeIdleMonitor         *monitor,
+                                                        guint64                   interval_msec,
+                                                        GnomeIdleMonitorWatchFunc callback,
+                                                        gpointer                  user_data,
+                                                        GDestroyNotify            notify);
+
+guint              gnome_idle_monitor_add_user_active_watch (GnomeIdleMonitor          *monitor,
+                                                            GnomeIdleMonitorWatchFunc  callback,
+                                                            gpointer                user_data,
+                                                            GDestroyNotify          notify);
 
 void               gnome_idle_monitor_remove_watch (GnomeIdleMonitor         *monitor,
                                                     guint                     id);
diff --git a/libgnome-desktop/test-idle-monitor.c b/libgnome-desktop/test-idle-monitor.c
index 6fdf424..1b808ff 100644
--- a/libgnome-desktop/test-idle-monitor.c
+++ b/libgnome-desktop/test-idle-monitor.c
@@ -3,21 +3,21 @@
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include "libgnome-desktop/gnome-idle-monitor.h"
 
-#define IDLE_TIME 60 * 1000 /* 1 minute */
+#define IDLE_TIME 1000 /* 1 second */
 
 GHashTable *monitors = NULL; /* key = device id, value = GnomeIdleMonitor */
 
 static void
-watch_func (GnomeIdleMonitor      *monitor,
-           guint                  id,
-           gpointer               user_data)
+active_watch_func (GnomeIdleMonitor *monitor,
+                  guint             id,
+                  gpointer          user_data)
 {
        GdkDevice *device;
        int device_id;
 
        g_object_get (monitor, "device", &device, NULL);
        device_id = gdk_x11_device_get_id (device);
-       g_message ("Watch func called for device %s (id: %d, watch id %d)",
+       g_message ("Active watch func called for device %s (id: %d, watch id %d)",
                   gdk_device_get_name (device),
                   device_id,
                   id);
@@ -25,32 +25,41 @@ watch_func (GnomeIdleMonitor      *monitor,
 }
 
 static void
-became_active_cb (GnomeIdleMonitor *monitor,
-                 gpointer          user_data)
+ensure_active_watch (GnomeIdleMonitor *monitor)
 {
        GdkDevice *device;
+       guint watch_id;
        int device_id;
 
        g_object_get (monitor, "device", &device, NULL);
        device_id = gdk_x11_device_get_id (device);
-       g_message ("Device '%s' (%d) became active",
-                  gdk_device_get_name (device), device_id);
-       g_object_unref (device);
+       watch_id = gnome_idle_monitor_add_user_active_watch (monitor,
+                                                            active_watch_func,
+                                                            NULL,
+                                                            NULL);
+       g_message ("Added active watch ID %d for device %s (%d)",
+                  watch_id,
+                  gdk_device_get_name (device),
+                  device_id);
 }
 
 static void
-triggered_idle_cb (GnomeIdleMonitor *monitor,
-                  guint             watch_id,
-                  gpointer          user_data)
+idle_watch_func (GnomeIdleMonitor      *monitor,
+                guint                  id,
+                gpointer               user_data)
 {
        GdkDevice *device;
        int device_id;
 
        g_object_get (monitor, "device", &device, NULL);
        device_id = gdk_x11_device_get_id (device);
-       g_message ("Device '%s' (%d) triggered idle on watch %d",
-                  gdk_device_get_name (device), device_id, watch_id);
+       g_message ("Idle watch func called for device %s (id: %d, watch id %d)",
+                  gdk_device_get_name (device),
+                  device_id,
+                  id);
        g_object_unref (device);
+
+       ensure_active_watch (monitor);
 }
 
 static void
@@ -64,19 +73,19 @@ device_added_cb (GdkDeviceManager *manager,
 
        device_id = gdk_x11_device_get_id (device);
        monitor = gnome_idle_monitor_new_for_device (device);
-       g_signal_connect (G_OBJECT (monitor), "became-active",
-                         G_CALLBACK (became_active_cb), NULL);
-       g_signal_connect (G_OBJECT (monitor), "triggered-idle",
-                         G_CALLBACK (triggered_idle_cb), NULL);
-       watch_id = gnome_idle_monitor_add_watch (monitor,
-                                                IDLE_TIME,
-                                                watch_func,
-                                                NULL,
-                                                NULL);
-       g_message ("Added watch ID %d for device %s (%d)",
+
+       watch_id = gnome_idle_monitor_add_idle_watch (monitor,
+                                                     IDLE_TIME,
+                                                     idle_watch_func,
+                                                     NULL,
+                                                     NULL);
+       g_message ("Added idle watch ID %d for device %s (%d)",
                   watch_id,
                   gdk_device_get_name (device),
                   device_id);
+
+       ensure_active_watch (monitor);
+
        g_hash_table_insert (monitors,
                             GINT_TO_POINTER (device_id),
                             monitor);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]