diff options
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r-- | libdbusmenu-glib/Makefile.am | 1 | ||||
-rw-r--r-- | libdbusmenu-glib/client.c | 87 | ||||
-rw-r--r-- | libdbusmenu-glib/client.h | 2 | ||||
-rw-r--r-- | libdbusmenu-glib/dbus-menu.xml | 126 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem-marshal.list | 2 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem-private.h | 40 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.c | 224 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.h | 19 | ||||
-rw-r--r-- | libdbusmenu-glib/server-marshal.list | 3 | ||||
-rw-r--r-- | libdbusmenu-glib/server.c | 173 | ||||
-rw-r--r-- | libdbusmenu-glib/server.h | 6 |
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: |