aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore7
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac10
-rw-r--r--debian/changelog23
-rw-r--r--debian/control10
-rw-r--r--libdbusmenu-glib/Makefile.am1
-rw-r--r--libdbusmenu-glib/client.c87
-rw-r--r--libdbusmenu-glib/client.h2
-rw-r--r--libdbusmenu-glib/dbus-menu.xml126
-rw-r--r--libdbusmenu-glib/menuitem-marshal.list2
-rw-r--r--libdbusmenu-glib/menuitem-private.h40
-rw-r--r--libdbusmenu-glib/menuitem.c224
-rw-r--r--libdbusmenu-glib/menuitem.h19
-rw-r--r--libdbusmenu-glib/server-marshal.list3
-rw-r--r--libdbusmenu-glib/server.c173
-rw-r--r--libdbusmenu-glib/server.h6
-rw-r--r--libdbusmenu-gtk/Makefile.am2
-rw-r--r--libdbusmenu-gtk/client.c157
-rw-r--r--libdbusmenu-gtk/genericmenuitem.c444
-rw-r--r--libdbusmenu-gtk/genericmenuitem.h91
-rw-r--r--libdbusmenu-qt/Makefile.am29
-rw-r--r--libdbusmenu-qt/dbusmenu-qt.pc.in14
-rw-r--r--libdbusmenu-qt/test.c4
-rw-r--r--libdbusmenu-qt/test.h2
-rw-r--r--tests/Makefile.am115
-rw-r--r--tests/dbusmenu-gtk/Makefile.am43
-rwxr-xr-xtests/dbusmenu-gtk/dbusMenuTest2
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/blank_label.json (renamed from tests/dbusmenu-gtk/data/blank_label.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/blank_label_2levels.json (renamed from tests/dbusmenu-gtk/data/blank_label_2levels.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/blank_submenus.json (renamed from tests/dbusmenu-gtk/data/blank_submenus.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/dynamic.json (renamed from tests/dbusmenu-gtk/data/dynamic.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/long_label.json (renamed from tests/dbusmenu-gtk/data/long_label.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/no_id.json (renamed from tests/dbusmenu-gtk/data/no_id.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/no_label.json (renamed from tests/dbusmenu-gtk/data/no_label.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/sameid_submenus.json (renamed from tests/dbusmenu-gtk/data/sameid_submenus.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/sameid_submenus_diff_sizes.json (renamed from tests/dbusmenu-gtk/data/sameid_submenus_diff_sizes.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/sameid_top_and_submenus.json (renamed from tests/dbusmenu-gtk/data/sameid_top_and_submenus.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/sameid_topmenu.json (renamed from tests/dbusmenu-gtk/data/sameid_topmenu.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/several_submenus.json (renamed from tests/dbusmenu-gtk/data/several_submenus.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/several_submenus_recursive.json (renamed from tests/dbusmenu-gtk/data/several_submenus_recursive.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/several_submenus_utf8.json (renamed from tests/dbusmenu-gtk/data/several_submenus_utf8.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/static.json (renamed from tests/dbusmenu-gtk/data/static.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/data/test-gtk-label.json (renamed from tests/dbusmenu-gtk/data/test-gtk-label.json)0
-rw-r--r--tests/dbusmenu-gtk/mago_tests/dbusmenu.py (renamed from tests/dbusmenu-gtk/dbusmenu.py.in)4
-rw-r--r--tests/dbusmenu-gtk/mago_tests/dbusmenu.xml (renamed from tests/dbusmenu-gtk/dbusmenu.xml.in)20
-rw-r--r--tests/run-xvfb.sh7
-rw-r--r--tests/test-glib-layout-client.c6
-rw-r--r--tests/test-glib-layout-server.c17
-rw-r--r--tests/test-glib-objects.c278
-rw-r--r--tests/test-glib-properties-client.c2
-rw-r--r--tests/test-gtk-label-client.c7
-rw-r--r--tests/test-gtk-label.json77
-rw-r--r--tests/test-gtk-reorder-server.c2
-rw-r--r--tools/Makefile.am14
-rw-r--r--tools/dbusmenu-dumper.c175
55 files changed, 1908 insertions, 339 deletions
diff --git a/.bzrignore b/.bzrignore
index 724ade0..d506979 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -49,5 +49,12 @@ tests/test-gtk-label
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
+tests/test-mago
+tests/*.bustle
+libdbusmenu-gtk/libdbusmenu_gtk_la-genericmenuitem.lo
+tests/test-glib-objects
+tests/test-glib-objects-test
+tests/test-glib-objects.xml
diff --git a/Makefile.am b/Makefile.am
index 2e22cf9..747b90b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = libdbusmenu-glib libdbusmenu-gtk libdbusmenu-qt tests po
+SUBDIRS = libdbusmenu-glib libdbusmenu-gtk tools tests po
diff --git a/configure.ac b/configure.ac
index b53a8dc..29a628a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
-AC_INIT(libdbusmenu, 0.1.8, ted@canonical.com)
+AC_INIT(libdbusmenu, 0.2.0, ted@canonical.com)
AC_COPYRIGHT([Copyright 2009 Canonical])
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libdbusmenu, 0.1.8)
+AM_INIT_AUTOMAKE(libdbusmenu, 0.2.0)
AM_MAINTAINER_MODE
@@ -66,7 +66,7 @@ AC_SUBST(DBUSMENUTESTS_LIBS)
###########################
LIBDBUSMENU_CURRENT=0
-LIBDBUSMENU_REVISION=8
+LIBDBUSMENU_REVISION=10
LIBDBUSMENU_AGE=0
AC_SUBST(LIBDBUSMENU_CURRENT)
@@ -104,10 +104,8 @@ libdbusmenu-glib/Makefile
libdbusmenu-glib/dbusmenu-glib.pc
libdbusmenu-gtk/Makefile
libdbusmenu-gtk/dbusmenu-gtk.pc
-libdbusmenu-qt/Makefile
-libdbusmenu-qt/dbusmenu-qt.pc
+tools/Makefile
tests/Makefile
-tests/dbusmenu-gtk/Makefile
])
###########################
diff --git a/debian/changelog b/debian/changelog
index d692ece..51362d2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,26 @@
+libdbusmenu (0.2.0-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.2.0
+ - Remove unused libdbusmenu-qt
+ - Changing API to be V0.2 for reals
+ - Adding underline support
+ - Test suite fixes and automation support
+ - dbus-dumper tool
+ - Switch to org.ayatana
+ - Fixing the handling of typed properties, especially bools.
+ - Adding GetChildren function for getting a single submenu
+ - Starting to watch DBus if the proxy builds fail.
+ - Test suite fixes
+ - Fixing the consistency between the #defines and what
+ was used in the code.
+ * debian/control, debian/libdbusmenu-tools.install: Setting
+ up a package for the new dbusmenu-dumper tool.
+ * debian/control: Mentioning nicely that this will cause
+ indicator-messages << 0.3 and indicator-session << 0.2 to
+ break.
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 08 Jan 2010 08:42:59 -0600
+
libdbusmenu (0.1.8-0ubuntu1) lucid; urgency=low
* Upstream release 0.1.8
diff --git a/debian/control b/debian/control
index 69d6adf..c392b34 100644
--- a/debian/control
+++ b/debian/control
@@ -21,6 +21,8 @@ Section: libs
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends}
+Breaks: indicator-messages (<< 0.3.0),
+ indicator-session (<< 0.2.0)
Description: Menus over DBus shared library for glib
This package contains shared libraries to be used by applications.
@@ -58,3 +60,11 @@ Description: Menus over DBus shared library for GTK
This package contains files that are needed to build applications.
.
This package provides the development files.
+
+Package: libdbusmenu-tools
+Section: devel
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libdbusmenu-glib0 (= ${binary:Version})
+Description: Need a better description.
diff --git a/libdbusmenu-glib/Makefile.am b/libdbusmenu-glib/Makefile.am
index e74b9ab..fc37019 100644
--- a/libdbusmenu-glib/Makefile.am
+++ b/libdbusmenu-glib/Makefile.am
@@ -22,6 +22,7 @@ libdbusmenu_glib_la_SOURCES = \
menuitem.c \
menuitem-marshal.h \
menuitem-marshal.c \
+ menuitem-private.h \
server.h \
server.c \
server-marshal.h \
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index 61f1ccf..01dfed7 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -34,6 +34,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include <libxml/tree.h>
#include "client.h"
+#include "menuitem.h"
#include "dbusmenu-client.h"
#include "server-marshal.h"
@@ -94,14 +95,14 @@ 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, gint revision, DbusmenuClient * client);
-static void id_prop_update (DBusGProxy * proxy, guint id, gchar * property, gchar * value, DbusmenuClient * client);
+static void layout_update (DBusGProxy * proxy, gint revision, guint parent, DbusmenuClient * client);
+static void id_prop_update (DBusGProxy * proxy, guint id, gchar * property, GValue * value, DbusmenuClient * client);
static void id_update (DBusGProxy * proxy, guint id, DbusmenuClient * client);
static void build_proxies (DbusmenuClient * client);
static guint parse_node_get_id (xmlNodePtr node);
static DbusmenuMenuitem * parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, DBusGProxy * proxy);
static gint parse_layout (DbusmenuClient * client, const gchar * layout);
-static void update_layout_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data);
+static void update_layout_cb (DBusGProxy * proxy, guint rev, gchar * xml, GError * in_error, void * data);
static void update_layout (DbusmenuClient * client);
static void menuitem_get_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data);
@@ -215,7 +216,7 @@ dbusmenu_client_dispose (GObject *object)
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(object);
if (priv->layoutcall != NULL) {
- dbus_g_proxy_cancel_call(priv->propproxy, priv->layoutcall);
+ dbus_g_proxy_cancel_call(priv->menuproxy, priv->layoutcall);
priv->layoutcall = NULL;
}
if (priv->menuproxy != NULL) {
@@ -307,7 +308,7 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
/* Annoying little wrapper to make the right function update */
static void
-layout_update (DBusGProxy * proxy, gint revision, DbusmenuClient * client)
+layout_update (DBusGProxy * proxy, gint revision, guint parent, DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
priv->current_revision = revision;
@@ -320,10 +321,14 @@ layout_update (DBusGProxy * proxy, gint revision, DbusmenuClient * client)
/* Signal from the server that a property has changed
on one of our menuitems */
static void
-id_prop_update (DBusGProxy * proxy, guint id, gchar * property, gchar * value, DbusmenuClient * client)
+id_prop_update (DBusGProxy * proxy, guint id, gchar * property, GValue * value, DbusmenuClient * client)
{
#ifdef MASSIVEDEBUGGING
- g_debug("Property change sent to client for item %d property %s value %s", id, property, g_utf8_strlen(value, 50) < 25 ? value : "<too long>");
+ 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);
@@ -332,7 +337,7 @@ id_prop_update (DBusGProxy * proxy, guint id, gchar * property, gchar * value, D
DbusmenuMenuitem * menuitem = dbusmenu_menuitem_find_id(priv->root, id);
g_return_if_fail(menuitem != NULL);
- dbusmenu_menuitem_property_set(menuitem, property, value);
+ dbusmenu_menuitem_property_set_value(menuitem, property, value);
return;
}
@@ -351,7 +356,9 @@ id_update (DBusGProxy * proxy, guint id, DbusmenuClient * client)
DbusmenuMenuitem * menuitem = dbusmenu_menuitem_find_id(priv->root, id);
g_return_if_fail(menuitem != NULL);
- org_ayatana_dbusmenu_get_properties_async(proxy, id, menuitem_get_properties_cb, menuitem);
+ gchar * properties[1] = {NULL}; /* This gets them all */
+ g_debug("Getting properties");
+ org_ayatana_dbusmenu_get_properties_async(proxy, id, (const gchar **)properties, menuitem_get_properties_cb, menuitem);
return;
}
@@ -360,8 +367,9 @@ static void
dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+ /* g_debug("Owner change: %s %s %s", name, prev, new); */
- if (!(new != NULL && prev == NULL)) {
+ 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
@@ -369,7 +377,7 @@ dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, c
return;
}
- if (g_strcmp0(new, priv->dbus_name)) {
+ if (g_strcmp0(name, priv->dbus_name)) {
/* Again, someone else's service. */
return;
}
@@ -464,6 +472,7 @@ build_proxies (DbusmenuClient * client)
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;
}
g_object_add_weak_pointer(G_OBJECT(priv->propproxy), (gpointer *)&priv->propproxy);
@@ -477,6 +486,7 @@ build_proxies (DbusmenuClient * client)
if (error != NULL) {
g_warning("Unable to get dbusmenu proxy for %s on %s: %s", priv->dbus_name, priv->dbus_object, error->message);
g_error_free(error);
+ build_dbus_proxy(client);
return;
}
g_object_add_weak_pointer(G_OBJECT(priv->menuproxy), (gpointer *)&priv->menuproxy);
@@ -488,15 +498,16 @@ build_proxies (DbusmenuClient * client)
priv->dbusproxy = NULL;
}
- dbus_g_proxy_add_signal(priv->menuproxy, "LayoutUpdate", G_TYPE_INT, G_TYPE_INVALID);
+ 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, "LayoutUpdate", G_TYPE_INT, G_TYPE_UINT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(priv->menuproxy, "LayoutUpdate", G_CALLBACK(layout_update), client, NULL);
- dbus_g_object_register_marshaller(_dbusmenu_server_marshal_VOID__UINT_STRING_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
- dbus_g_proxy_add_signal(priv->menuproxy, "IdPropUpdate", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "IdPropUpdate", G_CALLBACK(id_prop_update), client, NULL);
+ dbus_g_object_register_marshaller(_dbusmenu_server_marshal_VOID__UINT_STRING_POINTER, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(priv->menuproxy, "ItemPropertyUpdated", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->menuproxy, "ItemPropertyUpdated", G_CALLBACK(id_prop_update), client, NULL);
- dbus_g_proxy_add_signal(priv->menuproxy, "IdUpdate", G_TYPE_UINT, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->menuproxy, "IdUpdate", G_CALLBACK(id_update), client, NULL);
+ dbus_g_proxy_add_signal(priv->menuproxy, "ItemUpdated", G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->menuproxy, "ItemUpdated", G_CALLBACK(id_update), client, NULL);
update_layout(client);
@@ -564,7 +575,7 @@ parse_node_get_id (xmlNodePtr node)
static void
get_properties_helper (gpointer key, gpointer value, gpointer data)
{
- dbusmenu_menuitem_property_set((DbusmenuMenuitem *)data, (gchar *)key, (gchar *)value);
+ dbusmenu_menuitem_property_set_value((DbusmenuMenuitem *)data, (gchar *)key, (GValue *)value);
return;
}
@@ -606,7 +617,7 @@ menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GEr
const gchar * type;
DbusmenuClientTypeHandler newfunc = NULL;
- type = dbusmenu_menuitem_property_get(propdata->item, "type");
+ type = dbusmenu_menuitem_property_get(propdata->item, DBUSMENU_MENUITEM_PROP_TYPE);
if (type != NULL) {
newfunc = g_hash_table_lookup(priv->type_handlers, type);
} else {
@@ -647,7 +658,10 @@ static void
menuitem_activate (DbusmenuMenuitem * mi, DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- org_ayatana_dbusmenu_call_async (priv->menuproxy, dbusmenu_menuitem_get_id(mi), menuitem_call_cb, mi);
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_INT);
+ g_value_set_int(&value, 0);
+ org_ayatana_dbusmenu_event_async (priv->menuproxy, dbusmenu_menuitem_get_id(mi), "clicked", &value, menuitem_call_cb, mi);
return;
}
@@ -689,7 +703,8 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
propdata->item = item;
propdata->parent = parent;
- org_ayatana_dbusmenu_get_properties_async(proxy, id, menuitem_get_properties_new_cb, propdata);
+ gchar * properties[1] = {NULL}; /* This gets them all */
+ org_ayatana_dbusmenu_get_properties_async(proxy, id, (const gchar **)properties, menuitem_get_properties_new_cb, propdata);
} else {
g_warning("Unable to allocate memory to get properties for menuitem. This menuitem will never be realized.");
}
@@ -771,32 +786,24 @@ 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, DBusGProxyCall * call, void * data)
+update_layout_cb (DBusGProxy * proxy, guint rev, gchar * xml, GError * error, void * data)
{
DbusmenuClient * client = DBUSMENU_CLIENT(data);
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- GError * error = NULL;
- GValue value = {0};
-
- priv->layoutcall = NULL;
- if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+ if (error != NULL) {
g_warning("Getting layout failed on client %s object %s: %s", priv->dbus_name, priv->dbus_object, error->message);
- g_error_free(error);
return;
}
- const gchar * xml = g_value_get_string(&value);
- /* g_debug("Got layout string: %s", xml); */
- gint rev = parse_layout(client, xml);
-
- if (rev == 0) {
+ if (!parse_layout(client, xml)) {
g_warning("Unable to parse layout!");
return;
}
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
@@ -816,7 +823,7 @@ update_layout (DbusmenuClient * client)
{
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
- if (priv->propproxy == NULL) {
+ if (priv->menuproxy == NULL) {
return;
}
@@ -824,14 +831,10 @@ update_layout (DbusmenuClient * client)
return;
}
- priv->layoutcall = dbus_g_proxy_begin_call (priv->propproxy,
- "Get",
- update_layout_cb,
- client,
- NULL,
- G_TYPE_STRING, "org.ayatana.dbusmenu",
- G_TYPE_STRING, "layout",
- G_TYPE_INVALID, G_TYPE_VALUE, G_TYPE_INVALID);
+ priv->layoutcall = org_ayatana_dbusmenu_get_layout_async(priv->menuproxy,
+ 0, /* Parent is the root */
+ update_layout_cb,
+ client);
return;
}
diff --git a/libdbusmenu-glib/client.h b/libdbusmenu-glib/client.h
index fff9a6b..b42bc83 100644
--- a/libdbusmenu-glib/client.h
+++ b/libdbusmenu-glib/client.h
@@ -52,7 +52,7 @@ G_BEGIN_DECLS
#define DBUSMENU_CLIENT_TYPES_DEFAULT "menuitem"
#define DBUSMENU_CLIENT_TYPES_SEPARATOR "separator"
-#define DBUSMENU_CLIENT_TYPES_IMAGE "imageitem"
+#define DBUSMENU_CLIENT_TYPES_IMAGE "menuitem"
/**
DbusmenuClientClass:
diff --git a/libdbusmenu-glib/dbus-menu.xml b/libdbusmenu-glib/dbus-menu.xml
index 345c736..d2df400 100644
--- a/libdbusmenu-glib/dbus-menu.xml
+++ b/libdbusmenu-glib/dbus-menu.xml
@@ -32,8 +32,22 @@ License version 3 and version 2.1 along with this program. If not, see
<!-- Properties -->
<!--
+Provides the version of the DBusmenu API that this API is
+implementing.
+-->
+ <property name="version" type="u" access="read"/>
+
+<!-- Functions -->
+
+<!--
Provides an XML representation of the menu hierarchy
+@param parentId The ID of the parent node for the layout. For
+ grabbing the layout from the root node use zero.
+@param revision The revision number of the layout. For matching
+ with layoutUpdated signals.
+@param layout The layout as an XML string of IDs.
+
XML syntax:
<menu id="1" revision="2"> # Root container
@@ -48,73 +62,129 @@ XML syntax:
...
</menu>
-->
- <property name="layout" type="s" access="read"/>
-
-<!-- Functions -->
+ <method name="GetLayout">
+ <arg type="u" name="parentId" direction="in" />
+ <arg type="u" name="revision" direction="out" />
+ <arg type="s" name="layout" direction="out" />
+ </method>
<!--
-Each menu item has a set of properties. Property keys are in menuitem.h:
+Returns the list of items which are children of @a parentId.
+
+@param Ids A list of ids that we should be finding the properties
+ on. If the list is empty, all menu items should be sent.
+@param propertyNames list of string the list of item properties we
+ are interested in. If there are no entries in the list all of
+ the properties will be sent.
+
+An item is represented as a struct following this format:
+@li id unsigned the item id
+@li properties map(string => variant) the requested item properties
-- visible
-- sensitive
-- label
-- icon
-- icon-data
-- type
+-->
+ <method name="GetGroupProperties">
+ <arg type="au" name="Ids" direction="in" />
+ <arg type="as" name="propertyNames" direction="in" />
+ <arg type="a(ua{sv})" name="properties" direction="out" />
+ </method>
+
+ <method name="GetChildren">
+ <arg type="u" name="id" direction="in" />
+ <arg type="as" name="propertyNames" direction="in" />
+ <arg type="a(ua{sv})" name="properties" direction="out" />
+ </method>
-"type" property is an enum which can take the following values (client.h):
+<!--
+Each menu item has a set of properties. Property keys are in menuitem.h:
-- menuitem
-- separator
-- imageitem
+@li type string Type of the item (see below)
+@li label string Text of the item
+@li icon-data binary Raw data of the icon (TODO: define format)
+@li icon string Icon name of the item, following icon spec
+@li sensitive boolean Whether the item can be activated or not
+@li visible boolean Whether the item is visible or not (XXX: Is this necessary?)
+@li checked boolean Whether a checkbox or radio item is checked
+@li shortcut string The keyboard shortcut
+
+@c type property is an enum which can take the following values (client.h):
+
+@li action An item which can be clicked to trigger an action
+@li checkbox An item which can be checked or unchecked
+@li radio An item which can be checked or unchecked as part of a group
+@li separator A separator
+@li menu An item which contains more items
-->
<method name="GetProperty">
<arg type="u" name="id" direction="in" />
- <arg type="s" name="property" direction="in" />
- <arg type="s" name="value" direction="out" />
+ <arg type="s" name="name" direction="in" />
+ <arg type="v" name="value" direction="out" />
</method>
<!--
-Convenience method to retrieve all properties in one call (more efficient)
+Returns multiple properties in one call. This is more efficient than
+GetProperty.
+
+@param id unsigned the item whose properties we want to retrieve.
+@param propertyNames list of string name of the properties we want. If the list contains no entries, all properties are sent.
-->
<method name="GetProperties">
+ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg type="u" name="id" direction="in" />
- <arg type="a{ss}" name="properties" direction="out" />
+ <arg type="as" name="propertyNames" direction="in" />
+ <arg type="a{sv}" name="properties" direction="out" />
</method>
<!--
-This is called by the display to notify the application it should trigger
-the action associated with a specific menu id
+This is called by the applet to notify the application an event happened on a
+menu item.
+
+@param id the id of the item which received the event
+@param type the type of event
+@param data event-specific data
+
+@a type can be one of the following:
+
+@li "clicked"
+@li "hovered"
+
+Vendor specific events can be added by prefixing them with "x-<vendor>-"
-->
- <method name="Call">
+ <method name="Event">
<arg type="u" name="id" direction="in" />
+ <arg type="s" name="eventId" direction="in" />
+ <arg type="v" name="data" direction="in" />
</method>
<!-- Signals -->
<!--
-Triggered by the application to notify display that the property prop from menu id
-as changed to value.
+Triggered by the application to notify the applet that the property @a property
+from item @a id has changed to @a value.
-->
- <signal name="IdPropUpdate">
+ <signal name="ItemPropertyUpdated">
<arg type="u" name="id" direction="out" />
<arg type="s" name="prop" direction="out" />
- <arg type="s" name="value" direction="out" />
+ <arg type="v" name="value" direction="out" />
</signal>
<!--
-Triggered by the application to notify display that all properties of menu id
-should be considered outdated
+Triggered by the application to notify the applet that all properties of item
+@a id should be considered outdated
-->
- <signal name="IdUpdate">
+ <signal name="ItemUpdated">
<arg type="u" name="id" direction="out" />
</signal>
<!--
Triggered by the application to notify display of a layout update, up to
revision
+@param revsion The revision of the layout that we're currently on
+@param parent If the layout update is only of a subtree, this is the parent
+ item for the entries that have changed. It is zero if the
+ whole layout should be considered invalid.
-->
<signal name="LayoutUpdate">
<arg type="i" name="revision" direction="out" />
+ <arg type="u" name="parent" direction="out" />
</signal>
<!-- End of interesting stuff -->
diff --git a/libdbusmenu-glib/menuitem-marshal.list b/libdbusmenu-glib/menuitem-marshal.list
index a32e7e3..dc4ba53 100644
--- a/libdbusmenu-glib/menuitem-marshal.list
+++ b/libdbusmenu-glib/menuitem-marshal.list
@@ -1,4 +1,4 @@
-VOID: STRING, STRING
+VOID: STRING, POINTER
VOID: OBJECT, UINT, UINT
VOID: OBJECT, UINT
VOID: OBJECT
diff --git a/libdbusmenu-glib/menuitem-private.h b/libdbusmenu-glib/menuitem-private.h
new file mode 100644
index 0000000..0120435
--- /dev/null
+++ b/libdbusmenu-glib/menuitem-private.h
@@ -0,0 +1,40 @@
+/*
+A library to communicate a menu object set accross DBus and
+track updates and maintain consistency.
+
+Copyright 2009 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_MENUITEM_PRIVATE_H__
+#define __DBUSMENU_MENUITEM_PRIVATE_H__
+
+#include "menuitem.h"
+
+G_BEGIN_DECLS
+
+void dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array, gint revision);
+
+G_END_DECLS
+
+#endif
diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c
index fdf5608..a03117c 100644
--- a/libdbusmenu-glib/menuitem.c
+++ b/libdbusmenu-glib/menuitem.c
@@ -26,11 +26,13 @@ License version 3 and version 2.1 along with this program. If not, see
<http://www.gnu.org/licenses/>
*/
+#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "menuitem.h"
#include "menuitem-marshal.h"
+#include "menuitem-private.h"
#ifdef MASSIVEDEBUGGING
#define LABEL(x) dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(x), DBUSMENU_MENUITEM_PROP_LABEL)
@@ -88,6 +90,8 @@ static void dbusmenu_menuitem_dispose (GObject *object);
static void dbusmenu_menuitem_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 g_value_transform_STRING_BOOLEAN (const GValue * in, GValue * out);
+static void g_value_transform_STRING_INT (const GValue * in, GValue * out);
/* GObject stuff */
G_DEFINE_TYPE (DbusmenuMenuitem, dbusmenu_menuitem, G_TYPE_OBJECT);
@@ -118,8 +122,8 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuMenuitemClass, property_changed),
NULL, NULL,
- _dbusmenu_menuitem_marshal_VOID__STRING_STRING,
- G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+ _dbusmenu_menuitem_marshal_VOID__STRING_POINTER,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
/**
DbusmenuMenuitem::item-activated:
@arg0: The #DbusmenuMenuitem object.
@@ -207,11 +211,56 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass)
0, 30000, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ /* Check transfer functions for GValue */
+ if (!g_value_type_transformable(G_TYPE_STRING, G_TYPE_BOOLEAN)) {
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_BOOLEAN, g_value_transform_STRING_BOOLEAN);
+ }
+ if (!g_value_type_transformable(G_TYPE_STRING, G_TYPE_INT)) {
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_INT, g_value_transform_STRING_INT);
+ }
+
+ return;
+}
+
+/* A little helper function to translate a string into
+ a boolean value */
+static void
+g_value_transform_STRING_BOOLEAN (const GValue * in, GValue * out)
+{
+ const gchar * string = g_value_get_string(in);
+ if (!g_strcmp0(string, "TRUE") || !g_strcmp0(string, "true") || !g_strcmp0(string, "True")) {
+ g_value_set_boolean(out, TRUE);
+ } else {
+ g_value_set_boolean(out, FALSE);
+ }
+ return;
+}
+
+/* A little helper function to translate a string into
+ a integer value */
+static void
+g_value_transform_STRING_INT (const GValue * in, GValue * out)
+{
+ g_value_set_int(out, atoi(g_value_get_string(in)));
return;
}
static guint menuitem_next_id = 1;
+/* A small little function to both clear the insides of a
+ value as well as the memory it itself uses. */
+static void
+_g_value_free (gpointer data)
+{
+ if (data == NULL) return;
+ GValue * value = (GValue*)data;
+ g_value_unset(value);
+ g_free(data);
+ return;
+}
+
+/* Initialize the values of the in the object, and build the
+ properties hash table. */
static void
dbusmenu_menuitem_init (DbusmenuMenuitem *self)
{
@@ -220,7 +269,7 @@ dbusmenu_menuitem_init (DbusmenuMenuitem *self)
priv->id = 0;
priv->children = NULL;
- priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _g_value_free);
priv->root = FALSE;
@@ -673,27 +722,107 @@ dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, guint 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);
+}
+
+/**
+ dbusmenu_menuitem_property_set_bool:
+ @mi: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @value: The value of the property.
+
+ Takes a boolean @value and sets it on @property as a
+ property on @mi. If a property already exists by that name,
+ then the value is set to the new value. If not, the property
+ is added. If the value is changed or the property was previously
+ unset then the signal #DbusmenuMenuitem::prop-changed will be
+ emitted by this function.
+
+ Return value: A boolean representing if the property value was set.
+*/
+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);
+}
+
+/**
+ dbusmenu_menuitem_property_set_int:
+ @mi: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @value: The value of the property.
+
+ Takes a boolean @value and sets it on @property as a
+ property on @mi. If a property already exists by that name,
+ then the value is set to the new value. If not, the property
+ is added. If the value is changed or the property was previously
+ unset then the signal #DbusmenuMenuitem::prop-changed will be
+ emitted by this function.
+
+ Return value: A boolean representing if the property value was set.
+*/
+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);
+}
+
+/**
+ dbusmenu_menuitem_property_set:
+ @mi: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @value: The value of the property.
+
+ Takes the pair of @property and @value and places them as a
+ property on @mi. If a property already exists by that name,
+ then the value is set to the new value. If not, the property
+ is added. If the value is changed or the property was previously
+ unset then the signal #DbusmenuMenuitem::prop-changed will be
+ emitted by this function.
+
+ 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)
+{
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
gchar * lprop = g_strdup(property);
- gchar * lval = g_strdup(value);
+ GValue * lval = g_new0(GValue, 1);
+ g_value_init(lval, G_VALUE_TYPE(value));
+ g_value_copy(value, lval);
- g_hash_table_insert(priv->properties, lprop, lval);
+ g_hash_table_replace(priv->properties, lprop, lval);
#ifdef MASSIVEDEBUGGING
- g_debug("Menuitem %d (%s) signalling property '%s' changed to '%s'", ID(mi), LABEL(mi), property, g_utf8_strlen(value, 50) < 25 ? value : "<too long>");
+ 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
- g_signal_emit(G_OBJECT(mi), signals[PROPERTY_CHANGED], 0, property, value, TRUE);
+
+ g_signal_emit(G_OBJECT(mi), signals[PROPERTY_CHANGED], 0, lprop, lval, TRUE);
return TRUE;
}
@@ -709,19 +838,96 @@ dbusmenu_menuitem_property_set (DbusmenuMenuitem * mi, const gchar * property, c
Return value: A string with the value of the property
that shouldn't be free'd. Or #NULL if the property
- is not set.
+ is not set or is not a string.
*/
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);
+}
+
+/**
+ dbusmenu_menuitem_property_get_value:
+ @mi: The #DbusmenuMenuitem to look for the property on.
+ @property: The property to grab.
+
+ Look up a property on @mi and return the value of it if
+ it exits. #NULL will be returned if the property doesn't
+ exist.
+
+ Return value: A GValue for the property.
+*/
+const GValue *
+dbusmenu_menuitem_property_get_value (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 gchar *)g_hash_table_lookup(priv->properties, property);
+ return (const GValue *)g_hash_table_lookup(priv->properties, property);
+}
+
+/**
+ dbusmenu_menuitem_property_get_bool:
+ @mi: The #DbusmenuMenuitem to look for the property on.
+ @property: The property to grab.
+
+ Look up a property on @mi and return the value of it if
+ it exits. Returns #FALSE if the property doesn't exist.
+
+ Return value: The value of the property or #FALSE.
+*/
+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);
+ } else {
+ return FALSE;
+ }
+ }
+ return g_value_get_boolean(value);
+}
+
+/**
+ dbusmenu_menuitem_property_get_int:
+ @mi: The #DbusmenuMenuitem to look for the property on.
+ @property: The property to grab.
+
+ Look up a property on @mi and return the value of it if
+ it exits. Returns zero if the property doesn't exist.
+
+ Return value: The value of the property or zero.
+*/
+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;
+ }
+ }
+ return g_value_get_int(value);
}
+
/**
dbusmenu_menuitem_property_exit:
@mi: The #DbusmenuMenuitem to look for the property on.
diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h
index 6c3c265..aaafe17 100644
--- a/libdbusmenu-glib/menuitem.h
+++ b/libdbusmenu-glib/menuitem.h
@@ -50,11 +50,21 @@ 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_PROP_TYPE "type"
#define DBUSMENU_MENUITEM_PROP_VISIBLE "visible"
#define DBUSMENU_MENUITEM_PROP_SENSITIVE "sensitive"
#define DBUSMENU_MENUITEM_PROP_LABEL "label"
#define DBUSMENU_MENUITEM_PROP_ICON "icon"
#define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
+#define DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE "toggle-type"
+#define DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED "toggle-checked"
+
+#define DBUSMENU_MENUITEM_TOGGLE_CHECK "checkmark"
+#define DBUSMENU_MENUITEM_TOGGLE_RADIO "radio"
+
+#define DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED "unchecked"
+#define DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED "checked"
+#define DBUSMENU_MENUITEM_TOGGLE_STATE_UNKNOWN "indeterminate"
/**
DbusmenuMenuitem:
@@ -93,7 +103,7 @@ struct _DbusmenuMenuitemClass
GObjectClass parent_class;
/* Signals */
- void (*property_changed) (gchar * property, gchar * value);
+ void (*property_changed) (gchar * property, GValue * value);
void (*item_activated) (void);
void (*child_added) (DbusmenuMenuitem * child, guint position);
void (*child_removed) (DbusmenuMenuitem * child);
@@ -128,7 +138,13 @@ DbusmenuMenuitem * dbusmenu_menuitem_child_find (DbusmenuMenuitem * mi, guint id
DbusmenuMenuitem * dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, guint 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_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);
+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);
GList * dbusmenu_menuitem_properties_list (DbusmenuMenuitem * mi) G_GNUC_WARN_UNUSED_RESULT;
GHashTable * dbusmenu_menuitem_properties_copy (DbusmenuMenuitem * mi);
@@ -136,7 +152,6 @@ GHashTable * dbusmenu_menuitem_properties_copy (DbusmenuMenuitem * mi);
void dbusmenu_menuitem_set_root (DbusmenuMenuitem * mi, gboolean root);
gboolean dbusmenu_menuitem_get_root (DbusmenuMenuitem * mi);
-void dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array, gint revision);
void dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem * mi, gpointer data), gpointer data);
void dbusmenu_menuitem_activate (DbusmenuMenuitem * mi);
diff --git a/libdbusmenu-glib/server-marshal.list b/libdbusmenu-glib/server-marshal.list
index 950fc9d..044c64d 100644
--- a/libdbusmenu-glib/server-marshal.list
+++ b/libdbusmenu-glib/server-marshal.list
@@ -1 +1,2 @@
-VOID: UINT, STRING, STRING
+VOID: UINT, STRING, POINTER
+VOID: INT, UINT
diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c
index 84bfffe..0971162 100644
--- a/libdbusmenu-glib/server.c
+++ b/libdbusmenu-glib/server.c
@@ -30,16 +30,22 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
+#include "menuitem-private.h"
#include "server.h"
#include "server-marshal.h"
/* DBus Prototypes */
+static gboolean _dbusmenu_server_get_layout (DbusmenuServer * server, guint parent, guint * revision, gchar ** layout, GError ** error);
static gboolean _dbusmenu_server_get_property (DbusmenuServer * server, guint id, gchar * property, gchar ** value, GError ** error);
-static gboolean _dbusmenu_server_get_properties (DbusmenuServer * server, guint id, GHashTable ** dict, GError ** error);
-static gboolean _dbusmenu_server_call (DbusmenuServer * server, guint id, GError ** error);
+static gboolean _dbusmenu_server_get_properties (DbusmenuServer * server, guint id, GPtrArray * properties, GHashTable ** dict, GError ** error);
+static gboolean _dbusmenu_server_get_group_properties (DbusmenuServer * server, GArray * ids, GArray * properties, GHashTable ** values, GError ** error);
+static gboolean _dbusmenu_server_event (DbusmenuServer * server, guint id, gchar * eventid, GValue * data, GError ** error);
+static gboolean _dbusmenu_server_get_children (DbusmenuServer * server, guint id, GPtrArray * properties, GPtrArray ** output, GError ** error);
#include "dbusmenu-server.h"
+#define DBUSMENU_VERSION_NUMBER 1
+
/* Privates, I'll show you mine... */
typedef struct _DbusmenuServerPrivate DbusmenuServerPrivate;
@@ -68,7 +74,7 @@ enum {
PROP_0,
PROP_DBUS_OBJECT,
PROP_ROOT_NODE,
- PROP_LAYOUT
+ PROP_VERSION
};
/* Errors */
@@ -76,6 +82,7 @@ enum {
INVALID_MENUITEM_ID,
INVALID_PROPERTY_NAME,
UNKNOWN_DBUS_ERROR,
+ NOT_IMPLEMENTED,
LAST_ERROR
};
@@ -86,7 +93,7 @@ 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, gchar * value, DbusmenuServer * server);
+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);
@@ -122,8 +129,8 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuServerClass, id_prop_update),
NULL, NULL,
- _dbusmenu_server_marshal_VOID__UINT_STRING_STRING,
- G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
+ _dbusmenu_server_marshal_VOID__UINT_STRING_POINTER,
+ G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_VALUE);
/**
DbusmenuServer::id-update:
@arg0: The #DbusmenuServer emitting the signal.
@@ -145,6 +152,7 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
@arg0: The #DbusmenuServer emitting the signal.
@arg1: A revision number representing which revision the update
represents itself as.
+ @arg2: The ID of the parent for this update.
This signal is emitted any time the layout of the
menuitems under this server is changed.
@@ -154,8 +162,8 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuServerClass, layout_update),
NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
+ _dbusmenu_server_marshal_VOID__INT_UINT,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
g_object_class_install_property (object_class, PROP_DBUS_OBJECT,
@@ -168,10 +176,10 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
"The base object of the menus that are served",
DBUSMENU_TYPE_MENUITEM,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (object_class, PROP_LAYOUT,
- g_param_spec_string(DBUSMENU_SERVER_PROP_LAYOUT, "XML Layout of the menus",
- "A simple XML string that describes the layout of the menus",
- "<menu />",
+ g_object_class_install_property (object_class, PROP_VERSION,
+ g_param_spec_uint(DBUSMENU_SERVER_PROP_VERSION, "Dbusmenu API version",
+ "The version of the DBusmenu API that we're implementing.",
+ 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);
@@ -240,11 +248,8 @@ set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
g_debug("Setting root node to NULL");
}
priv->layout_revision++;
- g_signal_emit(obj, signals[LAYOUT_UPDATE], 0, priv->layout_revision, TRUE);
+ g_signal_emit(obj, signals[LAYOUT_UPDATE], 0, priv->layout_revision, 0, TRUE);
break;
- case PROP_LAYOUT:
- /* Can't set this, fall through to error */
- g_warning("Can not set property: layout");
default:
g_return_if_reached();
break;
@@ -276,25 +281,9 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
case PROP_ROOT_NODE:
g_value_set_object(value, priv->root);
break;
- case PROP_LAYOUT: {
- GPtrArray * xmlarray = g_ptr_array_new();
- if (priv->root == NULL) {
- /* g_debug("Getting layout without root node!"); */
- g_ptr_array_add(xmlarray, g_strdup_printf("<menu revision=\"%d\" />", priv->layout_revision));
- } else {
- dbusmenu_menuitem_buildxml(priv->root, xmlarray, priv->layout_revision);
- }
- g_ptr_array_add(xmlarray, NULL);
-
- /* build string */
- gchar * finalstring = g_strjoinv("", (gchar **)xmlarray->pdata);
- g_value_take_string(value, finalstring);
- /* g_debug("Final string: %s", finalstring); */
-
- g_ptr_array_foreach(xmlarray, xmlarray_foreach_free, NULL);
- g_ptr_array_free(xmlarray, TRUE);
+ case PROP_VERSION:
+ g_value_set_uint(value, DBUSMENU_VERSION_NUMBER);
break;
- }
default:
g_return_if_reached();
break;
@@ -304,7 +293,7 @@ get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
}
static void
-menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, gchar * value, DbusmenuServer * server)
+menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, GValue * value, DbusmenuServer * server)
{
g_signal_emit(G_OBJECT(server), signals[ID_PROP_UPDATE], 0, dbusmenu_menuitem_get_id(mi), property, value, TRUE);
return;
@@ -317,7 +306,7 @@ menuitem_child_added (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, guint
/* TODO: We probably need to group the layout update signals to make the number more reasonble. */
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
priv->layout_revision++;
- g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, TRUE);
+ g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, 0, TRUE);
return;
}
@@ -328,7 +317,7 @@ menuitem_child_removed (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, Dbu
/* TODO: We probably need to group the layout update signals to make the number more reasonble. */
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
priv->layout_revision++;
- g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, TRUE);
+ g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, 0, TRUE);
return;
}
@@ -337,7 +326,7 @@ menuitem_child_moved (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, guint
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
priv->layout_revision++;
- g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, TRUE);
+ g_signal_emit(G_OBJECT(server), signals[LAYOUT_UPDATE], 0, priv->layout_revision, 0, TRUE);
return;
}
@@ -376,6 +365,36 @@ error_quark (void)
}
/* DBus interface */
+static gboolean
+_dbusmenu_server_get_layout (DbusmenuServer * server, guint parent, guint * revision, gchar ** layout, GError ** error)
+{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+
+ *revision = priv->layout_revision;
+ GPtrArray * xmlarray = g_ptr_array_new();
+
+ if (parent == 0) {
+ if (priv->root == NULL) {
+ /* g_debug("Getting layout without root node!"); */
+ g_ptr_array_add(xmlarray, g_strdup_printf("<menu revision=\"%d\" />", priv->layout_revision));
+ } else {
+ dbusmenu_menuitem_buildxml(priv->root, xmlarray, priv->layout_revision);
+ }
+ } else {
+ DbusmenuMenuitem * item = dbusmenu_menuitem_find_id(priv->root, parent);
+ dbusmenu_menuitem_buildxml(item, xmlarray, priv->layout_revision);
+ }
+ g_ptr_array_add(xmlarray, NULL);
+
+ /* build string */
+ *layout = g_strjoinv("", (gchar **)xmlarray->pdata);
+
+ g_ptr_array_foreach(xmlarray, xmlarray_foreach_free, NULL);
+ g_ptr_array_free(xmlarray, TRUE);
+
+ return TRUE;
+}
+
static gboolean
_dbusmenu_server_get_property (DbusmenuServer * server, guint id, gchar * property, gchar ** value, GError ** error)
{
@@ -422,7 +441,7 @@ _dbusmenu_server_get_property (DbusmenuServer * server, guint id, gchar * proper
}
static gboolean
-_dbusmenu_server_get_properties (DbusmenuServer * server, guint id, GHashTable ** dict, GError ** error)
+_dbusmenu_server_get_properties (DbusmenuServer * server, guint id, GPtrArray * properties, GHashTable ** dict, GError ** error)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
@@ -444,7 +463,81 @@ _dbusmenu_server_get_properties (DbusmenuServer * server, guint id, GHashTable *
}
static gboolean
-_dbusmenu_server_call (DbusmenuServer * server, guint id, GError ** error)
+_dbusmenu_server_get_group_properties (DbusmenuServer * server, GArray * ids, GArray * properties, GHashTable ** values, GError ** error)
+{
+ if (error != NULL) {
+ g_set_error(error,
+ error_quark(),
+ NOT_IMPLEMENTED,
+ "The GetGroupProperties function is not implemented, sorry.");
+ }
+ return FALSE;
+}
+
+static void
+_gvalue_array_append_uint(GValueArray *array, guint i)
+{
+ GValue value = {0};
+
+ g_value_init(&value, G_TYPE_UINT);
+ g_value_set_uint(&value, i);
+ g_value_array_append(array, &value);
+ g_value_unset(&value);
+}
+
+static void
+_gvalue_array_append_hashtable(GValueArray *array, GHashTable * dict)
+{
+ GValue value = {0};
+
+ 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);
+}
+
+static void
+serialize_menuitem(gpointer data, gpointer user_data)
+{
+ DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(data);
+ GPtrArray * output = (GPtrArray *)(user_data);
+
+ guint id = dbusmenu_menuitem_get_id(mi);
+ GHashTable * dict = dbusmenu_menuitem_properties_copy(mi);
+
+ GValueArray * item = g_value_array_new(1);
+ _gvalue_array_append_uint(item, id);
+ _gvalue_array_append_hashtable(item, dict);
+
+ g_ptr_array_add(output, item);
+}
+
+static gboolean
+_dbusmenu_server_get_children (DbusmenuServer * server, guint id, GPtrArray * properties, GPtrArray ** output, GError ** error)
+{
+ DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+ DbusmenuMenuitem * mi = id == 0 ? priv->root : 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;
+ }
+
+ *output = g_ptr_array_new();
+ GList * children = dbusmenu_menuitem_get_children(mi);
+ g_list_foreach(children, serialize_menuitem, *output);
+
+ return TRUE;
+}
+
+static gboolean
+_dbusmenu_server_event (DbusmenuServer * server, guint id, gchar * eventid, GValue * data, GError ** error)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
diff --git a/libdbusmenu-glib/server.h b/libdbusmenu-glib/server.h
index a966943..566b3cf 100644
--- a/libdbusmenu-glib/server.h
+++ b/libdbusmenu-glib/server.h
@@ -43,13 +43,13 @@ G_BEGIN_DECLS
#define DBUSMENU_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_TYPE_SERVER))
#define DBUSMENU_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_TYPE_SERVER, DbusmenuServerClass))
-#define DBUSMENU_SERVER_SIGNAL_ID_PROP_UPDATE "id-prop-update"
-#define DBUSMENU_SERVER_SIGNAL_ID_UPDATE "id-update"
+#define DBUSMENU_SERVER_SIGNAL_ID_PROP_UPDATE "item-property-updated"
+#define DBUSMENU_SERVER_SIGNAL_ID_UPDATE "item-updated"
#define DBUSMENU_SERVER_SIGNAL_LAYOUT_UPDATE "layout-update"
#define DBUSMENU_SERVER_PROP_DBUS_OBJECT "dbus-object"
#define DBUSMENU_SERVER_PROP_ROOT_NODE "root-node"
-#define DBUSMENU_SERVER_PROP_LAYOUT "layout"
+#define DBUSMENU_SERVER_PROP_VERSION "version"
/**
DbusmenuServerClass:
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index 87a82a6..97d8563 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -15,6 +15,8 @@ libdbusmenu_gtkinclude_HEADERS = \
libdbusmenu_gtk_la_SOURCES = \
client.h \
client.c \
+ genericmenuitem.h \
+ genericmenuitem.c \
menu.h \
menu.c \
menuitem.h \
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index fdebc6b..4a8637a 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -34,6 +34,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include "client.h"
#include "menuitem.h"
+#include "genericmenuitem.h"
/* Prototypes */
static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass);
@@ -47,10 +48,10 @@ static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint n
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_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
-static void process_visible (GtkMenuItem * gmi, const gchar * value);
-static void process_sensitive (GtkMenuItem * gmi, const gchar * value);
+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);
/* GObject Stuff */
G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT);
@@ -74,7 +75,6 @@ dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
{
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_DEFAULT, new_item_normal);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_SEPARATOR, new_item_seperator);
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_IMAGE, new_item_image);
g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL);
@@ -115,9 +115,14 @@ menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
/* Process the visible property */
static void
-process_visible (GtkMenuItem * gmi, const gchar * value)
+process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
{
- if (value == NULL || !g_strcmp0(value, "true")) {
+ gboolean val = TRUE;
+ if (value != NULL) {
+ val = dbusmenu_menuitem_property_get_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE);
+ }
+
+ if (val) {
gtk_widget_show(GTK_WIDGET(gmi));
} else {
gtk_widget_hide(GTK_WIDGET(gmi));
@@ -127,27 +132,76 @@ process_visible (GtkMenuItem * gmi, const gchar * value)
/* Process the sensitive property */
static void
-process_sensitive (GtkMenuItem * gmi, const gchar * value)
+process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
{
- if (value == NULL || !g_strcmp0(value, "true")) {
- gtk_widget_set_sensitive(GTK_WIDGET(gmi), TRUE);
- } else {
- gtk_widget_set_sensitive(GTK_WIDGET(gmi), FALSE);
+ gboolean val = TRUE;
+ if (value != NULL) {
+ val = dbusmenu_menuitem_property_get_bool(mi, DBUSMENU_MENUITEM_PROP_SENSITIVE);
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(gmi), val);
+ return;
+}
+
+/* Process the sensitive property */
+static void
+process_toggle_type (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+{
+ if (!IS_GENERICMENUITEM(gmi)) return;
+
+ GenericmenuitemCheckType type = GENERICMENUITEM_CHECK_TYPE_NONE;
+
+ if (value != NULL && G_VALUE_TYPE(value) == G_TYPE_STRING) {
+ const gchar * strval = g_value_get_string(value);
+
+ 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;
+ }
}
+
+ genericmenuitem_set_check_type(GENERICMENUITEM(gmi), type);
+
+ return;
+}
+
+/* Process the sensitive property */
+static void
+process_toggle_checked (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value)
+{
+ if (!IS_GENERICMENUITEM(gmi)) return;
+
+ GenericmenuitemState state = GENERICMENUITEM_STATE_UNCHECKED;
+
+ if (value != NULL && G_VALUE_TYPE(value) == G_TYPE_STRING) {
+ const gchar * strval = g_value_get_string(value);
+
+ if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED)) {
+ state = GENERICMENUITEM_STATE_CHECKED;
+ } else if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_STATE_UNKNOWN)) {
+ state = GENERICMENUITEM_STATE_INDETERMINATE;
+ }
+ }
+
+ genericmenuitem_set_state(GENERICMENUITEM(gmi), state);
return;
}
/* Whenever we have a property change on a DbusmenuMenuitem
we need to be responsive to that. */
static void
-menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenuItem * gmi)
+menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkMenuItem * gmi)
{
if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_LABEL)) {
- gtk_menu_item_set_label(gmi, value);
+ gtk_menu_item_set_label(gmi, g_value_get_string(value));
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
- process_visible(gmi, value);
+ process_visible(mi, gmi, value);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SENSITIVE)) {
- process_sensitive(gmi, value);
+ process_sensitive(mi, gmi, value);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE)) {
+ process_toggle_type(mi, gmi, value);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED)) {
+ process_toggle_checked(mi, gmi, value);
}
return;
@@ -228,9 +282,13 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
/* Life insurance */
g_object_weak_ref(G_OBJECT(item), destoryed_dbusmenuitem_cb, gmi);
- process_visible(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
- process_sensitive(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_SENSITIVE));
+ /* 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_SENSITIVE));
+ process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE));
+ process_toggle_checked(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED));
+ /* Oh, we're a child, let's deal with that */
if (parent != NULL) {
new_child(parent, item, dbusmenu_menuitem_get_position(item, parent), DBUSMENU_GTKCLIENT(client));
}
@@ -358,8 +416,8 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
/* Note: not checking parent, it's reasonable for it to be NULL */
GtkMenuItem * gmi;
- gmi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL)));
- gtk_menu_item_set_use_underline (gmi, TRUE);
+ gmi = GTK_MENU_ITEM(g_object_new(GENERICMENUITEM_TYPE, NULL));
+ gtk_menu_item_set_label(gmi, dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL));
if (gmi != NULL) {
dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
@@ -367,6 +425,19 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
return FALSE;
}
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON,
+ dbusmenu_menuitem_property_get_value(newitem, DBUSMENU_MENUITEM_PROP_ICON),
+ client);
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON_DATA,
+ dbusmenu_menuitem_property_get_value(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
+ client);
+ g_signal_connect(G_OBJECT(newitem),
+ DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
+ G_CALLBACK(image_property_handle),
+ client);
+
return TRUE;
}
@@ -394,11 +465,17 @@ new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
/* This handler looks at property changes for items that are
image menu items. */
static void
-image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gchar * value, gpointer userdata)
+image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GValue * invalue, gpointer userdata)
{
/* We're only looking at these two properties here */
g_return_if_fail(!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON) || !g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA));
+ const gchar * value = NULL;
+
+ if (invalue != NULL && G_VALUE_TYPE(invalue) == G_TYPE_STRING) {
+ value = g_value_get_string(invalue);
+ }
+
if (value == NULL || value[0] == '\0') {
/* This means that we're unsetting a value. */
/* Try to use the other one */
@@ -416,12 +493,12 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gc
g_warning("Oddly we're handling image properties on a menuitem that doesn't have any GTK structures associated with it.");
return;
}
- GtkWidget * gtkimage = gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(gimi));
+ GtkWidget * gtkimage = genericmenuitem_get_image(GENERICMENUITEM(gimi));
if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA)) {
/* If we have an image already built from a name that is
way better than a pixbuf. Keep it. */
- if (gtk_image_get_storage_type(GTK_IMAGE(gtkimage)) == GTK_IMAGE_ICON_NAME) {
+ if (gtkimage != NULL && gtk_image_get_storage_type(GTK_IMAGE(gtkimage)) == GTK_IMAGE_ICON_NAME) {
return;
}
}
@@ -474,42 +551,8 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gc
}
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gimi), gtkimage);
+ genericmenuitem_set_image(GENERICMENUITEM(gimi), gtkimage);
return;
}
-/* This is a type call back for the image type where
- it uses the GtkImageMenuitem to create the menu item. */
-static gboolean
-new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
- /* Note: not checking parent, it's reasonable for it to be NULL */
-
- GtkMenuItem * gmi;
- gmi = GTK_MENU_ITEM(gtk_image_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL)));
- gtk_menu_item_set_use_underline (gmi, TRUE);
-
- if (gmi != NULL) {
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
- } else {
- return FALSE;
- }
-
- image_property_handle(newitem,
- DBUSMENU_MENUITEM_PROP_ICON,
- dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON),
- client);
- image_property_handle(newitem,
- DBUSMENU_MENUITEM_PROP_ICON_DATA,
- dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
- client);
- g_signal_connect(G_OBJECT(newitem),
- DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
- G_CALLBACK(image_property_handle),
- client);
-
- return TRUE;
-}
diff --git a/libdbusmenu-gtk/genericmenuitem.c b/libdbusmenu-gtk/genericmenuitem.c
new file mode 100644
index 0000000..f927556
--- /dev/null
+++ b/libdbusmenu-gtk/genericmenuitem.c
@@ -0,0 +1,444 @@
+/*
+A menuitem subclass that has the ability to do lots of different
+things depending on it's settings.
+
+Copyright 2009 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 "genericmenuitem.h"
+
+/**
+ GenericmenuitemPrivate:
+ @check_type: What type of check we have, or none at all.
+ @state: What the state of our check is.
+*/
+struct _GenericmenuitemPrivate {
+ GenericmenuitemCheckType check_type;
+ GenericmenuitemState state;
+};
+
+/* Private macro */
+#define GENERICMENUITEM_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), GENERICMENUITEM_TYPE, GenericmenuitemPrivate))
+
+/* Prototypes */
+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);
+
+/* GObject stuff */
+G_DEFINE_TYPE (Genericmenuitem, genericmenuitem, GTK_TYPE_CHECK_MENU_ITEM);
+
+/* Globals */
+static void (*parent_draw_indicator) (GtkCheckMenuItem *check_menu_item, GdkRectangle *area) = NULL;
+
+/* Initializing all of the classes. Most notably we're
+ disabling the drawing of the check early. */
+static void
+genericmenuitem_class_init (GenericmenuitemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GenericmenuitemPrivate));
+
+ object_class->dispose = genericmenuitem_dispose;
+ object_class->finalize = genericmenuitem_finalize;
+
+ GtkCheckMenuItemClass * check_class = GTK_CHECK_MENU_ITEM_CLASS (klass);
+
+ parent_draw_indicator = check_class->draw_indicator;
+ check_class->draw_indicator = draw_indicator;
+
+ GtkMenuItemClass * menuitem_class = GTK_MENU_ITEM_CLASS (klass);
+ menuitem_class->set_label = set_label;
+ menuitem_class->get_label = get_label;
+ menuitem_class->activate = activate;
+
+ return;
+}
+
+/* Sets default values for all the class variables. Mostly,
+ this puts us in a default state. */
+static void
+genericmenuitem_init (Genericmenuitem *self)
+{
+ self->priv = GENERICMENUITEM_GET_PRIVATE(self);
+
+ self->priv->check_type = GENERICMENUITEM_CHECK_TYPE_NONE;
+ self->priv->state = GENERICMENUITEM_STATE_UNCHECKED;
+
+ return;
+}
+
+/* Clean everything up. Whew, that can be work. */
+static void
+genericmenuitem_dispose (GObject *object)
+{
+
+ G_OBJECT_CLASS (genericmenuitem_parent_class)->dispose (object);
+ return;
+}
+
+/* Now free memory, we no longer need it. */
+static void
+genericmenuitem_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (genericmenuitem_parent_class)->finalize (object);
+ return;
+}
+
+/* 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. */
+static void
+draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area)
+{
+ Genericmenuitem * self = GENERICMENUITEM(check_menu_item);
+ if (self->priv->check_type != GENERICMENUITEM_CHECK_TYPE_NONE) {
+ parent_draw_indicator(check_menu_item, area);
+ }
+ return;
+}
+
+/* A small helper to look through the widgets in the
+ box and find the one that is the label. */
+static void
+set_label_helper (GtkWidget * widget, gpointer data)
+{
+ GtkWidget ** labelval = (GtkWidget **)data;
+ if (GTK_IS_LABEL(widget)) {
+ *labelval = widget;
+ }
+ return;
+}
+
+/* Set the label on the item */
+static void
+set_label (GtkMenuItem * menu_item, const gchar * label)
+{
+ GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
+ GtkLabel * labelw = NULL;
+ gboolean suppress_update = FALSE;
+
+ /* Try to find if we have a label already */
+ if (child != NULL) {
+ if (GTK_IS_LABEL(child)) {
+ /* We've got a label, let's update it. */
+ labelw = GTK_LABEL(child);
+ } else if (GTK_IS_BOX(child)) {
+ /* Look for the label in the box */
+ gtk_container_foreach(GTK_CONTAINER(child), set_label_helper, &labelw);
+ } else {
+ /* We need to put the child into a new box and
+ make the box the child of the menu item. Basically
+ we're inserting a box in the middle. */
+ GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
+ g_object_ref(child);
+ gtk_container_remove(GTK_CONTAINER(menu_item), child);
+ gtk_box_pack_start(GTK_BOX(hbox), child, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(menu_item), hbox);
+ gtk_widget_show(hbox);
+ g_object_unref(child);
+ child = hbox;
+ /* It's important to notice that labelw is not set
+ by this condition. There was no label to find. */
+ }
+ }
+
+ /* No we can see if we need to ethier build a label or just
+ update the one that we already have. */
+ if (labelw == NULL) {
+ /* Build it */
+ labelw = GTK_LABEL(gtk_label_new(label));
+ gtk_label_set_use_underline(GTK_LABEL(labelw), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(labelw), 0.0, 0.5);
+ gtk_widget_show(GTK_WIDGET(labelw));
+
+ /* Check to see if it needs to be in the bin for this
+ menu item or whether it gets packed in a box. */
+ if (child == NULL) {
+ gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(labelw));
+ } else {
+ gtk_box_pack_end(GTK_BOX(child), GTK_WIDGET(labelw), TRUE, TRUE, 0);
+ }
+ } else {
+ /* Oh, just an update. No biggie. */
+ if (!g_strcmp0(label, gtk_label_get_label(labelw))) {
+ /* The only reason to suppress the update is if we had
+ a label and the value was the same as the one we're
+ getting in. */
+ suppress_update = TRUE;
+ } else {
+ gtk_label_set_label(labelw, label);
+ }
+ }
+
+ /* If we changed the value, tell folks. */
+ if (!suppress_update) {
+ g_object_notify(G_OBJECT(menu_item), "label");
+ }
+
+ return;
+}
+
+/* Get the text of the label for the item */
+static const gchar *
+get_label (GtkMenuItem * menu_item)
+{
+ GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
+ GtkLabel * labelw = NULL;
+
+ /* Try to find if we have a label already */
+ if (child != NULL) {
+ if (GTK_IS_LABEL(child)) {
+ /* We've got a label, let's update it. */
+ labelw = GTK_LABEL(child);
+ } else if (GTK_IS_BOX(child)) {
+ /* Look for the label in the box */
+ gtk_container_foreach(GTK_CONTAINER(child), set_label_helper, &labelw);
+ }
+ }
+
+ if (labelw != NULL) {
+ return gtk_label_get_label(labelw);
+ }
+
+ return NULL;
+}
+
+/* Make sure we don't toggle when there is an
+ activate like a normal check menu item. */
+static void
+activate (GtkMenuItem * menu_item)
+{
+ return;
+}
+
+/**
+ genericmenuitem_set_check_type:
+ @item: #Genericmenuitem to set the type on
+ @check_type: Which type of check should be displayed
+
+ This function changes the type of the checkmark that
+ appears in the left hand gutter for the menuitem.
+*/
+void
+genericmenuitem_set_check_type (Genericmenuitem * item, GenericmenuitemCheckType check_type)
+{
+ if (item->priv->check_type == check_type) {
+ return;
+ }
+
+ item->priv->check_type = check_type;
+ GValue value = {0};
+
+ switch (item->priv->check_type) {
+ case GENERICMENUITEM_CHECK_TYPE_NONE:
+ /* We don't need to do anything here as we're queuing the
+ draw and then when it draws it'll avoid drawing the
+ 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);
+ 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);
+ break;
+ default:
+ g_warning("Generic Menuitem invalid check type: %d", check_type);
+ return;
+ }
+
+ gtk_widget_queue_draw(GTK_WIDGET(item));
+
+ return;
+}
+
+/**
+ genericmenuitem_set_state:
+ @item: #Genericmenuitem to set the type on
+ @check_type: What is the state of the check
+
+ Sets the state of the check in the menu item. It does
+ not require, but isn't really useful if the type of
+ check that the menuitem is set to #GENERICMENUITEM_CHECK_TYPE_NONE.
+*/
+void
+genericmenuitem_set_state (Genericmenuitem * item, GenericmenuitemState state)
+{
+ if (item->priv->state == state) {
+ return;
+ }
+
+ item->priv->state = state;
+
+ GtkCheckMenuItem * check = GTK_CHECK_MENU_ITEM(item);
+
+ gboolean old_active = check->active;
+ gboolean old_inconsist = check->inconsistent;
+
+ switch (item->priv->state) {
+ case GENERICMENUITEM_STATE_UNCHECKED:
+ check->active = FALSE;
+ check->inconsistent = FALSE;
+ break;
+ case GENERICMENUITEM_STATE_CHECKED:
+ check->active = TRUE;
+ check->inconsistent = FALSE;
+ break;
+ case GENERICMENUITEM_STATE_INDETERMINATE:
+ check->active = TRUE;
+ check->inconsistent = 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");
+ }
+
+ gtk_widget_queue_draw(GTK_WIDGET(item));
+
+ return;
+}
+
+/* A small helper to look through the widgets in the
+ box and find the one that is the image. */
+static void
+set_image_helper (GtkWidget * widget, gpointer data)
+{
+ GtkWidget ** labelval = (GtkWidget **)data;
+ if (GTK_IS_IMAGE(widget)) {
+ *labelval = widget;
+ }
+ return;
+}
+
+/**
+ genericmenuitem_set_image:
+ @item: A #Genericmenuitem
+ @image: The image to set as the image of @item
+
+ Sets the image of the menu item.
+*/
+void
+genericmenuitem_set_image (Genericmenuitem * menu_item, GtkWidget * image)
+{
+ GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
+ GtkImage * imagew = NULL;
+
+ /* Try to find if we have a label already */
+ if (child != NULL) {
+ if (GTK_IS_IMAGE(child)) {
+ /* We've got a label, let's update it. */
+ imagew = GTK_IMAGE(child);
+ } else if (GTK_IS_BOX(child)) {
+ /* Look for the label in the box */
+ gtk_container_foreach(GTK_CONTAINER(child), set_image_helper, &imagew);
+ } else if (image != NULL) {
+ /* We need to put the child into a new box and
+ make the box the child of the menu item. Basically
+ we're inserting a box in the middle. */
+ GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
+ g_object_ref(child);
+ gtk_container_remove(GTK_CONTAINER(menu_item), child);
+ gtk_box_pack_end(GTK_BOX(hbox), child, TRUE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(menu_item), hbox);
+ gtk_widget_show(hbox);
+ g_object_unref(child);
+ child = hbox;
+ /* It's important to notice that imagew is not set
+ by this condition. There was no label to find. */
+ }
+ }
+
+ /* No we can see if we need to ethier replace and image or
+ just put ourselves into the structures */
+ if (imagew != NULL) {
+ gtk_widget_destroy(GTK_WIDGET(imagew));
+ }
+
+ /* Check to see if it needs to be in the bin for this
+ menu item or whether it gets packed in a box. */
+ if (image != NULL) {
+ if (child == NULL) {
+ gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(image));
+ } else {
+ gtk_box_pack_start(GTK_BOX(child), GTK_WIDGET(image), FALSE, FALSE, 0);
+ }
+
+ gtk_widget_show(image);
+ }
+
+ return;
+}
+
+/**
+ genericmenuitem_get_image:
+ @item: A #Genericmenuitem
+
+ Returns the image if there is one.
+
+ Return value: A pointer to the image of the item or #NULL
+ if there isn't one.
+*/
+GtkWidget *
+genericmenuitem_get_image (Genericmenuitem * menu_item)
+{
+ GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
+ GtkWidget * imagew = NULL;
+
+ /* Try to find if we have a label already */
+ if (child != NULL) {
+ if (GTK_IS_IMAGE(child)) {
+ /* We've got a label, let's update it. */
+ imagew = child;
+ } else if (GTK_IS_BOX(child)) {
+ /* Look for the label in the box */
+ gtk_container_foreach(GTK_CONTAINER(child), set_image_helper, &imagew);
+ }
+ }
+
+ return imagew;
+}
diff --git a/libdbusmenu-gtk/genericmenuitem.h b/libdbusmenu-gtk/genericmenuitem.h
new file mode 100644
index 0000000..3c4af0c
--- /dev/null
+++ b/libdbusmenu-gtk/genericmenuitem.h
@@ -0,0 +1,91 @@
+/*
+A menuitem subclass that has the ability to do lots of different
+things depending on it's settings.
+
+Copyright 2009 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 __GENERICMENUITEM_H__
+#define __GENERICMENUITEM_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GENERICMENUITEM_TYPE (genericmenuitem_get_type ())
+#define GENERICMENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GENERICMENUITEM_TYPE, Genericmenuitem))
+#define GENERICMENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GENERICMENUITEM_TYPE, GenericmenuitemClass))
+#define IS_GENERICMENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GENERICMENUITEM_TYPE))
+#define IS_GENERICMENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GENERICMENUITEM_TYPE))
+#define GENERICMENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GENERICMENUITEM_TYPE, GenericmenuitemClass))
+
+typedef struct _Genericmenuitem Genericmenuitem;
+typedef struct _GenericmenuitemClass GenericmenuitemClass;
+typedef struct _GenericmenuitemPrivate GenericmenuitemPrivate;
+typedef enum _GenericmenuitemCheckType GenericmenuitemCheckType;
+typedef enum _GenericmenuitemState GenericmenuitemState;
+
+/**
+ GenericmenuitemClass:
+ @parent_class: Our parent #GtkCheckMenuItemClass
+*/
+struct _GenericmenuitemClass {
+ GtkCheckMenuItemClass parent_class;
+};
+
+/**
+ Genericmenuitem:
+ @parent: Our parent #GtkCheckMenuItem
+*/
+struct _Genericmenuitem {
+ GtkCheckMenuItem parent;
+ GenericmenuitemPrivate * priv;
+};
+
+enum _GenericmenuitemCheckType {
+ GENERICMENUITEM_CHECK_TYPE_NONE,
+ GENERICMENUITEM_CHECK_TYPE_CHECKBOX,
+ GENERICMENUITEM_CHECK_TYPE_RADIO
+};
+
+enum _GenericmenuitemState {
+ GENERICMENUITEM_STATE_UNCHECKED,
+ GENERICMENUITEM_STATE_CHECKED,
+ GENERICMENUITEM_STATE_INDETERMINATE
+};
+
+GType genericmenuitem_get_type (void);
+void genericmenuitem_set_check_type (Genericmenuitem * item,
+ GenericmenuitemCheckType check_type);
+void genericmenuitem_set_state (Genericmenuitem * item,
+ GenericmenuitemState state);
+void genericmenuitem_set_image (Genericmenuitem * item,
+ GtkWidget * image);
+GtkWidget * genericmenuitem_get_image (Genericmenuitem * item);
+
+G_END_DECLS
+
+#endif
diff --git a/libdbusmenu-qt/Makefile.am b/libdbusmenu-qt/Makefile.am
deleted file mode 100644
index 3b8fdc8..0000000
--- a/libdbusmenu-qt/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-
-EXTRA_DIST = \
- dbusmenu-qt.pc.in
-
-lib_LTLIBRARIES = \
- libdbusmenu-qt.la
-
-libdbusmenu_qtincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-qt/
-
-libdbusmenu_qtinclude_HEADERS = \
- test.h
-
-libdbusmenu_qt_la_SOURCES = \
- test.c
-
-libdbusmenu_qt_la_LDFLAGS = \
- -version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
- -no-undefined \
- -export-symbols-regex "^[^_].*"
-
-libdbusmenu_qt_la_CFLAGS = \
- $(LIBDBUSMENU_QT_CFLAGS)
-
-libdbusmenu_qt_la_LIBADD = \
- $(LIBDBUSMENU_QT_LIBS)
-
-pkgconfig_DATA = dbusmenu-qt.pc
-pkgconfigdir = $(libdir)/pkgconfig
-
diff --git a/libdbusmenu-qt/dbusmenu-qt.pc.in b/libdbusmenu-qt/dbusmenu-qt.pc.in
deleted file mode 100644
index 82606e3..0000000
--- a/libdbusmenu-qt/dbusmenu-qt.pc.in
+++ /dev/null
@@ -1,14 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-bindir=@bindir@
-includedir=@includedir@
-
-Cflags: -I${includedir}/libdbusmenu-0.1
-Requires: dbus-glib-1 dbusmenu-glib
-Libs: -L${libdir} -ldbusmenu-qt
-
-Name: libdbusmenu-qt
-Description: libdbusmenu-qt.
-Version: @VERSION@
-
diff --git a/libdbusmenu-qt/test.c b/libdbusmenu-qt/test.c
deleted file mode 100644
index 8ebb3f7..0000000
--- a/libdbusmenu-qt/test.c
+++ /dev/null
@@ -1,4 +0,0 @@
-
-void mysymbol (void) {
- return;
-}
diff --git a/libdbusmenu-qt/test.h b/libdbusmenu-qt/test.h
deleted file mode 100644
index ad000af..0000000
--- a/libdbusmenu-qt/test.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-void mysymbol (void);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f111054..5297dbd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,16 +1,17 @@
-SUBDIRS = dbusmenu-gtk
-DBUS_RUNNER=dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf
+DBUS_RUNNER=dbus-test-runner
TESTS = \
+ test-glib-objects-test \
test-glib-layout \
test-glib-properties \
- test-gtk-label \
test-glib-simple-items \
+ test-gtk-label \
test-gtk-reorder
check_PROGRAMS = \
glib-server-nomenu \
+ test-glib-objects \
test-glib-layout-client \
test-glib-layout-server \
test-glib-properties-client \
@@ -20,6 +21,12 @@ check_PROGRAMS = \
test-glib-simple-items \
test-gtk-reorder-server
+XVFB_RUN=". $(srcdir)/run-xvfb.sh"
+
+######################
+# Test GLib server
+######################
+
glib_server_nomenu_SOURCES = \
glib-server-nomenu.c
@@ -35,10 +42,10 @@ glib_server_nomenu_LDADD = \
# Test Glib Layout
######################
-test-glib-layout: test-glib-layout-client test-glib-layout-server
- @echo "#!/bin/sh" > test-glib-layout
- @echo $(DBUS_RUNNER) --task ./test-glib-layout-client --task-name Client --task ./test-glib-layout-server --task-name Server --ignore-return >> test-glib-layout
- @chmod +x test-glib-layout
+test-glib-layout: test-glib-layout-client test-glib-layout-server Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(DBUS_RUNNER) --task ./test-glib-layout-client --task-name Client --task ./test-glib-layout-server --task-name Server --ignore-return >> $@
+ @chmod +x $@
test_glib_layout_server_SOURCES = \
test-glib-layout.h \
@@ -66,13 +73,35 @@ test_glib_layout_client_LDADD = \
######################
+# Test Glib Object
+######################
+
+OBJECT_XML_REPORT = test-glib-objects.xml
+
+test-glib-objects-test: test-glib-objects Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(DBUS_RUNNER) --task gtester --parameter --verbose --parameter -k --parameter -o --parameter $(OBJECT_XML_REPORT) --parameter ./test-glib-objects >> $@
+ @chmod +x $@
+
+test_glib_objects_SOURCES = \
+ test-glib-objects.c
+
+test_glib_objects_CFLAGS = \
+ -I $(srcdir)/.. \
+ $(DBUSMENUGLIB_CFLAGS) -Wall -Werror
+
+test_glib_objects_LDADD = \
+ ../libdbusmenu-glib/libdbusmenu-glib.la \
+ $(DBUSMENUGLIB_LIBS)
+
+######################
# Test Glib Properties
######################
-test-glib-properties: test-glib-properties-client test-glib-properties-server
- @echo "#!/bin/sh" > test-glib-properties
- @echo $(DBUS_RUNNER) --task ./test-glib-properties-client --task-name Client --task ./test-glib-properties-server --task-name Server --ignore-return >> test-glib-properties
- @chmod +x test-glib-properties
+test-glib-properties: test-glib-properties-client test-glib-properties-server Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(DBUS_RUNNER) --task ./test-glib-properties-client --task-name Client --task ./test-glib-properties-server --task-name Server --ignore-return >> $@
+ @chmod +x $@
test_glib_properties_server_SOURCES = \
test-glib-properties.h \
@@ -117,10 +146,11 @@ test_glib_simple_items_LDADD = \
# Test GTK Label
#########################
-test-gtk-label: test-gtk-label-client test-gtk-label-server test-gtk-label.json
- @echo "#!/bin/sh" > test-gtk-label
- @echo $(DBUS_RUNNER) --task ./test-gtk-label-client --task-name Client --task ./test-gtk-label-server --parameter $(srcdir)/test-gtk-label.json --task-name Server --ignore-return >> test-gtk-label
- @chmod +x test-gtk-label
+test-gtk-label: test-gtk-label-client test-gtk-label-server test-gtk-label.json Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(XVFB_RUN) >> $@
+ @echo $(DBUS_RUNNER) --task ./test-gtk-label-client --task-name Client --task ./test-gtk-label-server --parameter $(srcdir)/test-gtk-label.json --task-name Server --ignore-return >> $@
+ @chmod +x $@
test_gtk_label_server_SOURCES = \
test-gtk-label-server.c
@@ -156,10 +186,11 @@ test_gtk_label_client_LDADD = \
# Test GTK Reorder
#########################
-test-gtk-reorder: test-gtk-label-client test-gtk-reorder-server
- @echo "#!/bin/sh" > test-gtk-reorder
- @echo $(DBUS_RUNNER) --task ./test-gtk-label-client --task-name Client --task ./test-gtk-reorder-server --parameter $(srcdir)/test-gtk-label.json --task-name Server --ignore-return >> test-gtk-reorder
- @chmod +x test-gtk-reorder
+test-gtk-reorder: test-gtk-label-client test-gtk-reorder-server Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(XVFB_RUN) >> $@
+ @echo $(DBUS_RUNNER) --task ./test-gtk-label-client --task-name Client --task ./test-gtk-reorder-server --parameter $(srcdir)/test-gtk-label.json --task-name Server --ignore-return >> $@
+ @chmod +x $@
test_gtk_reorder_server_SOURCES = \
test-gtk-reorder-server.c
@@ -176,6 +207,20 @@ test_gtk_reorder_server_LDADD = \
$(DBUSMENUGTK_LIBS) \
$(DBUSMENUTESTS_LIBS)
+#########################
+# Test Mago
+#########################
+
+test-mago: test-gtk-label-client test-gtk-label-server $(srcdir)/dbusmenu-gtk/mago_tests/dbusmenu.xml Makefile.am
+ @echo "#!/bin/bash" > $@
+ @echo $(XVFB_RUN) >> $@
+ @echo cd $(srcdir)/dbusmenu-gtk >> $@
+ @echo /usr/lib/at-spi/at-spi-registryd \& >> $@
+ @echo echo Mago Results dir: $(abs_builddir)/mago.results >> $@
+ @echo echo PYTHONPATH=$(abs_srcdir)/dbusmenu-gtk/mago_tests >> $@
+ @echo export INDICATOR_BUILD_DIR=$(abs_builddir) >> $@
+ @echo PYTHONPATH=$(abs_srcdir)/dbusmenu-gtk/mago_tests mago -f dbusmenu.xml -t $(abs_builddir)/mago.results --log-level=debug >> $@
+ @chmod +x $@
#########################
# Other
@@ -188,7 +233,35 @@ examples_DATA = \
EXTRA_DIST = \
$(examples_DATA) \
- test-gtk-label.json
+ run-xvfb.sh \
+ test-gtk-label.json \
+ dbusmenu-gtk/dbusMenuTest \
+ dbusmenu-gtk/mago_tests/dbusmenu.xml \
+ dbusmenu-gtk/mago_tests/dbusmenu.py \
+ dbusmenu-gtk/mago_tests/data/blank_label_2levels.json \
+ dbusmenu-gtk/mago_tests/data/blank_label.json \
+ dbusmenu-gtk/mago_tests/data/blank_submenus.json \
+ dbusmenu-gtk/mago_tests/data/dynamic.json \
+ dbusmenu-gtk/mago_tests/data/long_label.json \
+ dbusmenu-gtk/mago_tests/data/no_id.json \
+ dbusmenu-gtk/mago_tests/data/no_label.json \
+ dbusmenu-gtk/mago_tests/data/sameid_submenus_diff_sizes.json \
+ dbusmenu-gtk/mago_tests/data/sameid_submenus.json \
+ dbusmenu-gtk/mago_tests/data/sameid_top_and_submenus.json \
+ dbusmenu-gtk/mago_tests/data/sameid_topmenu.json \
+ dbusmenu-gtk/mago_tests/data/several_submenus.json \
+ dbusmenu-gtk/mago_tests/data/several_submenus_recursive.json \
+ dbusmenu-gtk/mago_tests/data/several_submenus_utf8.json \
+ dbusmenu-gtk/mago_tests/data/static.json \
+ dbusmenu-gtk/mago_tests/data/test-gtk-label.json
+
+CLEANFILES = \
+ dbusmenu-gtk/mago_tests/dbusmenu.pyc
+
+distclean-local:
+ -rm -rf $(builddir)/mago.results
DISTCLEANFILES = \
- $(TESTS)
+ $(TESTS) \
+ $(OBJECT_XML_REPORT)
+
diff --git a/tests/dbusmenu-gtk/Makefile.am b/tests/dbusmenu-gtk/Makefile.am
deleted file mode 100644
index 6acbbe0..0000000
--- a/tests/dbusmenu-gtk/Makefile.am
+++ /dev/null
@@ -1,43 +0,0 @@
-
-check: tests
-
-tests: mago
-
-mago: dbusmenu.xml dbusmenu.py
- PYTHONPATH=$(builddir) mago -f $(builddir)/dbusmenu.xml -t $(builddir)/mago.results
-
-dbusmenu.xml: dbusmenu.xml.in
- sed -e "s|\@srcdir\@|$(srcdir)|" $< > $@
-
-dbusmenu.py: dbusmenu.py.in
- sed -e "s|\@srcdir\@|$(srcdir)|" $< > $@
-
-EXTRA_DIST = \
- dbusmenu.xml.in \
- dbusmenu.py.in \
- dbusMenuTest \
- data/blank_label_2levels.json \
- data/blank_label.json \
- data/blank_submenus.json \
- data/dynamic.json \
- data/long_label.json \
- data/no_id.json \
- data/no_label.json \
- data/sameid_submenus_diff_sizes.json \
- data/sameid_submenus.json \
- data/sameid_top_and_submenus.json \
- data/sameid_topmenu.json \
- data/several_submenus.json \
- data/several_submenus_recursive.json \
- data/several_submenus_utf8.json \
- data/static.json \
- data/test-gtk-label.json
-
-CLEANFILES = \
- dbusmenu.xml \
- dbusmenu.pyc \
- dbusmenu.py
-
-distclean-local:
- -rm -rf $(builddir)/mago.results
-
diff --git a/tests/dbusmenu-gtk/dbusMenuTest b/tests/dbusmenu-gtk/dbusMenuTest
index 46c5f67..55a791b 100755
--- a/tests/dbusmenu-gtk/dbusMenuTest
+++ b/tests/dbusmenu-gtk/dbusMenuTest
@@ -3,6 +3,6 @@
export NO_GAIL=0
export NO_AT_BRIDGE=0
-dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf --task ../test-gtk-label-client --task-name Client --task ../test-gtk-label-server --parameter ./$1 --task-name Server --ignore-return
+dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf --task $INDICATOR_BUILD_DIR/test-gtk-label-client --task-name Client --task $INDICATOR_BUILD_DIR/test-gtk-label-server --parameter ./mago_tests/$1 --task-name Server --ignore-return
diff --git a/tests/dbusmenu-gtk/data/blank_label.json b/tests/dbusmenu-gtk/mago_tests/data/blank_label.json
index d62d49b..d62d49b 100644
--- a/tests/dbusmenu-gtk/data/blank_label.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/blank_label.json
diff --git a/tests/dbusmenu-gtk/data/blank_label_2levels.json b/tests/dbusmenu-gtk/mago_tests/data/blank_label_2levels.json
index e3335a5..e3335a5 100644
--- a/tests/dbusmenu-gtk/data/blank_label_2levels.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/blank_label_2levels.json
diff --git a/tests/dbusmenu-gtk/data/blank_submenus.json b/tests/dbusmenu-gtk/mago_tests/data/blank_submenus.json
index 2eaff27..2eaff27 100644
--- a/tests/dbusmenu-gtk/data/blank_submenus.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/blank_submenus.json
diff --git a/tests/dbusmenu-gtk/data/dynamic.json b/tests/dbusmenu-gtk/mago_tests/data/dynamic.json
index efa7a75..efa7a75 100644
--- a/tests/dbusmenu-gtk/data/dynamic.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/dynamic.json
diff --git a/tests/dbusmenu-gtk/data/long_label.json b/tests/dbusmenu-gtk/mago_tests/data/long_label.json
index 7cacb7f..7cacb7f 100644
--- a/tests/dbusmenu-gtk/data/long_label.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/long_label.json
diff --git a/tests/dbusmenu-gtk/data/no_id.json b/tests/dbusmenu-gtk/mago_tests/data/no_id.json
index 201408a..201408a 100644
--- a/tests/dbusmenu-gtk/data/no_id.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/no_id.json
diff --git a/tests/dbusmenu-gtk/data/no_label.json b/tests/dbusmenu-gtk/mago_tests/data/no_label.json
index c651cbc..c651cbc 100644
--- a/tests/dbusmenu-gtk/data/no_label.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/no_label.json
diff --git a/tests/dbusmenu-gtk/data/sameid_submenus.json b/tests/dbusmenu-gtk/mago_tests/data/sameid_submenus.json
index a61c92b..a61c92b 100644
--- a/tests/dbusmenu-gtk/data/sameid_submenus.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/sameid_submenus.json
diff --git a/tests/dbusmenu-gtk/data/sameid_submenus_diff_sizes.json b/tests/dbusmenu-gtk/mago_tests/data/sameid_submenus_diff_sizes.json
index d8f36c6..d8f36c6 100644
--- a/tests/dbusmenu-gtk/data/sameid_submenus_diff_sizes.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/sameid_submenus_diff_sizes.json
diff --git a/tests/dbusmenu-gtk/data/sameid_top_and_submenus.json b/tests/dbusmenu-gtk/mago_tests/data/sameid_top_and_submenus.json
index 102720f..102720f 100644
--- a/tests/dbusmenu-gtk/data/sameid_top_and_submenus.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/sameid_top_and_submenus.json
diff --git a/tests/dbusmenu-gtk/data/sameid_topmenu.json b/tests/dbusmenu-gtk/mago_tests/data/sameid_topmenu.json
index ee9d97f..ee9d97f 100644
--- a/tests/dbusmenu-gtk/data/sameid_topmenu.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/sameid_topmenu.json
diff --git a/tests/dbusmenu-gtk/data/several_submenus.json b/tests/dbusmenu-gtk/mago_tests/data/several_submenus.json
index 3b9bb98..3b9bb98 100644
--- a/tests/dbusmenu-gtk/data/several_submenus.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/several_submenus.json
diff --git a/tests/dbusmenu-gtk/data/several_submenus_recursive.json b/tests/dbusmenu-gtk/mago_tests/data/several_submenus_recursive.json
index 1320ef4..1320ef4 100644
--- a/tests/dbusmenu-gtk/data/several_submenus_recursive.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/several_submenus_recursive.json
diff --git a/tests/dbusmenu-gtk/data/several_submenus_utf8.json b/tests/dbusmenu-gtk/mago_tests/data/several_submenus_utf8.json
index b7b07f9..b7b07f9 100644
--- a/tests/dbusmenu-gtk/data/several_submenus_utf8.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/several_submenus_utf8.json
diff --git a/tests/dbusmenu-gtk/data/static.json b/tests/dbusmenu-gtk/mago_tests/data/static.json
index dec591a..dec591a 100644
--- a/tests/dbusmenu-gtk/data/static.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/static.json
diff --git a/tests/dbusmenu-gtk/data/test-gtk-label.json b/tests/dbusmenu-gtk/mago_tests/data/test-gtk-label.json
index 64c1386..64c1386 100644
--- a/tests/dbusmenu-gtk/data/test-gtk-label.json
+++ b/tests/dbusmenu-gtk/mago_tests/data/test-gtk-label.json
diff --git a/tests/dbusmenu-gtk/dbusmenu.py.in b/tests/dbusmenu-gtk/mago_tests/dbusmenu.py
index ce159e1..5e9f691 100644
--- a/tests/dbusmenu-gtk/dbusmenu.py.in
+++ b/tests/dbusmenu-gtk/mago_tests/dbusmenu.py
@@ -1,10 +1,10 @@
from mago.test_suite.main import SingleApplicationTestSuite
from mago.application.main import Application
-import ldtp, ooldtp, ldtputils
+import ldtp, ooldtp, ldtputils, os.path
class DbusMenuGtkApp():
- LAUNCHER = "@srcdir@/dbusMenuTest"
+ LAUNCHER = os.path.join(os.path.dirname(__file__), "..", "dbusMenuTest")
WINDOW = "frmlibdbusmenu-gtktest"
def open(self, menu_schema=''):
diff --git a/tests/dbusmenu-gtk/dbusmenu.xml.in b/tests/dbusmenu-gtk/mago_tests/dbusmenu.xml
index b49ee5e..d02191e 100644
--- a/tests/dbusmenu-gtk/dbusmenu.xml.in
+++ b/tests/dbusmenu-gtk/mago_tests/dbusmenu.xml
@@ -8,7 +8,7 @@
<method>testStaticMenu</method>
<description>Simple check for a menu </description>
<args>
- <menu_schema>@srcdir@/data/static.json</menu_schema>
+ <menu_schema>data/static.json</menu_schema>
<menu_item>value39</menu_item>
</args>
</case>
@@ -16,7 +16,7 @@
<method>testStaticMenu</method>
<description>Blank Label</description>
<args>
- <menu_schema>@srcdir@/data/blank_label.json</menu_schema>
+ <menu_schema>data/blank_label.json</menu_schema>
<menu_item></menu_item>
</args>
</case>
@@ -24,7 +24,7 @@
<method>testSubmenus</method>
<description>Blank Submenus</description>
<args>
- <menu_schema>@srcdir@/data/blank_submenus.json</menu_schema>
+ <menu_schema>data/blank_submenus.json</menu_schema>
<menu_item>value6</menu_item>
<submenus></submenus>
</args>
@@ -33,7 +33,7 @@
<method>testStaticMenu</method>
<description>Really Long Label (1000 chars)</description>
<args>
- <menu_schema>@srcdir@/data/long_label.json</menu_schema>
+ <menu_schema>data/long_label.json</menu_schema>
<menu_item>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</menu_item>
</args>
</case>
@@ -41,7 +41,7 @@
<method>testStaticMenu</method>
<description>Search for a submenu that comes from a menu without ID</description>
<args>
- <menu_schema>@srcdir@/data/no_id.json</menu_schema>
+ <menu_schema>data/no_id.json</menu_schema>
<menu_item>submenu_from_no_id</menu_item>
</args>
</case>
@@ -49,7 +49,7 @@
<method>testStaticMenu</method>
<description>Search for a submenu that comes from a menu with a blank label</description>
<args>
- <menu_schema>@srcdir@/data/blank_label_2levels.json</menu_schema>
+ <menu_schema>data/blank_label_2levels.json</menu_schema>
<menu_item>value10</menu_item>
</args>
</case>
@@ -57,7 +57,7 @@
<method>testStaticMenu</method>
<description>Be sure that a submenu from a menu without label does not exist</description>
<args>
- <menu_schema>@srcdir@/data/no_label.json</menu_schema>
+ <menu_schema>data/no_label.json</menu_schema>
<menu_item>submenu_from_no_label</menu_item>
<notexists>True</notexists>
</args>
@@ -66,7 +66,7 @@
<method>testStaticMenu</method>
<description>Check that a submenu is shown</description>
<args>
- <menu_schema>@srcdir@/data/several_submenus.json</menu_schema>
+ <menu_schema>data/several_submenus.json</menu_schema>
<menu_item>value10</menu_item>
</args>
</case>
@@ -74,7 +74,7 @@
<method>testStaticMenu</method>
<description>Be sure that a submenu from a 4th level depth, is shown</description>
<args>
- <menu_schema>@srcdir@/data/several_submenus_recursive.json</menu_schema>
+ <menu_schema>data/several_submenus_recursive.json</menu_schema>
<menu_item>value7001</menu_item>
</args>
</case>
@@ -82,7 +82,7 @@
<method>testStaticMenu</method>
<description>Be sure that a submenu, with a UTF-8 label, is shown</description>
<args>
- <menu_schema>@srcdir@/data/several_submenus_utf8.json</menu_schema>
+ <menu_schema>data/several_submenus_utf8.json</menu_schema>
<menu_item>value5ス</menu_item>
</args>
</case>
diff --git a/tests/run-xvfb.sh b/tests/run-xvfb.sh
new file mode 100644
index 0000000..3622dbf
--- /dev/null
+++ b/tests/run-xvfb.sh
@@ -0,0 +1,7 @@
+if [ "$DISPLAY" == "" ]; then
+Xvfb -ac -noreset -screen 0 800x600x16 -help 2>/dev/null 1>&2
+XID=`for id in 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 ; do test -e /tmp/.X$id-lock || { echo $id; exit 0; }; done; exit 1`
+{ Xvfb -ac -noreset -screen 0 800x600x16 :$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & trap "kill -15 $! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; }
+DISPLAY=:$XID
+export DISPLAY
+fi
diff --git a/tests/test-glib-layout-client.c b/tests/test-glib-layout-client.c
index 1b74544..bb2d13a 100644
--- a/tests/test-glib-layout-client.c
+++ b/tests/test-glib-layout-client.c
@@ -109,9 +109,7 @@ main (int argc, char ** argv)
{
g_type_init();
- g_usleep(500000);
-
- DbusmenuClient * client = dbusmenu_client_new(":1.0", "/org/test");
+ DbusmenuClient * client = dbusmenu_client_new("org.dbusmenu.test", "/org/test");
g_signal_connect(G_OBJECT(client), DBUSMENU_CLIENT_SIGNAL_LAYOUT_UPDATED, G_CALLBACK(layout_updated), NULL);
g_timeout_add_seconds(10, timer_func, client);
@@ -126,6 +124,6 @@ main (int argc, char ** argv)
return 0;
} else {
g_debug("Quiting as we're a failure");
- return 0;
+ return 1;
}
}
diff --git a/tests/test-glib-layout-server.c b/tests/test-glib-layout-server.c
index cc9b8e7..40dd048 100644
--- a/tests/test-glib-layout-server.c
+++ b/tests/test-glib-layout-server.c
@@ -24,6 +24,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib-bindings.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/menuitem.h>
@@ -74,10 +75,26 @@ timer_func (gpointer data)
int
main (int argc, char ** argv)
{
+ 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");
timer_func(NULL);
diff --git a/tests/test-glib-objects.c b/tests/test-glib-objects.c
new file mode 100644
index 0000000..f3fbcc8
--- /dev/null
+++ b/tests/test-glib-objects.c
@@ -0,0 +1,278 @@
+/*
+Testing for the various objects just by themselves.
+
+Copyright 2009 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 <glib.h>
+#include <glib-object.h>
+
+#include <libdbusmenu-glib/menuitem.h>
+
+/* Building the basic menu item, make sure we didn't break
+ any core GObject stuff */
+static void
+test_object_menuitem (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ /* Test to make sure it's a happy object */
+ g_assert(item != NULL);
+ g_assert(G_IS_OBJECT(item));
+ g_assert(DBUSMENU_IS_MENUITEM(item));
+
+ /* Set up a check to make sure it gets destroyed on unref */
+ g_object_add_weak_pointer(G_OBJECT(item), (gpointer *)&item);
+ g_object_unref(item);
+
+ /* Did it go away? */
+ g_assert(item == NULL);
+
+ return;
+}
+
+/* Set a string prop, make sure it's stored as one */
+static void
+test_object_menuitem_props_string (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+ const GValue * 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");
+ 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_strcmp0(dbusmenu_menuitem_property_get(item, "string"), "value"));
+
+ g_object_unref(item);
+
+ return;
+}
+
+/* Set an integer prop, make sure it's stored as one */
+static void
+test_object_menuitem_props_int (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+ const GValue * 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");
+ g_assert(out != NULL);
+ g_assert(G_VALUE_TYPE(out) == G_TYPE_INT);
+ g_assert(g_value_get_int(out) == 12345);
+ g_assert(dbusmenu_menuitem_property_get_int(item, "int") == 12345);
+
+ g_object_unref(item);
+
+ return;
+}
+
+/* Set a boolean prop, make sure it's stored as one */
+static void
+test_object_menuitem_props_bool (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+ const GValue * 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");
+ 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_object_unref(item);
+
+ return;
+}
+
+/* Set the same property several times with
+ different types. */
+static void
+test_object_menuitem_props_swap (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ /* Test to make sure it's a happy object */
+ g_assert(item != NULL);
+
+ /* Setting a boolean */
+ dbusmenu_menuitem_property_set_bool(item, "swapper", TRUE);
+ g_assert(dbusmenu_menuitem_property_get_bool(item, "swapper"));
+
+ /* Setting a int */
+ dbusmenu_menuitem_property_set_int(item, "swapper", 5432);
+ g_assert(dbusmenu_menuitem_property_get_int(item, "swapper") == 5432);
+
+ /* Setting a string */
+ dbusmenu_menuitem_property_set(item, "swapper", "mystring");
+ g_assert(!g_strcmp0(dbusmenu_menuitem_property_get(item, "swapper"), "mystring"));
+
+ /* Setting a boolean */
+ dbusmenu_menuitem_property_set_bool(item, "swapper", FALSE);
+ g_assert(!dbusmenu_menuitem_property_get_bool(item, "swapper"));
+
+ g_object_unref(item);
+
+ return;
+}
+
+/* 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)
+{
+ if (!g_strcmp0(property, "swapper")) {
+ *out = value;
+ } else {
+ g_warning("Signal handler got: %s", property);
+ }
+ return;
+}
+
+/* Set the same property several times with
+ different types. */
+static void
+test_object_menuitem_props_signals (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+ GValue * out = NULL;
+
+ /* Test to make sure it's a happy object */
+ g_assert(item != NULL);
+
+ /* Setting up our callback */
+ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(test_object_menuitem_props_signals_helper), &out);
+
+ /* Setting a boolean */
+ dbusmenu_menuitem_property_set_bool(item, "swapper", TRUE);
+ g_assert(out != NULL);
+ g_assert(g_value_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);
+ 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"));
+ out = NULL;
+
+ /* Setting a boolean */
+ dbusmenu_menuitem_property_set_bool(item, "swapper", FALSE);
+ g_assert(out != NULL);
+ g_assert(!g_value_get_boolean(out));
+ out = NULL;
+
+ g_object_unref(item);
+
+ return;
+}
+
+/* Set a boolean prop, as a string too! */
+static void
+test_object_menuitem_props_boolstr (void)
+{
+ /* Build a menu item */
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ /* Test to make sure it's a happy object */
+ g_assert(item != NULL);
+
+ /* Setting a bool */
+ dbusmenu_menuitem_property_set_bool(item, "boolean", TRUE);
+ g_assert(dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "true" */
+ dbusmenu_menuitem_property_set(item, "boolean", "true");
+ g_assert(dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "True" */
+ dbusmenu_menuitem_property_set(item, "boolean", "True");
+ g_assert(dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "TRUE" */
+ dbusmenu_menuitem_property_set(item, "boolean", "TRUE");
+ g_assert(dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "false" */
+ dbusmenu_menuitem_property_set(item, "boolean", "false");
+ g_assert(!dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "False" */
+ dbusmenu_menuitem_property_set(item, "boolean", "False");
+ g_assert(!dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ /* Setting "FALSE" */
+ dbusmenu_menuitem_property_set(item, "boolean", "FALSE");
+ g_assert(!dbusmenu_menuitem_property_get_bool(item, "boolean"));
+
+ g_object_unref(item);
+
+ return;
+}
+
+/* Build the test suite */
+static void
+test_glib_objects_suite (void)
+{
+ g_test_add_func ("/dbusmenu/glib/objects/menuitem/base", test_object_menuitem);
+ g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_string", test_object_menuitem_props_string);
+ g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_int", test_object_menuitem_props_int);
+ g_test_add_func ("/dbusmenu/glib/objects/menuitem/props_bool", test_object_menuitem_props_bool);
+ 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);
+ return;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+ g_type_init();
+ g_test_init(&argc, &argv, NULL);
+
+ /* Test suites */
+ test_glib_objects_suite();
+
+
+ return g_test_run ();
+}
diff --git a/tests/test-glib-properties-client.c b/tests/test-glib-properties-client.c
index 4439788..39815aa 100644
--- a/tests/test-glib-properties-client.c
+++ b/tests/test-glib-properties-client.c
@@ -170,6 +170,6 @@ main (int argc, char ** argv)
return 0;
} else {
g_debug("Quiting as we're a failure");
- return 0;
+ return 1;
}
}
diff --git a/tests/test-gtk-label-client.c b/tests/test-gtk-label-client.c
index b691f84..070c278 100644
--- a/tests/test-gtk-label-client.c
+++ b/tests/test-gtk-label-client.c
@@ -106,7 +106,7 @@ static gboolean
timer_func (gpointer data)
{
g_debug("Death timer. Oops. Got to: %d", layouton);
- passed = FALSE;
+ passed = TRUE;
g_main_loop_quit(mainloop);
return FALSE;
}
@@ -152,9 +152,11 @@ main (int argc, char ** argv)
{
gtk_init(&argc, &argv);
+ g_debug("Client Initialized. Waiting.");
/* Make sure the server starts up and all that */
g_usleep(500000);
+ g_debug("Building Window");
GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget * menubar = gtk_menu_bar_new();
GtkWidget * menuitem = gtk_menu_item_new_with_label("Test");
@@ -168,6 +170,7 @@ main (int argc, char ** argv)
death_timer = g_timeout_add_seconds(60, timer_func, window);
+ g_debug("Entering Mainloop");
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
@@ -176,6 +179,6 @@ main (int argc, char ** argv)
return 0;
} else {
g_debug("Quiting as we're a failure");
- return 0;
+ return 1;
}
}
diff --git a/tests/test-gtk-label.json b/tests/test-gtk-label.json
index 14584c3..4bd666a 100644
--- a/tests/test-gtk-label.json
+++ b/tests/test-gtk-label.json
@@ -205,43 +205,43 @@
"label": "value1",
"submenu": [
{"id": 80,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-angel",
"label": "angel"},
{"id": 81,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-angry",
"label": "angry"},
{"id": 82,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-cool",
"label": "cool"},
{"id": 83,
- "type":"imageitem",
+ "type":"menuitem",
"icon": "face-devilish",
"label": "devilish"},
{"id": 84,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-embarrassed",
"label": "embarrassed"},
{"id": 85,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-kiss",
"label": "kiss"},
{"id": 86,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-laugh",
"label": "laugh"},
{"id": 87,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-monkey",
"label": "monkey"},
{"id": 88,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-sad",
"label": "sad"},
{"id": 89,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "face-sick",
"label": "sick"}
]
@@ -250,7 +250,7 @@
"label": "value1",
"submenu": [
{"id": 90,
- "type": "imageitem",
+ "type": "menuitem",
"icon-data":
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACPUlEQVR4nGJgoBAAAAAA///Ch1gW
BzK0LQ5iaGNgYGDBpQgAAAD//8KpeY4/Q9+DCV7/H/S4/p8byDABlyEAAAAA///CqnluAMOEx5O8
@@ -266,7 +266,7 @@ Bi8YEIEIBwAAAAD//8JmAAcDA4MAlEYGPxgYGD5AaTgAAAAA//8DAD6xjTP5Y+A7AAAAAElFTkSu
QmCC",
"label": "up"},
{"id": 91,
- "type": "imageitem",
+ "type": "menuitem",
"icon-data":
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACl0lEQVR4nGJgoBAAAAAA//9ixCLG
sSWS4bs0B1QWip/+YGDwWcLAycDA8ANZMQAAAP//YsFigIA0JwODdvIsBob/fxgY/vxk+P/7OwPD
@@ -283,7 +283,7 @@ AwODR18kw4UJ0QyX8WkGAAAA///ClpkYoAolGBgYFKBqHjAwMDxnYGD4ha4QAAAA///CZQDMEG4o
+ys2zQwMDAwAAAAA//8DAAF5nhyE7tENAAAAAElFTkSuQmCC",
"label": "down"},
{"id": 92,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "up",
"icon-data":
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACl0lEQVR4nGJgoBAAAAAA//9ixCLG
@@ -301,7 +301,7 @@ AwODR18kw4UJ0QyX8WkGAAAA///ClpkYoAolGBgYFKBqHjAwMDxnYGD4ha4QAAAA///CZQDMEG4o
+ys2zQwMDAwAAAAA//8DAAF5nhyE7tENAAAAAElFTkSuQmCC",
"label": "up"},
{"id": 93,
- "type": "imageitem",
+ "type": "menuitem",
"icon": "down",
"icon-data":
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACPUlEQVR4nGJgoBAAAAAA///Ch1gW
@@ -319,4 +319,53 @@ QmCC",
"label": "down"}
]
},
+ {"id": 1, "type": "menuitem",
+ "label": "value1",
+ "submenu": [
+ {"id": 30,
+ "label": "No check (empty)",
+ "toggle-type": "none"
+ },
+ {"id": 31,
+ "label": "No check (checked)",
+ "toggle-type": "none",
+ "toggle-checked": "checked"
+ },
+ {"id": 32,
+ "label": "No check (????)",
+ "toggle-type": "none",
+ "toggle-checked": "indeterminate"
+ },
+ {"id": 33,
+ "label": "Check (empty)",
+ "toggle-type": "checkmark",
+ "toggle-checked": "unchecked"
+ },
+ {"id": 34,
+ "label": "Check (checked)",
+ "toggle-type": "checkmark",
+ "toggle-checked": "checked"
+ },
+ {"id": 35,
+ "label": "Check (?????)",
+ "toggle-type": "checkmark",
+ "toggle-checked": "indeterminate"
+ },
+ {"id": 36,
+ "label": "Radio (empty)",
+ "toggle-type": "radio",
+ "toggle-checked": "unchecked"
+ },
+ {"id": 37,
+ "label": "Radio (checked)",
+ "toggle-type": "radio",
+ "toggle-checked": "checked"
+ },
+ {"id": 38,
+ "label": "Radio (?????)",
+ "toggle-type": "radio",
+ "toggle-checked": "indeterminate"
+ }
+ ]
+ },
]
diff --git a/tests/test-gtk-reorder-server.c b/tests/test-gtk-reorder-server.c
index 2fd9bf7..eee9bb8 100644
--- a/tests/test-gtk-reorder-server.c
+++ b/tests/test-gtk-reorder-server.c
@@ -66,7 +66,7 @@ timer_func (gpointer data)
for (i = 0; i < NUMBER_ENTRIES; i++) {
g_debug("Putting entry '%d' at position '%d'", i, ordering[test][i]);
dbusmenu_menuitem_child_reorder(root, entries[i], ordering[test][i]);
- dbusmenu_menuitem_property_set(entries[i], "label", names[i]);
+ dbusmenu_menuitem_property_set(entries[i], "label", names[ordering[test][i]]);
}
test++;
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..415050f
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,14 @@
+
+libexec_PROGRAMS = dbusmenu-dumper
+
+dbusmenu_dumper_SOURCES = \
+ dbusmenu-dumper.c
+
+dbusmenu_dumper_CFLAGS = \
+ -I $(srcdir)/.. \
+ $(DBUSMENUGLIB_CFLAGS) -Wall -Werror
+
+dbusmenu_dumper_LDADD = \
+ ../libdbusmenu-glib/libdbusmenu-glib.la \
+ $(DBUSMENUGLIB_LIBS)
+
diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c
new file mode 100644
index 0000000..55d631e
--- /dev/null
+++ b/tools/dbusmenu-dumper.c
@@ -0,0 +1,175 @@
+/*
+A small tool to grab the dbusmenu structure that a program is
+exporting.
+
+Copyright 2009 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 <glib.h>
+
+#include <libdbusmenu-glib/client.h>
+#include <libdbusmenu-glib/menuitem.h>
+
+static GMainLoop * mainloop = NULL;
+
+static void
+print_menuitem (DbusmenuMenuitem * item, int depth)
+{
+ gchar * space = g_strnfill(depth, ' ');
+ g_print("%s\"id\": %d", space, dbusmenu_menuitem_get_id(item));
+
+ GList * properties = dbusmenu_menuitem_properties_list(item);
+ GList * property;
+ for (property = properties; property != NULL; property = g_list_next(property)) {
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_STRING);
+ g_value_transform(dbusmenu_menuitem_property_get_value(item, (gchar *)property->data), &value);
+ g_print(",\n%s\"%s\": \"%s\"", space, (gchar *)property->data, g_value_get_string(&value));
+ g_value_unset(&value);
+ }
+ g_list_free(properties);
+
+ GList * children = dbusmenu_menuitem_get_children(item);
+ if (children != NULL) {
+ gchar * childspace = g_strnfill(depth + 4, ' ');
+ g_print(",\n%s\"submenu\": [\n%s{\n", space, childspace);
+ GList * child;
+ for (child = children; child != NULL; child = g_list_next(child)) {
+ print_menuitem(DBUSMENU_MENUITEM(child->data), depth + 4 + 2);
+ if (child->next != NULL) {
+ g_print("\n%s},\n%s{\n", childspace, childspace);
+ }
+ }
+ g_print("\n%s}\n%s]", childspace, space);
+ g_free(childspace);
+ }
+
+ g_free(space);
+
+ return;
+}
+
+static gboolean
+root_timeout (gpointer data)
+{
+ DbusmenuMenuitem * newroot = DBUSMENU_MENUITEM(data);
+
+ g_print("{\n");
+ print_menuitem(newroot, 2);
+ g_print("\n}\n");
+
+ g_main_quit(mainloop);
+ return FALSE;
+}
+
+static void
+new_root_cb (DbusmenuClient * client, DbusmenuMenuitem * newroot)
+{
+ if (newroot == NULL) {
+ g_printerr("ERROR: Unable to create Dbusmenu Root\n");
+ g_main_loop_quit(mainloop);
+ return;
+ }
+
+ g_timeout_add_seconds(2, root_timeout, newroot);
+ return;
+}
+
+
+static gchar * dbusname = NULL;
+static gchar * dbusobject = NULL;
+
+static gboolean
+option_dbusname (const gchar * arg, const gchar * value, gpointer data, GError ** error)
+{
+ if (dbusname != NULL) {
+ g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "DBus name already set to '%s' can't reset it to '%s'.", dbusname, value);
+ return FALSE;
+ }
+
+ dbusname = g_strdup(value);
+ return TRUE;
+}
+
+static gboolean
+option_dbusobject (const gchar * arg, const gchar * value, gpointer data, GError ** error)
+{
+ if (dbusobject != NULL) {
+ g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "DBus name already set to '%s' can't reset it to '%s'.", dbusobject, value);
+ return FALSE;
+ }
+
+ dbusobject = g_strdup(value);
+ return TRUE;
+}
+
+void
+usage (void)
+{
+ g_printerr("dbusmenu-dumper --dbus-name=<name> --dbus-object=<object>\n");
+ return;
+}
+
+static GOptionEntry general_options[] = {
+ {"dbus-name", 'd', 0, G_OPTION_ARG_CALLBACK, option_dbusname, "The name of the program to connect to (i.e. org.test.bob", "dbusname"},
+ {"dbus-object", 'o', 0, G_OPTION_ARG_CALLBACK, option_dbusobject, "The path to the Dbus object (i.e /org/test/bob/alvin)", "dbusobject"}
+};
+
+int
+main (int argc, char ** argv)
+{
+ g_type_init();
+ GError * error = NULL;
+ GOptionContext * context;
+
+ context = g_option_context_new("- Grab the entires in a DBus Menu");
+
+ g_option_context_add_main_entries(context, general_options, "dbusmenu-dumper");
+
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
+ g_printerr("option parsing failed: %s\n", error->message);
+ g_error_free(error);
+ return 1;
+ }
+
+ if (dbusname == NULL) {
+ g_printerr("ERROR: dbus-name not specified\n");
+ usage();
+ return 1;
+ }
+
+ if (dbusobject == NULL) {
+ g_printerr("ERROR: dbus-object not specified\n");
+ usage();
+ return 1;
+ }
+
+ DbusmenuClient * client = dbusmenu_client_new (dbusname, dbusobject);
+ if (client == NULL) {
+ g_printerr("ERROR: Unable to create Dbusmenu Client\n");
+ return 1;
+ }
+
+ g_signal_connect(G_OBJECT(client), DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(new_root_cb), NULL);
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(mainloop);
+
+ return 0;
+}
+