diff options
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | libdbusmenu-glib/Makefile.am | 15 | ||||
-rw-r--r-- | libdbusmenu-glib/client-marshal.list | 1 | ||||
-rw-r--r-- | libdbusmenu-glib/client.c | 67 | ||||
-rw-r--r-- | libdbusmenu-glib/client.h | 6 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 28 | ||||
-rw-r--r-- | tests/test-glib-properties-client.c | 2 |
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; } |