aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-glib
diff options
context:
space:
mode:
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r--libdbusmenu-glib/Makefile.am24
-rw-r--r--libdbusmenu-glib/client.c49
-rw-r--r--libdbusmenu-glib/dbus-menu.xml26
-rw-r--r--libdbusmenu-glib/menuitem.c26
-rw-r--r--libdbusmenu-glib/menuitem.h120
-rw-r--r--libdbusmenu-glib/server.c19
6 files changed, 189 insertions, 75 deletions
diff --git a/libdbusmenu-glib/Makefile.am b/libdbusmenu-glib/Makefile.am
index c1aff41..3df1513 100644
--- a/libdbusmenu-glib/Makefile.am
+++ b/libdbusmenu-glib/Makefile.am
@@ -99,21 +99,25 @@ menuitem-marshal.c: $(srcdir)/menuitem-marshal.list
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
+INTROSPECTION_SCANNER_ARGS = \
+ --add-include-path=$(srcdir) \
+ $(addprefix --c-include=libdbusmenu-glib/, $(introspection_sources))
INTROSPECTION_COMPILER_ARGS = --includedir=$(builddir)
if HAVE_INTROSPECTION
introspection_sources = $(libdbusmenu_glibinclude_HEADERS)
-DbusmenuGlib-0.2.gir: libdbusmenu-glib.la
-DbusmenuGlib_0_2_gir_INCLUDES = \
+Dbusmenu_Glib-0.2.gir: libdbusmenu-glib.la
+Dbusmenu_Glib_0_2_gir_INCLUDES = \
GObject-2.0
-DbusmenuGlib_0_2_gir_CFLAGS = $(DBUSMENUGLIB_CFLAGS)
-DbusmenuGlib_0_2_gir_LIBS = libdbusmenu-glib.la
-DbusmenuGlib_0_2_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
+Dbusmenu_Glib_0_2_gir_CFLAGS = $(DBUSMENUGLIB_CFLAGS)
+Dbusmenu_Glib_0_2_gir_LIBS = libdbusmenu-glib.la
+Dbusmenu_Glib_0_2_gir_FILES = $(addprefix $(srcdir)/, $(introspection_sources))
+Dbusmenu_Glib_0_2_gir_NAMESPACE = Dbusmenu
+Dbusmenu_Glib_0_2_gir_VERSION = Glib-0.2
-INTROSPECTION_GIRS += DbusmenuGlib-0.2.gir
+INTROSPECTION_GIRS += Dbusmenu-Glib-0.2.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
@@ -132,10 +136,10 @@ endif
if HAVE_INTROSPECTION
vapidir = $(datadir)/vala/vapi
-vapi_DATA = DbusmenuGlib-0.2.vapi
+vapi_DATA = Dbusmenu-Glib-0.2.vapi
-DbusmenuGlib-0.2.vapi: DbusmenuGlib-0.2.gir
- $(VALA_API_GEN) --library=DbusmenuGlib-0.2 $<
+Dbusmenu-Glib-0.2.vapi: Dbusmenu-Glib-0.2.gir
+ $(VALA_API_GEN) --library=Dbusmenu-Glib-0.2 $<
CLEANFILES += $(vapi_DATA)
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index d2ba541..2e985d6 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -30,6 +30,8 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
+#include <dbus/dbus-glib-bindings.h>
+
#include <libxml/parser.h>
#include <libxml/tree.h>
@@ -397,6 +399,25 @@ dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, c
return build_proxies(client);
}
+/* This is the response to see if the name has an owner. If
+ it does, then we should build the proxies here. Race condition
+ check. */
+static void
+name_owner_check (DBusGProxy *proxy, gboolean has_owner, GError *error, gpointer userdata)
+{
+ if (error != NULL) {
+ return;
+ }
+
+ if (!has_owner) {
+ return;
+ }
+
+ DbusmenuClient * client = DBUSMENU_CLIENT(userdata);
+ build_proxies(client);
+ return;
+}
+
/* This function builds the DBus proxy which will look out for
the service coming up. */
static void
@@ -426,6 +447,13 @@ build_dbus_proxy (DbusmenuClient * client)
dbus_g_proxy_connect_signal(priv->dbusproxy, "NameOwnerChanged",
G_CALLBACK(dbus_owner_change), client, NULL);
+ /* Now let's check to make sure we're not in some race
+ condition case. */
+ org_freedesktop_DBus_name_has_owner_async(priv->dbusproxy,
+ priv->dbus_name,
+ name_owner_check,
+ client);
+
return;
}
@@ -533,6 +561,12 @@ build_proxies (DbusmenuClient * client)
static gint
parse_node_get_id (xmlNodePtr node)
{
+ if (node == NULL) {
+ return -1;
+ }
+ if (node->type != XML_ELEMENT_NODE) {
+ return -1;
+ }
if (g_strcmp0((gchar *)node->name, "menu") != 0) {
/* This kills some nodes early */
g_warning("XML Node is not 'menu' it is '%s'", node->name);
@@ -682,6 +716,17 @@ menuitem_call_cb (DBusGProxy * proxy, GError * error, gpointer userdata)
void
dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name, const GValue * value, guint timestamp)
{
+ g_return_if_fail(DBUSMENU_IS_CLIENT(client));
+ g_return_if_fail(id >= 0);
+ g_return_if_fail(name != NULL);
+
+ if (value == NULL) {
+ GValue internalval = {0};
+ g_value_init(&internalval, G_TYPE_INT);
+ g_value_set_int(&internalval, 0);
+ value = &internalval;
+ }
+
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
org_ayatana_dbusmenu_event_async (priv->menuproxy, id, name, value, timestamp, menuitem_call_cb, GINT_TO_POINTER(id));
return;
@@ -855,6 +900,10 @@ parse_layout (DbusmenuClient * client, const gchar * layout)
xmlNodePtr root = xmlDocGetRootElement(xmldoc);
+ if (root == NULL) {
+ g_warning("Unable to get root node of menu XML");
+ }
+
DbusmenuMenuitem * oldroot = priv->root;
priv->root = parse_layout_xml(client, root, priv->root, NULL, priv->menuproxy);
diff --git a/libdbusmenu-glib/dbus-menu.xml b/libdbusmenu-glib/dbus-menu.xml
index 7937049..53b67de 100644
--- a/libdbusmenu-glib/dbus-menu.xml
+++ b/libdbusmenu-glib/dbus-menu.xml
@@ -29,12 +29,18 @@ License version 3 and version 2.1 along with this program. If not, see
<http://www.gnu.org/licenses/>
-->
<node name="/" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
+ <dox:d><![CDATA[
+ @mainpage
+
+ The goal of DBusMenu is to expose menus on DBus.
+
+ Main interface is documented here: @ref org::ayatana::dbusmenu
+ ]]></dox:d>
<interface name="org.ayatana.dbusmenu">
<dox:d><![CDATA[
- The goal of this DBus interface is to be able to pass menu items
- through DBus.
+ A DBus interface to expose menus on DBus.
- Items are represented with a unique numeric id and a dictionary of
+ Menu items are represented with a unique numeric id and a dictionary of
properties.
To reduce the amount of DBus traffic, a property should only be returned
@@ -100,6 +106,20 @@ License version 3 and version 2.1 along with this program. If not, see
<td>Empty</td>
</tr>
<tr>
+ <td>shortcut</td>
+ <td>array of arrays of strings</td>
+ <td>The shortcut of the item. Each array represents the key press
+ in the list of keypresses. Each list of strings contains a list of
+ modifiers and then the key that is used. The modifier strings
+ allowed are: "Control", "Alt", "Shift" and "Super".
+
+ - A simple shortcut like Ctrl+S is represented as:
+ [["Control", "S"]]
+ - A complex shortcut like Ctrl+Q, Alt+X is represented as:
+ [["Control", "Q"], ["Alt", "X"]]</td>
+ <td>Empty</td>
+ </tr>
+ <tr>
<td>toggle-type</td>
<td>string</td>
<td>
diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c
index 6a3c4bc..623539c 100644
--- a/libdbusmenu-glib/menuitem.c
+++ b/libdbusmenu-glib/menuitem.c
@@ -517,6 +517,9 @@ dbusmenu_menuitem_take_children (DbusmenuMenuitem * mi)
GList * children = priv->children;
priv->children = NULL;
g_list_foreach(children, take_children_signal, mi);
+
+ dbusmenu_menuitem_property_remove(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY);
+
return children;
}
@@ -622,6 +625,10 @@ dbusmenu_menuitem_child_append (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
g_return_val_if_fail(g_list_find(priv->children, child) == NULL, FALSE);
+ if (priv->children == NULL && !dbusmenu_menuitem_property_exist(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY)) {
+ dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY, DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU);
+ }
+
priv->children = g_list_append(priv->children, child);
#ifdef MASSIVEDEBUGGING
g_debug("Menuitem %d (%s) signalling child added %d (%s) at %d", ID(mi), LABEL(mi), ID(child), LABEL(child), g_list_length(priv->children) - 1);
@@ -650,6 +657,10 @@ dbusmenu_menuitem_child_prepend (DbusmenuMenuitem * mi, DbusmenuMenuitem * child
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
g_return_val_if_fail(g_list_find(priv->children, child) == NULL, FALSE);
+ if (priv->children == NULL && !dbusmenu_menuitem_property_exist(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY)) {
+ dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY, DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU);
+ }
+
priv->children = g_list_prepend(priv->children, child);
#ifdef MASSIVEDEBUGGING
g_debug("Menuitem %d (%s) signalling child added %d (%s) at %d", ID(mi), LABEL(mi), ID(child), LABEL(child), 0);
@@ -683,6 +694,11 @@ dbusmenu_menuitem_child_delete (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)
#endif
g_signal_emit(G_OBJECT(mi), signals[CHILD_REMOVED], 0, child, TRUE);
g_object_unref(G_OBJECT(child));
+
+ if (priv->children == NULL) {
+ dbusmenu_menuitem_property_remove(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY);
+ }
+
return TRUE;
}
@@ -707,6 +723,10 @@ dbusmenu_menuitem_child_add_position (DbusmenuMenuitem * mi, DbusmenuMenuitem *
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
g_return_val_if_fail(g_list_find(priv->children, child) == NULL, FALSE);
+ if (priv->children == NULL && !dbusmenu_menuitem_property_exist(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY)) {
+ dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY, DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU);
+ }
+
priv->children = g_list_insert(priv->children, child, position);
#ifdef MASSIVEDEBUGGING
g_debug("Menuitem %d (%s) signalling child added %d (%s) at %d", ID(mi), LABEL(mi), ID(child), LABEL(child), position);
@@ -1199,7 +1219,7 @@ dbusmenu_menuitem_get_root (DbusmenuMenuitem * mi)
/**
dbusmenu_menuitem_buildxml:
@mi: #DbusmenuMenuitem to represent in XML
- @array: A list of string that will be turned into an XML file
+ @array: (element-type utf8): A list of string that will be turned into an XML file
This function will add strings to the array @array. It will put
at least one entry if this menu item has no children. If it has
@@ -1247,7 +1267,7 @@ foreach_helper (gpointer data, gpointer user_data)
dbusmenu_menuitem_foreach:
@mi: The #DbusmenItem to start from
@func: Function to call on every node in the tree
- @data: User data to pass to the function
+ @data: (closure): User data to pass to the function
This calls the function @func on this menu item and all
of the children of this item. And their children. And
@@ -1305,7 +1325,7 @@ dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const
dbusmenu_menuitem_send_about_to_show:
@mi: The #DbusmenuMenuitem to send the signal on.
@cb: Callback to call when the call has returned.
- @cb_data: Data to pass to the callback.
+ @cb_data: (closure): Data to pass to the callback.
This function is used to send the even that the submenu
of this item is about to be shown. Callers to this event
diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h
index e5b5ae2..e17d851 100644
--- a/libdbusmenu-glib/menuitem.h
+++ b/libdbusmenu-glib/menuitem.h
@@ -58,6 +58,8 @@ G_BEGIN_DECLS
#define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
#define DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE "toggle-type"
#define DBUSMENU_MENUITEM_PROP_TOGGLE_STATE "toggle-state"
+#define DBUSMENU_MENUITEM_PROP_SHORTCUT "shortcut"
+#define DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY "children-display"
#define DBUSMENU_MENUITEM_TOGGLE_CHECK "checkmark"
#define DBUSMENU_MENUITEM_TOGGLE_RADIO "radio"
@@ -68,16 +70,23 @@ G_BEGIN_DECLS
#define DBUSMENU_MENUITEM_ICON_NAME_BLANK "blank-icon"
+#define DBUSMENU_MENUITEM_SHORTCUT_CONTROL "Control"
+#define DBUSMENU_MENUITEM_SHORTCUT_ALT "Alt"
+#define DBUSMENU_MENUITEM_SHORTCUT_SHIFT "Shift"
+#define DBUSMENU_MENUITEM_SHORTCUT_SUPER "Super"
+
+#define DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU "submenu"
+
/**
- DbusmenuMenuitem:
-
- This is the #GObject based object that represents a menu
- item. It gets created the same on both the client and
- the server side and libdbusmenu-glib does the work of making
- this object model appear on both sides of DBus. Simple
- really, though through updates and people coming on and off
- the bus it can lead to lots of fun complex scenarios.
-*/
+ * DbusmenuMenuitem:
+ *
+ * This is the #GObject based object that represents a menu
+ * item. It gets created the same on both the client and
+ * the server side and libdbusmenu-glib does the work of making
+ * this object model appear on both sides of DBus. Simple
+ * really, though through updates and people coming on and off
+ * the bus it can lead to lots of fun complex scenarios.
+ */
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
struct _DbusmenuMenuitem
{
@@ -85,36 +94,41 @@ struct _DbusmenuMenuitem
};
/**
- dbusmenu_menuitem_about_to_show_cb:
- @mi Menu item that should be shown
- @user_data Extra user data sent with the function
-
- Callback prototype for a callback that is called when the
- menu should be shown.
-*/
+ * dbusmenu_menuitem_about_to_show_cb:
+ * @mi: Menu item that should be shown
+ * @user_data: (closure): Extra user data sent with the function
+ *
+ * Callback prototype for a callback that is called when the
+ * menu should be shown.
+ */
typedef void (*dbusmenu_menuitem_about_to_show_cb) (DbusmenuMenuitem * mi, gpointer user_data);
+/**
+ * dbusmenu_menuitem_buildxml_slot_t:
+ * @mi: (in): Menu item that should be built from
+ * @stringarray: (inout) (transfer none) (array) (element-type utf8): An array of strings that can be combined into an XML file.
+ *
+ * This is the function that is called to represent this menu item
+ * as an XML fragment. Should call it's own children.
+ */
+typedef void (*dbusmenu_menuitem_buildxml_slot_t) (DbusmenuMenuitem * mi, GPtrArray* stringarray);
/**
- DbusmenuMenuitemClass:
- @property_changed: Slot for #DbusmenuMenuitem::property-changed.
- @item_activated: Slot for #DbusmenuMenuitem::item-activated.
- @child_added: Slot for #DbusmenuMenuitem::child-added.
- @child_removed: Slot for #DbusmenuMenuitem::child-removed.
- @child_moved: Slot for #DbusmenuMenuitem::child-moved.
- @realized: Slot for #DbusmenuMenuitem::realized.
- @buildxml: Virtual function that appends the strings required
- to represent this menu item in the menu XML file.
- @handle_event: This function is to override how events are handled
- by subclasses. Look at #dbusmenu_menuitem_handle_event for
- lots of good information.
- @send_about_to_show: Virtual function that notifies server that the
- client is about to show a menu.
- @reserved1: Reserved for future use.
- @reserved2: Reserved for future use.
- @reserved3: Reserved for future use.
- @reserved4: Reserved for future use.
-*/
+ * DbusmenuMenuitemClass:
+ * @property_changed: Slot for #DbusmenuMenuitem::property-changed.
+ * @item_activated: Slot for #DbusmenuMenuitem::item-activated.
+ * @child_added: Slot for #DbusmenuMenuitem::child-added.
+ * @child_removed: Slot for #DbusmenuMenuitem::child-removed.
+ * @child_moved: Slot for #DbusmenuMenuitem::child-moved.
+ * @realized: Slot for #DbusmenuMenuitem::realized.
+ * @buildxml: Virtual function that appends the strings required to represent this menu item in the menu XML file.
+ * @handle_event: This function is to override how events are handled by subclasses. Look at #dbusmenu_menuitem_handle_event for lots of good information.
+ * @send_about_to_show: Virtual function that notifies server that the client is about to show a menu.
+ * @reserved1: Reserved for future use.
+ * @reserved2: Reserved for future use.
+ * @reserved3: Reserved for future use.
+ * @reserved4: Reserved for future use.
+ */
typedef struct _DbusmenuMenuitemClass DbusmenuMenuitemClass;
struct _DbusmenuMenuitemClass
{
@@ -129,7 +143,7 @@ struct _DbusmenuMenuitemClass
void (*realized) (void);
/* Virtual functions */
- void (*buildxml) (GPtrArray * stringarray);
+ dbusmenu_menuitem_buildxml_slot_t buildxml;
void (*handle_event) (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
void (*send_about_to_show) (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data);
@@ -179,23 +193,23 @@ void dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name,
void dbusmenu_menuitem_send_about_to_show (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data);
/**
- SECTION:menuitem
- @short_description: A lowlevel represenation of a menuitem
- @stability: Unstable
- @include: libdbusmenu-glib/menuitem.h
-
- A #DbusmenuMenuitem is the lowest level of represenation of a
- single item in a menu. It gets created on the server side
- and copied over to the client side where it gets rendered. As
- the server starts to change it, and grow it, and do all kinds
- of fun stuff that information is transfered over DBus and the
- client updates it's understanding of the object model.
-
- Most people using either the client or the server should be
- able to deal mostly with #DbusmenuMenuitem objects. These
- are simple, but then they can be attached to more complex
- objects and handled appropriately.
-*/
+ * SECTION:menuitem
+ * @short_description: A lowlevel represenation of a menuitem
+ * @stability: Unstable
+ * @include: libdbusmenu-glib/menuitem.h
+ *
+ * A #DbusmenuMenuitem is the lowest level of represenation of a
+ * single item in a menu. It gets created on the server side
+ * and copied over to the client side where it gets rendered. As
+ * the server starts to change it, and grow it, and do all kinds
+ * of fun stuff that information is transfered over DBus and the
+ * client updates it's understanding of the object model.
+ *
+ * Most people using either the client or the server should be
+ * able to deal mostly with #DbusmenuMenuitem objects. These
+ * are simple, but then they can be attached to more complex
+ * objects and handled appropriately.
+ */
G_END_DECLS
diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c
index 02c9c57..13c2843 100644
--- a/libdbusmenu-glib/server.c
+++ b/libdbusmenu-glib/server.c
@@ -146,8 +146,8 @@ dbusmenu_server_class_init (DbusmenuServerClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(DbusmenuServerClass, id_update),
NULL, NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE, 1, G_TYPE_UINT);
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
/**
DbusmenuServer::layout-updated:
@arg0: The #DbusmenuServer emitting the signal.
@@ -225,15 +225,22 @@ static void
set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
{
DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(obj);
+ GError * error = NULL;
switch (id) {
case PROP_DBUS_OBJECT:
g_return_if_fail(priv->dbusobject == NULL);
priv->dbusobject = g_value_dup_string(value);
- DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- dbus_g_connection_register_g_object(connection,
- priv->dbusobject,
- obj);
+ DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (connection == NULL || error != NULL) {
+ g_warning("Unable to get session bus: %s", error == NULL ? "No message" : error->message);
+ if (error != NULL) { g_error_free(error); }
+ } else {
+ dbus_g_connection_register_g_object(connection,
+ priv->dbusobject,
+ obj);
+ }
break;
case PROP_ROOT_NODE:
if (priv->root != NULL) {