[gnome-power-manager] Update the IDLETIME code to similar to gnome-session



commit b499906adc7c3e1973d8885afbe729ae2647c2ef
Author: Richard Hughes <richard hughsie com>
Date:   Sat Apr 18 09:29:28 2009 +0100

    Update the IDLETIME code to similar to gnome-session
    
    Our homebrewed IDLETIME code is starting to show bugs, so we should use the
    same (better) code in gnome-session written by William Jon McCann.
---
 src/egg-idletime.c |  760 ++++++++++++++++++++++------------------------------
 src/egg-idletime.h |   43 ++--
 src/gpm-idle.c     |   50 ++--
 3 files changed, 368 insertions(+), 485 deletions(-)

diff --git a/src/egg-idletime.c b/src/egg-idletime.c
index 6f509aa..e09ed5e 100644
--- a/src/egg-idletime.c
+++ b/src/egg-idletime.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2007 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2009 William Jon McCann <mccann jhu edu>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -19,42 +20,39 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
+#include "config.h"
+
+#include <time.h>
+#include <string.h>
 
-#include <glib.h>
 #include <X11/Xlib.h>
 #include <X11/extensions/sync.h>
+
+#include <glib.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "egg-idletime.h"
+#include "egg-debug.h"
 
-static void     egg_idletime_finalize   (GObject       *object);
+static void egg_idletime_finalize	(GObject		*object);
 
-#define EGG_IDLETIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_IDLETIME_TYPE, EggIdletimePrivate))
+#define EGG_IDLETIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_IDLETIME, EggIdletimePrivate))
 
 struct EggIdletimePrivate
 {
-	int			 sync_event;
-	guint			 last_event;
-	gboolean		 reset_set;
-	XSyncCounter		 idle_counter;
-	GPtrArray		*array;
-	Display			*dpy;
+	GHashTable	*watches;
+	int		 sync_event_base;
+	XSyncCounter	 counter;
 };
 
 typedef struct
 {
-	guint			 id;
-	XSyncValue		 timeout;
-	XSyncAlarm		 xalarm;
-} EggIdletimeAlarm;
+	guint		 id;
+	XSyncValue	 interval;
+	XSyncAlarm	 xalarm_positive;
+	XSyncAlarm	 xalarm_negative;
+} EggIdletimeWatch;
 
 enum {
 	SIGNAL_ALARM_EXPIRED,
@@ -62,271 +60,346 @@ enum {
 	LAST_SIGNAL
 };
 
+static guint32 watch_serial = 1;
 static guint signals [LAST_SIGNAL] = { 0 };
-static gpointer egg_idletime_object = NULL;
 
 G_DEFINE_TYPE (EggIdletime, egg_idletime, G_TYPE_OBJECT)
 
 /**
- * egg_idletime_xsync_alarm_set:
- *
- * Gets the time remaining for the current percentage
- *
+ * egg_idletime_xsyncvalue_to_int64:
  */
-static void
-egg_idletime_xsync_alarm_set (EggIdletime *idletime, EggIdletimeAlarm *alarm, gboolean positive)
+static gint64
+egg_idletime_xsyncvalue_to_int64 (XSyncValue value)
 {
-	XSyncAlarmAttributes attr;
-	XSyncValue delta;
-	unsigned int flags;
-	XSyncTestType test;
-
-	/* which way do we do the test? */
-	if (positive)
-		test = XSyncPositiveTransition;
-	else
-		test = XSyncNegativeTransition;
-
-	XSyncIntToValue (&delta, 0);
-
-	attr.trigger.counter = idletime->priv->idle_counter;
-	attr.trigger.value_type = XSyncAbsolute;
-	attr.trigger.test_type = test;
-	attr.trigger.wait_value = alarm->timeout;
-	attr.delta = delta;
-
-	flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta;
-
-	if (alarm->xalarm)
-		XSyncChangeAlarm (idletime->priv->dpy, alarm->xalarm, flags, &attr);
-	else
-		alarm->xalarm = XSyncCreateAlarm (idletime->priv->dpy, flags, &attr);
+	return ((guint64) XSyncValueHigh32 (value)) << 32
+		| (guint64) XSyncValueLow32 (value);
 }
 
 /**
- * egg_idletime_alarm_reset_all:
+ * egg_idletime_int64_to_xsyncvalue:
  */
-void
-egg_idletime_alarm_reset_all (EggIdletime *idletime)
+static XSyncValue
+egg_idletime_int64_to_xsyncvalue (gint64 value)
 {
-	guint i;
-	EggIdletimeAlarm *alarm;
+	XSyncValue ret;
+	XSyncIntsToValue (&ret, value, ((guint64)value) >> 32);
+	return ret;
+}
 
-	/* reset all the alarms (except the reset alarm) to their timeouts */
-	for (i=1; i<idletime->priv->array->len; i++) {
-		alarm = g_ptr_array_index (idletime->priv->array, i);
-		egg_idletime_xsync_alarm_set (idletime, alarm, TRUE);
+/**
+ * egg_idletime_find_alarm:
+ */
+static gboolean
+egg_idletime_find_alarm (gpointer key, EggIdletimeWatch *watch, XSyncAlarm *alarm)
+{
+	egg_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;
 	}
-
-	/* emit signal */
-	g_signal_emit (idletime, signals [SIGNAL_RESET], 0);
-
-	/* we need to be reset again on the next event */
-	idletime->priv->reset_set = FALSE;
+	return FALSE;
 }
 
 /**
- * egg_idletime_timeout:
+ * egg_idletime_find_watch_for_alarm:
  */
-static void
-egg_idletime_timeout (EggIdletime *idletime, EggIdletimeAlarm *alarm)
+static EggIdletimeWatch *
+egg_idletime_find_watch_for_alarm (EggIdletime *idletime, XSyncAlarm alarm)
 {
-	/* emit signal */
-	g_signal_emit (idletime, signals [SIGNAL_ALARM_EXPIRED], 0, alarm->id);
+	EggIdletimeWatch *watch;
+	watch = g_hash_table_find (idletime->priv->watches,
+				   (GHRFunc)egg_idletime_find_alarm, &alarm);
+	return watch;
 }
 
 /**
- * egg_idletime_xsync_value_add_one:
- *
- * Just adds one to a XSyncValue. I love X.
+ * egg_idletime_handle_alarm_notify_event:
  */
 static void
-egg_idletime_xsync_value_add_one (XSyncValue *from, XSyncValue *to)
+egg_idletime_handle_alarm_notify_event (EggIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event)
 {
-	int overflow;
-	XSyncValue add;
-	XSyncIntToValue (&add, -1);
-	XSyncValueAdd (to, *from, add, &overflow);
+	EggIdletimeWatch *watch;
+
+	if (alarm_event->state == XSyncAlarmDestroyed)
+		return;
+
+	watch = egg_idletime_find_watch_for_alarm (idletime, alarm_event->alarm);
+
+	if (watch == NULL) {
+		egg_warning ("Unable to find watch for alarm %d", (int)alarm_event->alarm);
+		return;
+	}
+
+	egg_debug ("Watch %d fired, idle time = %lld",
+		   watch->id, egg_idletime_xsyncvalue_to_int64 (alarm_event->counter_value));
+
+	if (alarm_event->alarm == watch->xalarm_positive) {
+		g_signal_emit (idletime, signals [SIGNAL_ALARM_EXPIRED], 0, watch->id);
+	} else {
+		g_signal_emit (idletime, signals [SIGNAL_RESET], 0);
+	}
 }
 
 /**
- * egg_idletime_alarm_find_id:
+ * egg_idletime_xevent_filter:
  */
-static EggIdletimeAlarm *
-egg_idletime_alarm_find_id (EggIdletime *idletime, guint id)
+static GdkFilterReturn
+egg_idletime_xevent_filter (GdkXEvent *xevent, GdkEvent *event, EggIdletime *idletime)
 {
-	guint i;
-	EggIdletimeAlarm *alarm;
-	for (i=0; i<idletime->priv->array->len; i++) {
-		alarm = g_ptr_array_index (idletime->priv->array, i);
-		if (alarm->id == id)
-			return alarm;
-	}
-	return NULL;
+	XEvent *ev;
+	XSyncAlarmNotifyEvent *alarm_event;
+
+	ev = xevent;
+	if (ev->xany.type != idletime->priv->sync_event_base + XSyncAlarmNotify)
+		return GDK_FILTER_CONTINUE;
+
+	alarm_event = xevent;
+	egg_idletime_handle_alarm_notify_event (idletime, alarm_event);
+
+	return GDK_FILTER_CONTINUE;
 }
 
 /**
- * egg_idletime_x_set_reset:
+ * egg_idletime_init_xsync:
  */
-static void
-egg_idletime_x_set_reset (EggIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event)
+static gboolean
+egg_idletime_init_xsync (EggIdletime *idletime)
 {
-	EggIdletimeAlarm *alarm;
+	int sync_error_base;
+	int res;
+	int major;
+	int minor;
+	int i;
+	int ncounters;
+	XSyncSystemCounter *counters;
 
-	alarm = egg_idletime_alarm_find_id (idletime, 0);
+	res = XSyncQueryExtension (GDK_DISPLAY (),
+				   &idletime->priv->sync_event_base,
+				   &sync_error_base);
+	if (res == 0) {
+		egg_warning ("EggIdletime: Sync extension not present");
+		return FALSE;
+	}
 
-	if (idletime->priv->reset_set == FALSE) {
-		/* don't match on the current value because
-		 * XSyncNegativeComparison means less or equal. */
-		egg_idletime_xsync_value_add_one (&alarm_event->counter_value, &alarm->timeout);
+	res = XSyncInitialize (GDK_DISPLAY (), &major, &minor);
+	if (res == 0) {
+		egg_warning ("EggIdletime: Unable to initialize Sync extension");
+		return FALSE;
+	}
 
-		/* set the reset alarm to fire the next time
-		 * idletime->priv->idle_counter < the current counter value */
-		egg_idletime_xsync_alarm_set (idletime, alarm, FALSE);
+	counters = XSyncListSystemCounters (GDK_DISPLAY (), &ncounters);
+	for (i = 0; i < ncounters; i++) {
+		if (counters[i].name != NULL &&
+		    g_strcmp0 (counters[i].name, "IDLETIME") == 0) {
+			idletime->priv->counter = counters[i].counter;
+			break;
+		}
+	}
+	XSyncFreeSystemCounterList (counters);
 
-		/* don't try to set this again */
-		idletime->priv->reset_set = TRUE;
+	if (idletime->priv->counter == None) {
+		egg_warning ("EggIdletime: IDLETIME counter not found");
+		return FALSE;
 	}
+
+	gdk_window_add_filter (NULL, (GdkFilterFunc) egg_idletime_xevent_filter, idletime);
+
+	return TRUE;
 }
 
 /**
- * egg_idletime_alarm_find_event:
+ * egg_idletime_get_next_watch_serial:
  */
-static EggIdletimeAlarm *
-egg_idletime_alarm_find_event (EggIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event)
+static guint32
+egg_idletime_get_next_watch_serial (void)
 {
-	guint i;
-	EggIdletimeAlarm *alarm;
-	for (i=0; i<idletime->priv->array->len; i++) {
-		alarm = g_ptr_array_index (idletime->priv->array, i);
-		if (alarm_event->alarm == alarm->xalarm)
-			return alarm;
-	}
-	return NULL;
+	guint32 serial;
+
+	serial = watch_serial++;
+	/* cope with overflow */
+	if ((gint32)watch_serial < 0)
+		watch_serial = 1;
+	return serial;
 }
 
 /**
- * egg_idletime_x_event_filter:
+ * egg_idletime_watch_new:
  */
-static GdkFilterReturn
-egg_idletime_x_event_filter (GdkXEvent *gdkxevent, GdkEvent *event, gpointer data)
+static EggIdletimeWatch *
+egg_idletime_watch_new (guint interval)
 {
-	EggIdletimeAlarm *alarm;
-	XEvent *xevent = (XEvent *) gdkxevent;
-	EggIdletime *idletime = (EggIdletime *) data;
-	XSyncAlarmNotifyEvent *alarm_event;
+	EggIdletimeWatch *watch;
 
-	/* no point continuing */
-	if (xevent->type != idletime->priv->sync_event + XSyncAlarmNotify)
-		return GDK_FILTER_CONTINUE;
+	watch = g_slice_new0 (EggIdletimeWatch);
+	watch->interval = egg_idletime_int64_to_xsyncvalue ((gint64)interval);
+	watch->id = egg_idletime_get_next_watch_serial ();
+	watch->xalarm_positive = None;
+	watch->xalarm_negative = None;
 
-	alarm_event = (XSyncAlarmNotifyEvent *) xevent;
+	return watch;
+}
 
-	alarm = egg_idletime_alarm_find_event (idletime, alarm_event);
+/**
+ * egg_idletime_watch_free:
+ */
+static void
+egg_idletime_watch_free (EggIdletimeWatch *watch)
+{
+	if (watch == NULL)
+		return;
+	if (watch->xalarm_positive != None)
+		XSyncDestroyAlarm (GDK_DISPLAY (), watch->xalarm_positive);
+	if (watch->xalarm_negative != None)
+		XSyncDestroyAlarm (GDK_DISPLAY (), watch->xalarm_negative);
+	g_slice_free (EggIdletimeWatch, watch);
+}
 
-	/* did we match one of our alarms? */
-	if (alarm != NULL) {
-		/* save the last state we triggered */
-		idletime->priv->last_event = alarm->id;
+/**
+ * egg_idletime_xsync_alarm_set:
+ */
+static gboolean
+egg_idletime_xsync_alarm_set (EggIdletime *idletime, EggIdletimeWatch *watch)
+{
+	XSyncAlarmAttributes attr;
+	XSyncValue delta;
+	guint flags;
 
-		/* do the signal */
-		if (alarm->id != 0) {
-			egg_idletime_timeout (idletime, alarm);
+	flags = XSyncCACounter
+		| XSyncCAValueType
+		| XSyncCATestType
+		| XSyncCAValue
+		| XSyncCADelta
+		| XSyncCAEvents;
 
-			/* we need the first alarm to go off to set the reset alarm */
-			egg_idletime_x_set_reset (idletime, alarm_event);
-			return GDK_FILTER_CONTINUE;
-		}
+	XSyncIntToValue (&delta, 0);
+	attr.trigger.counter = idletime->priv->counter;
+	attr.trigger.value_type = XSyncAbsolute;
+	attr.trigger.wait_value = watch->interval;
+	attr.delta = delta;
+	attr.events = TRUE;
 
-		/* do the reset callback */
-		egg_idletime_alarm_reset_all (idletime);
+	attr.trigger.test_type = XSyncPositiveTransition;
+	if (watch->xalarm_positive != None) {
+		egg_debug ("EggIdletime: updating alarm for positive transition wait=%lld",
+			   egg_idletime_xsyncvalue_to_int64 (attr.trigger.wait_value));
+		XSyncChangeAlarm (GDK_DISPLAY (), watch->xalarm_positive, flags, &attr);
+	} else {
+		egg_debug ("EggIdletime: creating new alarm for positive transition wait=%lld",
+			   egg_idletime_xsyncvalue_to_int64 (attr.trigger.wait_value));
+		watch->xalarm_positive = XSyncCreateAlarm (GDK_DISPLAY (), flags, &attr);
 	}
 
-	return GDK_FILTER_CONTINUE;
+	attr.trigger.test_type = XSyncNegativeTransition;
+	if (watch->xalarm_negative != None) {
+		egg_debug ("EggIdletime: updating alarm for negative transition wait=%lld",
+			   egg_idletime_xsyncvalue_to_int64 (attr.trigger.wait_value));
+		XSyncChangeAlarm (GDK_DISPLAY (), watch->xalarm_negative, flags, &attr);
+	} else {
+		egg_debug ("EggIdletime: creating new alarm for negative transition wait=%lld",
+			   egg_idletime_xsyncvalue_to_int64 (attr.trigger.wait_value));
+		watch->xalarm_negative = XSyncCreateAlarm (GDK_DISPLAY (), flags, &attr);
+	}
+
+	return TRUE;
 }
 
 /**
- * egg_idletime_get_idletime->priv->last_event:
+ * egg_idletime_add_watch:
  */
 guint
-egg_idletime_alarm_get (EggIdletime *idletime)
+egg_idletime_add_watch (EggIdletime *idletime, guint interval)
 {
-	return idletime->priv->last_event;
+	EggIdletimeWatch *watch;
+
+	g_return_val_if_fail (EGG_IS_IDLETIME (idletime), 0);
+
+	watch = egg_idletime_watch_new (interval);
+
+	egg_idletime_xsync_alarm_set (idletime, watch);
+
+	g_hash_table_insert (idletime->priv->watches,
+			     GUINT_TO_POINTER (watch->id), watch);
+	return watch->id;
 }
 
 /**
- * egg_idletime_alarm_set:
+ * egg_idletime_remove_watch:
  */
-gboolean
-egg_idletime_alarm_set (EggIdletime *idletime, guint id, guint timeout)
+void
+egg_idletime_remove_watch (EggIdletime *idletime, guint id)
 {
-	EggIdletimeAlarm *alarm;
-
-	/* id cannot be zero */
-	if (id == 0)
-		return FALSE;
+	g_return_if_fail (EGG_IS_IDLETIME (idletime));
 
-	/* timeout cannot be zero */
-	if (timeout == 0)
-		return FALSE;
+	g_hash_table_remove (idletime->priv->watches, GUINT_TO_POINTER (id));
+}
 
-	/* see if we already created an alarm with this ID */
-	alarm = egg_idletime_alarm_find_id (idletime, id);
-	if (alarm == NULL) {
-		/* create a new alarm */
-		alarm = g_new0 (EggIdletimeAlarm, 1);
+/**
+ * egg_idletime_finalize:
+ */
+static void
+egg_idletime_finalize (GObject *object)
+{
+	EggIdletime *idletime;
 
-		/* set the id - this is just something like userdata */
-		alarm->id = id;
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (EGG_IS_IDLETIME (object));
 
-		/* add to array */
-		g_ptr_array_add (idletime->priv->array, alarm);
-	}
+	idletime = EGG_IDLETIME (object);
 
-	/* set the timeout */
-	XSyncIntToValue (&alarm->timeout, (gint)timeout);
+	g_return_if_fail (idletime->priv != NULL);
 
-	/* set, and start the timer */
-	egg_idletime_xsync_alarm_set (idletime, alarm, TRUE);
-	return TRUE;
+	G_OBJECT_CLASS (egg_idletime_parent_class)->finalize (object);
 }
 
 /**
- * egg_idletime_alarm_free:
+ * egg_idletime_constructor:
  */
-static gboolean
-egg_idletime_alarm_free (EggIdletime *idletime, EggIdletimeAlarm *alarm)
+static GObject *
+egg_idletime_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)
 {
-	XSyncDestroyAlarm (idletime->priv->dpy, alarm->xalarm);
-	g_free (alarm);
-	g_ptr_array_remove (idletime->priv->array, alarm);
-	return TRUE;
+	EggIdletime *idletime;
+
+	idletime = EGG_IDLETIME (G_OBJECT_CLASS (egg_idletime_parent_class)->constructor (type, n_construct_properties, construct_properties));
+
+	if (!egg_idletime_init_xsync (idletime)) {
+		g_object_unref (idletime);
+		return NULL;
+	}
+
+	return G_OBJECT (idletime);
 }
 
 /**
- * egg_idletime_alarm_free:
+ * egg_idletime_dispose:
  */
-gboolean
-egg_idletime_alarm_remove (EggIdletime *idletime, guint id)
+static void
+egg_idletime_dispose (GObject *object)
 {
-	EggIdletimeAlarm *alarm;
-	alarm = egg_idletime_alarm_find_id (idletime, id);
-	if (alarm == NULL)
-		return FALSE;
-	egg_idletime_alarm_free (idletime, alarm);
-	return TRUE;
+	EggIdletime *idletime;
+
+	g_return_if_fail (EGG_IS_IDLETIME (object));
+
+	idletime = EGG_IDLETIME (object);
+
+	if (idletime->priv->watches != NULL) {
+		g_hash_table_destroy (idletime->priv->watches);
+		idletime->priv->watches = NULL;
+	}
+
+	G_OBJECT_CLASS (egg_idletime_parent_class)->dispose (object);
 }
 
 /**
  * egg_idletime_class_init:
- * @klass: This class instance
- **/
+ */
 static void
 egg_idletime_class_init (EggIdletimeClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
 	object_class->finalize = egg_idletime_finalize;
-	g_type_class_add_private (klass, sizeof (EggIdletimePrivate));
+	object_class->dispose = egg_idletime_dispose;
+	object_class->constructor = egg_idletime_constructor;
 
 	signals [SIGNAL_ALARM_EXPIRED] =
 		g_signal_new ("alarm-expired",
@@ -342,102 +415,31 @@ egg_idletime_class_init (EggIdletimeClass *klass)
 			      G_STRUCT_OFFSET (EggIdletimeClass, reset),
 			      NULL, NULL, g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE, 0);
+
+	g_type_class_add_private (klass, sizeof (EggIdletimePrivate));
 }
 
 /**
  * egg_idletime_init:
- *
- * @egg_idletime: This class instance
- **/
+ */
 static void
 egg_idletime_init (EggIdletime *idletime)
 {
-	int sync_error;
-	int ncounters;
-	XSyncSystemCounter *counters;
-	EggIdletimeAlarm *alarm;
-	int i;
-
 	idletime->priv = EGG_IDLETIME_GET_PRIVATE (idletime);
-
-	idletime->priv->array = g_ptr_array_new ();
-
-	idletime->priv->idle_counter = None;
-	idletime->priv->last_event = 0;
-	idletime->priv->sync_event = 0;
-	idletime->priv->dpy = GDK_DISPLAY ();
-
-	/* get the sync event */
-	if (!XSyncQueryExtension (idletime->priv->dpy, &idletime->priv->sync_event, &sync_error)) {
-		g_warning ("No Sync extension.");
-		return;
-	}
-
-	/* gtk_init should do XSyncInitialize for us */
-	counters = XSyncListSystemCounters (idletime->priv->dpy, &ncounters);
-	for (i = 0; i < ncounters && !idletime->priv->idle_counter; i++) {
-		if (!strcmp(counters[i].name, "IDLETIME"))
-			idletime->priv->idle_counter = counters[i].counter;
-	}
-//	XSyncFreeSystemCounterList (counters);
-
-	/* arh. we don't have IDLETIME support */
-	if (!idletime->priv->idle_counter) {
-		g_warning ("No idle counter.");
-		return;
-	}
-
-	idletime->priv->reset_set = FALSE;
-
-	/* catch the timer alarm */
-	gdk_window_add_filter (NULL, egg_idletime_x_event_filter, idletime);
-
-	/* create a reset alarm */
-	alarm = g_new0 (EggIdletimeAlarm, 1);
-	alarm->id = 0;
-	g_ptr_array_add (idletime->priv->array, alarm);
-}
-
-/**
- * egg_idletime_finalize:
- * @object: This class instance
- **/
-static void
-egg_idletime_finalize (GObject *object)
-{
-	guint i;
-	EggIdletime *idletime;
-	EggIdletimeAlarm *alarm;
-
-	g_return_if_fail (object != NULL);
-	g_return_if_fail (EGG_IS_IDLETIME (object));
-
-	idletime = EGG_IDLETIME (object);
-	idletime->priv = EGG_IDLETIME_GET_PRIVATE (idletime);
-
-	for (i=0; i<idletime->priv->array->len; i++) {
-		alarm = g_ptr_array_index (idletime->priv->array, i);
-		egg_idletime_alarm_free (idletime, alarm);
-	}
-	g_ptr_array_free (idletime->priv->array, TRUE);
-
-	G_OBJECT_CLASS (egg_idletime_parent_class)->finalize (object);
+	idletime->priv->counter = None;
+	idletime->priv->watches = g_hash_table_new_full (NULL, NULL, NULL,
+							(GDestroyNotify) egg_idletime_watch_free);
 }
 
 /**
  * egg_idletime_new:
- * Return value: new EggIdletime instance.
- **/
+ */
 EggIdletime *
 egg_idletime_new (void)
 {
-	if (egg_idletime_object != NULL) {
-		g_object_ref (egg_idletime_object);
-	} else {
-		egg_idletime_object = g_object_new (EGG_IDLETIME_TYPE, NULL);
-		g_object_add_weak_pointer (egg_idletime_object, &egg_idletime_object);
-	}
-	return EGG_IDLETIME (egg_idletime_object);
+	GObject *idletime;
+	idletime = g_object_new (EGG_TYPE_IDLETIME, NULL);
+	return EGG_IDLETIME (idletime);
 }
 
 /***************************************************************************
@@ -446,216 +448,94 @@ egg_idletime_new (void)
 #ifdef EGG_TEST
 #include "egg-test.h"
 
-static void
-egg_test_egg_idletime_wait (guint time_ms)
-{
-	GTimer *ltimer = g_timer_new ();
-	gfloat goal = time_ms / (gfloat) 1000.0f;
-	do {
-		g_main_context_iteration (NULL, FALSE);
-	} while (g_timer_elapsed (ltimer, NULL) < goal);
-	g_timer_destroy (ltimer);
-}
-
-static guint last_alarm = 0;
-static guint event_time;
-GTimer *timer;
+static guint _last_alarm = 0;
 
 static void
-gpm_alarm_expired_cb (EggIdletime *idletime, guint alarm, gpointer data)
+egg_idletime_test_alarm_expired_cb (EggIdletime *idletime, guint alarm, EggTest *test)
 {
-	last_alarm = alarm;
-	event_time = g_timer_elapsed (timer, NULL) * (gfloat) 1000.0f;
-//	g_print ("[evt %i in %ims]\n", alarm, event_time);
+	_last_alarm = alarm;
+	egg_debug ("alarm %i", alarm);
+	egg_test_loop_quit (test);
 }
 
 static void
-wait_until_alarm (void)
+egg_idletime_test_reset_cb (EggIdletime *idletime, EggTest *test)
 {
-	g_print ("*****************************\n");
-	g_print ("*** DO NOT MOVE THE MOUSE ***\n");
-	g_print ("*****************************\n");
-	while (last_alarm == 0)
-		g_main_context_iteration (NULL, FALSE);
-}
-
-static void
-wait_until_reset (void)
-{
-	if (last_alarm == 0)
-		return;
-	g_print ("*****************************\n");
-	g_print ("***     MOVE THE MOUSE    ***\n");
-	g_print ("*****************************\n");
-	while (last_alarm != 0)
-		g_main_context_iteration (NULL, FALSE);
-	egg_test_egg_idletime_wait (1000);
+	_last_alarm = 0;
+	egg_debug ("reset");
+	egg_test_loop_quit (test);
 }
 
 void
 egg_idletime_test (gpointer data)
 {
 	EggIdletime *idletime;
-	gboolean ret;
-	guint alarm;
-	guint i;
 	EggTest *test = (EggTest *) data;
+	guint id;
 
 	if (egg_test_start (test, "EggIdletime") == FALSE)
 		return;
 
-	timer = g_timer_new ();
 	gdk_init (NULL, NULL);
 
-	/* warn */
-
-	g_timer_start (timer);
 	/************************************************************/
-	egg_test_title (test, "check to see if delay works as expected");
-	egg_test_egg_idletime_wait (2000);
-	event_time = g_timer_elapsed (timer, NULL) * (gfloat) 1000.0f;
-	if (event_time > 1800 && event_time < 2200) {
-		egg_test_success (test, "time %i~=%i", 2000, event_time);
-	} else {
-		egg_test_failed (test, "time not the same! %i != %i", event_time, 2000);
-	}
-
-	/************************************************************/
-	egg_test_title (test, "make sure we get a non null device");
+	egg_test_title (test, "make sure we get an object");
 	idletime = egg_idletime_new ();
-	if (idletime != NULL) {
-		egg_test_success (test, "got EggIdletime");
-	} else {
-		egg_test_failed (test, "could not get EggIdletime");
-	}
+	egg_test_assert (test, (idletime != NULL));
 	g_signal_connect (idletime, "alarm-expired",
-			  G_CALLBACK (gpm_alarm_expired_cb), NULL);
+			  G_CALLBACK (egg_idletime_test_alarm_expired_cb), test);
+	g_signal_connect (idletime, "reset",
+			  G_CALLBACK (egg_idletime_test_reset_cb), test);
 
 	/************************************************************/
-	egg_test_title (test, "check if we are alarm zero with no alarms");
-	alarm = egg_idletime_alarm_get (idletime);
-	if (alarm == 0) {
-		egg_test_success (test, NULL);
-	} else {
-		egg_test_failed (test, "alarm %i set!", alarm);
-	}
+	egg_test_title (test, "add a watch");
+	id = egg_idletime_add_watch (idletime, 3000);
+	egg_test_assert (test, (id != 0));
 
 	/************************************************************/
-	egg_test_title (test, "check if we can set an reset alarm");
-	ret = egg_idletime_alarm_set (idletime, 0, 100);
-	if (!ret) {
-		egg_test_success (test, "ignored reset alarm");
-	} else {
-		egg_test_failed (test, "did not ignore reset alarm");
-	}
+	g_print ("*****************************\n");
+	g_print ("*** DO NOT MOVE THE MOUSE ***\n");
+	g_print ("*****************************\n");
+	egg_test_loop_wait (test, 4500);
+	egg_test_loop_check (test);
 
 	/************************************************************/
-	egg_test_title (test, "check if we can set an alarm timeout of zero");
-	ret = egg_idletime_alarm_set (idletime, 999, 0);
-	if (!ret) {
-		egg_test_success (test, "ignored invalid alarm");
-	} else {
-		egg_test_failed (test, "did not ignore invalid alarm");
-	}
+	egg_test_title (test, "check condition");
+	egg_test_assert (test, (_last_alarm == 1));
 
 	/************************************************************/
-	g_timer_start (timer);
-	egg_test_title (test, "check if we can set an alarm");
-	ret = egg_idletime_alarm_set (idletime, 101, 5000);
-	if (ret) {
-		egg_test_success (test, "set alarm okay");
-	} else {
-		egg_test_failed (test, "could not set alarm");
-	}
-
-	egg_idletime_alarm_set (idletime, 101, 5000);
-	wait_until_alarm ();
-
-	/* loop this two times */
-	for (i=0; i<2; i++) {
-		/* just let it time out, and wait for human input */
-		wait_until_reset ();
-		g_timer_start (timer);
-
-		/************************************************************/
-		g_timer_start (timer);
-		egg_test_title (test, "check if we can set an alarm");
-		ret = egg_idletime_alarm_set (idletime, 101, 5000);
-		if (ret) {
-			egg_test_success (test, "set alarm 5000ms okay");
-		} else {
-			egg_test_failed (test, "could not set alarm 5000ms");
-		}
-
-		/* wait for alarm to go off */
-		wait_until_alarm ();
-		g_timer_start (timer);
-
-		/************************************************************/
-		egg_test_title (test, "check if correct alarm has gone off");
-		alarm = egg_idletime_alarm_get (idletime);
-		if (alarm == 101) {
-			egg_test_success (test, "correct alarm");
-		} else {
-			egg_test_failed (test, "alarm %i set!", alarm);
-		}
-
-		/************************************************************/
-		egg_test_title (test, "check if alarm has gone off in correct time");
-		alarm = egg_idletime_alarm_get (idletime);
-		if (event_time > 3000 && event_time < 6000) {
-			egg_test_success (test, "correct, timeout ideally %ims (we did after %ims)", 5000, event_time);
-		} else {
-			egg_test_failed (test, "alarm %i did not timeout correctly !", alarm);
-		}
-	}
-
-	/* just let it time out, and wait for human input */
-	wait_until_reset ();
-	g_timer_start (timer);
+	g_print ("*****************************\n");
+	g_print ("***    MOVE THE MOUSE     ***\n");
+	g_print ("*****************************\n");
+	egg_test_loop_wait (test, 10000);
+	egg_test_loop_check (test);
 
 	/************************************************************/
-	g_timer_start (timer);
-	egg_test_title (test, "check if we can set an existing alarm");
-	ret = egg_idletime_alarm_set (idletime, 101, 10000);
-	if (ret) {
-		egg_test_success (test, "set alarm 10000ms okay");
-	} else {
-		egg_test_failed (test, "could not set alarm 10000ms");
-	}
+	egg_test_title (test, "check condition");
+	egg_test_assert (test, (_last_alarm == 0));
 
-	/* wait for alarm to go off */
-	wait_until_alarm ();
-	g_timer_start (timer);
+	/************************************************************/
+	g_print ("*****************************\n");
+	g_print ("*** DO NOT MOVE THE MOUSE ***\n");
+	g_print ("*****************************\n");
+	egg_test_loop_wait (test, 4500);
+	egg_test_loop_check (test);
 
 	/************************************************************/
-	egg_test_title (test, "check if alarm has gone off in the old time");
-	alarm = egg_idletime_alarm_get (idletime);
-	if (event_time > 5000) {
-		egg_test_success (test, "last timeout value used");
-	} else {
-		egg_test_failed (test, "incorrect timeout used %ims", event_time);
-	}
+	egg_test_title (test, "check condition");
+	egg_test_assert (test, (_last_alarm == 1));
 
 	/************************************************************/
-	egg_test_title (test, "check if we can remove an invalid alarm");
-	ret = egg_idletime_alarm_remove (idletime, 202);
-	if (!ret) {
-		egg_test_success (test, "ignored invalid alarm");
-	} else {
-		egg_test_failed (test, "removed invalid alarm");
-	}
+	g_print ("*****************************\n");
+	g_print ("***    MOVE THE MOUSE     ***\n");
+	g_print ("*****************************\n");
+	egg_test_loop_wait (test, 10000);
+	egg_test_loop_check (test);
 
 	/************************************************************/
-	egg_test_title (test, "check if we can remove an valid alarm");
-	ret = egg_idletime_alarm_remove (idletime, 101);
-	if (ret) {
-		egg_test_success (test, "removed valid alarm");
-	} else {
-		egg_test_failed (test, "failed to remove valid alarm");
-	}
+	egg_test_title (test, "check condition");
+	egg_test_assert (test, (_last_alarm == 0));
 
-	g_timer_destroy (timer);
 	g_object_unref (idletime);
 
 	egg_test_end (test);
diff --git a/src/egg-idletime.h b/src/egg-idletime.h
index d67e5ec..9616710 100644
--- a/src/egg-idletime.h
+++ b/src/egg-idletime.h
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2007 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2009 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2009 William Jon McCann <mccann jhu edu>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -26,12 +27,12 @@
 
 G_BEGIN_DECLS
 
-#define EGG_IDLETIME_TYPE		(egg_idletime_get_type ())
-#define EGG_IDLETIME(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_IDLETIME_TYPE, EggIdletime))
-#define EGG_IDLETIME_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), EGG_IDLETIME_TYPE, EggIdletimeClass))
-#define EGG_IS_IDLETIME(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_IDLETIME_TYPE))
-#define EGG_IS_IDLETIME_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), EGG_IDLETIME_TYPE))
-#define EGG_IDLETIME_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), EGG_IDLETIME_TYPE, EggIdletimeClass))
+#define EGG_TYPE_IDLETIME		(egg_idletime_get_type ())
+#define EGG_IDLETIME(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_IDLETIME, EggIdletime))
+#define EGG_IDLETIME_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_IDLETIME, EggIdletimeClass))
+#define EGG_IS_IDLETIME(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_IDLETIME))
+#define EGG_IS_IDLETIME_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_IDLETIME))
+#define EGG_IDLETIME_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_IDLETIME, EggIdletimeClass))
 
 typedef struct EggIdletimePrivate EggIdletimePrivate;
 
@@ -43,26 +44,22 @@ typedef struct
 
 typedef struct
 {
-	GObjectClass	parent_class;
-	void		(* alarm_expired)		(EggIdletime	*idletime,
-							 guint		 timer_id);
-	void		(* reset)			(EggIdletime	*idletime);
+	GObjectClass	 parent_class;
+	void		(* alarm_expired)	(EggIdletime	*idletime,
+						 guint		 timer_id);
+	void		(* reset)		(EggIdletime	*idletime);
 } EggIdletimeClass;
 
-GType		 egg_idletime_get_type			(void);
-EggIdletime	*egg_idletime_new			(void);
-
-void		 egg_idletime_alarm_reset_all		(EggIdletime	*idletime);
-guint		 egg_idletime_alarm_get			(EggIdletime	*idletime);
-gboolean	 egg_idletime_alarm_set			(EggIdletime	*idletime,
-							 guint		 alarm_id,
-							 guint		 timeout);
-gboolean	 egg_idletime_alarm_remove		(EggIdletime	*idletime,
-							 guint		 alarm_id);
+GType		 egg_idletime_get_type		(void);
+EggIdletime	*egg_idletime_new		(void);
+guint		 egg_idletime_add_watch		(EggIdletime	*idletime,
+						 guint		 interval);
+void		 egg_idletime_remove_watch	(EggIdletime	*idletime,
+						 guint		 id);
 #ifdef EGG_TEST
-void		 egg_idletime_test			(gpointer	 data);
+void		 egg_idletime_test		(gpointer	 data);
 #endif
 
 G_END_DECLS
 
-#endif	/* __EGG_IDLETIME_H */
+#endif /* __EGG_IDLETIME_H */
diff --git a/src/gpm-idle.c b/src/gpm-idle.c
index 3a61264..3e515e6 100644
--- a/src/gpm-idle.c
+++ b/src/gpm-idle.c
@@ -48,8 +48,6 @@
 /* Sets the idle percent limit, i.e. how hard the computer can work
    while considered "at idle" */
 #define GPM_IDLE_CPU_LIMIT			5
-#define GPM_IDLE_IDLETIME_ALARM_ID		1
-#define GPM_IDLE_IDLETIME_IGNORE_ID		2
 #define GPM_IDLE_TIMEOUT_IGNORE_DPMS_CHANGE	1.0f /* seconds */
 
 struct GpmIdlePrivate
@@ -63,6 +61,8 @@ struct GpmIdlePrivate
 	guint		 timeout_sleep;		/* in seconds */
 	guint		 timeout_blank_id;
 	guint		 timeout_sleep_id;
+	guint		 idletime_id;
+	guint		 idletime_ignore_id;
 	gboolean	 x_idle;
 	gboolean	 check_type_cpu;
 	GTimer		*timer;
@@ -260,8 +260,12 @@ gpm_idle_set_timeout_dim (GpmIdle *idle, guint timeout)
 	egg_debug ("Setting dim idle timeout: %ds", timeout);
 	if (idle->priv->timeout_dim != timeout) {
 		idle->priv->timeout_dim = timeout;
-		egg_idletime_alarm_set (idle->priv->idletime, GPM_IDLE_IDLETIME_ALARM_ID, idle->priv->timeout_dim * 1000);
-		gpm_idle_evaluate (idle);
+
+		/* remove old id */
+		if (idle->priv->idletime_id != 0)
+			egg_idletime_remove_watch (idle->priv->idletime, idle->priv->idletime_id);
+		idle->priv->idletime_id =
+			egg_idletime_add_watch (idle->priv->idletime, timeout * 1000);
 	}
 	return TRUE;
 }
@@ -334,18 +338,10 @@ gpm_idle_session_inhibited_changed_cb (GpmSession *session, gboolean is_inhibite
 static void
 gpm_idle_idletime_alarm_expired_cb (EggIdletime *idletime, guint alarm_id, GpmIdle *idle)
 {
-	gboolean ret;
-
 	egg_debug ("idletime alarm: %i", alarm_id);
 
-	/* this must be out 500ms ignored timer */
-	if (idle->priv->x_idle) {
-		egg_debug ("removing ignored timer");
-		ret = egg_idletime_alarm_remove (idle->priv->idletime, GPM_IDLE_IDLETIME_IGNORE_ID);
-		if (!ret)
-			egg_warning ("failed to remove timer %i", GPM_IDLE_IDLETIME_IGNORE_ID);
-		return;
-	}
+	if (alarm_id == idle->priv->idletime_ignore_id)
+		egg_debug ("expired 1ms timeout");
 
 	/* set again */
 	idle->priv->x_idle = TRUE;
@@ -360,25 +356,28 @@ gpm_idle_idletime_alarm_expired_cb (EggIdletime *idletime, guint alarm_id, GpmId
 static void
 gpm_idle_idletime_reset_cb (EggIdletime *idletime, GpmIdle *idle)
 {
-	guint id;
-	gboolean ret;
 	gdouble elapsed;
 	elapsed = g_timer_elapsed (idle->priv->timer, NULL);
 
-	id = egg_idletime_alarm_get (idle->priv->idletime);
-	egg_debug ("idletime reset: %i", id);
-
 	/* have we just chaged state? */
 	if (idle->priv->mode == GPM_IDLE_MODE_BLANK &&
 	    elapsed < GPM_IDLE_TIMEOUT_IGNORE_DPMS_CHANGE) {
 		egg_debug ("ignoring reset, as we've just done a state change");
 		/* make sure we trigger a short 1ms timeout so we can get the expired signal */
-		ret = egg_idletime_alarm_set (idle->priv->idletime, GPM_IDLE_IDLETIME_IGNORE_ID, 500);
-		if (!ret)
-			egg_error ("failed to set timer %i", GPM_IDLE_IDLETIME_IGNORE_ID);
+		if (idle->priv->idletime_ignore_id != 0)
+			egg_idletime_remove_watch (idle->priv->idletime, idle->priv->idletime_ignore_id);
+		idle->priv->idletime_ignore_id =
+			egg_idletime_add_watch (idle->priv->idletime, 1);
 		return;
 	}
 
+	/* remove 1ms timeout */
+	if (idle->priv->idletime_ignore_id != 0) {
+		egg_debug ("removing 1ms timeout");
+		egg_idletime_remove_watch (idle->priv->idletime, idle->priv->idletime_ignore_id);
+		idle->priv->idletime_ignore_id = 0;
+	}
+
 	idle->priv->x_idle = FALSE;
 	gpm_idle_evaluate (idle);
 }
@@ -407,6 +406,11 @@ gpm_idle_finalize (GObject *object)
 	g_timer_destroy (idle->priv->timer);
 	g_object_unref (idle->priv->load);
 	g_object_unref (idle->priv->session);
+
+	if (idle->priv->idletime_id != 0)
+		egg_idletime_remove_watch (idle->priv->idletime, idle->priv->idletime_id);
+	if (idle->priv->idletime_ignore_id != 0)
+		egg_idletime_remove_watch (idle->priv->idletime, idle->priv->idletime_ignore_id);
 	g_object_unref (idle->priv->idletime);
 
 	G_OBJECT_CLASS (gpm_idle_parent_class)->finalize (object);
@@ -452,6 +456,8 @@ gpm_idle_init (GpmIdle *idle)
 	idle->priv->timeout_sleep = G_MAXUINT;
 	idle->priv->timeout_blank_id = 0;
 	idle->priv->timeout_sleep_id = 0;
+	idle->priv->idletime_id = 0;
+	idle->priv->idletime_ignore_id = 0;
 	idle->priv->x_idle = FALSE;
 	idle->priv->timer = g_timer_new ();
 	idle->priv->load = gpm_load_new ();



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