aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore3
-rw-r--r--docs/libdbusmenu-gtk/reference/Makefile.am2
-rw-r--r--docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml2
-rw-r--r--libdbusmenu-glib/client.c78
-rw-r--r--libdbusmenu-glib/client.h8
-rw-r--r--libdbusmenu-gtk/Makefile.am7
-rw-r--r--libdbusmenu-gtk/client.c8
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk.h1
-rw-r--r--libdbusmenu-gtk/menuitem.h4
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.c288
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.h108
11 files changed, 490 insertions, 19 deletions
diff --git a/.bzrignore b/.bzrignore
index df33247..39be2d5 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -220,6 +220,9 @@ libdbusmenu-gtk/DbusmenuGtk-0.4.typelib
libdbusmenu-gtk/DbusmenuGtk-0.4.vapi
libdbusmenu-gtk/dbusmenu-gtk-0.4.pc
libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc
+libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo
+docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html
+docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml
libdbusmenu-gtk/libdbusmenu_gtk_la-parser.lo
test-gtk-parser
test-gtk-parser-test
diff --git a/docs/libdbusmenu-gtk/reference/Makefile.am b/docs/libdbusmenu-gtk/reference/Makefile.am
index 6e44a23..191d68e 100644
--- a/docs/libdbusmenu-gtk/reference/Makefile.am
+++ b/docs/libdbusmenu-gtk/reference/Makefile.am
@@ -54,7 +54,7 @@ CFILE_GLOB=$(top_srcdir)/libdbusmenu-gtk/*.c
# 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
diff --git a/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml b/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
index ae9ab07..ec6b82f 100644
--- a/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
+++ b/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
@@ -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">
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index 29ed4a0..a25ad79 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -120,6 +120,15 @@ struct _event_data_t {
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 item_activated (GDBusProxy * proxy, gint id, guint timestamp, Dbusme
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 @@ dbusmenu_client_init (DbusmenuClient *self)
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 @@ menuitem_get_properties_new_cb (GVariant * properties, GError * error, gpointer
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
@@ -1441,7 +1451,7 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
/* We've got everything built up at this node and reconcilled */
/* Flush the properties requests if this is the first level */
- if (dbusmenu_menuitem_get_id(parent) == 0) {
+ if (parent != NULL && dbusmenu_menuitem_get_id(parent) == 0) {
get_properties_flush(client);
}
@@ -1676,6 +1686,19 @@ dbusmenu_client_get_root (DbusmenuClient * client)
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
@@ -1700,6 +1723,37 @@ dbusmenu_client_get_root (DbusmenuClient * client)
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);
@@ -1720,6 +1774,14 @@ dbusmenu_client_add_type_handler (DbusmenuClient * client, const gchar * type, D
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;
}
+
diff --git a/libdbusmenu-glib/client.h b/libdbusmenu-glib/client.h
index 1ae89fa..f371792 100644
--- a/libdbusmenu-glib/client.h
+++ b/libdbusmenu-glib/client.h
@@ -110,7 +110,8 @@ struct _DbusmenuClient {
DbusmenuClientPrivate * priv;
};
-typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer 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 +120,11 @@ DbusmenuMenuitem * dbusmenu_client_get_root (DbusmenuClient * client)
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,
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index 201a631..f3556e9 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -24,7 +24,8 @@ libdbusmenu_gtkinclude_HEADERS = \
client.h \
menu.h \
menuitem.h \
- parser.h
+ parser.h \
+ serializablemenuitem.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
@@ -36,7 +37,9 @@ libdbusmenu_gtk_la_SOURCES = \
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) \
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 18a2cdd..d957f25 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -54,8 +54,8 @@ static void delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, Dbusm
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);
@@ -684,7 +684,7 @@ dbusmenu_gtkclient_menuitem_get_submenu (DbusmenuGtkClient * client, DbusmenuMen
/* 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);
@@ -719,7 +719,7 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
/* 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);
diff --git a/libdbusmenu-gtk/dbusmenu-gtk.h b/libdbusmenu-gtk/dbusmenu-gtk.h
index de63c61..f2fe5be 100644
--- a/libdbusmenu-gtk/dbusmenu-gtk.h
+++ b/libdbusmenu-gtk/dbusmenu-gtk.h
@@ -36,5 +36,6 @@ License version 3 and version 2.1 along with this program. If not, see
#include <libdbusmenu-gtk/client.h>
#include <libdbusmenu-gtk/menu.h>
#include <libdbusmenu-gtk/menuitem.h>
+#include <libdbusmenu-gtk/serializablemenuitem.h>
#endif /* __DBUSMENU_GLIB_H__ */
diff --git a/libdbusmenu-gtk/menuitem.h b/libdbusmenu-gtk/menuitem.h
index a2b6652..4fc42f9 100644
--- a/libdbusmenu-gtk/menuitem.h
+++ b/libdbusmenu-gtk/menuitem.h
@@ -26,8 +26,8 @@ License version 3 and version 2.1 along with this program. If not, see
<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>
diff --git a/libdbusmenu-gtk/serializablemenuitem.c b/libdbusmenu-gtk/serializablemenuitem.c
new file mode 100644
index 0000000..f67434e
--- /dev/null
+++ b/libdbusmenu-gtk/serializablemenuitem.c
@@ -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@canonical.com>
+
+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_dbusmenu_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_dbusmenu_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_dbusmenu_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_dbusmenu_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_dbusmenu_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;
+}
diff --git a/libdbusmenu-gtk/serializablemenuitem.h b/libdbusmenu-gtk/serializablemenuitem.h
new file mode 100644
index 0000000..1ca3ef8
--- /dev/null
+++ b/libdbusmenu-gtk/serializablemenuitem.h
@@ -0,0 +1,108 @@
+/*
+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@canonical.com>
+
+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
+*/
+struct _DbusmenuGtkSerializableMenuItem {
+ GtkMenuItem parent;
+
+ DbusmenuGtkSerializableMenuItemPrivate * priv;
+};
+
+GType dbusmenu_gtk_serializable_menu_item_get_type (void);
+
+DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi);
+void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type);
+void dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi);
+
+G_END_DECLS
+
+#endif