[gnome-desktop] libgnome-desktop: Add GnomeIdleMonitor
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-desktop] libgnome-desktop: Add GnomeIdleMonitor
- Date: Mon, 22 Oct 2012 16:06:10 +0000 (UTC)
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]