aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog7
-rw-r--r--libdbusmenu-glib/Makefile.am15
-rw-r--r--libdbusmenu-glib/client-marshal.list1
-rw-r--r--libdbusmenu-glib/client.c67
-rw-r--r--libdbusmenu-glib/client.h6
-rw-r--r--libdbusmenu-gtk/client.c28
-rw-r--r--tests/test-glib-properties-client.c2
7 files changed, 123 insertions, 3 deletions
diff --git a/debian/changelog b/debian/changelog
index 62b6109..e95d400 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+libdbusmenu (0.3.10-0ubuntu1~ppa2~activate1) UNRELEASED; urgency=low
+
+ * Upstream Merge
+ * Support activation of menus client side
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 18 Aug 2010 09:17:46 -0500
+
libdbusmenu (0.3.10-0ubuntu1~ppa1) maverick; urgency=low
* New upstream release.
diff --git a/libdbusmenu-glib/Makefile.am b/libdbusmenu-glib/Makefile.am
index 3df1513..0a6513f 100644
--- a/libdbusmenu-glib/Makefile.am
+++ b/libdbusmenu-glib/Makefile.am
@@ -4,6 +4,7 @@ CLEANFILES =
EXTRA_DIST = \
dbusmenu-glib.pc.in \
dbus-menu.xml \
+ client-marshal.list \
menuitem-marshal.list \
server-marshal.list
@@ -32,6 +33,8 @@ libdbusmenu_glib_la_SOURCES = \
server.c \
server-marshal.h \
server-marshal.c \
+ client-marshal.h \
+ client-marshal.c \
client-menuitem.h \
client-menuitem.c \
client.h \
@@ -54,6 +57,8 @@ pkgconfigdir = $(libdir)/pkgconfig
BUILT_SOURCES = \
dbusmenu-client.h \
dbusmenu-server.h \
+ client-marshal.h \
+ client-marshal.c \
menuitem-marshal.h \
menuitem-marshal.c \
server-marshal.h \
@@ -73,6 +78,16 @@ dbusmenu-client.h: dbus-menu.xml
--output=dbusmenu-client.h \
$(srcdir)/dbus-menu.xml
+client-marshal.h: $(srcdir)/client-marshal.list
+ glib-genmarshal --header \
+ --prefix=_dbusmenu_client_marshal $(srcdir)/client-marshal.list \
+ > client-marshal.h
+
+client-marshal.c: $(srcdir)/client-marshal.list
+ glib-genmarshal --body \
+ --prefix=_dbusmenu_client_marshal $(srcdir)/client-marshal.list \
+ > client-marshal.c
+
server-marshal.h: $(srcdir)/server-marshal.list
glib-genmarshal --header \
--prefix=_dbusmenu_server_marshal $(srcdir)/server-marshal.list \
diff --git a/libdbusmenu-glib/client-marshal.list b/libdbusmenu-glib/client-marshal.list
new file mode 100644
index 0000000..34e3956
--- /dev/null
+++ b/libdbusmenu-glib/client-marshal.list
@@ -0,0 +1 @@
+VOID: OBJECT, UINT
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index 7c73b7b..cc91b32 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -41,6 +41,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include "client-menuitem.h"
#include "dbusmenu-client.h"
#include "server-marshal.h"
+#include "client-marshal.h"
/* Properties */
enum {
@@ -54,6 +55,7 @@ enum {
LAYOUT_UPDATED,
ROOT_CHANGED,
NEW_MENUITEM,
+ ITEM_ACTIVATE,
LAST_SIGNAL
};
@@ -123,6 +125,7 @@ static void update_layout (DbusmenuClient * client);
static void menuitem_get_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data);
static void get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, org_ayatana_dbusmenu_get_properties_reply callback, gpointer user_data);
static GQuark error_domain (void);
+static void item_activated (DBusGProxy * proxy, gint id, guint timestamp, DbusmenuClient * client);
/* Build a type */
G_DEFINE_TYPE (DbusmenuClient, dbusmenu_client, G_TYPE_OBJECT);
@@ -187,6 +190,22 @@ dbusmenu_client_class_init (DbusmenuClientClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
+ /**
+ DbusmenuClient::item-activate:
+ @arg0: The #DbusmenuClient object
+ @arg1: The #DbusmenuMenuitem activated
+ @arg2: A timestamp that the event happened at
+
+ Signaled when the server wants to activate an item in
+ order to display the menu.
+ */
+ signals[ITEM_ACTIVATE] = g_signal_new(DBUSMENU_CLIENT_SIGNAL_ITEM_ACTIVATE,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DbusmenuClientClass, item_activate),
+ NULL, NULL,
+ _dbusmenu_client_marshal_VOID__OBJECT_UINT,
+ G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
g_object_class_install_property (object_class, PROP_DBUSOBJECT,
g_param_spec_string(DBUSMENU_CLIENT_PROP_DBUS_OBJECT, "DBus Object we represent",
@@ -582,6 +601,28 @@ get_properties_globber (DbusmenuClient * client, gint id, const gchar ** propert
return;
}
+/* Called when a server item wants to activate the menu */
+static void
+item_activated (DBusGProxy * proxy, gint id, guint timestamp, DbusmenuClient * client)
+{
+ DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+
+ if (priv->root == NULL) {
+ g_warning("Asked to activate item %d when we don't have a menu structure.", id);
+ return;
+ }
+
+ DbusmenuMenuitem * menuitem = dbusmenu_menuitem_find_id(priv->root, id);
+ if (menuitem == NULL) {
+ g_warning("Unable to find menu item %d to activate.", id);
+ return;
+ }
+
+ g_signal_emit(G_OBJECT(client), signals[ITEM_ACTIVATE], 0, menuitem, timestamp, TRUE);
+
+ return;
+}
+
/* Annoying little wrapper to make the right function update */
static void
layout_update (DBusGProxy * proxy, guint revision, gint parent, DbusmenuClient * client)
@@ -821,6 +862,10 @@ build_proxies (DbusmenuClient * client)
dbus_g_proxy_add_signal(priv->menuproxy, "ItemUpdated", G_TYPE_INT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(priv->menuproxy, "ItemUpdated", G_CALLBACK(id_update), client, NULL);
+ 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, "ItemActivationRequested", G_TYPE_INT, G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->menuproxy, "ItemActivationRequested", G_CALLBACK(item_activated), client, NULL);
+
update_layout(client);
return;
@@ -1126,6 +1171,9 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
/* g_debug("Looking at child: %d", position); */
gint childid = parse_node_get_id(children);
if (childid < 0) {
+ /* Don't increment the position when there isn't a valid
+ node in the XML tree. It's probably a comment. */
+ position--;
continue;
}
DbusmenuMenuitem * childmi = NULL;
@@ -1143,11 +1191,17 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
}
if (childmi == NULL) {
+ #ifdef MASSIVEDEBUGGING
+ g_debug("Building new menu item %d at position %d", childid, position);
+ #endif
/* If we can't recycle, then we build a new one */
childmi = parse_layout_new_child(childid, client, item);
dbusmenu_menuitem_child_add_position(item, childmi, position);
g_object_unref(childmi);
} else {
+ #ifdef MASSIVEDEBUGGING
+ g_debug("Recycling menu item %d at position %d", childid, position);
+ #endif
/* If we can recycle, make sure it's in the right place */
dbusmenu_menuitem_child_reorder(item, childmi, position);
parse_layout_update(childmi, client);
@@ -1175,6 +1229,19 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it
children = node->children;
GList * childmis = dbusmenu_menuitem_get_children(item);
while (children != NULL && childmis != NULL) {
+ gint xmlid = parse_node_get_id(children);
+ /* If this isn't a valid menu item we need to move on
+ until we have one. This avoids things like comments. */
+ if (xmlid < 0) {
+ children = children->next;
+ continue;
+ }
+
+ #ifdef MASSIVEDEBUGGING
+ gint miid = dbusmenu_menuitem_get_id(DBUSMENU_MENUITEM(childmis->data));
+ g_debug("Recursing parse_layout_xml. XML ID: %d MI ID: %d", xmlid, miid);
+ #endif
+
parse_layout_xml(client, children, DBUSMENU_MENUITEM(childmis->data), item, proxy);
children = children->next;
diff --git a/libdbusmenu-glib/client.h b/libdbusmenu-glib/client.h
index 2b76f5e..6ca2232 100644
--- a/libdbusmenu-glib/client.h
+++ b/libdbusmenu-glib/client.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
#define DBUSMENU_CLIENT_SIGNAL_LAYOUT_UPDATED "layout-updated"
#define DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED "root-changed"
#define DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM "new-menuitem"
+#define DBUSMENU_CLIENT_SIGNAL_ITEM_ACTIVATE "item-activate"
#define DBUSMENU_CLIENT_PROP_DBUS_NAME "dbus-name"
#define DBUSMENU_CLIENT_PROP_DBUS_OBJECT "dbus-object"
@@ -59,10 +60,10 @@ G_BEGIN_DECLS
@parent_class: #GObjectClass
@layout_updated: Slot for #DbusmenuClient::layout-updated.
@new_menuitem: Slot for #DbusmenuClient::new-menuitem.
+ @item_activate: Slote for #DbusmenuClient::item-activate.
@reserved1: Reserved for future use.
@reserved2: Reserved for future use.
@reserved3: Reserved for future use.
- @reserved4: Reserved for future use.
A simple class that takes all of the information from a
#DbusmenuServer over DBus and makes the same set of
@@ -75,12 +76,13 @@ struct _DbusmenuClientClass {
void (*layout_updated)(void);
void (*root_changed) (DbusmenuMenuitem * newroot);
void (*new_menuitem) (DbusmenuMenuitem * newitem);
+ void (*item_activate) (DbusmenuMenuitem * item, guint timestamp);
/* Reserved for future use */
void (*reserved1) (void);
void (*reserved2) (void);
void (*reserved3) (void);
- void (*reserved4) (void);
+ /* void (*reserved4) (void); */
};
/**
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index b5b509f..da81544 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -54,6 +54,7 @@ static void new_menuitem (DbusmenuClient * client, DbusmenuMenuitem * mi, gpoint
static void new_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position, DbusmenuGtkClient * gtkclient);
static void delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, DbusmenuGtkClient * gtkclient);
static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint new, guint old, DbusmenuGtkClient * gtkclient);
+static void item_activate (DbusmenuClient * client, DbusmenuMenuitem * mi, guint timestamp, gpointer userdata);
static gboolean new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
@@ -91,7 +92,9 @@ dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_DEFAULT, new_item_normal);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_SEPARATOR, new_item_seperator);
+ /* TODO: I think these can be handled in the class... */
g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL);
+ g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_ITEM_ACTIVATE, G_CALLBACK(item_activate), NULL);
return;
}
@@ -431,6 +434,31 @@ new_menuitem (DbusmenuClient * client, DbusmenuMenuitem * mi, gpointer userdata)
return;
}
+/* Signaled when we should show a menuitem at request of the application
+ that it is in. */
+static void
+item_activate (DbusmenuClient * client, DbusmenuMenuitem * mi, guint timestamp, gpointer userdata)
+{
+ gpointer pmenu = g_object_get_data(G_OBJECT(mi), data_menu);
+ if (pmenu == NULL) {
+ g_warning("Activated menu item doesn't have a menu? ID: %d", dbusmenu_menuitem_get_id(mi));
+ return;
+ }
+
+ GtkWidget * parent = gtk_widget_get_parent(GTK_WIDGET(pmenu));
+ if (parent == NULL) {
+ g_warning("Activated menu item's menu doesn't have a parent? ID: %d", dbusmenu_menuitem_get_id(mi));
+ return;
+ }
+
+ if (!gtk_widget_mnemonic_activate(parent, FALSE)) {
+ g_warning("Unable to activate item: %d", dbusmenu_menuitem_get_id(mi));
+ return;
+ }
+
+ return;
+}
+
#ifdef MASSIVEDEBUGGING
static void
destroy_gmi (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
diff --git a/tests/test-glib-properties-client.c b/tests/test-glib-properties-client.c
index 434465a..ae7b80b 100644
--- a/tests/test-glib-properties-client.c
+++ b/tests/test-glib-properties-client.c
@@ -121,7 +121,7 @@ static void
layout_updated (DbusmenuClient * client, gpointer data)
{
g_debug("Layout Updated");
- g_timeout_add (250, layout_verify_timer, client);
+ g_timeout_add (500, layout_verify_timer, client);
return;
}