← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~ted/cape-girardeau/lib-flesh into lp:~ted/cape-girardeau/trunk

 

Ted Gould has proposed merging lp:~ted/cape-girardeau/lib-flesh into lp:~ted/cape-girardeau/trunk.

    Requested reviews:
    Canonical Desktop Experience Team (canonical-dx-team)



This branch fleshes out the library for clients and adds a variety of tests for making sure they work.

It doesn't connect to a watcher yet, as we didn't have one to test against, so that didn't really make sense anyway :)  Build that next.
-- 
https://code.launchpad.net/~ted/cape-girardeau/lib-flesh/+merge/13810
Your team ayatana-commits is subscribed to branch lp:~ted/cape-girardeau/trunk.
=== modified file '.bzrignore'
--- .bzrignore	2009-10-16 19:32:21 +0000
+++ .bzrignore	2009-10-22 21:45:20 +0000
@@ -15,3 +15,12 @@
 src/libcustomindicator/custom-indicator-enum-types.c
 src/stamp-enum-types
 src/libcustomindicator_la-custom-indicator-enum-types.lo
+tests/.deps
+tests/.libs
+tests/libcustomindicator-check-results.xml
+tests/libcustomindicator-check-results.html
+tests/test-libcustomindicator
+tests/test-libcustomindicator-dbus-client
+tests/test-libcustomindicator-dbus-server
+tests/libcustomindicator-tests
+tests/test-libcustomindicator-dbus

=== modified file 'Makefile.am'
--- Makefile.am	2009-10-15 19:45:07 +0000
+++ Makefile.am	2009-10-22 21:45:20 +0000
@@ -1,5 +1,6 @@
 SUBDIRS = data \
-          src
+          src \
+		  tests
 
 DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall
 

=== modified file 'autogen.sh'
--- autogen.sh	2009-10-13 19:02:17 +0000
+++ autogen.sh	2009-10-22 21:45:20 +0000
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-PKG_NAME="upanel"
+PKG_NAME="indicator-custom"
 
 which gnome-autogen.sh || {
 	echo "You need gnome-common from GNOME SVN"

=== modified file 'configure.ac'
--- configure.ac	2009-10-16 18:20:33 +0000
+++ configure.ac	2009-10-22 21:45:20 +0000
@@ -80,6 +80,7 @@
 Makefile
 src/Makefile
 data/Makefile
+tests/Makefile
 ])
 
 ###########################

=== modified file 'src/libcustomindicator/custom-indicator.c'
--- src/libcustomindicator/custom-indicator.c	2009-10-16 02:12:52 +0000
+++ src/libcustomindicator/custom-indicator.c	2009-10-22 21:45:20 +0000
@@ -2,21 +2,97 @@
 #include "config.h"
 #endif
 
-#include "custom-indicator.h"
-
+#include <dbus/dbus-glib.h>
+#include <libdbusmenu-glib/server.h>
+
+#include "libcustomindicator/custom-indicator.h"
+#include "libcustomindicator/custom-indicator-enum-types.h"
+
+#include "notification-item-server.h"
+#include "notification-watcher-client.h"
+
+/**
+	CustomIndicatorPrivate:
+	@id: The ID of the indicator.  Maps to CustomIndicator::id.
+	@category: Which category the indicator is.  Maps to CustomIndicator::category.
+	@status: The status of the indicator.  Maps to CustomIndicator::status.
+	@icon_name: The name of the icon to use.  Maps to CustomIndicator::icon-name.
+	@attention_icon_name: The name of the attention icon to use.  Maps to CustomIndicator::attention-icon-name.
+	@menu: The menu for this indicator.  Maps to CustomIndicator::menu
+	@watcher_proxy: The proxy connection to the watcher we're connected to.  If we're not connected to one this will be #NULL.
+
+	All of the private data in an instance of a
+	custom indicator.
+*/
 typedef struct _CustomIndicatorPrivate CustomIndicatorPrivate;
 struct _CustomIndicatorPrivate {
-	int placeholder;
-};
-
+	/* Properties */
+	gchar * id;
+	CustomIndicatorCategory category;
+	CustomIndicatorStatus status;
+	gchar * icon_name;
+	gchar * attention_icon_name;
+	DbusmenuServer * menu;
+
+	/* Fun stuff */
+	DBusGProxy * watcher_proxy;
+};
+
+/* Signals Stuff */
+enum {
+	NEW_ICON,
+	NEW_ATTENTION_ICON,
+	NEW_STATUS,
+	CONNECTION_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* Enum for the properties so that they can be quickly
+   found and looked up. */
+enum {
+	PROP_0,
+	PROP_ID,
+	PROP_CATEGORY,
+	PROP_CATEGORY_ENUM,
+	PROP_STATUS,
+	PROP_STATUS_ENUM,
+	PROP_ICON_NAME,
+	PROP_ATTENTION_ICON_NAME,
+	PROP_MENU,
+	PROP_MENU_OBJECT,
+	PROP_CONNECTED
+};
+
+/* The strings so that they can be slowly looked up. */
+#define PROP_ID_S                    "id"
+#define PROP_CATEGORY_S              "category"
+#define PROP_CATEGORY_ENUM_S         "category-enum"
+#define PROP_STATUS_S                "status"
+#define PROP_STATUS_ENUM_S           "status-enum"
+#define PROP_ICON_NAME_S             "icon-name"
+#define PROP_ATTENTION_ICON_NAME_S   "attention-icon-name"
+#define PROP_MENU_S                  "menu"
+#define PROP_MENU_OBJECT_S           "menu-object"
+#define PROP_CONNECTED_S             "connected"
+
+/* Private macro, shhhh! */
 #define CUSTOM_INDICATOR_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), CUSTOM_INDICATOR_TYPE, CustomIndicatorPrivate))
+                             (G_TYPE_INSTANCE_GET_PRIVATE ((o), CUSTOM_INDICATOR_TYPE, CustomIndicatorPrivate))
 
+/* Boiler plate */
 static void custom_indicator_class_init (CustomIndicatorClass *klass);
 static void custom_indicator_init       (CustomIndicator *self);
 static void custom_indicator_dispose    (GObject *object);
 static void custom_indicator_finalize   (GObject *object);
+/* Property functions */
+static void custom_indicator_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
+static void custom_indicator_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
+/* Other stuff */
+static void check_connect (CustomIndicator * self);
 
+/* GObject type */
 G_DEFINE_TYPE (CustomIndicator, custom_indicator, G_TYPE_OBJECT);
 
 static void
@@ -26,32 +102,708 @@
 
 	g_type_class_add_private (klass, sizeof (CustomIndicatorPrivate));
 
+	/* Clean up */
 	object_class->dispose = custom_indicator_dispose;
 	object_class->finalize = custom_indicator_finalize;
 
+	/* Property funcs */
+	object_class->set_property = custom_indicator_set_property;
+	object_class->get_property = custom_indicator_get_property;
+
+	/* Properties */
+	g_object_class_install_property(object_class, PROP_ID,
+	                                g_param_spec_string(PROP_ID_S,
+	                                                    "The ID for this indicator",
+	                                                    "An ID that should be unique, but used consistently by this program and it's indicator.",
+	                                                    NULL,
+	                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_CATEGORY,
+	                                g_param_spec_string(PROP_CATEGORY_S,
+	                                                    "Indicator Category as a string",
+	                                                    "The type of indicator that this represents as a string.  For DBus.",
+	                                                    NULL,
+	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_CATEGORY_ENUM,
+	                                g_param_spec_enum(PROP_CATEGORY_ENUM_S,
+	                                                  "Indicator Category",
+	                                                  "The type of indicator that this represents.  Please don't use 'other'.  Defaults to 'Application Status'.",
+	                                                  CUSTOM_INDICATOR_TYPE_INDICATOR_CATEGORY,
+	                                                  CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS,
+	                                                  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_STATUS,
+	                                g_param_spec_string(PROP_STATUS_S,
+	                                                    "Indicator Status as a string",
+	                                                    "The status of the indicator represented as a string.  For DBus.",
+	                                                    NULL,
+	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_STATUS_ENUM,
+	                                g_param_spec_enum(PROP_STATUS_ENUM_S,
+	                                                  "Indicator Status",
+	                                                  "Whether the indicator is shown or requests attention.  Defaults to 'off'.",
+	                                                  CUSTOM_INDICATOR_TYPE_INDICATOR_STATUS,
+	                                                  CUSTOM_INDICATOR_STATUS_PASSIVE,
+	                                                  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_ICON_NAME,
+	                                g_param_spec_string(PROP_ICON_NAME_S,
+	                                                    "An icon for the indicator",
+	                                                    "The default icon that is shown for the indicator.",
+	                                                    NULL,
+	                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_ATTENTION_ICON_NAME,
+	                                g_param_spec_string(PROP_ATTENTION_ICON_NAME_S,
+	                                                    "An icon to show when the indicator request attention.",
+	                                                    "If the indicator sets it's status to 'attention' then this icon is shown.",
+	                                                    NULL,
+	                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_MENU,
+	                                g_param_spec_string(PROP_MENU_S,
+	                                                    "The object path of the menu on DBus.",
+	                                                    "A method for getting the menu path as a string for DBus.",
+	                                                    NULL,
+	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_MENU_OBJECT,
+	                                g_param_spec_object(PROP_MENU_OBJECT_S,
+	                                                    "The Menu for the indicator",
+	                                                    "A DBus Menu Server object that can have a menu attached to it.  The object from this menu will be sent across the bus for the client to connect to and signal.",
+	                                                    DBUSMENU_TYPE_SERVER,
+	                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property(object_class, PROP_CONNECTED,
+	                                g_param_spec_boolean(PROP_CONNECTED_S,
+	                                                     "Whether we're conneced to a watcher",
+	                                                     "Pretty simple, true if we have a reasonable expectation of being displayed through this object.  You should hide your TrayIcon if so.",
+	                                                     FALSE,
+	                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+
+	/* Signals */
+
+	/**
+		CustomIndicator::new-icon:
+		@arg0: The #CustomIndicator object
+		
+		Signaled when there is a new icon set for the
+		object.
+	*/
+	signals[NEW_ICON] = g_signal_new (CUSTOM_INDICATOR_SIGNAL_NEW_ICON,
+	                                  G_TYPE_FROM_CLASS(klass),
+	                                  G_SIGNAL_RUN_LAST,
+	                                  G_STRUCT_OFFSET (CustomIndicatorClass, new_icon),
+	                                  NULL, NULL,
+	                                  g_cclosure_marshal_VOID__VOID,
+	                                  G_TYPE_NONE, 0, G_TYPE_NONE);
+
+	/**
+		CustomIndicator::new-attention-icon:
+		@arg0: The #CustomIndicator object
+		
+		Signaled when there is a new attention icon set for the
+		object.
+	*/
+	signals[NEW_ATTENTION_ICON] = g_signal_new (CUSTOM_INDICATOR_SIGNAL_NEW_ATTENTION_ICON,
+	                                            G_TYPE_FROM_CLASS(klass),
+	                                            G_SIGNAL_RUN_LAST,
+	                                            G_STRUCT_OFFSET (CustomIndicatorClass, new_attention_icon),
+	                                            NULL, NULL,
+	                                            g_cclosure_marshal_VOID__VOID,
+	                                            G_TYPE_NONE, 0, G_TYPE_NONE);
+
+	/**
+		CustomIndicator::new-status:
+		@arg0: The #CustomIndicator object
+		@arg1: The string value of the #CustomIndicatorStatus enum.
+		
+		Signaled when the status of the indicator changes.
+	*/
+	signals[NEW_STATUS] = g_signal_new (CUSTOM_INDICATOR_SIGNAL_NEW_STATUS,
+	                                    G_TYPE_FROM_CLASS(klass),
+	                                    G_SIGNAL_RUN_LAST,
+	                                    G_STRUCT_OFFSET (CustomIndicatorClass, new_status),
+	                                    NULL, NULL,
+	                                    g_cclosure_marshal_VOID__STRING,
+	                                    G_TYPE_NONE, 1, G_TYPE_STRING, G_TYPE_NONE);
+
+	/**
+		CustomIndicator::connection-changed:
+		@arg0: The #CustomIndicator object
+		@arg1: Whether we're connected or not
+		
+		Signaled when we connect to a watcher, or when it drops
+		away.
+	*/
+	signals[CONNECTION_CHANGED] = g_signal_new (CUSTOM_INDICATOR_SIGNAL_CONNECTION_CHANGED,
+	                                            G_TYPE_FROM_CLASS(klass),
+	                                            G_SIGNAL_RUN_LAST,
+	                                            G_STRUCT_OFFSET (CustomIndicatorClass, connection_changed),
+	                                            NULL, NULL,
+	                                            g_cclosure_marshal_VOID__BOOLEAN,
+	                                            G_TYPE_NONE, 1, G_TYPE_BOOLEAN, G_TYPE_NONE);
+	
+	/* Initialize the object as a DBus type */
+	dbus_g_object_type_install_info(CUSTOM_INDICATOR_TYPE,
+	                                &dbus_glib__notification_item_server_object_info);
+
 	return;
 }
 
 static void
 custom_indicator_init (CustomIndicator *self)
 {
+	CustomIndicatorPrivate * priv = CUSTOM_INDICATOR_GET_PRIVATE(self);
+	g_return_if_fail(priv != NULL);
+
+	priv->id = NULL;
+	priv->category = CUSTOM_INDICATOR_CATEGORY_OTHER;
+	priv->status = CUSTOM_INDICATOR_STATUS_PASSIVE;
+	priv->icon_name = NULL;
+	priv->attention_icon_name = NULL;
+	priv->menu = NULL;
+
+	priv->watcher_proxy = NULL;
+
+	/* Put the object on DBus */
+	GError * error = NULL;
+	DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+	if (error != NULL) {
+		g_error("Unable to connect to the session bus when creating custom indicator: %s", error->message);
+		g_error_free(error);
+		return;
+	}
+	dbus_g_connection_register_g_object(connection,
+	                                    "/need/a/path",
+	                                    G_OBJECT(self));
 
 	return;
 }
 
+/* Free all objects, make sure that all the dbus
+   signals are sent out before we shut this down. */
 static void
 custom_indicator_dispose (GObject *object)
 {
+	CustomIndicator * self = CUSTOM_INDICATOR(object);
+	g_return_if_fail(self != NULL);
+
+	CustomIndicatorPrivate * priv = CUSTOM_INDICATOR_GET_PRIVATE(self);
+	g_return_if_fail(priv != NULL);
+
+	if (priv->status != CUSTOM_INDICATOR_STATUS_PASSIVE) {
+		custom_indicator_set_status(self, CUSTOM_INDICATOR_STATUS_PASSIVE);
+	}
+
+	if (priv->menu != NULL) {
+		g_object_unref(G_OBJECT(priv->menu));
+		priv->menu = NULL;
+	}
+
+	if (priv->watcher_proxy != NULL) {
+		DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+		dbus_g_connection_flush(session_bus);
+		g_object_unref(G_OBJECT(priv->watcher_proxy));
+		priv->watcher_proxy = NULL;
+	}
 
 	G_OBJECT_CLASS (custom_indicator_parent_class)->dispose (object);
 	return;
 }
 
+/* Free all of the memory that we could be using in
+   the object. */
 static void
 custom_indicator_finalize (GObject *object)
 {
+	CustomIndicator * self = CUSTOM_INDICATOR(object);
+	g_return_if_fail(self != NULL);
+
+	CustomIndicatorPrivate * priv = CUSTOM_INDICATOR_GET_PRIVATE(self);
+	g_return_if_fail(priv != NULL);
+
+	if (priv->status != CUSTOM_INDICATOR_STATUS_PASSIVE) {
+		g_warning("Finalizing Custom Status with the status set to: %d", priv->status);
+	}
+
+	if (priv->id != NULL) {
+		g_free(priv->id);
+		priv->id = NULL;
+	}
+
+	if (priv->icon_name != NULL) {
+		g_free(priv->icon_name);
+		priv->icon_name = NULL;
+	}
+
+	if (priv->attention_icon_name != NULL) {
+		g_free(priv->attention_icon_name);
+		priv->attention_icon_name = NULL;
+	}
 
 	G_OBJECT_CLASS (custom_indicator_parent_class)->finalize (object);
 	return;
 }
 
+#define WARN_BAD_TYPE(prop, value)  g_warning("Can not work with property '%s' with value of type '%s'.", prop, G_VALUE_TYPE_NAME(value))
+
+/* Set some properties */
+static void
+custom_indicator_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+	CustomIndicator * self = CUSTOM_INDICATOR(object);
+	g_return_if_fail(self != NULL);
+
+	CustomIndicatorPrivate * priv = CUSTOM_INDICATOR_GET_PRIVATE(self);
+	g_return_if_fail(priv != NULL);
+
+	switch (prop_id) {
+	/* *********************** */
+	case PROP_ID:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			if (priv->id != NULL) {
+				g_warning("Resetting ID value when I already had a value of: %s", priv->id);
+				g_free(priv->id);
+				priv->id = NULL;
+			}
+			priv->id = g_strdup(g_value_get_string(value));
+		} else {
+			WARN_BAD_TYPE(PROP_ID_S, value);
+		}
+		check_connect(self);
+		break;
+	/* *********************** */
+	case PROP_CATEGORY_ENUM:
+		if (G_VALUE_HOLDS_ENUM(value)) {
+			priv->category = g_value_get_enum(value);
+		} else {
+			WARN_BAD_TYPE(PROP_CATEGORY_ENUM_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_STATUS_ENUM: {
+		gboolean changed = FALSE;
+		if (G_VALUE_HOLDS_ENUM(value)) {
+			if (priv->status != g_value_get_enum(value)) {
+				changed = TRUE;
+			}
+			priv->status = g_value_get_enum(value);
+		} else {
+			WARN_BAD_TYPE(PROP_STATUS_ENUM_S, value);
+		}
+		if (changed) {
+			GParamSpecEnum * enumspec = G_PARAM_SPEC_ENUM(pspec);
+			if (enumspec != NULL) {
+				GEnumValue * enumval = g_enum_get_value(enumspec->enum_class, priv->status);
+				g_signal_emit(object, signals[NEW_STATUS], 0, enumval->value_nick, TRUE);
+			}
+		}
+		break;
+	}
+	/* *********************** */
+	case PROP_ICON_NAME:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			const gchar * instr = g_value_get_string(value);
+			gboolean changed = FALSE;
+			if (priv->icon_name == NULL) {
+				priv->icon_name = g_strdup(instr);
+				changed = TRUE;
+			} else if (!g_strcmp0(instr, priv->icon_name)) {
+				changed = FALSE;
+			} else {
+				g_free(priv->icon_name);
+				priv->icon_name = g_strdup(instr);
+				changed = TRUE;
+			}
+			if (changed) {
+				g_signal_emit(object, signals[NEW_ICON], 0, TRUE);
+			}
+		} else {
+			WARN_BAD_TYPE(PROP_ICON_NAME_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_ATTENTION_ICON_NAME:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			const gchar * instr = g_value_get_string(value);
+			gboolean changed = FALSE;
+			if (priv->attention_icon_name == NULL) {
+				priv->attention_icon_name = g_strdup(instr);
+				changed = TRUE;
+			} else if (!g_strcmp0(instr, priv->attention_icon_name)) {
+				changed = FALSE;
+			} else {
+				g_free(priv->attention_icon_name);
+				priv->attention_icon_name = g_strdup(instr);
+				changed = TRUE;
+			}
+			if (changed) {
+				g_signal_emit(object, signals[NEW_ATTENTION_ICON], 0, TRUE);
+			}
+		} else {
+			WARN_BAD_TYPE(PROP_ATTENTION_ICON_NAME_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_MENU_OBJECT:
+		if (G_VALUE_HOLDS_OBJECT(value)) {
+			if (priv->menu != NULL) {
+				g_object_unref(G_OBJECT(priv->menu));
+			}
+			priv->menu = DBUSMENU_SERVER(g_value_get_object(value));
+			g_object_ref(G_OBJECT(priv->menu));
+		} else {
+			WARN_BAD_TYPE(PROP_MENU_S, value);
+		}
+		break;
+	/* *********************** */
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+
+	return;
+}
+
+/* Function to fill our value with the property it's requesting. */
+static void
+custom_indicator_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+	CustomIndicator * self = CUSTOM_INDICATOR(object);
+	g_return_if_fail(self != NULL);
+
+	CustomIndicatorPrivate * priv = CUSTOM_INDICATOR_GET_PRIVATE(self);
+	g_return_if_fail(priv != NULL);
+
+	switch (prop_id) {
+	/* *********************** */
+	case PROP_ID:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			g_value_set_string(value, priv->id);
+		} else {
+			WARN_BAD_TYPE(PROP_ID_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_CATEGORY:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			GParamSpec * spec_for_enum = g_object_class_find_property(G_OBJECT_GET_CLASS(object), PROP_CATEGORY_ENUM_S);
+			GParamSpecEnum * enumspec = G_PARAM_SPEC_ENUM(spec_for_enum);
+			if (enumspec != NULL) {
+				GEnumValue * enumval = g_enum_get_value(enumspec->enum_class, priv->category);
+				g_value_set_string(value, enumval->value_nick);
+			} else {
+				g_assert_not_reached();
+			}
+		} else {
+			WARN_BAD_TYPE(PROP_CATEGORY_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_CATEGORY_ENUM:
+		if (G_VALUE_HOLDS_ENUM(value)) {
+			/* We want the enum value */
+			g_value_set_enum(value, priv->category);
+		} else {
+			WARN_BAD_TYPE(PROP_CATEGORY_ENUM_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_STATUS:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			GParamSpec * spec_for_enum = g_object_class_find_property(G_OBJECT_GET_CLASS(object), PROP_STATUS_ENUM_S);
+			GParamSpecEnum * enumspec = G_PARAM_SPEC_ENUM(spec_for_enum);
+			if (enumspec != NULL) {
+				GEnumValue * enumval = g_enum_get_value(enumspec->enum_class, priv->status);
+				g_value_set_string(value, enumval->value_nick);
+			} else {
+				g_assert_not_reached();
+			}
+		} else {
+			WARN_BAD_TYPE(PROP_STATUS_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_STATUS_ENUM:
+		if (G_VALUE_HOLDS_ENUM(value)) {
+			/* We want the enum value */
+			g_value_set_enum(value, priv->status);
+		} else {
+			WARN_BAD_TYPE(PROP_STATUS_ENUM_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_ICON_NAME:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			g_value_set_string(value, priv->icon_name);
+		} else {
+			WARN_BAD_TYPE(PROP_ICON_NAME_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_ATTENTION_ICON_NAME:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			g_value_set_string(value, priv->attention_icon_name);
+		} else {
+			WARN_BAD_TYPE(PROP_ATTENTION_ICON_NAME_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_MENU:
+		if (G_VALUE_HOLDS_STRING(value)) {
+			if (priv->menu != NULL) {
+				g_object_get_property(G_OBJECT(priv->menu), DBUSMENU_SERVER_PROP_DBUS_OBJECT, value);
+			}
+		} else {
+			WARN_BAD_TYPE(PROP_MENU_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_MENU_OBJECT:
+		if (G_VALUE_HOLDS_OBJECT(value)) {
+			g_value_set_object(value, priv->menu);
+		} else {
+			WARN_BAD_TYPE(PROP_MENU_OBJECT_S, value);
+		}
+		break;
+	/* *********************** */
+	case PROP_CONNECTED:
+		if (G_VALUE_HOLDS_BOOLEAN(value)) {
+			g_value_set_boolean(value, priv->watcher_proxy != NULL ? TRUE : FALSE);
+		} else {
+			WARN_BAD_TYPE(PROP_CONNECTED_S, value);
+		}
+		break;
+	/* *********************** */
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+
+	return;
+}
+
+/* This function is used to see if we have enough information to
+   connect to things.  If we do, and we're not connected, it
+   connects for us. */
+static void
+check_connect (CustomIndicator * self)
+{
+
+
+
+}
+
+
+/* ************************* */
+/*    Public Functions       */
+/* ************************* */
+
+/**
+	custom_indicator_set_id:
+	@ci: The #CustomIndicator object to use
+	@id: ID to set for this indicator
+
+	Wrapper function for property #CustomIndicator::id.
+*/
+void
+custom_indicator_set_id (CustomIndicator * ci, const gchar * id)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_value_set_string(&value, id);
+	g_object_set_property(G_OBJECT(ci), PROP_ID_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_set_category:
+	@ci: The #CustomIndicator object to use
+	@category: The category to set for this indicator
+
+	Wrapper function for property #CustomIndicator::category.
+*/
+void
+custom_indicator_set_category (CustomIndicator * ci, CustomIndicatorCategory category)
+{
+	GValue value = {0};
+	g_value_init(&value, CUSTOM_INDICATOR_TYPE_INDICATOR_CATEGORY);
+	g_value_set_enum(&value, category);
+	g_object_set_property(G_OBJECT(ci), PROP_CATEGORY_ENUM_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_set_status:
+	@ci: The #CustomIndicator object to use
+	@status: The status to set for this indicator
+
+	Wrapper function for property #CustomIndicator::status.
+*/
+void
+custom_indicator_set_status (CustomIndicator * ci, CustomIndicatorStatus status)
+{
+	GValue value = {0};
+	g_value_init(&value, CUSTOM_INDICATOR_TYPE_INDICATOR_STATUS);
+	g_value_set_enum(&value, status);
+	g_object_set_property(G_OBJECT(ci), PROP_STATUS_ENUM_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_set_icon:
+	@ci: The #CustomIndicator object to use
+	@icon_name: The name of the icon to set for this indicator
+
+	Wrapper function for property #CustomIndicator::icon.
+*/
+void custom_indicator_set_icon (CustomIndicator * ci, const gchar * icon_name)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_value_set_string(&value, icon_name);
+	g_object_set_property(G_OBJECT(ci), PROP_ICON_NAME_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_set_attention_icon:
+	@ci: The #CustomIndicator object to use
+	@icon_name: The name of the attention icon to set for this indicator
+
+	Wrapper function for property #CustomIndicator::attention-icon.
+*/
+void
+custom_indicator_set_attention_icon (CustomIndicator * ci, const gchar * icon_name)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_value_set_string(&value, icon_name);
+	g_object_set_property(G_OBJECT(ci), PROP_ATTENTION_ICON_NAME_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_set_menu:
+	@ci: The #CustomIndicator object to use
+	@menu: The object with the menu for the indicator
+
+	Wrapper function for property #CustomIndicator::menu.
+*/
+void
+custom_indicator_set_menu (CustomIndicator * ci, DbusmenuServer * menu)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_OBJECT);
+	g_value_set_object(&value, G_OBJECT(menu));
+	g_object_set_property(G_OBJECT(ci), PROP_MENU_OBJECT_S, &value);
+	return;
+}
+
+/**
+	custom_indicator_get_id:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::id.
+
+	Return value: The current ID
+*/
+const gchar *
+custom_indicator_get_id (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_object_get_property(G_OBJECT(ci), PROP_ID_S, &value);
+	return g_value_get_string(&value);
+}
+
+/**
+	custom_indicator_get_category:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::category.
+
+	Return value: The current category.
+*/
+CustomIndicatorCategory
+custom_indicator_get_category (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, CUSTOM_INDICATOR_TYPE_INDICATOR_CATEGORY);
+	g_object_get_property(G_OBJECT(ci), PROP_CATEGORY_ENUM_S, &value);
+	return g_value_get_enum(&value);
+}
+
+/**
+	custom_indicator_get_status:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::status.
+
+	Return value: The current status.
+*/
+CustomIndicatorStatus
+custom_indicator_get_status (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, CUSTOM_INDICATOR_TYPE_INDICATOR_STATUS);
+	g_object_get_property(G_OBJECT(ci), PROP_STATUS_ENUM_S, &value);
+	return g_value_get_enum(&value);
+}
+
+/**
+	custom_indicator_get_icon:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::icon-name.
+
+	Return value: The current icon name.
+*/
+const gchar *
+custom_indicator_get_icon (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_object_get_property(G_OBJECT(ci), PROP_ICON_NAME_S, &value);
+	return g_value_get_string(&value);
+}
+
+/**
+	custom_indicator_get_attention_icon:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::attention-icon-name.
+
+	Return value: The current attention icon name.
+*/
+const gchar *
+custom_indicator_get_attention_icon (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_STRING);
+	g_object_get_property(G_OBJECT(ci), PROP_ATTENTION_ICON_NAME_S, &value);
+	return g_value_get_string(&value);
+}
+
+/**
+	custom_indicator_get_menu:
+	@ci: The #CustomIndicator object to use
+
+	Wrapper function for property #CustomIndicator::menu.
+
+	Return value: The current menu being used.
+*/
+DbusmenuServer *
+custom_indicator_get_menu (CustomIndicator * ci)
+{
+	GValue value = {0};
+	g_value_init(&value, G_TYPE_OBJECT);
+	g_object_get_property(G_OBJECT(ci), PROP_MENU_OBJECT_S, &value);
+	return DBUSMENU_SERVER(g_value_get_object(&value));
+}
+
+

=== modified file 'src/libcustomindicator/custom-indicator.h'
--- src/libcustomindicator/custom-indicator.h	2009-10-18 03:16:44 +0000
+++ src/libcustomindicator/custom-indicator.h	2009-10-22 21:45:20 +0000
@@ -3,6 +3,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <libdbusmenu-glib/server.h>
 
 G_BEGIN_DECLS
 
@@ -13,6 +14,11 @@
 #define IS_CUSTOM_INDICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CUSTOM_INDICATOR_TYPE))
 #define CUSTOM_INDICATOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CUSTOM_INDICATOR_TYPE, CustomIndicatorClass))
 
+#define CUSTOM_INDICATOR_SIGNAL_NEW_ICON            "new-icon"
+#define CUSTOM_INDICATOR_SIGNAL_NEW_ATTENTION_ICON  "new-attention-icon"
+#define CUSTOM_INDICATOR_SIGNAL_NEW_STATUS          "new-status"
+#define CUSTOM_INDICATOR_SIGNAL_CONNECTION_CHANGED  "connection-changed"
+
 /**
 	CustomIndicatorCategory:
 	@CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS: The indicator is used to display the status of the application.
@@ -34,8 +40,8 @@
 
 /**
 	CustomIndicatorStatus:
-	@CUSTOM_INDICATOR_STATUS_OFF: The indicator should not be shown to the user.
-	@CUSTOM_INDICATOR_STATUS_ON: The indicator should be shown in it's default state.
+	@CUSTOM_INDICATOR_STATUS_PASSIVE: The indicator should not be shown to the user.
+	@CUSTOM_INDICATOR_STATUS_ACTIVE: The indicator should be shown in it's default state.
 	@CUSTOM_INDICATOR_STATUS_ATTENTION: The indicator should show it's attention icon.
 
 	These are the states that the indicator can be on in
@@ -44,20 +50,66 @@
 	shown by setting it to @CUSTOM_INDICATOR_STATUS_ON.
 */
 typedef enum { /*< prefix=CUSTOM_INDICATOR_STATUS >*/
-	CUSTOM_INDICATOR_STATUS_OFF,
-	CUSTOM_INDICATOR_STATUS_ON,
+	CUSTOM_INDICATOR_STATUS_PASSIVE,
+	CUSTOM_INDICATOR_STATUS_ACTIVE,
 	CUSTOM_INDICATOR_STATUS_ATTENTION
 } CustomIndicatorStatus;
 
 typedef struct _CustomIndicator      CustomIndicator;
 typedef struct _CustomIndicatorClass CustomIndicatorClass;
 
+/**
+	CustomIndicatorClass:
+	@parent_class: Mia familia
+	@new_icon: Slot for #CustomIndicator::new-icon.
+	@new_attention_icon: Slot for #CustomIndicator::new-attention-icon.
+	@new_status: Slot for #CustomIndicator::new-status.
+	@connection_changed: Slot for #CustomIndicator::connection-changed.
+	@custom_indicator_reserved_1: Reserved for future use.
+	@custom_indicator_reserved_2: Reserved for future use.
+	@custom_indicator_reserved_3: Reserved for future use.
+	@custom_indicator_reserved_4: Reserved for future use.
+
+	The signals and external functions that make up the #CustomIndicator
+	class object.
+*/
 struct _CustomIndicatorClass {
+	/* Parent */
 	GObjectClass parent_class;
+
+	/* DBus Signals */
+	void (* new_icon)               (CustomIndicator * indicator,
+	                                 gpointer          user_data);
+	void (* new_attention_icon)     (CustomIndicator * indicator,
+	                                 gpointer          user_data);
+	void (* new_status)             (CustomIndicator * indicator,
+	                                 gchar *           status_string,
+	                                 gpointer          user_data);
+
+	/* Local Signals */
+	void (* connection_changed)     (CustomIndicator * indicator,
+	                                 gboolean          connected,
+	                                 gpointer          user_data);
+
+	/* Reserved */
+	void (*custom_indicator_reserved_1)(void);
+	void (*custom_indicator_reserved_2)(void);
+	void (*custom_indicator_reserved_3)(void);
+	void (*custom_indicator_reserved_4)(void);
 };
 
+/**
+	CustomIndicator:
+	@parent: Parent object.
+
+	A custom indicator represents the values that are needed to show a
+	unique status in the panel for an application.  In general, applications
+	should try to fit in the other indicators that are available on the
+	panel before using this.  But, sometimes it is necissary.
+*/
 struct _CustomIndicator {
 	GObject parent;
+	/* None.  We're a very private object. */
 };
 
 /* GObject Stuff */
@@ -75,7 +127,7 @@
 void                            custom_indicator_set_attention_icon (CustomIndicator * ci,
                                                                      const gchar * icon_name);
 void                            custom_indicator_set_menu           (CustomIndicator * ci,
-                                                                     void * menu);
+                                                                     DbusmenuServer * menu);
 
 /* Get properties */
 const gchar *                   custom_indicator_get_id             (CustomIndicator * ci);
@@ -83,7 +135,7 @@
 CustomIndicatorStatus           custom_indicator_get_status         (CustomIndicator * ci);
 const gchar *                   custom_indicator_get_icon           (CustomIndicator * ci);
 const gchar *                   custom_indicator_get_attention_icon (CustomIndicator * ci);
-void *                          custom_indicator_get_menu           (CustomIndicator * ci);
+DbusmenuServer *                custom_indicator_get_menu           (CustomIndicator * ci);
 
 G_END_DECLS
 

=== added directory 'tests'
=== added file 'tests/Makefile.am'
--- tests/Makefile.am	1970-01-01 00:00:00 +0000
+++ tests/Makefile.am	2009-10-22 21:45:20 +0000
@@ -0,0 +1,84 @@
+
+check_PROGRAMS = \
+	test-libcustomindicator \
+	test-libcustomindicator-dbus-client \
+	test-libcustomindicator-dbus-server
+
+TESTS =
+DISTCLEANFILES = $(TESTS)
+
+#########################################
+##  test-libcustomindicator
+#########################################
+
+test_libcustomindicator_SOURCES = \
+	test-libcustomindicator.c
+
+test_libcustomindicator_CFLAGS = \
+	$(INDICATOR_CFLAGS) \
+	-Wall -Werror \
+	-I$(top_srcdir)/src
+
+test_libcustomindicator_LDADD = \
+	$(INDICATOR_LIBS) \
+	$(top_builddir)/src/libcustomindicator.la
+
+#########################################
+##  test-libcustomindicator-dbus-client
+#########################################
+
+test_libcustomindicator_dbus_client_SOURCES = \
+	test-defines.h \
+	test-libcustomindicator-dbus-client.c
+
+test_libcustomindicator_dbus_client_CFLAGS = \
+	$(INDICATOR_CFLAGS) \
+	-Wall -Werror \
+	-I$(top_srcdir)/src
+
+test_libcustomindicator_dbus_client_LDADD = \
+	$(INDICATOR_LIBS) \
+	$(top_builddir)/src/libcustomindicator.la
+
+#########################################
+##  test-libcustomindicator-dbus-server
+#########################################
+
+test_libcustomindicator_dbus_server_SOURCES = \
+	test-defines.h \
+	test-libcustomindicator-dbus-server.c
+
+test_libcustomindicator_dbus_server_CFLAGS = \
+	$(INDICATOR_CFLAGS) \
+	-Wall -Werror \
+	-I$(top_srcdir)/src
+
+test_libcustomindicator_dbus_server_LDADD = \
+	$(INDICATOR_LIBS) \
+	$(top_builddir)/src/libcustomindicator.la
+
+#########################################
+##  Actual tests
+#########################################
+
+XML_REPORT   = libcustomindicator-check-results.xml
+HTML_REPORT  = libcustomindicator-check-results.html
+
+libcustomindicator-tests: test-libcustomindicator
+	@echo "#!/bin/sh" > libcustomindicator-tests
+	@echo gtester -k --verbose -o=$(XML_REPORT) ./test-libcustomindicator >> libcustomindicator-tests
+	@chmod +x libcustomindicator-tests
+
+TESTS += libcustomindicator-tests
+DISTCLEANFILES += $(XML_REPORT) $(HTML_REPORT)
+
+
+DBUS_RUNNER=dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf
+
+test-libcustomindicator-dbus: test-libcustomindicator-dbus-client test-libcustomindicator-dbus-server Makefile.am
+	@echo "#!/bin/sh" > test-libcustomindicator-dbus
+	@echo $(DBUS_RUNNER) --task ./test-libcustomindicator-dbus-client --task-name Client --task ./test-libcustomindicator-dbus-server --task-name Server --ignore-return >> test-libcustomindicator-dbus
+	@chmod +x test-libcustomindicator-dbus
+
+TESTS += test-libcustomindicator-dbus
+

=== added file 'tests/test-defines.h'
--- tests/test-defines.h	1970-01-01 00:00:00 +0000
+++ tests/test-defines.h	2009-10-22 21:45:20 +0000
@@ -0,0 +1,10 @@
+
+#define  TEST_ID                   "my-id"
+#define  TEST_ICON_NAME            "my-icon-name"
+#define  TEST_ATTENTION_ICON_NAME  "my-attention-icon-name"
+#define  TEST_STATE                CUSTOM_INDICATOR_STATUS_ACTIVE
+#define  TEST_STATE_S              "active"
+#define  TEST_CATEGORY             CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS
+#define  TEST_CATEGORY_S           "application-status"
+#define  TEST_OBJECT               "/an/object/path/to/use"
+

=== added file 'tests/test-libcustomindicator-dbus-client.c'
--- tests/test-libcustomindicator-dbus-client.c	1970-01-01 00:00:00 +0000
+++ tests/test-libcustomindicator-dbus-client.c	2009-10-22 21:45:20 +0000
@@ -0,0 +1,272 @@
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+#include <libcustomindicator/custom-indicator.h>
+#include "test-defines.h"
+
+static GMainLoop * mainloop = NULL;
+static gboolean passed = TRUE;
+static int propcount = 0;
+
+static void
+check_propcount (void)
+{
+	if (propcount >= 6) {
+		g_main_loop_quit(mainloop);
+	}
+	return;
+}
+
+
+static void
+prop_id_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting ID failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_ID, g_value_get_string(&value))) {
+		g_debug("Property ID Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property ID Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+static void
+prop_category_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting category failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_CATEGORY_S, g_value_get_string(&value))) {
+		g_debug("Property category Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property category Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+static void
+prop_status_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting status failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_STATE_S, g_value_get_string(&value))) {
+		g_debug("Property status Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property status Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+static void
+prop_icon_name_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting icon name failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_ICON_NAME, g_value_get_string(&value))) {
+		g_debug("Property icon name Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property icon name Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+static void
+prop_attention_icon_name_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting attention icon name failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_ATTENTION_ICON_NAME, g_value_get_string(&value))) {
+		g_debug("Property attention icon name Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property attention icon name Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+static void
+prop_menu_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	propcount++;
+
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting menu object failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		check_propcount();
+		return;
+	}
+
+	if (g_strcmp0(TEST_OBJECT, g_value_get_string(&value))) {
+		g_debug("Property menu object Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property menu object Returned: PASSED");
+	}
+
+	check_propcount();
+	return;
+}
+
+gboolean
+kill_func (gpointer userdata)
+{
+	g_main_loop_quit(mainloop);
+	g_warning("Forced to Kill");
+	passed = FALSE;
+	return FALSE;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+	g_type_init();
+
+	g_usleep(500000);
+
+	GError * error = NULL;
+	DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+	if (error != NULL) {
+		g_error("Unable to get session bus: %s", error->message);
+		return 1;
+	}
+
+	DBusGProxy * props = dbus_g_proxy_new_for_name_owner(session_bus,
+	                                                     ":1.0",
+	                                                     "/need/a/path",
+	                                                     DBUS_INTERFACE_PROPERTIES,
+	                                                     &error);
+	if (error != NULL) {
+		g_error("Unable to get property proxy: %s", error->message);
+		return 1;
+	}
+
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_id_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "Id",
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_category_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "Category",
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_status_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "Status",
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_icon_name_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "IconName",
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_attention_icon_name_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "AttentionIconName",
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_begin_call (props,
+	                         "Get",
+	                         prop_menu_cb,
+	                         NULL, NULL,
+	                         G_TYPE_STRING, "org.ayatana.indicator.custom.NotificationItem",
+	                         G_TYPE_STRING, "Menu",
+	                         G_TYPE_INVALID);
+
+	g_timeout_add_seconds(2, kill_func, NULL);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(mainloop);
+
+	if (passed) {
+		g_debug("Quiting");
+		return 0;
+	} else {
+		g_debug("Quiting as we're a failure");
+		return 1;
+	}
+	return 0;
+}

=== added file 'tests/test-libcustomindicator-dbus-server.c'
--- tests/test-libcustomindicator-dbus-server.c	1970-01-01 00:00:00 +0000
+++ tests/test-libcustomindicator-dbus-server.c	2009-10-22 21:45:20 +0000
@@ -0,0 +1,44 @@
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+#include <libcustomindicator/custom-indicator.h>
+#include "test-defines.h"
+
+static GMainLoop * mainloop = NULL;
+
+gboolean
+kill_func (gpointer userdata)
+{
+	g_main_loop_quit(mainloop);
+	return FALSE;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+	g_type_init();
+
+	g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
+
+	DbusmenuServer * dms = dbusmenu_server_new(TEST_OBJECT);
+
+	CustomIndicator * ci = CUSTOM_INDICATOR(g_object_new(CUSTOM_INDICATOR_TYPE, 
+	                                                     "id", TEST_ID,
+	                                                     "category-enum", TEST_CATEGORY,
+	                                                     "status-enum", TEST_STATE,
+	                                                     "icon-name", TEST_ICON_NAME,
+	                                                     "attention-icon-name", TEST_ATTENTION_ICON_NAME,
+	                                                     "menu-object", dms,
+	                                                     NULL));
+
+	g_timeout_add_seconds(2, kill_func, NULL);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(mainloop);
+
+	g_object_unref(G_OBJECT(ci));
+	g_debug("Quiting");
+
+	return 0;
+}

=== added file 'tests/test-libcustomindicator.c'
--- tests/test-libcustomindicator.c	1970-01-01 00:00:00 +0000
+++ tests/test-libcustomindicator.c	2009-10-22 21:45:20 +0000
@@ -0,0 +1,163 @@
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libcustomindicator/custom-indicator.h>
+
+void
+test_libcustomindicator_prop_signals_status_helper (CustomIndicator * ci, gchar * status, gboolean * signalactivated)
+{
+	*signalactivated = TRUE;
+	return;
+}
+
+void
+test_libcustomindicator_prop_signals_helper (CustomIndicator * ci, gboolean * signalactivated)
+{
+	*signalactivated = TRUE;
+	return;
+}
+
+void
+test_libcustomindicator_prop_signals (void)
+{
+	CustomIndicator * ci = CUSTOM_INDICATOR(g_object_new(CUSTOM_INDICATOR_TYPE, NULL));
+	g_assert(ci != NULL);
+
+	gboolean signaled = FALSE;
+	gulong handlerid;
+
+	handlerid = 0;
+	handlerid = g_signal_connect(G_OBJECT(ci), "new-icon", G_CALLBACK(test_libcustomindicator_prop_signals_helper), &signaled);
+	g_assert(handlerid != 0);
+
+	handlerid = 0;
+	handlerid = g_signal_connect(G_OBJECT(ci), "new-attention-icon", G_CALLBACK(test_libcustomindicator_prop_signals_helper), &signaled);
+	g_assert(handlerid != 0);
+
+	handlerid = 0;
+	handlerid = g_signal_connect(G_OBJECT(ci), "new-status", G_CALLBACK(test_libcustomindicator_prop_signals_status_helper), &signaled);
+	g_assert(handlerid != 0);
+
+
+	signaled = FALSE;
+	custom_indicator_set_icon(ci, "bob");
+	g_assert(signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_icon(ci, "bob");
+	g_assert(!signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_icon(ci, "al");
+	g_assert(signaled);
+
+
+	signaled = FALSE;
+	custom_indicator_set_attention_icon(ci, "bob");
+	g_assert(signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_attention_icon(ci, "bob");
+	g_assert(!signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_attention_icon(ci, "al");
+	g_assert(signaled);
+
+
+	signaled = FALSE;
+	custom_indicator_set_status(ci, CUSTOM_INDICATOR_STATUS_PASSIVE);
+	g_assert(!signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_status(ci, CUSTOM_INDICATOR_STATUS_ACTIVE);
+	g_assert(signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_status(ci, CUSTOM_INDICATOR_STATUS_ACTIVE);
+	g_assert(!signaled);
+
+	signaled = FALSE;
+	custom_indicator_set_status(ci, CUSTOM_INDICATOR_STATUS_ATTENTION);
+	g_assert(signaled);
+
+	return;
+}
+
+void
+test_libcustomindicator_init_set_props (void)
+{
+	CustomIndicator * ci = CUSTOM_INDICATOR(g_object_new(CUSTOM_INDICATOR_TYPE, NULL));
+	g_assert(ci != NULL);
+
+	custom_indicator_set_id(ci, "my-id");
+	custom_indicator_set_category(ci, CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS);
+	custom_indicator_set_status(ci, CUSTOM_INDICATOR_STATUS_ACTIVE);
+	custom_indicator_set_icon(ci, "my-name");
+	custom_indicator_set_attention_icon(ci, "my-attention-name");
+
+	g_assert(!g_strcmp0("my-id", custom_indicator_get_id(ci)));
+	g_assert(!g_strcmp0("my-name", custom_indicator_get_icon(ci)));
+	g_assert(!g_strcmp0("my-attention-name", custom_indicator_get_attention_icon(ci)));
+	g_assert(custom_indicator_get_status(ci) == CUSTOM_INDICATOR_STATUS_ACTIVE);
+	g_assert(custom_indicator_get_category(ci) == CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS);
+
+	g_object_unref(G_OBJECT(ci));
+	return;
+}
+
+void
+test_libcustomindicator_init_with_props (void)
+{
+	CustomIndicator * ci = CUSTOM_INDICATOR(g_object_new(CUSTOM_INDICATOR_TYPE, 
+	                                                     "id", "my-id",
+	                                                     "category-enum", CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS,
+	                                                     "status-enum", CUSTOM_INDICATOR_STATUS_ACTIVE,
+	                                                     "icon-name", "my-name",
+	                                                     "attention-icon-name", "my-attention-name",
+	                                                     NULL));
+	g_assert(ci != NULL);
+
+	g_assert(!g_strcmp0("my-id", custom_indicator_get_id(ci)));
+	g_assert(!g_strcmp0("my-name", custom_indicator_get_icon(ci)));
+	g_assert(!g_strcmp0("my-attention-name", custom_indicator_get_attention_icon(ci)));
+	g_assert(custom_indicator_get_status(ci) == CUSTOM_INDICATOR_STATUS_ACTIVE);
+	g_assert(custom_indicator_get_category(ci) == CUSTOM_INDICATOR_CATEGORY_APPLICATION_STATUS);
+
+	g_object_unref(G_OBJECT(ci));
+	return;
+}
+
+void
+test_libcustomindicator_init (void)
+{
+	CustomIndicator * ci = CUSTOM_INDICATOR(g_object_new(CUSTOM_INDICATOR_TYPE, NULL));
+	g_assert(ci != NULL);
+	g_object_unref(G_OBJECT(ci));
+	return;
+}
+
+void
+test_libcustomindicator_props_suite (void)
+{
+	g_test_add_func ("/indicator-custom/libcustomindicator/init",        test_libcustomindicator_init);
+	g_test_add_func ("/indicator-custom/libcustomindicator/init_props",  test_libcustomindicator_init_with_props);
+	g_test_add_func ("/indicator-custom/libcustomindicator/init_set_props",  test_libcustomindicator_init_set_props);
+	g_test_add_func ("/indicator-custom/libcustomindicator/prop_signals",  test_libcustomindicator_prop_signals);
+
+	return;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+	g_type_init();
+	g_test_init(&argc, &argv, NULL);
+
+	/* Test suites */
+	test_libcustomindicator_props_suite();
+
+
+	return g_test_run ();
+}


Follow ups