aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-gtk
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2011-01-27 14:19:46 -0600
committerTed Gould <ted@gould.cx>2011-01-27 14:19:46 -0600
commit2a91021522eb038b3aa18f2532ac289b921c9a48 (patch)
treee196e319299579a539bcdcc439b180dea0d327a2 /libdbusmenu-gtk
parent3354af7e467e14415756fc3e640b5c027af5ebde (diff)
parent35265154f7d70dc31837ff8fe4e45a810c393c2b (diff)
downloadlibdbusmenu-2a91021522eb038b3aa18f2532ac289b921c9a48.tar.gz
libdbusmenu-2a91021522eb038b3aa18f2532ac289b921c9a48.tar.bz2
libdbusmenu-2a91021522eb038b3aa18f2532ac289b921c9a48.zip
Import upstream version 0.3.94
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r--libdbusmenu-gtk/Makefile.am11
-rw-r--r--libdbusmenu-gtk/Makefile.in62
-rw-r--r--libdbusmenu-gtk/client.c36
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk.h41
-rw-r--r--libdbusmenu-gtk/menuitem.h4
-rw-r--r--libdbusmenu-gtk/parser.c679
-rw-r--r--libdbusmenu-gtk/parser.h37
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.c288
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.h115
9 files changed, 1253 insertions, 20 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index b8e1170..f3556e9 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -20,9 +20,12 @@ EXTRA_DIST = \
libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.4/libdbusmenu-gtk$(VER)/
libdbusmenu_gtkinclude_HEADERS = \
+ dbusmenu-gtk.h \
client.h \
menu.h \
- menuitem.h
+ menuitem.h \
+ parser.h \
+ serializablemenuitem.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
@@ -32,7 +35,11 @@ libdbusmenu_gtk_la_SOURCES = \
menu.h \
menu.c \
menuitem.h \
- menuitem.c
+ menuitem.c \
+ parser.h \
+ parser.c \
+ serializablemenuitem.h \
+ serializablemenuitem.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
diff --git a/libdbusmenu-gtk/Makefile.in b/libdbusmenu-gtk/Makefile.in
index e35a0c8..3700d89 100644
--- a/libdbusmenu-gtk/Makefile.in
+++ b/libdbusmenu-gtk/Makefile.in
@@ -46,12 +46,7 @@ DIST_COMMON = $(libdbusmenu_gtk3include_HEADERS) \
$(srcdir)/Makefile.in $(srcdir)/dbusmenu-gtk-0.4.pc.in \
$(srcdir)/dbusmenu-gtk3-0.4.pc.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/gnome-doc-utils.m4 \
- $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \
- $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/libtool.m4 \
- $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
- $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
- $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -90,7 +85,9 @@ libdbusmenu_gtk_la_DEPENDENCIES = \
../libdbusmenu-glib/libdbusmenu-glib.la $(am__DEPENDENCIES_1)
am_libdbusmenu_gtk_la_OBJECTS = libdbusmenu_gtk_la-client.lo \
libdbusmenu_gtk_la-genericmenuitem.lo \
- libdbusmenu_gtk_la-menu.lo libdbusmenu_gtk_la-menuitem.lo
+ libdbusmenu_gtk_la-menu.lo libdbusmenu_gtk_la-menuitem.lo \
+ libdbusmenu_gtk_la-parser.lo \
+ libdbusmenu_gtk_la-serializablemenuitem.lo
libdbusmenu_gtk_la_OBJECTS = $(am_libdbusmenu_gtk_la_OBJECTS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
@@ -105,7 +102,9 @@ am__DEPENDENCIES_2 = ../libdbusmenu-glib/libdbusmenu-glib.la \
libdbusmenu_gtk3_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__objects_1 = libdbusmenu_gtk3_la-client.lo \
libdbusmenu_gtk3_la-genericmenuitem.lo \
- libdbusmenu_gtk3_la-menu.lo libdbusmenu_gtk3_la-menuitem.lo
+ libdbusmenu_gtk3_la-menu.lo libdbusmenu_gtk3_la-menuitem.lo \
+ libdbusmenu_gtk3_la-parser.lo \
+ libdbusmenu_gtk3_la-serializablemenuitem.lo
am_libdbusmenu_gtk3_la_OBJECTS = $(am__objects_1)
libdbusmenu_gtk3_la_OBJECTS = $(am_libdbusmenu_gtk3_la_OBJECTS)
libdbusmenu_gtk3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
@@ -331,9 +330,12 @@ EXTRA_DIST = \
libdbusmenu_gtkincludedir = $(includedir)/libdbusmenu-0.4/libdbusmenu-gtk$(VER)/
libdbusmenu_gtkinclude_HEADERS = \
+ dbusmenu-gtk.h \
client.h \
menu.h \
- menuitem.h
+ menuitem.h \
+ parser.h \
+ serializablemenuitem.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
@@ -343,7 +345,11 @@ libdbusmenu_gtk_la_SOURCES = \
menu.h \
menu.c \
menuitem.h \
- menuitem.c
+ menuitem.c \
+ parser.h \
+ parser.c \
+ serializablemenuitem.h \
+ serializablemenuitem.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
@@ -499,10 +505,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk3_la-genericmenuitem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk3_la-menu.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk3_la-menuitem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk3_la-parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk3_la-serializablemenuitem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-client.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-genericmenuitem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-menu.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-menuitem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbusmenu_gtk_la-serializablemenuitem.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -560,6 +570,22 @@ libdbusmenu_gtk_la-menuitem.lo: menuitem.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk_la-menuitem.lo `test -f 'menuitem.c' || echo '$(srcdir)/'`menuitem.c
+libdbusmenu_gtk_la-parser.lo: parser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk_la_CFLAGS) $(CFLAGS) -MT libdbusmenu_gtk_la-parser.lo -MD -MP -MF $(DEPDIR)/libdbusmenu_gtk_la-parser.Tpo -c -o libdbusmenu_gtk_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbusmenu_gtk_la-parser.Tpo $(DEPDIR)/libdbusmenu_gtk_la-parser.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='parser.c' object='libdbusmenu_gtk_la-parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
+
+libdbusmenu_gtk_la-serializablemenuitem.lo: serializablemenuitem.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk_la_CFLAGS) $(CFLAGS) -MT libdbusmenu_gtk_la-serializablemenuitem.lo -MD -MP -MF $(DEPDIR)/libdbusmenu_gtk_la-serializablemenuitem.Tpo -c -o libdbusmenu_gtk_la-serializablemenuitem.lo `test -f 'serializablemenuitem.c' || echo '$(srcdir)/'`serializablemenuitem.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbusmenu_gtk_la-serializablemenuitem.Tpo $(DEPDIR)/libdbusmenu_gtk_la-serializablemenuitem.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='serializablemenuitem.c' object='libdbusmenu_gtk_la-serializablemenuitem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk_la-serializablemenuitem.lo `test -f 'serializablemenuitem.c' || echo '$(srcdir)/'`serializablemenuitem.c
+
libdbusmenu_gtk3_la-client.lo: client.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -MT libdbusmenu_gtk3_la-client.lo -MD -MP -MF $(DEPDIR)/libdbusmenu_gtk3_la-client.Tpo -c -o libdbusmenu_gtk3_la-client.lo `test -f 'client.c' || echo '$(srcdir)/'`client.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbusmenu_gtk3_la-client.Tpo $(DEPDIR)/libdbusmenu_gtk3_la-client.Plo
@@ -592,6 +618,22 @@ libdbusmenu_gtk3_la-menuitem.lo: menuitem.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk3_la-menuitem.lo `test -f 'menuitem.c' || echo '$(srcdir)/'`menuitem.c
+libdbusmenu_gtk3_la-parser.lo: parser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -MT libdbusmenu_gtk3_la-parser.lo -MD -MP -MF $(DEPDIR)/libdbusmenu_gtk3_la-parser.Tpo -c -o libdbusmenu_gtk3_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbusmenu_gtk3_la-parser.Tpo $(DEPDIR)/libdbusmenu_gtk3_la-parser.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='parser.c' object='libdbusmenu_gtk3_la-parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk3_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
+
+libdbusmenu_gtk3_la-serializablemenuitem.lo: serializablemenuitem.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -MT libdbusmenu_gtk3_la-serializablemenuitem.lo -MD -MP -MF $(DEPDIR)/libdbusmenu_gtk3_la-serializablemenuitem.Tpo -c -o libdbusmenu_gtk3_la-serializablemenuitem.lo `test -f 'serializablemenuitem.c' || echo '$(srcdir)/'`serializablemenuitem.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbusmenu_gtk3_la-serializablemenuitem.Tpo $(DEPDIR)/libdbusmenu_gtk3_la-serializablemenuitem.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='serializablemenuitem.c' object='libdbusmenu_gtk3_la-serializablemenuitem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdbusmenu_gtk3_la_CFLAGS) $(CFLAGS) -c -o libdbusmenu_gtk3_la-serializablemenuitem.lo `test -f 'serializablemenuitem.c' || echo '$(srcdir)/'`serializablemenuitem.c
+
mostlyclean-libtool:
-rm -f *.lo
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 18a2cdd..7ab2fe9 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -42,6 +42,7 @@ struct _DbusmenuGtkClientPrivate {
};
#define DBUSMENU_GTKCLIENT_GET_PRIVATE(o) (DBUSMENU_GTKCLIENT(o)->priv)
+#define USE_FALLBACK_PROP "use-fallback"
/* Prototypes */
static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass);
@@ -54,8 +55,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 +685,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 +720,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);
@@ -737,6 +738,29 @@ new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
return TRUE;
}
+/* A little helper so we don't generate a bunch of warnings
+ about being able to set use-fallback */
+static void
+set_use_fallback (GtkWidget * widget)
+{
+ static gboolean checked = FALSE;
+ static gboolean available = FALSE;
+
+ if (!checked) {
+ available = (g_object_class_find_property(G_OBJECT_CLASS(GTK_IMAGE_GET_CLASS(widget)), USE_FALLBACK_PROP) != NULL);
+ if (!available) {
+ g_warning("The '" USE_FALLBACK_PROP "' is not available on GtkImage so icons may not show correctly.");
+ }
+ checked = TRUE;
+ }
+
+ if (available) {
+ g_object_set(G_OBJECT(widget), USE_FALLBACK_PROP, TRUE, NULL);
+ }
+
+ return;
+}
+
/* This handler looks at property changes for items that are
image menu items. */
static void
@@ -789,7 +813,7 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, GVariant
gtkimage = NULL;
} else if (g_strcmp0(iconname, DBUSMENU_MENUITEM_ICON_NAME_BLANK) == 0) {
gtkimage = gtk_image_new();
- g_object_set(G_OBJECT(gtkimage), "use-fallback", TRUE, NULL);
+ set_use_fallback(gtkimage);
} else {
/* Look to see if we want to have an icon with the 'ltr' or
'rtl' depending on what we're doing. */
@@ -808,7 +832,7 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, GVariant
can just convert it to this name. */
if (gtkimage == NULL) {
gtkimage = gtk_image_new_from_icon_name(finaliconname, GTK_ICON_SIZE_MENU);
- g_object_set(G_OBJECT(gtkimage), "use-fallback", TRUE, NULL);
+ set_use_fallback(gtkimage);
} else {
gtk_image_set_from_icon_name(GTK_IMAGE(gtkimage), finaliconname, GTK_ICON_SIZE_MENU);
}
diff --git a/libdbusmenu-gtk/dbusmenu-gtk.h b/libdbusmenu-gtk/dbusmenu-gtk.h
new file mode 100644
index 0000000..f2fe5be
--- /dev/null
+++ b/libdbusmenu-gtk/dbusmenu-gtk.h
@@ -0,0 +1,41 @@
+/*
+A library to communicate a menu object set accross DBus and
+track updates and maintain consistency.
+
+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_H__
+#define __DBUSMENU_GTK_H__
+
+/* Start with the glib stuff */
+#include <libdbusmenu-glib/dbusmenu-glib.h>
+
+/* Now get the GTK stuff */
+#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/parser.c b/libdbusmenu-gtk/parser.c
new file mode 100644
index 0000000..5d71585
--- /dev/null
+++ b/libdbusmenu-gtk/parser.c
@@ -0,0 +1,679 @@
+/*
+Parse to take a set of GTK Menus and turn them into something that can
+be sent over the wire.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Numerous (check Bazaar)
+
+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 "parser.h"
+#include "menuitem.h"
+#include "serializablemenuitem.h"
+
+#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item"
+
+typedef struct _RecurseContext
+{
+ GtkWidget * toplevel;
+ DbusmenuMenuitem * parent;
+} RecurseContext;
+
+static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse);
+static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget);
+static void accel_changed (GtkWidget * widget,
+ gpointer data);
+static gboolean update_stock_item (DbusmenuMenuitem * menuitem,
+ GtkWidget * widget);
+static void checkbox_toggled (GtkWidget * widget,
+ DbusmenuMenuitem * mi);
+static void update_icon_name (DbusmenuMenuitem * menuitem,
+ GtkWidget * widget);
+static GtkWidget * find_menu_label (GtkWidget * widget);
+static void label_notify_cb (GtkWidget * widget,
+ GParamSpec * pspec,
+ gpointer data);
+static void action_notify_cb (GtkAction * action,
+ GParamSpec * pspec,
+ gpointer data);
+static void item_activated (DbusmenuMenuitem * item,
+ guint timestamp,
+ gpointer user_data);
+static gboolean item_about_to_show (DbusmenuMenuitem * item,
+ gpointer user_data);
+static void widget_notify_cb (GtkWidget * widget,
+ GParamSpec * pspec,
+ gpointer data);
+static gboolean should_show_image (GtkImage * image);
+static void menuitem_notify_cb (GtkWidget * widget,
+ GParamSpec * pspec,
+ gpointer data);
+
+/**
+ dbusmenu_gtk_parse_menu_structure:
+ @widget: A #GtkMenuItem or #GtkMenuShell to turn into a #DbusmenuMenuitem
+
+ Goes through the GTK structures and turns them into the appropraite
+ Dbusmenu structures along with setting up all the relationships
+ between the objects. It also stores the dbusmenu items as a cache
+ on the GTK items so that they'll be reused if necissary.
+
+ Return value: A dbusmenu item representing the menu structure
+*/
+DbusmenuMenuitem *
+dbusmenu_gtk_parse_menu_structure (GtkWidget * widget)
+{
+ g_return_val_if_fail(GTK_IS_MENU_ITEM(widget) || GTK_IS_MENU_SHELL(widget), NULL);
+
+ RecurseContext recurse = {0};
+
+ recurse.toplevel = gtk_widget_get_toplevel(widget);
+
+ parse_menu_structure_helper(widget, &recurse);
+
+ return recurse.parent;
+}
+
+/* Called when the dbusmenu item that we're keeping around
+ is finalized */
+static void
+dbusmenu_cache_freed (gpointer data, GObject * obj)
+{
+ /* If the dbusmenu item is killed we don't need to remove
+ the weak ref as well. */
+ g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM);
+ g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj);
+ return;
+}
+
+/* Called if we replace the cache on the object with a new
+ dbusmenu menuitem */
+static void
+object_cache_freed (gpointer data)
+{
+ if (!G_IS_OBJECT(data)) return;
+ g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data);
+ return;
+}
+
+static void
+parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
+{
+
+ /* If this is a shell, then let's handle the items in it. */
+ if (GTK_IS_MENU_SHELL (widget)) {
+ /* Okay, this is a little janky and all.. but some applications update some
+ * menuitem properties such as sensitivity on the activate callback. This
+ * seems a little weird, but it's not our place to judge when all this code
+ * is so crazy. So we're going to get ever crazier and activate all the
+ * menus that are directly below the menubar and force the applications to
+ * update their sensitivity. The menus won't actually popup in the app
+ * window due to our gtk+ patches.
+ *
+ * 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));
+
+ for (; children != NULL; children = children->next) {
+ gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
+ children->data,
+ TRUE);
+ }
+
+ g_list_free (children);
+ }
+
+ if (recurse->parent == NULL) {
+ recurse->parent = dbusmenu_menuitem_new();
+ }
+
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ (GtkCallback)parse_menu_structure_helper,
+ recurse);
+ return;
+ }
+
+ if (GTK_IS_MENU_ITEM(widget)) {
+ DbusmenuMenuitem * thisitem = NULL;
+
+ /* Check to see if we're cached already */
+ gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM);
+ if (pmi != NULL) {
+ thisitem = DBUSMENU_MENUITEM(pmi);
+ g_object_ref(G_OBJECT(thisitem));
+ }
+
+ /* We don't have one, so we'll need to build it */
+ if (thisitem == NULL) {
+ thisitem = construct_dbusmenu_for_widget (widget);
+ g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, thisitem, object_cache_freed);
+ g_object_weak_ref(G_OBJECT(thisitem), dbusmenu_cache_freed, widget);
+
+ if (!gtk_widget_get_visible (widget)) {
+ g_signal_connect (G_OBJECT (widget),
+ "notify::visible",
+ G_CALLBACK (menuitem_notify_cb),
+ recurse->toplevel);
+ }
+
+ if (GTK_IS_TEAROFF_MENU_ITEM (widget)) {
+ dbusmenu_menuitem_property_set_bool (thisitem,
+ DBUSMENU_MENUITEM_PROP_VISIBLE,
+ FALSE);
+ }
+ }
+
+ /* Check to see if we're in our parents list of children, if we have
+ a parent. */
+ if (recurse->parent != NULL) {
+ GList * children = dbusmenu_menuitem_get_children (recurse->parent);
+ GList * peek = NULL;
+
+ if (children != NULL) {
+ peek = g_list_find (children, thisitem);
+ }
+
+ /* Oops, let's tell our parents about us */
+ if (peek == NULL) {
+ /* TODO: Should we set a weak ref on the parent? */
+ g_object_set_data (G_OBJECT (thisitem),
+ "dbusmenu-parent",
+ recurse->parent);
+ dbusmenu_menuitem_child_append (recurse->parent,
+ thisitem);
+ }
+ }
+
+ GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+ if (menu != NULL) {
+ DbusmenuMenuitem * parent_save = recurse->parent;
+ recurse->parent = thisitem;
+ parse_menu_structure_helper (menu, recurse);
+ recurse->parent = parent_save;
+ }
+
+ if (recurse->parent == NULL) {
+ recurse->parent = thisitem;
+ } else {
+ g_object_unref(thisitem);
+ }
+ }
+
+ return;
+}
+
+/* Turn a widget into a dbusmenu item depending on the type of GTK
+ object that it is. */
+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))
+ {
+ DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();
+
+ gboolean visible = FALSE;
+ gboolean sensitive = FALSE;
+ if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
+ {
+ dbusmenu_menuitem_property_set (mi,
+ "type",
+ "separator");
+
+ visible = gtk_widget_get_visible (widget);
+ sensitive = gtk_widget_get_sensitive (widget);
+ }
+ else
+ {
+ gboolean label_set = FALSE;
+
+ g_signal_connect (widget,
+ "accel-closures-changed",
+ G_CALLBACK (accel_changed),
+ mi);
+
+ if (GTK_IS_CHECK_MENU_ITEM (widget))
+ {
+ dbusmenu_menuitem_property_set (mi,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ gtk_check_menu_item_get_draw_as_radio (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
+
+ dbusmenu_menuitem_property_set_int (mi,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+
+ g_signal_connect (widget,
+ "activate",
+ G_CALLBACK (checkbox_toggled),
+ mi);
+ }
+
+ if (GTK_IS_IMAGE_MENU_ITEM (widget))
+ {
+ GtkWidget *image;
+ GtkImageType image_type;
+
+ image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
+
+ if (GTK_IS_IMAGE (image))
+ {
+ image_type = gtk_image_get_storage_type (GTK_IMAGE (image));
+
+ if (image_type == GTK_IMAGE_STOCK)
+ {
+ label_set = update_stock_item (mi, image);
+ }
+ else if (image_type == GTK_IMAGE_ICON_NAME)
+ {
+ update_icon_name (mi, image);
+ }
+ else if (image_type == GTK_IMAGE_PIXBUF)
+ {
+ dbusmenu_menuitem_property_set_image (mi,
+ DBUSMENU_MENUITEM_PROP_ICON_DATA,
+ gtk_image_get_pixbuf (GTK_IMAGE (image)));
+ }
+ }
+ }
+
+ GtkWidget *label = find_menu_label (widget);
+
+ dbusmenu_menuitem_property_set (mi,
+ "label",
+ label ? gtk_label_get_text (GTK_LABEL (label)) : NULL);
+
+ if (label)
+ {
+ // Sometimes, an app will directly find and modify the label
+ // (like empathy), so watch the label especially for that.
+ g_signal_connect (G_OBJECT (label),
+ "notify",
+ G_CALLBACK (label_notify_cb),
+ mi);
+ }
+
+ if (GTK_IS_ACTIVATABLE (widget))
+ {
+ GtkActivatable *activatable = GTK_ACTIVATABLE (widget);
+
+ if (gtk_activatable_get_use_action_appearance (activatable))
+ {
+ GtkAction *action = gtk_activatable_get_related_action (activatable);
+
+ if (action)
+ {
+ visible = gtk_action_is_visible (action);
+ sensitive = gtk_action_is_sensitive (action);
+
+ g_signal_connect_object (action, "notify",
+ G_CALLBACK (action_notify_cb),
+ mi,
+ G_CONNECT_AFTER);
+ }
+ }
+ }
+
+ if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
+ {
+ visible = gtk_widget_get_visible (widget);
+ sensitive = gtk_widget_get_sensitive (widget);
+ }
+
+ dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
+
+ g_signal_connect (G_OBJECT (mi),
+ DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK (item_activated),
+ widget);
+
+ g_signal_connect (G_OBJECT (mi),
+ DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
+ G_CALLBACK (item_about_to_show),
+ widget);
+ }
+
+ dbusmenu_menuitem_property_set_bool (mi,
+ DBUSMENU_MENUITEM_PROP_VISIBLE,
+ visible);
+
+ dbusmenu_menuitem_property_set_bool (mi,
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ sensitive);
+
+ g_signal_connect (widget,
+ "notify",
+ G_CALLBACK (widget_notify_cb),
+ mi);
+ return mi;
+ }
+
+ /* If it's none of those we're going to just create a
+ generic menuitem as a place holder for it. */
+ return dbusmenu_menuitem_new();
+}
+
+static void
+menuitem_notify_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ if (pspec->name == g_intern_static_string ("visible"))
+ {
+ GtkWidget * new_toplevel = gtk_widget_get_toplevel (widget);
+ GtkWidget * old_toplevel = GTK_WIDGET(data);
+
+ if (new_toplevel == old_toplevel) {
+ /* TODO: Figure this out -> rebuild (context->bridge, window); */
+ }
+
+ /* We only care about this once, so let's disconnect now. */
+ g_signal_handlers_disconnect_by_func (widget,
+ G_CALLBACK (menuitem_notify_cb),
+ data);
+ }
+}
+
+static void
+accel_changed (GtkWidget *widget,
+ gpointer data)
+{
+ DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
+ dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
+}
+
+static gboolean
+update_stock_item (DbusmenuMenuitem *menuitem,
+ GtkWidget *widget)
+{
+ GtkStockItem stock;
+ GtkImage *image;
+
+ g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
+
+ image = GTK_IMAGE (widget);
+
+ if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK)
+ return FALSE;
+
+ gchar * stock_id = NULL;
+ gtk_image_get_stock(image, &stock_id, NULL);
+
+ gtk_stock_lookup (stock_id, &stock);
+
+ if (should_show_image (image))
+ dbusmenu_menuitem_property_set (menuitem,
+ DBUSMENU_MENUITEM_PROP_ICON_NAME,
+ stock_id);
+ else
+ dbusmenu_menuitem_property_remove (menuitem,
+ DBUSMENU_MENUITEM_PROP_ICON_NAME);
+
+ const gchar *label = dbusmenu_menuitem_property_get (menuitem,
+ DBUSMENU_MENUITEM_PROP_LABEL);
+
+ if (stock.label != NULL && label != NULL)
+ {
+ dbusmenu_menuitem_property_set (menuitem,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ stock.label);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
+{
+ dbusmenu_menuitem_property_set_int (mi,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+}
+
+static void
+update_icon_name (DbusmenuMenuitem *menuitem,
+ GtkWidget *widget)
+{
+ GtkImage *image;
+
+ g_return_if_fail (GTK_IS_IMAGE (widget));
+
+ image = GTK_IMAGE (widget);
+
+ if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME)
+ return;
+
+ if (should_show_image (image)) {
+ const gchar * icon_name = NULL;
+ gtk_image_get_icon_name(image, &icon_name, NULL);
+ dbusmenu_menuitem_property_set (menuitem,
+ DBUSMENU_MENUITEM_PROP_ICON_NAME,
+ icon_name);
+ } else {
+ dbusmenu_menuitem_property_remove (menuitem,
+ DBUSMENU_MENUITEM_PROP_ICON_NAME);
+ }
+}
+
+static GtkWidget *
+find_menu_label (GtkWidget *widget)
+{
+ GtkWidget *label = NULL;
+
+ if (GTK_IS_LABEL (widget))
+ return widget;
+
+ if (GTK_IS_CONTAINER (widget))
+ {
+ GList *children;
+ GList *l;
+
+ children = gtk_container_get_children (GTK_CONTAINER (widget));
+
+ for (l = children; l; l = l->next)
+ {
+ label = find_menu_label (l->data);
+
+ if (label)
+ break;
+ }
+
+ g_list_free (children);
+ }
+
+ return label;
+}
+
+static void
+label_notify_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
+
+ if (pspec->name == g_intern_static_string ("label"))
+ {
+ dbusmenu_menuitem_property_set (child,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ gtk_label_get_text (GTK_LABEL (widget)));
+ }
+}
+
+static void
+action_notify_cb (GtkAction *action,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
+
+ if (pspec->name == g_intern_static_string ("sensitive"))
+ {
+ dbusmenu_menuitem_property_set_bool (mi,
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ gtk_action_is_sensitive (action));
+ }
+ else if (pspec->name == g_intern_static_string ("visible"))
+ {
+ dbusmenu_menuitem_property_set_bool (mi,
+ DBUSMENU_MENUITEM_PROP_VISIBLE,
+ gtk_action_is_visible (action));
+ }
+ else if (pspec->name == g_intern_static_string ("active"))
+ {
+ dbusmenu_menuitem_property_set_int (mi,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+ }
+ else if (pspec->name == g_intern_static_string ("label"))
+ {
+ dbusmenu_menuitem_property_set (mi,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ gtk_action_get_label (action));
+ }
+}
+
+static void
+item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data)
+{
+ GtkWidget *child;
+
+ if (user_data != NULL)
+ {
+ child = (GtkWidget *)user_data;
+
+ if (GTK_IS_MENU_ITEM (child))
+ {
+ gtk_menu_item_activate (GTK_MENU_ITEM (child));
+ }
+ }
+}
+
+static gboolean
+item_about_to_show (DbusmenuMenuitem *item, gpointer user_data)
+{
+ GtkWidget *child;
+
+ if (user_data != NULL)
+ {
+ child = (GtkWidget *)user_data;
+
+ if (GTK_IS_MENU_ITEM (child))
+ {
+ // Only called for items with submens. So we activate it here in
+ // case the program dynamically creates menus (like empathy does)
+ gtk_menu_item_activate (GTK_MENU_ITEM (child));
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+widget_notify_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
+
+ if (pspec->name == g_intern_static_string ("sensitive"))
+ {
+ dbusmenu_menuitem_property_set_bool (child,
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ gtk_widget_get_sensitive (widget));
+ }
+ else if (pspec->name == g_intern_static_string ("label"))
+ {
+ dbusmenu_menuitem_property_set (child,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ gtk_menu_item_get_label (GTK_MENU_ITEM (widget)));
+ }
+ else if (pspec->name == g_intern_static_string ("visible"))
+ {
+ dbusmenu_menuitem_property_set_bool (child,
+ DBUSMENU_MENUITEM_PROP_VISIBLE,
+ gtk_widget_get_visible (widget));
+ }
+ else if (pspec->name == g_intern_static_string ("stock"))
+ {
+ update_stock_item (child, widget);
+ }
+ else if (pspec->name == g_intern_static_string ("icon-name"))
+ {
+ update_icon_name (child, widget);
+ }
+ else if (pspec->name == g_intern_static_string ("parent"))
+ {
+ /*
+ * We probably should have added a 'remove' method to the
+ * UbuntuMenuProxy early on, but it's late in the cycle now.
+ */
+ if (gtk_widget_get_parent (widget) == NULL)
+ {
+ g_signal_handlers_disconnect_by_func (widget,
+ G_CALLBACK (widget_notify_cb),
+ child);
+
+ DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent");
+
+ if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child))
+ {
+ dbusmenu_menuitem_child_delete (parent, child);
+ }
+ }
+ }
+}
+
+static gboolean
+should_show_image (GtkImage *image)
+{
+ GtkWidget *item;
+
+ item = gtk_widget_get_ancestor (GTK_WIDGET (image),
+ GTK_TYPE_IMAGE_MENU_ITEM);
+
+ if (item)
+ {
+ GtkSettings *settings;
+ gboolean gtk_menu_images;
+
+ settings = gtk_widget_get_settings (item);
+
+ g_object_get (settings, "gtk-menu-images", &gtk_menu_images, NULL);
+
+ if (gtk_menu_images)
+ return TRUE;
+
+ return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item));
+ }
+
+ return FALSE;
+}
+
diff --git a/libdbusmenu-gtk/parser.h b/libdbusmenu-gtk/parser.h
new file mode 100644
index 0000000..a40d709
--- /dev/null
+++ b/libdbusmenu-gtk/parser.h
@@ -0,0 +1,37 @@
+/*
+Parse to take a set of GTK Menus and turn them into something that can
+be sent over the wire.
+
+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_PARSER_H__
+#define DBUSMENU_GTK_PARSER_H__
+
+#include <libdbusmenu-glib/menuitem.h>
+#include <gtk/gtk.h>
+
+DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget);
+
+#endif /* DBUSMENU_GTK_PARSER_H__ */
diff --git a/libdbusmenu-gtk/serializablemenuitem.c b/libdbusmenu-gtk/serializablemenuitem.c
new file mode 100644
index 0000000..cfd864d
--- /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_menuitem:
+ @smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring
+
+ This function is for menu items that are instanciated from
+ GTK and have their properites set using GTK functions. This
+ builds a #DbusmenuMenuitem that then has the properties that
+ should be sent over the bus to create a new item of this
+ type on the other side.
+
+ Return value: (transfer full) A #DbusmenuMenuitem who's values will be
+ set by this object.
+*/
+DbusmenuMenuitem *
+dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi)
+{
+ g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL);
+
+ DbusmenuGtkSerializableMenuItemClass * klass = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_GET_CLASS(smi);
+ if (klass->build_dbusmenu_menuitem != NULL) {
+ return klass->build_dbusmenu_menuitem(smi);
+ }
+
+ return NULL;
+}
+
+/* Callback to the generic type handler */
+typedef struct _type_handler_t type_handler_t;
+struct _type_handler_t {
+ DbusmenuGtkSerializableMenuItemClass * class;
+ GType type;
+};
+
+/* Handle the type with this item. */
+static gboolean
+type_handler (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
+{
+ type_handler_t * th = (type_handler_t *)user_data;
+
+ DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL));
+ g_return_val_if_fail(smi != NULL, FALSE);
+
+ dbusmenu_gtk_serializable_menu_item_set_menuitem(smi, newitem);
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent);
+
+ return TRUE;
+}
+
+/* Destruction is inevitable */
+static void
+type_destroy_handler (DbusmenuClient * client, const gchar * type, gpointer user_data)
+{
+ g_return_if_fail(user_data != NULL);
+ type_handler_t * th = (type_handler_t *)user_data;
+ g_type_class_unref(th->class);
+ g_free(user_data);
+ return;
+}
+
+/**
+ dbusmenu_gtk_serializable_menu_item_register_to_client:
+ @client: #DbusmenuClient that we should register a type at.
+ @item_type: The #GType of a class that is a subclass of #DbusmenuGtkSerializableMenuItem
+
+ Registers a generic handler for dealing with all subclasses of
+ #DbusmenuGtkSerializableMenuItem. This handler responds to the callback,
+ creates a new object and attaches it to the appropriate #DbusmenuMenuitem
+ object.
+*/
+void
+dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type)
+{
+ g_return_if_fail(g_type_is_a(item_type, DBUSMENU_TYPE_GTK_SERIALIZABLE_MENU_ITEM));
+
+ gpointer type_class = g_type_class_ref(item_type);
+ g_return_if_fail(type_class != NULL);
+
+ DbusmenuGtkSerializableMenuItemClass * class = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_CLASS(type_class);
+
+ if (class->get_type_string == NULL) {
+ g_type_class_unref(type_class);
+ g_error("No 'get_type_string' in subclass of DbusmenuGtkSerializableMenuItem");
+ return;
+ }
+
+ /* Register type */
+ type_handler_t * th = g_new0(type_handler_t, 1);
+ th->class = class;
+ th->type = item_type;
+ if (!dbusmenu_client_add_type_handler_full(client, class->get_type_string(), type_handler, th, type_destroy_handler)) {
+ type_destroy_handler(client, class->get_type_string(), th);
+ }
+
+ /* Register defaults */
+ /* TODO: Need API on another branch */
+
+ return;
+}
+
+/**
+ dbusmenu_gtk_serializable_menu_item_set_menuitem:
+ @smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of
+ @mi: Menuitem to get the properties from
+
+ This function is used on the server side to signal to the object
+ that it should get its' property change events from @mi instead
+ of expecting calls to its' API. A call to this function sets the
+ property and subclasses should listen to the notify signal to
+ pick up this property being set.
+*/
+void
+dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi)
+{
+ g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi));
+ g_return_if_fail(mi != NULL);
+
+ smi->priv->mi = mi;
+ g_object_notify(G_OBJECT(smi), DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM_PROP_MENUITEM);
+
+ return;
+}
diff --git a/libdbusmenu-gtk/serializablemenuitem.h b/libdbusmenu-gtk/serializablemenuitem.h
new file mode 100644
index 0000000..db28a24
--- /dev/null
+++ b/libdbusmenu-gtk/serializablemenuitem.h
@@ -0,0 +1,115 @@
+/*
+An object to act as a base class for easy GTK widgets that can be
+transfered over dbusmenu.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@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
+
+ The Serializable Menuitem provides a way for menu items to be created
+ that can easily be picked up by the Dbusmenu GTK Parser. This way
+ you can create custom items, and transport them across dbusmenu to
+ your menus or the appmenu on the other side of the bus. By providing
+ these function the parser has enough information to both serialize, and
+ deserialize on the other side, the menuitem you've so carefully created.
+*/
+struct _DbusmenuGtkSerializableMenuItem {
+ GtkMenuItem parent;
+
+ DbusmenuGtkSerializableMenuItemPrivate * priv;
+};
+
+GType dbusmenu_gtk_serializable_menu_item_get_type (void);
+
+DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi);
+void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type);
+void dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi);
+
+G_END_DECLS
+
+#endif