[gnome-shell] messageTray: show the summary with new notifications when the user becomes active



commit 30ca25e9782f278b1d6ae8051dc83f2c7a4e0465
Author: Marina Zhurakhinskaya <marinaz redhat com>
Date:   Wed Mar 14 22:50:58 2012 -0400

    messageTray: show the summary with new notifications when the user becomes active
    
    If the user was inactive while a notification was shown, we show the summary
    when the user becomes active again. This ensures that we inform the user of
    the existance of new notifications that the user might have missed.
    
    When the user comes back from away, the summary is now only shown if it has
    new notifications.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=643014

 js/ui/messageTray.js     |   80 +++++++---
 src/Makefile.am          |    2 +
 src/shell-idle-monitor.c |  412 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-idle-monitor.h |   72 ++++++++
 4 files changed, 546 insertions(+), 20 deletions(-)
---
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index 5541638..502b9f3 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -1344,9 +1344,7 @@ const MessageTray = new Lang.Class({
         this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
             this._onStatusChanged(proxy.status);
         }));
-        this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
         this._busy = false;
-        this._backFromAway = false;
         this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
             this._onStatusChanged(status);
         }));
@@ -1392,6 +1390,12 @@ const MessageTray = new Lang.Class({
         this._summaryItemTitleWidth = 0;
         this._pointerBarrier = 0;
 
+        this._unseenNotifications = [];
+        this._idleMonitorWatchId = 0;
+        this._backFromAway = false;
+
+        this.idleMonitor = new Shell.IdleMonitor();
+
         // To simplify the summary item animation code, we pretend
         // that there's an invisible SummaryItem to the left of the
         // leftmost real summary item, and that it's expanded when all
@@ -1635,6 +1639,10 @@ const MessageTray = new Lang.Class({
     },
 
     _onNotificationDestroy: function(notification) {
+        let unseenNotificationsIndex = this._unseenNotifications.indexOf(notification);
+        if (unseenNotificationsIndex != -1)
+            this._unseenNotifications.splice(unseenNotificationsIndex, 1);
+
         if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
             this._updateNotificationTimeout(0);
             this._notificationRemoved = true;
@@ -1918,16 +1926,10 @@ const MessageTray = new Lang.Class({
     },
 
     _onStatusChanged: function(status) {
-        this._backFromAway = (this._userStatus == GnomeSession.PresenceStatus.IDLE && this._userStatus != status);
-        this._userStatus = status;
-
         if (status == GnomeSession.PresenceStatus.BUSY) {
             // remove notification and allow the summary to be closed now
             this._updateNotificationTimeout(0);
-            if (this._summaryTimeoutId) {
-                Mainloop.source_remove(this._summaryTimeoutId);
-                this._summaryTimeoutId = 0;
-            }
+            this._unsetSummaryTimeout();
             this._busy = true;
         } else if (status != GnomeSession.PresenceStatus.IDLE) {
             // We preserve the previous value of this._busy if the status turns to IDLE
@@ -1957,6 +1959,7 @@ const MessageTray = new Lang.Class({
             this._pointerInTray = false;
             this._pointerInSummary = false;
             this._updateNotificationTimeout(0);
+            this._unsetSummaryTimeout();
             this._updateState();
         }
         return false;
@@ -1967,6 +1970,7 @@ const MessageTray = new Lang.Class({
         this._pointerInTray = false;
         this._pointerInSummary = false;
         this._updateNotificationTimeout(0);
+        this._unsetSummaryTimeout();
         this._updateState();
     },
 
@@ -2012,15 +2016,13 @@ const MessageTray = new Lang.Class({
                               || notificationsVisible;
 
         if (this._summaryState == State.HIDDEN && !mustHideSummary) {
-            if (this._backFromAway) {
-                // Immediately set this to false, so that we don't schedule a timeout later
-                this._backFromAway = false;
-                if (!this._busy)
-                    this._showSummary(LONGER_SUMMARY_TIMEOUT);
-            } else if (notificationsDone && this._newSummaryItems.length > 0 && !this._busy) {
-                this._showSummary(SUMMARY_TIMEOUT);
-            } else if (summarySummoned) {
+            if (summarySummoned) {
                 this._showSummary(0);
+            } else if (notificationsDone && !this._busy) {
+                if (this._backFromAway && this._unseenNotifications.length > 0)
+                    this._showSummary(LONGER_SUMMARY_TIMEOUT);
+                else if (this._newSummaryItems.length > 0)
+                    this._showSummary(SUMMARY_TIMEOUT);
             }
         } else if (this._summaryState == State.SHOWN) {
             if (!summaryPinned || mustHideSummary)
@@ -2109,8 +2111,32 @@ const MessageTray = new Lang.Class({
                     });
     },
 
+    _onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
+        this.idleMonitor.remove_watch(this._idleMonitorWatchId);
+        this._idleMonitorWatchId = 0;
+
+        if (userBecameIdle) {
+            // The user became idle, which means the user was active while the notifications were
+            // shown and we can unset this._unseenNotifications .
+            this._unseenNotiications = [];
+        } else if (this._unseenNotifications.length == 1 && this._unseenNotifications[0] == this._notification) {
+            // The user became active while the only notification in this._unseenNotifications is being shown
+            // as this._notification , so we can unset this._unseenNotifications .
+            this._unseenNotifications = [];
+        } else {
+            // The user became active and we have one or more unseen notifications. We should show
+            // the message tray to the user to inform the user about the missed notifications.
+            this._backFromAway = true;
+            this._updateState();
+       }
+    },
+
     _showNotification: function() {
         this._notification = this._notificationQueue.shift();
+        this._unseenNotifications.push(this._notification);
+        if (this._idleMonitorWatchId == 0)
+            this._idleMonitorWatchId = this.idleMonitor.add_watch(1000,
+                                                                  Lang.bind(this, this._onIdleMonitorWatch));
         this._notificationClickedId = this._notification.connect('done-displaying',
                                                                  Lang.bind(this, this._escapeTray));
         this._notificationBin.child = this._notification.actor;
@@ -2189,6 +2215,13 @@ const MessageTray = new Lang.Class({
                                      Lang.bind(this, this._notificationTimeout));
     },
 
+    _unsetSummaryTimeout: function(timeout) {
+        if (this._summaryTimeoutId) {
+            Mainloop.source_remove(this._summaryTimeoutId);
+            this._summaryTimeoutId = 0;
+        }
+    },
+
     _notificationTimeout: function() {
         let [x, y, mods] = global.get_pointer();
         if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
@@ -2272,6 +2305,7 @@ const MessageTray = new Lang.Class({
     },
 
     _showSummary: function(timeout) {
+        this._updateSeenSummaryItems();
         this._summaryBin.opacity = 0;
         this._summaryBin.y = this.actor.height;
         this._tween(this._summaryBin, '_summaryState', State.SHOWN,
@@ -2286,8 +2320,6 @@ const MessageTray = new Lang.Class({
     },
 
     _showSummaryCompleted: function(timeout) {
-        this._newSummaryItems = [];
-
         if (timeout != 0) {
             this._summaryTimeoutId =
                 Mainloop.timeout_add(timeout * 1000,
@@ -2302,6 +2334,7 @@ const MessageTray = new Lang.Class({
     },
 
     _hideSummary: function() {
+        this._updateSeenSummaryItems();
         this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
                     { opacity: 0,
                       time: ANIMATION_TIME,
@@ -2309,13 +2342,20 @@ const MessageTray = new Lang.Class({
                       onComplete: this._hideSummaryCompleted,
                       onCompleteScope: this,
                     });
-        this._newSummaryItems = [];
     },
 
     _hideSummaryCompleted: function() {
         this._setExpandedSummaryItem(null);
     },
 
+    _updateSeenSummaryItems: function() {
+        if (this._backFromAway) {
+            this._backFromAway = false;
+            this._unseenNotifications = [];
+        }
+        this._newSummaryItems = [];
+    },
+
     _showSummaryBoxPointer: function() {
         this._summaryBoxPointerItem = this._clickedSummaryItem;
         this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
diff --git a/src/Makefile.am b/src/Makefile.am
index b1f74a0..95f1a41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -109,6 +109,7 @@ shell_public_headers_h =		\
 	shell-generic-container.h	\
 	shell-gtk-embed.h		\
 	shell-global.h			\
+	shell-idle-monitor.h		\
 	shell-mobile-providers.h	\
 	shell-mount-operation.h		\
 	shell-network-agent.h		\
@@ -155,6 +156,7 @@ libgnome_shell_la_SOURCES =		\
 	shell-generic-container.c	\
 	shell-gtk-embed.c		\
 	shell-global.c			\
+	shell-idle-monitor.c		\
 	shell-keyring-prompt.h		\
 	shell-keyring-prompt.c		\
 	shell-mobile-providers.c	\
diff --git a/src/shell-idle-monitor.c b/src/shell-idle-monitor.c
new file mode 100644
index 0000000..22581d1
--- /dev/null
+++ b/src/shell-idle-monitor.c
@@ -0,0 +1,412 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Adapted from gnome-session/gnome-session/gs-idle-monitor.c
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: William Jon McCann <mccann jhu edu>
+ *
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+
+#include <glib.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include "shell-idle-monitor.h"
+
+#define SHELL_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorPrivate))
+
+struct ShellIdleMonitorPrivate
+{
+        Display     *display;
+
+        GHashTable  *watches;
+        int          sync_event_base;
+        XSyncCounter counter;
+};
+
+typedef struct
+{
+        Display                  *display;
+        guint                     id;
+        XSyncValue                interval;
+        ShellIdleMonitorWatchFunc callback;
+        gpointer                  user_data;
+        GDestroyNotify            notify;
+        XSyncAlarm                xalarm_positive;
+        XSyncAlarm                xalarm_negative;
+} ShellIdleMonitorWatch;
+
+static guint32 watch_serial = 1;
+
+G_DEFINE_TYPE (ShellIdleMonitor, shell_idle_monitor, G_TYPE_OBJECT)
+
+static gint64
+_xsyncvalue_to_int64 (XSyncValue value)
+{
+        return ((guint64) XSyncValueHigh32 (value)) << 32
+                | (guint64) XSyncValueLow32 (value);
+}
+
+static XSyncValue
+_int64_to_xsyncvalue (gint64 value)
+{
+        XSyncValue ret;
+
+        XSyncIntsToValue (&ret, value, ((guint64)value) >> 32);
+
+        return ret;
+}
+
+static void
+shell_idle_monitor_dispose (GObject *object)
+{
+        ShellIdleMonitor *monitor;
+
+        monitor = SHELL_IDLE_MONITOR (object);
+
+        if (monitor->priv->watches != NULL) {
+                g_hash_table_destroy (monitor->priv->watches);
+                monitor->priv->watches = NULL;
+        }
+
+        G_OBJECT_CLASS (shell_idle_monitor_parent_class)->dispose (object);
+}
+
+static gboolean
+_find_alarm (gpointer               key,
+             ShellIdleMonitorWatch *watch,
+             XSyncAlarm            *alarm)
+{
+        /* g_debug ("Searching for %d in %d,%d", (int)*alarm, (int)watch->xalarm_positive, (int)watch->xalarm_negative); */
+        if (watch->xalarm_positive == *alarm
+            || watch->xalarm_negative == *alarm) {
+                return TRUE;
+        }
+        return FALSE;
+}
+
+static ShellIdleMonitorWatch *
+find_watch_for_alarm (ShellIdleMonitor *monitor,
+                      XSyncAlarm        alarm)
+{
+        ShellIdleMonitorWatch *watch;
+
+        watch = g_hash_table_find (monitor->priv->watches,
+                                   (GHRFunc)_find_alarm,
+                                   &alarm);
+        return watch;
+}
+
+static void
+handle_alarm_notify_event (ShellIdleMonitor         *monitor,
+                           XSyncAlarmNotifyEvent    *alarm_event)
+{
+        ShellIdleMonitorWatch *watch;
+        gboolean               condition;
+
+        if (alarm_event->state == XSyncAlarmDestroyed) {
+                return;
+        }
+
+        watch = find_watch_for_alarm (monitor, alarm_event->alarm);
+
+        if (watch == NULL) {
+                /* g_debug ("Unable to find watch for alarm %d", (int)alarm_event->alarm); */
+                return;
+        }
+
+        /* g_debug ("Watch %d fired, idle time = %" G_GINT64_FORMAT,
+                 watch->id,
+                 _xsyncvalue_to_int64 (alarm_event->counter_value)); */
+
+        if (alarm_event->alarm == watch->xalarm_positive) {
+                condition = TRUE;
+        } else {
+                condition = FALSE;
+        }
+
+        if (watch->callback != NULL) {
+                watch->callback (monitor,
+                                 watch->id,
+                                 condition,
+                                 watch->user_data);
+        }
+}
+
+static GdkFilterReturn
+xevent_filter (GdkXEvent        *xevent,
+               GdkEvent         *event,
+               ShellIdleMonitor *monitor)
+{
+        XEvent                *ev;
+        XSyncAlarmNotifyEvent *alarm_event;
+
+        ev = xevent;
+        if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
+                return GDK_FILTER_CONTINUE;
+        }
+
+        alarm_event = xevent;
+
+        handle_alarm_notify_event (monitor, alarm_event);
+
+        return GDK_FILTER_CONTINUE;
+}
+
+static gboolean
+init_xsync (ShellIdleMonitor *monitor)
+{
+        int                 sync_error_base;
+        int                 res;
+        int                 major;
+        int                 minor;
+        int                 i;
+        int                 ncounters;
+        XSyncSystemCounter *counters;
+
+        res = XSyncQueryExtension (monitor->priv->display,
+                                   &monitor->priv->sync_event_base,
+                                   &sync_error_base);
+        if (! res) {
+                g_warning ("ShellIdleMonitor: Sync extension not present");
+                return FALSE;
+        }
+
+        res = XSyncInitialize (monitor->priv->display, &major, &minor);
+        if (! res) {
+                g_warning ("ShellIdleMonitor: Unable to initialize Sync extension");
+                return FALSE;
+        }
+
+        counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
+        for (i = 0; i < ncounters; i++) {
+                if (counters[i].name != NULL
+                    && strcmp (counters[i].name, "IDLETIME") == 0) {
+                        monitor->priv->counter = counters[i].counter;
+                        break;
+                }
+        }
+        XSyncFreeSystemCounterList (counters);
+
+        if (monitor->priv->counter == None) {
+                g_warning ("ShellIdleMonitor: IDLETIME counter not found");
+                return FALSE;
+        }
+
+        gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
+
+        return TRUE;
+}
+
+static GObject *
+shell_idle_monitor_constructor (GType                  type,
+                                guint                  n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+        ShellIdleMonitor *monitor;
+
+        monitor = SHELL_IDLE_MONITOR (G_OBJECT_CLASS (shell_idle_monitor_parent_class)->constructor (type,
+                                                                                                     n_construct_properties,
+                                                                                                     construct_properties));
+
+        monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+
+        if (! init_xsync (monitor)) {
+                g_object_unref (monitor);
+                return NULL;
+        }
+
+        return G_OBJECT (monitor);
+}
+
+static void
+shell_idle_monitor_class_init (ShellIdleMonitorClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->dispose = shell_idle_monitor_dispose;
+        object_class->constructor = shell_idle_monitor_constructor;
+
+        g_type_class_add_private (klass, sizeof (ShellIdleMonitorPrivate));
+}
+
+static guint32
+get_next_watch_serial (void)
+{
+        guint32 serial;
+
+        serial = watch_serial++;
+
+        if ((gint32)watch_serial < 0) {
+                watch_serial = 1;
+        }
+
+        /* FIXME: make sure it isn't in the hash */
+
+        return serial;
+}
+
+static ShellIdleMonitorWatch *
+idle_monitor_watch_new (guint interval)
+{
+        ShellIdleMonitorWatch *watch;
+
+        watch = g_slice_new0 (ShellIdleMonitorWatch);
+        watch->interval = _int64_to_xsyncvalue ((gint64)interval);
+        watch->id = get_next_watch_serial ();
+        watch->xalarm_positive = None;
+        watch->xalarm_negative = None;
+
+        return watch;
+}
+
+static void
+idle_monitor_watch_free (ShellIdleMonitorWatch *watch)
+{
+        if (watch == NULL) {
+                return;
+        }
+
+        if (watch->notify != NULL) {
+            watch->notify (watch->user_data);
+        }
+
+        if (watch->xalarm_positive != None) {
+                XSyncDestroyAlarm (watch->display, watch->xalarm_positive);
+        }
+        if (watch->xalarm_negative != None) {
+                XSyncDestroyAlarm (watch->display, watch->xalarm_negative);
+        }
+        g_slice_free (ShellIdleMonitorWatch, watch);
+}
+
+static void
+shell_idle_monitor_init (ShellIdleMonitor *monitor)
+{
+        monitor->priv = SHELL_IDLE_MONITOR_GET_PRIVATE (monitor);
+
+        monitor->priv->watches = g_hash_table_new_full (NULL,
+                                                        NULL,
+                                                        NULL,
+                                                        (GDestroyNotify)idle_monitor_watch_free);
+
+        monitor->priv->counter = None;
+}
+
+ShellIdleMonitor *
+shell_idle_monitor_new (void)
+{
+        GObject *idle_monitor;
+
+        idle_monitor = g_object_new (SHELL_TYPE_IDLE_MONITOR,
+                                     NULL);
+
+        return SHELL_IDLE_MONITOR (idle_monitor);
+}
+
+static gboolean
+_xsync_alarm_set (ShellIdleMonitor      *monitor,
+                  ShellIdleMonitorWatch *watch)
+{
+        XSyncAlarmAttributes attr;
+        XSyncValue           delta;
+        guint                flags;
+
+        flags = XSyncCACounter
+                | XSyncCAValueType
+                | XSyncCATestType
+                | XSyncCAValue
+                | XSyncCADelta
+                | XSyncCAEvents;
+
+        XSyncIntToValue (&delta, 0);
+        attr.trigger.counter = monitor->priv->counter;
+        attr.trigger.value_type = XSyncAbsolute;
+        attr.trigger.wait_value = watch->interval;
+        attr.delta = delta;
+        attr.events = TRUE;
+
+        attr.trigger.test_type = XSyncPositiveTransition;
+        if (watch->xalarm_positive != None) {
+                /* g_debug ("ShellIdleMonitor: updating alarm for positive transition wait=%" G_GINT64_FORMAT,
+                         _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
+                XSyncChangeAlarm (monitor->priv->display, watch->xalarm_positive, flags, &attr);
+        } else {
+                /* g_debug ("ShellIdleMonitor: creating new alarm for positive transition wait=%" G_GINT64_FORMAT,
+                         _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
+                watch->xalarm_positive = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
+        }
+
+        attr.trigger.wait_value = _int64_to_xsyncvalue (_xsyncvalue_to_int64 (watch->interval) - 1);
+        attr.trigger.test_type = XSyncNegativeTransition;
+        if (watch->xalarm_negative != None) {
+                /* g_debug ("ShellIdleMonitor: updating alarm for negative transition wait=%" G_GINT64_FORMAT,
+                         _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
+                XSyncChangeAlarm (monitor->priv->display, watch->xalarm_negative, flags, &attr);
+        } else {
+                /* g_debug ("ShellIdleMonitor: creating new alarm for negative transition wait=%" G_GINT64_FORMAT,
+                         _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
+                watch->xalarm_negative = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
+        }
+
+        return TRUE;
+}
+
+guint
+shell_idle_monitor_add_watch (ShellIdleMonitor         *monitor,
+                              guint                     interval,
+                              ShellIdleMonitorWatchFunc callback,
+                              gpointer                  user_data,
+                              GDestroyNotify            notify)
+{
+        ShellIdleMonitorWatch *watch;
+
+        g_return_val_if_fail (SHELL_IS_IDLE_MONITOR (monitor), 0);
+        g_return_val_if_fail (callback != NULL, 0);
+
+        watch = idle_monitor_watch_new (interval);
+        watch->display = monitor->priv->display;
+        watch->callback = callback;
+        watch->user_data = user_data;
+        watch->notify = notify;
+
+        _xsync_alarm_set (monitor, watch);
+
+        g_hash_table_insert (monitor->priv->watches,
+                             GUINT_TO_POINTER (watch->id),
+                             watch);
+        return watch->id;
+}
+
+void
+shell_idle_monitor_remove_watch (ShellIdleMonitor *monitor,
+                                 guint          id)
+{
+        g_return_if_fail (SHELL_IS_IDLE_MONITOR (monitor));
+
+        g_hash_table_remove (monitor->priv->watches,
+                             GUINT_TO_POINTER (id));
+}
diff --git a/src/shell-idle-monitor.h b/src/shell-idle-monitor.h
new file mode 100644
index 0000000..1086d92
--- /dev/null
+++ b/src/shell-idle-monitor.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Adapted from gnome-session/gnome-session/gs-idle-monitor.h
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: William Jon McCann <mccann jhu edu>
+ *
+ */
+
+#ifndef __SHELL_IDLE_MONITOR_H
+#define __SHELL_IDLE_MONITOR_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define SHELL_TYPE_IDLE_MONITOR         (shell_idle_monitor_get_type ())
+#define SHELL_IDLE_MONITOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitor))
+#define SHELL_IDLE_MONITOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorClass))
+#define SHELL_IS_IDLE_MONITOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), SHELL_TYPE_IDLE_MONITOR))
+#define SHELL_IS_IDLE_MONITOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), SHELL_TYPE_IDLE_MONITOR))
+#define SHELL_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorClass))
+
+typedef struct ShellIdleMonitorPrivate ShellIdleMonitorPrivate;
+
+typedef struct
+{
+        GObject                  parent;
+        ShellIdleMonitorPrivate *priv;
+} ShellIdleMonitor;
+
+typedef struct
+{
+        GObjectClass          parent_class;
+} ShellIdleMonitorClass;
+
+typedef void (*ShellIdleMonitorWatchFunc) (ShellIdleMonitor *monitor,
+                                           guint             id,
+                                           gboolean          condition,
+                                           gpointer          user_data);
+
+GType              shell_idle_monitor_get_type     (void);
+
+ShellIdleMonitor * shell_idle_monitor_new          (void);
+
+guint              shell_idle_monitor_add_watch    (ShellIdleMonitor         *monitor,
+                                                    guint                     interval,
+                                                    ShellIdleMonitorWatchFunc callback,
+                                                    gpointer                  user_data,
+                                                    GDestroyNotify            notify);
+
+void               shell_idle_monitor_remove_watch (ShellIdleMonitor         *monitor,
+                                                    guint                     id);
+
+G_END_DECLS
+
+#endif /* __SHELL_IDLE_MONITOR_H */



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