diff options
author | Ken VanDine <ken.vandine@canonical.com> | 2011-01-27 16:40:56 -0500 |
---|---|---|
committer | Ken VanDine <ken.vandine@canonical.com> | 2011-01-27 16:40:56 -0500 |
commit | e08b0e33060a39b3c95e43531825a95f5d415af8 (patch) | |
tree | cb3deecc01d16e57265afe76ce1074df10a79baa /libdbusmenu-gtk | |
parent | 4ef0a2886c4d4865a453ee32656937eb37669421 (diff) | |
parent | ea3e23cd918f2b8c7b6f9a94b3d80499bc0ce550 (diff) | |
download | libdbusmenu-e08b0e33060a39b3c95e43531825a95f5d415af8.tar.gz libdbusmenu-e08b0e33060a39b3c95e43531825a95f5d415af8.tar.bz2 libdbusmenu-e08b0e33060a39b3c95e43531825a95f5d415af8.zip |
releasing version 0.3.94-0ubuntu1
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r-- | libdbusmenu-gtk/Makefile.am | 11 | ||||
-rw-r--r-- | libdbusmenu-gtk/Makefile.in | 62 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 36 | ||||
-rw-r--r-- | libdbusmenu-gtk/dbusmenu-gtk.h | 41 | ||||
-rw-r--r-- | libdbusmenu-gtk/menuitem.h | 4 | ||||
-rw-r--r-- | libdbusmenu-gtk/parser.c | 679 | ||||
-rw-r--r-- | libdbusmenu-gtk/parser.h | 37 | ||||
-rw-r--r-- | libdbusmenu-gtk/serializablemenuitem.c | 288 | ||||
-rw-r--r-- | libdbusmenu-gtk/serializablemenuitem.h | 115 |
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", >k_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 |