aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r--libdbusmenu-gtk/Makefile.am35
-rw-r--r--libdbusmenu-gtk/client.c237
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk.h1
-rw-r--r--libdbusmenu-gtk/genericmenuitem-enum-types.c.in116
-rw-r--r--libdbusmenu-gtk/genericmenuitem-enum-types.h.in65
-rw-r--r--libdbusmenu-gtk/genericmenuitem.c119
-rw-r--r--libdbusmenu-gtk/genericmenuitem.h71
-rw-r--r--libdbusmenu-gtk/menu.c14
-rw-r--r--libdbusmenu-gtk/menuitem.c21
-rw-r--r--libdbusmenu-gtk/parser.c290
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.c288
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.h133
12 files changed, 818 insertions, 572 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index 50a8f2c..b4564d1 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -1,6 +1,4 @@
-CLEANFILES =
-
if USE_GTK3
VER=3
GTKGIR=Gtk-3.0
@@ -13,10 +11,28 @@ GTKVALA=gtk+-2.0
lib_LTLIBRARIES = libdbusmenu-gtk.la
endif
+BUILT_SOURCES =
+CLEANFILES =
+DISTCLEANFILES =
EXTRA_DIST = \
dbusmenu-gtk-0.4.pc.in \
dbusmenu-gtk3-0.4.pc.in
+##############
+# Enum Stuff
+##############
+
+include $(top_srcdir)/Makefile.am.enum
+
+glib_enum_h = genericmenuitem-enum-types.h
+glib_enum_c = genericmenuitem-enum-types.c
+glib_enum_headers = $(srcdir)/genericmenuitem.h
+
+
+#####################
+# Include Directory
+#####################
+
libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.4/libdbusmenu-gtk$(VER)/
libdbusmenu_gtkinclude_HEADERS = \
@@ -24,22 +40,21 @@ libdbusmenu_gtkinclude_HEADERS = \
client.h \
menu.h \
menuitem.h \
- parser.h \
- serializablemenuitem.h
+ parser.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
client.c \
genericmenuitem.h \
genericmenuitem.c \
+ genericmenuitem-enum-types.h \
+ genericmenuitem-enum-types.c \
menu.h \
menu.c \
menuitem.h \
menuitem.c \
parser.h \
- parser.c \
- serializablemenuitem.h \
- serializablemenuitem.c
+ parser.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
@@ -92,7 +107,7 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(builddir) --includedir=$(top_buildd
if HAVE_INTROSPECTION
-introspection_sources = $(filter-out genericmenuitem.%, $(libdbusmenu_gtkinclude_HEADERS) $(libdbusmenu_gtk_la_SOURCES))
+introspection_sources = $(filter-out genericmenuitem%, $(libdbusmenu_gtkinclude_HEADERS) $(libdbusmenu_gtk_la_SOURCES))
DbusmenuGtk$(VER)-0.4.gir: libdbusmenu-gtk$(VER).la
DbusmenuGtk_0_4_gir_INCLUDES = \
@@ -103,7 +118,6 @@ DbusmenuGtk_0_4_gir_CFLAGS = $(DBUSMENUGTK_CFLAGS) -I$(top_srcdir)
DbusmenuGtk_0_4_gir_LIBS = libdbusmenu-gtk$(VER).la
DbusmenuGtk_0_4_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
DbusmenuGtk_0_4_gir_NAMESPACE = DbusmenuGtk$(VER)
-DbusmenuGtk_0_4_gir_SCANNERFLAGS = $(INTROSPECTION_SCANNER_ARGS)
DbusmenuGtk_0_4_gir_EXPORT_PACKAGES = dbusmenu-gtk$(VER)-0.4
# We duplicate these for the same reason as libdbusmenu_gtk3includedir above
@@ -112,7 +126,6 @@ DbusmenuGtk3_0_4_gir_CFLAGS = $(DbusmenuGtk_0_4_gir_CFLAGS)
DbusmenuGtk3_0_4_gir_LIBS = $(DbusmenuGtk_0_4_gir_LIBS)
DbusmenuGtk3_0_4_gir_FILES = $(DbusmenuGtk_0_4_gir_FILES)
DbusmenuGtk3_0_4_gir_NAMESPACE = $(DbusmenuGtk_0_4_gir_NAMESPACE)
-DbusmenuGtk3_0_4_gir_SCANNERFLAGS = $(DbusmenuGtk_0_4_gir_SCANNERFLAGS)
DbusmenuGtk3_0_4_gir_EXPORT_PACKAGES = $(DbusmenuGtk_0_4_gir_EXPORT_PACKAGES)
INTROSPECTION_GIRS += DbusmenuGtk$(VER)-0.4.gir
@@ -131,6 +144,7 @@ endif
# VAPI Files
#########################
+if HAVE_VALA
if HAVE_INTROSPECTION
vapidir = $(datadir)/vala/vapi
@@ -154,4 +168,5 @@ DbusmenuGtk$(VER)-0.4.tmp.gir: DbusmenuGtk$(VER)-0.4.gir
CLEANFILES += $(vapi_DATA) DbusmenuGtk$(VER)-0.4.tmp.gir
endif
+endif
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 497808b..1051f20 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -31,10 +31,12 @@ License version 3 and version 2.1 along with this program. If not, see
#endif
#include <gtk/gtk.h>
+#include <glib.h>
#include "client.h"
#include "menuitem.h"
#include "genericmenuitem.h"
+#include "genericmenuitem-enum-types.h"
/* Private */
struct _DbusmenuGtkClientPrivate {
@@ -59,6 +61,7 @@ static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint n
static void item_activate (DbusmenuClient * client, DbusmenuMenuitem * mi, guint timestamp, gpointer userdata);
static void theme_dir_changed (DbusmenuClient * client, GStrv theme_dirs, gpointer userdata);
static void remove_theme_dirs (GtkIconTheme * theme, GStrv dirs);
+static void event_result (DbusmenuClient * client, DbusmenuMenuitem * mi, const gchar * event, GVariant * variant, guint timestamp, GError * error);
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);
@@ -119,6 +122,7 @@ dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL);
g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_ITEM_ACTIVATE, G_CALLBACK(item_activate), NULL);
g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_ICON_THEME_DIRS_CHANGED, G_CALLBACK(theme_dir_changed), NULL);
+ g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_EVENT_RESULT, G_CALLBACK(event_result), NULL);
theme_dir_changed(DBUSMENU_CLIENT(self), dbusmenu_client_get_icon_paths(DBUSMENU_CLIENT(self)), NULL);
@@ -448,8 +452,97 @@ dbusmenu_gtkclient_get_accel_group (DbusmenuGtkClient * client)
/* Internal Functions */
-static const gchar * data_menuitem = "dbusmenugtk-data-gtkmenuitem";
-static const gchar * data_menu = "dbusmenugtk-data-gtkmenu";
+static const gchar * data_menuitem = "dbusmenugtk-data-gtkmenuitem";
+static const gchar * data_menu = "dbusmenugtk-data-gtkmenu";
+static const gchar * data_activating = "dbusmenugtk-data-activating";
+static const gchar * data_idle_close_id = "dbusmenugtk-data-idle-close-id";
+static const gchar * data_delayed_close = "dbusmenugtk-data-delayed-close";
+
+static void
+menu_item_start_activating(DbusmenuMenuitem * mi)
+{
+ /* Mark this item and all it's parents as activating */
+ DbusmenuMenuitem * parent = mi;
+ do {
+ g_object_set_data(G_OBJECT(parent), data_activating,
+ GINT_TO_POINTER(TRUE));
+ } while ((parent = dbusmenu_menuitem_get_parent (parent)) != NULL);
+
+ GVariant * variant = g_variant_new("i", 0);
+ dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_ACTIVATED, variant, gtk_get_current_event_time());
+}
+
+static gboolean
+menu_item_is_activating(DbusmenuMenuitem * mi)
+{
+ return GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi), data_activating));
+}
+
+static void
+menu_item_stop_activating(DbusmenuMenuitem * mi)
+{
+ if (!menu_item_is_activating(mi))
+ return;
+
+ /* Mark this item and all it's parents as not activating and finally
+ send their queued close event. */
+ g_object_set_data(G_OBJECT(mi), data_activating, GINT_TO_POINTER(FALSE));
+
+ /* There is one master root parent that we don't care about, so stop
+ right before it */
+ DbusmenuMenuitem * parent = dbusmenu_menuitem_get_parent (mi);
+ while (dbusmenu_menuitem_get_parent (parent) != NULL &&
+ menu_item_is_activating(parent)) {
+ /* Now clean up the activating flag */
+ g_object_set_data(G_OBJECT(parent), data_activating,
+ GINT_TO_POINTER(FALSE));
+
+ gboolean should_close = FALSE;
+
+ /* Note that dbus might be fast enough to have already
+ processed the app's reply before close_in_idle() is called.
+ So to avoid that, we shut down any pending close_in_idle call */
+ guint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent),
+ data_idle_close_id));
+ if (id > 0) {
+ g_source_remove(id);
+ g_object_set_data(G_OBJECT(parent), data_idle_close_id,
+ GINT_TO_POINTER(0));
+ should_close = TRUE;
+ }
+
+ gboolean delayed = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi),
+ data_delayed_close));
+ if (delayed) {
+ g_object_set_data(G_OBJECT(mi), data_delayed_close,
+ GINT_TO_POINTER(FALSE));
+ should_close = TRUE;
+ }
+
+ /* And finally send a delayed closed event if one would have
+ happened */
+ if (should_close) {
+ dbusmenu_menuitem_handle_event(parent,
+ DBUSMENU_MENUITEM_EVENT_CLOSED,
+ NULL,
+ gtk_get_current_event_time());
+ }
+
+ parent = dbusmenu_menuitem_get_parent (parent);
+ }
+}
+
+static void
+event_result (DbusmenuClient * client, DbusmenuMenuitem * mi,
+ const gchar * event, GVariant * variant, guint timestamp,
+ GError * error)
+{
+ if (g_strcmp0(event, DBUSMENU_MENUITEM_EVENT_ACTIVATED) == 0) {
+ menu_item_stop_activating(mi);
+ }
+
+ return;
+}
/* This is the call back for the GTK widget for when it gets
clicked on by the user to send it back across the bus. */
@@ -457,8 +550,7 @@ static gboolean
menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
{
if (gtk_menu_item_get_submenu(gmi) == NULL) {
- GVariant * variant = g_variant_new("i", 0);
- dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_ACTIVATED, variant, gtk_get_current_event_time());
+ menu_item_start_activating(mi);
} else {
/* TODO: We need to stop the display of the submenu
until this callback returns. */
@@ -467,13 +559,42 @@ menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
return TRUE;
}
+static gboolean
+close_in_idle (DbusmenuMenuitem * mi)
+{
+ /* Don't send closed signal if we also sent activating signal.
+ We'd just be asking for race conditions. We'll send closed
+ when done with activation. */
+ if (!menu_item_is_activating(mi))
+ dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_CLOSED, NULL, gtk_get_current_event_time());
+ else
+ g_object_set_data(G_OBJECT(mi), data_delayed_close, GINT_TO_POINTER(TRUE));
+
+ g_object_set_data(G_OBJECT(mi), data_idle_close_id, GINT_TO_POINTER(0));
+ return FALSE;
+}
+
static void
submenu_notify_visible_cb (GtkWidget * menu, GParamSpec * pspec, DbusmenuMenuitem * mi)
{
- if (gtk_widget_get_visible (menu))
- dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_OPENED, NULL, gtk_get_current_event_time());
- else
- dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_CLOSED, NULL, gtk_get_current_event_time());
+ if (gtk_widget_get_visible (menu)) {
+ menu_item_stop_activating(mi); /* just in case */
+ dbusmenu_menuitem_handle_event(mi, DBUSMENU_MENUITEM_EVENT_OPENED, NULL, gtk_get_current_event_time());
+ } else {
+ /* Try to close in the idle loop because we actually get a menu
+ close notification before we get notified that a menu item
+ was clicked. We want to give that clicked signal some
+ time, so we wait until all queued signals are handled before
+ continuing. (our handling of the closed signal depends on
+ whether the user clicked an item or not) */
+ guint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi),
+ data_idle_close_id));
+ if (id == 0) {
+ id = g_idle_add((GSourceFunc)close_in_idle, mi);
+ g_object_set_data(G_OBJECT(mi), data_idle_close_id,
+ GINT_TO_POINTER(id));
+ }
+ }
}
/* Process the visible property */
@@ -551,11 +672,58 @@ process_toggle_state (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * varia
return;
}
+/* Submenu processing */
+static void
+process_submenu (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * variant, DbusmenuGtkClient * gtkclient)
+{
+ const gchar * submenu = NULL;
+ if (variant != NULL) {
+ submenu = g_variant_get_string(variant, NULL);
+ }
+
+ if (g_strcmp0(submenu, DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU) != 0) {
+ /* This is the only case we're really supporting right now,
+ so if it's not this, we want to clean up. */
+ /* We're just going to warn for now. */
+ gpointer pmenu = g_object_get_data(G_OBJECT(mi), data_menu);
+ if (pmenu != NULL) {
+ g_warning("The child-display variable is set to '%s' but there's a menu, odd?", submenu);
+ }
+ } else {
+ /* We need to build a menu for these guys to live in. */
+ GtkMenu * menu = GTK_MENU(gtk_menu_new());
+ g_object_ref_sink(menu);
+ g_object_set_data_full(G_OBJECT(mi), data_menu, menu, g_object_unref);
+
+ gtk_menu_item_set_submenu(gmi, GTK_WIDGET(menu));
+
+ g_signal_connect(menu, "notify::visible", G_CALLBACK(submenu_notify_visible_cb), mi);
+ }
+
+ return;
+}
+
+/* Process the disposition changing */
+static void
+process_disposition (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * variant, DbusmenuGtkClient * gtkclient)
+{
+ /* We can only handle generic menu items here. Perhaps someone else
+ will find the value useful. Not us. */
+ if (!IS_GENERICMENUITEM(gmi)) {
+ return;
+ }
+
+ genericmenuitem_set_disposition(GENERICMENUITEM(gmi), genericmenuitem_disposition_get_value_from_nick(g_variant_get_string(variant, NULL)));
+ return;
+}
+
/* Whenever we have a property change on a DbusmenuMenuitem
we need to be responsive to that. */
static void
-menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * variant, GtkMenuItem * gmi)
+menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * variant, DbusmenuGtkClient * gtkclient)
{
+ GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(gtkclient, mi);
+
if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_LABEL)) {
gtk_menu_item_set_label(gmi, variant == NULL ? NULL : g_variant_get_string(variant, NULL));
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
@@ -566,6 +734,10 @@ menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * variant, Gt
process_toggle_type(mi, gmi, variant);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE)) {
process_toggle_state(mi, gmi, variant);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY)) {
+ process_submenu(mi, gmi, variant, gtkclient);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_DISPOSITION)) {
+ process_disposition(mi, gmi, variant, gtkclient);
}
return;
@@ -582,19 +754,6 @@ menu_shortcut_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value,
return;
}
-/* Call back that happens when the DbusmenuMenuitem
- is destroyed. We're making sure to clean up everything
- else down the pipe. */
-static void
-destoryed_dbusmenuitem_cb (gpointer udata, GObject * dbusmenuitem)
-{
- #ifdef MASSIVEDEBUGGING
- g_debug("DbusmenuMenuitem was destroyed");
- #endif
- gtk_widget_destroy(GTK_WIDGET(udata));
- return;
-}
-
/* The new menuitem signal only happens if we don't have a type handler
for the type of the item. This should be an error condition and we're
printing out a message. */
@@ -697,14 +856,11 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
#endif
/* Attach these two */
- g_object_set_data(G_OBJECT(item), data_menuitem, gmi);
- g_object_ref(G_OBJECT(gmi));
- #ifdef MASSIVEDEBUGGING
- g_signal_connect(G_OBJECT(gmi), "destroy", G_CALLBACK(destroy_gmi), item);
- #endif
+ g_object_ref_sink(G_OBJECT(gmi));
+ g_object_set_data_full(G_OBJECT(item), data_menuitem, gmi, (GDestroyNotify)gtk_widget_destroy);
/* DbusmenuMenuitem signals */
- g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), gmi);
+ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), client);
g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_shortcut_change_cb), client);
g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(delete_child), client);
g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(move_child), client);
@@ -712,14 +868,13 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
/* GtkMenuitem signals */
g_signal_connect(G_OBJECT(gmi), "activate", G_CALLBACK(menu_pressed_cb), item);
- /* Life insurance */
- g_object_weak_ref(G_OBJECT(item), destoryed_dbusmenuitem_cb, gmi);
-
/* Check our set of props to see if any are set already */
process_visible(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
process_sensitive(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_ENABLED));
process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE));
process_toggle_state(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE));
+ process_submenu(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY), client);
+ process_disposition(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_DISPOSITION), client);
refresh_shortcut(client, item);
/* Oh, we're a child, let's deal with that */
@@ -741,17 +896,12 @@ new_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position, Dbus
if (g_strcmp0(dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_TYPE), DBUSMENU_CLIENT_TYPES_SEPARATOR) == 0) { return; }
gpointer ann_menu = g_object_get_data(G_OBJECT(mi), data_menu);
- GtkMenu * menu = GTK_MENU(ann_menu);
- if (menu == NULL) {
- /* Oh, we don't have a submenu, build one! */
- menu = GTK_MENU(gtk_menu_new());
- g_object_set_data(G_OBJECT(mi), data_menu, menu);
-
- GtkMenuItem * parent = dbusmenu_gtkclient_menuitem_get(gtkclient, mi);
- gtk_menu_item_set_submenu(parent, GTK_WIDGET(menu));
+ if (ann_menu == NULL) {
+ g_warning("Children but no menu, someone's been naughty with their '" DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY "' property: '%s'", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY));
+ return;
+ }
- g_signal_connect(menu, "notify::visible", G_CALLBACK(submenu_notify_visible_cb), mi);
- }
+ GtkMenu * menu = GTK_MENU(ann_menu);
GtkMenuItem * childmi = dbusmenu_gtkclient_menuitem_get(gtkclient, child);
gtk_menu_shell_insert(GTK_MENU_SHELL(menu), GTK_WIDGET(childmi), position);
@@ -771,7 +921,7 @@ delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, DbusmenuGtkClient
if (menu != NULL) {
gtk_widget_destroy(GTK_WIDGET(menu));
- g_object_set_data(G_OBJECT(mi), data_menu, NULL);
+ g_object_steal_data(G_OBJECT(mi), data_menu);
}
}
@@ -875,11 +1025,10 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
GtkMenuItem * gmi;
gmi = GTK_MENU_ITEM(g_object_new(GENERICMENUITEM_TYPE, NULL));
- gtk_menu_item_set_label(gmi, dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL));
if (gmi != NULL) {
+ gtk_menu_item_set_label(gmi, dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL));
dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
- g_object_unref(gmi);
} else {
return FALSE;
}
diff --git a/libdbusmenu-gtk/dbusmenu-gtk.h b/libdbusmenu-gtk/dbusmenu-gtk.h
index f2fe5be..de63c61 100644
--- a/libdbusmenu-gtk/dbusmenu-gtk.h
+++ b/libdbusmenu-gtk/dbusmenu-gtk.h
@@ -36,6 +36,5 @@ 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/genericmenuitem-enum-types.c.in b/libdbusmenu-gtk/genericmenuitem-enum-types.c.in
new file mode 100644
index 0000000..8b2c046
--- /dev/null
+++ b/libdbusmenu-gtk/genericmenuitem-enum-types.c.in
@@ -0,0 +1,116 @@
+/*** BEGIN file-header ***/
+/*
+Enums from the dbusmenu headers
+
+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/>
+*/
+
+#include "genericmenuitem-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+#include "@basename@"
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+/**
+ @enum_name@_get_type:
+
+ Builds a GLib type for the #@EnumName@ enumeration.
+
+ Return value: A unique #GType for the #@EnumName@ enum.
+*/
+GType
+@enum_name@_get_type (void)
+{
+ static GType etype = 0;
+ if (G_UNLIKELY(etype == 0)) {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL}
+ };
+
+ etype = g_@type@_register_static (g_intern_static_string("@EnumName@"), values);
+ }
+
+ return etype;
+}
+
+/**
+ @enum_name@_get_nick:
+ @value: The value of @EnumName@ to get the nick of
+
+ Looks up in the enum table for the nick of @value.
+
+ Return value: The nick for the given value or #NULL on error
+*/
+const gchar *
+@enum_name@_get_nick (@EnumName@ value)
+{
+ GEnumClass * class = G_ENUM_CLASS(g_type_class_ref(@enum_name@_get_type()));
+ g_return_val_if_fail(class != NULL, NULL);
+
+ const gchar * ret = NULL;
+ GEnumValue * val = g_enum_get_value(class, value);
+ if (val != NULL) {
+ ret = val->value_nick;
+ }
+
+ g_type_class_unref(class);
+ return ret;
+}
+
+/**
+ @enum_name@_get_value_from_nick:
+ @nick: The enum nick to lookup
+
+ Looks up in the enum table for the value of @nick.
+
+ Return value: The value for the given @nick
+*/
+@EnumName@
+@enum_name@_get_value_from_nick (const gchar * nick)
+{
+ GEnumClass * class = G_ENUM_CLASS(g_type_class_ref(@enum_name@_get_type()));
+ g_return_val_if_fail(class != NULL, 0);
+
+ @EnumName@ ret = 0;
+ GEnumValue * val = g_enum_get_value_by_nick(class, nick);
+ if (val != NULL) {
+ ret = val->value;
+ }
+
+ g_type_class_unref(class);
+ return ret;
+}
+
+
+/*** END value-tail ***/
diff --git a/libdbusmenu-gtk/genericmenuitem-enum-types.h.in b/libdbusmenu-gtk/genericmenuitem-enum-types.h.in
new file mode 100644
index 0000000..5758438
--- /dev/null
+++ b/libdbusmenu-gtk/genericmenuitem-enum-types.h.in
@@ -0,0 +1,65 @@
+/*** BEGIN file-header ***/
+/*
+Enums from the dbusmenu headers
+
+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_ENUM_TYPES_H__
+#define __DBUSMENU_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-tail ***/
+
+G_END_DECLS
+
+#endif /* __DBUSMENU_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from file: "@filename@" */
+#include "@basename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+const gchar * @enum_name@_get_nick (@EnumName@ value) G_GNUC_CONST;
+@EnumName@ @enum_name@_get_value_from_nick (const gchar * nick) G_GNUC_CONST;
+
+/**
+ DBUSMENU_TYPE_@ENUMSHORT@:
+
+ Gets the #GType value for the type associated with the
+ #@EnumName@ enumerated type.
+*/
+#define DBUSMENU_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+
+/*** END value-header ***/
diff --git a/libdbusmenu-gtk/genericmenuitem.c b/libdbusmenu-gtk/genericmenuitem.c
index 3652ceb..5488f93 100644
--- a/libdbusmenu-gtk/genericmenuitem.c
+++ b/libdbusmenu-gtk/genericmenuitem.c
@@ -30,6 +30,8 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
+#include <gdk/gdk.h>
+
#include "genericmenuitem.h"
/*
@@ -40,6 +42,7 @@ License version 3 and version 2.1 along with this program. If not, see
struct _GenericmenuitemPrivate {
GenericmenuitemCheckType check_type;
GenericmenuitemState state;
+ GenericmenuitemDisposition disposition;
};
/* Private macro */
@@ -102,6 +105,7 @@ genericmenuitem_init (Genericmenuitem *self)
self->priv->check_type = GENERICMENUITEM_CHECK_TYPE_NONE;
self->priv->state = GENERICMENUITEM_STATE_UNCHECKED;
+ self->priv->disposition = GENERICMENUITEM_DISPOSITION_NORMAL;
return;
}
@@ -165,18 +169,61 @@ set_label_helper (GtkWidget * widget, gpointer data)
style. It should be considered for caching when
optimizing. */
static gint
-get_hpadding (GtkWidget * widget)
+get_toggle_space (GtkWidget * widget)
{
gint padding = 0;
- gtk_widget_style_get(widget, "horizontal-padding", &padding, NULL);
+ gtk_widget_style_get(widget, "toggle-spacing", &padding, NULL);
return padding;
}
+/* Get the value to put in the span for the disposition */
+static gchar *
+get_text_color (GenericmenuitemDisposition disposition, GtkWidget * widget)
+{
+ struct {const gchar * color_name; const gchar * default_color;} values[] = {
+ /* NORMAL */ { NULL, NULL},
+ /* INFO */ { "informational-color", "blue"},
+ /* WARN */ { "warning-color", "orange"},
+ /* ALERT */ { "error-color", "red"}
+ };
+
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GtkStyleContext * context = gtk_widget_get_style_context(widget);
+ GdkRGBA color;
+
+ if (gtk_style_context_lookup_color(context, values[disposition].color_name, &color)) {
+ return g_strdup_printf("rgb(%d, %d, %d)", (gint)(color.red * 255), (gint)(color.green * 255), (gint)(color.blue * 255));
+ }
+#endif
+
+ return g_strdup(values[disposition].default_color);
+}
+
/* Set the label on the item */
static void
-set_label (GtkMenuItem * menu_item, const gchar * label)
+set_label (GtkMenuItem * menu_item, const gchar * in_label)
{
- if (label == NULL) return;
+ if (in_label == NULL) return;
+
+ /* Build a label that might include the colors of the disposition
+ so that it gets rendered in the menuitem. */
+ gchar * local_label = NULL;
+ switch (GENERICMENUITEM(menu_item)->priv->disposition) {
+ case GENERICMENUITEM_DISPOSITION_NORMAL:
+ local_label = g_strdup(in_label);
+ break;
+ case GENERICMENUITEM_DISPOSITION_INFORMATIONAL:
+ case GENERICMENUITEM_DISPOSITION_WARNING:
+ case GENERICMENUITEM_DISPOSITION_ALERT: {
+ gchar * color = get_text_color(GENERICMENUITEM(menu_item)->priv->disposition, GTK_WIDGET(menu_item));
+ local_label = g_markup_printf_escaped("<span fgcolor=\"%s\">%s</span>", color, in_label);
+ g_free(color);
+ break;
+ }
+ default:
+ g_warn_if_reached();
+ break;
+ }
GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
GtkLabel * labelw = NULL;
@@ -194,10 +241,10 @@ set_label (GtkMenuItem * menu_item, const gchar * label)
/* We need to put the child into a new box and
make the box the child of the menu item. Basically
we're inserting a box in the middle. */
- GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
+ GtkWidget * hbox = gtk_hbox_new(FALSE, get_toggle_space(GTK_WIDGET(menu_item)));
g_object_ref(child);
gtk_container_remove(GTK_CONTAINER(menu_item), child);
- gtk_box_pack_start(GTK_BOX(hbox), child, FALSE, FALSE, get_hpadding(GTK_WIDGET(menu_item)));
+ gtk_box_pack_start(GTK_BOX(hbox), child, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(menu_item), hbox);
gtk_widget_show(hbox);
g_object_unref(child);
@@ -211,10 +258,12 @@ set_label (GtkMenuItem * menu_item, const gchar * label)
update the one that we already have. */
if (labelw == NULL) {
/* Build it */
- labelw = GTK_LABEL(gtk_accel_label_new(label));
+ labelw = GTK_LABEL(gtk_accel_label_new(local_label));
gtk_label_set_use_underline(GTK_LABEL(labelw), TRUE);
+ gtk_label_set_use_markup(GTK_LABEL(labelw), TRUE);
gtk_misc_set_alignment(GTK_MISC(labelw), 0.0, 0.5);
gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(labelw), GTK_WIDGET(menu_item));
+ gtk_label_set_markup_with_mnemonic(labelw, local_label);
gtk_widget_show(GTK_WIDGET(labelw));
/* Check to see if it needs to be in the bin for this
@@ -222,17 +271,17 @@ set_label (GtkMenuItem * menu_item, const gchar * label)
if (child == NULL) {
gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(labelw));
} else {
- gtk_box_pack_end(GTK_BOX(child), GTK_WIDGET(labelw), TRUE, TRUE, get_hpadding(GTK_WIDGET(menu_item)));
+ gtk_box_pack_end(GTK_BOX(child), GTK_WIDGET(labelw), TRUE, TRUE, 0);
}
} else {
/* Oh, just an update. No biggie. */
- if (!g_strcmp0(label, gtk_label_get_label(labelw))) {
+ if (!g_strcmp0(local_label, gtk_label_get_label(labelw))) {
/* The only reason to suppress the update is if we had
a label and the value was the same as the one we're
getting in. */
suppress_update = TRUE;
} else {
- gtk_label_set_label(labelw, label);
+ gtk_label_set_markup_with_mnemonic(labelw, local_label);
}
}
@@ -241,6 +290,12 @@ set_label (GtkMenuItem * menu_item, const gchar * label)
g_object_notify(G_OBJECT(menu_item), "label");
}
+ /* Clean up this */
+ if (local_label != NULL) {
+ g_free(local_label);
+ local_label = NULL;
+ }
+
return;
}
@@ -401,10 +456,10 @@ genericmenuitem_set_image (Genericmenuitem * menu_item, GtkWidget * image)
/* We need to put the child into a new box and
make the box the child of the menu item. Basically
we're inserting a box in the middle. */
- GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
+ GtkWidget * hbox = gtk_hbox_new(FALSE, get_toggle_space(GTK_WIDGET(menu_item)));
g_object_ref(child);
gtk_container_remove(GTK_CONTAINER(menu_item), child);
- gtk_box_pack_end(GTK_BOX(hbox), child, TRUE, TRUE, get_hpadding(GTK_WIDGET(menu_item)));
+ gtk_box_pack_end(GTK_BOX(hbox), child, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(menu_item), hbox);
gtk_widget_show(hbox);
g_object_unref(child);
@@ -429,7 +484,7 @@ genericmenuitem_set_image (Genericmenuitem * menu_item, GtkWidget * image)
if (child == NULL) {
gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(image));
} else {
- gtk_box_pack_start(GTK_BOX(child), GTK_WIDGET(image), FALSE, FALSE, get_hpadding(GTK_WIDGET(menu_item)));
+ gtk_box_pack_start(GTK_BOX(child), GTK_WIDGET(image), FALSE, FALSE, 0);
}
gtk_widget_show(image);
@@ -466,3 +521,41 @@ genericmenuitem_get_image (Genericmenuitem * menu_item)
return imagew;
}
+
+/**
+ * genericmenuitem_set_disposition:
+ * @item: A #Genericmenuitem
+ * @disposition: The disposition of the item
+ *
+ * Sets the disposition of the menuitem.
+ */
+void
+genericmenuitem_set_disposition (Genericmenuitem * item, GenericmenuitemDisposition disposition)
+{
+ g_return_if_fail(IS_GENERICMENUITEM(item));
+
+ if (item->priv->disposition == disposition)
+ return;
+
+ item->priv->disposition = disposition;
+
+ set_label(GTK_MENU_ITEM(item), get_label(GTK_MENU_ITEM(item)));
+
+ return;
+}
+
+/**
+ * genericmenuitem_get_disposition:
+ * @item: A #Genericmenuitem
+ *
+ * Gets the disposition of the menuitem.
+ *
+ * Return value: The disposition of the menuitem.
+ */
+GenericmenuitemDisposition
+genericmenuitem_get_disposition (Genericmenuitem * item)
+{
+ g_return_val_if_fail(IS_GENERICMENUITEM(item), GENERICMENUITEM_DISPOSITION_NORMAL);
+
+ return item->priv->disposition;
+}
diff --git a/libdbusmenu-gtk/genericmenuitem.h b/libdbusmenu-gtk/genericmenuitem.h
index 5e3c640..0b7df55 100644
--- a/libdbusmenu-gtk/genericmenuitem.h
+++ b/libdbusmenu-gtk/genericmenuitem.h
@@ -42,11 +42,9 @@ G_BEGIN_DECLS
#define IS_GENERICMENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GENERICMENUITEM_TYPE))
#define GENERICMENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GENERICMENUITEM_TYPE, GenericmenuitemClass))
-typedef struct _Genericmenuitem Genericmenuitem;
-typedef struct _GenericmenuitemClass GenericmenuitemClass;
-typedef struct _GenericmenuitemPrivate GenericmenuitemPrivate;
-typedef enum _GenericmenuitemCheckType GenericmenuitemCheckType;
-typedef enum _GenericmenuitemState GenericmenuitemState;
+typedef struct _Genericmenuitem Genericmenuitem;
+typedef struct _GenericmenuitemClass GenericmenuitemClass;
+typedef struct _GenericmenuitemPrivate GenericmenuitemPrivate;
/*
GenericmenuitemClass:
@@ -65,26 +63,61 @@ struct _Genericmenuitem {
GenericmenuitemPrivate * priv;
};
-enum _GenericmenuitemCheckType {
+/**
+ * GenericmenuitemCheckType:
+ * @GENERICMENUITEM_CHECK_TYPE_NONE: No check
+ * @GENERICMENUITEM_CHECK_TYPE_CHECKBOX: Nice little check
+ * @GENERICMENUITEM_CHECK_TYPE_RADIO: Radio button
+ *
+ * Tracks what type of checkmark should be shown on the item
+ */
+typedef enum { /*< prefix=GENERICMENUITEM_CHECK_TYPE >*/
GENERICMENUITEM_CHECK_TYPE_NONE,
GENERICMENUITEM_CHECK_TYPE_CHECKBOX,
GENERICMENUITEM_CHECK_TYPE_RADIO
-};
-
-enum _GenericmenuitemState {
+} GenericmenuitemCheckType;
+
+/**
+ * GenericmenuitemState:
+ * @GENERICMENUITEM_STATE_UNCHECKED: No check visisble
+ * @GENERICMENUITEM_STATE_CHECKED: Check visible
+ * @GENERICMENUITEM_STATE_INDETERMINATE: We have no clue
+ *
+ * What the state of the check mark on the item is
+ */
+typedef enum { /*< prefix=GENERICMENUITEM_STATE >*/
GENERICMENUITEM_STATE_UNCHECKED,
GENERICMENUITEM_STATE_CHECKED,
GENERICMENUITEM_STATE_INDETERMINATE
-};
-
-GType genericmenuitem_get_type (void);
-void genericmenuitem_set_check_type (Genericmenuitem * item,
- GenericmenuitemCheckType check_type);
-void genericmenuitem_set_state (Genericmenuitem * item,
- GenericmenuitemState state);
-void genericmenuitem_set_image (Genericmenuitem * item,
- GtkWidget * image);
-GtkWidget * genericmenuitem_get_image (Genericmenuitem * item);
+} GenericmenuitemState;
+
+/**
+ * GenericmenuitemDisposition:
+ * @GENERICMENUITEM_DISPOSITION_NORMAL: Normal state
+ * @GENERICMENUITEM_DISPOSITION_INFORMATIONAL: Item is informational
+ * @GENERICMENUITEM_DISPOSITION_WARNING: Oh, you should watch out for this one
+ * @GENERICMENUITEM_DISPOSITION_ALERT: Boom!
+ *
+ * What the disposition of the menu item is
+ */
+typedef enum { /*< prefix=GENERICMENUITEM_DISPOSITION >*/
+ GENERICMENUITEM_DISPOSITION_NORMAL,
+ GENERICMENUITEM_DISPOSITION_INFORMATIONAL,
+ GENERICMENUITEM_DISPOSITION_WARNING,
+ GENERICMENUITEM_DISPOSITION_ALERT
+} GenericmenuitemDisposition;
+
+GType genericmenuitem_get_type (void);
+void genericmenuitem_set_check_type (Genericmenuitem * item,
+ GenericmenuitemCheckType check_type);
+void genericmenuitem_set_state (Genericmenuitem * item,
+ GenericmenuitemState state);
+void genericmenuitem_set_image (Genericmenuitem * item,
+ GtkWidget * image);
+GtkWidget * genericmenuitem_get_image (Genericmenuitem * item);
+void genericmenuitem_set_disposition (Genericmenuitem * item,
+ GenericmenuitemDisposition disposition);
+GenericmenuitemDisposition genericmenuitem_get_disposition (Genericmenuitem * item);
G_END_DECLS
diff --git a/libdbusmenu-gtk/menu.c b/libdbusmenu-gtk/menu.c
index 0b31069..236a596 100644
--- a/libdbusmenu-gtk/menu.c
+++ b/libdbusmenu-gtk/menu.c
@@ -329,6 +329,18 @@ remove_child_signals (gpointer data, gpointer user_data)
return;
}
+/* Handler for all of the menu items on a root change to ensure that
+ the menus are hidden before we start going and deleting things. */
+static void
+popdown_all (DbusmenuMenuitem * mi, gpointer user_data)
+{
+ GtkMenu * menu = dbusmenu_gtkclient_menuitem_get_submenu(DBUSMENU_GTKCLIENT(user_data), mi);
+ if (menu != NULL) {
+ gtk_menu_popdown(menu);
+ }
+ return;
+}
+
/* When the root menuitem changes we need to resetup things so that
we're back in the game. */
static void
@@ -344,6 +356,8 @@ root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGt
g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_moved, menu);
g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_delete, menu);
+ dbusmenu_menuitem_foreach(priv->root, popdown_all, client);
+
g_object_unref(priv->root);
priv->root = NULL;
}
diff --git a/libdbusmenu-gtk/menuitem.c b/libdbusmenu-gtk/menuitem.c
index ca2bc3e..0f511bc 100644
--- a/libdbusmenu-gtk/menuitem.c
+++ b/libdbusmenu-gtk/menuitem.c
@@ -275,6 +275,17 @@ dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, c
void
dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * key, GdkModifierType * modifier)
{
+ guint dummykey;
+ GdkModifierType dummymodifier;
+
+ if (key == NULL) {
+ key = &dummykey;
+ }
+
+ if (modifier == NULL) {
+ modifier = &dummymodifier;
+ }
+
*key = 0;
*modifier = 0;
@@ -287,15 +298,15 @@ dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * ke
if (g_variant_n_children(wrapper) != 1) {
g_warning("Unable to parse shortcut, too many keys");
- g_variant_unref(wrapper);
return;
}
GVariantIter iter;
- g_variant_iter_init(&iter, g_variant_get_child_value(wrapper, 0));
+ GVariant * child = g_variant_get_child_value(wrapper, 0);
+ g_variant_iter_init(&iter, child);
gchar * string;
- while(g_variant_iter_next(&iter, "s", &string)) {
+ while(g_variant_iter_loop(&iter, "s", &string)) {
if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_CONTROL) == 0) {
*modifier |= GDK_CONTROL_MASK;
} else if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_ALT) == 0) {
@@ -308,10 +319,10 @@ dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * ke
GdkModifierType tempmod;
gtk_accelerator_parse(string, key, &tempmod);
}
-
- g_free(string);
}
+ g_variant_unref(child);
+
return;
}
diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c
index a7f90a2..e988c62 100644
--- a/libdbusmenu-gtk/parser.c
+++ b/libdbusmenu-gtk/parser.c
@@ -28,7 +28,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include "parser.h"
#include "menuitem.h"
-#include "serializablemenuitem.h"
+#include "client.h"
#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item"
#define PARSER_DATA "dbusmenu-gtk-parser-data"
@@ -79,9 +79,17 @@ static void item_activated (DbusmenuMenuitem * item,
gpointer user_data);
static gboolean item_about_to_show (DbusmenuMenuitem * item,
gpointer user_data);
+static gboolean item_handle_event (DbusmenuMenuitem * item,
+ const gchar * name,
+ GVariant * variant,
+ guint timestamp,
+ GtkWidget * widget);
static void widget_notify_cb (GtkWidget * widget,
GParamSpec * pspec,
gpointer data);
+static void widget_add_cb (GtkWidget * widget,
+ GtkWidget * child,
+ gpointer data);
static gboolean should_show_image (GtkImage * image);
static void menuitem_notify_cb (GtkWidget * widget,
GParamSpec * pspec,
@@ -164,6 +172,8 @@ parse_data_free (gpointer data)
g_signal_handlers_disconnect_matched(pdata->widget, (GSignalMatchType)G_SIGNAL_MATCH_FUNC,
0, 0, NULL, G_CALLBACK(widget_notify_cb), NULL);
g_signal_handlers_disconnect_matched(pdata->widget, (GSignalMatchType)G_SIGNAL_MATCH_FUNC,
+ 0, 0, NULL, G_CALLBACK(widget_add_cb), NULL);
+ g_signal_handlers_disconnect_matched(pdata->widget, (GSignalMatchType)G_SIGNAL_MATCH_FUNC,
0, 0, NULL, G_CALLBACK(accel_changed), NULL);
g_signal_handlers_disconnect_matched(pdata->widget, (GSignalMatchType)G_SIGNAL_MATCH_FUNC,
0, 0, NULL, G_CALLBACK(checkbox_toggled), NULL);
@@ -260,6 +270,71 @@ new_menuitem (GtkWidget * widget)
return item;
}
+static gboolean
+toggle_widget_visibility (GtkWidget * widget)
+{
+ gboolean vis = gtk_widget_get_visible (widget);
+ gtk_widget_set_visible (widget, !vis);
+ gtk_widget_set_visible (widget, vis);
+ g_object_unref (G_OBJECT (widget));
+ return FALSE;
+}
+
+static void
+watch_submenu(DbusmenuMenuitem * mi, GtkWidget * menu)
+{
+ g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
+ g_return_if_fail(GTK_IS_MENU_SHELL(menu));
+
+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(mi), PARSER_DATA);
+
+ pdata->shell = menu;
+ g_signal_connect (G_OBJECT (menu),
+ "child-added",
+ G_CALLBACK (child_added_cb),
+ mi);
+ g_signal_connect (G_OBJECT (menu),
+ "child-removed",
+ G_CALLBACK (child_removed_cb),
+ mi);
+ g_object_add_weak_pointer(G_OBJECT (menu), (gpointer*)&pdata->shell);
+
+ /* Some apps (notably Eclipse RCP apps) don't fill contents of submenus
+ until the menu is shown. So we fake that by toggling the visibility of
+ any submenus we come across. Further, these apps need it done with a
+ delay while they finish initializing, so we put the call in the idle
+ queue. */
+ g_idle_add((GSourceFunc)toggle_widget_visibility,
+ g_object_ref (G_OBJECT (menu)));
+}
+
+static void
+activate_toplevel_item (GtkWidget * item)
+{
+ /* Make sure that we have a menu item before we start calling
+ functions that depend on it. This should almost always be
+ the case. */
+ if (!GTK_IS_MENU_ITEM(item)) {
+ return;
+ }
+
+ /* If the item is not opening a submenu we don't want to activate
+ it as that'd cause an action. Like opening a preferences dialog
+ to the user. That's not a good idea. */
+ if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(item)) == NULL) {
+ return;
+ }
+
+ GtkWidget * shell = gtk_widget_get_parent (item);
+ if (!GTK_IS_MENU_BAR (shell)) {
+ return;
+ }
+
+ gtk_menu_shell_activate_item (GTK_MENU_SHELL (shell),
+ item,
+ TRUE);
+}
+
static void
parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
{
@@ -276,33 +351,14 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
* Note that this will not force menuitems in submenus to be updated as well.
*/
if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) {
- GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
- GList *iter;
-
- for (iter = children; iter != NULL; iter = iter->next) {
- gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
- iter->data,
- TRUE);
- }
-
- g_list_free (children);
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ (GtkCallback)activate_toplevel_item,
+ NULL);
}
if (recurse->parent == NULL) {
recurse->parent = new_menuitem(widget);
-
- ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(recurse->parent), PARSER_DATA);
-
- pdata->shell = widget;
- g_signal_connect (G_OBJECT (widget),
- "child-added",
- G_CALLBACK (child_added_cb),
- recurse->parent);
- g_signal_connect (G_OBJECT (widget),
- "child-removed",
- G_CALLBACK (child_removed_cb),
- recurse->parent);
- g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->shell);
+ watch_submenu(recurse->parent, widget);
}
gtk_container_foreach (GTK_CONTAINER (widget),
@@ -438,13 +494,6 @@ sanitize_label (GtkLabel * label)
static DbusmenuMenuitem *
construct_dbusmenu_for_widget (GtkWidget * widget)
{
- /* If it's a subclass of our serializable menu item then we can
- use its own build function */
- if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) {
- DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget);
- return dbusmenu_gtk_serializable_menu_item_build_menuitem(smi);
- }
-
/* If it's a standard GTK Menu Item we need to do some of our own work */
if (GTK_IS_MENU_ITEM (widget))
{
@@ -454,11 +503,11 @@ construct_dbusmenu_for_widget (GtkWidget * widget)
gboolean visible = FALSE;
gboolean sensitive = FALSE;
- if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
+ if (GTK_IS_SEPARATOR_MENU_ITEM (widget) || !find_menu_label (widget))
{
dbusmenu_menuitem_property_set (mi,
- "type",
- "separator");
+ DBUSMENU_MENUITEM_PROP_TYPE,
+ DBUSMENU_CLIENT_TYPES_SEPARATOR);
visible = gtk_widget_get_visible (widget);
sensitive = gtk_widget_get_sensitive (widget);
@@ -512,21 +561,18 @@ construct_dbusmenu_for_widget (GtkWidget * widget)
GtkWidget *label = find_menu_label (widget);
- if (label)
- {
- // Sometimes, an app will directly find and modify the label
- // (like empathy), so watch the label especially for that.
- gchar * text = sanitize_label (GTK_LABEL (label));
- dbusmenu_menuitem_property_set (mi, "label", text);
- g_free (text);
-
- pdata->label = label;
- g_signal_connect (G_OBJECT (label),
- "notify",
- G_CALLBACK (label_notify_cb),
- mi);
- g_object_add_weak_pointer(G_OBJECT (label), (gpointer*)&pdata->label);
- }
+ // Sometimes, an app will directly find and modify the label
+ // (like empathy), so watch the label especially for that.
+ gchar * text = sanitize_label (GTK_LABEL (label));
+ dbusmenu_menuitem_property_set (mi, "label", text);
+ g_free (text);
+
+ pdata->label = label;
+ g_signal_connect (G_OBJECT (label),
+ "notify",
+ G_CALLBACK (label_notify_cb),
+ mi);
+ g_object_add_weak_pointer(G_OBJECT (label), (gpointer*)&pdata->label);
if (GTK_IS_ACTIVATABLE (widget))
{
@@ -554,16 +600,7 @@ construct_dbusmenu_for_widget (GtkWidget * widget)
GtkWidget *submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
if (submenu)
{
- pdata->shell = submenu;
- g_signal_connect (G_OBJECT (submenu),
- "child-added",
- G_CALLBACK (child_added_cb),
- mi);
- g_signal_connect (G_OBJECT (submenu),
- "child-removed",
- G_CALLBACK (child_removed_cb),
- mi);
- g_object_add_weak_pointer(G_OBJECT(submenu), (gpointer*)&pdata->shell);
+ watch_submenu(mi, submenu);
}
if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
@@ -583,6 +620,11 @@ construct_dbusmenu_for_widget (GtkWidget * widget)
DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
G_CALLBACK (item_about_to_show),
widget);
+
+ g_signal_connect (G_OBJECT (mi),
+ DBUSMENU_MENUITEM_SIGNAL_EVENT,
+ G_CALLBACK (item_handle_event),
+ widget);
}
dbusmenu_menuitem_property_set_bool (mi,
@@ -598,6 +640,11 @@ construct_dbusmenu_for_widget (GtkWidget * widget)
G_CALLBACK (widget_notify_cb),
mi);
+ g_signal_connect (widget,
+ "add",
+ G_CALLBACK (widget_add_cb),
+ mi);
+
return mi;
}
@@ -760,11 +807,48 @@ find_menu_label (GtkWidget *widget)
}
static void
+recreate_menu_item (DbusmenuMenuitem * parent, DbusmenuMenuitem * child)
+{
+ if (parent == NULL)
+ {
+ /* We need a parent */
+ return;
+ }
+ ParserData * pdata = g_object_get_data (G_OBJECT (child), PARSER_DATA);
+ /* Keep a pointer to the GtkMenuItem, as pdata->widget might be
+ * invalidated when we delete the DbusmenuMenuitem
+ */
+ GtkWidget * menuitem = pdata->widget;
+
+ dbusmenu_menuitem_child_delete (parent, child);
+
+ RecurseContext recurse = {0};
+ recurse.toplevel = gtk_widget_get_toplevel(menuitem);
+ recurse.parent = parent;
+
+ parse_menu_structure_helper(menuitem, &recurse);
+}
+
+static gboolean
+recreate_menu_item_in_idle_cb (gpointer data)
+{
+ DbusmenuMenuitem * child = (DbusmenuMenuitem *)data;
+ DbusmenuMenuitem * parent = dbusmenu_menuitem_get_parent (child);
+ g_object_unref (child);
+ recreate_menu_item (parent, child);
+ return FALSE;
+}
+
+static void
label_notify_cb (GtkWidget *widget,
GParamSpec *pspec,
gpointer data)
{
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
+ GValue prop_value = {0};
+
+ g_value_init (&prop_value, pspec->value_type);
+ g_object_get_property (G_OBJECT (widget), pspec->name, &prop_value);
if (pspec->name == g_intern_static_string ("label"))
{
@@ -774,6 +858,27 @@ label_notify_cb (GtkWidget *widget,
text);
g_free (text);
}
+ else if (pspec->name == g_intern_static_string ("parent"))
+ {
+ if (GTK_WIDGET (g_value_get_object (&prop_value)) == NULL)
+ {
+ /* This label is being removed from its GtkMenuItem. The
+ * menuitem becomes a separator now. As the client doesn't handle
+ * changing types so well, we remove the current DbusmenuMenuitem
+ * and add a new one.
+ *
+ * Note, we have to defer this to idle, as we are called before
+ * bin->child member of our old parent is invalidated. If we go ahead
+ * and call parse_menu_structure_helper now, the GtkMenuItem will
+ * still appear to have a label and we never convert it to a separator
+ */
+ g_object_ref (child);
+ g_idle_add ((GSourceFunc)recreate_menu_item_in_idle_cb, child);
+ }
+ }
+
+ g_value_unset(&prop_value);
+ return;
}
static void
@@ -872,6 +977,54 @@ item_about_to_show (DbusmenuMenuitem *item, gpointer user_data)
return TRUE;
}
+static gboolean
+item_handle_event (DbusmenuMenuitem *item, const gchar *name,
+ GVariant *variant, guint timestamp, GtkWidget *widget)
+{
+ if (g_strcmp0 (name, DBUSMENU_MENUITEM_EVENT_OPENED) == 0)
+ {
+ GtkWidget *submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+ if (submenu != NULL)
+ {
+ // Show the submenu so the app can notice and futz with the menus as
+ // desired (empathy and geany do this)
+ gtk_widget_show (submenu);
+ }
+ }
+ else if (g_strcmp0 (name, DBUSMENU_MENUITEM_EVENT_CLOSED) == 0)
+ {
+ GtkWidget *submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+ if (submenu != NULL)
+ {
+ // Hide the submenu so the app can notice and futz with the menus as
+ // desired (empathy and geany do this)
+ gtk_widget_hide (submenu);
+ }
+ }
+
+ return FALSE; // just pass through on everything
+}
+
+static gboolean
+handle_first_label (DbusmenuMenuitem *mi)
+{
+ ParserData *pdata = g_object_get_data (G_OBJECT (mi), PARSER_DATA);
+ if (!pdata->label)
+ {
+ /* GtkMenuItem's can start life as a separator if they have no child
+ * GtkLabel. In this case, we need to convert the DbusmenuMenuitem from
+ * a separator to a normal menuitem if the application adds a label.
+ * As changing types isn't handled too well by the client, we delete
+ * this menuitem for now and then recreate it
+ */
+ DbusmenuMenuitem * parent = dbusmenu_menuitem_get_parent (mi);
+ recreate_menu_item (parent, mi);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void
widget_notify_cb (GtkWidget *widget,
GParamSpec *pspec,
@@ -891,6 +1044,11 @@ widget_notify_cb (GtkWidget *widget,
}
else if (pspec->name == g_intern_static_string ("label"))
{
+ if (handle_first_label (child))
+ {
+ return;
+ }
+
dbusmenu_menuitem_property_set (child,
DBUSMENU_MENUITEM_PROP_LABEL,
g_value_get_string (&prop_value));
@@ -952,6 +1110,7 @@ widget_notify_cb (GtkWidget *widget,
if (item != NULL) {
GtkWidget * menu = GTK_WIDGET (g_value_get_object (&prop_value));
parse_menu_structure_helper(menu, &recurse);
+ watch_submenu(item, menu);
} else {
/* Note: it would be really odd that we wouldn't have a cached
item, but we should handle that appropriately. */
@@ -962,6 +1121,15 @@ widget_notify_cb (GtkWidget *widget,
g_value_unset (&prop_value);
}
+static void
+widget_add_cb (GtkWidget *widget,
+ GtkWidget *child,
+ gpointer data)
+{
+ if (find_menu_label (child) != NULL)
+ handle_first_label (data);
+}
+
/* A child item was added to a menu we're watching. Let's try to integrate it. */
static void
child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
@@ -972,6 +1140,10 @@ child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
recurse.toplevel = gtk_widget_get_toplevel(GTK_WIDGET(menu));
recurse.parent = menuitem;
+ if (GTK_IS_MENU_BAR(menu)) {
+ activate_toplevel_item (widget);
+ }
+
parse_menu_structure_helper(widget, &recurse);
}
diff --git a/libdbusmenu-gtk/serializablemenuitem.c b/libdbusmenu-gtk/serializablemenuitem.c
deleted file mode 100644
index b560fe3..0000000
--- a/libdbusmenu-gtk/serializablemenuitem.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
-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_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 (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(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;
-}
diff --git a/libdbusmenu-gtk/serializablemenuitem.h b/libdbusmenu-gtk/serializablemenuitem.h
deleted file mode 100644
index 9bea89f..0000000
--- a/libdbusmenu-gtk/serializablemenuitem.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-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))
-
-/**
- * DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_PROP_MENUITEM:
- *
- * String to access property #DbusmenuGtkSerializableMenuItem:dbusmenu-menuitem
- */
-#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.
-
- Signals and functions for #DbusmenuGtkSerializableMenuItem.
-*/
-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);
-
-/**
- SECTION:serializablemenuitem
- @short_description: A way to build #GtkMenuItems that can be sent over Dbusmenu
- @stability: Unstable
- @include: libdbusmenu-gtk/serializablemenuitem.h
-
- Menuitems can subclass from this instead of #GtkMenuItem and
- by providing the appropriate functions Dbusmenu will be able
- to parse them and send them over the bus.
-*/
-
-G_END_DECLS
-
-#endif