diff options
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r-- | libdbusmenu-glib/Makefile.am | 24 | ||||
-rw-r--r-- | libdbusmenu-glib/client.c | 49 | ||||
-rw-r--r-- | libdbusmenu-glib/dbus-menu.xml | 26 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.c | 26 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.h | 120 | ||||
-rw-r--r-- | libdbusmenu-glib/server.c | 19 |
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) { |