aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2011-02-11 22:03:16 -0600
committerTed Gould <ted@gould.cx>2011-02-11 22:03:16 -0600
commit274b3a49d6f516dfb038bc2b2b3de2d4e2511e51 (patch)
tree4dbfbfc17fd4e82d4b0879d8ceaf31bdeec7f70a
parent3a572218ff8520ca284966d9395c2fd06544d233 (diff)
parente417951544c716a7f8ed3f7b348135e409cf1356 (diff)
downloadlibdbusmenu-274b3a49d6f516dfb038bc2b2b3de2d4e2511e51.tar.gz
libdbusmenu-274b3a49d6f516dfb038bc2b2b3de2d4e2511e51.tar.bz2
libdbusmenu-274b3a49d6f516dfb038bc2b2b3de2d4e2511e51.zip
Updating to group prop change signals branch to get the changes there (oh, pull in some trunk too)
-rw-r--r--.bzrignore39
-rw-r--r--Makefile.am5
-rw-r--r--configure.ac75
-rw-r--r--docs/libdbusmenu-gtk/reference/Makefile.am13
-rw-r--r--docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml2
-rw-r--r--libdbusmenu-glib/Makefile.am85
-rw-r--r--libdbusmenu-glib/clean-namespaces.xslt14
-rw-r--r--libdbusmenu-glib/client-marshal.list2
-rw-r--r--libdbusmenu-glib/client-menuitem.c6
-rw-r--r--libdbusmenu-glib/client.c781
-rw-r--r--libdbusmenu-glib/client.h50
-rw-r--r--libdbusmenu-glib/dbus-menu.xml6
-rw-r--r--libdbusmenu-glib/dbusmenu-glib-0.4.pc.in (renamed from libdbusmenu-glib/dbusmenu-glib.pc.in)4
-rw-r--r--libdbusmenu-glib/dbusmenu-glib.h37
-rw-r--r--libdbusmenu-glib/menuitem-marshal.list2
-rw-r--r--libdbusmenu-glib/menuitem-private.h1
-rw-r--r--libdbusmenu-glib/menuitem-proxy.c18
-rw-r--r--libdbusmenu-glib/menuitem-proxy.h18
-rw-r--r--libdbusmenu-glib/menuitem.c240
-rw-r--r--libdbusmenu-glib/menuitem.h37
-rw-r--r--libdbusmenu-glib/server-marshal.list2
-rw-r--r--libdbusmenu-glib/server.c973
-rw-r--r--libdbusmenu-glib/server.h26
-rw-r--r--libdbusmenu-gtk/Makefile.am103
-rw-r--r--libdbusmenu-gtk/client.c120
-rw-r--r--libdbusmenu-gtk/client.h11
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk-0.4.pc.in (renamed from libdbusmenu-gtk/dbusmenu-gtk.pc.in)4
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk.h41
-rw-r--r--libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc.in14
-rw-r--r--libdbusmenu-gtk/genericmenuitem.c59
-rw-r--r--libdbusmenu-gtk/menu.c49
-rw-r--r--libdbusmenu-gtk/menu.h11
-rw-r--r--libdbusmenu-gtk/menuitem.c139
-rw-r--r--libdbusmenu-gtk/menuitem.h8
-rw-r--r--libdbusmenu-gtk/parser.c825
-rw-r--r--libdbusmenu-gtk/parser.h37
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.c288
-rw-r--r--libdbusmenu-gtk/serializablemenuitem.h115
-rw-r--r--tests/Makefile.am39
-rw-r--r--tests/dbusmenu-jsonloader-0.4.pc.in (renamed from tests/dbusmenu-jsonloader.pc.in)2
-rw-r--r--tests/json-loader.c154
-rw-r--r--tests/test-glib-events-client.c14
-rw-r--r--tests/test-glib-events-server.c55
-rw-r--r--tests/test-glib-layout-server.c53
-rw-r--r--tests/test-glib-objects.c70
-rw-r--r--tests/test-glib-properties-server.c7
-rw-r--r--tests/test-glib-proxy-client.c7
-rw-r--r--tests/test-glib-proxy-proxy.c52
-rw-r--r--tests/test-glib-proxy-server.c51
-rw-r--r--tests/test-glib-simple-items.c3
-rw-r--r--tests/test-glib-submenu-server.c53
-rw-r--r--tests/test-gtk-label-server.c52
-rw-r--r--tests/test-gtk-objects.c4
-rw-r--r--tests/test-gtk-parser.c115
-rw-r--r--tests/test-gtk-reorder-server.c55
-rw-r--r--tests/test-gtk-shortcut-server.c53
-rw-r--r--tests/test-gtk-submenu-server.c55
-rw-r--r--tests/test-json-01.json1644
-rw-r--r--tests/test-json-client.c60
-rw-r--r--tests/test-json-server.c61
-rwxr-xr-xtools/dbusmenu-bench2
-rw-r--r--tools/dbusmenu-dumper.c154
-rw-r--r--tools/testapp/Makefile.am8
-rw-r--r--tools/testapp/main.c49
64 files changed, 4890 insertions, 2242 deletions
diff --git a/.bzrignore b/.bzrignore
index c1088c1..39be2d5 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -49,8 +49,8 @@ tests/test-gtk-reorder-server.c
tests/test-gtk-reorder-server
tests/test-gtk-reorder
tools/dbusmenu-dumper
-libdbusmenu-[0-9].[0-9].[0-9].tar.gz
-libdbusmenu-[0-9].[0-9].[0-9].tar.gz.asc
+libdbusmenu-[0-9]*.[0-9]*.[0-9]*.tar.gz
+libdbusmenu-[0-9]*.[0-9]*.[0-9]*.tar.gz.asc
tests/test-mago
tests/*.bustle
libdbusmenu-gtk/libdbusmenu_gtk_la-genericmenuitem.lo
@@ -182,7 +182,7 @@ docs/libdbusmenu-gtk/reference/tmpl/menuitem.sgml
docs/libdbusmenu-gtk/reference/tmpl/menuitem.sgml.bak
gtk-doc.make
m4/gtk-doc.m4
-tests/dbusmenu-jsonloader.pc
+tests/dbusmenu-jsonloader-0.4.pc
tests/libdbusmenu-jsonloader.la
tests/libdbusmenu_jsonloader_la-json-loader.lo
tests/test-json-server
@@ -194,3 +194,36 @@ libdbusmenu-glib/libdbusmenu_glib_la-client-marshal.lo
tests/test-glib-events
tests/test-glib-events-client
tests/test-glib-events-server
+libdbusmenu-glib/dbus-menu.xml.c
+libdbusmenu-glib/dbus-menu.xml.h
+libdbusmenu-glib/libdbusmenu_glib_la-dbus-menu.xml.lo
+libdbusmenu-glib/dbus-menu-clean.xml
+libdbusmenu-glib/dbus-menu-clean.xml.c
+libdbusmenu-glib/dbus-menu-clean.xml.h
+libdbusmenu-glib/libdbusmenu_glib_la-dbus-menu-clean.xml.lo
+libdbusmenu-gtk/DbusmenuGtk3-0.2.gir
+libdbusmenu-gtk/DbusmenuGtk3-0.2.tmp.gir
+libdbusmenu-gtk/DbusmenuGtk3-0.2.typelib
+libdbusmenu-gtk/dbusmenu-gtk3.pc
+libdbusmenu-gtk/libdbusmenu-gtk3.la
+libdbusmenu-gtk/libdbusmenu_gtk3_la-client.lo
+libdbusmenu-gtk/libdbusmenu_gtk3_la-genericmenuitem.lo
+libdbusmenu-gtk/libdbusmenu_gtk3_la-menu.lo
+libdbusmenu-gtk/libdbusmenu_gtk3_la-menuitem.lo
+libdbusmenu-glib/Dbusmenu-Glib-0.4.gir
+libdbusmenu-glib/Dbusmenu-Glib-0.4.typelib
+libdbusmenu-glib/Dbusmenu-Glib-0.4.vapi
+libdbusmenu-glib/dbusmenu-glib-0.4.pc
+libdbusmenu-gtk/DbusmenuGtk-0.4.gir
+libdbusmenu-gtk/DbusmenuGtk-0.4.tmp.gir
+libdbusmenu-gtk/DbusmenuGtk-0.4.typelib
+libdbusmenu-gtk/DbusmenuGtk-0.4.vapi
+libdbusmenu-gtk/dbusmenu-gtk-0.4.pc
+libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc
+libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo
+docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html
+docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml
+libdbusmenu-gtk/libdbusmenu_gtk_la-parser.lo
+test-gtk-parser
+test-gtk-parser-test
+test-gtk-parser.xml
diff --git a/Makefile.am b/Makefile.am
index b5fff3e..c2c0980 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,11 @@ SUBDIRS = \
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection --enable-gtk-doc
+## Can't disable deprecations yet, working on that, but
+## we want to get there.
+#
+# DISTCHECK_CONFIGURE_FLAGS = --enable-introspection --enable-gtk-doc --disable-deprecations
+
dist-hook:
@if test -d "$(top_srcdir)/.bzr"; \
then \
diff --git a/configure.ac b/configure.ac
index 6f894fd..381df76 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
-AC_INIT(libdbusmenu, 0.3.16, ted@canonical.com)
+AC_INIT(libdbusmenu, 0.3.96, ted@canonical.com)
AC_COPYRIGHT([Copyright 2009,2010 Canonical])
AC_PREREQ(2.62)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libdbusmenu, 0.3.16, [-Wno-portability])
+AM_INIT_AUTOMAKE(libdbusmenu, 0.3.96, [-Wno-portability])
AM_MAINTAINER_MODE
@@ -21,6 +21,15 @@ AC_CONFIG_MACRO_DIR([m4])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+AC_ARG_ENABLE([deprecations],
+ [AS_HELP_STRING([--enable-deprecations],
+ [allow deprecated API usage @<:@default=yes@:>@])],
+ [],
+ [enable_deprecations=yes])
+AS_IF([test "x$enable_deprecations" = xno],
+ [CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE -DGTK_DISABLE_SINGLE_INCLUDES"]
+)
+
###########################
# GTK Doc
###########################
@@ -32,12 +41,11 @@ GNOME_DOC_INIT
# Dependencies - GLib
###########################
-GLIB_REQUIRED_VERSION=2.18
-DBUS_REQUIRED_VERSION=0.76
+GLIB_REQUIRED_VERSION=2.26
XML_REQUIRED_VERSION=2.6
PKG_CHECK_MODULES(DBUSMENUGLIB, glib-2.0 >= $GLIB_REQUIRED_VERSION
- dbus-glib-1 >= $DBUS_REQUIRED_VERSION
+ gio-2.0 >= $GLIB_REQUIRED_VERSION
libxml-2.0 >= $XML_REQUIRED_VERSION)
AC_SUBST(DBUSMENUGLIB_CFLAGS)
@@ -48,14 +56,31 @@ AC_SUBST(DBUSMENUGLIB_LIBS)
###########################
GTK_REQUIRED_VERSION=2.16
-
-PKG_CHECK_MODULES(DBUSMENUGTK, gtk+-2.0 >= $GTK_REQUIRED_VERSION
- glib-2.0 >= $GLIB_REQUIRED_VERSION
- dbus-glib-1 >= $DBUS_REQUIRED_VERSION
- libxml-2.0 >= $XML_REQUIRED_VERSION)
-
-AC_SUBST(DBUSMENUGTK_CFLAGS)
-AC_SUBST(DBUSMENUGTK_LIBS)
+GTK3_REQUIRED_VERSION=2.91
+
+AC_ARG_WITH([gtk],
+ [AS_HELP_STRING([--with-gtk],
+ [Which version of gtk to use @<:@default=2@:>@])],
+ [],
+ [with_gtk=2])
+AS_IF([test "x$with_gtk" = x3],
+ [PKG_CHECK_MODULES(DBUSMENUGTK, gtk+-3.0 >= $GTK3_REQUIRED_VERSION
+ glib-2.0 >= $GLIB_REQUIRED_VERSION
+ libxml-2.0 >= $XML_REQUIRED_VERSION)
+ AC_SUBST(DBUSMENUGTK_CFLAGS)
+ AC_SUBST(DBUSMENUGTK_LIBS)
+ AC_DEFINE(HAVE_GTK3, 1, [whether gtk3 is available])
+ ],
+ [test "x$with_gtk" = x2],
+ [PKG_CHECK_MODULES(DBUSMENUGTK, gtk+-2.0 >= $GTK_REQUIRED_VERSION
+ glib-2.0 >= $GLIB_REQUIRED_VERSION
+ libxml-2.0 >= $XML_REQUIRED_VERSION)
+ AC_SUBST(DBUSMENUGTK_CFLAGS)
+ AC_SUBST(DBUSMENUGTK_LIBS)
+ ],
+ [AC_MSG_FAILURE([Value for --with-gtk was neither 2 nor 3])]
+)
+AM_CONDITIONAL(USE_GTK3, [test "x$with_gtk" = x3])
###########################
# Dependencies - dumper
@@ -88,6 +113,12 @@ AC_SUBST(DBUSMENUTESTS_LIBS)
GOBJECT_INTROSPECTION_CHECK([0.6.7])
+PKG_CHECK_EXISTS([gobject-introspection-1.0 >= 0.10],
+ introspection_ten=yes,
+ introspection_ten=no)
+
+AM_CONDITIONAL(INTROSPECTION_TEN, [test "x$introspection_ten" = "xyes"])
+
###########################
# Vala API Generation
###########################
@@ -95,11 +126,17 @@ GOBJECT_INTROSPECTION_CHECK([0.6.7])
AC_PATH_PROG([VALA_API_GEN], [vapigen])
###########################
+# XSLT Processor
+###########################
+
+AC_PATH_PROG([XSLT_PROC], [xsltproc])
+
+###########################
# Lib versioning
###########################
-LIBDBUSMENU_CURRENT=1
-LIBDBUSMENU_REVISION=17
+LIBDBUSMENU_CURRENT=3
+LIBDBUSMENU_REVISION=4
LIBDBUSMENU_AGE=0
AC_SUBST(LIBDBUSMENU_CURRENT)
@@ -134,13 +171,14 @@ AC_OUTPUT([
Makefile
po/Makefile.in
libdbusmenu-glib/Makefile
-libdbusmenu-glib/dbusmenu-glib.pc
+libdbusmenu-glib/dbusmenu-glib-0.4.pc
libdbusmenu-gtk/Makefile
-libdbusmenu-gtk/dbusmenu-gtk.pc
+libdbusmenu-gtk/dbusmenu-gtk-0.4.pc
+libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc
tools/Makefile
tools/testapp/Makefile
tests/Makefile
-tests/dbusmenu-jsonloader.pc
+tests/dbusmenu-jsonloader-0.4.pc
docs/Makefile
docs/libdbusmenu-glib/Makefile
docs/libdbusmenu-glib/reference/Makefile
@@ -160,5 +198,6 @@ libdbusmenu Configuration:
Prefix: $prefix
Massive Debugging: $with_massivedebugging
+ GTK+ Version: $with_gtk
])
diff --git a/docs/libdbusmenu-gtk/reference/Makefile.am b/docs/libdbusmenu-gtk/reference/Makefile.am
index ec1bd28..191d68e 100644
--- a/docs/libdbusmenu-gtk/reference/Makefile.am
+++ b/docs/libdbusmenu-gtk/reference/Makefile.am
@@ -1,5 +1,12 @@
+
## Process this file with automake to produce Makefile.in
+if USE_GTK3
+VER=3
+else
+VER=
+endif
+
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
@@ -9,7 +16,7 @@ AUTOMAKE_OPTIONS = 1.6
# of using the various options.
# The name of the module, e.g. 'glib'.
-DOC_MODULE=libdbusmenu-gtk
+DOC_MODULE=libdbusmenu-gtk$(VER)
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
@@ -47,7 +54,7 @@ CFILE_GLOB=$(top_srcdir)/libdbusmenu-gtk/*.c
# Header files to ignore when scanning.
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES=
+IGNORE_HFILES=genericmenuitem.h
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
@@ -68,7 +75,7 @@ expand_content_files=
# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
INCLUDES=-I$(top_srcdir) $(DBUSMENUGLIB_CFLAGS) $(DBUSMENUGTK_CFLAGS)
-GTKDOC_LIBS=$(top_builddir)/libdbusmenu-gtk/libdbusmenu-gtk.la
+GTKDOC_LIBS=$(top_builddir)/libdbusmenu-gtk/libdbusmenu-gtk$(VER).la $(DBUSMENUGLIB_LIBS) $(DBUSMENUGTK_LIBS)
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.local.make
diff --git a/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml b/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
index ae9ab07..ec6b82f 100644
--- a/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
+++ b/docs/libdbusmenu-gtk/reference/libdbusmenu-gtk-docs.sgml
@@ -13,8 +13,8 @@
<title>API</title>
<xi:include href="xml/menu.xml"/>
<xi:include href="xml/client.xml"/>
- <xi:include href="xml/genericmenuitem.xml"/>
<xi:include href="xml/menuitem.xml"/>
+ <xi:include href="xml/serializablemenuitem.xml"/>
</chapter>
<chapter id="object-tree">
diff --git a/libdbusmenu-glib/Makefile.am b/libdbusmenu-glib/Makefile.am
index 0a6513f..a139f7c 100644
--- a/libdbusmenu-glib/Makefile.am
+++ b/libdbusmenu-glib/Makefile.am
@@ -2,7 +2,8 @@
CLEANFILES =
EXTRA_DIST = \
- dbusmenu-glib.pc.in \
+ clean-namespaces.xslt \
+ dbusmenu-glib-0.4.pc.in \
dbus-menu.xml \
client-marshal.list \
menuitem-marshal.list \
@@ -11,17 +12,18 @@ EXTRA_DIST = \
lib_LTLIBRARIES = \
libdbusmenu-glib.la
-libdbusmenu_glibincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-glib/
+libdbusmenu_glibincludedir=$(includedir)/libdbusmenu-0.4/libdbusmenu-glib/
libdbusmenu_glibinclude_HEADERS = \
+ dbusmenu-glib.h \
menuitem.h \
menuitem-proxy.h \
server.h \
client.h
libdbusmenu_glib_la_SOURCES = \
- dbusmenu-server.h \
- dbusmenu-client.h \
+ dbus-menu-clean.xml.h \
+ dbus-menu-clean.xml.c \
menuitem.h \
menuitem.c \
menuitem-marshal.h \
@@ -51,12 +53,25 @@ libdbusmenu_glib_la_CFLAGS = \
libdbusmenu_glib_la_LIBADD = \
$(DBUSMENUGLIB_LIBS)
-pkgconfig_DATA = dbusmenu-glib.pc
+pkgconfig_DATA = dbusmenu-glib-0.4.pc
pkgconfigdir = $(libdir)/pkgconfig
+%.xml.h: %.xml
+ echo "extern const char * $(subst -,_,$(subst .,_,$(basename $(notdir $@))));" > $@
+
+%.xml.c: %.xml
+ echo "const char * $(subst -,_,$(subst .,_,$(basename $(notdir $@)))) = " > $@
+ sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@
+ echo ";" >> $@
+
+dbus-menu-clean.xml: dbus-menu.xml
+ $(XSLT_PROC) $(srcdir)/clean-namespaces.xslt $< > $@ || (rm -f $@ && /bin/false)
+
+CLEANFILES += dbus-menu-clean.xml
+
BUILT_SOURCES = \
- dbusmenu-client.h \
- dbusmenu-server.h \
+ dbus-menu-clean.xml.c \
+ dbus-menu-clean.xml.h \
client-marshal.h \
client-marshal.c \
menuitem-marshal.h \
@@ -64,19 +79,7 @@ BUILT_SOURCES = \
server-marshal.h \
server-marshal.c
-dbusmenu-server.h: dbus-menu.xml
- dbus-binding-tool \
- --prefix=_dbusmenu_server \
- --mode=glib-server \
- --output=dbusmenu-server.h \
- $(srcdir)/dbus-menu.xml
-
-dbusmenu-client.h: dbus-menu.xml
- dbus-binding-tool \
- --prefix=_dbusmenu_client \
- --mode=glib-client \
- --output=dbusmenu-client.h \
- $(srcdir)/dbus-menu.xml
+CLEANFILES += $(BUILT_SOURCES)
client-marshal.h: $(srcdir)/client-marshal.list
glib-genmarshal --header \
@@ -114,25 +117,39 @@ menuitem-marshal.c: $(srcdir)/menuitem-marshal.list
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = \
- --add-include-path=$(srcdir) \
- $(addprefix --c-include=libdbusmenu-glib/, $(introspection_sources))
+
+if INTROSPECTION_TEN
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) \
+ --warn-all \
+ --add-include-path=$(srcdir) \
+ $(addprefix --c-include=libdbusmenu-glib/, $(introspection_sources)) \
+ --symbol-prefix=dbusmenu \
+ --identifier-prefix=Dbusmenu
+else
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) \
+ --warn-all \
+ --add-include-path=$(srcdir) \
+ $(addprefix --c-include=libdbusmenu-glib/, $(introspection_sources))
+endif
+
INTROSPECTION_COMPILER_ARGS = --includedir=$(builddir)
if HAVE_INTROSPECTION
introspection_sources = $(libdbusmenu_glibinclude_HEADERS)
-Dbusmenu_Glib-0.2.gir: libdbusmenu-glib.la
-Dbusmenu_Glib_0_2_gir_INCLUDES = \
+Dbusmenu_Glib-0.4.gir: libdbusmenu-glib.la
+Dbusmenu_Glib_0_4_gir_INCLUDES = \
GObject-2.0
-Dbusmenu_Glib_0_2_gir_CFLAGS = $(DBUSMENUGLIB_CFLAGS)
-Dbusmenu_Glib_0_2_gir_LIBS = libdbusmenu-glib.la
-Dbusmenu_Glib_0_2_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
-Dbusmenu_Glib_0_2_gir_NAMESPACE = Dbusmenu
-Dbusmenu_Glib_0_2_gir_VERSION = Glib-0.2
+Dbusmenu_Glib_0_4_gir_CFLAGS = $(DBUSMENUGLIB_CFLAGS) -I$(top_srcdir)
+Dbusmenu_Glib_0_4_gir_LIBS = libdbusmenu-glib.la
+Dbusmenu_Glib_0_4_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
+Dbusmenu_Glib_0_4_gir_NAMESPACE = Dbusmenu
+Dbusmenu_Glib_0_4_gir_VERSION = Glib-0.4
+Dbusmenu_Glib_0_4_gir_EXPORT_PACKAGES = dbusmenu-glib-0.4
+Dbusmenu_Glib_0_4_gir_SCANNER_FLAGS = $(INTROSPECTION_SCANNER_ARGS)
-INTROSPECTION_GIRS += Dbusmenu-Glib-0.2.gir
+INTROSPECTION_GIRS += Dbusmenu-Glib-0.4.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
@@ -151,10 +168,10 @@ endif
if HAVE_INTROSPECTION
vapidir = $(datadir)/vala/vapi
-vapi_DATA = Dbusmenu-Glib-0.2.vapi
+vapi_DATA = Dbusmenu-Glib-0.4.vapi
-Dbusmenu-Glib-0.2.vapi: Dbusmenu-Glib-0.2.gir
- $(VALA_API_GEN) --library=Dbusmenu-Glib-0.2 $<
+Dbusmenu-Glib-0.4.vapi: Dbusmenu-Glib-0.4.gir
+ $(VALA_API_GEN) --library=Dbusmenu-Glib-0.4 $<
CLEANFILES += $(vapi_DATA)
diff --git a/libdbusmenu-glib/clean-namespaces.xslt b/libdbusmenu-glib/clean-namespaces.xslt
new file mode 100644
index 0000000..8c0c521
--- /dev/null
+++ b/libdbusmenu-glib/clean-namespaces.xslt
@@ -0,0 +1,14 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dox="http://www.canonical.com/dbus/dox.dtd">
+ <xsl:template match="*|@*">
+ <xsl:copy>
+ <xsl:apply-templates select="*|@*" />
+ </xsl:copy>
+ </xsl:template>
+ <xsl:template match="@dox:*|dox:*"/>
+ <xsl:template match="*">
+ <xsl:element name="{local-name()}">
+ <xsl:apply-templates select="@* | node()"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet>
+
diff --git a/libdbusmenu-glib/client-marshal.list b/libdbusmenu-glib/client-marshal.list
index 2e14491..866dfa8 100644
--- a/libdbusmenu-glib/client-marshal.list
+++ b/libdbusmenu-glib/client-marshal.list
@@ -1,2 +1,2 @@
VOID: OBJECT, UINT
-VOID: OBJECT, STRING, POINTER, UINT, POINTER
+VOID: OBJECT, STRING, VARIANT, UINT, POINTER
diff --git a/libdbusmenu-glib/client-menuitem.c b/libdbusmenu-glib/client-menuitem.c
index 9c21065..0f14b85 100644
--- a/libdbusmenu-glib/client-menuitem.c
+++ b/libdbusmenu-glib/client-menuitem.c
@@ -45,7 +45,7 @@ static void dbusmenu_client_menuitem_class_init (DbusmenuClientMenuitemClass *kl
static void dbusmenu_client_menuitem_init (DbusmenuClientMenuitem *self);
static void dbusmenu_client_menuitem_dispose (GObject *object);
static void dbusmenu_client_menuitem_finalize (GObject *object);
-static void handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+static void handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp);
static void send_about_to_show (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gpointer user_data), gpointer cb_data);
G_DEFINE_TYPE (DbusmenuClientMenuitem, dbusmenu_client_menuitem, DBUSMENU_TYPE_MENUITEM);
@@ -102,10 +102,10 @@ dbusmenu_client_menuitem_new (gint id, DbusmenuClient * client)
/* Passes the event signal on through the client. */
static void
-handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp)
+handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * variant, guint timestamp)
{
DbusmenuClientMenuitemPrivate * priv = DBUSMENU_CLIENT_MENUITEM_GET_PRIVATE(mi);
- dbusmenu_client_send_event(priv->client, dbusmenu_menuitem_get_id(mi), name, value, timestamp);
+ dbusmenu_client_send_event(priv->client, dbusmenu_menuitem_get_id(mi), name, variant, timestamp);
return;
}
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index ca16c9a..cb90789 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -30,7 +30,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
@@ -39,9 +39,13 @@ License version 3 and version 2.1 along with this program. If not, see
#include "menuitem.h"
#include "menuitem-private.h"
#include "client-menuitem.h"
-#include "dbusmenu-client.h"
#include "server-marshal.h"
#include "client-marshal.h"
+#include "dbus-menu-clean.xml.h"
+
+/* How many property requests should we queue before
+ sending the message on dbus */
+#define MAX_PROPERTIES_TO_QUEUE 100
/* Properties */
enum {
@@ -60,9 +64,10 @@ enum {
LAST_SIGNAL
};
+typedef void (*properties_func) (GVariant * properties, GError * error, gpointer user_data);
+
static guint signals[LAST_SIGNAL] = { 0 };
-typedef struct _DbusmenuClientPrivate DbusmenuClientPrivate;
struct _DbusmenuClientPrivate
{
DbusmenuMenuitem * root;
@@ -70,15 +75,18 @@ struct _DbusmenuClientPrivate
gchar * dbus_object;
gchar * dbus_name;
- DBusGConnection * session_bus;
- DBusGProxy * menuproxy;
- DBusGProxy * propproxy;
- DBusGProxyCall * layoutcall;
+ GDBusConnection * session_bus;
+ GCancellable * session_bus_cancel;
+
+ GDBusProxy * menuproxy;
+ GCancellable * menuproxy_cancel;
+
+ GCancellable * layoutcall;
gint current_revision;
gint my_revision;
- DBusGProxy * dbusproxy;
+ guint dbusproxy;
GHashTable * type_handlers;
@@ -98,7 +106,7 @@ struct _newItemPropData
typedef struct _properties_listener_t properties_listener_t;
struct _properties_listener_t {
gint id;
- org_ayatana_dbusmenu_get_properties_reply callback;
+ properties_func callback;
gpointer user_data;
gboolean replied;
};
@@ -108,13 +116,28 @@ struct _event_data_t {
DbusmenuClient * client;
DbusmenuMenuitem * menuitem;
gchar * event;
- GValue data;
+ GVariant * variant;
guint timestamp;
};
+typedef struct _type_handler_t type_handler_t;
+struct _type_handler_t {
+ DbusmenuClient * client;
+ DbusmenuClientTypeHandler cb;
+ DbusmenuClientTypeDestroyHandler destroy_cb;
+ gpointer user_data;
+ gchar * type;
+};
+
+typedef struct _properties_callback_t properties_callback_t;
+struct _properties_callback_t {
+ DbusmenuClient * client;
+ GArray * listeners;
+};
+
-#define DBUSMENU_CLIENT_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_CLIENT, DbusmenuClientPrivate))
+#define DBUSMENU_CLIENT_GET_PRIVATE(o) (DBUSMENU_CLIENT(o)->priv)
+#define DBUSMENU_INTERFACE "com.canonical.dbusmenu"
/* GObject Stuff */
static void dbusmenu_client_class_init (DbusmenuClientClass *klass);
@@ -124,19 +147,27 @@ static void dbusmenu_client_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);
/* Private Funcs */
-static void layout_update (DBusGProxy * proxy, guint revision, gint parent, DbusmenuClient * client);
-static void id_prop_update (DBusGProxy * proxy, gint id, gchar * property, GValue * value, DbusmenuClient * client);
-static void id_update (DBusGProxy * proxy, gint id, DbusmenuClient * client);
+static void layout_update (GDBusProxy * proxy, guint revision, gint parent, DbusmenuClient * client);
+static void id_prop_update (GDBusProxy * proxy, gint id, gchar * property, GVariant * value, DbusmenuClient * client);
+static void id_update (GDBusProxy * proxy, gint id, DbusmenuClient * client);
static void build_proxies (DbusmenuClient * client);
static gint parse_node_get_id (xmlNodePtr node);
-static DbusmenuMenuitem * parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, DBusGProxy * proxy);
+static DbusmenuMenuitem * parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy);
static gint parse_layout (DbusmenuClient * client, const gchar * layout);
-static void update_layout_cb (DBusGProxy * proxy, guint rev, gchar * xml, GError * in_error, void * data);
+static void update_layout_cb (GObject * proxy, GAsyncResult * res, gpointer data);
static void update_layout (DbusmenuClient * client);
-static void menuitem_get_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data);
-static void get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, org_ayatana_dbusmenu_get_properties_reply callback, gpointer user_data);
+static void menuitem_get_properties_cb (GVariant * properties, GError * error, gpointer data);
+static void get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, properties_func callback, gpointer user_data);
static GQuark error_domain (void);
-static void item_activated (DBusGProxy * proxy, gint id, guint timestamp, DbusmenuClient * client);
+static void item_activated (GDBusProxy * proxy, gint id, guint timestamp, DbusmenuClient * client);
+static void menuproxy_build_cb (GObject * object, GAsyncResult * res, gpointer user_data);
+static void menuproxy_name_changed_cb (GObject * object, GParamSpec * pspec, gpointer user_data);
+static void menuproxy_signal_cb (GDBusProxy * proxy, gchar * sender, gchar * signal, GVariant * params, gpointer user_data);
+static void type_handler_destroy (gpointer user_data);
+
+/* Globals */
+static GDBusNodeInfo * dbusmenu_node_info = NULL;
+static GDBusInterfaceInfo * dbusmenu_interface_info = NULL;
/* Build a type */
G_DEFINE_TYPE (DbusmenuClient, dbusmenu_client, G_TYPE_OBJECT);
@@ -234,8 +265,8 @@ dbusmenu_client_class_init (DbusmenuClientClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (DbusmenuClientClass, event_result),
NULL, NULL,
- _dbusmenu_client_marshal_VOID__OBJECT_STRING_POINTER_UINT_POINTER,
- G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_POINTER);
+ _dbusmenu_client_marshal_VOID__OBJECT_STRING_VARIANT_UINT_POINTER,
+ G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_VARIANT, G_TYPE_UINT, G_TYPE_POINTER);
g_object_class_install_property (object_class, PROP_DBUSOBJECT,
g_param_spec_string(DBUSMENU_CLIENT_PROP_DBUS_OBJECT, "DBus Object we represent",
@@ -248,12 +279,32 @@ dbusmenu_client_class_init (DbusmenuClientClass *klass)
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ if (dbusmenu_node_info == NULL) {
+ GError * error = NULL;
+
+ dbusmenu_node_info = g_dbus_node_info_new_for_xml(dbus_menu_clean_xml, &error);
+ if (error != NULL) {
+ g_error("Unable to parse DBusmenu Interface description: %s", error->message);
+ g_error_free(error);
+ }
+ }
+
+ if (dbusmenu_interface_info == NULL) {
+ dbusmenu_interface_info = g_dbus_node_info_lookup_interface(dbusmenu_node_info, DBUSMENU_INTERFACE);
+
+ if (dbusmenu_interface_info == NULL) {
+ g_error("Unable to find interface '" DBUSMENU_INTERFACE "'");
+ }
+ }
+
return;
}
static void
dbusmenu_client_init (DbusmenuClient *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_TYPE_CLIENT, DbusmenuClientPrivate);
+
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(self);
priv->root = NULL;
@@ -262,17 +313,20 @@ dbusmenu_client_init (DbusmenuClient *self)
priv->dbus_name = NULL;
priv->session_bus = NULL;
+ priv->session_bus_cancel = NULL;
+
priv->menuproxy = NULL;
- priv->propproxy = NULL;
+ priv->menuproxy_cancel = NULL;
+
priv->layoutcall = NULL;
priv->current_revision = 0;
priv->my_revision = 0;
- priv->dbusproxy = NULL;
+ priv->dbusproxy = 0;
priv->type_handlers = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, NULL);
+ g_free, type_handler_destroy);
priv->delayed_idle = 0;
priv->delayed_property_list = g_array_new(TRUE, FALSE, sizeof(gchar *));
@@ -313,7 +367,7 @@ dbusmenu_client_dispose (GObject *object)
if (localerror == NULL) {
g_set_error_literal(&localerror, error_domain(), 0, "DbusmenuClient Shutdown");
}
- listener->callback(priv->menuproxy, NULL, localerror, listener->user_data);
+ listener->callback(NULL, localerror, listener->user_data);
}
}
if (localerror != NULL) {
@@ -325,22 +379,39 @@ dbusmenu_client_dispose (GObject *object)
}
if (priv->layoutcall != NULL) {
- dbus_g_proxy_cancel_call(priv->menuproxy, priv->layoutcall);
+ g_cancellable_cancel(priv->layoutcall);
+ g_object_unref(priv->layoutcall);
priv->layoutcall = NULL;
}
+
+ /* Bring down the menu proxy, ensure we're not
+ looking for one at the same time. */
+ if (priv->menuproxy_cancel != NULL) {
+ g_cancellable_cancel(priv->menuproxy_cancel);
+ g_object_unref(priv->menuproxy_cancel);
+ priv->menuproxy_cancel = NULL;
+ }
if (priv->menuproxy != NULL) {
g_object_unref(G_OBJECT(priv->menuproxy));
priv->menuproxy = NULL;
}
- if (priv->propproxy != NULL) {
- g_object_unref(G_OBJECT(priv->propproxy));
- priv->propproxy = NULL;
+
+ if (priv->dbusproxy != 0) {
+ g_bus_unwatch_name(priv->dbusproxy);
+ priv->dbusproxy = 0;
+ }
+
+ /* Bring down the session bus, ensure we're not
+ looking for one at the same time. */
+ if (priv->session_bus_cancel != NULL) {
+ g_cancellable_cancel(priv->session_bus_cancel);
+ g_object_unref(priv->session_bus_cancel);
+ priv->session_bus_cancel = NULL;
}
- if (priv->dbusproxy != NULL) {
- g_object_unref(G_OBJECT(priv->dbusproxy));
- priv->dbusproxy = NULL;
+ if (priv->session_bus != NULL) {
+ g_object_unref(priv->session_bus);
+ priv->session_bus = NULL;
}
- priv->session_bus = NULL;
if (priv->root != NULL) {
g_object_unref(G_OBJECT(priv->root));
@@ -445,47 +516,38 @@ find_listener (GArray * listeners, guint index, gint id)
/* Call back from getting the group properties, now we need
to unwind and call the various functions. */
static void
-get_properties_callback (DBusGProxy *proxy, GPtrArray *OUT_properties, GError *error, gpointer userdata)
+get_properties_callback (GObject *obj, GAsyncResult * res, gpointer user_data)
{
- GArray * listeners = (GArray *)userdata;
+ properties_callback_t * cbdata = (properties_callback_t *)user_data;
+ GArray * listeners = cbdata->listeners;
int i;
+ GError * error = NULL;
+ GVariant * params = NULL;
- #ifdef MASSIVEDEBUGGING
- g_debug("Get properties callback: %d", OUT_properties->len);
- #endif
+ params = g_dbus_proxy_call_finish(G_DBUS_PROXY(obj), res, &error);
if (error != NULL) {
/* If we get an error, all our callbacks need to hear about it. */
g_warning("Group Properties error: %s", error->message);
for (i = 0; i < listeners->len; i++) {
properties_listener_t * listener = &g_array_index(listeners, properties_listener_t, i);
- listener->callback(proxy, NULL, error, listener->user_data);
+ listener->callback(NULL, error, listener->user_data);
}
- g_array_free(listeners, TRUE);
- return;
+ g_error_free(error);
+ goto out;
}
/* Callback all the folks we can find */
- for (i = 0; i < OUT_properties->len; i++) {
- GValueArray * varray = (GValueArray *)g_ptr_array_index(OUT_properties, i);
-
- if (varray->n_values != 2) {
- g_warning("Value Array is %d entries long but we expected 2.", varray->n_values);
+ GVariantIter * iter = g_variant_iter_new(g_variant_get_child_value(params, 0));
+ GVariant * child;
+ while ((child = g_variant_iter_next_value(iter)) != NULL) {
+ if (g_strcmp0(g_variant_get_type_string(child), "(ia{sv})") != 0) {
+ g_warning("Properties return signature is not '(ia{sv})' it is '%s'", g_variant_get_type_string(child));
continue;
}
- GValue * vid = g_value_array_get_nth(varray, 0);
- GValue * vproperties = g_value_array_get_nth(varray, 1);
-
- if (G_VALUE_TYPE(vid) != G_TYPE_INT) {
- g_warning("ID Entry not holding an int: %s", G_VALUE_TYPE_NAME(vid));
- }
- if (G_VALUE_TYPE(vproperties) != dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) {
- g_warning("Properties Entry not holding an a{sv}: %s", G_VALUE_TYPE_NAME(vproperties));
- }
-
- gint id = g_value_get_int(vid);
- GHashTable * properties = g_value_get_boxed(vproperties);
+ gint id = g_variant_get_int32(g_variant_get_child_value(child, 0));
+ GVariant * properties = g_variant_get_child_value(child, 1);
properties_listener_t * listener = find_listener(listeners, 0, id);
if (listener == NULL) {
@@ -494,30 +556,36 @@ get_properties_callback (DBusGProxy *proxy, GPtrArray *OUT_properties, GError *e
}
if (!listener->replied) {
- listener->callback(proxy, properties, NULL, listener->user_data);
+ listener->callback(properties, NULL, listener->user_data);
listener->replied = TRUE;
} else {
g_warning("Odd, we've already replied to the listener on ID %d", id);
}
}
+ g_variant_iter_free(iter);
+ g_variant_unref(params);
/* Provide errors for those who we can't */
GError * localerror = NULL;
for (i = 0; i < listeners->len; i++) {
properties_listener_t * listener = &g_array_index(listeners, properties_listener_t, i);
if (!listener->replied) {
+ g_warning("Generating properties error for: %d", listener->id);
if (localerror == NULL) {
g_set_error_literal(&localerror, error_domain(), 0, "Error getting properties for ID");
}
- listener->callback(proxy, NULL, localerror, listener->user_data);
+ listener->callback(NULL, localerror, listener->user_data);
}
}
if (localerror != NULL) {
g_error_free(localerror);
}
+out:
/* Clean up */
g_array_free(listeners, TRUE);
+ g_object_unref(cbdata->client);
+ g_free(user_data);
return;
}
@@ -527,8 +595,9 @@ get_properties_callback (DBusGProxy *proxy, GPtrArray *OUT_properties, GError *e
static gboolean
get_properties_idle (gpointer user_data)
{
+ properties_callback_t * cbdata = NULL;
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(user_data);
- //org_ayatana_dbusmenu_get_properties_async(priv->menuproxy, id, properties, callback, user_data);
+ g_return_val_if_fail(priv->menuproxy != NULL, TRUE);
if (priv->delayed_property_listeners->len == 0) {
g_warning("Odd, idle func got no listeners.");
@@ -536,16 +605,40 @@ get_properties_idle (gpointer user_data)
}
/* Build up an ID list to pass */
- GArray * idlist = g_array_new(FALSE, FALSE, sizeof(gint));
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+
gint i;
for (i = 0; i < priv->delayed_property_listeners->len; i++) {
- g_array_append_val(idlist, g_array_index(priv->delayed_property_listeners, properties_listener_t, i).id);
+ g_variant_builder_add(&builder, "i", g_array_index(priv->delayed_property_listeners, properties_listener_t, i).id);
}
- org_ayatana_dbusmenu_get_group_properties_async(priv->menuproxy, idlist, (const gchar **)priv->delayed_property_list->data, get_properties_callback, priv->delayed_property_listeners);
+ GVariant * variant_ids = g_variant_builder_end(&builder);
+
+ /* Build up a prop list to pass */
+ g_variant_builder_init(&builder, g_variant_type_new("as"));
+ /* TODO: need to use delayed property list here */
+ GVariant * variant_props = g_variant_builder_end(&builder);
- /* Free ID List */
- g_array_free(idlist, TRUE);
+ /* Combine them into a value for the parameter */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&builder, variant_ids);
+ g_variant_builder_add_value(&builder, variant_props);
+ GVariant * variant_params = g_variant_builder_end(&builder);
+
+ cbdata = g_new(properties_callback_t, 1);
+ cbdata->listeners = priv->delayed_property_listeners;
+ cbdata->client = DBUSMENU_CLIENT(user_data);
+ g_object_ref(G_OBJECT(user_data));
+
+ g_dbus_proxy_call(priv->menuproxy,
+ "GetGroupProperties",
+ variant_params,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout */
+ NULL, /* cancellable */
+ get_properties_callback,
+ cbdata);
/* Free properties */
gchar ** dataregion = (gchar **)g_array_free(priv->delayed_property_list, FALSE);
@@ -579,22 +672,20 @@ get_properties_flush (DbusmenuClient * client)
get_properties_idle(client);
- dbus_g_connection_flush(priv->session_bus);
-
return;
}
/* A function to group all the get_properties commands to make them
more efficient over dbus. */
static void
-get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, org_ayatana_dbusmenu_get_properties_reply callback, gpointer user_data)
+get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, properties_func callback, gpointer user_data)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
if (find_listener(priv->delayed_property_listeners, 0, id) != NULL) {
g_warning("Asking for properties from same ID twice: %d", id);
GError * localerror = NULL;
g_set_error_literal(&localerror, error_domain(), 0, "ID already queued");
- callback(priv->menuproxy, NULL, localerror, user_data);
+ callback(NULL, localerror, user_data);
g_error_free(localerror);
return;
}
@@ -628,12 +719,19 @@ get_properties_globber (DbusmenuClient * client, gint id, const gchar ** propert
priv->delayed_idle = g_idle_add(get_properties_idle, client);
}
+ /* Look at how many proprites we have queued up and
+ make it so that we don't leave too many in one
+ request. */
+ if (priv->delayed_property_listeners->len == MAX_PROPERTIES_TO_QUEUE) {
+ get_properties_flush(client);
+ }
+
return;
}
/* Called when a server item wants to activate the menu */
static void
-item_activated (DBusGProxy * proxy, gint id, guint timestamp, DbusmenuClient * client)
+item_activated (GDBusProxy * proxy, gint id, guint timestamp, DbusmenuClient * client)
{
g_return_if_fail(DBUSMENU_IS_CLIENT(client));
@@ -657,7 +755,7 @@ item_activated (DBusGProxy * proxy, gint id, guint timestamp, DbusmenuClient * c
/* Annoying little wrapper to make the right function update */
static void
-layout_update (DBusGProxy * proxy, guint revision, gint parent, DbusmenuClient * client)
+layout_update (GDBusProxy * proxy, guint revision, gint parent, DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
priv->current_revision = revision;
@@ -670,16 +768,8 @@ layout_update (DBusGProxy * proxy, guint revision, gint parent, DbusmenuClient *
/* Signal from the server that a property has changed
on one of our menuitems */
static void
-id_prop_update (DBusGProxy * proxy, gint id, gchar * property, GValue * value, DbusmenuClient * client)
+id_prop_update (GDBusProxy * proxy, gint id, gchar * property, GVariant * value, DbusmenuClient * client)
{
- #ifdef MASSIVEDEBUGGING
- GValue valstr = {0};
- g_value_init(&valstr, G_TYPE_STRING);
- g_value_transform(value, &valstr);
- g_debug("Property change sent to client for item %d property %s value %s", id, property, g_utf8_strlen(g_value_get_string(&valstr), 50) < 25 ? g_value_get_string(&valstr) : "<too long>");
- g_value_unset(&valstr);
- #endif
-
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
g_return_if_fail(priv->root != NULL);
@@ -692,7 +782,7 @@ id_prop_update (DBusGProxy * proxy, gint id, gchar * property, GValue * value, D
return;
}
- dbusmenu_menuitem_property_set_value(menuitem, property, value);
+ dbusmenu_menuitem_property_set_variant(menuitem, property, value);
return;
}
@@ -700,7 +790,7 @@ id_prop_update (DBusGProxy * proxy, gint id, gchar * property, GValue * value, D
/* Oh, lots of updates now. That silly server, they want
to change all kinds of stuff! */
static void
-id_update (DBusGProxy * proxy, gint id, DbusmenuClient * client)
+id_update (GDBusProxy * proxy, gint id, DbusmenuClient * client)
{
#ifdef MASSIVEDEBUGGING
g_debug("Client side ID update: %d", id);
@@ -720,83 +810,39 @@ id_update (DBusGProxy * proxy, gint id, DbusmenuClient * client)
/* Watches to see if our DBus savior comes onto the bus */
static void
-dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, DbusmenuClient * client)
+dbus_owner_change (GDBusConnection * connection, const gchar * name, const gchar * owner, gpointer user_data)
{
- DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- /* g_debug("Owner change: %s %s %s", name, prev, new); */
-
- if (!(new[0] != '\0' && prev[0] == '\0')) {
- /* If it's not someone new getting on the bus, sorry we
- simply just don't care. It's not that your service isn't
- important to someone, just not us. You'll find the right
- process someday, there's lots of processes out there. */
- return;
- }
+ g_return_if_fail(DBUSMENU_IS_CLIENT(user_data));
- if (g_strcmp0(name, priv->dbus_name)) {
- /* Again, someone else's service. */
- return;
- }
+ DbusmenuClient * client = DBUSMENU_CLIENT(user_data);
/* Woot! A service for us to love and to hold for ever
and ever and ever! */
return build_proxies(client);
}
-/* This is the response to see if the name has an owner. If
- it does, then we should build the proxies here. Race condition
- check. */
-static void
-name_owner_check (DBusGProxy *proxy, gboolean has_owner, GError *error, gpointer userdata)
-{
- if (error != NULL) {
- return;
- }
-
- if (!has_owner) {
- return;
- }
-
- DbusmenuClient * client = DBUSMENU_CLIENT(userdata);
- build_proxies(client);
- return;
-}
-
/* This function builds the DBus proxy which will look out for
the service coming up. */
static void
build_dbus_proxy (DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- GError * error = NULL;
- if (priv->dbusproxy != NULL) {
+ if (priv->dbusproxy != 0) {
return;
}
- priv->dbusproxy = dbus_g_proxy_new_for_name_owner (priv->session_bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &error);
- if (error != NULL) {
- g_debug("Oh, that's bad. That's really bad. We can't get a proxy to DBus itself? Seriously? Here's all I know: %s", error->message);
- g_error_free(error);
- return;
- }
-
- dbus_g_proxy_add_signal(priv->dbusproxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->dbusproxy, "NameOwnerChanged",
- G_CALLBACK(dbus_owner_change), client, NULL);
+ priv->dbusproxy = g_bus_watch_name_on_connection(priv->session_bus,
+ priv->dbus_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ dbus_owner_change,
+ NULL,
+ client,
+ NULL);
/* Now let's check to make sure we're not in some race
condition case. */
- org_freedesktop_DBus_name_has_owner_async(priv->dbusproxy,
- priv->dbus_name,
- name_owner_check,
- client);
+ /* TODO: Not sure how to check for names in GDBus */
return;
}
@@ -820,7 +866,11 @@ proxy_destroyed (GObject * gobj_proxy, gpointer userdata)
}
if ((gpointer)priv->menuproxy == (gpointer)gobj_proxy) {
- priv->layoutcall = NULL;
+ if (priv->layoutcall != NULL) {
+ g_cancellable_cancel(priv->layoutcall);
+ g_object_unref(priv->layoutcall);
+ priv->layoutcall = NULL;
+ }
}
priv->current_revision = 0;
@@ -830,75 +880,197 @@ proxy_destroyed (GObject * gobj_proxy, gpointer userdata)
return;
}
+/* Respond to us getting the session bus (hopefully) or handle
+ the error if not */
+void
+session_bus_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+{
+ GError * error = NULL;
+
+ /* NOTE: We're not using any other variables before checking
+ the result because they could be destroyed and thus invalid */
+ GDBusConnection * bus = g_bus_get_finish(res, &error);
+ if (error != NULL) {
+ g_warning("Unable to get session bus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* If this wasn't cancelled, we should be good */
+ DbusmenuClient * client = DBUSMENU_CLIENT(user_data);
+ DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+ priv->session_bus = bus;
+
+ if (priv->session_bus_cancel != NULL) {
+ g_object_unref(priv->session_bus_cancel);
+ priv->session_bus_cancel = NULL;
+ }
+
+ /* Retry to build the proxies now that we have a bus */
+ build_proxies(DBUSMENU_CLIENT(user_data));
+
+ return;
+}
+
/* When we have a name and an object, build the two proxies and get the
first version of the layout */
static void
build_proxies (DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- GError * error = NULL;
g_return_if_fail(priv->dbus_object != NULL);
g_return_if_fail(priv->dbus_name != NULL);
- priv->session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (error != NULL) {
- g_error("Unable to get session bus: %s", error->message);
- g_error_free(error);
- build_dbus_proxy(client);
+ if (priv->session_bus == NULL) {
+ /* We don't have the session bus yet, that's okay, but
+ we need to handle that. */
+
+ /* If we're already running we don't need to look again. */
+ if (priv->session_bus_cancel == NULL) {
+ priv->session_bus_cancel = g_cancellable_new();
+
+ /* Async get the session bus */
+ g_bus_get(G_BUS_TYPE_SESSION, priv->session_bus_cancel, session_bus_cb, client);
+ }
+
+ /* This function exists, it'll be called again when we get
+ the session bus so this condition will be ignored */
return;
}
- priv->propproxy = dbus_g_proxy_new_for_name_owner(priv->session_bus,
- priv->dbus_name,
- priv->dbus_object,
- DBUS_INTERFACE_PROPERTIES,
- &error);
- if (error != NULL) {
- g_warning("Unable to get property proxy for %s on %s: %s", priv->dbus_name, priv->dbus_object, error->message);
- g_error_free(error);
- build_dbus_proxy(client);
- return;
+ /* Build us a menu proxy */
+ if (priv->menuproxy == NULL) {
+
+ /* Check to see if we're already building one */
+ if (priv->menuproxy_cancel == NULL) {
+ priv->menuproxy_cancel = g_cancellable_new();
+
+ g_dbus_proxy_new(priv->session_bus,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ dbusmenu_interface_info,
+ priv->dbus_name,
+ priv->dbus_object,
+ DBUSMENU_INTERFACE,
+ priv->menuproxy_cancel,
+ menuproxy_build_cb,
+ client);
+ }
}
- g_object_add_weak_pointer(G_OBJECT(priv->propproxy), (gpointer *)&priv->propproxy);
- g_signal_connect(G_OBJECT(priv->propproxy), "destroy", G_CALLBACK(proxy_destroyed), client);
- priv->menuproxy = dbus_g_proxy_new_for_name_owner(priv->session_bus,
- priv->dbus_name,
- priv->dbus_object,
- "org.ayatana.dbusmenu",
- &error);
+ return;
+}
+
+/* Callback when we know if the menu proxy can be created or
+ not and do something with it! */
+static void
+menuproxy_build_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+{
+ GError * error = NULL;
+
+ /* NOTE: We're not using any other variables before checking
+ the result because they could be destroyed and thus invalid */
+ GDBusProxy * proxy = g_dbus_proxy_new_finish(res, &error);
if (error != NULL) {
- g_warning("Unable to get dbusmenu proxy for %s on %s: %s", priv->dbus_name, priv->dbus_object, error->message);
+ g_warning("Unable to get menu proxy: %s", error->message);
g_error_free(error);
- build_dbus_proxy(client);
return;
}
- g_object_add_weak_pointer(G_OBJECT(priv->menuproxy), (gpointer *)&priv->menuproxy);
- g_signal_connect(G_OBJECT(priv->menuproxy), "destroy", G_CALLBACK(proxy_destroyed), client);
+
+ /* If this wasn't cancelled, we should be good */
+ DbusmenuClient * client = DBUSMENU_CLIENT(user_data);
+ DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+ priv->menuproxy = proxy;
+
+ if (priv->menuproxy_cancel != NULL) {
+ g_object_unref(priv->menuproxy_cancel);
+ priv->menuproxy_cancel = NULL;
+ }
/* If we get here, we don't need the DBus proxy */
- if (priv->dbusproxy != NULL) {
- g_object_unref(G_OBJECT(priv->dbusproxy));
- priv->dbusproxy = NULL;
+ if (priv->dbusproxy != 0) {
+ g_bus_unwatch_name(priv->dbusproxy);
+ priv->dbusproxy = 0;
}
- dbus_g_object_register_marshaller(_dbusmenu_server_marshal_VOID__UINT_INT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID);
- dbus_g_proxy_add_signal(priv->menuproxy, "LayoutUpdated", G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "LayoutUpdated", G_CALLBACK(layout_update), client, NULL);
+ g_signal_connect(priv->menuproxy, "g-signal", G_CALLBACK(menuproxy_signal_cb), client);
+ g_signal_connect(priv->menuproxy, "notify::g-name-owner", G_CALLBACK(menuproxy_name_changed_cb), client);
- dbus_g_object_register_marshaller(_dbusmenu_server_marshal_VOID__INT_STRING_POINTER, G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
- dbus_g_proxy_add_signal(priv->menuproxy, "ItemPropertyUpdated", G_TYPE_INT, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "ItemPropertyUpdated", G_CALLBACK(id_prop_update), client, NULL);
+ gchar * name_owner = g_dbus_proxy_get_name_owner(priv->menuproxy);
+ if (name_owner != NULL) {
+ update_layout(client);
+ g_free(name_owner);
+ }
- dbus_g_proxy_add_signal(priv->menuproxy, "ItemUpdated", G_TYPE_INT, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "ItemUpdated", G_CALLBACK(id_update), client, NULL);
+ return;
+}
- dbus_g_object_register_marshaller(_dbusmenu_server_marshal_VOID__INT_UINT, G_TYPE_NONE, G_TYPE_INT, G_TYPE_UINT, G_TYPE_INVALID);
- dbus_g_proxy_add_signal(priv->menuproxy, "ItemActivationRequested", G_TYPE_INT, G_TYPE_UINT, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "ItemActivationRequested", G_CALLBACK(item_activated), client, NULL);
+/* Handle the case where we change owners */
+static void
+menuproxy_name_changed_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
+{
+ GDBusProxy * proxy = G_DBUS_PROXY(object);
- update_layout(client);
+ gchar * owner = g_dbus_proxy_get_name_owner(proxy);
+
+ if (owner == NULL) {
+ /* Oh, no! We lost our owner! */
+ proxy_destroyed(G_OBJECT(proxy), user_data);
+ } else {
+ g_free(owner);
+ update_layout(DBUSMENU_CLIENT(user_data));
+ }
+
+ return;
+}
+
+/* Handle the signals out of the proxy */
+static void
+menuproxy_signal_cb (GDBusProxy * proxy, gchar * sender, gchar * signal, GVariant * params, gpointer user_data)
+{
+ g_return_if_fail(DBUSMENU_IS_CLIENT(user_data));
+ DbusmenuClient * client = DBUSMENU_CLIENT(user_data);
+
+ if (g_strcmp0(signal, "LayoutUpdated") == 0) {
+ guint revision; gint parent;
+ g_variant_get(params, "(ui)", &revision, &parent);
+ layout_update(proxy, revision, parent, client);
+ } else if (g_strcmp0(signal, "ItemPropertiesUpdated") == 0) {
+ GVariantIter items;
+ g_variant_iter_init(&items, g_variant_get_child_value(params, 0));
+
+ GVariant * item;
+ while ((item = g_variant_iter_next_value(&items)) != NULL) {
+ gint id = g_variant_get_int32(g_variant_get_child_value(item, 0));
+ GVariantIter properties;
+ g_variant_iter_init(&properties, g_variant_get_child_value(item, 1));
+ gchar * property;
+ GVariant * value;
+
+ while (g_variant_iter_next(&properties, "{sv}", &property, &value)) {
+ GVariant * internalvalue = value;
+ if (G_LIKELY(g_variant_is_of_type(value, G_VARIANT_TYPE_VARIANT))) {
+ /* Unboxing if needed */
+ internalvalue = g_variant_get_variant(value);
+ }
+ id_prop_update(proxy, id, property, internalvalue, client);
+ }
+ }
+ } else if (g_strcmp0(signal, "ItemPropertyUpdated") == 0) {
+ gint id; gchar * property; GVariant * value;
+ g_variant_get(params, "(isv)", &id, &property, &value);
+ id_prop_update(proxy, id, property, value, client);
+ } else if (g_strcmp0(signal, "ItemUpdated") == 0) {
+ gint id;
+ g_variant_get(params, "(i)", &id);
+ id_update(proxy, id, client);
+ } else if (g_strcmp0(signal, "ItemActivationRequested") == 0) {
+ gint id; guint timestamp;
+ g_variant_get(params, "(iu)", &id, &timestamp);
+ item_activated(proxy, id, timestamp, client);
+ } else {
+ g_warning("Received signal '%s' from menu proxy that is unknown", signal);
+ }
return;
}
@@ -937,32 +1109,38 @@ parse_node_get_id (xmlNodePtr node)
return -1;
}
-/* A small helper that calls _property_set on each hash table
- entry in the properties hash. */
-static void
-get_properties_helper (gpointer key, gpointer value, gpointer data)
-{
- dbusmenu_menuitem_property_set_value((DbusmenuMenuitem *)data, (gchar *)key, (GValue *)value);
- return;
-}
-
/* This is the callback for the properties on a menu item. There
should be all of them in the Hash, and they we use foreach to
copy them into the menuitem.
This isn't the most efficient way. We can optimize this by
somehow removing the foreach. But that is for later. */
static void
-menuitem_get_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
+menuitem_get_properties_cb (GVariant * properties, GError * error, gpointer data)
{
g_return_if_fail(DBUSMENU_IS_MENUITEM(data));
+ DbusmenuMenuitem * item = DBUSMENU_MENUITEM(data);
+
if (error != NULL) {
g_warning("Error getting properties on a menuitem: %s", error->message);
g_object_unref(data);
return;
}
- g_hash_table_foreach(properties, get_properties_helper, data);
- g_hash_table_destroy(properties);
+
+ GVariantIter * iter = g_variant_iter_new(properties);
+ gchar * key;
+ GVariant * value;
+
+ while (g_variant_iter_next(iter, "{sv}", &key, &value)) {
+ dbusmenu_menuitem_property_set_variant(item, key, value);
+
+ g_variant_unref(value);
+ g_free(key);
+ }
+
+ g_variant_iter_free(iter);
+
g_object_unref(data);
+
return;
}
@@ -970,7 +1148,7 @@ menuitem_get_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError
is getting recycled with the update, but we think might have prop
changes. */
static void
-menuitem_get_properties_replace_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
+menuitem_get_properties_replace_cb (GVariant * properties, GError * error, gpointer data)
{
g_return_if_fail(DBUSMENU_IS_MENUITEM(data));
gboolean have_error = FALSE;
@@ -983,14 +1161,14 @@ menuitem_get_properties_replace_cb (DBusGProxy * proxy, GHashTable * properties,
GList * current_props = NULL;
for (current_props = dbusmenu_menuitem_properties_list(DBUSMENU_MENUITEM(data));
- current_props != NULL ; current_props = g_list_next(current_props)) {
- if (have_error || g_hash_table_lookup(properties, current_props->data) == NULL) {
- dbusmenu_menuitem_property_remove(DBUSMENU_MENUITEM(data), (const gchar *)current_props->data);
- }
+ current_props != NULL && have_error == FALSE;
+ current_props = g_list_next(current_props)) {
+ dbusmenu_menuitem_property_remove(DBUSMENU_MENUITEM(data), (const gchar *)current_props->data);
}
+ g_list_free(current_props);
if (!have_error) {
- menuitem_get_properties_cb(proxy, properties, error, data);
+ menuitem_get_properties_cb(properties, error, data);
} else {
g_object_unref(data);
}
@@ -1001,7 +1179,7 @@ menuitem_get_properties_replace_cb (DBusGProxy * proxy, GHashTable * properties,
/* This is a different get properites call back that also sends
new signals. It basically is a small wrapper around the original. */
static void
-menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
+menuitem_get_properties_new_cb (GVariant * properties, GError * error, gpointer data)
{
g_return_if_fail(data != NULL);
newItemPropData * propdata = (newItemPropData *)data;
@@ -1009,7 +1187,6 @@ menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GEr
if (error != NULL) {
g_warning("Error getting properties on a new menuitem: %s", error->message);
g_object_unref(propdata->item);
- g_free(data);
return;
}
@@ -1017,22 +1194,22 @@ menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GEr
/* Extra ref as get_properties will unref once itself */
g_object_ref(propdata->item);
- menuitem_get_properties_cb (proxy, properties, error, propdata->item);
+ menuitem_get_properties_cb (properties, error, propdata->item);
gboolean handled = FALSE;
const gchar * type;
- DbusmenuClientTypeHandler newfunc = NULL;
+ type_handler_t * th = NULL;
type = dbusmenu_menuitem_property_get(propdata->item, DBUSMENU_MENUITEM_PROP_TYPE);
if (type != NULL) {
- newfunc = g_hash_table_lookup(priv->type_handlers, type);
+ th = (type_handler_t *)g_hash_table_lookup(priv->type_handlers, type);
} else {
- newfunc = g_hash_table_lookup(priv->type_handlers, DBUSMENU_CLIENT_TYPES_DEFAULT);
+ th = (type_handler_t *)g_hash_table_lookup(priv->type_handlers, DBUSMENU_CLIENT_TYPES_DEFAULT);
}
- if (newfunc != NULL) {
- handled = newfunc(propdata->item, propdata->parent, propdata->client);
+ if (th != NULL && th->cb != NULL) {
+ handled = th->cb(propdata->item, propdata->parent, propdata->client, th->user_data);
}
#ifdef MASSIVEDEBUGGING
@@ -1053,28 +1230,39 @@ menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GEr
/* Respond to the call function to make sure that the other side
got it, or print a warning. */
static void
-menuitem_call_cb (DBusGProxy * proxy, GError * error, gpointer userdata)
+menuitem_call_cb (GObject * proxy, GAsyncResult * res, gpointer userdata)
{
+ GError * error = NULL;
event_data_t * edata = (event_data_t *)userdata;
+ GVariant * params;
+
+ params = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error);
if (error != NULL) {
g_warning("Unable to call event '%s' on menu item %d: %s", edata->event, dbusmenu_menuitem_get_id(edata->menuitem), error->message);
}
- g_signal_emit(edata->client, signals[EVENT_RESULT], 0, edata->menuitem, edata->event, &edata->data, edata->timestamp, error, TRUE);
+ g_signal_emit(edata->client, signals[EVENT_RESULT], 0, edata->menuitem, edata->event, edata->variant, edata->timestamp, error, TRUE);
- g_value_unset(&edata->data);
+ g_variant_unref(edata->variant);
g_free(edata->event);
g_object_unref(edata->menuitem);
g_free(edata);
+ if (G_UNLIKELY(error != NULL)) {
+ g_error_free(error);
+ }
+ if (G_LIKELY(params != NULL)) {
+ g_variant_unref(params);
+ }
+
return;
}
/* Sends the event over DBus to the server on the other side
of the bus. */
void
-dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name, const GValue * value, guint timestamp)
+dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name, GVariant * variant, guint timestamp)
{
g_return_if_fail(DBUSMENU_IS_CLIENT(client));
g_return_if_fail(id >= 0);
@@ -1087,11 +1275,8 @@ dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name
return;
}
- if (value == NULL) {
- GValue internalval = {0};
- g_value_init(&internalval, G_TYPE_INT);
- g_value_set_int(&internalval, 0);
- value = &internalval;
+ if (variant == NULL) {
+ variant = g_variant_new_int32(0);
}
event_data_t * edata = g_new0(event_data_t, 1);
@@ -1099,15 +1284,18 @@ dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name
edata->menuitem = mi;
g_object_ref(edata->menuitem);
edata->event = g_strdup(name);
- g_value_init(&edata->data, G_VALUE_TYPE(value));
- g_value_copy(value, &edata->data);
edata->timestamp = timestamp;
-
- DBusGAsyncData *stuff;
- stuff = g_slice_new (DBusGAsyncData);
- stuff->cb = G_CALLBACK (menuitem_call_cb);
- stuff->userdata = edata;
- dbus_g_proxy_begin_call_with_timeout (priv->menuproxy, "Event", org_ayatana_dbusmenu_event_async_callback, stuff, _dbus_glib_async_data_free, 1000, G_TYPE_INT, id, G_TYPE_STRING, name, G_TYPE_VALUE, value, G_TYPE_UINT, timestamp, G_TYPE_INVALID);
+ edata->variant = variant;
+ g_variant_ref(variant);
+
+ g_dbus_proxy_call(priv->menuproxy,
+ "Event",
+ g_variant_new("(isvu)", id, name, variant, timestamp),
+ G_DBUS_CALL_FLAGS_NONE,
+ 1000, /* timeout */
+ NULL, /* cancellable */
+ menuitem_call_cb,
+ edata);
return;
}
@@ -1122,14 +1310,24 @@ struct _about_to_show_t {
/* Reports errors and responds to update request that were a result
of sending the about to show signal. */
static void
-about_to_show_cb (DBusGProxy * proxy, gboolean need_update, GError * error, gpointer userdata)
+about_to_show_cb (GObject * proxy, GAsyncResult * res, gpointer userdata)
{
+ gboolean need_update = FALSE;
+ GError * error = NULL;
about_to_show_t * data = (about_to_show_t *)userdata;
+ GVariant * params = NULL;
+
+ params = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error);
if (error != NULL) {
g_warning("Unable to send about_to_show: %s", error->message);
/* Note: we're just ensuring only the callback gets called */
need_update = FALSE;
+ g_error_free(error);
+ error = NULL;
+ } else {
+ g_variant_get(params, "(b)", &need_update);
+ g_variant_unref(params);
}
/* If we need to update, do that first. */
@@ -1160,7 +1358,14 @@ dbusmenu_client_send_about_to_show(DbusmenuClient * client, gint id, void (*cb)(
data->cb_data = cb_data;
g_object_ref(client);
- org_ayatana_dbusmenu_about_to_show_async (priv->menuproxy, id, about_to_show_cb, data);
+ g_dbus_proxy_call(priv->menuproxy,
+ "AboutToShow",
+ g_variant_new("(i)", id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout */
+ NULL, /* cancellable */
+ about_to_show_cb,
+ data);
return;
}
@@ -1206,7 +1411,7 @@ parse_layout_update (DbusmenuMenuitem * item, DbusmenuClient * client)
/* Parse recursively through the XML and make it into
objects as need be */
static DbusmenuMenuitem *
-parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, DBusGProxy * proxy)
+parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy)
{
/* First verify and figure out what we've got */
gint id = parse_node_get_id(node);
@@ -1283,8 +1488,10 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
/* We've got everything built up at this node and reconcilled */
- /* Flush the properties requests */
- get_properties_flush(client);
+ /* Flush the properties requests if this is the first level */
+ if (parent != NULL && dbusmenu_menuitem_get_id(parent) == 0) {
+ get_properties_flush(client);
+ }
/* now it's time to recurse down the tree. */
children = node->children;
@@ -1377,24 +1584,38 @@ parse_layout (DbusmenuClient * client, const gchar * layout)
/* When the layout property returns, here's where we take care of that. */
static void
-update_layout_cb (DBusGProxy * proxy, guint rev, gchar * xml, GError * error, void * data)
+update_layout_cb (GObject * proxy, GAsyncResult * res, gpointer data)
{
DbusmenuClient * client = DBUSMENU_CLIENT(data);
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+ GError * error = NULL;
+ GVariant * params = NULL;
+
+ params = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error);
+
if (error != NULL) {
- g_warning("Getting layout failed on client %s object %s: %s", priv->dbus_name, priv->dbus_object, error->message);
- return;
+ g_warning("Getting layout failed: %s", error->message);
+ g_error_free(error);
+ goto out;
}
- if (!parse_layout(client, xml)) {
+ guint rev;
+ gchar * xml;
+
+ g_variant_get(params, "(us)", &rev, &xml);
+ g_variant_unref(params);
+
+ guint parseable = parse_layout(client, xml);
+ g_free(xml);
+
+ if (parseable == 0) {
g_warning("Unable to parse layout!");
- return;
+ goto out;
}
priv->my_revision = rev;
/* g_debug("Root is now: 0x%X", (unsigned int)priv->root); */
- priv->layoutcall = NULL;
#ifdef MASSIVEDEBUGGING
g_debug("Client signaling layout has changed.");
#endif
@@ -1406,6 +1627,13 @@ update_layout_cb (DBusGProxy * proxy, guint rev, gchar * xml, GError * error, vo
update_layout(client);
}
+out:
+ if (priv->layoutcall != NULL) {
+ g_object_unref(priv->layoutcall);
+ priv->layoutcall = NULL;
+ }
+
+ g_object_unref(G_OBJECT(client));
return;
}
@@ -1420,14 +1648,27 @@ update_layout (DbusmenuClient * client)
return;
}
+ gchar * name_owner = g_dbus_proxy_get_name_owner(priv->menuproxy);
+ if (name_owner == NULL) {
+ return;
+ }
+ g_free(name_owner);
+
if (priv->layoutcall != NULL) {
return;
}
- priv->layoutcall = org_ayatana_dbusmenu_get_layout_async(priv->menuproxy,
- 0, /* Parent is the root */
- update_layout_cb,
- client);
+ priv->layoutcall = g_cancellable_new();
+
+ g_object_ref(G_OBJECT(client));
+ g_dbus_proxy_call(priv->menuproxy,
+ "GetLayout",
+ g_variant_new("(i)", 0), /* root */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout */
+ priv->layoutcall, /* cancellable */
+ update_layout_cb,
+ client);
return;
}
@@ -1480,10 +1721,6 @@ dbusmenu_client_get_root (DbusmenuClient * client)
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- if (priv->propproxy == NULL) {
- return NULL;
- }
-
#ifdef MASSIVEDEBUGGING
g_debug("Client get root: %X", (guint)priv->root);
#endif
@@ -1491,6 +1728,19 @@ dbusmenu_client_get_root (DbusmenuClient * client)
return priv->root;
}
+/* Remove the type handler when we're all done with it */
+static void
+type_handler_destroy (gpointer user_data)
+{
+ type_handler_t * th = (type_handler_t *)user_data;
+ if (th->destroy_cb != NULL) {
+ th->destroy_cb(th->client, th->type, th->user_data);
+ }
+ g_free(th->type);
+ g_free(th);
+ return;
+}
+
/**
dbusmenu_client_add_type_handler:
@client: Client where we're getting types coming in
@@ -1515,6 +1765,37 @@ dbusmenu_client_get_root (DbusmenuClient * client)
gboolean
dbusmenu_client_add_type_handler (DbusmenuClient * client, const gchar * type, DbusmenuClientTypeHandler newfunc)
{
+ return dbusmenu_client_add_type_handler_full(client, type, newfunc, NULL, NULL);
+}
+
+/**
+ dbusmenu_client_add_type_handler_full:
+ @client: Client where we're getting types coming in
+ @type: A text string that will be matched with the 'type'
+ property on incoming menu items
+ @newfunc: The function that will be executed with those new
+ items when they come in.
+ @user_data: Data passed to @newfunc when it is called
+ @destroy_func: A function that is called when the type handler is
+ removed (usually on client destruction) which will free
+ the resources in @user_data.
+
+ This function connects into the type handling of the #DbusmenuClient.
+ Every new menuitem that comes in immediately gets asked for it's
+ properties. When we get those properties we check the 'type'
+ property and look to see if it matches a handler that is known
+ by the client. If so, the @newfunc function is executed on that
+ #DbusmenuMenuitem. If not, then the DbusmenuClient::new-menuitem
+ signal is sent.
+
+ In the future the known types will be sent to the server so that it
+ can make choices about the menu item types availble.
+
+ Return value: If registering the new type was successful.
+*/
+gboolean
+dbusmenu_client_add_type_handler_full (DbusmenuClient * client, const gchar * type, DbusmenuClientTypeHandler newfunc, gpointer user_data, DbusmenuClientTypeDestroyHandler destroy_func)
+{
g_return_val_if_fail(DBUSMENU_IS_CLIENT(client), FALSE);
g_return_val_if_fail(type != NULL, FALSE);
@@ -1535,6 +1816,14 @@ dbusmenu_client_add_type_handler (DbusmenuClient * client, const gchar * type, D
return FALSE;
}
- g_hash_table_insert(priv->type_handlers, g_strdup(type), newfunc);
+ type_handler_t * th = g_new0(type_handler_t, 1);
+ th->client = client;
+ th->cb = newfunc;
+ th->destroy_cb = destroy_func;
+ th->user_data = user_data;
+ th->type = g_strdup(type);
+
+ g_hash_table_insert(priv->type_handlers, g_strdup(type), th);
return TRUE;
}
+
diff --git a/libdbusmenu-glib/client.h b/libdbusmenu-glib/client.h
index 5d4b5c3..6d78edf 100644
--- a/libdbusmenu-glib/client.h
+++ b/libdbusmenu-glib/client.h
@@ -56,6 +56,8 @@ G_BEGIN_DECLS
#define DBUSMENU_CLIENT_TYPES_SEPARATOR "separator"
#define DBUSMENU_CLIENT_TYPES_IMAGE "standard"
+typedef struct _DbusmenuClientPrivate DbusmenuClientPrivate;
+
/**
DbusmenuClientClass:
@parent_class: #GObjectClass
@@ -65,6 +67,10 @@ G_BEGIN_DECLS
@event_result: Slot for #DbusmenuClient::event-error.
@reserved1: Reserved for future use.
@reserved2: Reserved for future use.
+ @reserved3: Reserved for future use.
+ @reserved4: Reserved for future use.
+ @reserved5: Reserved for future use.
+ @reserved6: Reserved for future use.
A simple class that takes all of the information from a
#DbusmenuServer over DBus and makes the same set of
@@ -78,13 +84,15 @@ struct _DbusmenuClientClass {
void (*root_changed) (DbusmenuMenuitem * newroot);
void (*new_menuitem) (DbusmenuMenuitem * newitem);
void (*item_activate) (DbusmenuMenuitem * item, guint timestamp);
- void (*event_result) (DbusmenuMenuitem * item, gchar * event, GValue * data, guint timestamp, GError * error);
+ void (*event_result) (DbusmenuMenuitem * item, gchar * event, GVariant * data, guint timestamp, GError * error);
- /* Reserved for future use */
+ /*< Private >*/
void (*reserved1) (void);
void (*reserved2) (void);
- /* void (*reserved3) (void); */
- /* void (*reserved4) (void); */
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
};
/**
@@ -97,9 +105,34 @@ struct _DbusmenuClientClass {
typedef struct _DbusmenuClient DbusmenuClient;
struct _DbusmenuClient {
GObject parent;
+
+ /*< Private >*/
+ DbusmenuClientPrivate * priv;
};
-typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+/**
+ DbusmenuClientTypeHandler:
+ @newitem: The #DbusmenuMenuitem that was created
+ @parent: The parent of @newitem or #NULL if none
+ @client: A pointer to the #DbusmenuClient
+ @user_data: The data you gave us
+
+ The type handler is called when a dbusmenu item is created
+ with a matching type as setup in #dbusmenu_client_add_type_handler
+*/
+typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
+
+/**
+ DbusmenuClientTypeDestroyHandler:
+ @client: A pointer to the #DbusmenuClient
+ @type: The type that this handler was registered with
+ @user_data: The data you gave us
+
+ This handler is called when the type becomes unregistered by the
+ client. This is usally caused by the #DbusmenuClient being destroyed
+ and should free memory or unref objects in @user_data.
+*/
+typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data);
GType dbusmenu_client_get_type (void);
DbusmenuClient * dbusmenu_client_new (const gchar * name,
@@ -108,10 +141,15 @@ DbusmenuMenuitem * dbusmenu_client_get_root (DbusmenuClient * client)
gboolean dbusmenu_client_add_type_handler (DbusmenuClient * client,
const gchar * type,
DbusmenuClientTypeHandler newfunc);
+gboolean dbusmenu_client_add_type_handler_full (DbusmenuClient * client,
+ const gchar * type,
+ DbusmenuClientTypeHandler newfunc,
+ gpointer user_data,
+ DbusmenuClientTypeDestroyHandler destory_func);
void dbusmenu_client_send_event (DbusmenuClient * client,
gint id,
const gchar * name,
- const GValue * value,
+ GVariant * variant,
guint timestamp);
void dbusmenu_client_send_about_to_show(DbusmenuClient * client,
gint id,
diff --git a/libdbusmenu-glib/dbus-menu.xml b/libdbusmenu-glib/dbus-menu.xml
index 82de533..4a4d166 100644
--- a/libdbusmenu-glib/dbus-menu.xml
+++ b/libdbusmenu-glib/dbus-menu.xml
@@ -28,15 +28,15 @@ 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/>
-->
-<node name="/" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
+<node name="/" xmlns:dox="http://www.canonical.com/dbus/dox.dtd">
<dox:d><![CDATA[
@mainpage
The goal of DBusMenu is to expose menus on DBus.
- Main interface is documented here: @ref org::ayatana::dbusmenu
+ Main interface is documented here: @ref com::canonical::dbusmenu
]]></dox:d>
- <interface name="org.ayatana.dbusmenu">
+ <interface name="com.canonical.dbusmenu">
<dox:d><![CDATA[
A DBus interface to expose menus on DBus.
diff --git a/libdbusmenu-glib/dbusmenu-glib.pc.in b/libdbusmenu-glib/dbusmenu-glib-0.4.pc.in
index dacd903..31a1eac 100644
--- a/libdbusmenu-glib/dbusmenu-glib.pc.in
+++ b/libdbusmenu-glib/dbusmenu-glib-0.4.pc.in
@@ -4,8 +4,8 @@ libdir=@libdir@
bindir=@bindir@
includedir=@includedir@
-Cflags: -I${includedir}/libdbusmenu-0.1
-Requires: dbus-glib-1
+Cflags: -I${includedir}/libdbusmenu-0.4
+Requires:
Libs: -L${libdir} -ldbusmenu-glib
Name: libdbusmenu-glib
diff --git a/libdbusmenu-glib/dbusmenu-glib.h b/libdbusmenu-glib/dbusmenu-glib.h
new file mode 100644
index 0000000..9c377ca
--- /dev/null
+++ b/libdbusmenu-glib/dbusmenu-glib.h
@@ -0,0 +1,37 @@
+/*
+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_GLIB_H__
+#define __DBUSMENU_GLIB_H__
+
+#include <libdbusmenu-glib/client.h>
+#include <libdbusmenu-glib/menuitem.h>
+#include <libdbusmenu-glib/menuitem-proxy.h>
+#include <libdbusmenu-glib/server.h>
+
+#endif /* __DBUSMENU_GLIB_H__ */
diff --git a/libdbusmenu-glib/menuitem-marshal.list b/libdbusmenu-glib/menuitem-marshal.list
index 654c91b..e3cb272 100644
--- a/libdbusmenu-glib/menuitem-marshal.list
+++ b/libdbusmenu-glib/menuitem-marshal.list
@@ -1,4 +1,4 @@
-VOID: STRING, POINTER
+VOID: STRING, VARIANT
VOID: OBJECT, UINT, UINT
VOID: OBJECT, UINT
VOID: OBJECT
diff --git a/libdbusmenu-glib/menuitem-private.h b/libdbusmenu-glib/menuitem-private.h
index 3a0c026..2028464 100644
--- a/libdbusmenu-glib/menuitem-private.h
+++ b/libdbusmenu-glib/menuitem-private.h
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
void dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array);
gboolean dbusmenu_menuitem_realized (DbusmenuMenuitem * mi);
void dbusmenu_menuitem_set_realized (DbusmenuMenuitem * mi);
+GVariant * dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi);
G_END_DECLS
diff --git a/libdbusmenu-glib/menuitem-proxy.c b/libdbusmenu-glib/menuitem-proxy.c
index 2dd5ada..1d97c4c 100644
--- a/libdbusmenu-glib/menuitem-proxy.c
+++ b/libdbusmenu-glib/menuitem-proxy.c
@@ -32,7 +32,6 @@ License version 3 and version 2.1 along with this program. If not, see
#include "menuitem-proxy.h"
-typedef struct _DbusmenuMenuitemProxyPrivate DbusmenuMenuitemProxyPrivate;
struct _DbusmenuMenuitemProxyPrivate {
DbusmenuMenuitem * mi;
gulong sig_property_changed;
@@ -49,8 +48,7 @@ enum {
#define PROP_MENU_ITEM_S "menu-item"
-#define DBUSMENU_MENUITEM_PROXY_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_MENUITEM_PROXY, DbusmenuMenuitemProxyPrivate))
+#define DBUSMENU_MENUITEM_PROXY_GET_PRIVATE(o) (DBUSMENU_MENUITEM_PROXY(o)->priv)
static void dbusmenu_menuitem_proxy_class_init (DbusmenuMenuitemProxyClass *klass);
static void dbusmenu_menuitem_proxy_init (DbusmenuMenuitemProxy *self);
@@ -58,7 +56,7 @@ static void dbusmenu_menuitem_proxy_dispose (GObject *object);
static void dbusmenu_menuitem_proxy_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);
-static void handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+static void handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * variant, guint timestamp);
static void add_menuitem (DbusmenuMenuitemProxy * pmi, DbusmenuMenuitem * mi);
static void remove_menuitem (DbusmenuMenuitemProxy * pmi);
@@ -92,6 +90,8 @@ dbusmenu_menuitem_proxy_class_init (DbusmenuMenuitemProxyClass *klass)
static void
dbusmenu_menuitem_proxy_init (DbusmenuMenuitemProxy *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_TYPE_MENUITEM_PROXY, DbusmenuMenuitemProxyPrivate);
+
DbusmenuMenuitemProxyPrivate * priv = DBUSMENU_MENUITEM_PROXY_GET_PRIVATE(self);
priv->mi = NULL;
@@ -162,21 +162,21 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
/* Takes the event and passes it along to the item that we're
playing proxy for. */
static void
-handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp)
+handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * variant, guint timestamp)
{
g_return_if_fail(DBUSMENU_IS_MENUITEM_PROXY(mi));
DbusmenuMenuitemProxyPrivate * priv = DBUSMENU_MENUITEM_PROXY_GET_PRIVATE(mi);
g_return_if_fail(priv->mi != NULL);
- return dbusmenu_menuitem_handle_event(priv->mi, name, value, timestamp);
+ return dbusmenu_menuitem_handle_event(priv->mi, name, variant, timestamp);
}
/* Watches a property change and makes sure to put that value
into our property list. */
static void
-proxy_item_property_changed (DbusmenuMenuitem * mi, gchar * property, GValue * value, gpointer user_data)
+proxy_item_property_changed (DbusmenuMenuitem * mi, gchar * property, GVariant * variant, gpointer user_data)
{
DbusmenuMenuitemProxy * pmi = DBUSMENU_MENUITEM_PROXY(user_data);
- dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(pmi), property, value);
+ dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(pmi), property, variant);
return;
}
@@ -273,7 +273,7 @@ add_menuitem (DbusmenuMenuitemProxy * pmi, DbusmenuMenuitem * mi)
GList * prop;
for (prop = props; prop != NULL; prop = g_list_next(prop)) {
gchar * prop_name = (gchar *)prop->data;
- dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(pmi), prop_name, dbusmenu_menuitem_property_get_value(priv->mi, prop_name));
+ dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(pmi), prop_name, dbusmenu_menuitem_property_get_variant(priv->mi, prop_name));
}
g_list_free(props);
diff --git a/libdbusmenu-glib/menuitem-proxy.h b/libdbusmenu-glib/menuitem-proxy.h
index 56c4941..2a22efe 100644
--- a/libdbusmenu-glib/menuitem-proxy.h
+++ b/libdbusmenu-glib/menuitem-proxy.h
@@ -42,17 +42,28 @@ G_BEGIN_DECLS
#define DBUSMENU_IS_MENUITEM_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_TYPE_MENUITEM_PROXY))
#define DBUSMENU_MENUITEM_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_TYPE_MENUITEM_PROXY, DbusmenuMenuitemProxyClass))
-typedef struct _DbusmenuMenuitemProxy DbusmenuMenuitemProxy;
-typedef struct _DbusmenuMenuitemProxyClass DbusmenuMenuitemProxyClass;
+typedef struct _DbusmenuMenuitemProxy DbusmenuMenuitemProxy;
+typedef struct _DbusmenuMenuitemProxyClass DbusmenuMenuitemProxyClass;
+typedef struct _DbusmenuMenuitemProxyPrivate DbusmenuMenuitemProxyPrivate;
/**
DbusmenuMenuitemProxyClass:
@parent_class: The Class of #DbusmeneMenuitem
+ @reserved1: Reserved for future use.
+ @reserved2: Reserved for future use.
+ @reserved3: Reserved for future use.
+ @reserved4: Reserved for future use.
Functions and signal slots for #DbusmenuMenuitemProxy.
*/
struct _DbusmenuMenuitemProxyClass {
DbusmenuMenuitemClass parent_class;
+
+ /*< Private >*/
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
};
/**
@@ -63,6 +74,9 @@ struct _DbusmenuMenuitemProxyClass {
*/
struct _DbusmenuMenuitemProxy {
DbusmenuMenuitem parent;
+
+ /*< Private >*/
+ DbusmenuMenuitemProxyPrivate * priv;
};
GType dbusmenu_menuitem_proxy_get_type (void);
diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c
index ef037d1..159463b 100644
--- a/libdbusmenu-glib/menuitem.c
+++ b/libdbusmenu-glib/menuitem.c
@@ -52,7 +52,6 @@ License version 3 and version 2.1 along with this program. If not, see
out of data that we have. They can still be gotten using
accessor functions, but are protected appropriately.
*/
-typedef struct _DbusmenuMenuitemPrivate DbusmenuMenuitemPrivate;
struct _DbusmenuMenuitemPrivate
{
gint id;
@@ -71,6 +70,7 @@ enum {
CHILD_MOVED,
REALIZED,
SHOW_TO_USER,
+ ABOUT_TO_SHOW,
LAST_SIGNAL
};
@@ -84,8 +84,7 @@ enum {
#define PROP_ID_S "id"
-#define DBUSMENU_MENUITEM_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_MENUITEM, DbusmenuMenuitemPrivate))
+#define DBUSMENU_MENUITEM_GET_PRIVATE(o) (DBUSMENU_MENUITEM(o)->priv)
/* Prototypes */
static void dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass);
@@ -96,7 +95,7 @@ static void set_property (GObject * obj, guint id, const GValue * value, GParamS
static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec);
static void g_value_transform_STRING_BOOLEAN (const GValue * in, GValue * out);
static void g_value_transform_STRING_INT (const GValue * in, GValue * out);
-static void handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+static void handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp);
static void send_about_to_show (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gpointer user_data), gpointer cb_data);
/* GObject stuff */
@@ -131,8 +130,8 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuMenuitemClass, property_changed),
NULL, NULL,
- _dbusmenu_menuitem_marshal_VOID__STRING_POINTER,
- G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+ _dbusmenu_menuitem_marshal_VOID__STRING_VARIANT,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT);
/**
DbusmenuMenuitem::item-activated:
@arg0: The #DbusmenuMenuitem object.
@@ -231,6 +230,21 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass)
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT, G_TYPE_NONE);
+ /**
+ DbusmenuMenuitem::about-to-show:
+ @arg0: The #DbusmenuMenuitem object.
+
+ Emitted when the submenu for this item
+ is about to be shown
+ */
+ signals[ABOUT_TO_SHOW] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, about_to_show),
+ NULL, NULL,
+ _dbusmenu_menuitem_marshal_VOID__VOID,
+ G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
+
g_object_class_install_property (object_class, PROP_ID,
g_param_spec_int(PROP_ID_S, "ID for the menu item",
"This is a unique indentifier for the menu item.",
@@ -273,15 +287,12 @@ g_value_transform_STRING_INT (const GValue * in, GValue * out)
static gint menuitem_next_id = 1;
-/* A small little function to both clear the insides of a
- value as well as the memory it itself uses. */
+/* Make the unref function match the prototype need for the
+ hashtable destructor */
static void
-_g_value_free (gpointer data)
+_g_variant_unref (gpointer data)
{
- if (data == NULL) return;
- GValue * value = (GValue*)data;
- g_value_unset(value);
- g_free(data);
+ g_variant_unref((GVariant *)data);
return;
}
@@ -290,12 +301,14 @@ _g_value_free (gpointer data)
static void
dbusmenu_menuitem_init (DbusmenuMenuitem *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_TYPE_MENUITEM, DbusmenuMenuitemPrivate);
+
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(self);
priv->id = -1;
priv->children = NULL;
- priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _g_value_free);
+ priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _g_variant_unref);
priv->root = FALSE;
priv->realized = FALSE;
@@ -380,7 +393,7 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
/* Handles the activate event if it is sent. */
static void
-handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp)
+handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp)
{
if (g_strcmp0(name, "clicked") == 0) {
g_signal_emit(G_OBJECT(mi), signals[ITEM_ACTIVATED], 0, timestamp, TRUE);
@@ -401,7 +414,8 @@ send_about_to_show (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gp
if (dbusmenu_menuitem_get_children(mi) == NULL) {
g_warning("About to Show called on an item wihtout submenus. We're ignoring it.");
} else {
- g_signal_emit(G_OBJECT(mi), signals[ITEM_ACTIVATED], 0, 0 /* timestamp */, TRUE);
+ gboolean dummy;
+ g_signal_emit(G_OBJECT(mi), signals[ABOUT_TO_SHOW], 0, &dummy);
}
if (cb != NULL) {
@@ -533,7 +547,6 @@ take_children_signal (gpointer data, gpointer user_data)
g_debug("Menuitem %d (%s) signalling child removed %d (%s)", ID(user_data), LABEL(user_data), ID(data), LABEL(data));
#endif
g_signal_emit(G_OBJECT(user_data), signals[CHILD_REMOVED], 0, DBUSMENU_MENUITEM(data), TRUE);
- g_object_unref(G_OBJECT(data));
return;
}
@@ -547,7 +560,8 @@ take_children_signal (gpointer data, gpointer user_data)
on the children it has taken. A lot of responsibility involved
in taking children.
- Return value: A #GList of pointers to #DbusmenuMenuitem objects.
+ Return value: (transfer full) (array) (element-type Dbusmenu.Menuitem)
+ A #GList of pointers to #DbusmenuMenuitem objects.
*/
GList *
dbusmenu_menuitem_take_children (DbusmenuMenuitem * mi)
@@ -916,10 +930,11 @@ dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, gint id)
gboolean
dbusmenu_menuitem_property_set (DbusmenuMenuitem * mi, const gchar * property, const gchar * value)
{
- GValue val = {0};
- g_value_init(&val, G_TYPE_STRING);
- g_value_set_static_string(&val, value);
- return dbusmenu_menuitem_property_set_value(mi, property, &val);
+ GVariant * variant = NULL;
+ if (value != NULL) {
+ variant = g_variant_new_string(value);
+ }
+ return dbusmenu_menuitem_property_set_variant(mi, property, variant);
}
/**
@@ -940,10 +955,8 @@ dbusmenu_menuitem_property_set (DbusmenuMenuitem * mi, const gchar * property, c
gboolean
dbusmenu_menuitem_property_set_bool (DbusmenuMenuitem * mi, const gchar * property, const gboolean value)
{
- GValue val = {0};
- g_value_init(&val, G_TYPE_BOOLEAN);
- g_value_set_boolean(&val, value);
- return dbusmenu_menuitem_property_set_value(mi, property, &val);
+ GVariant * variant = g_variant_new("b", value);
+ return dbusmenu_menuitem_property_set_variant(mi, property, variant);
}
/**
@@ -964,14 +977,12 @@ dbusmenu_menuitem_property_set_bool (DbusmenuMenuitem * mi, const gchar * proper
gboolean
dbusmenu_menuitem_property_set_int (DbusmenuMenuitem * mi, const gchar * property, const gint value)
{
- GValue val = {0};
- g_value_init(&val, G_TYPE_INT);
- g_value_set_int(&val, value);
- return dbusmenu_menuitem_property_set_value(mi, property, &val);
+ GVariant * variant = g_variant_new("i", value);
+ return dbusmenu_menuitem_property_set_variant(mi, property, variant);
}
/**
- dbusmenu_menuitem_property_set:
+ dbusmenu_menuitem_property_set_variant:
@mi: The #DbusmenuMenuitem to set the property on.
@property: Name of the property to set.
@value: The value of the property.
@@ -986,37 +997,38 @@ dbusmenu_menuitem_property_set_int (DbusmenuMenuitem * mi, const gchar * propert
Return value: A boolean representing if the property value was set.
*/
gboolean
-dbusmenu_menuitem_property_set_value (DbusmenuMenuitem * mi, const gchar * property, const GValue * value)
+dbusmenu_menuitem_property_set_variant (DbusmenuMenuitem * mi, const gchar * property, GVariant * value)
{
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), FALSE);
g_return_val_if_fail(property != NULL, FALSE);
- g_return_val_if_fail(G_IS_VALUE(value), FALSE);
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
- /* g_debug("Setting a property. ID: %d Prop: %s Value: %s", priv->id, property, value); */
- #if 0
- gpointer lookup = g_hash_table_lookup(priv->properties, property);
- if (g_strcmp0((gchar *)lookup, value) == 0) {
- /* The value is the same as the value currently in the
- table so we don't really care. Just say everything's okay */
- return TRUE;
- }
- #endif
+ gboolean replaced = FALSE;
+ gpointer currentval = g_hash_table_lookup(priv->properties, property);
- gchar * lprop = g_strdup(property);
- GValue * lval = g_new0(GValue, 1);
- g_value_init(lval, G_VALUE_TYPE(value));
- g_value_copy(value, lval);
+ if (value != NULL) {
+ gchar * lprop = g_strdup(property);
+ g_variant_ref(value);
- g_hash_table_replace(priv->properties, lprop, lval);
- #ifdef MASSIVEDEBUGGING
- gchar * valstr = g_strdup_value_contents(lval);
- g_debug("Menuitem %d (%s) signalling property '%s' changed to '%s'", ID(mi), LABEL(mi), property, g_utf8_strlen(valstr, 50) < 25 ? valstr : "<too long>");
- g_free(valstr);
- #endif
+ if (currentval == NULL || !g_variant_equal((GVariant*)currentval, value)) {
+ g_hash_table_replace(priv->properties, lprop, value);
+ replaced = TRUE;
+ }
+ } else {
+ if (currentval != NULL) {
+ g_hash_table_remove(priv->properties, property);
+ replaced = TRUE;
+ }
+ }
- g_signal_emit(G_OBJECT(mi), signals[PROPERTY_CHANGED], 0, lprop, lval, TRUE);
+ /* NOTE: The actual value is invalid at this point
+ becuse it has been unref'd when replaced in the hash
+ table. But the fact that there was a value is
+ the imporant part. */
+ if (currentval == NULL || replaced) {
+ g_signal_emit(G_OBJECT(mi), signals[PROPERTY_CHANGED], 0, property, value, TRUE);
+ }
return TRUE;
}
@@ -1037,14 +1049,14 @@ dbusmenu_menuitem_property_set_value (DbusmenuMenuitem * mi, const gchar * prope
const gchar *
dbusmenu_menuitem_property_get (DbusmenuMenuitem * mi, const gchar * property)
{
- const GValue * value = dbusmenu_menuitem_property_get_value(mi, property);
- if (value == NULL) return NULL;
- if (G_VALUE_TYPE(value) != G_TYPE_STRING) return NULL;
- return g_value_get_string(value);
+ GVariant * variant = dbusmenu_menuitem_property_get_variant(mi, property);
+ if (variant == NULL) return NULL;
+ if (!g_variant_type_equal(g_variant_get_type(variant), G_VARIANT_TYPE_STRING)) return NULL;
+ return g_variant_get_string(variant, NULL);
}
/**
- dbusmenu_menuitem_property_get_value:
+ dbusmenu_menuitem_property_get_variant:
@mi: The #DbusmenuMenuitem to look for the property on.
@property: The property to grab.
@@ -1052,17 +1064,17 @@ dbusmenu_menuitem_property_get (DbusmenuMenuitem * mi, const gchar * property)
it exits. #NULL will be returned if the property doesn't
exist.
- Return value: A GValue for the property.
+ Return value: A GVariant for the property.
*/
-const GValue *
-dbusmenu_menuitem_property_get_value (DbusmenuMenuitem * mi, const gchar * property)
+GVariant *
+dbusmenu_menuitem_property_get_variant (DbusmenuMenuitem * mi, const gchar * property)
{
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL);
g_return_val_if_fail(property != NULL, NULL);
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
- return (const GValue *)g_hash_table_lookup(priv->properties, property);
+ return (GVariant *)g_hash_table_lookup(priv->properties, property);
}
/**
@@ -1078,19 +1090,25 @@ dbusmenu_menuitem_property_get_value (DbusmenuMenuitem * mi, const gchar * prope
gboolean
dbusmenu_menuitem_property_get_bool (DbusmenuMenuitem * mi, const gchar * property)
{
- const GValue * value = dbusmenu_menuitem_property_get_value(mi, property);
- if (value == NULL) return FALSE;
- if (G_VALUE_TYPE(value) != G_TYPE_BOOLEAN) {
- if (g_value_type_transformable(G_VALUE_TYPE(value), G_TYPE_BOOLEAN)) {
- GValue boolval = {0};
- g_value_init(&boolval, G_TYPE_BOOLEAN);
- g_value_transform(value, &boolval);
- return g_value_get_boolean(&boolval);
+ GVariant * variant = dbusmenu_menuitem_property_get_variant(mi, property);
+ if (variant == NULL) return FALSE;
+
+ if (g_variant_type_equal(g_variant_get_type(variant), G_VARIANT_TYPE_BOOLEAN)) {
+ return g_variant_get_boolean(variant);
+ }
+
+ if (g_variant_type_equal(g_variant_get_type(variant), G_VARIANT_TYPE_STRING)) {
+ const gchar * string = g_variant_get_string(variant, NULL);
+
+ if (!g_strcmp0(string, "TRUE") || !g_strcmp0(string, "true") || !g_strcmp0(string, "True")) {
+ return TRUE;
} else {
return FALSE;
}
}
- return g_value_get_boolean(value);
+
+ g_warning("Property '%s' has been requested as an boolean but is not one.", property);
+ return FALSE;
}
/**
@@ -1106,19 +1124,20 @@ dbusmenu_menuitem_property_get_bool (DbusmenuMenuitem * mi, const gchar * proper
gint
dbusmenu_menuitem_property_get_int (DbusmenuMenuitem * mi, const gchar * property)
{
- const GValue * value = dbusmenu_menuitem_property_get_value(mi, property);
- if (value == NULL) return 0;
- if (G_VALUE_TYPE(value) != G_TYPE_INT) {
- if (g_value_type_transformable(G_VALUE_TYPE(value), G_TYPE_INT)) {
- GValue intval = {0};
- g_value_init(&intval, G_TYPE_INT);
- g_value_transform(value, &intval);
- return g_value_get_int(&intval);
- } else {
- return 0;
- }
+ GVariant * variant = dbusmenu_menuitem_property_get_variant(mi, property);
+ if (variant == NULL) return 0;
+
+ if (g_variant_type_equal(g_variant_get_type(variant), G_VARIANT_TYPE_INT32)) {
+ return g_variant_get_int32(variant);
+ }
+
+ if (g_variant_type_equal(g_variant_get_type(variant), G_VARIANT_TYPE_STRING)) {
+ const gchar * string = g_variant_get_string(variant, NULL);
+ return atoi(string);
}
- return g_value_get_int(value);
+
+ g_warning("Property '%s' has been requested as an int but is not one.", property);
+ return 0;
}
@@ -1185,11 +1204,17 @@ dbusmenu_menuitem_properties_list (DbusmenuMenuitem * mi)
return g_hash_table_get_keys(priv->properties);
}
+/* Copy the keys and make references to the variants that are
+ in the new table. They'll be free'd and unref'd when the
+ Hashtable gets destroyed. */
static void
copy_helper (gpointer in_key, gpointer in_value, gpointer in_data)
{
GHashTable * table = (GHashTable *)in_data;
- g_hash_table_insert(table, in_key, in_value);
+ gchar * key = (gchar *)in_key;
+ GVariant * value = (GVariant *)in_value;
+ g_variant_ref(value);
+ g_hash_table_insert(table, g_strdup(key), value);
return;
}
@@ -1210,7 +1235,7 @@ copy_helper (gpointer in_key, gpointer in_value, gpointer in_data)
GHashTable *
dbusmenu_menuitem_properties_copy (DbusmenuMenuitem * mi)
{
- GHashTable * ret = g_hash_table_new(g_str_hash, g_str_equal);
+ GHashTable * ret = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _g_variant_unref);
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), ret);
@@ -1220,6 +1245,45 @@ dbusmenu_menuitem_properties_copy (DbusmenuMenuitem * mi)
return ret;
}
+/* Looks at each value in the hashtable and tries to convert it
+ into a variant and add it to our variant builder */
+static void
+variant_helper (gpointer in_key, gpointer in_value, gpointer user_data)
+{
+ g_variant_builder_add((GVariantBuilder *)user_data, "{sv}", in_key, in_value);
+ return;
+}
+
+/**
+ dbusmenu_menuitem_properties_variant:
+ @mi: #DbusmenuMenuitem to get properties from
+
+ Grabs the properties of the menuitem as a GVariant with the
+ type "a{sv}".
+
+ Return Value: A GVariant of type "a{sv}" or NULL on error.
+*/
+GVariant *
+dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi)
+{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL);
+
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+
+ GVariant * final_variant = NULL;
+
+ if (g_hash_table_size(priv->properties) > 0) {
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, g_variant_type_new("a{sv}"));
+
+ g_hash_table_foreach(priv->properties, variant_helper, &builder);
+
+ final_variant = g_variant_builder_end(&builder);
+ }
+
+ return final_variant;
+}
+
/**
dbusmenu_menuitem_set_root:
@mi: #DbusmenuMenuitem to set whether it's root
@@ -1332,7 +1396,7 @@ dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem
dbusmenu_menuitem_handle_event:
@mi: The #DbusmenuMenuitem to send the signal on.
@name: The name of the signal
- @value: A value that could be set for the event
+ @variant: A value that could be set for the event
@timestamp: The timestamp of when the event happened
This function is called to create an event. It is likely
@@ -1348,7 +1412,7 @@ dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem
reason not to.
*/
void
-dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp)
+dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * variant, guint timestamp)
{
g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
#ifdef MASSIVEDEBUGGING
@@ -1357,7 +1421,7 @@ dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const
DbusmenuMenuitemClass * class = DBUSMENU_MENUITEM_GET_CLASS(mi);
if (class->handle_event != NULL) {
- return class->handle_event(mi, name, value, timestamp);
+ return class->handle_event(mi, name, variant, timestamp);
}
return;
}
diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h
index d7cf586..a4c7611 100644
--- a/libdbusmenu-glib/menuitem.h
+++ b/libdbusmenu-glib/menuitem.h
@@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define DBUSMENU_MENUITEM_SIGNAL_REALIZED "realized"
#define DBUSMENU_MENUITEM_SIGNAL_REALIZED_ID (g_signal_lookup(DBUSMENU_MENUITEM_SIGNAL_REALIZED, DBUSMENU_TYPE_MENUITEM))
#define DBUSMENU_MENUITEM_SIGNAL_SHOW_TO_USER "show-to-user"
+#define DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW "about-to-show"
#define DBUSMENU_MENUITEM_PROP_TYPE "type"
#define DBUSMENU_MENUITEM_PROP_VISIBLE "visible"
@@ -78,6 +79,8 @@ G_BEGIN_DECLS
#define DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU "submenu"
+typedef struct _DbusmenuMenuitemPrivate DbusmenuMenuitemPrivate;
+
/**
* DbusmenuMenuitem:
*
@@ -92,6 +95,9 @@ typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
struct _DbusmenuMenuitem
{
GObject parent;
+
+ /*< Private >*/
+ DbusmenuMenuitemPrivate * priv;
};
/**
@@ -122,10 +128,18 @@ typedef void (*dbusmenu_menuitem_buildxml_slot_t) (DbusmenuMenuitem * mi, GPtrAr
* @child_removed: Slot for #DbusmenuMenuitem::child-removed.
* @child_moved: Slot for #DbusmenuMenuitem::child-moved.
* @realized: Slot for #DbusmenuMenuitem::realized.
+ * @about_to_show: Slot for #DbusmenuMenuitem::about-to-show.
* @buildxml: Virtual function that appends the strings required to represent this menu item in the menu XML file.
* @handle_event: This function is to override how events are handled by subclasses. Look at #dbusmenu_menuitem_handle_event for lots of good information.
* @send_about_to_show: Virtual function that notifies server that the client is about to show a menu.
* @show_to_user: Slot for #DbusmenuMenuitem::show-to-user.
+ *
+ * @reserved1: Reserved for future use.
+ * @reserved2: Reserved for future use.
+ * @reserved3: Reserved for future use.
+ * @reserved4: Reserved for future use.
+ * @reserved5: Reserved for future use.
+ * @reserved6: Reserved for future use.
*/
typedef struct _DbusmenuMenuitemClass DbusmenuMenuitemClass;
struct _DbusmenuMenuitemClass
@@ -133,7 +147,7 @@ struct _DbusmenuMenuitemClass
GObjectClass parent_class;
/* Signals */
- void (*property_changed) (gchar * property, GValue * value);
+ void (*property_changed) (gchar * property, GVariant * value);
void (*item_activated) (guint timestamp);
void (*child_added) (DbusmenuMenuitem * child, guint position);
void (*child_removed) (DbusmenuMenuitem * child);
@@ -142,14 +156,19 @@ struct _DbusmenuMenuitemClass
/* Virtual functions */
dbusmenu_menuitem_buildxml_slot_t buildxml;
- void (*handle_event) (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+ void (*handle_event) (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp);
void (*send_about_to_show) (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gpointer user_data), gpointer cb_data);
void (*show_to_user) (DbusmenuMenuitem * mi, guint timestamp, gpointer cb_data);
- /* void (*reserved1) (void); */
- /* void (*reserved2) (void); */
- /* void (*reserved3) (void); */
- /* void (*reserved4) (void); -- realized, realloc when bumping lib version */
+ gboolean (*about_to_show) (void);
+
+ /*< Private >*/
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
};
GType dbusmenu_menuitem_get_type (void);
@@ -172,11 +191,11 @@ DbusmenuMenuitem * dbusmenu_menuitem_child_find (DbusmenuMenuitem * mi, gint id)
DbusmenuMenuitem * dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, gint id);
gboolean dbusmenu_menuitem_property_set (DbusmenuMenuitem * mi, const gchar * property, const gchar * value);
-gboolean dbusmenu_menuitem_property_set_value (DbusmenuMenuitem * mi, const gchar * property, const GValue * value);
+gboolean dbusmenu_menuitem_property_set_variant (DbusmenuMenuitem * mi, const gchar * property, GVariant * value);
gboolean dbusmenu_menuitem_property_set_bool (DbusmenuMenuitem * mi, const gchar * property, const gboolean value);
gboolean dbusmenu_menuitem_property_set_int (DbusmenuMenuitem * mi, const gchar * property, const gint value);
const gchar * dbusmenu_menuitem_property_get (DbusmenuMenuitem * mi, const gchar * property);
-const GValue * dbusmenu_menuitem_property_get_value (DbusmenuMenuitem * mi, const gchar * property);
+GVariant * dbusmenu_menuitem_property_get_variant (DbusmenuMenuitem * mi, const gchar * property);
gboolean dbusmenu_menuitem_property_get_bool (DbusmenuMenuitem * mi, const gchar * property);
gint dbusmenu_menuitem_property_get_int (DbusmenuMenuitem * mi, const gchar * property);
gboolean dbusmenu_menuitem_property_exist (DbusmenuMenuitem * mi, const gchar * property);
@@ -188,7 +207,7 @@ void dbusmenu_menuitem_set_root (DbusmenuMenuitem * mi, gboolean root);
gboolean dbusmenu_menuitem_get_root (DbusmenuMenuitem * mi);
void dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem * mi, gpointer data), gpointer data);
-void dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+void dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp);
void dbusmenu_menuitem_send_about_to_show (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gpointer user_data), gpointer cb_data);
void dbusmenu_menuitem_show_to_user (DbusmenuMenuitem * mi, guint timestamp);
diff --git a/libdbusmenu-glib/server-marshal.list b/libdbusmenu-glib/server-marshal.list
index 0d68c4e..08ebf93 100644
--- a/libdbusmenu-glib/server-marshal.list
+++ b/libdbusmenu-glib/server-marshal.list
@@ -1,3 +1,3 @@
-VOID: INT, STRING, POINTER
+VOID: INT, STRING, VARIANT
VOID: UINT, INT
VOID: INT, UINT
diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c
index 68afb92..6a65b56 100644
--- a/libdbusmenu-glib/server.c
+++ b/libdbusmenu-glib/server.c
@@ -30,41 +30,36 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
+#include <gio/gio.h>
+
#include "menuitem-private.h"
#include "server.h"
#include "server-marshal.h"
-/* DBus Prototypes */
-static gboolean _dbusmenu_server_get_layout (DbusmenuServer * server, gint parent, guint * revision, gchar ** layout, GError ** error);
-static gboolean _dbusmenu_server_get_property (DbusmenuServer * server, gint id, gchar * property, gchar ** value, GError ** error);
-static gboolean _dbusmenu_server_get_properties (DbusmenuServer * server, gint id, gchar ** properties, GHashTable ** dict, GError ** error);
-static gboolean _dbusmenu_server_get_group_properties (DbusmenuServer * server, GArray * ids, gchar ** properties, GPtrArray ** values, GError ** error);
-static gboolean _dbusmenu_server_event (DbusmenuServer * server, gint id, gchar * eventid, GValue * data, guint timestamp, GError ** error);
-static gboolean _dbusmenu_server_get_children (DbusmenuServer * server, gint id, GPtrArray * properties, GPtrArray ** output, GError ** error);
-static gboolean _dbusmenu_server_about_to_show (DbusmenuServer * server, gint id, gboolean * need_update, GError ** error);
-/* DBus Helpers */
-static void _gvalue_array_append_int(GValueArray *array, gint i);
-static void _gvalue_array_append_hashtable(GValueArray *array, GHashTable * dict);
-
-#include "dbusmenu-server.h"
+#include "dbus-menu-clean.xml.h"
static void layout_update_signal (DbusmenuServer * server);
-#define DBUSMENU_VERSION_NUMBER 2
+#define DBUSMENU_VERSION_NUMBER 2
+#define DBUSMENU_INTERFACE "com.canonical.dbusmenu"
/* Privates, I'll show you mine... */
-typedef struct _DbusmenuServerPrivate DbusmenuServerPrivate;
-
struct _DbusmenuServerPrivate
{
DbusmenuMenuitem * root;
gchar * dbusobject;
gint layout_revision;
guint layout_idle;
+
+ GDBusConnection * bus;
+ GCancellable * bus_lookup;
+ guint dbus_registration;
+
+ GArray * prop_array;
+ guint property_idle;
};
-#define DBUSMENU_SERVER_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_SERVER, DbusmenuServerPrivate))
+#define DBUSMENU_SERVER_GET_PRIVATE(o) (DBUSMENU_SERVER(o)->priv)
/* Signals */
enum {
@@ -91,22 +86,111 @@ enum {
INVALID_PROPERTY_NAME,
UNKNOWN_DBUS_ERROR,
NOT_IMPLEMENTED,
+ NO_VALID_LAYOUT,
LAST_ERROR
};
+/* Method Table */
+typedef void (*MethodTableFunc) (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation);
+
+typedef struct _method_table_t method_table_t;
+struct _method_table_t {
+ const gchar * interned_name;
+ MethodTableFunc func;
+};
+
+enum {
+ METHOD_GET_LAYOUT = 0,
+ METHOD_GET_GROUP_PROPERTIES,
+ METHOD_GET_CHILDREN,
+ METHOD_GET_PROPERTY,
+ METHOD_GET_PROPERTIES,
+ METHOD_EVENT,
+ METHOD_ABOUT_TO_SHOW,
+ /* Counter, do not remove! */
+ METHOD_COUNT
+};
+
/* Prototype */
-static void dbusmenu_server_class_init (DbusmenuServerClass *class);
-static void dbusmenu_server_init (DbusmenuServer *self);
-static void dbusmenu_server_dispose (GObject *object);
-static void dbusmenu_server_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);
-static void menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, GValue * value, DbusmenuServer * server);
-static void menuitem_child_added (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, guint pos, DbusmenuServer * server);
-static void menuitem_child_removed (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, DbusmenuServer * server);
-static void menuitem_signals_create (DbusmenuMenuitem * mi, gpointer data);
-static void menuitem_signals_remove (DbusmenuMenuitem * mi, gpointer data);
-static GQuark error_quark (void);
+static void dbusmenu_server_class_init (DbusmenuServerClass *class);
+static void dbusmenu_server_init (DbusmenuServer *self);
+static void dbusmenu_server_dispose (GObject *object);
+static void dbusmenu_server_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);
+static void register_object (DbusmenuServer * server);
+static void bus_got_cb (GObject * obj,
+ GAsyncResult * result,
+ gpointer user_data);
+static void bus_method_call (GDBusConnection * connection,
+ const gchar * sender,
+ const gchar * path,
+ const gchar * interface,
+ const gchar * method,
+ GVariant * params,
+ GDBusMethodInvocation * invocation,
+ gpointer user_data);
+static GVariant * bus_get_prop (GDBusConnection * connection,
+ const gchar * sender,
+ const gchar * path,
+ const gchar * interface,
+ const gchar * property,
+ GError ** error,
+ gpointer user_data);
+static void menuitem_property_changed (DbusmenuMenuitem * mi,
+ gchar * property,
+ GVariant * variant,
+ DbusmenuServer * server);
+static void menuitem_child_added (DbusmenuMenuitem * parent,
+ DbusmenuMenuitem * child,
+ guint pos,
+ DbusmenuServer * server);
+static void menuitem_child_removed (DbusmenuMenuitem * parent,
+ DbusmenuMenuitem * child,
+ DbusmenuServer * server);
+static void menuitem_signals_create (DbusmenuMenuitem * mi,
+ gpointer data);
+static void menuitem_signals_remove (DbusmenuMenuitem * mi,
+ gpointer data);
+static GQuark error_quark (void);
+static void prop_array_teardown (GArray * prop_array);
+static void bus_get_layout (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_get_group_properties (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_get_children (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_get_property (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_get_properties (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_event (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+static void bus_about_to_show (DbusmenuServer * server,
+ GVariant * params,
+ GDBusMethodInvocation * invocation);
+
+/* Globals */
+static GDBusNodeInfo * dbusmenu_node_info = NULL;
+static GDBusInterfaceInfo * dbusmenu_interface_info = NULL;
+static const GDBusInterfaceVTable dbusmenu_interface_table = {
+ method_call: bus_method_call,
+ get_property: bus_get_prop,
+ set_property: NULL /* No properties that can be set */
+};
+static method_table_t dbusmenu_method_table[METHOD_COUNT];
G_DEFINE_TYPE (DbusmenuServer, dbusmenu_server, G_TYPE_OBJECT);
@@ -137,8 +221,8 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuServerClass, id_prop_update),
NULL, NULL,
- _dbusmenu_server_marshal_VOID__INT_STRING_POINTER,
- G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_VALUE);
+ _dbusmenu_server_marshal_VOID__INT_STRING_VARIANT,
+ G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_VARIANT);
/**
DbusmenuServer::id-update:
@arg0: The #DbusmenuServer emitting the signal.
@@ -193,7 +277,7 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
g_object_class_install_property (object_class, PROP_DBUS_OBJECT,
g_param_spec_string(DBUSMENU_SERVER_PROP_DBUS_OBJECT, "DBus object path",
"The object that represents this set of menus on DBus",
- "/org/ayatana/dbusmenu",
+ "/com/canonical/dbusmenu",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ROOT_NODE,
g_param_spec_object(DBUSMENU_SERVER_PROP_ROOT_NODE, "Root menu node",
@@ -206,7 +290,45 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
DBUSMENU_VERSION_NUMBER, DBUSMENU_VERSION_NUMBER, DBUSMENU_VERSION_NUMBER,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- dbus_g_object_type_install_info(DBUSMENU_TYPE_SERVER, &dbus_glib__dbusmenu_server_object_info);
+ if (dbusmenu_node_info == NULL) {
+ GError * error = NULL;
+
+ dbusmenu_node_info = g_dbus_node_info_new_for_xml(dbus_menu_clean_xml, &error);
+ if (error != NULL) {
+ g_error("Unable to parse DBusmenu Interface description: %s", error->message);
+ g_error_free(error);
+ }
+ }
+
+ if (dbusmenu_interface_info == NULL) {
+ dbusmenu_interface_info = g_dbus_node_info_lookup_interface(dbusmenu_node_info, DBUSMENU_INTERFACE);
+
+ if (dbusmenu_interface_info == NULL) {
+ g_error("Unable to find interface '" DBUSMENU_INTERFACE "'");
+ }
+ }
+
+ /* Building our Method table :( */
+ dbusmenu_method_table[METHOD_GET_LAYOUT].interned_name = g_intern_static_string("GetLayout");
+ dbusmenu_method_table[METHOD_GET_LAYOUT].func = bus_get_layout;
+
+ dbusmenu_method_table[METHOD_GET_GROUP_PROPERTIES].interned_name = g_intern_static_string("GetGroupProperties");
+ dbusmenu_method_table[METHOD_GET_GROUP_PROPERTIES].func = bus_get_group_properties;
+
+ dbusmenu_method_table[METHOD_GET_CHILDREN].interned_name = g_intern_static_string("GetChildren");
+ dbusmenu_method_table[METHOD_GET_CHILDREN].func = bus_get_children;
+
+ dbusmenu_method_table[METHOD_GET_PROPERTY].interned_name = g_intern_static_string("GetProperty");
+ dbusmenu_method_table[METHOD_GET_PROPERTY].func = bus_get_property;
+
+ dbusmenu_method_table[METHOD_GET_PROPERTIES].interned_name = g_intern_static_string("GetProperties");
+ dbusmenu_method_table[METHOD_GET_PROPERTIES].func = bus_get_properties;
+
+ dbusmenu_method_table[METHOD_EVENT].interned_name = g_intern_static_string("Event");
+ dbusmenu_method_table[METHOD_EVENT].func = bus_event;
+
+ dbusmenu_method_table[METHOD_ABOUT_TO_SHOW].interned_name = g_intern_static_string("AboutToShow");
+ dbusmenu_method_table[METHOD_ABOUT_TO_SHOW].func = bus_about_to_show;
return;
}
@@ -214,12 +336,17 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
static void
dbusmenu_server_init (DbusmenuServer *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_TYPE_SERVER, DbusmenuServerPrivate);
+
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(self);
priv->root = NULL;
priv->dbusobject = NULL;
priv->layout_revision = 1;
priv->layout_idle = 0;
+ priv->bus = NULL;
+ priv->bus_lookup = NULL;
+ priv->dbus_registration = 0;
return;
}
@@ -231,6 +358,17 @@ dbusmenu_server_dispose (GObject *object)
if (priv->layout_idle != 0) {
g_source_remove(priv->layout_idle);
+ priv->layout_idle = 0;
+ }
+
+ if (priv->property_idle != 0) {
+ g_source_remove(priv->property_idle);
+ priv->property_idle = 0;
+ }
+
+ if (priv->prop_array != NULL) {
+ prop_array_teardown(priv->prop_array);
+ priv->prop_array = NULL;
}
if (priv->root != NULL) {
@@ -238,6 +376,27 @@ dbusmenu_server_dispose (GObject *object)
g_object_unref(priv->root);
}
+ if (priv->dbus_registration != 0) {
+ g_dbus_connection_unregister_object(priv->bus, priv->dbus_registration);
+ priv->dbus_registration = 0;
+ }
+
+ if (priv->bus != NULL) {
+ g_object_unref(priv->bus);
+ priv->bus = NULL;
+ }
+
+ if (priv->bus_lookup != NULL) {
+ if (!g_cancellable_is_cancelled(priv->bus_lookup)) {
+ /* Note, this may case the async function to run at
+ some point in the future. That's okay, it'll get an
+ error, but just FYI */
+ g_cancellable_cancel(priv->bus_lookup);
+ }
+ g_object_unref(priv->bus_lookup);
+ priv->bus_lookup = NULL;
+ }
+
G_OBJECT_CLASS (dbusmenu_server_parent_class)->dispose (object);
return;
}
@@ -253,27 +412,36 @@ static void
set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(obj);
- GError * error = NULL;
switch (id) {
case PROP_DBUS_OBJECT:
g_return_if_fail(priv->dbusobject == NULL);
priv->dbusobject = g_value_dup_string(value);
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (connection == NULL || error != NULL) {
- g_warning("Unable to get session bus: %s", error == NULL ? "No message" : error->message);
- if (error != NULL) { g_error_free(error); }
+ if (priv->bus == NULL) {
+ if (priv->bus_lookup == NULL) {
+ priv->bus_lookup = g_cancellable_new();
+ g_return_if_fail(priv->bus_lookup != NULL);
+ }
+
+ g_bus_get(G_BUS_TYPE_SESSION, priv->bus_lookup, bus_got_cb, obj);
} else {
- dbus_g_connection_register_g_object(connection,
- priv->dbusobject,
- obj);
+ register_object(DBUSMENU_SERVER(obj));
}
break;
case PROP_ROOT_NODE:
if (priv->root != NULL) {
dbusmenu_menuitem_foreach(priv->root, menuitem_signals_remove, obj);
dbusmenu_menuitem_set_root(priv->root, FALSE);
+
+ GList * properties = dbusmenu_menuitem_properties_list(priv->root);
+ GList * iter;
+ for (iter = properties; iter != NULL; iter = g_list_next(iter)) {
+ gchar * property = (gchar *)iter->data;
+ menuitem_property_changed(priv->root, property, g_variant_new_string("deadvalue"), DBUSMENU_SERVER(obj));
+ }
+ g_list_free(properties);
+
g_object_unref(G_OBJECT(priv->root));
priv->root = NULL;
}
@@ -282,6 +450,14 @@ set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
g_object_ref(G_OBJECT(priv->root));
dbusmenu_menuitem_set_root(priv->root, TRUE);
dbusmenu_menuitem_foreach(priv->root, menuitem_signals_create, obj);
+
+ GList * properties = dbusmenu_menuitem_properties_list(priv->root);
+ GList * iter;
+ for (iter = properties; iter != NULL; iter = g_list_next(iter)) {
+ gchar * property = (gchar *)iter->data;
+ menuitem_property_changed(priv->root, property, dbusmenu_menuitem_property_get_variant(priv->root, property), DBUSMENU_SERVER(obj));
+ }
+ g_list_free(properties);
} else {
g_debug("Setting root node to NULL");
}
@@ -329,6 +505,128 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
return;
}
+/* Register the object on the dbus bus */
+static void
+register_object (DbusmenuServer * server)
+{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ /* Object info */
+ g_return_if_fail(priv->bus != NULL);
+ g_return_if_fail(priv->dbusobject != NULL);
+
+ /* Class info */
+ g_return_if_fail(dbusmenu_node_info != NULL);
+ g_return_if_fail(dbusmenu_interface_info != NULL);
+
+ /* We might block on this in the future, but it'd be nice if
+ we could change the object path. Thinking about it... */
+ if (priv->dbus_registration != 0) {
+ g_dbus_connection_unregister_object(priv->bus, priv->dbus_registration);
+ priv->dbus_registration = 0;
+ }
+
+ GError * error = NULL;
+ priv->dbus_registration = g_dbus_connection_register_object(priv->bus,
+ priv->dbusobject,
+ dbusmenu_interface_info,
+ &dbusmenu_interface_table,
+ server,
+ NULL,
+ &error);
+
+ if (error != NULL) {
+ g_warning("Unable to register object on bus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* If we've got it registered let's tell everyone about it */
+ g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATED], 0, priv->layout_revision, 0, TRUE);
+ if (priv->dbusobject != NULL && priv->bus != NULL) {
+ g_dbus_connection_emit_signal(priv->bus,
+ NULL,
+ priv->dbusobject,
+ DBUSMENU_INTERFACE,
+ "LayoutUpdated",
+ g_variant_new("(ui)", priv->layout_revision, 0),
+ NULL);
+ }
+
+ return;
+}
+
+/* Callback from asking GIO to get us the session bus */
+static void
+bus_got_cb (GObject * obj, GAsyncResult * result, gpointer user_data)
+{
+ GError * error = NULL;
+
+ GDBusConnection * bus = g_bus_get_finish(result, &error);
+
+ if (error != NULL) {
+ g_warning("Unable to get session bus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Note: We're not using the user_data before we check for
+ the error so that in the cancelled case at destruction of
+ the object we don't end up with an invalid object. */
+
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(user_data);
+ priv->bus = bus;
+
+ register_object(DBUSMENU_SERVER(user_data));
+
+ return;
+}
+
+/* Function for the GDBus vtable to handle all method calls and dish
+ them out the appropriate functions */
+static void
+bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data)
+{
+ int i;
+ const gchar * interned_method = g_intern_string(method);
+
+ for (i = 0; i < METHOD_COUNT; i++) {
+ if (dbusmenu_method_table[i].interned_name == interned_method) {
+ if (dbusmenu_method_table[i].func != NULL) {
+ return dbusmenu_method_table[i].func(DBUSMENU_SERVER(user_data), params, invocation);
+ } else {
+ /* If we have a null function we're responding but nothing else. */
+ g_warning("Invalid function call for '%s' with parameters: %s", method, g_variant_print(params, TRUE));
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+ }
+ }
+
+ /* We're here because there's an error */
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NOT_IMPLEMENTED,
+ "Unable to find method '%s'",
+ method);
+ return;
+}
+
+/* For the GDBus vtable but we only have one property so it's pretty
+ simple. */
+static GVariant *
+bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data)
+{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(user_data);
+
+ /* None of these should happen */
+ g_return_val_if_fail(g_strcmp0(interface, DBUSMENU_INTERFACE) == 0, NULL);
+ g_return_val_if_fail(g_strcmp0(path, priv->dbusobject) == 0, NULL);
+ g_return_val_if_fail(g_strcmp0(property, "version") == 0, NULL);
+
+ return g_variant_new_uint32(DBUSMENU_VERSION_NUMBER);
+}
+
/* Handle actually signalling in the idle loop. This way we collect all
the updates. */
static gboolean
@@ -338,6 +636,15 @@ layout_update_idle (gpointer user_data)
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATED], 0, priv->layout_revision, 0, TRUE);
+ if (priv->dbusobject != NULL && priv->bus != NULL) {
+ g_dbus_connection_emit_signal(priv->bus,
+ NULL,
+ priv->dbusobject,
+ DBUSMENU_INTERFACE,
+ "LayoutUpdated",
+ g_variant_new("(ui)", priv->layout_revision, 0),
+ NULL);
+ }
priv->layout_idle = 0;
@@ -358,10 +665,180 @@ layout_update_signal (DbusmenuServer * server)
return;
}
+typedef struct _prop_idle_item_t prop_idle_item_t;
+struct _prop_idle_item_t {
+ gint id;
+ GArray * array;
+};
+
+typedef struct _prop_idle_prop_t prop_idle_prop_t;
+struct _prop_idle_prop_t {
+ gchar * property;
+ GVariant * variant;
+};
+
+/* Takes appart our data structure so we don't leak any
+ memory or references. */
+static void
+prop_array_teardown (GArray * prop_array)
+{
+ int i, j;
+
+ for (i = 0; i < prop_array->len; i++) {
+ prop_idle_item_t * iitem = &g_array_index(prop_array, prop_idle_item_t, i);
+
+ for (j = 0; j < iitem->array->len; j++) {
+ prop_idle_prop_t * iprop = &g_array_index(iitem->array, prop_idle_prop_t, j);
+
+ g_free(iprop->property);
+ g_variant_unref(iprop->variant);
+ }
+
+ g_array_free(iitem->array, TRUE);
+ }
+
+ g_array_free(prop_array, TRUE);
+
+ return;
+}
+
+/* Works in the idle to send a set of property updates so that they'll
+ all update in a single dbus message. */
+static gboolean
+menuitem_property_idle (gpointer user_data)
+{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(user_data);
+
+ /* Source will get removed as we return */
+ priv->property_idle = 0;
+
+ /* If there are no items, let's just not signal */
+ if (priv->prop_array == NULL) {
+ return FALSE;
+ }
+
+ int i, j;
+ GVariantBuilder itembuilder;
+ g_variant_builder_init(&itembuilder, G_VARIANT_TYPE_ARRAY);
+
+ for (i = 0; i < priv->prop_array->len; i++) {
+ prop_idle_item_t * iitem = &g_array_index(priv->prop_array, prop_idle_item_t, i);
+
+ GVariantBuilder tuplebuilder;
+ g_variant_builder_init(&tuplebuilder, G_VARIANT_TYPE_TUPLE);
+
+ g_variant_builder_add_value(&tuplebuilder, g_variant_new_int32(iitem->id));
+
+ GVariantBuilder dictbuilder;
+ g_variant_builder_init(&dictbuilder, G_VARIANT_TYPE_DICTIONARY);
+
+ for (j = 0; j < iitem->array->len; j++) {
+ prop_idle_prop_t * iprop = &g_array_index(iitem->array, prop_idle_prop_t, j);
+
+ GVariant * entry = g_variant_new_dict_entry(g_variant_new_string(iprop->property),
+ g_variant_new_variant(iprop->variant));
+
+ g_variant_builder_add_value(&dictbuilder, entry);
+ }
+
+ g_variant_builder_add_value(&tuplebuilder, g_variant_builder_end(&dictbuilder));
+
+ g_variant_builder_add_value(&itembuilder, g_variant_builder_end(&tuplebuilder));
+ }
+
+ GVariant * megadata = g_variant_builder_end(&itembuilder);
+
+ if (priv->dbusobject != NULL && priv->bus != NULL) {
+ g_dbus_connection_emit_signal(priv->bus,
+ NULL,
+ priv->dbusobject,
+ DBUSMENU_INTERFACE,
+ "ItemPropertiesUpdated",
+ g_variant_new_tuple(&megadata, 1),
+ NULL);
+ } else {
+ g_variant_unref(megadata);
+ }
+
+ /* Clean everything up */
+ prop_array_teardown(priv->prop_array);
+ priv->prop_array = NULL;
+
+ return FALSE;
+}
+
static void
-menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, GValue * value, DbusmenuServer * server)
+menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, GVariant * variant, DbusmenuServer * server)
{
- g_signal_emit(G_OBJECT(server), signals[ID_PROP_UPDATE], 0, dbusmenu_menuitem_get_id(mi), property, value, TRUE);
+ int i;
+ gint item_id;
+
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ item_id = dbusmenu_menuitem_get_id(mi);
+
+ g_signal_emit(G_OBJECT(server), signals[ID_PROP_UPDATE], 0, item_id, property, variant, TRUE);
+
+ /* See if we have a property array, if not, we need to
+ build one of these suckers */
+ if (priv->prop_array == NULL) {
+ priv->prop_array = g_array_new(FALSE, FALSE, sizeof(prop_idle_item_t));
+ }
+
+ /* Look to see if we already have this item in the list
+ and use it if so */
+ prop_idle_item_t * item = NULL;
+ for (i = 0; i < priv->prop_array->len; i++) {
+ prop_idle_item_t * iitem = &g_array_index(priv->prop_array, prop_idle_item_t, i);
+ if (iitem->id == item_id) {
+ item = iitem;
+ break;
+ }
+ }
+
+ GArray * properties = NULL;
+ /* If not, we'll need to build ourselves one */
+ if (item == NULL) {
+ prop_idle_item_t myitem;
+ myitem.id = item_id;
+ myitem.array = g_array_new(FALSE, FALSE, sizeof(prop_idle_prop_t));
+
+ g_array_append_val(priv->prop_array, myitem);
+ properties = myitem.array;
+ } else {
+ properties = item->array;
+ }
+
+ /* Check to see if this property is in the list */
+ prop_idle_prop_t * prop = NULL;
+ for (i = 0; i < properties->len; i++) {
+ prop_idle_prop_t * iprop = &g_array_index(properties, prop_idle_prop_t, i);
+ if (g_strcmp0(iprop->property, property) == 0) {
+ prop = iprop;
+ break;
+ }
+ }
+
+ /* If so, we need to swap the value */
+ if (prop != NULL) {
+ g_variant_unref(prop->variant);
+ prop->variant = variant;
+ } else {
+ /* else we need to add it */
+ prop_idle_prop_t myprop;
+ myprop.property = g_strdup(property);
+ myprop.variant = variant;
+
+ g_array_append_val(properties, myprop);
+ }
+ g_variant_ref(variant);
+
+ /* Check to see if the idle is already queued, and queue it
+ if not. */
+ if (priv->property_idle == 0) {
+ priv->property_idle = g_idle_add(menuitem_property_idle, server);
+ }
+
return;
}
@@ -412,7 +889,20 @@ menuitem_child_moved (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, guint
static void
menuitem_shown (DbusmenuMenuitem * mi, guint timestamp, DbusmenuServer * server)
{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
g_signal_emit(G_OBJECT(server), signals[ITEM_ACTIVATION], 0, dbusmenu_menuitem_get_id(mi), timestamp, TRUE);
+
+ if (priv->dbusobject != NULL && priv->bus != NULL) {
+ g_dbus_connection_emit_signal(priv->bus,
+ NULL,
+ priv->dbusobject,
+ DBUSMENU_INTERFACE,
+ "ItemActivationRequested",
+ g_variant_new("(iu)", dbusmenu_menuitem_get_id(mi), timestamp),
+ NULL);
+ }
+
return;
}
@@ -452,12 +942,15 @@ error_quark (void)
}
/* DBus interface */
-static gboolean
-_dbusmenu_server_get_layout (DbusmenuServer * server, gint parent, guint * revision, gchar ** layout, GError ** error)
+static void
+bus_get_layout (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
- *revision = priv->layout_revision;
+ gint parent = 0;
+ g_variant_get(params, "(i)", &parent);
+
+ guint revision = priv->layout_revision;
GPtrArray * xmlarray = g_ptr_array_new();
if (parent == 0) {
@@ -468,199 +961,275 @@ _dbusmenu_server_get_layout (DbusmenuServer * server, gint parent, guint * revis
dbusmenu_menuitem_buildxml(priv->root, xmlarray);
}
} else {
- DbusmenuMenuitem * item = dbusmenu_menuitem_find_id(priv->root, parent);
+ DbusmenuMenuitem * item = NULL;
+ if (priv->root != NULL) {
+ item = dbusmenu_menuitem_find_id(priv->root, parent);
+ }
+
if (item == NULL) {
- if (error != NULL) {
- g_set_error(error,
- error_quark(),
- INVALID_MENUITEM_ID,
- "The ID supplied %d does not refer to a menu item we have",
- parent);
- }
- return FALSE;
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ INVALID_MENUITEM_ID,
+ "The ID supplied %d does not refer to a menu item we have",
+ parent);
+ return;
}
dbusmenu_menuitem_buildxml(item, xmlarray);
}
g_ptr_array_add(xmlarray, NULL);
/* build string */
- *layout = g_strjoinv("", (gchar **)xmlarray->pdata);
+ gchar * layout = g_strjoinv("", (gchar **)xmlarray->pdata);
g_ptr_array_foreach(xmlarray, xmlarray_foreach_free, NULL);
g_ptr_array_free(xmlarray, TRUE);
- return TRUE;
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(us)",
+ revision,
+ layout));
+
+ g_free(layout);
+
+ return;
}
-static gboolean
-_dbusmenu_server_get_property (DbusmenuServer * server, gint id, gchar * property, gchar ** value, GError ** error)
+/* Get a single property off of a single menuitem */
+static void
+bus_get_property (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ if (priv->root == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
+ gint id = g_variant_get_int32(g_variant_get_child_value(params, 0));
+ const gchar * property = g_variant_get_string(g_variant_get_child_value(params, 1), NULL);
+
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
if (mi == NULL) {
- if (error != NULL) {
- g_set_error(error,
+ g_dbus_method_invocation_return_error(invocation,
error_quark(),
INVALID_MENUITEM_ID,
"The ID supplied %d does not refer to a menu item we have",
id);
- }
- return FALSE;
+ return;
}
- const gchar * prop = dbusmenu_menuitem_property_get(mi, property);
- if (prop == NULL) {
- if (error != NULL) {
- g_set_error(error,
+ GVariant * variant = dbusmenu_menuitem_property_get_variant(mi, property);
+ if (variant == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
error_quark(),
INVALID_PROPERTY_NAME,
"The property '%s' does not exist on menuitem with ID of %d",
property,
id);
- }
- return FALSE;
+ return;
}
- if (value == NULL) {
- if (error != NULL) {
- g_set_error(error,
- error_quark(),
- UNKNOWN_DBUS_ERROR,
- "Uhm, yeah. We didn't get anywhere to put the value, that's really weird. Seems impossible really.");
- }
- return FALSE;
- }
-
- *value = g_strdup(prop);
-
- return TRUE;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(v)", variant));
+ return;
}
-static gboolean
-_dbusmenu_server_get_properties (DbusmenuServer * server, gint id, gchar ** properties, GHashTable ** dict, GError ** error)
+/* Get some properties off of a single menuitem */
+static void
+bus_get_properties (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ if (priv->root == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
+ gint id = g_variant_get_int32(g_variant_get_child_value(params, 0));
+
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
if (mi == NULL) {
- if (error != NULL) {
- g_set_error(error,
+ g_dbus_method_invocation_return_error(invocation,
error_quark(),
INVALID_MENUITEM_ID,
"The ID supplied %d does not refer to a menu item we have",
id);
- }
- return FALSE;
+ return;
}
- *dict = dbusmenu_menuitem_properties_copy(mi);
+ GVariant * dict = dbusmenu_menuitem_properties_variant(mi);
- return TRUE;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(a{sv})", dict));
+
+ return;
}
/* Handles getting a bunch of properties from a variety of menu items
to make one mega dbus message */
-static gboolean
-_dbusmenu_server_get_group_properties (DbusmenuServer * server, GArray * ids, gchar ** properties, GPtrArray ** values, GError ** error)
+static void
+bus_get_group_properties (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
- /* Build an initial pointer array */
- *values = g_ptr_array_new();
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
- /* Go through each ID to get that ID's properties */
- int idcnt;
- for (idcnt = 0; idcnt < ids->len; idcnt++) {
- GHashTable * idprops = NULL;
- GError * error = NULL;
- gint id = g_array_index(ids, int, idcnt);
+ if (priv->root == NULL) {
+ GVariant * idlist = g_variant_get_child_value(params, 0);
+ if (g_variant_n_children(idlist) == 1 && g_variant_get_int32(g_variant_get_child_value(idlist, 0)) == 0) {
+ GVariant * final = g_variant_parse(g_variant_type_new("(a(ia{sv}))"), "([(0, {})],)", NULL, NULL, NULL);
+ g_dbus_method_invocation_return_value(invocation, final);
+ return;
+ }
- /* Get the properties for this ID the old fashioned way. */
- if (!_dbusmenu_server_get_properties(server, id, properties, &idprops, &error)) {
- g_warning("Error getting the properties from ID %d: %s", id, error->message);
- g_error_free(error);
- error = NULL;
- continue;
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
+ GVariantIter ids;
+ g_variant_iter_init(&ids, g_variant_get_child_value(params, 0));
+
+ GVariantBuilder builder;
+ gboolean builder_init = FALSE;
+
+ gint id;
+ while (g_variant_iter_next(&ids, "i", &id)) {
+ DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
+ if (mi == NULL) continue;
+
+ if (!builder_init) {
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ builder_init = TRUE;
}
- GValueArray * valarray = g_value_array_new(2);
+ GVariantBuilder wbuilder;
+ g_variant_builder_init(&wbuilder, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add(&wbuilder, "i", id);
+ GVariant * props = dbusmenu_menuitem_properties_variant(mi);
- _gvalue_array_append_int(valarray, id);
- _gvalue_array_append_hashtable(valarray, idprops);
+ if (props == NULL) {
+ GError * error = NULL;
+ props = g_variant_parse(g_variant_type_new("a{sv}"), "{}", NULL, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to parse '{}' as a 'a{sv}': %s", error->message);
+ g_error_free(error);
+ props = NULL;
+ }
+ }
- g_ptr_array_add(*values, valarray);
- }
+ g_variant_builder_add_value(&wbuilder, props);
+ GVariant * mi_data = g_variant_builder_end(&wbuilder);
- return TRUE;
-}
+ g_variant_builder_add_value(&builder, mi_data);
+ }
-/* Allocate a value on the stack for the int and append
- it to the array. */
-static void
-_gvalue_array_append_int(GValueArray *array, gint i)
-{
- GValue value = {0};
+ GVariant * ret = NULL;
+
+ if (builder_init) {
+ ret = g_variant_builder_end(&builder);
+ } else {
+ GError * error = NULL;
+ ret = g_variant_parse(g_variant_type_new("a(ia{sv})"), "[]", NULL, NULL, NULL);
+ if (error != NULL) {
+ g_warning("Unable to parse '[]' as a 'a(ia{sv})': %s", error->message);
+ g_error_free(error);
+ ret = NULL;
+ }
+ }
- g_value_init(&value, G_TYPE_INT);
- g_value_set_int(&value, i);
- g_value_array_append(array, &value);
- g_value_unset(&value);
-}
+ GVariant * final = NULL;
+ if (ret != NULL) {
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&builder, ret);
+ final = g_variant_builder_end(&builder);
+ } else {
+ g_warning("Error building property list, final variant is NULL");
+ }
-/* Allocate a value on the stack for the hashtable and append
- it to the array. */
-static void
-_gvalue_array_append_hashtable(GValueArray *array, GHashTable * dict)
-{
- GValue value = {0};
+ g_dbus_method_invocation_return_value(invocation, final);
- g_value_init(&value, dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE));
- g_value_set_boxed(&value, dict);
- g_value_array_append(array, &value);
- g_value_unset(&value);
+ return;
}
+/* Turn a menuitem into an variant and attach it to the
+ VariantBuilder we passed in */
static void
serialize_menuitem(gpointer data, gpointer user_data)
{
DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(data);
- GPtrArray * output = (GPtrArray *)(user_data);
+ GVariantBuilder * builder = (GVariantBuilder *)(user_data);
+ GVariantBuilder tuple;
+
+ g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
gint id = dbusmenu_menuitem_get_id(mi);
- GHashTable * dict = dbusmenu_menuitem_properties_copy(mi);
-
- GValueArray * item = g_value_array_new(2);
- _gvalue_array_append_int(item, id);
- _gvalue_array_append_hashtable(item, dict);
+ g_variant_builder_add_value(&tuple, g_variant_new_int32(id));
- g_ptr_array_add(output, item);
+ GVariant * props = dbusmenu_menuitem_properties_variant(mi);
+ g_variant_builder_add_value(&tuple, props);
- g_hash_table_unref(dict);
+ g_variant_builder_add_value(builder, g_variant_builder_end(&tuple));
return;
}
-static gboolean
-_dbusmenu_server_get_children (DbusmenuServer * server, gint id, GPtrArray * properties, GPtrArray ** output, GError ** error)
+/* Gets the children and their properties of the ID that is
+ passed into the function */
+static void
+bus_get_children (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+ gint id = g_variant_get_int32(g_variant_get_child_value(params, 0));
+
+ if (priv->root == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
if (mi == NULL) {
- if (error != NULL) {
- g_set_error(error,
- error_quark(),
- INVALID_MENUITEM_ID,
- "The ID supplied %d does not refer to a menu item we have",
- id);
- }
- return FALSE;
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ INVALID_MENUITEM_ID,
+ "The ID supplied %d does not refer to a menu item we have",
+ id);
+ return;
}
- *output = g_ptr_array_new();
GList * children = dbusmenu_menuitem_get_children(mi);
- g_list_foreach(children, serialize_menuitem, *output);
+ GVariant * ret = NULL;
+
+ if (children != NULL) {
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
- return TRUE;
+ g_list_foreach(children, serialize_menuitem, &builder);
+
+ GVariant * end = g_variant_builder_end(&builder);
+ ret = g_variant_new_tuple(&end, 1);
+ } else {
+ GError * error = NULL;
+ ret = g_variant_parse(g_variant_type_new("(a(ia{sv}))"), "([(0, {})],)", NULL, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to parse '([(0, {})],)' as a '(a(ia{sv}))': %s", error->message);
+ g_error_free(error);
+ ret = NULL;
+ }
+ }
+
+ g_dbus_method_invocation_return_value(invocation, ret);
+ return;
}
/* Structure for holding the event data for the idle function
@@ -669,7 +1238,7 @@ typedef struct _idle_event_t idle_event_t;
struct _idle_event_t {
DbusmenuMenuitem * mi;
gchar * eventid;
- GValue data;
+ GVariant * variant;
guint timestamp;
};
@@ -680,66 +1249,92 @@ event_local_handler (gpointer user_data)
{
idle_event_t * data = (idle_event_t *)user_data;
- dbusmenu_menuitem_handle_event(data->mi, data->eventid, &data->data, data->timestamp);
+ dbusmenu_menuitem_handle_event(data->mi, data->eventid, data->variant, data->timestamp);
g_object_unref(data->mi);
g_free(data->eventid);
- g_value_unset(&data->data);
+ g_variant_unref(data->variant);
g_free(data);
return FALSE;
}
-/* Handles the even coming off of DBus */
-static gboolean
-_dbusmenu_server_event (DbusmenuServer * server, gint id, gchar * eventid, GValue * data, guint timestamp, GError ** error)
+/* Handles the events coming off of DBus */
+static void
+bus_event (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ if (priv->root == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
+ gint id = g_variant_get_int32(g_variant_get_child_value(params, 0));
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
if (mi == NULL) {
- if (error != NULL) {
- g_set_error(error,
- error_quark(),
- INVALID_MENUITEM_ID,
- "The ID supplied %d does not refer to a menu item we have",
- id);
- }
- return FALSE;
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ INVALID_MENUITEM_ID,
+ "The ID supplied %d does not refer to a menu item we have",
+ id);
+ return;
}
idle_event_t * event_data = g_new0(idle_event_t, 1);
event_data->mi = mi;
g_object_ref(event_data->mi);
- event_data->eventid = g_strdup(eventid);
- event_data->timestamp = timestamp;
- g_value_init(&(event_data->data), G_VALUE_TYPE(data));
- g_value_copy(data, &(event_data->data));
+ event_data->eventid = g_strdup(g_variant_get_string(g_variant_get_child_value(params, 1), NULL));
+ event_data->timestamp = g_variant_get_uint32(g_variant_get_child_value(params, 3));
+ event_data->variant = g_variant_get_child_value(params, 2);
+
+ if (g_variant_is_of_type(event_data->variant, G_VARIANT_TYPE_VARIANT)) {
+ event_data->variant = g_variant_get_variant(event_data->variant);
+ }
+
+ g_variant_ref(event_data->variant);
g_timeout_add(0, event_local_handler, event_data);
- return TRUE;
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
}
/* Recieve the About To Show function. Pass it to our menu item. */
-static gboolean
-_dbusmenu_server_about_to_show (DbusmenuServer * server, gint id, gboolean * need_update, GError ** error)
+static void
+bus_about_to_show (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * invocation)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ if (priv->root == NULL) {
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ NO_VALID_LAYOUT,
+ "There currently isn't a layout in this server");
+ return;
+ }
+
+ gint id = g_variant_get_int32(g_variant_get_child_value(params, 0));
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
if (mi == NULL) {
- if (error != NULL) {
- g_set_error(error,
- error_quark(),
- INVALID_MENUITEM_ID,
- "The ID supplied %d does not refer to a menu item we have",
- id);
- }
- return FALSE;
+ g_dbus_method_invocation_return_error(invocation,
+ error_quark(),
+ INVALID_MENUITEM_ID,
+ "The ID supplied %d does not refer to a menu item we have",
+ id);
+ return;
}
+ dbusmenu_menuitem_send_about_to_show(mi, NULL, NULL);
+
/* GTK+ does not support about-to-show concept for now */
- *need_update = FALSE;
- return TRUE;
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(b)", FALSE));
+ return;
}
/* Public Interface */
@@ -750,7 +1345,7 @@ _dbusmenu_server_about_to_show (DbusmenuServer * server, gint id, gboolean * nee
Creates a new #DbusmenuServer object with a specific object
path on DBus. If @object is set to NULL the default object
- name of "/org/ayatana/dbusmenu" will be used.
+ name of "/com/canonical/dbusmenu" will be used.
Return value: A brand new #DbusmenuServer
*/
@@ -758,7 +1353,7 @@ DbusmenuServer *
dbusmenu_server_new (const gchar * object)
{
if (object == NULL) {
- object = "/org/ayatana/dbusmenu";
+ object = "/com/canonical/dbusmenu";
}
DbusmenuServer * self = g_object_new(DBUSMENU_TYPE_SERVER,
diff --git a/libdbusmenu-glib/server.h b/libdbusmenu-glib/server.h
index a9bf213..5668258 100644
--- a/libdbusmenu-glib/server.h
+++ b/libdbusmenu-glib/server.h
@@ -53,6 +53,8 @@ G_BEGIN_DECLS
#define DBUSMENU_SERVER_PROP_ROOT_NODE "root-node"
#define DBUSMENU_SERVER_PROP_VERSION "version"
+typedef struct _DbusmenuServerPrivate DbusmenuServerPrivate;
+
/**
DbusmenuServerClass:
@parent_class: #GObjectClass
@@ -60,9 +62,13 @@ G_BEGIN_DECLS
@id_update: Slot for #DbusmenuServer::id-update.
@layout_updated: Slot for #DbusmenuServer::layout-update.
@item_activation_requested: Slot for #DbusmenuServer::item-activation-requested.
- @dbusmenu_server_reserved1: Reserved for future use.
- @dbusmenu_server_reserved2: Reserved for future use.
- @dbusmenu_server_reserved3: Reserved for future use.
+
+ @reserved1: Reserved for future use.
+ @reserved2: Reserved for future use.
+ @reserved3: Reserved for future use.
+ @reserved4: Reserved for future use.
+ @reserved5: Reserved for future use.
+ @reserved6: Reserved for future use.
The class implementing the virtual functions for #DbusmenuServer.
*/
@@ -76,10 +82,13 @@ struct _DbusmenuServerClass {
void (*layout_updated)(gint revision);
void (*item_activation)(gint id, guint timestamp);
- /* Reserved */
- void (*dbusmenu_server_reserved1)(void);
- void (*dbusmenu_server_reserved2)(void);
- void (*dbusmenu_server_reserved3)(void);
+ /*< Private >*/
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
};
/**
@@ -92,6 +101,9 @@ struct _DbusmenuServerClass {
typedef struct _DbusmenuServer DbusmenuServer;
struct _DbusmenuServer {
GObject parent;
+
+ /*< Private >*/
+ DbusmenuServerPrivate * priv;
};
GType dbusmenu_server_get_type (void);
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index 2be63b7..f3556e9 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -1,18 +1,31 @@
CLEANFILES =
-EXTRA_DIST = \
- dbusmenu-gtk.pc.in
+if USE_GTK3
+VER=3
+GTKGIR=Gtk-3.0
+GTKVALA=gtk+-3.0
+lib_LTLIBRARIES = libdbusmenu-gtk3.la
+else
+VER=
+GTKGIR=Gtk-2.0
+GTKVALA=gtk+-2.0
+lib_LTLIBRARIES = libdbusmenu-gtk.la
+endif
-lib_LTLIBRARIES = \
- libdbusmenu-gtk.la
+EXTRA_DIST = \
+ dbusmenu-gtk-0.4.pc.in \
+ dbusmenu-gtk3-0.4.pc.in
-libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-gtk/
+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 \
@@ -22,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) \
@@ -36,7 +53,18 @@ libdbusmenu_gtk_la_LIBADD = \
../libdbusmenu-glib/libdbusmenu-glib.la \
$(DBUSMENUGTK_LIBS)
-pkgconfig_DATA = dbusmenu-gtk.pc
+# We duplicate these here because Automake won't let us use $(VER) on the left hand side.
+# Since we carefully use $(VER) in the right hand side above, we can assign the same values.
+# Only one version of the library is every compiled at the same time, so it is safe to reuse
+# the right hand sides like this.
+libdbusmenu_gtk3includedir = $(libdbusmenu_gtkincludedir)
+libdbusmenu_gtk3include_HEADERS = $(libdbusmenu_gtkinclude_HEADERS)
+libdbusmenu_gtk3_la_SOURCES = $(libdbusmenu_gtk_la_SOURCES)
+libdbusmenu_gtk3_la_LDFLAGS = $(libdbusmenu_gtk_la_LDFLAGS)
+libdbusmenu_gtk3_la_CFLAGS = $(libdbusmenu_gtk_la_CFLAGS)
+libdbusmenu_gtk3_la_LIBADD = $(libdbusmenu_gtk_la_LIBADD)
+
+pkgconfig_DATA = dbusmenu-gtk$(VER)-0.4.pc
pkgconfigdir = $(libdir)/pkgconfig
#########################
@@ -45,26 +73,49 @@ pkgconfigdir = $(libdir)/pkgconfig
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = \
- --add-include-path=$(srcdir) \
+
+if INTROSPECTION_TEN
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) \
+ --warn-all \
+ --add-include-path=$(top_builddir)/libdbusmenu-glib \
+ $(addprefix --c-include=libdbusmenu-gtk/, $(introspection_sources)) \
+ --symbol-prefix=dbusmenu \
+ --identifier-prefix=DbusmenuGtk
+else
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) \
+ --warn-all \
--add-include-path=$(top_builddir)/libdbusmenu-glib \
$(addprefix --c-include=libdbusmenu-gtk/, $(introspection_sources))
+endif
+
INTROSPECTION_COMPILER_ARGS = --includedir=$(builddir) --includedir=$(top_builddir)/libdbusmenu-glib
if HAVE_INTROSPECTION
introspection_sources = $(libdbusmenu_gtkinclude_HEADERS)
-DbusmenuGtk-0.2.gir: libdbusmenu-gtk.la
-DbusmenuGtk_0_2_gir_INCLUDES = \
+DbusmenuGtk$(VER)-0.4.gir: libdbusmenu-gtk$(VER).la
+DbusmenuGtk_0_4_gir_INCLUDES = \
GObject-2.0 \
- Gtk-2.0 \
- Dbusmenu-Glib-0.2
-DbusmenuGtk_0_2_gir_CFLAGS = $(DBUSMENUGTK_CFLAGS) -I$(top_srcdir)
-DbusmenuGtk_0_2_gir_LIBS = libdbusmenu-gtk.la
-DbusmenuGtk_0_2_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
-
-INTROSPECTION_GIRS += DbusmenuGtk-0.2.gir
+ $(GTKGIR) \
+ Dbusmenu-Glib-0.4
+DbusmenuGtk_0_4_gir_CFLAGS = $(DBUSMENUGTK_CFLAGS) -I$(top_srcdir)
+DbusmenuGtk_0_4_gir_LIBS = libdbusmenu-gtk$(VER).la
+DbusmenuGtk_0_4_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
+DbusmenuGtk_0_4_gir_NAMESPACE = DbusmenuGtk$(VER)
+DbusmenuGtk_0_4_gir_SCANNERFLAGS = $(INTROSPECTION_SCANNER_ARGS)
+DbusmenuGtk_0_4_gir_EXPORT_PACKAGES = dbusmenu-gtk$(VER)-0.4
+
+# We duplicate these for the same reason as libdbusmenu_gtk3includedir above
+DbusmenuGtk3_0_4_gir_INCLUDES = $(DbusmenuGtk_0_4_gir_INCLUDES)
+DbusmenuGtk3_0_4_gir_CFLAGS = $(DbusmenuGtk_0_4_gir_CFLAGS)
+DbusmenuGtk3_0_4_gir_LIBS = $(DbusmenuGtk_0_4_gir_LIBS)
+DbusmenuGtk3_0_4_gir_FILES = $(DbusmenuGtk_0_4_gir_FILES)
+DbusmenuGtk3_0_4_gir_NAMESPACE = $(DbusmenuGtk_0_4_gir_NAMESPACE)
+DbusmenuGtk3_0_4_gir_SCANNERFLAGS = $(DbusmenuGtk_0_4_gir_SCANNERFLAGS)
+DbusmenuGtk3_0_4_gir_EXPORT_PACKAGES = $(DbusmenuGtk_0_4_gir_EXPORT_PACKAGES)
+
+INTROSPECTION_GIRS += DbusmenuGtk$(VER)-0.4.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
@@ -83,24 +134,24 @@ endif
if HAVE_INTROSPECTION
vapidir = $(datadir)/vala/vapi
-vapi_DATA = DbusmenuGtk-0.2.vapi
+vapi_DATA = DbusmenuGtk$(VER)-0.4.vapi
-DbusmenuGtk-0.2.vapi: DbusmenuGtk-0.2.tmp.gir Makefile.am
- $(VALA_API_GEN) --library=DbusmenuGtk-0.2 \
+DbusmenuGtk$(VER)-0.4.vapi: DbusmenuGtk$(VER)-0.4.tmp.gir Makefile.am
+ $(VALA_API_GEN) --library=DbusmenuGtk$(VER)-0.4 \
--pkg gdk-pixbuf-2.0 \
- --pkg gtk+-2.0 \
+ --pkg $(GTKVALA) \
--pkg atk \
- --pkg Dbusmenu-Glib-0.2 \
+ --pkg Dbusmenu-Glib-0.4 \
--vapidir=$(top_builddir)/libdbusmenu-glib \
$<
-DbusmenuGtk-0.2.tmp.gir: DbusmenuGtk-0.2.gir
+DbusmenuGtk$(VER)-0.4.tmp.gir: DbusmenuGtk$(VER)-0.4.gir
$(SED) \
-e "s|GdkPixbuf.Pixbuf|Gdk.Pixbuf|g" \
-e "s|Atk.ImplementorIface|Atk.Implementor|g" \
$< > $@
-CLEANFILES += $(vapi_DATA) DbusmenuGtk-0.2.tmp.gir
+CLEANFILES += $(vapi_DATA) DbusmenuGtk$(VER)-0.4.tmp.gir
endif
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 6970d59..7ab2fe9 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -37,13 +37,12 @@ License version 3 and version 2.1 along with this program. If not, see
#include "genericmenuitem.h"
/* Private */
-typedef struct _DbusmenuGtkClientPrivate DbusmenuGtkClientPrivate;
struct _DbusmenuGtkClientPrivate {
GtkAccelGroup * agroup;
};
-#define DBUSMENU_GTKCLIENT_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_GTKCLIENT_TYPE, 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);
@@ -56,12 +55,12 @@ 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, const GValue * value);
-static void process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value);
-static void image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GValue * invalue, gpointer userdata);
+static void process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value);
+static void process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value);
+static void image_property_handle (DbusmenuMenuitem * item, const gchar * property, GVariant * invalue, gpointer userdata);
/* GObject Stuff */
G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT);
@@ -85,6 +84,8 @@ dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass)
static void
dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_GTKCLIENT_TYPE, DbusmenuGtkClientPrivate);
+
DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(self);
priv->agroup = NULL;
@@ -249,6 +250,7 @@ dbusmenu_gtkclient_set_accel_group (DbusmenuGtkClient * client, GtkAccelGroup *
}
priv->agroup = agroup;
+ g_object_ref(priv->agroup);
return;
}
@@ -283,10 +285,8 @@ static gboolean
menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
{
if (gtk_menu_item_get_submenu(gmi) == NULL) {
- GValue value = {0};
- g_value_init(&value, G_TYPE_INT);
- g_value_set_int(&value, 0);
- dbusmenu_menuitem_handle_event(mi, "clicked", &value, gtk_get_current_event_time());
+ GVariant * variant = g_variant_new("i", 0);
+ dbusmenu_menuitem_handle_event(mi, "clicked", variant, gtk_get_current_event_time());
} else {
/* TODO: We need to stop the display of the submenu
until this callback returns. */
@@ -297,7 +297,7 @@ menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
/* Process the visible property */
static void
-process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value)
{
gboolean val = TRUE;
if (value != NULL) {
@@ -314,7 +314,7 @@ process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
/* Process the sensitive property */
static void
-process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * value)
{
gboolean val = TRUE;
if (value != NULL) {
@@ -326,26 +326,21 @@ process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * valu
/* Process the sensitive property */
static void
-process_toggle_type (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+process_toggle_type (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * variant)
{
if (!IS_GENERICMENUITEM(gmi)) return;
- if (value == NULL) return;
+ if (variant == NULL) return;
GenericmenuitemCheckType type = GENERICMENUITEM_CHECK_TYPE_NONE;
- GValue strvalue = {0};
- g_value_init(&strvalue, G_TYPE_STRING);
-
- if (value != NULL && g_value_transform(value, &strvalue)) {
- const gchar * strval = g_value_get_string(&strvalue);
+ if (variant != NULL) {
+ const gchar * strval = g_variant_get_string(variant, NULL);
if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_CHECK)) {
type = GENERICMENUITEM_CHECK_TYPE_CHECKBOX;
} else if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_RADIO)) {
type = GENERICMENUITEM_CHECK_TYPE_RADIO;
}
-
- g_value_unset(&strvalue);
}
genericmenuitem_set_check_type(GENERICMENUITEM(gmi), type);
@@ -355,17 +350,14 @@ process_toggle_type (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * va
/* Process the sensitive property */
static void
-process_toggle_state (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+process_toggle_state (DbusmenuMenuitem * mi, GtkMenuItem * gmi, GVariant * variant)
{
if (!IS_GENERICMENUITEM(gmi)) return;
GenericmenuitemState state = GENERICMENUITEM_STATE_UNCHECKED;
- GValue intvalue = {0};
- g_value_init(&intvalue, G_TYPE_INT);
-
- if (value != NULL && g_value_transform(value, &intvalue)) {
- int val = g_value_get_int(&intvalue);
+ if (variant != NULL) {
+ int val = g_variant_get_int32(variant);
if (val == DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED) {
state = GENERICMENUITEM_STATE_CHECKED;
@@ -381,18 +373,18 @@ process_toggle_state (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * v
/* Whenever we have a property change on a DbusmenuMenuitem
we need to be responsive to that. */
static void
-menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkMenuItem * gmi)
+menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * variant, GtkMenuItem * gmi)
{
if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_LABEL)) {
- gtk_menu_item_set_label(gmi, g_value_get_string(value));
+ gtk_menu_item_set_label(gmi, variant == NULL ? NULL : g_variant_get_string(variant, NULL));
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
- process_visible(mi, gmi, value);
+ process_visible(mi, gmi, variant);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_ENABLED)) {
- process_sensitive(mi, gmi, value);
+ process_sensitive(mi, gmi, variant);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE)) {
- process_toggle_type(mi, gmi, value);
+ process_toggle_type(mi, gmi, variant);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE)) {
- process_toggle_state(mi, gmi, value);
+ process_toggle_state(mi, gmi, variant);
}
return;
@@ -401,7 +393,7 @@ menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkMen
/* Special handler for the shortcut changing as we need to have the
client for that one to get the accel group. */
static void
-menu_shortcut_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, DbusmenuGtkClient * client)
+menu_shortcut_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, DbusmenuGtkClient * client)
{
if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SHORTCUT)) {
refresh_shortcut(client, mi);
@@ -454,11 +446,17 @@ activate_helper (GtkMenuShell * shell)
activate_helper(GTK_MENU_SHELL(parent));
}
+ /* This code is being commented out for GTK 3 because it
+ doesn't expose the right variables. We need to figure
+ this out as menus won't get grabs properly.
+ TODO FIXME HELP ARGHHHHHHHH */
+#if (HAVE_GTK3 == 0)
if (!GTK_MENU_SHELL (parent)->active) {
gtk_grab_add (parent);
GTK_MENU_SHELL (parent)->have_grab = TRUE;
GTK_MENU_SHELL (parent)->active = TRUE;
}
+#endif
gtk_menu_shell_select_item(GTK_MENU_SHELL(parent), attach);
}
@@ -537,10 +535,10 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
g_object_weak_ref(G_OBJECT(item), destoryed_dbusmenuitem_cb, gmi);
/* Check our set of props to see if any are set already */
- process_visible(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
- process_sensitive(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_ENABLED));
- process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE));
- process_toggle_state(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE));
+ process_visible(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
+ process_sensitive(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_ENABLED));
+ process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE));
+ process_toggle_state(item, gmi, dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE));
refresh_shortcut(client, item);
/* Oh, we're a child, let's deal with that */
@@ -687,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);
@@ -705,11 +703,11 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
image_property_handle(newitem,
DBUSMENU_MENUITEM_PROP_ICON_NAME,
- dbusmenu_menuitem_property_get_value(newitem, DBUSMENU_MENUITEM_PROP_ICON_NAME),
+ dbusmenu_menuitem_property_get_variant(newitem, DBUSMENU_MENUITEM_PROP_ICON_NAME),
client);
image_property_handle(newitem,
DBUSMENU_MENUITEM_PROP_ICON_DATA,
- dbusmenu_menuitem_property_get_value(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
+ dbusmenu_menuitem_property_get_variant(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
client);
g_signal_connect(G_OBJECT(newitem),
DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
@@ -722,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);
@@ -740,10 +738,33 @@ 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
-image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GValue * invalue, gpointer userdata)
+image_property_handle (DbusmenuMenuitem * item, const gchar * property, GVariant * variant, gpointer userdata)
{
/* We're only looking at these two properties here */
if (g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_NAME) != 0 &&
@@ -752,11 +773,10 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GV
}
const gchar * value = NULL;
-
- if (invalue != NULL && G_VALUE_TYPE(invalue) == G_TYPE_STRING) {
- value = g_value_get_string(invalue);
+ if (variant != NULL) {
+ value = g_variant_get_string(variant, NULL);
}
-
+
if (value == NULL || value[0] == '\0') {
/* This means that we're unsetting a value. */
/* Try to use the other one */
@@ -793,6 +813,7 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GV
gtkimage = NULL;
} else if (g_strcmp0(iconname, DBUSMENU_MENUITEM_ICON_NAME_BLANK) == 0) {
gtkimage = gtk_image_new();
+ 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. */
@@ -811,6 +832,7 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GV
can just convert it to this name. */
if (gtkimage == NULL) {
gtkimage = gtk_image_new_from_icon_name(finaliconname, GTK_ICON_SIZE_MENU);
+ set_use_fallback(gtkimage);
} else {
gtk_image_set_from_icon_name(GTK_IMAGE(gtkimage), finaliconname, GTK_ICON_SIZE_MENU);
}
diff --git a/libdbusmenu-gtk/client.h b/libdbusmenu-gtk/client.h
index a7c96ee..c986a5d 100644
--- a/libdbusmenu-gtk/client.h
+++ b/libdbusmenu-gtk/client.h
@@ -43,6 +43,8 @@ G_BEGIN_DECLS
#define DBUSMENU_GTKCLIENT_SIGNAL_ROOT_CHANGED DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED
+typedef struct _DbusmenuGtkClientPrivate DbusmenuGtkClientPrivate;
+
/**
DbusmenuGtkClientClass:
@parent_class: #GtkMenuClass
@@ -50,6 +52,8 @@ G_BEGIN_DECLS
@reserved2: Reserved for future use.
@reserved3: Reserved for future use.
@reserved4: Reserved for future use.
+ @reserved5: Reserved for future use.
+ @reserved6: Reserved for future use.
*/
typedef struct _DbusmenuGtkClientClass DbusmenuGtkClientClass;
struct _DbusmenuGtkClientClass {
@@ -58,11 +62,13 @@ struct _DbusmenuGtkClientClass {
/* Signals */
void (*root_changed) (DbusmenuMenuitem * newroot);
- /* Reserved */
+ /*< Private >*/
void (*reserved1) (void);
void (*reserved2) (void);
void (*reserved3) (void);
void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
};
/**
@@ -72,6 +78,9 @@ struct _DbusmenuGtkClientClass {
typedef struct _DbusmenuGtkClient DbusmenuGtkClient;
struct _DbusmenuGtkClient {
DbusmenuClient parent;
+
+ /*< Private >*/
+ DbusmenuGtkClientPrivate * priv;
};
GType dbusmenu_gtkclient_get_type (void);
diff --git a/libdbusmenu-gtk/dbusmenu-gtk.pc.in b/libdbusmenu-gtk/dbusmenu-gtk-0.4.pc.in
index df4cb36..8784556 100644
--- a/libdbusmenu-gtk/dbusmenu-gtk.pc.in
+++ b/libdbusmenu-gtk/dbusmenu-gtk-0.4.pc.in
@@ -4,8 +4,8 @@ libdir=@libdir@
bindir=@bindir@
includedir=@includedir@
-Cflags: -I${includedir}/libdbusmenu-0.1
-Requires: dbus-glib-1 dbusmenu-glib
+Cflags: -I${includedir}/libdbusmenu-0.4
+Requires: dbusmenu-glib-0.4
Libs: -L${libdir} -ldbusmenu-gtk
Name: libdbusmenu-gtk
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/dbusmenu-gtk3-0.4.pc.in b/libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc.in
new file mode 100644
index 0000000..804b13e
--- /dev/null
+++ b/libdbusmenu-gtk/dbusmenu-gtk3-0.4.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+bindir=@bindir@
+includedir=@includedir@
+
+Cflags: -I${includedir}/libdbusmenu-0.4
+Requires: dbusmenu-glib-0.4
+Libs: -L${libdir} -ldbusmenu-gtk3
+
+Name: libdbusmenu-gtk3
+Description: libdbusmenu-gtk3.
+Version: @VERSION@
+
diff --git a/libdbusmenu-gtk/genericmenuitem.c b/libdbusmenu-gtk/genericmenuitem.c
index 30b072f..2af70f3 100644
--- a/libdbusmenu-gtk/genericmenuitem.c
+++ b/libdbusmenu-gtk/genericmenuitem.c
@@ -51,7 +51,6 @@ static void genericmenuitem_class_init (GenericmenuitemClass *klass);
static void genericmenuitem_init (Genericmenuitem *self);
static void genericmenuitem_dispose (GObject *object);
static void genericmenuitem_finalize (GObject *object);
-static void draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area);
static void set_label (GtkMenuItem * menu_item, const gchar * label);
static const gchar * get_label (GtkMenuItem * menu_item);
static void activate (GtkMenuItem * menu_item);
@@ -59,8 +58,14 @@ static void activate (GtkMenuItem * menu_item);
/* GObject stuff */
G_DEFINE_TYPE (Genericmenuitem, genericmenuitem, GTK_TYPE_CHECK_MENU_ITEM);
-/* Globals */
+#if HAVE_GTK3
+static void draw_indicator (GtkCheckMenuItem *check_menu_item, cairo_t *cr);
+static void (*parent_draw_indicator) (GtkCheckMenuItem *check_menu_item, cairo_t *cr) = NULL;
+#else
+static void draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area);
static void (*parent_draw_indicator) (GtkCheckMenuItem *check_menu_item, GdkRectangle *area) = NULL;
+#endif
+static void (*parent_menuitem_activate) (GtkMenuItem * mi) = NULL;
/* Initializing all of the classes. Most notably we're
disabling the drawing of the check early. */
@@ -82,6 +87,7 @@ genericmenuitem_class_init (GenericmenuitemClass *klass)
GtkMenuItemClass * menuitem_class = GTK_MENU_ITEM_CLASS (klass);
menuitem_class->set_label = set_label;
menuitem_class->get_label = get_label;
+ parent_menuitem_activate = menuitem_class->activate;
menuitem_class->activate = activate;
return;
@@ -121,6 +127,17 @@ genericmenuitem_finalize (GObject *object)
/* Checks to see if we should be drawing a little box at
all. If we should be, let's do that, otherwise we're
going suppress the box drawing. */
+#if HAVE_GTK3
+static void
+draw_indicator (GtkCheckMenuItem *check_menu_item, cairo_t *cr)
+{
+ Genericmenuitem * self = GENERICMENUITEM(check_menu_item);
+ if (self->priv->check_type != GENERICMENUITEM_CHECK_TYPE_NONE) {
+ parent_draw_indicator(check_menu_item, cr);
+ }
+ return;
+}
+#else
static void
draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area)
{
@@ -130,6 +147,7 @@ draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area)
}
return;
}
+#endif
/* A small helper to look through the widgets in the
box and find the one that is the label. */
@@ -275,7 +293,6 @@ genericmenuitem_set_check_type (Genericmenuitem * item, GenericmenuitemCheckType
}
item->priv->check_type = check_type;
- GValue value = {0};
switch (item->priv->check_type) {
case GENERICMENUITEM_CHECK_TYPE_NONE:
@@ -284,14 +301,10 @@ genericmenuitem_set_check_type (Genericmenuitem * item, GenericmenuitemCheckType
check on the item. */
break;
case GENERICMENUITEM_CHECK_TYPE_CHECKBOX:
- g_value_init(&value, G_TYPE_BOOLEAN);
- g_value_set_boolean(&value, FALSE);
- g_object_set_property(G_OBJECT(item), "draw-as-radio", &value);
+ gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(item), FALSE);
break;
case GENERICMENUITEM_CHECK_TYPE_RADIO:
- g_value_init(&value, G_TYPE_BOOLEAN);
- g_value_set_boolean(&value, TRUE);
- g_object_set_property(G_OBJECT(item), "draw-as-radio", &value);
+ gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(item), TRUE);
break;
default:
g_warning("Generic Menuitem invalid check type: %d", check_type);
@@ -322,38 +335,32 @@ genericmenuitem_set_state (Genericmenuitem * item, GenericmenuitemState state)
item->priv->state = state;
GtkCheckMenuItem * check = GTK_CHECK_MENU_ITEM(item);
-
- gboolean old_active = check->active;
- gboolean old_inconsist = check->inconsistent;
+ gboolean goal_active = FALSE;
switch (item->priv->state) {
case GENERICMENUITEM_STATE_UNCHECKED:
- check->active = FALSE;
- check->inconsistent = FALSE;
+ goal_active = FALSE;
+ gtk_check_menu_item_set_inconsistent (check, FALSE);
break;
case GENERICMENUITEM_STATE_CHECKED:
- check->active = TRUE;
- check->inconsistent = FALSE;
+ goal_active = TRUE;
+ gtk_check_menu_item_set_inconsistent (check, FALSE);
break;
case GENERICMENUITEM_STATE_INDETERMINATE:
- check->active = TRUE;
- check->inconsistent = TRUE;
+ goal_active = TRUE;
+ gtk_check_menu_item_set_inconsistent (check, TRUE);
break;
default:
g_warning("Generic Menuitem invalid check state: %d", state);
return;
}
- if (old_active != check->active) {
- g_object_notify(G_OBJECT(item), "active");
- }
-
- if (old_inconsist != check->inconsistent) {
- g_object_notify(G_OBJECT(item), "inconsistent");
+ if (goal_active != gtk_check_menu_item_get_active(check)) {
+ if (parent_menuitem_activate != NULL) {
+ parent_menuitem_activate(GTK_MENU_ITEM(check));
+ }
}
- gtk_widget_queue_draw(GTK_WIDGET(item));
-
return;
}
diff --git a/libdbusmenu-gtk/menu.c b/libdbusmenu-gtk/menu.c
index 4fa546b..2a27fe2 100644
--- a/libdbusmenu-gtk/menu.c
+++ b/libdbusmenu-gtk/menu.c
@@ -44,16 +44,15 @@ enum {
};
/* Private */
-typedef struct _DbusmenuGtkMenuPrivate DbusmenuGtkMenuPrivate;
struct _DbusmenuGtkMenuPrivate {
DbusmenuGtkClient * client;
+ DbusmenuMenuitem * root;
gchar * dbus_object;
gchar * dbus_name;
};
-#define DBUSMENU_GTKMENU_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuPrivate))
+#define DBUSMENU_GTKMENU_GET_PRIVATE(o) (DBUSMENU_GTKMENU(o)->priv)
/* Prototypes */
static void dbusmenu_gtkmenu_class_init (DbusmenuGtkMenuClass *klass);
@@ -65,6 +64,8 @@ static void get_property (GObject * obj, guint id, GValue * value, GParamSpec *
/* Internal */
static void build_client (DbusmenuGtkMenu * self);
static void child_realized (DbusmenuMenuitem * child, gpointer userdata);
+static void remove_child_signals (gpointer data, gpointer user_data);
+static void root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu);
/* GObject Stuff */
G_DEFINE_TYPE (DbusmenuGtkMenu, dbusmenu_gtkmenu, GTK_TYPE_MENU);
@@ -110,6 +111,8 @@ menu_focus_cb(DbusmenuGtkMenu * menu, gpointer userdata)
static void
dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuPrivate);
+
DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(self);
priv->client = NULL;
@@ -127,6 +130,12 @@ dbusmenu_gtkmenu_dispose (GObject *object)
{
DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(object);
+ /* Remove signals from the root */
+ if (priv->root != NULL) {
+ /* This will clear the root */
+ root_changed(priv->client, NULL, DBUSMENU_GTKMENU(object));
+ }
+
if (priv->client != NULL) {
g_object_unref(G_OBJECT(priv->client));
priv->client = NULL;
@@ -237,7 +246,7 @@ root_child_added (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint posit
GtkMenuItem * mi = dbusmenu_gtkclient_menuitem_get(priv->client, child);
if (mi != NULL) {
GtkWidget * item = GTK_WIDGET(mi);
- gtk_menu_insert(GTK_MENU(menu), item, dbusmenu_menuitem_get_position_realized(child, root));
+ gtk_menu_shell_insert(GTK_MENU_SHELL(menu), item, dbusmenu_menuitem_get_position_realized(child, root));
#ifdef MASSIVEDEBUGGING
menu_pos_t menu_pos;
menu_pos.mi = mi;
@@ -271,6 +280,10 @@ root_child_delete (DbusmenuMenuitem * root, DbusmenuMenuitem * child, DbusmenuGt
#ifdef MASSIVEDEBUGGING
g_debug("Root child deleted");
#endif
+
+ /* Remove signal for realized */
+ remove_child_signals(child, menu);
+
DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu);
GtkWidget * item = GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child));
if (item != NULL) {
@@ -299,7 +312,7 @@ child_realized (DbusmenuMenuitem * child, gpointer userdata)
GtkWidget * child_widget = GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child));
if (child_widget != NULL) {
- gtk_menu_append(menu, child_widget);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), child_widget);
gtk_menu_reorder_child(GTK_MENU(menu), child_widget, dbusmenu_menuitem_get_position_realized(child, dbusmenu_client_get_root(DBUSMENU_CLIENT(priv->client))));
} else {
g_warning("Child is realized, but doesn't have a GTK Widget!");
@@ -308,15 +321,41 @@ child_realized (DbusmenuMenuitem * child, gpointer userdata)
return;
}
+/* Remove any signals we attached to children -- just realized right now */
+static void
+remove_child_signals (gpointer data, gpointer user_data)
+{
+ g_signal_handlers_disconnect_by_func(G_OBJECT(data), child_realized, user_data);
+ return;
+}
+
/* When the root menuitem changes we need to resetup things so that
we're back in the game. */
static void
root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu) {
+ DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu);
+
+ /* Clear out our interest in the old root */
+ if (priv->root != NULL) {
+ GList * children = dbusmenu_menuitem_get_children(priv->root);
+ g_list_foreach(children, remove_child_signals, menu);
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_added, menu);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_moved, menu);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_delete, menu);
+
+ g_object_unref(priv->root);
+ priv->root = NULL;
+ }
+
if (newroot == NULL) {
gtk_widget_hide(GTK_WIDGET(menu));
return;
}
+ priv->root = newroot;
+ g_object_ref(priv->root);
+
g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(root_child_added), menu);
g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(root_child_moved), menu);
g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(root_child_delete), menu);
diff --git a/libdbusmenu-gtk/menu.h b/libdbusmenu-gtk/menu.h
index 5147d30..896e466 100644
--- a/libdbusmenu-gtk/menu.h
+++ b/libdbusmenu-gtk/menu.h
@@ -42,6 +42,8 @@ G_BEGIN_DECLS
#define DBUSMENU_IS_GTKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_GTKMENU_TYPE))
#define DBUSMENU_GTKMENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuClass))
+typedef struct _DbusmenuGtkMenuPrivate DbusmenuGtkMenuPrivate;
+
/**
DbusmenuGtkMenuClass:
@parent_class: #GtkMenuClass
@@ -49,16 +51,20 @@ G_BEGIN_DECLS
@reserved2: Reserved for future use.
@reserved3: Reserved for future use.
@reserved4: Reserved for future use.
+ @reserved5: Reserved for future use.
+ @reserved6: Reserved for future use.
*/
typedef struct _DbusmenuGtkMenuClass DbusmenuGtkMenuClass;
struct _DbusmenuGtkMenuClass {
GtkMenuClass parent_class;
- /* Reserved */
+ /*< Private >*/
void (*reserved1) (void);
void (*reserved2) (void);
void (*reserved3) (void);
void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
};
/**
@@ -68,6 +74,9 @@ struct _DbusmenuGtkMenuClass {
typedef struct _DbusmenuGtkMenu DbusmenuGtkMenu;
struct _DbusmenuGtkMenu {
GtkMenu parent;
+
+ /*< Private >*/
+ DbusmenuGtkMenuPrivate * priv;
};
GType dbusmenu_gtkmenu_get_type (void);
diff --git a/libdbusmenu-gtk/menuitem.c b/libdbusmenu-gtk/menuitem.c
index 5846aa7..fa5eb89 100644
--- a/libdbusmenu-gtk/menuitem.c
+++ b/libdbusmenu-gtk/menuitem.c
@@ -29,7 +29,6 @@ License version 3 and version 2.1 along with this program. If not, see
#include "menuitem.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
-#include <dbus/dbus-gtype-specialized.h>
/**
dbusmenu_menuitem_property_set_image:
@@ -178,50 +177,31 @@ dbusmenu_menuitem_property_set_shortcut (DbusmenuMenuitem * menuitem, guint key,
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
g_return_val_if_fail(gtk_accelerator_valid(key, modifier), FALSE);
- GArray * array = g_array_sized_new(TRUE, TRUE, sizeof(gchar *), 4); /* Four seems like the max we'd need, plus it's still small */
-
- const gchar * control_val = DBUSMENU_MENUITEM_SHORTCUT_CONTROL;
- const gchar * alt_val = DBUSMENU_MENUITEM_SHORTCUT_ALT;
- const gchar * shift_val = DBUSMENU_MENUITEM_SHORTCUT_SHIFT;
- const gchar * super_val = DBUSMENU_MENUITEM_SHORTCUT_SUPER;
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
if (modifier & GDK_CONTROL_MASK) {
- g_array_append_val(array, control_val);
+ g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_CONTROL);
}
if (modifier & GDK_MOD1_MASK) {
- g_array_append_val(array, alt_val);
+ g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_ALT);
}
if (modifier & GDK_SHIFT_MASK) {
- g_array_append_val(array, shift_val);
+ g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_SHIFT);
}
if (modifier & GDK_SUPER_MASK) {
- g_array_append_val(array, super_val);
+ g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_SUPER);
}
const gchar * keyname = gdk_keyval_name(key);
- g_array_append_val(array, keyname);
-
- GType type = dbus_g_type_get_collection("GPtrArray", G_TYPE_STRV);
- GPtrArray * wrapper = (GPtrArray *)dbus_g_type_specialized_construct(type);
-
- GValue value = {0,};
- g_value_init(&value, type);
- g_value_take_boxed(&value, wrapper);
-
- DBusGTypeSpecializedAppendContext ctx;
- dbus_g_type_specialized_init_append(&value, &ctx);
-
- GValue strval = {0,};
- g_value_init(&strval, G_TYPE_STRV);
- g_value_take_boxed(&strval, array->data);
- g_array_free(array, FALSE);
+ g_variant_builder_add(&builder, "s", keyname);
- dbus_g_type_specialized_collection_append(&ctx, &strval);
- dbus_g_type_specialized_collection_end_append(&ctx);
+ GVariant * inside = g_variant_builder_end(&builder);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add_value(&builder, inside);
+ GVariant * outsidevariant = g_variant_builder_end(&builder);
- dbusmenu_menuitem_property_set_value(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT, &value);
-
- return TRUE;
+ return dbusmenu_menuitem_property_set_variant(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT, outsidevariant);
}
/* Look at the closures in an accel group and find
@@ -250,7 +230,7 @@ dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, c
g_return_val_if_fail(GTK_IS_MENU_ITEM(gmi), FALSE);
GClosure * closure = NULL;
- GtkWidget *label = GTK_BIN (gmi)->child;
+ GtkWidget *label = gtk_bin_get_child(GTK_BIN (gmi));
if (GTK_IS_ACCEL_LABEL (label))
{
@@ -279,68 +259,6 @@ dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, c
return dbusmenu_menuitem_property_set_shortcut(menuitem, key->accel_key, key->accel_mods);
}
-/* A set of typed data for the interator */
-typedef struct _iter_data_t iter_data_t;
-struct _iter_data_t {
- guint * key;
- GdkModifierType * modifier;
-};
-
-/* Goes through the wrapper items. In reality we only support one
- so it checks to see if a key is set first. But, we could possibly,
- support more in the future. */
-static void
-_wrapper_iterator (const GValue * value, gpointer user_data)
-{
- iter_data_t * iter_data = (iter_data_t *)user_data;
-
- if (*iter_data->key != 0) {
- g_warning("Shortcut is more than one entry. Which we don't currently support. Taking the first.");
- return;
- }
-
- if (!G_VALUE_HOLDS(value, G_TYPE_STRV)) {
- g_warning("Unexpected shortcut structure. Value array is: %s", G_VALUE_TYPE_NAME(value));
- return;
- }
-
- gchar ** stringarray = (gchar **)g_value_get_boxed(value);
- if (stringarray == NULL) {
- return;
- }
-
- const gchar * last_string = NULL;
- int i;
-
- for (i = 0; stringarray[i] != NULL; i++) {
- last_string = stringarray[i];
-
- if (g_strcmp0(last_string, DBUSMENU_MENUITEM_SHORTCUT_CONTROL) == 0) {
- *iter_data->modifier |= GDK_CONTROL_MASK;
- continue;
- }
- if (g_strcmp0(last_string, DBUSMENU_MENUITEM_SHORTCUT_ALT) == 0) {
- *iter_data->modifier |= GDK_MOD1_MASK;
- continue;
- }
- if (g_strcmp0(last_string, DBUSMENU_MENUITEM_SHORTCUT_SHIFT) == 0) {
- *iter_data->modifier |= GDK_SHIFT_MASK;
- continue;
- }
- if (g_strcmp0(last_string, DBUSMENU_MENUITEM_SHORTCUT_SUPER) == 0) {
- *iter_data->modifier |= GDK_SUPER_MASK;
- continue;
- }
- }
-
- if (last_string != NULL) {
- GdkModifierType tempmod;
- gtk_accelerator_parse(last_string, iter_data->key, &tempmod);
- }
-
- return;
-}
-
/**
dbusmenu_menuitem_property_get_shortcut:
@menuitem: The #DbusmenuMenuitem to get the shortcut off
@@ -358,20 +276,37 @@ dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * ke
g_return_if_fail(DBUSMENU_IS_MENUITEM(menuitem));
- const GValue * wrapper = dbusmenu_menuitem_property_get_value(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT);
+ GVariant * wrapper = dbusmenu_menuitem_property_get_variant(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT);
if (wrapper == NULL) {
return;
}
- if (!dbus_g_type_is_collection(G_VALUE_TYPE(wrapper))) {
- g_warning("Unexpected shortcut structure. Wrapper is: %s", G_VALUE_TYPE_NAME(wrapper));
+
+ if (g_variant_n_children(wrapper) != 1) {
+ g_warning("Unable to parse shortcut, too many keys");
+ g_variant_unref(wrapper);
return;
}
- iter_data_t iter_data;
- iter_data.key = key;
- iter_data.modifier = modifier;
+ GVariantIter iter;
+ g_variant_iter_init(&iter, g_variant_get_child_value(wrapper, 0));
+ gchar * string;
+
+ while(g_variant_iter_next(&iter, "s", &string)) {
+ if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_CONTROL) == 0) {
+ *modifier |= GDK_CONTROL_MASK;
+ } else if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_ALT) == 0) {
+ *modifier |= GDK_MOD1_MASK;
+ } else if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_SHIFT) == 0) {
+ *modifier |= GDK_SHIFT_MASK;
+ } else if (g_strcmp0(string, DBUSMENU_MENUITEM_SHORTCUT_SUPER) == 0) {
+ *modifier |= GDK_SUPER_MASK;
+ } else {
+ GdkModifierType tempmod;
+ gtk_accelerator_parse(string, key, &tempmod);
+ }
- dbus_g_type_collection_value_iterate(wrapper, _wrapper_iterator, &iter_data);
+ g_free(string);
+ }
return;
}
diff --git a/libdbusmenu-gtk/menuitem.h b/libdbusmenu-gtk/menuitem.h
index 6960f76..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>
@@ -35,6 +35,8 @@ License version 3 and version 2.1 along with this program. If not, see
#include <gdk/gdk.h>
#include <gtk/gtk.h>
+G_BEGIN_DECLS
+
gboolean dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data);
GdkPixbuf * dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property);
@@ -43,4 +45,6 @@ gboolean dbusmenu_menuitem_property_set_shortcut_string (DbusmenuMenuitem * menu
gboolean dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, const GtkMenuItem * gmi);
void dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * key, GdkModifierType * modifiers);
+G_END_DECLS
+
#endif
diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c
new file mode 100644
index 0000000..70cde53
--- /dev/null
+++ b/libdbusmenu-gtk/parser.c
@@ -0,0 +1,825 @@
+/*
+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"
+#define PARSER_DATA "dbusmenu-gtk-parser-data"
+
+typedef struct _ParserData
+{
+ GtkWidget *label;
+ GtkAction *action;
+ GtkWidget *widget;
+ GtkWidget *shell;
+} ParserData;
+
+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 child_added_cb (GtkContainer * menu,
+ GtkWidget * widget,
+ 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);
+
+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA);
+
+ if (pdata != NULL && pdata->label != NULL) {
+ g_signal_handlers_disconnect_by_func(pdata->label, G_CALLBACK(label_notify_cb), obj);
+ g_object_remove_weak_pointer(G_OBJECT(pdata->label), (gpointer*)&pdata->label);
+ }
+
+ if (pdata != NULL && pdata->action != NULL) {
+ g_signal_handlers_disconnect_by_func(pdata->action, G_CALLBACK(action_notify_cb), obj);
+ g_object_remove_weak_pointer(G_OBJECT(pdata->action), (gpointer*)&pdata->action);
+ }
+
+ if (pdata != NULL && pdata->widget != NULL) {
+ g_signal_handlers_disconnect_by_func(pdata->widget, G_CALLBACK(widget_notify_cb), obj);
+ g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget);
+ }
+
+ if (pdata != NULL && pdata->shell != NULL) {
+ g_signal_handlers_disconnect_by_func(pdata->shell, G_CALLBACK(child_added_cb), obj);
+ g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell);
+ }
+
+ return;
+}
+
+/* Called if we replace the cache on the object with a new
+ dbusmenu menuitem */
+static void
+object_cache_freed (gpointer data)
+{
+ // TODO: make this have access to both data and obj so we can call these
+ //if (!G_IS_OBJECT(obj)) return;
+ //g_object_weak_unref(G_OBJECT(obj), dbusmenu_cache_freed, data);
+ //dbusmenu_cache_freed(data, obj);
+ return;
+}
+
+/* Gets the positon of the child with its' parent if it has one.
+ Returns -1 if the position is unable to be calculated. */
+static gint
+get_child_position (GtkWidget * child)
+{
+ GtkWidget * parent = gtk_widget_get_parent (child);
+ if (parent == NULL || !GTK_IS_CONTAINER (parent))
+ return -1;
+
+ GList * children = gtk_container_get_children (GTK_CONTAINER (parent));
+ GList * iter;
+ gint position = 0;
+
+ for (iter = children; iter != NULL; iter = iter->next) {
+ if (iter->data == child)
+ break;
+ ++position;
+ }
+
+ g_list_free (children);
+
+ if (iter == NULL)
+ return -1;
+ else
+ return position;
+}
+
+/* Creates a new menu item that is attached to the widget and has
+ the data linkages hooked up. Also allocates the ParserData */
+static DbusmenuMenuitem *
+new_menuitem (GtkWidget * widget)
+{
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ ParserData *pdata = g_new0 (ParserData, 1);
+ g_object_set_data_full(G_OBJECT(item), PARSER_DATA, pdata, g_free);
+
+ g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, item, object_cache_freed);
+ g_object_weak_ref(G_OBJECT(item), dbusmenu_cache_freed, widget);
+
+ return item;
+}
+
+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));
+ GList *iter;
+
+ for (iter = children; iter != NULL; iter = iter->next) {
+ gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
+ iter->data,
+ TRUE);
+ }
+
+ g_list_free (children);
+ }
+
+ if (recurse->parent == NULL) {
+ recurse->parent = new_menuitem(widget);
+ }
+
+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(recurse->parent), PARSER_DATA);
+
+ pdata->shell = widget;
+ g_signal_connect (G_OBJECT (widget),
+ "child-added",
+ G_CALLBACK (child_added_cb),
+ recurse->parent);
+ g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->shell);
+
+ 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);
+
+ 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);
+ gint pos = get_child_position (widget);
+ if (pos >= 0)
+ dbusmenu_menuitem_child_add_position (recurse->parent,
+ thisitem,
+ pos);
+ else
+ 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 = new_menuitem(widget);
+
+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(mi), PARSER_DATA);
+
+ 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.
+ pdata->label = label;
+ g_signal_connect (G_OBJECT (label),
+ "notify",
+ G_CALLBACK (label_notify_cb),
+ mi);
+ g_object_add_weak_pointer(G_OBJECT (label), (gpointer*)&pdata->label);
+ }
+
+ if (GTK_IS_ACTIVATABLE (widget))
+ {
+ 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);
+
+ pdata->action = action;
+ g_signal_connect_object (action, "notify",
+ G_CALLBACK (action_notify_cb),
+ mi,
+ G_CONNECT_AFTER);
+ g_object_add_weak_pointer(G_OBJECT (action), (gpointer*)&pdata->action);
+ }
+ }
+ }
+
+ 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);
+
+ pdata->widget = widget;
+ g_signal_connect (widget,
+ "notify",
+ G_CALLBACK (widget_notify_cb),
+ mi);
+ g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->widget);
+
+ return mi;
+ }
+
+ /* If it's none of those we're going to just create a
+ generic menuitem as a place holder for it. */
+ return new_menuitem(widget);
+}
+
+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);
+ }
+ }
+ }
+ else if (pspec->name == g_intern_static_string ("submenu"))
+ {
+ /* The underlying submenu got swapped out. Let's see what it is now. */
+ /* First, delete any children that may exist currently. */
+ DbusmenuMenuitem * item = DBUSMENU_MENUITEM(g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM));
+ if (item != NULL)
+ {
+ GList * children = dbusmenu_menuitem_take_children (item);
+ GList * child = children;
+ while (child != NULL) {
+ g_object_unref (G_OBJECT(child->data));
+ child = child->next;
+ }
+ g_list_free(children);
+ }
+
+ /* Now parse new submenu. */
+ RecurseContext recurse = {0};
+ recurse.toplevel = gtk_widget_get_toplevel(widget);
+ recurse.parent = item;
+
+ if (item != NULL) {
+ GtkWidget * menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+ parse_menu_structure_helper(menu, &recurse);
+ } else {
+ /* Note: it would be really odd that we wouldn't have a cached
+ item, but we should handle that appropriately. */
+ parse_menu_structure_helper(widget, &recurse);
+ g_object_unref(G_OBJECT(recurse.parent));
+ }
+ }
+}
+
+/* A child item was added to a menu we're watching. Let's try to integrate it. */
+static void
+child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
+{
+ DbusmenuMenuitem *menuitem = (DbusmenuMenuitem *)data;
+
+ RecurseContext recurse = {0};
+ recurse.toplevel = gtk_widget_get_toplevel(GTK_WIDGET(menu));
+ recurse.parent = menuitem;
+
+ parse_menu_structure_helper(widget, &recurse);
+}
+
+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
diff --git a/tests/Makefile.am b/tests/Makefile.am
index aa79c8f..62142dc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -16,7 +16,8 @@ TESTS = \
test-gtk-label \
test-gtk-shortcut \
test-gtk-reorder \
- test-gtk-submenu
+ test-gtk-submenu \
+ test-gtk-parser-test
check_PROGRAMS = \
glib-server-nomenu \
@@ -42,7 +43,8 @@ check_PROGRAMS = \
test-json-client \
test-json-server \
test-gtk-submenu-server \
- test-gtk-submenu-client
+ test-gtk-submenu-client \
+ test-gtk-parser
XVFB_RUN=". $(srcdir)/run-xvfb.sh"
@@ -52,7 +54,7 @@ XVFB_RUN=". $(srcdir)/run-xvfb.sh"
lib_LTLIBRARIES = libdbusmenu-jsonloader.la
-libdbusmenu_jsonloaderincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-jsonloader/
+libdbusmenu_jsonloaderincludedir=$(includedir)/libdbusmenu-0.4/libdbusmenu-jsonloader/
libdbusmenu_jsonloaderinclude_HEADERS = \
json-loader.h
@@ -80,7 +82,7 @@ libdbusmenu_jsonloader_la_LIBADD = \
$(DBUSMENUGLIB_LIBS) \
$(DBUSMENUTESTS_LIBS)
-pkgconfig_DATA = dbusmenu-jsonloader.pc
+pkgconfig_DATA = dbusmenu-jsonloader-0.4.pc
pkgconfigdir = $(libdir)/pkgconfig
######################
@@ -384,6 +386,35 @@ test_gtk_objects_LDADD = \
$(DBUSMENUGLIB_LIBS) \
$(DBUSMENUGTK_LIBS)
+######################
+# Test GTK Parser
+######################
+
+GTK_PARSER_XML_REPORT = test-gtk-parser.xml
+
+test-gtk-parser-test: test-gtk-parser Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(XVFB_RUN) >> $@
+ @echo gtester --verbose -k -o $(GTK_PARSER_XML_REPORT) ./test-gtk-parser >> $@
+ @chmod +x $@
+
+test_gtk_parser_SOURCES = \
+ test-gtk-parser.c
+
+test_gtk_parser_CFLAGS = \
+ -I $(srcdir)/.. \
+ $(DBUSMENUGLIB_CFLAGS) \
+ $(DBUSMENUGTK_CFLAGS) \
+ -DSRCDIR="\"$(srcdir)\"" \
+ -Wall -Werror
+
+test_gtk_parser_LDADD = \
+ ../libdbusmenu-glib/libdbusmenu-glib.la \
+ ../libdbusmenu-gtk/libdbusmenu-gtk.la \
+ $(DBUSMENUGLIB_LIBS) \
+ $(DBUSMENUGTK_LIBS)
+
+
#########################
# Test GTK Label
#########################
diff --git a/tests/dbusmenu-jsonloader.pc.in b/tests/dbusmenu-jsonloader-0.4.pc.in
index d042132..62bfeb2 100644
--- a/tests/dbusmenu-jsonloader.pc.in
+++ b/tests/dbusmenu-jsonloader-0.4.pc.in
@@ -5,7 +5,7 @@ bindir=@bindir@
includedir=@includedir@
Cflags: -I${includedir}/libdbusmenu-0.1
-Requires: dbus-glib-1,dbusmenu-glib,json-glib-1.0
+Requires: dbusmenu-glib-0.4 json-glib-1.0
Libs: -L${libdir} -ldbusmenu-jsonloader
Name: libdbusmenu-jsonloader
diff --git a/tests/json-loader.c b/tests/json-loader.c
index aad4295..14e90e0 100644
--- a/tests/json-loader.c
+++ b/tests/json-loader.c
@@ -20,115 +20,76 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "json-loader.h"
-#include <dbus/dbus-gtype-specialized.h>
-static GValue *
-node2value (JsonNode * node)
+static GVariant * node2variant (JsonNode * node);
+
+static void
+array_foreach (JsonArray * array, guint index, JsonNode * node, gpointer user_data)
+{
+ GVariantBuilder * builder = (GVariantBuilder *)user_data;
+ GVariant * variant = node2variant(node);
+ if (variant != NULL) {
+ g_variant_builder_add_value(builder, variant);
+ }
+ return;
+}
+
+static void
+object_foreach (JsonObject * array, const gchar * member, JsonNode * node, gpointer user_data)
+{
+ GVariantBuilder * builder = (GVariantBuilder *)user_data;
+ GVariant * variant = node2variant(node);
+ if (variant != NULL) {
+ g_variant_builder_add(builder, "{sv}", member, variant);
+ }
+ return;
+}
+
+static GVariant *
+node2variant (JsonNode * node)
{
if (node == NULL) {
return NULL;
}
- GValue * value = g_new0(GValue, 1);
-
if (JSON_NODE_TYPE(node) == JSON_NODE_VALUE) {
- json_node_get_value(node, value);
- return value;
+ switch (json_node_get_value_type(node)) {
+ case G_TYPE_INT:
+ case G_TYPE_INT64:
+ return g_variant_new_int32(json_node_get_int(node));
+ case G_TYPE_DOUBLE:
+ case G_TYPE_FLOAT:
+ return g_variant_new_double(json_node_get_double(node));
+ case G_TYPE_BOOLEAN:
+ return g_variant_new_boolean(json_node_get_boolean(node));
+ case G_TYPE_STRING:
+ return g_variant_new_string(json_node_get_string(node));
+ default:
+ g_assert_not_reached();
+ }
}
if (JSON_NODE_TYPE(node) == JSON_NODE_ARRAY) {
- JsonArray * array = json_node_get_array(node);
- JsonNode * first = json_array_get_element(array, 0);
-
- if (JSON_NODE_TYPE(first) == JSON_NODE_VALUE) {
- GValue subvalue = {0};
- json_node_get_value(first, &subvalue);
-
- if (G_VALUE_TYPE(&subvalue) == G_TYPE_STRING) {
- GArray * garray = g_array_sized_new(TRUE, TRUE, sizeof(gchar *), json_array_get_length(array));
- g_value_init(value, G_TYPE_STRV);
- g_value_take_boxed(value, garray->data);
-
- int i;
- for (i = 0; i < json_array_get_length(array); i++) {
- const gchar * str = json_node_get_string(json_array_get_element(array, i));
- gchar * dupstr = g_strdup(str);
- g_array_append_val(garray, dupstr);
- }
-
- g_array_free(garray, FALSE);
- } else {
- GValueArray * varray = g_value_array_new(json_array_get_length(array));
- g_value_init(value, G_TYPE_VALUE_ARRAY);
- g_value_take_boxed(value, varray);
-
- g_value_array_append(varray, &subvalue);
- g_value_unset(&subvalue);
-
- int i;
- for (i = 1; i < json_array_get_length(array); i++) {
- json_node_get_value(first, &subvalue);
- g_value_array_append(varray, &subvalue);
- g_value_unset(&subvalue);
- }
- }
-
- } else {
- GValue * subvalue = node2value(first);
- GType type = dbus_g_type_get_collection("GPtrArray", G_VALUE_TYPE(subvalue));
- gpointer * wrapper = dbus_g_type_specialized_construct(type);
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
- g_value_init(value, type);
- g_value_take_boxed(value, wrapper);
-
- DBusGTypeSpecializedAppendContext ctx;
- dbus_g_type_specialized_init_append(value, &ctx);
-
- dbus_g_type_specialized_collection_append(&ctx, subvalue);
- int i;
- for (i = 1; i < json_array_get_length(array); i++) {
- GValue * subvalue = node2value(node);
- dbus_g_type_specialized_collection_append(&ctx, subvalue);
- }
+ JsonArray * array = json_node_get_array(node);
+ json_array_foreach_element(array, array_foreach, &builder);
- dbus_g_type_specialized_collection_end_append(&ctx);
- }
+ return g_variant_builder_end(&builder);
}
if (JSON_NODE_TYPE(node) == JSON_NODE_OBJECT) {
- JsonObject * obj = json_node_get_object(node);
-
- GType type = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
- GHashTable * hash = (GHashTable *)dbus_g_type_specialized_construct(type);
-
- g_value_init(value, type);
- g_value_take_boxed(value, hash);
-
- DBusGTypeSpecializedAppendContext ctx;
- dbus_g_type_specialized_init_append(value, &ctx);
-
- GList * members = NULL;
- for (members = json_object_get_members(obj); members != NULL; members = g_list_next(members)) {
- const gchar * member = members->data;
-
- JsonNode * lnode = json_object_get_member(obj, member);
- GValue * value = node2value(lnode);
-
- if (value != NULL) {
- GValue name = {0};
- g_value_init(&name, G_TYPE_STRING);
- g_value_set_static_string(&name, member);
-
- dbus_g_type_specialized_map_append(&ctx, &name, value);
-
- g_value_unset(&name);
- g_value_unset(value);
- g_free(value);
- }
- }
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_DICTIONARY);
+
+ JsonObject * array = json_node_get_object(node);
+ json_object_foreach_member(array, object_foreach, &builder);
+
+ return g_variant_builder_end(&builder);
}
- return value;
+ return NULL;
}
static void
@@ -144,12 +105,11 @@ set_props (DbusmenuMenuitem * mi, JsonObject * node)
if (!g_strcmp0(member, "submenu")) { continue; }
JsonNode * lnode = json_object_get_member(node, member);
- GValue * value = node2value(lnode);
+ GVariant * variant = node2variant(lnode);
- if (value != NULL) {
- dbusmenu_menuitem_property_set_value(mi, member, value);
- g_value_unset(value);
- g_free(value);
+ if (variant != NULL) {
+ dbusmenu_menuitem_property_set_variant(mi, member, variant);
+ g_variant_unref(variant);
}
}
diff --git a/tests/test-glib-events-client.c b/tests/test-glib-events-client.c
index 97d5caf..2cc5439 100644
--- a/tests/test-glib-events-client.c
+++ b/tests/test-glib-events-client.c
@@ -35,7 +35,7 @@ static gboolean passed = TRUE;
static gboolean first = TRUE;
static void
-event_status (DbusmenuClient * client, DbusmenuMenuitem * item, gchar * name, GValue * data, guint timestamp, GError * error, gpointer user_data)
+event_status (DbusmenuClient * client, DbusmenuMenuitem * item, gchar * name, GVariant * data, guint timestamp, GError * error, gpointer user_data)
{
g_debug("Event status: %s", error == NULL ? "Sent" : "Error");
@@ -46,8 +46,8 @@ event_status (DbusmenuClient * client, DbusmenuMenuitem * item, gchar * name, GV
return;
}
- if (g_value_get_int(data) != DATA_VALUE) {
- g_debug("Data value pass fail got: %d", g_value_get_int(data));
+ if (g_variant_get_int32(data) != DATA_VALUE) {
+ g_debug("Data value pass fail got: %d", g_variant_get_int32(g_variant_get_child_value(data, 0)));
passed = FALSE;
g_main_loop_quit(mainloop);
return;
@@ -96,11 +96,8 @@ layout_updated (DbusmenuClient * client, gpointer user_data)
return;
}
- GValue data = {0};
- g_value_init(&data, G_TYPE_INT);
- g_value_set_int(&data, DATA_VALUE);
-
- dbusmenu_menuitem_handle_event(menuroot, "clicked", &data, TIMESTAMP_VALUE);
+ GVariant * data = g_variant_new_int32(DATA_VALUE);
+ dbusmenu_menuitem_handle_event(menuroot, "clicked", data, TIMESTAMP_VALUE);
return;
}
@@ -128,6 +125,7 @@ main (int argc, char ** argv)
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
+ g_debug("Main loop complete");
g_object_unref(G_OBJECT(client));
if (passed) {
diff --git a/tests/test-glib-events-server.c b/tests/test-glib-events-server.c
index 0d1e0b1..ab72c6b 100644
--- a/tests/test-glib-events-server.c
+++ b/tests/test-glib-events-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
@@ -49,35 +45,40 @@ timer_func (gpointer data)
return FALSE;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
server = dbusmenu_server_new("/org/test");
DbusmenuMenuitem * menuitem = dbusmenu_menuitem_new();
dbusmenu_server_set_root(server, menuitem);
g_signal_connect(G_OBJECT(menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(handle_event), NULL);
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
+
g_timeout_add_seconds(3, timer_func, NULL);
mainloop = g_main_loop_new(NULL, FALSE);
diff --git a/tests/test-glib-layout-server.c b/tests/test-glib-layout-server.c
index 111e164..e289349 100644
--- a/tests/test-glib-layout-server.c
+++ b/tests/test-glib-layout-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
@@ -72,33 +68,38 @@ timer_func (gpointer data)
return TRUE;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
+ server = dbusmenu_server_new("/org/test");
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
+ timer_func(NULL);
+ g_timeout_add(2500, timer_func, NULL);
- if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
+ return;
+}
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
- server = dbusmenu_server_new("/org/test");
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
- timer_func(NULL);
- g_timeout_add(2500, timer_func, NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-glib-objects.c b/tests/test-glib-objects.c
index 1d4f673..9c99280 100644
--- a/tests/test-glib-objects.c
+++ b/tests/test-glib-objects.c
@@ -77,17 +77,17 @@ test_object_menuitem_props_string (void)
{
/* Build a menu item */
DbusmenuMenuitem * item = dbusmenu_menuitem_new();
- const GValue * out = NULL;
+ GVariant * out = NULL;
/* Test to make sure it's a happy object */
g_assert(item != NULL);
/* Setting a string */
dbusmenu_menuitem_property_set(item, "string", "value");
- out = dbusmenu_menuitem_property_get_value(item, "string");
+ out = dbusmenu_menuitem_property_get_variant(item, "string");
g_assert(out != NULL);
- g_assert(G_VALUE_TYPE(out) == G_TYPE_STRING);
- g_assert(!g_strcmp0(g_value_get_string(out), "value"));
+ g_assert(g_variant_type_equal(g_variant_get_type(out), G_VARIANT_TYPE_STRING));
+ g_assert(!g_strcmp0(g_variant_get_string(out, NULL), "value"));
g_assert(!g_strcmp0(dbusmenu_menuitem_property_get(item, "string"), "value"));
g_object_unref(item);
@@ -101,17 +101,17 @@ test_object_menuitem_props_int (void)
{
/* Build a menu item */
DbusmenuMenuitem * item = dbusmenu_menuitem_new();
- const GValue * out = NULL;
+ GVariant * out = NULL;
/* Test to make sure it's a happy object */
g_assert(item != NULL);
/* Setting a string */
dbusmenu_menuitem_property_set_int(item, "int", 12345);
- out = dbusmenu_menuitem_property_get_value(item, "int");
+ out = dbusmenu_menuitem_property_get_variant(item, "int");
g_assert(out != NULL);
- g_assert(G_VALUE_TYPE(out) == G_TYPE_INT);
- g_assert(g_value_get_int(out) == 12345);
+ g_assert(g_variant_type_equal(g_variant_get_type(out), G_VARIANT_TYPE_INT32));
+ g_assert(g_variant_get_int32(out) == 12345);
g_assert(dbusmenu_menuitem_property_get_int(item, "int") == 12345);
g_object_unref(item);
@@ -125,18 +125,18 @@ test_object_menuitem_props_bool (void)
{
/* Build a menu item */
DbusmenuMenuitem * item = dbusmenu_menuitem_new();
- const GValue * out = NULL;
+ GVariant * out = NULL;
/* Test to make sure it's a happy object */
g_assert(item != NULL);
/* Setting a string */
dbusmenu_menuitem_property_set_bool(item, "boolean", TRUE);
- out = dbusmenu_menuitem_property_get_value(item, "boolean");
+ out = dbusmenu_menuitem_property_get_variant(item, "boolean");
g_assert(out != NULL);
- g_assert(G_VALUE_TYPE(out) == G_TYPE_BOOLEAN);
- g_assert(g_value_get_boolean(out));
- g_assert(dbusmenu_menuitem_property_get_int(item, "boolean"));
+ g_assert(g_variant_type_equal(g_variant_get_type(out), G_VARIANT_TYPE_BOOLEAN));
+ g_assert(g_variant_get_boolean(out));
+ /* g_assert(dbusmenu_menuitem_property_get_int(item, "boolean") == 0); */
g_object_unref(item);
@@ -177,7 +177,7 @@ test_object_menuitem_props_swap (void)
/* A helper to put a value into a pointer for eval. */
static void
-test_object_menuitem_props_signals_helper (DbusmenuMenuitem * mi, gchar * property, GValue * value, GValue ** out)
+test_object_menuitem_props_signals_helper (DbusmenuMenuitem * mi, gchar * property, GVariant * value, GVariant ** out)
{
if (!g_strcmp0(property, "swapper")) {
*out = value;
@@ -194,7 +194,7 @@ test_object_menuitem_props_signals (void)
{
/* Build a menu item */
DbusmenuMenuitem * item = dbusmenu_menuitem_new();
- GValue * out = NULL;
+ GVariant * out = NULL;
/* Test to make sure it's a happy object */
g_assert(item != NULL);
@@ -205,25 +205,25 @@ test_object_menuitem_props_signals (void)
/* Setting a boolean */
dbusmenu_menuitem_property_set_bool(item, "swapper", TRUE);
g_assert(out != NULL);
- g_assert(g_value_get_boolean(out));
+ g_assert(g_variant_get_boolean(out));
out = NULL;
/* Setting a int */
dbusmenu_menuitem_property_set_int(item, "swapper", 5432);
g_assert(out != NULL);
- g_assert(g_value_get_int(out) == 5432);
+ g_assert(g_variant_get_int32(out) == 5432);
out = NULL;
/* Setting a string */
dbusmenu_menuitem_property_set(item, "swapper", "mystring");
g_assert(out != NULL);
- g_assert(!g_strcmp0(g_value_get_string(out), "mystring"));
+ g_assert(!g_strcmp0(g_variant_get_string(out, NULL), "mystring"));
out = NULL;
/* Setting a boolean */
dbusmenu_menuitem_property_set_bool(item, "swapper", FALSE);
g_assert(out != NULL);
- g_assert(!g_value_get_boolean(out));
+ g_assert(!g_variant_get_boolean(out));
out = NULL;
g_object_unref(item);
@@ -274,6 +274,37 @@ test_object_menuitem_props_boolstr (void)
return;
}
+/* Set and then remove a prop */
+static void
+test_object_menuitem_props_removal (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ /* Test to make sure it's a happy object */
+ g_assert(item != NULL);
+
+ /* Set the property and ensure that it's set */
+ dbusmenu_menuitem_property_set_variant(item, "myprop", g_variant_new_int32(34));
+ g_assert(dbusmenu_menuitem_property_get_variant(item, "myprop") != NULL);
+
+ /* Remove the property and ensure it goes away */
+ dbusmenu_menuitem_property_set_variant(item, "myprop", NULL);
+ g_assert(dbusmenu_menuitem_property_get_variant(item, "myprop") == NULL);
+
+ /* Set the property again */
+ dbusmenu_menuitem_property_set_variant(item, "myprop", g_variant_new_int32(34));
+ g_assert(dbusmenu_menuitem_property_get_variant(item, "myprop") != NULL);
+
+ /* Remove the property with a NULL string */
+ dbusmenu_menuitem_property_set(item, "myprop", NULL);
+ g_assert(dbusmenu_menuitem_property_get_variant(item, "myprop") == NULL);
+
+ g_object_unref(item);
+
+ return;
+}
+
/* Build the test suite */
static void
test_glib_objects_suite (void)
@@ -286,6 +317,7 @@ test_glib_objects_suite (void)
g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_swap", test_object_menuitem_props_swap);
g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_signals", test_object_menuitem_props_signals);
g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_boolstr", test_object_menuitem_props_boolstr);
+ g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_removal", test_object_menuitem_props_removal);
return;
}
diff --git a/tests/test-glib-properties-server.c b/tests/test-glib-properties-server.c
index 091e550..4248ea2 100644
--- a/tests/test-glib-properties-server.c
+++ b/tests/test-glib-properties-server.c
@@ -20,10 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -91,8 +88,6 @@ main (int argc, char ** argv)
{
g_type_init();
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
-
server = dbusmenu_server_new("/org/test");
timer_func(NULL);
diff --git a/tests/test-glib-proxy-client.c b/tests/test-glib-proxy-client.c
index 0ae2e20..2e1e2d2 100644
--- a/tests/test-glib-proxy-client.c
+++ b/tests/test-glib-proxy-client.c
@@ -150,10 +150,9 @@ layout_verify_timer (gpointer data)
g_main_loop_quit(mainloop);
}
- GValue value = {0};
- g_value_init(&value, G_TYPE_INT);
- g_value_set_int(&value, 0);
- dbusmenu_menuitem_handle_event(menuroot, "clicked", &value, layouton);
+ GVariant * value = g_variant_new("i", 0);
+ dbusmenu_menuitem_handle_event(menuroot, "clicked", value, layouton);
+ g_variant_unref(value);
return FALSE;
}
diff --git a/tests/test-glib-proxy-proxy.c b/tests/test-glib-proxy-proxy.c
index 722cf1f..8a17ead 100644
--- a/tests/test-glib-proxy-proxy.c
+++ b/tests/test-glib-proxy-proxy.c
@@ -1,9 +1,5 @@
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/menuitem-proxy.h>
@@ -32,6 +28,24 @@ root_changed (DbusmenuClient * client, DbusmenuMenuitem * newroot, gpointer user
return;
}
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ client = dbusmenu_client_new((gchar *)user_data, "/org/test");
+
+ g_signal_connect(client, DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), server);
+
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
int
main (int argc, char ** argv)
{
@@ -47,28 +61,16 @@ main (int argc, char ** argv)
g_debug("I am '%s' and I'm proxying '%s'", whoami, myproxy);
- GError * error = NULL;
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
-
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(connection)));
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, whoami, 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
server = dbusmenu_server_new("/org/test");
- client = dbusmenu_client_new(myproxy, "/org/test");
- g_signal_connect(client, DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), server);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ whoami,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ myproxy,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-glib-proxy-server.c b/tests/test-glib-proxy-server.c
index f32b426..a5dfd4e 100644
--- a/tests/test-glib-proxy-server.c
+++ b/tests/test-glib-proxy-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -104,31 +100,36 @@ layout_change (DbusmenuMenuitem * oldroot, guint timestamp, gpointer data)
return;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- g_type_init();
-
- GError * error = NULL;
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
-
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(connection)));
+ server = dbusmenu_server_new("/org/test");
+ layout_change(NULL, 0, NULL);
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
+ return;
+}
- if (!org_freedesktop_DBus_request_name(bus_proxy, "test.proxy.server", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
- server = dbusmenu_server_new("/org/test");
- layout_change(NULL, 0, NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "test.proxy.server",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-glib-simple-items.c b/tests/test-glib-simple-items.c
index 5b9f538..3ea5480 100644
--- a/tests/test-glib-simple-items.c
+++ b/tests/test-glib-simple-items.c
@@ -1,6 +1,3 @@
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
-
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
diff --git a/tests/test-glib-submenu-server.c b/tests/test-glib-submenu-server.c
index 68f7004..73362c1 100644
--- a/tests/test-glib-submenu-server.c
+++ b/tests/test-glib-submenu-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
@@ -72,33 +68,38 @@ timer_func (gpointer data)
return TRUE;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
+ server = dbusmenu_server_new("/org/test");
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
+ timer_func(NULL);
+ g_timeout_add(2500, timer_func, NULL);
- if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
+ return;
+}
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
- server = dbusmenu_server_new("/org/test");
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
- timer_func(NULL);
- g_timeout_add(2500, timer_func, NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-gtk-label-server.c b/tests/test-gtk-label-server.c
index 32572fc..ddf8fcf 100644
--- a/tests/test-gtk-label-server.c
+++ b/tests/test-gtk-label-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -53,6 +49,25 @@ timer_func (gpointer data)
return TRUE;
}
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ server = dbusmenu_server_new("/org/test");
+
+ timer_func(NULL);
+ g_timeout_add_seconds(5, timer_func, NULL);
+
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
int
main (int argc, char ** argv)
{
@@ -73,26 +88,15 @@ main (int argc, char ** argv)
root_array = json_node_get_array(root_node);
g_debug("%d layouts in test description '%s'", json_array_get_length(root_array), argv[1]);
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "glib.label.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
- server = dbusmenu_server_new("/org/test");
-
- timer_func(NULL);
- g_timeout_add_seconds(5, timer_func, NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "glib.label.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-gtk-objects.c b/tests/test-gtk-objects.c
index 726f404..30fc022 100644
--- a/tests/test-gtk-objects.c
+++ b/tests/test-gtk-objects.c
@@ -72,7 +72,7 @@ test_object_prop_pixbuf (void)
g_object_unref(pixbuf);
/* Check to see if it's set */
- const GValue * val = dbusmenu_menuitem_property_get_value(item, prop_name);
+ GVariant * val = dbusmenu_menuitem_property_get_variant(item, prop_name);
g_assert(val != NULL);
/* Get the pixbuf back! */
@@ -105,7 +105,7 @@ test_object_prop_shortcut (void)
g_assert(success);
/* Check for value */
- const GValue * val = dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_SHORTCUT);
+ GVariant * val = dbusmenu_menuitem_property_get_variant(item, DBUSMENU_MENUITEM_PROP_SHORTCUT);
g_assert(val != NULL);
/* Check to see if we love it */
diff --git a/tests/test-gtk-parser.c b/tests/test-gtk-parser.c
new file mode 100644
index 0000000..b66b46a
--- /dev/null
+++ b/tests/test-gtk-parser.c
@@ -0,0 +1,115 @@
+/*
+Testing for the various objects just by themselves.
+
+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 the GNU General Public License version 3, 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 GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libdbusmenu-glib/menuitem-private.h>
+#include <libdbusmenu-gtk/parser.h>
+
+/* Just makes sure we can connect here people */
+static void
+test_parser_runs (void)
+{
+ GtkWidget * gmi = gtk_menu_item_new_with_label("Test Item");
+ g_assert(gmi != NULL);
+ DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(gmi);
+ g_assert(mi != NULL);
+
+ g_object_unref(gmi);
+ g_object_unref(mi);
+
+ return;
+}
+
+const gchar * test_parser_children_builder =
+"<?xml version=\"1.0\"?>"
+"<interface>"
+"<requires lib=\"gtk+\" version=\"2.16\"/>"
+/* Start menu bar */
+"<object class=\"GtkMenuBar\" id=\"menubar\"><property name=\"visible\">True</property>"
+/* Child 1 */
+"<child><object class=\"GtkMenuItem\" id=\"child_one\"><property name=\"visible\">True</property><property name=\"label\">Child One</property></object></child>"
+/* Child 2 */
+"<child><object class=\"GtkMenuItem\" id=\"child_two\"><property name=\"visible\">True</property><property name=\"label\">Child Two</property></object></child>"
+/* Child 3 */
+"<child><object class=\"GtkMenuItem\" id=\"child_three\"><property name=\"visible\">True</property><property name=\"label\">Child Three</property></object></child>"
+/* Child 4 */
+"<child><object class=\"GtkMenuItem\" id=\"child_four\"><property name=\"visible\">True</property><property name=\"label\">Child Four</property></object></child>"
+/* Stop menubar */
+"</object>"
+"</interface>";
+
+/* Ensure the parser can find children */
+static void
+test_parser_children (void) {
+ GtkBuilder * builder = gtk_builder_new();
+ g_assert(builder != NULL);
+
+ GError * error = NULL;
+ gtk_builder_add_from_string(builder, test_parser_children_builder, -1, &error);
+ if (error != NULL) {
+ g_error("Unable to parse UI definition: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+
+ GtkWidget * menu = GTK_WIDGET(gtk_builder_get_object(builder, "menubar"));
+ g_assert(menu != NULL);
+
+ DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(menu);
+ g_assert(mi != NULL);
+
+/*
+ GPtrArray * xmlarray = g_ptr_array_new();
+ dbusmenu_menuitem_buildxml(mi, xmlarray);
+ g_debug("XML: %s", g_strjoinv("", (gchar **)xmlarray->pdata));
+*/
+
+ GList * children = dbusmenu_menuitem_get_children(mi);
+ g_assert(children != NULL);
+
+ g_assert(g_list_length(children) == 4);
+
+ g_object_unref(mi);
+ g_object_unref(menu);
+
+ return;
+}
+
+/* Build the test suite */
+static void
+test_gtk_parser_suite (void)
+{
+ g_test_add_func ("/dbusmenu/gtk/parser/base", test_parser_runs);
+ g_test_add_func ("/dbusmenu/gtk/parser/children", test_parser_children);
+ return;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+ gtk_init(&argc, &argv);
+ g_test_init(&argc, &argv, NULL);
+
+ /* Test suites */
+ test_gtk_parser_suite();
+
+
+ return g_test_run ();
+}
diff --git a/tests/test-gtk-reorder-server.c b/tests/test-gtk-reorder-server.c
index eee9bb8..44209f1 100644
--- a/tests/test-gtk-reorder-server.c
+++ b/tests/test-gtk-reorder-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -73,29 +69,9 @@ timer_func (gpointer data)
return TRUE;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "glib.label.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
server = dbusmenu_server_new("/org/test");
root = dbusmenu_menuitem_new();
dbusmenu_server_set_root(server, root);
@@ -109,6 +85,31 @@ main (int argc, char ** argv)
timer_func(NULL);
g_timeout_add_seconds(5, timer_func, NULL);
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "glib.label.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
+
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-gtk-shortcut-server.c b/tests/test-gtk-shortcut-server.c
index 3b703a1..b205d03 100644
--- a/tests/test-gtk-shortcut-server.c
+++ b/tests/test-gtk-shortcut-server.c
@@ -20,13 +20,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
+#include <gio/gio.h>
#include <gdk/gdkkeysyms.h>
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
-
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-gtk/menuitem.h>
@@ -61,33 +57,38 @@ build_menu (void)
return;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
+ server = dbusmenu_server_new("/org/test");
+ build_menu();
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
+ g_timeout_add_seconds(10, timer_func, NULL);
- if (!org_freedesktop_DBus_request_name(bus_proxy, "glib.label.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
+ return;
+}
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
- server = dbusmenu_server_new("/org/test");
- build_menu();
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
- g_timeout_add_seconds(10, timer_func, NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "glib.label.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-gtk-submenu-server.c b/tests/test-gtk-submenu-server.c
index 11cede0..9c4d7d4 100644
--- a/tests/test-gtk-submenu-server.c
+++ b/tests/test-gtk-submenu-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -59,29 +55,9 @@ add_item(DbusmenuMenuitem * parent, const char * label)
return item;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "glib.label.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
DbusmenuServer * server = dbusmenu_server_new("/org/test");
DbusmenuMenuitem * root = dbusmenu_menuitem_new();
dbusmenu_server_set_root(server, root);
@@ -101,6 +77,31 @@ main (int argc, char ** argv)
g_timeout_add_seconds(4, show_item, item);
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "glib.label.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ NULL,
+ NULL);
+
g_timeout_add_seconds(6, timer_func, NULL);
mainloop = g_main_loop_new(NULL, FALSE);
diff --git a/tests/test-json-01.json b/tests/test-json-01.json
index 08e9112..b626d20 100644
--- a/tests/test-json-01.json
+++ b/tests/test-json-01.json
@@ -1,127 +1,127 @@
{
"id": 0,
- "children-display": "submenu",
+ "children-display": 'submenu',
"submenu": [
{
"id": 5,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "File",
+ "label": 'File',
"visible": true,
"submenu": [
{
"id": 6,
"enabled": true,
- "label": "Quit",
- "shortcut": [["Control", "q"]],
+ "label": 'Quit',
+ "shortcut": [['Control', 'q']],
"visible": true
},
{
"id": 7,
"enabled": true,
- "label": "Close all",
- "shortcut": [["Control", "Shift", "w"]],
+ "label": 'Close all',
+ "shortcut": [['Control', 'Shift', 'w']],
"visible": true
},
{
"id": 8,
"enabled": true,
- "label": "Close",
- "shortcut": [["Control", "w"]],
+ "label": 'Close',
+ "shortcut": [['Control', 'w']],
"visible": true
},
{
"id": 9,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 10,
"enabled": true,
- "label": "Send by Email...",
+ "label": 'Send by Email...',
"visible": true
},
{
"id": 11,
"enabled": true,
- "label": "Print...",
- "shortcut": [["Control", "p"]],
+ "label": 'Print...',
+ "shortcut": [['Control', 'p']],
"visible": true
},
{
"id": 12,
"enabled": true,
- "label": "Page Setup",
+ "label": 'Page Setup',
"visible": true
},
{
"id": 13,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 14,
"enabled": true,
- "label": "Revert",
+ "label": 'Revert',
"visible": true
},
{
"id": 15,
"enabled": true,
- "label": "Save as Template...",
+ "label": 'Save as Template...',
"visible": true
},
{
"id": 16,
"enabled": true,
- "label": "Save a Copy...",
+ "label": 'Save a Copy...',
"visible": true
},
{
"id": 17,
"enabled": true,
- "label": "Save As...",
- "shortcut": [["Control", "Shift", "s"]],
+ "label": 'Save As...',
+ "shortcut": [['Control', 'Shift', 's']],
"visible": true
},
{
"id": 18,
"enabled": true,
- "label": "Save",
- "shortcut": [["Control", "s"]],
+ "label": 'Save',
+ "shortcut": [['Control', 's']],
"visible": true
},
{
"id": 19,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 20,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Open Recent",
+ "label": 'Open Recent',
"visible": true,
"submenu": [
{
"id": 21,
"enabled": true,
- "label": "Document History",
+ "label": 'Document History',
"visible": true
},
{
"id": 22,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 23,
"enabled": true,
- "label": "giggity.jpg",
- "shortcut": [["Control", "2"]],
+ "label": 'giggity.jpg',
+ "shortcut": [['Control', '2']],
"visible": true
},
{
"id": 24,
"enabled": true,
- "label": "Icon Height.svg",
- "shortcut": [["Control", "1"]],
+ "label": 'Icon Height.svg',
+ "shortcut": [['Control', '1']],
"visible": true
}
]
@@ -129,150 +129,150 @@
{
"id": 25,
"enabled": true,
- "label": "Open Location...",
+ "label": 'Open Location...',
"visible": true
},
{
"id": 26,
"enabled": true,
- "label": "Open as Layers...",
- "shortcut": [["Control", "Alt", "o"]],
+ "label": 'Open as Layers...',
+ "shortcut": [['Control', 'Alt', 'o']],
"visible": true
},
{
"id": 27,
"enabled": true,
- "label": "Open...",
- "shortcut": [["Control", "o"]],
+ "label": 'Open...',
+ "shortcut": [['Control', 'o']],
"visible": true
},
{
"id": 28,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Create",
+ "label": 'Create',
"visible": true,
"submenu": [
{
"id": 29,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Web Page Themes",
+ "label": 'Web Page Themes',
"visible": true,
"submenu": [
{
"id": 30,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Classic.Gimp.Org",
+ "label": 'Classic.Gimp.Org',
"visible": true,
"submenu": [
{
"id": 31,
"enabled": true,
- "label": "Tube Sub-Sub-Button Label...",
+ "label": 'Tube Sub-Sub-Button Label...',
"visible": true
},
{
"id": 32,
"enabled": true,
- "label": "Tube Sub-Button Label...",
+ "label": 'Tube Sub-Button Label...',
"visible": true
},
{
"id": 33,
"enabled": true,
- "label": "Tube Button Label...",
+ "label": 'Tube Button Label...',
"visible": true
},
{
"id": 34,
"enabled": true,
- "label": "Small Header...",
+ "label": 'Small Header...',
"visible": true
},
{
"id": 35,
"enabled": true,
- "label": "General Tube Labels...",
+ "label": 'General Tube Labels...',
"visible": true
},
{
"id": 36,
"enabled": true,
- "label": "Big Header...",
+ "label": 'Big Header...',
"visible": true
}
]
},
{
"id": 37,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Beveled Pattern",
+ "label": 'Beveled Pattern',
"visible": true,
"submenu": [
{
"id": 38,
"enabled": true,
- "label": "Hrule...",
+ "label": 'Hrule...',
"visible": true
},
{
"id": 39,
"enabled": true,
- "label": "Heading...",
+ "label": 'Heading...',
"visible": true
},
{
"id": 40,
"enabled": true,
- "label": "Button...",
+ "label": 'Button...',
"visible": true
},
{
"id": 41,
"enabled": true,
- "label": "Bullet...",
+ "label": 'Bullet...',
"visible": true
},
{
"id": 42,
"enabled": true,
- "label": "Arrow...",
+ "label": 'Arrow...',
"visible": true
}
]
},
{
"id": 43,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Alien Glow",
+ "label": 'Alien Glow',
"visible": true,
"submenu": [
{
"id": 44,
"enabled": true,
- "label": "Hrule...",
+ "label": 'Hrule...',
"visible": true
},
{
"id": 45,
"enabled": true,
- "label": "Button...",
+ "label": 'Button...',
"visible": true
},
{
"id": 46,
"enabled": true,
- "label": "Bullet...",
+ "label": 'Bullet...',
"visible": true
},
{
"id": 47,
"enabled": true,
- "label": "Arrow...",
+ "label": 'Arrow...',
"visible": true
}
]
@@ -281,274 +281,274 @@
},
{
"id": 48,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Patterns",
+ "label": 'Patterns',
"visible": true,
"submenu": [
{
"id": 49,
"enabled": true,
- "label": "Truchet...",
+ "label": 'Truchet...',
"visible": true
},
{
"id": 50,
"enabled": true,
- "label": "Swirly...",
+ "label": 'Swirly...',
"visible": true
},
{
"id": 51,
"enabled": true,
- "label": "Swirl-Tile...",
+ "label": 'Swirl-Tile...',
"visible": true
},
{
"id": 52,
"enabled": true,
- "label": "Render Map...",
+ "label": 'Render Map...',
"visible": true
},
{
"id": 53,
"enabled": true,
- "label": "Land...",
+ "label": 'Land...',
"visible": true
},
{
"id": 54,
"enabled": true,
- "label": "Flatland...",
+ "label": 'Flatland...',
"visible": true
},
{
"id": 55,
"enabled": true,
- "label": "Camouflage...",
+ "label": 'Camouflage...',
"visible": true
},
{
"id": 56,
"enabled": true,
- "label": "3D Truchet...",
+ "label": '3D Truchet...',
"visible": true
}
]
},
{
"id": 57,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Logos",
+ "label": 'Logos',
"visible": true,
"submenu": [
{
"id": 58,
"enabled": true,
- "label": "Web Title Header...",
+ "label": 'Web Title Header...',
"visible": true
},
{
"id": 59,
"enabled": true,
- "label": "Textured...",
+ "label": 'Textured...',
"visible": true
},
{
"id": 60,
"enabled": true,
- "label": "Text Circle...",
+ "label": 'Text Circle...',
"visible": true
},
{
"id": 61,
"enabled": true,
- "label": "Starscape...",
+ "label": 'Starscape...',
"visible": true
},
{
"id": 62,
"enabled": true,
- "label": "Speed Text...",
+ "label": 'Speed Text...',
"visible": true
},
{
"id": 63,
"enabled": true,
- "label": "SOTA Chrome...",
+ "label": 'SOTA Chrome...',
"visible": true
},
{
"id": 64,
"enabled": true,
- "label": "Particle Trace...",
+ "label": 'Particle Trace...',
"visible": true
},
{
"id": 65,
"enabled": true,
- "label": "Newsprint Text...",
+ "label": 'Newsprint Text...',
"visible": true
},
{
"id": 66,
"enabled": true,
- "label": "Neon...",
+ "label": 'Neon...',
"visible": true
},
{
"id": 67,
"enabled": true,
- "label": "Imigre-26...",
+ "label": 'Imigre-26...',
"visible": true
},
{
"id": 68,
"enabled": true,
- "label": "Gradient Bevel...",
+ "label": 'Gradient Bevel...',
"visible": true
},
{
"id": 69,
"enabled": true,
- "label": "Glowing Hot...",
+ "label": 'Glowing Hot...',
"visible": true
},
{
"id": 70,
"enabled": true,
- "label": "Glossy...",
+ "label": 'Glossy...',
"visible": true
},
{
"id": 71,
"enabled": true,
- "label": "Frosty...",
+ "label": 'Frosty...',
"visible": true
},
{
"id": 72,
"enabled": true,
- "label": "Crystal...",
+ "label": 'Crystal...',
"visible": true
},
{
"id": 73,
"enabled": true,
- "label": "Cool Metal...",
+ "label": 'Cool Metal...',
"visible": true
},
{
"id": 74,
"enabled": true,
- "label": "Comic Book...",
+ "label": 'Comic Book...',
"visible": true
},
{
"id": 75,
"enabled": true,
- "label": "Chrome...",
+ "label": 'Chrome...',
"visible": true
},
{
"id": 76,
"enabled": true,
- "label": "Chip Away...",
+ "label": 'Chip Away...',
"visible": true
},
{
"id": 77,
"enabled": true,
- "label": "Chalk...",
+ "label": 'Chalk...',
"visible": true
},
{
"id": 78,
"enabled": true,
- "label": "Carved...",
+ "label": 'Carved...',
"visible": true
},
{
"id": 79,
"enabled": true,
- "label": "Bovination...",
+ "label": 'Bovination...',
"visible": true
},
{
"id": 80,
"enabled": true,
- "label": "Blended...",
+ "label": 'Blended...',
"visible": true
},
{
"id": 81,
"enabled": true,
- "label": "Basic I...",
+ "label": 'Basic I...',
"visible": true
},
{
"id": 82,
"enabled": true,
- "label": "Basic II...",
+ "label": 'Basic II...',
"visible": true
},
{
"id": 83,
"enabled": true,
- "label": "Alien Neon...",
+ "label": 'Alien Neon...',
"visible": true
},
{
"id": 84,
"enabled": true,
- "label": "Alien Glow...",
+ "label": 'Alien Glow...',
"visible": true
},
{
"id": 85,
"enabled": true,
- "label": "3D Outline...",
+ "label": '3D Outline...',
"visible": true
}
]
},
{
"id": 86,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Buttons",
+ "label": 'Buttons',
"visible": true,
"submenu": [
{
"id": 87,
"enabled": true,
- "label": "Simple Beveled Button...",
+ "label": 'Simple Beveled Button...',
"visible": true
},
{
"id": 88,
"enabled": true,
- "label": "Round Button...",
+ "label": 'Round Button...',
"visible": true
}
]
},
{
"id": 89,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 90,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "xscanimage",
+ "label": 'xscanimage',
"visible": true,
"submenu": [
{
"id": 91,
"enabled": false,
- "label": "Device dialog...",
+ "label": 'Device dialog...',
"visible": true
}
]
@@ -556,14 +556,14 @@
{
"id": 92,
"enabled": true,
- "label": "Screenshot...",
+ "label": 'Screenshot...',
"visible": true
},
{
"id": 93,
"enabled": true,
- "label": "From Clipboard",
- "shortcut": [["Control", "Shift", "v"]],
+ "label": 'From Clipboard',
+ "shortcut": [['Control', 'Shift', 'v']],
"visible": true
}
]
@@ -571,154 +571,154 @@
{
"id": 94,
"enabled": true,
- "label": "New...",
- "shortcut": [["Control", "n"]],
+ "label": 'New...',
+ "shortcut": [['Control', 'n']],
"visible": true
}
]
},
{
"id": 95,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Edit",
+ "label": 'Edit',
"visible": true,
"submenu": [
{
"id": 96,
"enabled": true,
- "label": "Units",
+ "label": 'Units',
"visible": true
},
{
"id": 97,
"enabled": true,
- "label": "Modules",
+ "label": 'Modules',
"visible": true
},
{
"id": 98,
"enabled": true,
- "label": "Keyboard Shortcuts",
+ "label": 'Keyboard Shortcuts',
"visible": true
},
{
"id": 99,
"enabled": true,
- "label": "Preferences",
+ "label": 'Preferences',
"visible": true
},
{
"id": 100,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 101,
"enabled": false,
- "label": "Stroke Path...",
+ "label": 'Stroke Path...',
"visible": true
},
{
"id": 102,
"enabled": false,
- "label": "Stroke Selection...",
+ "label": 'Stroke Selection...',
"visible": true
},
{
"id": 103,
"enabled": true,
- "label": "Fill with Pattern",
- "shortcut": [["Control", "semicolon"]],
+ "label": 'Fill with Pattern',
+ "shortcut": [['Control', 'semicolon']],
"visible": true
},
{
"id": 104,
"enabled": true,
- "label": "Fill with BG Color",
- "shortcut": [["Control", "period"]],
+ "label": 'Fill with BG Color',
+ "shortcut": [['Control', 'period']],
"visible": true
},
{
"id": 105,
"enabled": true,
- "label": "Fill with FG Color",
- "shortcut": [["Control", "comma"]],
+ "label": 'Fill with FG Color',
+ "shortcut": [['Control', 'comma']],
"visible": true
},
{
"id": 106,
"enabled": true,
- "label": "Clear",
- "shortcut": [["Delete"]],
+ "label": 'Clear',
+ "shortcut": [['Delete']],
"visible": true
},
{
"id": 107,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 108,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Buffer",
+ "label": 'Buffer',
"visible": true,
"submenu": [
{
"id": 109,
"enabled": true,
- "label": "Paste Named...",
+ "label": 'Paste Named...',
"visible": true
},
{
"id": 110,
"enabled": true,
- "label": "Copy Visible Named...",
+ "label": 'Copy Visible Named...',
"visible": true
},
{
"id": 111,
"enabled": true,
- "label": "Copy Named...",
+ "label": 'Copy Named...',
"visible": true
},
{
"id": 112,
"enabled": true,
- "label": "Cut Named...",
+ "label": 'Cut Named...',
"visible": true
}
]
},
{
"id": 113,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Paste as",
+ "label": 'Paste as',
"visible": true,
"submenu": [
{
"id": 114,
"enabled": true,
- "label": "New Pattern...",
+ "label": 'New Pattern...',
"visible": true
},
{
"id": 115,
"enabled": true,
- "label": "New Brush...",
+ "label": 'New Brush...',
"visible": true
},
{
"id": 116,
"enabled": true,
- "label": "New Layer",
+ "label": 'New Layer',
"visible": true
},
{
"id": 117,
"enabled": true,
- "label": "New Image",
- "shortcut": [["Control", "Shift", "v"]],
+ "label": 'New Image',
+ "shortcut": [['Control', 'Shift', 'v']],
"visible": true
}
]
@@ -726,390 +726,390 @@
{
"id": 118,
"enabled": true,
- "label": "Paste Into",
+ "label": 'Paste Into',
"visible": true
},
{
"id": 119,
"enabled": true,
- "label": "Paste",
- "shortcut": [["Control", "v"]],
+ "label": 'Paste',
+ "shortcut": [['Control', 'v']],
"visible": true
},
{
"id": 120,
"enabled": true,
- "label": "Copy Visible",
- "shortcut": [["Control", "Shift", "c"]],
+ "label": 'Copy Visible',
+ "shortcut": [['Control', 'Shift', 'c']],
"visible": true
},
{
"id": 121,
"enabled": true,
- "label": "Copy",
- "shortcut": [["Control", "c"]],
+ "label": 'Copy',
+ "shortcut": [['Control', 'c']],
"visible": true
},
{
"id": 122,
"enabled": true,
- "label": "Cut",
- "shortcut": [["Control", "x"]],
+ "label": 'Cut',
+ "shortcut": [['Control', 'x']],
"visible": true
},
{
"id": 123,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 124,
"enabled": true,
- "label": "Undo History",
+ "label": 'Undo History',
"visible": true
},
{
"id": 3,
"enabled": false,
- "label": "_Fade...",
+ "label": '_Fade...',
"visible": true
},
{
"id": 2,
"enabled": false,
- "label": "_Redo",
- "shortcut": [["Control", "y"]],
+ "label": '_Redo',
+ "shortcut": [['Control', 'y']],
"visible": true
},
{
"id": 1,
"enabled": false,
- "label": "_Undo",
- "shortcut": [["Control", "z"]],
+ "label": '_Undo',
+ "shortcut": [['Control', 'z']],
"visible": true
}
]
},
{
"id": 125,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Select",
+ "label": 'Select',
"visible": true,
"submenu": [
{
"id": 126,
"enabled": false,
- "label": "To Path",
+ "label": 'To Path',
"visible": true
},
{
"id": 127,
"enabled": true,
- "label": "Save to Channel",
+ "label": 'Save to Channel',
"visible": true
},
{
"id": 128,
"enabled": true,
- "label": "Toggle Quick Mask",
- "shortcut": [["Shift", "q"]],
+ "label": 'Toggle Quick Mask',
+ "shortcut": [['Shift', 'q']],
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 129,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 130,
"enabled": true,
- "label": "Distort...",
+ "label": 'Distort...',
"visible": true
},
{
"id": 131,
"enabled": false,
- "label": "Border...",
+ "label": 'Border...',
"visible": true
},
{
"id": 132,
"enabled": false,
- "label": "Grow...",
+ "label": 'Grow...',
"visible": true
},
{
"id": 133,
"enabled": false,
- "label": "Shrink...",
+ "label": 'Shrink...',
"visible": true
},
{
"id": 134,
"enabled": false,
- "label": "Sharpen",
+ "label": 'Sharpen',
"visible": true
},
{
"id": 135,
"enabled": false,
- "label": "Feather...",
+ "label": 'Feather...',
"visible": true
},
{
"id": 136,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 137,
"enabled": true,
- "label": "Selection Editor",
+ "label": 'Selection Editor',
"visible": true
},
{
"id": 138,
"enabled": false,
- "label": "From Path",
- "shortcut": [["Shift", "v"]],
+ "label": 'From Path',
+ "shortcut": [['Shift', 'v']],
"visible": true
},
{
"id": 139,
"enabled": true,
- "label": "By Color",
- "shortcut": [["Shift", "o"]],
+ "label": 'By Color',
+ "shortcut": [['Shift', 'o']],
"visible": true
},
{
"id": 140,
"enabled": false,
- "label": "Float",
- "shortcut": [["Control", "Shift", "l"]],
+ "label": 'Float',
+ "shortcut": [['Control', 'Shift', 'l']],
"visible": true
},
{
"id": 141,
"enabled": true,
- "label": "Invert",
- "shortcut": [["Control", "i"]],
+ "label": 'Invert',
+ "shortcut": [['Control', 'i']],
"visible": true
},
{
"id": 142,
"enabled": false,
- "label": "None",
- "shortcut": [["Control", "Shift", "a"]],
+ "label": 'None',
+ "shortcut": [['Control', 'Shift', 'a']],
"visible": true
},
{
"id": 143,
"enabled": true,
- "label": "All",
- "shortcut": [["Control", "a"]],
+ "label": 'All',
+ "shortcut": [['Control', 'a']],
"visible": true
}
]
},
{
"id": 144,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "View",
+ "label": 'View',
"visible": true,
"submenu": [
{
"id": 145,
"enabled": true,
- "label": "Show Statusbar",
+ "label": 'Show Statusbar',
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 146,
"enabled": true,
- "label": "Show Scrollbars",
+ "label": 'Show Scrollbars',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 147,
"enabled": true,
- "label": "Show Rulers",
- "shortcut": [["Control", "Shift", "r"]],
+ "label": 'Show Rulers',
+ "shortcut": [['Control', 'Shift', 'r']],
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 148,
"enabled": true,
- "label": "Show Menubar",
+ "label": 'Show Menubar',
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 149,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Padding Color",
+ "label": 'Padding Color',
"visible": true,
"submenu": [
{
"id": 150,
"enabled": true,
- "label": "As in Preferences",
+ "label": 'As in Preferences',
"visible": true
},
{
"id": 151,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 152,
"enabled": true,
- "label": "Select Custom Color...",
+ "label": 'Select Custom Color...',
"visible": true
},
{
"id": 153,
"enabled": true,
- "label": "Dark Check Color",
+ "label": 'Dark Check Color',
"visible": true
},
{
"id": 154,
"enabled": true,
- "label": "Light Check Color",
+ "label": 'Light Check Color',
"visible": true
},
{
"id": 155,
"enabled": true,
- "label": "From Theme",
+ "label": 'From Theme',
"visible": true
}
]
},
{
"id": 156,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 157,
"enabled": true,
- "label": "Snap to Active Path",
+ "label": 'Snap to Active Path',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 158,
"enabled": true,
- "label": "Snap to Canvas Edges",
+ "label": 'Snap to Canvas Edges',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 159,
"enabled": true,
- "label": "Snap to Grid",
+ "label": 'Snap to Grid',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 160,
"enabled": true,
- "label": "Snap to Guides",
+ "label": 'Snap to Guides',
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 161,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 162,
"enabled": true,
- "label": "Show Sample Points",
+ "label": 'Show Sample Points',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 163,
"enabled": true,
- "label": "Show Grid",
+ "label": 'Show Grid',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 164,
"enabled": true,
- "label": "Show Guides",
- "shortcut": [["Control", "Shift", "t"]],
+ "label": 'Show Guides',
+ "shortcut": [['Control', 'Shift', 't']],
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 165,
"enabled": true,
- "label": "Show Layer Boundary",
+ "label": 'Show Layer Boundary',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 166,
"enabled": true,
- "label": "Show Selection",
- "shortcut": [["Control", "t"]],
+ "label": 'Show Selection',
+ "shortcut": [['Control', 't']],
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 167,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 168,
"enabled": true,
- "label": "Display Filters...",
+ "label": 'Display Filters...',
"visible": true
},
{
"id": 169,
"enabled": true,
- "label": "Navigation Window",
+ "label": 'Navigation Window',
"visible": true
},
{
"id": 170,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 171,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Fullscreen",
- "shortcut": [["F11"]],
+ "label": 'Fullscreen',
+ "shortcut": [['F11']],
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true,
"submenu": [
{
"id": 172,
"enabled": true,
- "label": "Open Display...",
+ "label": 'Open Display...',
"visible": true
}
]
@@ -1117,142 +1117,142 @@
{
"id": 173,
"enabled": true,
- "label": "Shrink Wrap",
- "shortcut": [["Control", "e"]],
+ "label": 'Shrink Wrap',
+ "shortcut": [['Control', 'e']],
"visible": true
},
{
"id": 174,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 175,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "_Zoom (67%)",
+ "label": '_Zoom (67%)',
"visible": true,
"submenu": [
{
"id": 176,
"enabled": true,
- "label": "Othe_r (67%)...",
+ "label": 'Othe_r (67%)...',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 177,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 178,
"enabled": true,
- "label": "1:16 (6.25%)",
+ "label": '1:16 (6.25%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 179,
"enabled": true,
- "label": "1:8 (12.5%)",
+ "label": '1:8 (12.5%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 180,
"enabled": true,
- "label": "1:4 (25%)",
+ "label": '1:4 (25%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 181,
"enabled": true,
- "label": "1:2 (50%)",
+ "label": '1:2 (50%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 182,
"enabled": true,
- "label": "1:1 (100%)",
- "shortcut": [["1"]],
+ "label": '1:1 (100%)',
+ "shortcut": [['1']],
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 183,
"enabled": true,
- "label": "2:1 (200%)",
+ "label": '2:1 (200%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 184,
"enabled": true,
- "label": "4:1 (400%)",
+ "label": '4:1 (400%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 185,
"enabled": true,
- "label": "8:1 (800%)",
+ "label": '8:1 (800%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 186,
"enabled": true,
- "label": "16:1 (1600%)",
+ "label": '16:1 (1600%)',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 187,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 188,
"enabled": true,
- "label": "Fill Window",
+ "label": 'Fill Window',
"visible": true
},
{
"id": 189,
"enabled": true,
- "label": "Fit Image in Window",
- "shortcut": [["Control", "Shift", "e"]],
+ "label": 'Fit Image in Window',
+ "shortcut": [['Control', 'Shift', 'e']],
"visible": true
},
{
"id": 190,
"enabled": true,
- "label": "Zoom In",
- "shortcut": [["plus"]],
+ "label": 'Zoom In',
+ "shortcut": [['plus']],
"visible": true
},
{
"id": 191,
"enabled": true,
- "label": "Zoom Out",
- "shortcut": [["minus"]],
+ "label": 'Zoom Out',
+ "shortcut": [['minus']],
"visible": true
},
{
"id": 4,
"enabled": true,
- "label": "Re_vert Zoom (67%)",
- "shortcut": [["grave"]],
+ "label": 'Re_vert Zoom (67%)',
+ "shortcut": [['grave']],
"visible": true
}
]
@@ -1260,253 +1260,253 @@
{
"id": 192,
"enabled": true,
- "label": "Dot for Dot",
+ "label": 'Dot for Dot',
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 193,
"enabled": true,
- "label": "New View",
+ "label": 'New View',
"visible": true
}
]
},
{
"id": 194,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Image",
+ "label": 'Image',
"visible": true,
"submenu": [
{
"id": 195,
"enabled": true,
- "label": "Image Properties",
- "shortcut": [["Alt", "Return"]],
+ "label": 'Image Properties',
+ "shortcut": [['Alt', 'Return']],
"visible": true
},
{
"id": 196,
"enabled": true,
- "label": "Configure Grid...",
+ "label": 'Configure Grid...',
"visible": true
},
{
"id": 197,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Guides",
+ "label": 'Guides',
"visible": true,
"submenu": [
{
"id": 198,
"enabled": true,
- "label": "Remove all Guides",
+ "label": 'Remove all Guides',
"visible": true
},
{
"id": 199,
"enabled": true,
- "label": "New Guides from Selection",
+ "label": 'New Guides from Selection',
"visible": true
},
{
"id": 200,
"enabled": true,
- "label": "New Guide...",
+ "label": 'New Guide...',
"visible": true
},
{
"id": 201,
"enabled": true,
- "label": "New Guide (by Percent)...",
+ "label": 'New Guide (by Percent)...',
"visible": true
}
]
},
{
"id": 202,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 203,
"enabled": true,
- "label": "Align Visible Layers...",
+ "label": 'Align Visible Layers...',
"visible": true
},
{
"id": 204,
"enabled": true,
- "label": "Flatten Image",
+ "label": 'Flatten Image',
"visible": true
},
{
"id": 205,
"enabled": true,
- "label": "Merge Visible Layers...",
- "shortcut": [["Control", "m"]],
+ "label": 'Merge Visible Layers...',
+ "shortcut": [['Control', 'm']],
"visible": true
},
{
"id": 206,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 207,
"enabled": true,
- "label": "Zealous Crop",
+ "label": 'Zealous Crop',
"visible": true
},
{
"id": 208,
"enabled": true,
- "label": "Autocrop Image",
+ "label": 'Autocrop Image',
"visible": true
},
{
"id": 209,
"enabled": false,
- "label": "Crop to Selection",
+ "label": 'Crop to Selection',
"visible": true
},
{
"id": 210,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 211,
"enabled": true,
- "label": "Scale Image...",
+ "label": 'Scale Image...',
"visible": true
},
{
"id": 212,
"enabled": true,
- "label": "Print Size...",
+ "label": 'Print Size...',
"visible": true
},
{
"id": 213,
"enabled": false,
- "label": "Fit Canvas to Selection",
+ "label": 'Fit Canvas to Selection',
"visible": true
},
{
"id": 214,
"enabled": true,
- "label": "Fit Canvas to Layers",
+ "label": 'Fit Canvas to Layers',
"visible": true
},
{
"id": 215,
"enabled": true,
- "label": "Canvas Size...",
+ "label": 'Canvas Size...',
"visible": true
},
{
"id": 216,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 217,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Transform",
+ "label": 'Transform',
"visible": true,
"submenu": [
{
"id": 218,
"enabled": true,
- "label": "Guillotine",
+ "label": 'Guillotine',
"visible": true
},
{
"id": 219,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 220,
"enabled": true,
- "label": "Rotate 180\302\260",
+ "label": 'Rotate 180?',
"visible": true
},
{
"id": 221,
"enabled": true,
- "label": "Rotate 90\302\260 counter-clockwise",
+ "label": 'Rotate 90? counter-clockwise',
"visible": true
},
{
"id": 222,
"enabled": true,
- "label": "Rotate 90\302\260 clockwise",
+ "label": 'Rotate 90? clockwise',
"visible": true
},
{
"id": 223,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 224,
"enabled": true,
- "label": "Flip Vertically",
+ "label": 'Flip Vertically',
"visible": true
},
{
"id": 225,
"enabled": true,
- "label": "Flip Horizontally",
+ "label": 'Flip Horizontally',
"visible": true
}
]
},
{
"id": 226,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Mode",
+ "label": 'Mode',
"visible": true,
"submenu": [
{
"id": 227,
"enabled": true,
- "label": "Convert to Color Profile...",
+ "label": 'Convert to Color Profile...',
"visible": true
},
{
"id": 228,
"enabled": true,
- "label": "Assign Color Profile...",
+ "label": 'Assign Color Profile...',
"visible": true
},
{
"id": 229,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 230,
"enabled": true,
- "label": "Indexed...",
+ "label": 'Indexed...',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 231,
"enabled": true,
- "label": "Grayscale",
+ "label": 'Grayscale',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 232,
"enabled": true,
- "label": "RGB",
+ "label": 'RGB',
"toggle-state": 1,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
}
]
@@ -1514,347 +1514,347 @@
{
"id": 233,
"enabled": true,
- "label": "Duplicate",
- "shortcut": [["Control", "d"]],
+ "label": 'Duplicate',
+ "shortcut": [['Control', 'd']],
"visible": true
}
]
},
{
"id": 234,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Layer",
+ "label": 'Layer',
"visible": true,
"submenu": [
{
"id": 235,
"enabled": true,
- "label": "Autocrop Layer",
+ "label": 'Autocrop Layer',
"visible": true
},
{
"id": 236,
"enabled": false,
- "label": "Crop to Selection",
+ "label": 'Crop to Selection',
"visible": true
},
{
"id": 237,
"enabled": true,
- "label": "Scale Layer...",
+ "label": 'Scale Layer...',
"visible": true
},
{
"id": 238,
"enabled": true,
- "label": "Layer to Image Size",
+ "label": 'Layer to Image Size',
"visible": true
},
{
"id": 239,
"enabled": true,
- "label": "Layer Boundary Size...",
+ "label": 'Layer Boundary Size...',
"visible": true
},
{
"id": 240,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 241,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Transform",
+ "label": 'Transform',
"visible": true,
"submenu": [
{
"id": 242,
"enabled": true,
- "label": "Offset...",
- "shortcut": [["Control", "Shift", "o"]],
+ "label": 'Offset...',
+ "shortcut": [['Control', 'Shift', 'o']],
"visible": true
},
{
"id": 243,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 244,
"enabled": true,
- "label": "Arbitrary Rotation...",
+ "label": 'Arbitrary Rotation...',
"visible": true
},
{
"id": 245,
"enabled": true,
- "label": "Rotate 180\302\260",
+ "label": 'Rotate 180?',
"visible": true
},
{
"id": 246,
"enabled": true,
- "label": "Rotate 90\302\260 counter-clockwise",
+ "label": 'Rotate 90? counter-clockwise',
"visible": true
},
{
"id": 247,
"enabled": true,
- "label": "Rotate 90\302\260 clockwise",
+ "label": 'Rotate 90? clockwise',
"visible": true
},
{
"id": 248,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 249,
"enabled": true,
- "label": "Flip Vertically",
+ "label": 'Flip Vertically',
"visible": true
},
{
"id": 250,
"enabled": true,
- "label": "Flip Horizontally",
+ "label": 'Flip Horizontally',
"visible": true
}
]
},
{
"id": 251,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Transparency",
+ "label": 'Transparency',
"visible": true,
"submenu": [
{
"id": 252,
"enabled": true,
- "label": "Intersect with Selection",
+ "label": 'Intersect with Selection',
"visible": true
},
{
"id": 253,
"enabled": true,
- "label": "Subtract from Selection",
+ "label": 'Subtract from Selection',
"visible": true
},
{
"id": 254,
"enabled": true,
- "label": "Add to Selection",
+ "label": 'Add to Selection',
"visible": true
},
{
"id": 255,
"enabled": true,
- "label": "Alpha to Selection",
+ "label": 'Alpha to Selection',
"visible": true
},
{
"id": 256,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 257,
"enabled": true,
- "label": "Threshold Alpha...",
+ "label": 'Threshold Alpha...',
"visible": true
},
{
"id": 258,
"enabled": true,
- "label": "Semi-Flatten",
+ "label": 'Semi-Flatten',
"visible": true
},
{
"id": 259,
"enabled": true,
- "label": "Color to Alpha...",
+ "label": 'Color to Alpha...',
"visible": true
},
{
"id": 260,
"enabled": true,
- "label": "Remove Alpha Channel",
+ "label": 'Remove Alpha Channel',
"visible": true
},
{
"id": 261,
"enabled": false,
- "label": "Add Alpha Channel",
+ "label": 'Add Alpha Channel',
"visible": true
}
]
},
{
"id": 262,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Mask",
+ "label": 'Mask',
"visible": true,
"submenu": [
{
"id": 263,
"enabled": false,
- "label": "Intersect with Selection",
+ "label": 'Intersect with Selection',
"visible": true
},
{
"id": 264,
"enabled": false,
- "label": "Subtract from Selection",
+ "label": 'Subtract from Selection',
"visible": true
},
{
"id": 265,
"enabled": false,
- "label": "Add to Selection",
+ "label": 'Add to Selection',
"visible": true
},
{
"id": 266,
"enabled": false,
- "label": "Mask to Selection",
+ "label": 'Mask to Selection',
"visible": true
},
{
"id": 267,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 268,
"enabled": false,
- "label": "Disable Layer Mask",
+ "label": 'Disable Layer Mask',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 269,
"enabled": false,
- "label": "Edit Layer Mask",
+ "label": 'Edit Layer Mask',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 270,
"enabled": false,
- "label": "Show Layer Mask",
+ "label": 'Show Layer Mask',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 271,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 272,
"enabled": false,
- "label": "Delete Layer Mask",
+ "label": 'Delete Layer Mask',
"visible": true
},
{
"id": 273,
"enabled": false,
- "label": "Apply Layer Mask",
+ "label": 'Apply Layer Mask',
"visible": true
},
{
"id": 274,
"enabled": true,
- "label": "Add Layer Mask...",
+ "label": 'Add Layer Mask...',
"visible": true
}
]
},
{
"id": 275,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Stack",
+ "label": 'Stack',
"visible": true,
"submenu": [
{
"id": 276,
"enabled": true,
- "label": "Reverse Layer Order",
+ "label": 'Reverse Layer Order',
"visible": true
},
{
"id": 277,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 278,
"enabled": false,
- "label": "Layer to Bottom",
+ "label": 'Layer to Bottom',
"visible": true
},
{
"id": 279,
"enabled": false,
- "label": "Layer to Top",
+ "label": 'Layer to Top',
"visible": true
},
{
"id": 280,
"enabled": false,
- "label": "Lower Layer",
+ "label": 'Lower Layer',
"visible": true
},
{
"id": 281,
"enabled": false,
- "label": "Raise Layer",
+ "label": 'Raise Layer',
"visible": true
},
{
"id": 282,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 283,
"enabled": false,
- "label": "Select Bottom Layer",
- "shortcut": [["End"]],
+ "label": 'Select Bottom Layer',
+ "shortcut": [['End']],
"visible": true
},
{
"id": 284,
"enabled": false,
- "label": "Select Top Layer",
- "shortcut": [["Home"]],
+ "label": 'Select Top Layer',
+ "shortcut": [['Home']],
"visible": true
},
{
"id": 285,
"enabled": false,
- "label": "Select Next Layer",
- "shortcut": [["Page_Down"]],
+ "label": 'Select Next Layer',
+ "shortcut": [['Page_Down']],
"visible": true
},
{
"id": 286,
"enabled": false,
- "label": "Select Previous Layer",
- "shortcut": [["Page_Up"]],
+ "label": 'Select Previous Layer',
+ "shortcut": [['Page_Up']],
"visible": true
}
]
},
{
"id": 287,
- "children-display": "submenu",
- "type": "separator",
+ "children-display": 'submenu',
+ "type": 'separator',
"submenu": [
{
"id": 288,
"enabled": false,
- "label": "Empty",
+ "label": 'Empty',
"visible": true
}
]
@@ -1862,704 +1862,704 @@
{
"id": 289,
"enabled": true,
- "label": "Delete Layer",
+ "label": 'Delete Layer',
"visible": true
},
{
"id": 290,
"enabled": false,
- "label": "Merge Down",
+ "label": 'Merge Down',
"visible": true
},
{
"id": 291,
"enabled": false,
- "label": "Anchor Layer",
- "shortcut": [["Control", "h"]],
+ "label": 'Anchor Layer',
+ "shortcut": [['Control', 'h']],
"visible": true
},
{
"id": 292,
"enabled": true,
- "label": "Duplicate Layer",
- "shortcut": [["Control", "Shift", "d"]],
+ "label": 'Duplicate Layer',
+ "shortcut": [['Control', 'Shift', 'd']],
"visible": true
},
{
"id": 293,
"enabled": true,
- "label": "New from Visible",
+ "label": 'New from Visible',
"visible": true
},
{
"id": 294,
"enabled": true,
- "label": "New Layer...",
- "shortcut": [["Control", "Shift", "n"]],
+ "label": 'New Layer...',
+ "shortcut": [['Control', 'Shift', 'n']],
"visible": true
}
]
},
{
"id": 295,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Colors",
+ "label": 'Colors',
"visible": true,
"submenu": [
{
"id": 296,
"enabled": true,
- "label": "Retinex...",
+ "label": 'Retinex...',
"visible": true
},
{
"id": 297,
"enabled": true,
- "label": "Maximum RGB...",
+ "label": 'Maximum RGB...',
"visible": true
},
{
"id": 298,
"enabled": false,
- "label": "Hot...",
+ "label": 'Hot...',
"visible": true
},
{
"id": 299,
"enabled": true,
- "label": "Filter Pack...",
+ "label": 'Filter Pack...',
"visible": true
},
{
"id": 300,
"enabled": true,
- "label": "Color to Alpha...",
+ "label": 'Color to Alpha...',
"visible": true
},
{
"id": 301,
"enabled": true,
- "label": "Colorify...",
+ "label": 'Colorify...',
"visible": true
},
{
"id": 302,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 303,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Info",
+ "label": 'Info',
"visible": true,
"submenu": [
{
"id": 304,
"enabled": true,
- "label": "Smooth Palette...",
+ "label": 'Smooth Palette...',
"visible": true
},
{
"id": 305,
"enabled": true,
- "label": "Colorcube Analysis...",
+ "label": 'Colorcube Analysis...',
"visible": true
},
{
"id": 306,
"enabled": true,
- "label": "Border Average...",
+ "label": 'Border Average...',
"visible": true
},
{
"id": 307,
"enabled": true,
- "label": "Histogram",
+ "label": 'Histogram',
"visible": true
}
]
},
{
"id": 308,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Map",
+ "label": 'Map',
"visible": true,
"submenu": [
{
"id": 309,
"enabled": true,
- "label": "Sample Colorize...",
+ "label": 'Sample Colorize...',
"visible": true
},
{
"id": 310,
"enabled": true,
- "label": "Rotate Colors...",
+ "label": 'Rotate Colors...',
"visible": true
},
{
"id": 311,
"enabled": true,
- "label": "Palette Map",
+ "label": 'Palette Map',
"visible": true
},
{
"id": 312,
"enabled": true,
- "label": "Gradient Map",
+ "label": 'Gradient Map',
"visible": true
},
{
"id": 313,
"enabled": true,
- "label": "Color Exchange...",
+ "label": 'Color Exchange...',
"visible": true
},
{
"id": 314,
"enabled": true,
- "label": "Alien Map...",
+ "label": 'Alien Map...',
"visible": true
},
{
"id": 315,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 316,
"enabled": false,
- "label": "Set Colormap...",
+ "label": 'Set Colormap...',
"visible": true
},
{
"id": 317,
"enabled": false,
- "label": "Rearrange Colormap...",
+ "label": 'Rearrange Colormap...',
"visible": true
}
]
},
{
"id": 318,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Components",
+ "label": 'Components',
"visible": true,
"submenu": [
{
"id": 319,
"enabled": false,
- "label": "Recompose",
+ "label": 'Recompose',
"visible": true
},
{
"id": 320,
"enabled": true,
- "label": "Decompose...",
+ "label": 'Decompose...',
"visible": true
},
{
"id": 321,
"enabled": false,
- "label": "Compose...",
+ "label": 'Compose...',
"visible": true
},
{
"id": 322,
"enabled": true,
- "label": "Channel Mixer...",
+ "label": 'Channel Mixer...',
"visible": true
}
]
},
{
"id": 323,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Auto",
+ "label": 'Auto',
"visible": true,
"submenu": [
{
"id": 324,
"enabled": true,
- "label": "Stretch HSV",
+ "label": 'Stretch HSV',
"visible": true
},
{
"id": 325,
"enabled": true,
- "label": "Stretch Contrast",
+ "label": 'Stretch Contrast',
"visible": true
},
{
"id": 326,
"enabled": true,
- "label": "Normalize",
+ "label": 'Normalize',
"visible": true
},
{
"id": 327,
"enabled": true,
- "label": "Color Enhance",
+ "label": 'Color Enhance',
"visible": true
},
{
"id": 328,
"enabled": true,
- "label": "White Balance",
+ "label": 'White Balance',
"visible": true
},
{
"id": 329,
"enabled": true,
- "label": "Equalize",
+ "label": 'Equalize',
"visible": true
}
]
},
{
"id": 330,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 331,
"enabled": true,
- "label": "Use GEGL",
+ "label": 'Use GEGL',
"toggle-state": 0,
- "toggle-type": "checkmark",
+ "toggle-type": 'checkmark',
"visible": true
},
{
"id": 332,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 333,
"enabled": true,
- "label": "Value Invert",
+ "label": 'Value Invert',
"visible": true
},
{
"id": 334,
"enabled": true,
- "label": "Invert",
+ "label": 'Invert',
"visible": true
},
{
"id": 335,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 336,
"enabled": true,
- "label": "Desaturate...",
+ "label": 'Desaturate...',
"visible": true
},
{
"id": 337,
"enabled": true,
- "label": "Posterize...",
+ "label": 'Posterize...',
"visible": true
},
{
"id": 338,
"enabled": true,
- "label": "Curves...",
+ "label": 'Curves...',
"visible": true
},
{
"id": 339,
"enabled": true,
- "label": "Levels...",
+ "label": 'Levels...',
"visible": true
},
{
"id": 340,
"enabled": true,
- "label": "Threshold...",
+ "label": 'Threshold...',
"visible": true
},
{
"id": 341,
"enabled": true,
- "label": "Brightness-Contrast...",
+ "label": 'Brightness-Contrast...',
"visible": true
},
{
"id": 342,
"enabled": true,
- "label": "Colorize...",
+ "label": 'Colorize...',
"visible": true
},
{
"id": 343,
"enabled": true,
- "label": "Hue-Saturation...",
+ "label": 'Hue-Saturation...',
"visible": true
},
{
"id": 344,
"enabled": true,
- "label": "Color Balance...",
+ "label": 'Color Balance...',
"visible": true
}
]
},
{
"id": 345,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Tools",
+ "label": 'Tools',
"visible": true,
"submenu": [
{
"id": 346,
"enabled": true,
- "label": "Swap Colors",
- "shortcut": [["x"]],
+ "label": 'Swap Colors',
+ "shortcut": [['x']],
"visible": true
},
{
"id": 347,
"enabled": true,
- "label": "Default Colors",
- "shortcut": [["d"]],
+ "label": 'Default Colors',
+ "shortcut": [['d']],
"visible": true
},
{
"id": 348,
"enabled": true,
- "label": "Toolbox",
- "shortcut": [["Control", "b"]],
+ "label": 'Toolbox',
+ "shortcut": [['Control', 'b']],
"visible": true
},
{
"id": 349,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 350,
"enabled": true,
- "label": "GEGL Operation...",
+ "label": 'GEGL Operation...',
"visible": true
},
{
"id": 351,
"enabled": true,
- "label": "Text",
- "shortcut": [["t"]],
+ "label": 'Text',
+ "shortcut": [['t']],
"visible": true
},
{
"id": 352,
"enabled": true,
- "label": "Measure",
- "shortcut": [["Shift", "m"]],
+ "label": 'Measure',
+ "shortcut": [['Shift', 'm']],
"visible": true
},
{
"id": 353,
"enabled": true,
- "label": "Zoom",
- "shortcut": [["z"]],
+ "label": 'Zoom',
+ "shortcut": [['z']],
"visible": true
},
{
"id": 354,
"enabled": true,
- "label": "Color Picker",
- "shortcut": [["o"]],
+ "label": 'Color Picker',
+ "shortcut": [['o']],
"visible": true
},
{
"id": 355,
"enabled": true,
- "label": "Paths",
- "shortcut": [["b"]],
+ "label": 'Paths',
+ "shortcut": [['b']],
"visible": true
},
{
"id": 356,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Color Tools",
+ "label": 'Color Tools',
"visible": true,
"submenu": [
{
"id": 357,
"enabled": true,
- "label": "Desaturate...",
+ "label": 'Desaturate...',
"visible": true
},
{
"id": 358,
"enabled": true,
- "label": "Posterize...",
+ "label": 'Posterize...',
"visible": true
},
{
"id": 359,
"enabled": true,
- "label": "Curves...",
+ "label": 'Curves...',
"visible": true
},
{
"id": 360,
"enabled": true,
- "label": "Levels...",
+ "label": 'Levels...',
"visible": true
},
{
"id": 361,
"enabled": true,
- "label": "Threshold...",
+ "label": 'Threshold...',
"visible": true
},
{
"id": 362,
"enabled": true,
- "label": "Brightness-Contrast...",
+ "label": 'Brightness-Contrast...',
"visible": true
},
{
"id": 363,
"enabled": true,
- "label": "Colorize...",
+ "label": 'Colorize...',
"visible": true
},
{
"id": 364,
"enabled": true,
- "label": "Hue-Saturation...",
+ "label": 'Hue-Saturation...',
"visible": true
},
{
"id": 365,
"enabled": true,
- "label": "Color Balance...",
+ "label": 'Color Balance...',
"visible": true
}
]
},
{
"id": 366,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Transform Tools",
+ "label": 'Transform Tools',
"visible": true,
"submenu": [
{
"id": 367,
"enabled": true,
- "label": "Flip",
- "shortcut": [["Shift", "f"]],
+ "label": 'Flip',
+ "shortcut": [['Shift', 'f']],
"visible": true
},
{
"id": 368,
"enabled": true,
- "label": "Perspective",
- "shortcut": [["Shift", "p"]],
+ "label": 'Perspective',
+ "shortcut": [['Shift', 'p']],
"visible": true
},
{
"id": 369,
"enabled": true,
- "label": "Shear",
- "shortcut": [["Shift", "s"]],
+ "label": 'Shear',
+ "shortcut": [['Shift', 's']],
"visible": true
},
{
"id": 370,
"enabled": true,
- "label": "Scale",
- "shortcut": [["Shift", "t"]],
+ "label": 'Scale',
+ "shortcut": [['Shift', 't']],
"visible": true
},
{
"id": 371,
"enabled": true,
- "label": "Rotate",
- "shortcut": [["Shift", "r"]],
+ "label": 'Rotate',
+ "shortcut": [['Shift', 'r']],
"visible": true
},
{
"id": 372,
"enabled": true,
- "label": "Crop",
- "shortcut": [["Shift", "c"]],
+ "label": 'Crop',
+ "shortcut": [['Shift', 'c']],
"visible": true
},
{
"id": 373,
"enabled": true,
- "label": "Move",
- "shortcut": [["m"]],
+ "label": 'Move',
+ "shortcut": [['m']],
"visible": true
},
{
"id": 374,
"enabled": true,
- "label": "Align",
- "shortcut": [["q"]],
+ "label": 'Align',
+ "shortcut": [['q']],
"visible": true
}
]
},
{
"id": 375,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Paint Tools",
+ "label": 'Paint Tools',
"visible": true,
"submenu": [
{
"id": 376,
"enabled": true,
- "label": "Dodge / Burn",
- "shortcut": [["Shift", "d"]],
+ "label": 'Dodge / Burn',
+ "shortcut": [['Shift', 'd']],
"visible": true
},
{
"id": 377,
"enabled": true,
- "label": "Smudge",
- "shortcut": [["s"]],
+ "label": 'Smudge',
+ "shortcut": [['s']],
"visible": true
},
{
"id": 378,
"enabled": true,
- "label": "Blur / Sharpen",
- "shortcut": [["Shift", "u"]],
+ "label": 'Blur / Sharpen',
+ "shortcut": [['Shift', 'u']],
"visible": true
},
{
"id": 379,
"enabled": true,
- "label": "Perspective Clone",
+ "label": 'Perspective Clone',
"visible": true
},
{
"id": 380,
"enabled": true,
- "label": "Heal",
- "shortcut": [["h"]],
+ "label": 'Heal',
+ "shortcut": [['h']],
"visible": true
},
{
"id": 381,
"enabled": true,
- "label": "Clone",
- "shortcut": [["c"]],
+ "label": 'Clone',
+ "shortcut": [['c']],
"visible": true
},
{
"id": 382,
"enabled": true,
- "label": "Ink",
- "shortcut": [["k"]],
+ "label": 'Ink',
+ "shortcut": [['k']],
"visible": true
},
{
"id": 383,
"enabled": true,
- "label": "Airbrush",
- "shortcut": [["a"]],
+ "label": 'Airbrush',
+ "shortcut": [['a']],
"visible": true
},
{
"id": 384,
"enabled": true,
- "label": "Eraser",
- "shortcut": [["Shift", "e"]],
+ "label": 'Eraser',
+ "shortcut": [['Shift', 'e']],
"visible": true
},
{
"id": 385,
"enabled": true,
- "label": "Paintbrush",
- "shortcut": [["p"]],
+ "label": 'Paintbrush',
+ "shortcut": [['p']],
"visible": true
},
{
"id": 386,
"enabled": true,
- "label": "Pencil",
- "shortcut": [["n"]],
+ "label": 'Pencil',
+ "shortcut": [['n']],
"visible": true
},
{
"id": 387,
"enabled": true,
- "label": "Blend",
- "shortcut": [["l"]],
+ "label": 'Blend',
+ "shortcut": [['l']],
"visible": true
},
{
"id": 388,
"enabled": true,
- "label": "Bucket Fill",
- "shortcut": [["Shift", "b"]],
+ "label": 'Bucket Fill',
+ "shortcut": [['Shift', 'b']],
"visible": true
}
]
},
{
"id": 389,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Selection Tools",
+ "label": 'Selection Tools',
"visible": true,
"submenu": [
{
"id": 390,
"enabled": true,
- "label": "Intelligent Scissors",
- "shortcut": [["i"]],
+ "label": 'Intelligent Scissors',
+ "shortcut": [['i']],
"visible": true
},
{
"id": 391,
"enabled": true,
- "label": "By Color Select",
- "shortcut": [["Shift", "o"]],
+ "label": 'By Color Select',
+ "shortcut": [['Shift', 'o']],
"visible": true
},
{
"id": 392,
"enabled": true,
- "label": "Fuzzy Select",
- "shortcut": [["u"]],
+ "label": 'Fuzzy Select',
+ "shortcut": [['u']],
"visible": true
},
{
"id": 393,
"enabled": true,
- "label": "Foreground Select",
+ "label": 'Foreground Select',
"visible": true
},
{
"id": 394,
"enabled": true,
- "label": "Free Select",
- "shortcut": [["f"]],
+ "label": 'Free Select',
+ "shortcut": [['f']],
"visible": true
},
{
"id": 395,
"enabled": true,
- "label": "Ellipse Select",
- "shortcut": [["e"]],
+ "label": 'Ellipse Select',
+ "shortcut": [['e']],
"visible": true
},
{
"id": 396,
"enabled": true,
- "label": "Rectangle Select",
- "shortcut": [["r"]],
+ "label": 'Rectangle Select',
+ "shortcut": [['r']],
"visible": true
}
]
@@ -2568,438 +2568,438 @@
},
{
"id": 397,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Filters",
+ "label": 'Filters',
"visible": true,
"submenu": [
{
"id": 398,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Script-Fu",
+ "label": 'Script-Fu',
"visible": true,
"submenu": [
{
"id": 399,
"enabled": true,
- "label": "Start Server...",
+ "label": 'Start Server...',
"visible": true
},
{
"id": 400,
"enabled": true,
- "label": "Refresh Scripts",
+ "label": 'Refresh Scripts',
"visible": true
},
{
"id": 401,
"enabled": true,
- "label": "Console",
+ "label": 'Console',
"visible": true
}
]
},
{
"id": 402,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Python-Fu",
+ "label": 'Python-Fu',
"visible": true,
"submenu": [
{
"id": 403,
"enabled": true,
- "label": "Console",
+ "label": 'Console',
"visible": true
}
]
},
{
"id": 404,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 405,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Alpha to Logo",
+ "label": 'Alpha to Logo',
"visible": true,
"submenu": [
{
"id": 406,
"enabled": true,
- "label": "Textured...",
+ "label": 'Textured...',
"visible": true
},
{
"id": 407,
"enabled": true,
- "label": "Particle Trace...",
+ "label": 'Particle Trace...',
"visible": true
},
{
"id": 408,
"enabled": true,
- "label": "Neon...",
+ "label": 'Neon...',
"visible": true
},
{
"id": 409,
"enabled": true,
- "label": "Gradient Bevel...",
+ "label": 'Gradient Bevel...',
"visible": true
},
{
"id": 410,
"enabled": true,
- "label": "Glowing Hot...",
+ "label": 'Glowing Hot...',
"visible": true
},
{
"id": 411,
"enabled": true,
- "label": "Glossy...",
+ "label": 'Glossy...',
"visible": true
},
{
"id": 412,
"enabled": true,
- "label": "Frosty...",
+ "label": 'Frosty...',
"visible": true
},
{
"id": 413,
"enabled": true,
- "label": "Cool Metal...",
+ "label": 'Cool Metal...',
"visible": true
},
{
"id": 414,
"enabled": true,
- "label": "Comic Book...",
+ "label": 'Comic Book...',
"visible": true
},
{
"id": 415,
"enabled": true,
- "label": "Chrome...",
+ "label": 'Chrome...',
"visible": true
},
{
"id": 416,
"enabled": true,
- "label": "Chip Away...",
+ "label": 'Chip Away...',
"visible": true
},
{
"id": 417,
"enabled": true,
- "label": "Chalk...",
+ "label": 'Chalk...',
"visible": true
},
{
"id": 418,
"enabled": true,
- "label": "Bovination...",
+ "label": 'Bovination...',
"visible": true
},
{
"id": 419,
"enabled": true,
- "label": "Blended...",
+ "label": 'Blended...',
"visible": true
},
{
"id": 420,
"enabled": true,
- "label": "Basic I...",
+ "label": 'Basic I...',
"visible": true
},
{
"id": 421,
"enabled": true,
- "label": "Basic II...",
+ "label": 'Basic II...',
"visible": true
},
{
"id": 422,
"enabled": true,
- "label": "Alien Neon...",
+ "label": 'Alien Neon...',
"visible": true
},
{
"id": 423,
"enabled": true,
- "label": "Alien Glow...",
+ "label": 'Alien Glow...',
"visible": true
},
{
"id": 424,
"enabled": true,
- "label": "3D Outline...",
+ "label": '3D Outline...',
"visible": true
}
]
},
{
"id": 425,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 426,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Animation",
+ "label": 'Animation',
"visible": true,
"submenu": [
{
"id": 427,
"enabled": true,
- "label": "Unoptimize",
+ "label": 'Unoptimize',
"visible": true
},
{
"id": 428,
"enabled": true,
- "label": "Playback...",
+ "label": 'Playback...',
"visible": true
},
{
"id": 429,
"enabled": true,
- "label": "Optimize (for GIF)",
+ "label": 'Optimize (for GIF)',
"visible": true
},
{
"id": 430,
"enabled": true,
- "label": "Optimize (Difference)",
+ "label": 'Optimize (Difference)',
"visible": true
},
{
"id": 431,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 432,
"enabled": true,
- "label": "Waves...",
+ "label": 'Waves...',
"visible": true
},
{
"id": 433,
"enabled": true,
- "label": "Spinning Globe...",
+ "label": 'Spinning Globe...',
"visible": true
},
{
"id": 434,
"enabled": true,
- "label": "Rippling...",
+ "label": 'Rippling...',
"visible": true
},
{
"id": 435,
"enabled": true,
- "label": "Burn-In...",
+ "label": 'Burn-In...',
"visible": true
},
{
"id": 436,
"enabled": true,
- "label": "Blend...",
+ "label": 'Blend...',
"visible": true
}
]
},
{
"id": 437,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Web",
+ "label": 'Web',
"visible": true,
"submenu": [
{
"id": 438,
"enabled": true,
- "label": "Slice...",
+ "label": 'Slice...',
"visible": true
},
{
"id": 439,
"enabled": true,
- "label": "Semi-Flatten",
+ "label": 'Semi-Flatten',
"visible": true
},
{
"id": 440,
"enabled": true,
- "label": "Image Map...",
+ "label": 'Image Map...',
"visible": true
}
]
},
{
"id": 441,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Render",
+ "label": 'Render',
"visible": true,
"submenu": [
{
"id": 442,
"enabled": true,
- "label": "Spyrogimp...",
+ "label": 'Spyrogimp...',
"visible": true
},
{
"id": 443,
"enabled": true,
- "label": "Sphere Designer...",
+ "label": 'Sphere Designer...',
"visible": true
},
{
"id": 444,
"enabled": true,
- "label": "Line Nova...",
+ "label": 'Line Nova...',
"visible": true
},
{
"id": 445,
"enabled": true,
- "label": "Lava...",
+ "label": 'Lava...',
"visible": true
},
{
"id": 446,
"enabled": true,
- "label": "Gfig...",
+ "label": 'Gfig...',
"visible": true
},
{
"id": 447,
"enabled": true,
- "label": "Fractal Explorer...",
+ "label": 'Fractal Explorer...',
"visible": true
},
{
"id": 448,
"enabled": true,
- "label": "Circuit...",
+ "label": 'Circuit...',
"visible": true
},
{
"id": 449,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 450,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Pattern",
+ "label": 'Pattern',
"visible": true,
"submenu": [
{
"id": 451,
"enabled": true,
- "label": "Sinus...",
+ "label": 'Sinus...',
"visible": true
},
{
"id": 452,
"enabled": true,
- "label": "Qbist...",
+ "label": 'Qbist...',
"visible": true
},
{
"id": 453,
"enabled": true,
- "label": "Maze...",
+ "label": 'Maze...',
"visible": true
},
{
"id": 454,
"enabled": true,
- "label": "Jigsaw...",
+ "label": 'Jigsaw...',
"visible": true
},
{
"id": 455,
"enabled": true,
- "label": "Grid...",
+ "label": 'Grid...',
"visible": true
},
{
"id": 456,
"enabled": true,
- "label": "Diffraction Patterns...",
+ "label": 'Diffraction Patterns...',
"visible": true
},
{
"id": 457,
"enabled": true,
- "label": "CML Explorer...",
+ "label": 'CML Explorer...',
"visible": true
},
{
"id": 458,
"enabled": true,
- "label": "Checkerboard...",
+ "label": 'Checkerboard...',
"visible": true
}
]
},
{
"id": 459,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Nature",
+ "label": 'Nature',
"visible": true,
"submenu": [
{
"id": 460,
"enabled": true,
- "label": "IFS Fractal...",
+ "label": 'IFS Fractal...',
"visible": true
},
{
"id": 461,
"enabled": true,
- "label": "Flame...",
+ "label": 'Flame...',
"visible": true
}
]
},
{
"id": 462,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Clouds",
+ "label": 'Clouds',
"visible": true,
"submenu": [
{
"id": 463,
"enabled": true,
- "label": "Solid Noise...",
+ "label": 'Solid Noise...',
"visible": true
},
{
"id": 464,
"enabled": true,
- "label": "Plasma...",
+ "label": 'Plasma...',
"visible": true
},
{
"id": 465,
"enabled": true,
- "label": "Fog...",
+ "label": 'Fog...',
"visible": true
},
{
"id": 466,
"enabled": true,
- "label": "Difference Clouds...",
+ "label": 'Difference Clouds...',
"visible": true
}
]
@@ -3008,661 +3008,661 @@
},
{
"id": 467,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Map",
+ "label": 'Map',
"visible": true,
"submenu": [
{
"id": 468,
"enabled": true,
- "label": "Warp...",
+ "label": 'Warp...',
"visible": true
},
{
"id": 469,
"enabled": true,
- "label": "Tile...",
+ "label": 'Tile...',
"visible": true
},
{
"id": 470,
"enabled": true,
- "label": "Small Tiles...",
+ "label": 'Small Tiles...',
"visible": true
},
{
"id": 471,
"enabled": true,
- "label": "Paper Tile...",
+ "label": 'Paper Tile...',
"visible": true
},
{
"id": 472,
"enabled": true,
- "label": "Map Object...",
+ "label": 'Map Object...',
"visible": true
},
{
"id": 473,
"enabled": true,
- "label": "Make Seamless",
+ "label": 'Make Seamless',
"visible": true
},
{
"id": 474,
"enabled": true,
- "label": "Illusion...",
+ "label": 'Illusion...',
"visible": true
},
{
"id": 475,
"enabled": true,
- "label": "Fractal Trace...",
+ "label": 'Fractal Trace...',
"visible": true
},
{
"id": 476,
"enabled": true,
- "label": "Displace...",
+ "label": 'Displace...',
"visible": true
},
{
"id": 477,
"enabled": true,
- "label": "Bump Map...",
+ "label": 'Bump Map...',
"visible": true
}
]
},
{
"id": 478,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Decor",
+ "label": 'Decor',
"visible": true,
"submenu": [
{
"id": 479,
"enabled": false,
- "label": "Stencil Chrome...",
+ "label": 'Stencil Chrome...',
"visible": true
},
{
"id": 480,
"enabled": false,
- "label": "Stencil Carve...",
+ "label": 'Stencil Carve...',
"visible": true
},
{
"id": 481,
"enabled": false,
- "label": "Slide...",
+ "label": 'Slide...',
"visible": true
},
{
"id": 482,
"enabled": false,
- "label": "Round Corners...",
+ "label": 'Round Corners...',
"visible": true
},
{
"id": 483,
"enabled": true,
- "label": "Old Photo...",
+ "label": 'Old Photo...',
"visible": true
},
{
"id": 484,
"enabled": true,
- "label": "Fuzzy Border...",
+ "label": 'Fuzzy Border...',
"visible": true
},
{
"id": 485,
"enabled": true,
- "label": "Coffee Stain...",
+ "label": 'Coffee Stain...',
"visible": true
},
{
"id": 486,
"enabled": true,
- "label": "Add Border...",
+ "label": 'Add Border...',
"visible": true
},
{
"id": 487,
"enabled": true,
- "label": "Add Bevel...",
+ "label": 'Add Bevel...',
"visible": true
}
]
},
{
"id": 488,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Artistic",
+ "label": 'Artistic',
"visible": true,
"submenu": [
{
"id": 489,
"enabled": true,
- "label": "Weave...",
+ "label": 'Weave...',
"visible": true
},
{
"id": 490,
"enabled": true,
- "label": "Van Gogh (LIC)...",
+ "label": 'Van Gogh (LIC)...',
"visible": true
},
{
"id": 491,
"enabled": true,
- "label": "Softglow...",
+ "label": 'Softglow...',
"visible": true
},
{
"id": 492,
"enabled": true,
- "label": "Predator...",
+ "label": 'Predator...',
"visible": true
},
{
"id": 493,
"enabled": true,
- "label": "Photocopy...",
+ "label": 'Photocopy...',
"visible": true
},
{
"id": 494,
"enabled": true,
- "label": "Oilify...",
+ "label": 'Oilify...',
"visible": true
},
{
"id": 495,
"enabled": true,
- "label": "GIMPressionist...",
+ "label": 'GIMPressionist...',
"visible": true
},
{
"id": 496,
"enabled": true,
- "label": "Cubism...",
+ "label": 'Cubism...',
"visible": true
},
{
"id": 497,
"enabled": true,
- "label": "Clothify...",
+ "label": 'Clothify...',
"visible": true
},
{
"id": 498,
"enabled": true,
- "label": "Cartoon...",
+ "label": 'Cartoon...',
"visible": true
},
{
"id": 499,
"enabled": true,
- "label": "Apply Canvas...",
+ "label": 'Apply Canvas...',
"visible": true
}
]
},
{
"id": 500,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Combine",
+ "label": 'Combine',
"visible": true,
"submenu": [
{
"id": 501,
"enabled": true,
- "label": "Filmstrip...",
+ "label": 'Filmstrip...',
"visible": true
},
{
"id": 502,
"enabled": true,
- "label": "Depth Merge...",
+ "label": 'Depth Merge...',
"visible": true
}
]
},
{
"id": 503,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Generic",
+ "label": 'Generic',
"visible": true,
"submenu": [
{
"id": 504,
"enabled": true,
- "label": "Erode",
+ "label": 'Erode',
"visible": true
},
{
"id": 505,
"enabled": true,
- "label": "Dilate",
+ "label": 'Dilate',
"visible": true
},
{
"id": 506,
"enabled": true,
- "label": "Convolution Matrix...",
+ "label": 'Convolution Matrix...',
"visible": true
}
]
},
{
"id": 507,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Edge-Detect",
+ "label": 'Edge-Detect',
"visible": true,
"submenu": [
{
"id": 508,
"enabled": true,
- "label": "Sobel...",
+ "label": 'Sobel...',
"visible": true
},
{
"id": 509,
"enabled": true,
- "label": "Neon...",
+ "label": 'Neon...',
"visible": true
},
{
"id": 510,
"enabled": true,
- "label": "Laplace",
+ "label": 'Laplace',
"visible": true
},
{
"id": 511,
"enabled": true,
- "label": "Edge...",
+ "label": 'Edge...',
"visible": true
},
{
"id": 512,
"enabled": true,
- "label": "Difference of Gaussians...",
+ "label": 'Difference of Gaussians...',
"visible": true
}
]
},
{
"id": 513,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Noise",
+ "label": 'Noise',
"visible": true,
"submenu": [
{
"id": 514,
"enabled": true,
- "label": "Spread...",
+ "label": 'Spread...',
"visible": true
},
{
"id": 515,
"enabled": true,
- "label": "Slur...",
+ "label": 'Slur...',
"visible": true
},
{
"id": 516,
"enabled": true,
- "label": "RGB Noise...",
+ "label": 'RGB Noise...',
"visible": true
},
{
"id": 517,
"enabled": true,
- "label": "Pick...",
+ "label": 'Pick...',
"visible": true
},
{
"id": 518,
"enabled": true,
- "label": "Hurl...",
+ "label": 'Hurl...',
"visible": true
},
{
"id": 519,
"enabled": true,
- "label": "HSV Noise...",
+ "label": 'HSV Noise...',
"visible": true
}
]
},
{
"id": 520,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Light and Shadow",
+ "label": 'Light and Shadow',
"visible": true,
"submenu": [
{
"id": 521,
"enabled": true,
- "label": "Glass Tile...",
+ "label": 'Glass Tile...',
"visible": true
},
{
"id": 522,
"enabled": true,
- "label": "Apply Lens...",
+ "label": 'Apply Lens...',
"visible": true
},
{
"id": 523,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 524,
"enabled": true,
- "label": "Xach-Effect...",
+ "label": 'Xach-Effect...',
"visible": true
},
{
"id": 525,
"enabled": true,
- "label": "Perspective...",
+ "label": 'Perspective...',
"visible": true
},
{
"id": 526,
"enabled": true,
- "label": "Drop Shadow...",
+ "label": 'Drop Shadow...',
"visible": true
},
{
"id": 527,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 528,
"enabled": true,
- "label": "Supernova...",
+ "label": 'Supernova...',
"visible": true
},
{
"id": 529,
"enabled": true,
- "label": "Sparkle...",
+ "label": 'Sparkle...',
"visible": true
},
{
"id": 530,
"enabled": true,
- "label": "Lighting Effects...",
+ "label": 'Lighting Effects...',
"visible": true
},
{
"id": 531,
"enabled": true,
- "label": "Lens Flare...",
+ "label": 'Lens Flare...',
"visible": true
},
{
"id": 532,
"enabled": true,
- "label": "Gradient Flare...",
+ "label": 'Gradient Flare...',
"visible": true
}
]
},
{
"id": 533,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Distorts",
+ "label": 'Distorts',
"visible": true,
"submenu": [
{
"id": 534,
"enabled": true,
- "label": "Wind...",
+ "label": 'Wind...',
"visible": true
},
{
"id": 535,
"enabled": true,
- "label": "Whirl and Pinch...",
+ "label": 'Whirl and Pinch...',
"visible": true
},
{
"id": 536,
"enabled": true,
- "label": "Waves...",
+ "label": 'Waves...',
"visible": true
},
{
"id": 537,
"enabled": true,
- "label": "Video...",
+ "label": 'Video...',
"visible": true
},
{
"id": 538,
"enabled": true,
- "label": "Value Propagate...",
+ "label": 'Value Propagate...',
"visible": true
},
{
"id": 539,
"enabled": true,
- "label": "Shift...",
+ "label": 'Shift...',
"visible": true
},
{
"id": 540,
"enabled": true,
- "label": "Ripple...",
+ "label": 'Ripple...',
"visible": true
},
{
"id": 541,
"enabled": true,
- "label": "Polar Coordinates...",
+ "label": 'Polar Coordinates...',
"visible": true
},
{
"id": 542,
"enabled": true,
- "label": "Pagecurl...",
+ "label": 'Pagecurl...',
"visible": true
},
{
"id": 543,
"enabled": true,
- "label": "Newsprint...",
+ "label": 'Newsprint...',
"visible": true
},
{
"id": 544,
"enabled": true,
- "label": "Mosaic...",
+ "label": 'Mosaic...',
"visible": true
},
{
"id": 545,
"enabled": true,
- "label": "Lens Distortion...",
+ "label": 'Lens Distortion...',
"visible": true
},
{
"id": 546,
"enabled": true,
- "label": "IWarp...",
+ "label": 'IWarp...',
"visible": true
},
{
"id": 547,
"enabled": true,
- "label": "Erase Every Other Row...",
+ "label": 'Erase Every Other Row...',
"visible": true
},
{
"id": 548,
"enabled": true,
- "label": "Engrave...",
+ "label": 'Engrave...',
"visible": true
},
{
"id": 549,
"enabled": true,
- "label": "Emboss...",
+ "label": 'Emboss...',
"visible": true
},
{
"id": 550,
"enabled": true,
- "label": "Curve Bend...",
+ "label": 'Curve Bend...',
"visible": true
},
{
"id": 551,
"enabled": true,
- "label": "Blinds...",
+ "label": 'Blinds...',
"visible": true
}
]
},
{
"id": 552,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Enhance",
+ "label": 'Enhance',
"visible": true,
"submenu": [
{
"id": 553,
"enabled": true,
- "label": "Unsharp Mask...",
+ "label": 'Unsharp Mask...',
"visible": true
},
{
"id": 554,
"enabled": true,
- "label": "Sharpen...",
+ "label": 'Sharpen...',
"visible": true
},
{
"id": 555,
"enabled": true,
- "label": "Red Eye Removal...",
+ "label": 'Red Eye Removal...',
"visible": true
},
{
"id": 556,
"enabled": false,
- "label": "NL Filter...",
+ "label": 'NL Filter...',
"visible": true
},
{
"id": 557,
"enabled": true,
- "label": "Destripe...",
+ "label": 'Destripe...',
"visible": true
},
{
"id": 558,
"enabled": true,
- "label": "Despeckle...",
+ "label": 'Despeckle...',
"visible": true
},
{
"id": 559,
"enabled": true,
- "label": "Deinterlace...",
+ "label": 'Deinterlace...',
"visible": true
},
{
"id": 560,
"enabled": true,
- "label": "Antialias",
+ "label": 'Antialias',
"visible": true
}
]
},
{
"id": 561,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Blur",
+ "label": 'Blur',
"visible": true,
"submenu": [
{
"id": 562,
"enabled": true,
- "label": "Tileable Blur...",
+ "label": 'Tileable Blur...',
"visible": true
},
{
"id": 563,
"enabled": true,
- "label": "Selective Gaussian Blur...",
+ "label": 'Selective Gaussian Blur...',
"visible": true
},
{
"id": 564,
"enabled": true,
- "label": "Pixelize...",
+ "label": 'Pixelize...',
"visible": true
},
{
"id": 565,
"enabled": true,
- "label": "Motion Blur...",
+ "label": 'Motion Blur...',
"visible": true
},
{
"id": 566,
"enabled": true,
- "label": "Gaussian Blur...",
+ "label": 'Gaussian Blur...',
"visible": true
},
{
"id": 567,
"enabled": true,
- "label": "Blur",
+ "label": 'Blur',
"visible": true
}
]
},
{
"id": 568,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 569,
"enabled": true,
- "label": "Reset all Filters",
+ "label": 'Reset all Filters',
"visible": true
},
{
"id": 570,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": false,
- "label": "Re-Show Last",
- "shortcut": [["Control", "Shift", "f"]],
+ "label": 'Re-Show Last',
+ "shortcut": [['Control', 'Shift', 'f']],
"visible": true,
"submenu": [
{
"id": 571,
"enabled": false,
- "label": "Empty",
+ "label": 'Empty',
"visible": true
}
]
@@ -3670,210 +3670,210 @@
{
"id": 572,
"enabled": false,
- "label": "Repeat Last",
- "shortcut": [["Control", "f"]],
+ "label": 'Repeat Last',
+ "shortcut": [['Control', 'f']],
"visible": true
}
]
},
{
"id": 573,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Windows",
+ "label": 'Windows',
"visible": true,
"submenu": [
{
"id": 574,
"enabled": true,
- "label": "Toolbox",
- "shortcut": [["Control", "b"]],
+ "label": 'Toolbox',
+ "shortcut": [['Control', 'b']],
"visible": true
},
{
"id": 575,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 576,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Dockable Dialogs",
+ "label": 'Dockable Dialogs',
"visible": true,
"submenu": [
{
"id": 577,
"enabled": true,
- "label": "Error Console",
+ "label": 'Error Console',
"visible": true
},
{
"id": 578,
"enabled": true,
- "label": "Tools",
+ "label": 'Tools',
"visible": true
},
{
"id": 579,
"enabled": true,
- "label": "Templates",
+ "label": 'Templates',
"visible": true
},
{
"id": 580,
"enabled": true,
- "label": "Document History",
+ "label": 'Document History',
"visible": true
},
{
"id": 581,
"enabled": true,
- "label": "Images",
+ "label": 'Images',
"visible": true
},
{
"id": 582,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 583,
"enabled": true,
- "label": "Buffers",
+ "label": 'Buffers',
"visible": true
},
{
"id": 584,
"enabled": true,
- "label": "Fonts",
+ "label": 'Fonts',
"visible": true
},
{
"id": 585,
"enabled": true,
- "label": "Palettes",
+ "label": 'Palettes',
"visible": true
},
{
"id": 586,
"enabled": true,
- "label": "Gradients",
- "shortcut": [["Control", "g"]],
+ "label": 'Gradients',
+ "shortcut": [['Control', 'g']],
"visible": true
},
{
"id": 587,
"enabled": true,
- "label": "Patterns",
- "shortcut": [["Control", "Shift", "p"]],
+ "label": 'Patterns',
+ "shortcut": [['Control', 'Shift', 'p']],
"visible": true
},
{
"id": 588,
"enabled": true,
- "label": "Brushes",
- "shortcut": [["Control", "Shift", "b"]],
+ "label": 'Brushes',
+ "shortcut": [['Control', 'Shift', 'b']],
"visible": true
},
{
"id": 589,
"enabled": true,
- "label": "Colors",
+ "label": 'Colors',
"visible": true
},
{
"id": 590,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 591,
"enabled": true,
- "label": "Sample Points",
+ "label": 'Sample Points',
"visible": true
},
{
"id": 592,
"enabled": true,
- "label": "Pointer",
+ "label": 'Pointer',
"visible": true
},
{
"id": 593,
"enabled": true,
- "label": "Undo History",
+ "label": 'Undo History',
"visible": true
},
{
"id": 594,
"enabled": true,
- "label": "Navigation",
+ "label": 'Navigation',
"visible": true
},
{
"id": 595,
"enabled": true,
- "label": "Selection Editor",
+ "label": 'Selection Editor',
"visible": true
},
{
"id": 596,
"enabled": true,
- "label": "Histogram",
+ "label": 'Histogram',
"visible": true
},
{
"id": 597,
"enabled": true,
- "label": "Colormap",
+ "label": 'Colormap',
"visible": true
},
{
"id": 598,
"enabled": true,
- "label": "Paths",
+ "label": 'Paths',
"visible": true
},
{
"id": 599,
"enabled": true,
- "label": "Channels",
+ "label": 'Channels',
"visible": true
},
{
"id": 600,
"enabled": true,
- "label": "Layers",
- "shortcut": [["Control", "l"]],
+ "label": 'Layers',
+ "shortcut": [['Control', 'l']],
"visible": true
},
{
"id": 601,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 602,
"enabled": true,
- "label": "Device Status",
+ "label": 'Device Status',
"visible": true
},
{
"id": 603,
"enabled": true,
- "label": "Tool Options",
+ "label": 'Tool Options',
"visible": true
}
]
},
{
"id": 604,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Recently Closed Docks",
+ "label": 'Recently Closed Docks',
"visible": true,
"submenu": [
{
"id": 605,
"enabled": false,
- "label": "Empty",
+ "label": 'Empty',
"visible": true
}
]
@@ -3882,139 +3882,139 @@
},
{
"id": 606,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "Help",
+ "label": 'Help',
"visible": true,
"submenu": [
{
"id": 607,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "User Manual",
+ "label": 'User Manual',
"visible": true,
"submenu": [
{
"id": 608,
"enabled": true,
- "label": "Working with Digital Camera Photos",
+ "label": 'Working with Digital Camera Photos',
"visible": true
},
{
"id": 609,
"enabled": true,
- "label": "Using Paths",
+ "label": 'Using Paths',
"visible": true
},
{
"id": 610,
"enabled": true,
- "label": "Preparing your Images for the Web",
+ "label": 'Preparing your Images for the Web',
"visible": true
},
{
"id": 611,
"enabled": true,
- "label": "How to Use Dialogs",
+ "label": 'How to Use Dialogs',
"visible": true
},
{
"id": 612,
"enabled": true,
- "label": "Drawing Simple Objects",
+ "label": 'Drawing Simple Objects',
"visible": true
},
{
"id": 613,
"enabled": true,
- "label": "Create, Open and Save Files",
+ "label": 'Create, Open and Save Files',
"visible": true
},
{
"id": 614,
"enabled": true,
- "label": "Basic Concepts",
+ "label": 'Basic Concepts',
"visible": true
}
]
},
{
"id": 615,
- "children-display": "submenu",
+ "children-display": 'submenu',
"enabled": true,
- "label": "GIMP Online",
+ "label": 'GIMP Online',
"visible": true,
"submenu": [
{
"id": 616,
"enabled": true,
- "label": "User Manual Web Site",
+ "label": 'User Manual Web Site',
"visible": true
},
{
"id": 617,
"enabled": true,
- "label": "Plug-in Registry",
+ "label": 'Plug-in Registry',
"visible": true
},
{
"id": 618,
"enabled": true,
- "label": "Main Web Site",
+ "label": 'Main Web Site',
"visible": true
},
{
"id": 619,
"enabled": true,
- "label": "Developer Web Site",
+ "label": 'Developer Web Site',
"visible": true
}
]
},
{
"id": 620,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 621,
"enabled": true,
- "label": "Procedure Browser",
+ "label": 'Procedure Browser',
"visible": true
},
{
"id": 622,
"enabled": true,
- "label": "Plug-In Browser",
+ "label": 'Plug-In Browser',
"visible": true
},
{
"id": 623,
- "type": "separator"
+ "type": 'separator'
},
{
"id": 624,
"enabled": true,
- "label": "About",
+ "label": 'About',
"visible": true
},
{
"id": 625,
"enabled": true,
- "label": "Tip of the Day",
+ "label": 'Tip of the Day',
"visible": true
},
{
"id": 626,
"enabled": true,
- "label": "Context Help",
- "shortcut": [["Shift", "F1"]],
+ "label": 'Context Help',
+ "shortcut": [['Shift', 'F1']],
"visible": true
},
{
"id": 627,
"enabled": true,
- "label": "Help",
- "shortcut": [["F1"]],
+ "label": 'Help',
+ "shortcut": [['F1']],
"visible": true
}
]
diff --git a/tests/test-json-client.c b/tests/test-json-client.c
index f9da55e..d4e782b 100644
--- a/tests/test-json-client.c
+++ b/tests/test-json-client.c
@@ -21,38 +21,21 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <glib.h>
#include <gio/gio.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
-#include <dbus/dbus-glib-lowlevel.h>
GMainLoop * mainloop = NULL;
-int
-main (int argc, char ** argv)
+gboolean
+timeout_func (gpointer user_data)
{
- g_type_init();
- g_debug("Wait for friends");
-
- GError * error = NULL;
- DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (error != NULL) {
- g_error("Unable to get session bus: %s", error->message);
- return 1;
- }
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(session_bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
-
- gboolean has_owner = FALSE;
- gint owner_count = 0;
- while (!has_owner && owner_count < 10000) {
- org_freedesktop_DBus_name_has_owner(bus_proxy, "org.dbusmenu.test", &has_owner, NULL);
- owner_count++;
- }
+ g_warning("Timeout without getting name");
+ g_main_loop_quit(mainloop);
+ return FALSE;
+}
- if (owner_count == 10000) {
- g_error("Unable to get name owner after 10000 tries");
- return 1;
- }
+void
+name_appeared (GDBusConnection * connection, const gchar * name, const gchar * owner, gpointer user_data)
+{
+ char ** argv = (char **)user_data;
g_usleep(500000);
@@ -69,7 +52,28 @@ main (int argc, char ** argv)
g_file_replace_contents(ofile, output, g_utf8_strlen(output, -1), NULL, FALSE, 0, NULL, NULL, NULL);
}
- g_debug("Exiting");
+ g_main_loop_quit(mainloop);
+ return;
+}
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+ g_debug("Wait for friends");
+
+ g_bus_watch_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ name_appeared,
+ NULL,
+ argv,
+ NULL);
+
+ g_timeout_add_seconds(2, timeout_func, NULL);
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(mainloop);
return 0;
}
diff --git a/tests/test-json-server.c b/tests/test-json-server.c
index fe9507a..083de60 100644
--- a/tests/test-json-server.c
+++ b/tests/test-json-server.c
@@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
@@ -40,38 +36,49 @@ timer_func (gpointer data)
return FALSE;
}
-int
-main (int argc, char ** argv)
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
{
- GError * error = NULL;
-
- g_type_init();
-
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
-
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
+ gchar ** argv = (gchar **)user_data;
DbusmenuServer * server = dbusmenu_server_new("/org/test");
DbusmenuMenuitem * root = dbusmenu_json_build_from_file(argv[1]);
- g_return_val_if_fail(root!=NULL, 1);
+ if (root == NULL) {
+ g_warning("Unable to build root");
+ g_main_loop_quit(mainloop);
+ return;
+ }
dbusmenu_server_set_root(server, root);
g_timeout_add(10000, timer_func, NULL);
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ g_main_loop_quit(mainloop);
+ return;
+}
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ argv,
+ NULL);
+
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tools/dbusmenu-bench b/tools/dbusmenu-bench
index 4b58da8..dcf5f6f 100755
--- a/tools/dbusmenu-bench
+++ b/tools/dbusmenu-bench
@@ -35,7 +35,7 @@ from xml.etree import ElementTree as ET
import dbus
-DBUS_INTERFACE = "org.ayatana.dbusmenu"
+DBUS_INTERFACE = "com.canonical.dbusmenu"
DBUS_SERVICE = "org.dbusmenu.test"
DBUS_PATH = "/MenuBar"
diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c
index 3256f7e..bd986e8 100644
--- a/tools/dbusmenu-dumper.c
+++ b/tools/dbusmenu-dumper.c
@@ -21,7 +21,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
-#include <dbus/dbus-glib.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
@@ -30,111 +29,10 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libdbusmenu-glib/client.h>
#include <libdbusmenu-glib/menuitem.h>
-#include <dbus/dbus-gtype-specialized.h>
#include <X11/Xlib.h>
static GMainLoop * mainloop = NULL;
-static gchar * value2string (const GValue * value, int depth);
-
-static gchar *
-strv_dumper(const GValue * value)
-{
- gchar ** strv = (gchar **)g_value_get_boxed(value);
-
- gchar * joined = g_strjoinv("\", \"", strv);
- gchar * retval = g_strdup_printf("[\"%s\"]", joined);
- g_free(joined);
- return retval;
-}
-
-typedef struct _collection_iterator_t collection_iterator_t;
-struct _collection_iterator_t {
- gchar * space;
- GPtrArray * array;
- gboolean first;
- int depth;
-};
-
-static void
-collection_iterate (const GValue * value, gpointer user_data)
-{
- collection_iterator_t * iter = (collection_iterator_t *)user_data;
-
- gchar * str = value2string(value, iter->depth);
- gchar * retval = NULL;
-
- if (iter->first) {
- iter->first = FALSE;
- retval = g_strdup_printf("\n%s%s", iter->space, str);
- } else {
- retval = g_strdup_printf(",\n%s%s", iter->space, str);
- }
-
- g_ptr_array_add(iter->array, retval);
- g_free(str);
-
- return;
-}
-
-static gchar *
-collection_dumper (const GValue * value, int depth)
-{
- gchar * space = g_strnfill(depth, ' ');
- GPtrArray * array = g_ptr_array_new_with_free_func(g_free);
-
- g_ptr_array_add(array, g_strdup("["));
-
- collection_iterator_t iter;
- iter.space = space;
- iter.array = array;
- iter.first = TRUE;
- iter.depth = depth + 2;
-
- dbus_g_type_collection_value_iterate(value, collection_iterate, &iter);
-
- g_ptr_array_add(array, g_strdup_printf("\n%s]", space));
-
- g_free(space);
-
- gchar * retstr = NULL;
- if (array->len == 3) {
- retstr = g_strdup_printf("[%s]", ((gchar *)array->pdata[1]) + depth + 1/*for newline*/);
- } else {
- retstr = g_strjoinv(NULL, (gchar **)array->pdata);
- }
-
- g_ptr_array_free(array, TRUE);
-
- return retstr;
-}
-
-static gchar *
-value2string (const GValue * value, int depth)
-{
- gchar * str = NULL;
-
- if (value == NULL) {
- return g_strdup("(null)");
- }
-
- if (dbus_g_type_is_collection(G_VALUE_TYPE(value))) {
- str = collection_dumper(value, depth);
- } else if (G_VALUE_TYPE(value) == G_TYPE_STRV) {
- str = strv_dumper(value);
- } else if (G_VALUE_TYPE(value) == G_TYPE_BOOLEAN) {
- if (g_value_get_boolean(value)) {
- str = g_strdup("true");
- } else {
- str = g_strdup("false");
- }
- } else {
- str = g_strdup_value_contents(value);
- }
-
- return str;
-}
-
static gint
list_str_cmp (gconstpointer a, gconstpointer b)
{
@@ -151,10 +49,11 @@ print_menuitem (DbusmenuMenuitem * item, int depth)
GList * properties = g_list_sort(properties_raw, list_str_cmp);
GList * property;
for (property = properties; property != NULL; property = g_list_next(property)) {
- const GValue * value = dbusmenu_menuitem_property_get_value(item, (gchar *)property->data);
- gchar * str = value2string(value, depth + g_utf8_strlen((gchar *)property->data, -1) + 2 /*quotes*/ + 2 /*: */);
+ GVariant * variant = dbusmenu_menuitem_property_get_variant(item, (gchar *)property->data);
+ gchar * str = g_variant_print(variant, FALSE);
g_print(",\n%s\"%s\": %s", space, (gchar *)property->data, str);
g_free(str);
+ g_variant_unref(variant);
}
g_list_free(properties);
@@ -350,39 +249,46 @@ static gchar * dbusobject = NULL;
static gboolean
init_dbus_vars_from_window(Window window)
{
- DBusGConnection *connection;
GError *error;
- DBusGProxy *proxy;
+ GDBusProxy *proxy;
error = NULL;
- connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (connection == NULL) {
- g_printerr("Failed to open connection to bus: %s\n", error->message);
+
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "com.canonical.AppMenu.Registrar",
+ "/com/canonical/AppMenu/Registrar",
+ "com.canonical.AppMenu.Registrar",
+ NULL,
+ &error);
+ if (error != NULL) {
+ g_warning("Unable to get registrar proxy: %s", error->message);
g_error_free(error);
return FALSE;
}
- proxy = dbus_g_proxy_new_for_name (connection,
- "org.ayatana.AppMenu.Registrar",
- "/org/ayatana/AppMenu/Registrar",
- "org.ayatana.AppMenu.Registrar");
-
error = NULL;
- if (!dbus_g_proxy_call (proxy, "GetMenuForWindow", &error,
- G_TYPE_UINT, window, G_TYPE_INVALID,
- G_TYPE_STRING, &dbusname, DBUS_TYPE_G_OBJECT_PATH, &dbusobject, G_TYPE_INVALID))
- {
- g_printerr("ERROR: %s\n", error->message);
+ GVariant * retval;
+
+ retval = g_dbus_proxy_call_sync(proxy,
+ "GetMenuForWindow",
+ g_variant_new("u", window),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (error != NULL) {
+ g_warning("Unable to call 'GetMenuForWindow' on registrar: %s", error->message);
g_error_free(error);
- g_object_unref(proxy);
return FALSE;
}
- if (!g_strcmp0(dbusobject, "/")) {
- return FALSE;
- }
+ g_variant_get(retval, "so", &dbusname, &dbusobject);
- g_object_unref (proxy);
+ g_variant_unref(retval);
+ g_object_unref(proxy);
return TRUE;
}
diff --git a/tools/testapp/Makefile.am b/tools/testapp/Makefile.am
index a8b42dd..39de532 100644
--- a/tools/testapp/Makefile.am
+++ b/tools/testapp/Makefile.am
@@ -1,4 +1,10 @@
+if USE_GTK3
+VER=3
+else
+VER=
+endif
+
libexec_PROGRAMS = dbusmenu-testapp
dbusmenu_testapp_SOURCES = \
@@ -12,6 +18,6 @@ dbusmenu_testapp_CFLAGS = \
dbusmenu_testapp_LDADD = \
$(builddir)/../../libdbusmenu-glib/libdbusmenu-glib.la \
- $(builddir)/../../libdbusmenu-gtk/libdbusmenu-gtk.la \
+ $(builddir)/../../libdbusmenu-gtk/libdbusmenu-gtk$(VER).la \
$(DBUSMENUGTK_LIBS) \
$(DBUSMENUTESTS_LIBS)
diff --git a/tools/testapp/main.c b/tools/testapp/main.c
index f489407..67e962d 100644
--- a/tools/testapp/main.c
+++ b/tools/testapp/main.c
@@ -26,9 +26,7 @@ License version 3 and version 2.1 along with this program. If not, see
<http://www.gnu.org/licenses/>
*/
#include <glib.h>
-
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include <json-glib/json-glib.h>
@@ -117,6 +115,24 @@ void init_menu(DbusmenuMenuitem *root, const char *filename)
}
}
+static void
+on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ DbusmenuServer *server = dbusmenu_server_new("/MenuBar");
+ DbusmenuMenuitem *root = dbusmenu_menuitem_new_with_id(0);
+ init_menu(root, (gchar *)user_data);
+ dbusmenu_server_set_root(server, root);
+
+ return;
+}
+
+static void
+name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data)
+{
+ g_error("Unable to get name '%s' on DBus", name);
+ return;
+}
+
int main (int argc, char ** argv)
{
g_type_init();
@@ -127,25 +143,14 @@ int main (int argc, char ** argv)
}
const char *filename = argv[1];
- GError * error = NULL;
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
- guint nameret = 0;
-
- if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) {
- g_error("Unable to call to request name");
- return 1;
- }
-
- if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_error("Unable to get name");
- return 1;
- }
-
- DbusmenuServer *server = dbusmenu_server_new("/MenuBar");
- DbusmenuMenuitem *root = dbusmenu_menuitem_new_with_id(0);
- init_menu(root, filename);
- dbusmenu_server_set_root(server, root);
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ "org.dbusmenu.test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus,
+ NULL,
+ name_lost,
+ (gpointer)filename,
+ NULL);
g_main_loop_run(g_main_loop_new(NULL, FALSE));