aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-glib
diff options
context:
space:
mode:
Diffstat (limited to 'libdbusmenu-glib')
-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
11 files changed, 556 insertions, 127 deletions
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: