← Back to team overview

ayatana-commits team mailing list archive

[Branch ~dbusmenu-team/dbusmenu/trunk] Rev 197: Adding in a serializable menuitem object

 

Merge authors:
  Ted Gould (ted)
Related merge proposals:
  https://code.launchpad.net/~ted/dbusmenu/serializable-menuitem/+merge/47604
  proposed by: Ted Gould (ted)
  review: Needs Fixing - Mikkel Kamstrup Erlandsen (kamstrup)
------------------------------------------------------------
revno: 197 [merge]
committer: Ted Gould <ted@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2011-01-27 13:49:40 -0600
message:
  Adding in a serializable menuitem object
added:
  libdbusmenu-gtk/serializablemenuitem.c
  libdbusmenu-gtk/serializablemenuitem.h
modified:
  .bzrignore
  docs/libdbusmenu-gtk/reference/Makefile.am
  docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
  libdbusmenu-glib/client.c
  libdbusmenu-glib/client.h
  libdbusmenu-gtk/Makefile.am
  libdbusmenu-gtk/client.c
  libdbusmenu-gtk/dbusmenu-gtk.h
  libdbusmenu-gtk/menuitem.h


--
lp:dbusmenu
https://code.launchpad.net/~dbusmenu-team/dbusmenu/trunk

Your team ayatana-commits is subscribed to branch lp:dbusmenu.
To unsubscribe from this branch go to https://code.launchpad.net/~dbusmenu-team/dbusmenu/trunk/+edit-subscription
=== modified file '.bzrignore'
--- .bzrignore	2011-01-23 19:30:00 +0000
+++ .bzrignore	2011-01-27 19:49:40 +0000
@@ -224,3 +224,6 @@
 test-gtk-parser
 test-gtk-parser-test
 test-gtk-parser.xml
+libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo
+docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html
+docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml

=== modified file 'docs/libdbusmenu-gtk/reference/Makefile.am'
--- docs/libdbusmenu-gtk/reference/Makefile.am	2010-11-23 21:19:52 +0000
+++ docs/libdbusmenu-gtk/reference/Makefile.am	2011-01-21 23:01:41 +0000
@@ -54,7 +54,7 @@
 
 # Header files to ignore when scanning.
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES=
+IGNORE_HFILES=genericmenuitem.h
 
 # Images to copy into HTML directory.
 # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png

=== modified file 'docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml'
--- docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml	2010-06-09 16:24:31 +0000
+++ docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml	2011-01-21 23:01:41 +0000
@@ -13,8 +13,8 @@
     <title>API</title>
         <xi:include href="xml/menu.xml"/>
     <xi:include href="xml/client.xml"/>
-    <xi:include href="xml/genericmenuitem.xml"/>
     <xi:include href="xml/menuitem.xml"/>
+    <xi:include href="xml/serializablemenuitem.xml"/>
 
   </chapter>
   <chapter id="object-tree">

=== modified file 'libdbusmenu-glib/client.c'
--- libdbusmenu-glib/client.c	2011-01-26 23:12:22 +0000
+++ libdbusmenu-glib/client.c	2011-01-27 19:49:40 +0000
@@ -120,6 +120,15 @@
 	guint timestamp;
 };
 
+typedef struct _type_handler_t type_handler_t;
+struct _type_handler_t {
+	DbusmenuClient * client;
+	DbusmenuClientTypeHandler cb;
+	DbusmenuClientTypeDestroyHandler destroy_cb;
+	gpointer user_data;
+	gchar * type;
+};
+
 
 #define DBUSMENU_CLIENT_GET_PRIVATE(o) (DBUSMENU_CLIENT(o)->priv)
 #define DBUSMENU_INTERFACE  "com.canonical.dbusmenu"
@@ -148,6 +157,7 @@
 static void menuproxy_build_cb (GObject * object, GAsyncResult * res, gpointer user_data);
 static void menuproxy_name_changed_cb (GObject * object, GParamSpec * pspec, gpointer user_data);
 static void menuproxy_signal_cb (GDBusProxy * proxy, gchar * sender, gchar * signal, GVariant * params, gpointer user_data);
+static void type_handler_destroy (gpointer user_data);
 
 /* Globals */
 static GDBusNodeInfo *            dbusmenu_node_info = NULL;
@@ -310,7 +320,7 @@
 	priv->dbusproxy = 0;
 
 	priv->type_handlers = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                            g_free, NULL);
+	                                            g_free, type_handler_destroy);
 
 	priv->delayed_idle = 0;
 	priv->delayed_property_list = g_array_new(TRUE, FALSE, sizeof(gchar *));
@@ -1153,17 +1163,17 @@
 	gboolean handled = FALSE;
 
 	const gchar * type;
-	DbusmenuClientTypeHandler newfunc = NULL;
+	type_handler_t * th = NULL;
 	
 	type = dbusmenu_menuitem_property_get(propdata->item, DBUSMENU_MENUITEM_PROP_TYPE);
 	if (type != NULL) {
-		newfunc = g_hash_table_lookup(priv->type_handlers, type);
+		th = (type_handler_t *)g_hash_table_lookup(priv->type_handlers, type);
 	} else {
-		newfunc = g_hash_table_lookup(priv->type_handlers, DBUSMENU_CLIENT_TYPES_DEFAULT);
+		th = (type_handler_t *)g_hash_table_lookup(priv->type_handlers, DBUSMENU_CLIENT_TYPES_DEFAULT);
 	}
 
-	if (newfunc != NULL) {
-		handled = newfunc(propdata->item, propdata->parent, propdata->client);
+	if (th != NULL && th->cb != NULL) {
+		handled = th->cb(propdata->item, propdata->parent, propdata->client, th->user_data);
 	}
 
 	#ifdef MASSIVEDEBUGGING
@@ -1679,6 +1689,19 @@
 	return priv->root;
 }
 
+/* Remove the type handler when we're all done with it */
+static void
+type_handler_destroy (gpointer user_data)
+{
+	type_handler_t * th = (type_handler_t *)user_data;
+	if (th->destroy_cb != NULL) {
+		th->destroy_cb(th->client, th->type, th->user_data);
+	}
+	g_free(th->type);
+	g_free(th);
+	return;
+}
+
 /**
 	dbusmenu_client_add_type_handler:
 	@client: Client where we're getting types coming in
@@ -1703,6 +1726,37 @@
 gboolean
 dbusmenu_client_add_type_handler (DbusmenuClient * client, const gchar * type, DbusmenuClientTypeHandler newfunc)
 {
+	return dbusmenu_client_add_type_handler_full(client, type, newfunc, NULL, NULL);
+}
+
+/**
+	dbusmenu_client_add_type_handler_full:
+	@client: Client where we're getting types coming in
+	@type: A text string that will be matched with the 'type'
+	    property on incoming menu items
+	@newfunc: The function that will be executed with those new
+	    items when they come in.
+	@user_data: Data passed to @newfunc when it is called
+	@destroy_func: A function that is called when the type handler is
+		removed (usually on client destruction) which will free
+		the resources in @user_data.
+
+	This function connects into the type handling of the #DbusmenuClient.
+	Every new menuitem that comes in immediately gets asked for it's
+	properties.  When we get those properties we check the 'type'
+	property and look to see if it matches a handler that is known
+	by the client.  If so, the @newfunc function is executed on that
+	#DbusmenuMenuitem.  If not, then the DbusmenuClient::new-menuitem
+	signal is sent.
+
+	In the future the known types will be sent to the server so that it
+	can make choices about the menu item types availble.
+
+	Return value: If registering the new type was successful.
+*/
+gboolean
+dbusmenu_client_add_type_handler_full (DbusmenuClient * client, const gchar * type, DbusmenuClientTypeHandler newfunc, gpointer user_data, DbusmenuClientTypeDestroyHandler destroy_func)
+{
 	g_return_val_if_fail(DBUSMENU_IS_CLIENT(client), FALSE);
 	g_return_val_if_fail(type != NULL, FALSE);
 
@@ -1723,6 +1777,14 @@
 		return FALSE;
 	}
 
-	g_hash_table_insert(priv->type_handlers, g_strdup(type), newfunc);
+	type_handler_t * th = g_new0(type_handler_t, 1);
+	th->client = client;
+	th->cb = newfunc;
+	th->destroy_cb = destroy_func;
+	th->user_data = user_data;
+	th->type = g_strdup(type);
+
+	g_hash_table_insert(priv->type_handlers, g_strdup(type), th);
 	return TRUE;
 }
+

=== modified file 'libdbusmenu-glib/client.h'
--- libdbusmenu-glib/client.h	2010-11-18 03:07:51 +0000
+++ libdbusmenu-glib/client.h	2011-01-27 15:35:14 +0000
@@ -110,7 +110,29 @@
 	DbusmenuClientPrivate * priv;
 };
 
-typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+/**
+	DbusmenuClientTypeHandler:
+	@newitem: The #DbusmenuMenuitem that was created
+	@parent: The parent of @newitem or #NULL if none
+	@client: A pointer to the #DbusmenuClient
+	@user_data: The data you gave us
+
+	The type handler is called when a dbusmenu item is created
+	with a matching type as setup in #dbusmenu_client_add_type_handler
+*/
+typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
+
+/**
+	DbusmenuClientTypeDestroyHandler:
+	@client: A pointer to the #DbusmenuClient
+	@type: The type that this handler was registered with
+	@user_data: The data you gave us
+
+	This handler is called when the type becomes unregistered by the
+	client.  This is usally caused by the #DbusmenuClient being destroyed
+	and should free memory or unref objects in @user_data.
+*/
+typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data);
 
 GType                dbusmenu_client_get_type          (void);
 DbusmenuClient *     dbusmenu_client_new               (const gchar * name,
@@ -119,6 +141,11 @@
 gboolean             dbusmenu_client_add_type_handler  (DbusmenuClient * client,
                                                         const gchar * type,
                                                         DbusmenuClientTypeHandler newfunc);
+gboolean             dbusmenu_client_add_type_handler_full (DbusmenuClient * client,
+                                                        const gchar * type,
+                                                        DbusmenuClientTypeHandler newfunc,
+                                                        gpointer user_data,
+                                                        DbusmenuClientTypeDestroyHandler destory_func);
 void                 dbusmenu_client_send_event        (DbusmenuClient * client,
                                                         gint id,
                                                         const gchar * name,

=== modified file 'libdbusmenu-gtk/Makefile.am'
--- libdbusmenu-gtk/Makefile.am	2011-01-23 18:45:05 +0000
+++ libdbusmenu-gtk/Makefile.am	2011-01-27 19:49:40 +0000
@@ -24,7 +24,8 @@
 	client.h \
 	menu.h \
 	menuitem.h \
-	parser.h
+	parser.h \
+	serializablemenuitem.h
 
 libdbusmenu_gtk_la_SOURCES = \
 	client.h \
@@ -36,7 +37,9 @@
 	menuitem.h \
 	menuitem.c \
 	parser.h \
-	parser.c
+	parser.c \
+	serializablemenuitem.h \
+	serializablemenuitem.c
 
 libdbusmenu_gtk_la_LDFLAGS = \
 	-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \

=== modified file 'libdbusmenu-gtk/client.c'
--- libdbusmenu-gtk/client.c	2011-01-27 04:42:30 +0000
+++ libdbusmenu-gtk/client.c	2011-01-27 19:49:40 +0000
@@ -55,8 +55,8 @@
 static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint new, guint old, DbusmenuGtkClient * gtkclient);
 static void item_activate (DbusmenuClient * client, DbusmenuMenuitem * mi, guint timestamp, gpointer userdata);
 
-static gboolean new_item_normal     (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
-static gboolean new_item_seperator  (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static gboolean new_item_normal     (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
+static gboolean new_item_seperator  (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
 
 static void process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value);
 static void process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value);
@@ -685,7 +685,7 @@
 /* The base type handler that builds a plain ol'
    GtkMenuItem to represent, well, the GtkMenuItem */
 static gboolean
-new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
 {
 	g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
 	g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
@@ -720,7 +720,7 @@
 /* Type handler for the seperators where it builds
    a GtkSeparator to act as the GtkMenuItem */
 static gboolean
-new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
 {
 	g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
 	g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);

=== modified file 'libdbusmenu-gtk/dbusmenu-gtk.h'
--- libdbusmenu-gtk/dbusmenu-gtk.h	2011-01-21 16:35:55 +0000
+++ libdbusmenu-gtk/dbusmenu-gtk.h	2011-01-21 17:59:06 +0000
@@ -36,5 +36,6 @@
 #include <libdbusmenu-gtk/client.h>
 #include <libdbusmenu-gtk/menu.h>
 #include <libdbusmenu-gtk/menuitem.h>
+#include <libdbusmenu-gtk/serializablemenuitem.h>
 
 #endif /* __DBUSMENU_GLIB_H__ */

=== modified file 'libdbusmenu-gtk/menuitem.h'
--- libdbusmenu-gtk/menuitem.h	2010-12-13 13:40:01 +0000
+++ libdbusmenu-gtk/menuitem.h	2011-01-21 22:48:41 +0000
@@ -26,8 +26,8 @@
 <http://www.gnu.org/licenses/>
 */
 
-#ifndef __DBUSMENU_GTKMENUITEM_H__
-#define __DBUSMENU_GTKMENUITEM_H__ 1
+#ifndef DBUSMENU_GTK_MENUITEM_H__
+#define DBUSMENU_GTK_MENUITEM_H__ 1
 
 #include <glib.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>

=== added file 'libdbusmenu-gtk/serializablemenuitem.c'
--- libdbusmenu-gtk/serializablemenuitem.c	1970-01-01 00:00:00 +0000
+++ libdbusmenu-gtk/serializablemenuitem.c	2011-01-27 15:28:44 +0000
@@ -0,0 +1,288 @@
+/*
+An object to act as a base class for easy GTK widgets that can be
+transfered over dbusmenu.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+This program is free software: you can redistribute it and/or modify it 
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the 
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by 
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but 
+WITHOUT ANY WARRANTY; without even the implied warranties of 
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
+PURPOSE.  See the applicable version of the GNU Lesser General Public 
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public 
+License version 3 and version 2.1 along with this program.  If not, see 
+<http://www.gnu.org/licenses/>
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "client.h"
+#include "serializablemenuitem.h"
+
+/**
+	DbusmenuGtkSerializableMenuItemPrivate:
+	@mi: Menuitem to watch the property changes from
+*/
+struct _DbusmenuGtkSerializableMenuItemPrivate {
+	DbusmenuMenuitem * mi;
+};
+
+/* Properties */
+enum {
+	PROP_0,
+	PROP_MENUITEM
+};
+
+/* Private macro, only used in object init */
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM, DbusmenuGtkSerializableMenuItemPrivate))
+
+/* Function prototypes */
+static void dbusmenu_gtk_serializable_menu_item_class_init (DbusmenuGtkSerializableMenuItemClass *klass);
+static void dbusmenu_gtk_serializable_menu_item_init       (DbusmenuGtkSerializableMenuItem *self);
+static void dbusmenu_gtk_serializable_menu_item_dispose    (GObject *object);
+static void dbusmenu_gtk_serializable_menu_item_finalize   (GObject *object);
+static void set_property                                   (GObject * obj,
+                                                            guint id,
+                                                            const GValue * value,
+                                                            GParamSpec * pspec);
+static void get_property                                   (GObject * obj,
+                                                            guint id,
+                                                            GValue * value,
+                                                            GParamSpec * pspec);
+
+/* GObject boiler plate */
+G_DEFINE_TYPE (DbusmenuGtkSerializableMenuItem, dbusmenu_gtk_serializable_menu_item, GTK_TYPE_MENU_ITEM);
+
+/* Initialize the stuff in the class structure */
+static void
+dbusmenu_gtk_serializable_menu_item_class_init (DbusmenuGtkSerializableMenuItemClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (DbusmenuGtkSerializableMenuItemPrivate));
+
+	object_class->dispose = dbusmenu_gtk_serializable_menu_item_dispose;
+	object_class->finalize = dbusmenu_gtk_serializable_menu_item_finalize;
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+
+	g_object_class_install_property (object_class, PROP_MENUITEM,
+	                                 g_param_spec_object(DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_PROP_MENUITEM, "DBusmenu Menuitem attached to item",
+	                                              "A menuitem who's properties are being watched and where changes should be watched for updates.  It is the responsibility of subclasses to set up the signal handlers for those property changes.",
+	                                              DBUSMENU_TYPE_MENUITEM,
+	                                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	return;
+}
+
+/* Initialize the object structures and private structure */
+static void
+dbusmenu_gtk_serializable_menu_item_init (DbusmenuGtkSerializableMenuItem *self)
+{
+	self->priv = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_GET_PRIVATE(self);
+
+	self->priv->mi = NULL;
+
+	return;
+}
+
+/* Free all references to objects */
+static void
+dbusmenu_gtk_serializable_menu_item_dispose (GObject *object)
+{
+	DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(object);
+	g_return_if_fail(smi != NULL);
+
+	if (smi->priv->mi != NULL) {
+		g_object_unref(G_OBJECT(smi->priv->mi));
+		smi->priv->mi = NULL;
+	}
+
+
+	G_OBJECT_CLASS (dbusmenu_gtk_serializable_menu_item_parent_class)->dispose (object);
+	return;
+}
+
+/* Free memory */
+static void
+dbusmenu_gtk_serializable_menu_item_finalize (GObject *object)
+{
+
+
+
+	G_OBJECT_CLASS (dbusmenu_gtk_serializable_menu_item_parent_class)->finalize (object);
+	return;
+}
+
+/* Set an object property */
+static void
+set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
+{
+	DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(obj);
+
+	switch (id) {
+	case PROP_MENUITEM:
+		smi->priv->mi = g_value_get_object(value);
+		break;
+	default:
+		g_return_if_reached();
+		break;
+	}
+
+	return;
+}
+
+/* Get an object property */
+static void
+get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
+{
+	DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(obj);
+
+	switch (id) {
+	case PROP_MENUITEM:
+		g_value_set_object(value, smi->priv->mi);
+		break;
+	default:
+		g_return_if_reached();
+		break;
+	}
+
+	return;
+}
+
+/**
+	dbusmenu_gtk_serializable_menu_item_build_menuitem:
+	@smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring
+
+	This function is for menu items that are instanciated from
+	GTK and have their properites set using GTK functions.  This
+	builds a #DbusmenuMenuitem that then has the properties that
+	should be sent over the bus to create a new item of this
+	type on the other side.
+
+	Return value: (transfer full) A #DbusmenuMenuitem who's values will be
+		set by this object.
+*/
+DbusmenuMenuitem *
+dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi)
+{
+	g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL);
+
+	DbusmenuGtkSerializableMenuItemClass * klass = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_GET_CLASS(smi);
+	if (klass->build_dbusmenu_menuitem != NULL) {
+		return klass->build_dbusmenu_menuitem(smi);
+	}
+
+	return NULL;
+}
+
+/* Callback to the generic type handler */
+typedef struct _type_handler_t type_handler_t;
+struct _type_handler_t {
+	DbusmenuGtkSerializableMenuItemClass * class;
+	GType type;
+};
+
+/* Handle the type with this item. */
+static gboolean
+type_handler (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
+{
+	type_handler_t * th = (type_handler_t *)user_data;
+
+	DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL));
+	g_return_val_if_fail(smi != NULL, FALSE);
+
+	dbusmenu_gtk_serializable_menu_item_set_menuitem(smi, newitem);
+	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent);
+
+	return TRUE;
+}
+
+/* Destruction is inevitable */
+static void
+type_destroy_handler (DbusmenuClient * client, const gchar * type, gpointer user_data)
+{
+	g_return_if_fail(user_data != NULL);
+	type_handler_t * th = (type_handler_t *)user_data;
+	g_type_class_unref(th->class);
+	g_free(user_data);
+	return;
+}
+
+/**
+	dbusmenu_gtk_serializable_menu_item_register_to_client:
+	@client: #DbusmenuClient that we should register a type at.
+	@item_type: The #GType of a class that is a subclass of #DbusmenuGtkSerializableMenuItem
+
+	Registers a generic handler for dealing with all subclasses of
+	#DbusmenuGtkSerializableMenuItem.  This handler responds to the callback,
+	creates a new object and attaches it to the appropriate #DbusmenuMenuitem
+	object.
+*/
+void
+dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type)
+{
+	g_return_if_fail(g_type_is_a(item_type, DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM));
+
+	gpointer type_class = g_type_class_ref(item_type);
+	g_return_if_fail(type_class != NULL);
+
+	DbusmenuGtkSerializableMenuItemClass * class = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_CLASS(type_class);
+
+	if (class->get_type_string == NULL) {
+		g_type_class_unref(type_class);
+		g_error("No 'get_type_string' in subclass of DbusmenuGtkSerializableMenuItem");
+		return;
+	}
+
+	/* Register type */
+	type_handler_t * th = g_new0(type_handler_t, 1);
+	th->class = class;
+	th->type = item_type;
+	if (!dbusmenu_client_add_type_handler_full(client, class->get_type_string(), type_handler, th, type_destroy_handler)) {
+		type_destroy_handler(client, class->get_type_string(), th);
+	}
+
+	/* Register defaults */
+	/* TODO: Need API on another branch */
+
+	return;
+}
+
+/**
+	dbusmenu_gtk_serializable_menu_item_set_menuitem:
+	@smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of
+	@mi: Menuitem to get the properties from
+
+	This function is used on the server side to signal to the object
+	that it should get its' property change events from @mi instead
+	of expecting calls to its' API.  A call to this function sets the
+	property and subclasses should listen to the notify signal to
+	pick up this property being set.
+*/
+void
+dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi)
+{
+	g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi));
+	g_return_if_fail(mi != NULL);
+
+	smi->priv->mi = mi;
+	g_object_notify(G_OBJECT(smi), DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_PROP_MENUITEM);
+
+	return;
+}

=== added file 'libdbusmenu-gtk/serializablemenuitem.h'
--- libdbusmenu-gtk/serializablemenuitem.h	1970-01-01 00:00:00 +0000
+++ libdbusmenu-gtk/serializablemenuitem.h	2011-01-27 15:40:30 +0000
@@ -0,0 +1,115 @@
+/*
+An object to act as a base class for easy GTK widgets that can be
+transfered over dbusmenu.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+This program is free software: you can redistribute it and/or modify it 
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the 
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by 
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but 
+WITHOUT ANY WARRANTY; without even the implied warranties of 
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
+PURPOSE.  See the applicable version of the GNU Lesser General Public 
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public 
+License version 3 and version 2.1 along with this program.  If not, see 
+<http://www.gnu.org/licenses/>
+*/
+
+#ifndef DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_H__
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_H__ 1
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <libdbusmenu-glib/menuitem.h>
+#include <libdbusmenu-glib/client.h>
+
+G_BEGIN_DECLS
+
+#define DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM            (dbusmenu_gtk_serializable_menu_item_get_type ())
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM, DbusmenuGtkSerializableMenuItem))
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM, DbusmenuGtkSerializableMenuItemClass))
+#define DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM))
+#define DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM))
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM, DbusmenuGtkSerializableMenuItemClass))
+
+#define DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_PROP_MENUITEM   "dbusmenu-menuitem"
+
+typedef struct _DbusmenuGtkSerializableMenuItem        DbusmenuGtkSerializableMenuItem;
+typedef struct _DbusmenuGtkSerializableMenuItemClass   DbusmenuGtkSerializableMenuItemClass;
+typedef struct _DbusmenuGtkSerializableMenuItemPrivate DbusmenuGtkSerializableMenuItemPrivate;
+
+/**
+	DbusmenuGtkSerializableMenuItemClass:
+	@parent_class: Inherit from GtkMenuItem
+	@get_type_string: Static function to get a string describing this type
+	@get_default_properties: Return a hashtable of defaults for the menu item type
+	@build_dbusmenu_menuitem: Build a menuitem that can be sent over dbus
+	@_dbusmenu_gtk_serializable_menu_item_reserved1: Reserved for future use.
+	@_dbusmenu_gtk_serializable_menu_item_reserved2: Reserved for future use.
+	@_dbusmenu_gtk_serializable_menu_item_reserved3: Reserved for future use.
+	@_dbusmenu_gtk_serializable_menu_item_reserved4: Reserved for future use.
+	@_dbusmenu_gtk_serializable_menu_item_reserved5: Reserved for future use.
+	@_dbusmenu_gtk_serializable_menu_item_reserved6: Reserved for future use.
+*/
+struct _DbusmenuGtkSerializableMenuItemClass {
+	GtkMenuItemClass parent_class;
+
+	/* Subclassable functions */
+	const gchar *        (*get_type_string)          (void);
+	GHashTable *         (*get_default_properties)   (void);
+
+	DbusmenuMenuitem *   (*build_dbusmenu_menuitem)    (DbusmenuGtkSerializableMenuItem * smi);
+
+	/* Signals */
+
+
+
+	/* Empty Space */
+	/*< Private >*/
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved1) (void);
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved2) (void);
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved3) (void);
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved4) (void);
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved5) (void);
+	void (*_dbusmenu_gtk_serializable_menu_item_reserved6) (void);
+};
+
+/**
+	DbusmenuGtkSerializableMenuItem:
+	@parent: Inherit from GtkMenuItem
+	@priv: Blind structure of private variables
+
+	The Serializable Menuitem provides a way for menu items to be created
+	that can easily be picked up by the Dbusmenu GTK Parser.  This way
+	you can create custom items, and transport them across dbusmenu to
+	your menus or the appmenu on the other side of the bus.  By providing
+	these function the parser has enough information to both serialize, and
+	deserialize on the other side, the menuitem you've so carefully created.
+*/
+struct _DbusmenuGtkSerializableMenuItem {
+	GtkMenuItem parent;
+
+	DbusmenuGtkSerializableMenuItemPrivate * priv;
+};
+
+GType dbusmenu_gtk_serializable_menu_item_get_type (void);
+
+DbusmenuMenuitem *  dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi);
+void                dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type);
+void                dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi);
+
+G_END_DECLS
+
+#endif