[gnome-desktop] libgnome-desktop: Add GnomeIdleMonitor



commit df9594452e497b29e6397c01b6619747b104e49f
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Sun Aug 19 23:47:43 2012 -0400

    libgnome-desktop: Add GnomeIdleMonitor
    
    This copy/paste code has long been part of gnome-shell, gnome-session,
    gnome-screensaver, and probably other places as well. It deserves a
    standard place in gnome-desktop for code deduplication.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=682224

 libgnome-desktop/Makefile.am          |    4 +-
 libgnome-desktop/gnome-idle-monitor.c |  431 +++++++++++++++++++++++++++++++++
 libgnome-desktop/gnome-idle-monitor.h |   77 ++++++
 3 files changed, 511 insertions(+), 1 deletions(-)
---
diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am
index e1dd1e8..5ac9812 100644
--- a/libgnome-desktop/Makefile.am
+++ b/libgnome-desktop/Makefile.am
@@ -35,6 +35,7 @@ introspection_sources = 		\
 	gnome-pnp-ids.c			\
 	gnome-wall-clock.c		\
 	gnome-xkb-info.c		\
+	gnome-idle-monitor.c		\
 	edid-parse.c
 
 libgnome_desktop_3_la_SOURCES = 	\
@@ -71,7 +72,8 @@ libgnome_desktop_HEADERS = \
         gnome-rr-labeler.h		\
         gnome-pnp-ids.h			\
         gnome-wall-clock.h		\
-	gnome-xkb-info.h
+	gnome-xkb-info.h		\
+	gnome-idle-monitor.h
 
 if USE_INTERNAL_PNP_IDS
 pnpdatadir = $(datadir)/libgnome-desktop-3.0
diff --git a/libgnome-desktop/gnome-idle-monitor.c b/libgnome-desktop/gnome-idle-monitor.c
new file mode 100644
index 0000000..603f9c2
--- /dev/null
+++ b/libgnome-desktop/gnome-idle-monitor.c
@@ -0,0 +1,431 @@
+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
+ *
+ * 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.
+ */
+
+#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>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include "gnome-idle-monitor.h"
+
+#define GNOME_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_IDLE_MONITOR, GnomeIdleMonitorPrivate))
+
+struct GnomeIdleMonitorPrivate
+{
+	Display	    *display;
+
+	GHashTable  *watches;
+	int	     sync_event_base;
+	XSyncCounter counter;
+
+	XSyncAlarm   xalarm_reset;
+};
+
+typedef struct
+{
+	Display			 *display;
+	guint			  id;
+	GnomeIdleMonitorWatchFunc callback;
+	gpointer		  user_data;
+	GDestroyNotify		  notify;
+	XSyncAlarm		  xalarm;
+} GnomeIdleMonitorWatch;
+
+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
+_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 gboolean
+_find_alarm (gpointer		    key,
+	     GnomeIdleMonitorWatch *watch,
+	     XSyncAlarm		   *alarm)
+{
+	return watch->xalarm == *alarm;
+}
+
+static XSyncAlarm
+_xsync_alarm_set (GnomeIdleMonitor	*monitor,
+		  XSyncTestType          test_type,
+		  guint64                interval)
+{
+	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.delta = delta;
+	attr.events = TRUE;
+
+	attr.trigger.wait_value = _int64_to_xsyncvalue (interval);
+	attr.trigger.test_type = test_type;
+	return XSyncCreateAlarm (monitor->priv->display, flags, &attr);
+}
+
+static GnomeIdleMonitorWatch *
+find_watch_for_alarm (GnomeIdleMonitor *monitor,
+		      XSyncAlarm	alarm)
+{
+	GnomeIdleMonitorWatch *watch;
+
+	watch = g_hash_table_find (monitor->priv->watches,
+				   (GHRFunc)_find_alarm,
+				   &alarm);
+	return watch;
+}
+
+static void
+handle_alarm_notify_event (GnomeIdleMonitor	    *monitor,
+			   XSyncAlarmNotifyEvent    *alarm_event)
+{
+	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 = 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);
+		}
+	}
+}
+
+static GdkFilterReturn
+xevent_filter (GdkXEvent	*xevent,
+	       GdkEvent		*event,
+	       GnomeIdleMonitor *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 XSyncCounter
+find_idletime_counter (Display *display)
+{
+	int		    i;
+	int		    ncounters;
+	XSyncSystemCounter *counters;
+
+	counters = XSyncListSystemCounters (display, &ncounters);
+	for (i = 0; i < ncounters; i++) {
+		if (counters[i].name != NULL && strcmp (counters[i].name, "IDLETIME") == 0) {
+			return counters[i].counter;
+		}
+	}
+	XSyncFreeSystemCounterList (counters);
+
+	return None;
+}
+
+static guint32
+get_next_watch_serial (void)
+{
+	static guint32 serial = 1;
+	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)
+{
+	if (watch == NULL) {
+		return;
+	}
+
+	if (watch->notify != NULL) {
+	    watch->notify (watch->user_data);
+	}
+
+	if (watch->xalarm != None) {
+		XSyncDestroyAlarm (watch->display, watch->xalarm);
+	}
+	g_slice_free (GnomeIdleMonitorWatch, watch);
+}
+
+static void
+init_xsync (GnomeIdleMonitor *monitor)
+{
+	int		    sync_error_base;
+	int		    res;
+	int		    major;
+	int		    minor;
+
+	res = XSyncQueryExtension (monitor->priv->display,
+				   &monitor->priv->sync_event_base,
+				   &sync_error_base);
+	if (! res) {
+		g_warning ("GnomeIdleMonitor: Sync extension not present");
+		return;
+	}
+
+	res = XSyncInitialize (monitor->priv->display, &major, &minor);
+	if (! res) {
+		g_warning ("GnomeIdleMonitor: Unable to initialize Sync extension");
+		return;
+	}
+
+	monitor->priv->counter = find_idletime_counter (monitor->priv->display);
+	if (monitor->priv->counter == None) {
+		g_warning ("GnomeIdleMonitor: IDLETIME counter not found");
+		return;
+	}
+
+	monitor->priv->xalarm_reset = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1);
+
+	gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
+}
+
+static void
+gnome_idle_monitor_dispose (GObject *object)
+{
+	GnomeIdleMonitor *monitor;
+
+	monitor = GNOME_IDLE_MONITOR (object);
+	if (monitor->priv->watches != NULL) {
+		g_hash_table_destroy (monitor->priv->watches);
+		monitor->priv->watches = NULL;
+	}
+
+	G_OBJECT_CLASS (gnome_idle_monitor_parent_class)->dispose (object);
+}
+
+static GObject *
+gnome_idle_monitor_constructor (GType                  type,
+                                guint                  n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+	static GnomeIdleMonitor *global_monitor = NULL;
+
+	if (g_once_init_enter (&global_monitor)) {
+		GnomeIdleMonitor *monitor;
+
+		monitor = GNOME_IDLE_MONITOR (G_OBJECT_CLASS (gnome_idle_monitor_parent_class)->constructor (type,
+													     n_construct_properties,
+													     construct_properties));
+
+		g_once_init_leave (&global_monitor, monitor);
+	}
+
+	return g_object_ref (global_monitor);
+}
+
+static void
+gnome_idle_monitor_class_init (GnomeIdleMonitorClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->dispose = gnome_idle_monitor_dispose;
+	object_class->constructor = gnome_idle_monitor_constructor;
+
+        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));
+}
+
+static void
+gnome_idle_monitor_init (GnomeIdleMonitor *monitor)
+{
+	monitor->priv = GNOME_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;
+
+	monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+	init_xsync (monitor);
+}
+
+GnomeIdleMonitor *
+gnome_idle_monitor_new (void)
+{
+	return GNOME_IDLE_MONITOR (g_object_new (GNOME_TYPE_IDLE_MONITOR, NULL));
+}
+
+/**
+ * gnome_idle_monitor_add_watch:
+ * @monitor: A #GnomeIdleMonitor
+ * @interval: The idletime interval, in milliseconds
+ * @callback: (allow-none): The callback to call when the user has
+ *     accumulated @interval seconds of idle time.
+ * @user_data: (allow-none): The user data to pass to the callback
+ * @notify: A #GDestroyNotify
+ * @watch_id: (out): The watch ID
+ *
+ * Adds a watch for a specific idle time. The callback will be called
+ * when the user has accumlated @interval seconds of idle time.
+ * This function will return an ID in @watch_id that can either be passed
+ * to 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 switch on the
+ * watch ID that is passed to the signal.
+ *
+ * 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.
+ */
+void
+gnome_idle_monitor_add_watch (GnomeIdleMonitor	       *monitor,
+			      guint			interval,
+			      GnomeIdleMonitorWatchFunc callback,
+			      gpointer			user_data,
+			      GDestroyNotify		notify,
+			      guint                    *watch_id)
+{
+	GnomeIdleMonitorWatch *watch;
+
+	g_return_if_fail (GNOME_IS_IDLE_MONITOR (monitor));
+
+	watch = idle_monitor_watch_new ();
+	watch->display = monitor->priv->display;
+	watch->callback = callback;
+	watch->user_data = user_data;
+	watch->notify = notify;
+	watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, interval);
+
+	g_hash_table_insert (monitor->priv->watches,
+			     GUINT_TO_POINTER (watch->id),
+			     watch);
+	*watch_id = watch->id;
+}
+
+/**
+ * gnome_idle_monitor_remove_watch:
+ * @monitor: A #GnomeIdleMonitor
+ * @id: A watch ID
+ *
+ * Removes an idle time watcher, previously added by
+ * gnome_idle_monitor_add_watch().
+ */
+void
+gnome_idle_monitor_remove_watch (GnomeIdleMonitor *monitor,
+				 guint		   id)
+{
+	g_return_if_fail (GNOME_IS_IDLE_MONITOR (monitor));
+
+	g_hash_table_remove (monitor->priv->watches,
+			     GUINT_TO_POINTER (id));
+}
+
+/**
+ * gnome_idle_monitor_get_idletime:
+ * @monitor: A #GnomeIdleMonitor
+ *
+ * Returns: The user's current idle time, in milliseconds.
+ */
+gint64
+gnome_idle_monitor_get_idletime (GnomeIdleMonitor *monitor)
+{
+	XSyncValue value;
+
+	if (!XSyncQueryCounter (monitor->priv->display, monitor->priv->counter, &value))
+		return FALSE;
+
+	return _xsyncvalue_to_int64 (value);
+}
diff --git a/libgnome-desktop/gnome-idle-monitor.h b/libgnome-desktop/gnome-idle-monitor.h
new file mode 100644
index 0000000..dc173b8
--- /dev/null
+++ b/libgnome-desktop/gnome-idle-monitor.h
@@ -0,0 +1,77 @@
+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
+ *
+ * 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 __GNOME_IDLE_MONITOR_H__
+#define __GNOME_IDLE_MONITOR_H__
+
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
+#error    This is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-idle-monitor.h
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_IDLE_MONITOR         (gnome_idle_monitor_get_type ())
+#define GNOME_IDLE_MONITOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GNOME_TYPE_IDLE_MONITOR, GnomeIdleMonitor))
+#define GNOME_IDLE_MONITOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GNOME_TYPE_IDLE_MONITOR, GnomeIdleMonitorClass))
+#define GNOME_IS_IDLE_MONITOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNOME_TYPE_IDLE_MONITOR))
+#define GNOME_IS_IDLE_MONITOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GNOME_TYPE_IDLE_MONITOR))
+#define GNOME_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GNOME_TYPE_IDLE_MONITOR, GnomeIdleMonitorClass))
+
+typedef struct GnomeIdleMonitorPrivate GnomeIdleMonitorPrivate;
+
+typedef struct
+{
+        GObject                  parent;
+        GnomeIdleMonitorPrivate *priv;
+} GnomeIdleMonitor;
+
+typedef struct
+{
+        GObjectClass          parent_class;
+} GnomeIdleMonitorClass;
+
+typedef void (*GnomeIdleMonitorWatchFunc) (GnomeIdleMonitor      *monitor,
+                                           guint                  id,
+                                           gpointer               user_data);
+
+GType              gnome_idle_monitor_get_type     (void);
+
+GnomeIdleMonitor * gnome_idle_monitor_new          (void);
+
+void               gnome_idle_monitor_add_watch    (GnomeIdleMonitor         *monitor,
+                                                    guint                     interval,
+                                                    GnomeIdleMonitorWatchFunc callback,
+                                                    gpointer                  user_data,
+                                                    GDestroyNotify            notify,
+	                                            guint                    *watch_id);
+
+void               gnome_idle_monitor_remove_watch (GnomeIdleMonitor         *monitor,
+                                                    guint                     id);
+
+gint64             gnome_idle_monitor_get_idletime (GnomeIdleMonitor         *monitor);
+
+G_END_DECLS
+
+#endif /* __GNOME_IDLE_MONITOR_H__ */



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