Ted Gould has proposed merging lp:~ted/dbusmenu/show-menu-on-activate into 
lp:dbusmenu.

Requested reviews:
  DBus Menu Team (dbusmenu-team)


Opening menus when requested.  Originally I thought we'd be able to use 
activate, but that created a nice little signal loop -- oops.  Added a new 
signal to the menu item and bubble that up.
-- 
https://code.launchpad.net/~ted/dbusmenu/show-menu-on-activate/+merge/33268
Your team ayatana-commits is subscribed to branch lp:dbusmenu.
=== modified file '.bzrignore'
--- .bzrignore	2010-06-28 23:33:43 +0000
+++ .bzrignore	2010-08-20 22:08:49 +0000
@@ -188,3 +188,6 @@
 tests/test-json-server
 tests/test-json-client
 tests/test-json
+libdbusmenu-glib/client-marshal.c
+libdbusmenu-glib/client-marshal.h
+libdbusmenu-glib/libdbusmenu_glib_la-client-marshal.lo

=== modified file 'libdbusmenu-glib/Makefile.am'
--- libdbusmenu-glib/Makefile.am	2010-05-21 18:37:36 +0000
+++ libdbusmenu-glib/Makefile.am	2010-08-20 22:08:49 +0000
@@ -4,6 +4,7 @@
 EXTRA_DIST = \
 	dbusmenu-glib.pc.in \
 	dbus-menu.xml \
+	client-marshal.list \
 	menuitem-marshal.list \
 	server-marshal.list
 
@@ -32,6 +33,8 @@
 	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 @@
 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 @@
 		--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 \

=== added file 'libdbusmenu-glib/client-marshal.list'
--- libdbusmenu-glib/client-marshal.list	1970-01-01 00:00:00 +0000
+++ libdbusmenu-glib/client-marshal.list	2010-08-20 22:08:49 +0000
@@ -0,0 +1,1 @@
+VOID: OBJECT, UINT

=== modified file 'libdbusmenu-glib/client.c'
--- libdbusmenu-glib/client.c	2010-08-20 14:21:21 +0000
+++ libdbusmenu-glib/client.c	2010-08-20 22:08:49 +0000
@@ -41,6 +41,7 @@
 #include "client-menuitem.h"
 #include "dbusmenu-client.h"
 #include "server-marshal.h"
+#include "client-marshal.h"
 
 /* Properties */
 enum {
@@ -54,6 +55,7 @@
 	LAYOUT_UPDATED,
 	ROOT_CHANGED,
 	NEW_MENUITEM,
+	ITEM_ACTIVATE,
 	LAST_SIGNAL
 };
 
@@ -123,6 +125,7 @@
 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 @@
 	                                        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 @@
 	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 @@
 	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;

=== modified file 'libdbusmenu-glib/client.h'
--- libdbusmenu-glib/client.h	2010-03-31 18:47:27 +0000
+++ libdbusmenu-glib/client.h	2010-08-20 22:08:49 +0000
@@ -46,6 +46,7 @@
 #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 @@
 	@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 @@
 	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); */
 };
 
 /**

=== modified file 'libdbusmenu-glib/menuitem.c'
--- libdbusmenu-glib/menuitem.c	2010-06-08 04:00:17 +0000
+++ libdbusmenu-glib/menuitem.c	2010-08-20 22:08:49 +0000
@@ -70,6 +70,7 @@
 	CHILD_REMOVED,
 	CHILD_MOVED,
 	REALIZED,
+	SHOW_TO_USER,
 	LAST_SIGNAL
 };
 
@@ -211,6 +212,22 @@
 	                                           NULL, NULL,
 	                                           _dbusmenu_menuitem_marshal_VOID__VOID,
 	                                           G_TYPE_NONE, 0, G_TYPE_NONE);
+	/**
+		DbusmenuMenuitem::show-to-user:
+		@arg0: The #DbusmenuMenuitem which should be shown.
+		@arg1: Timestamp the event happened at
+
+		Signaled when the application would like the visualization
+		of this menu item shown to the user.  This usually requires
+		going over the bus to get it done.
+	*/
+	signals[SHOW_TO_USER] =      g_signal_new(DBUSMENU_MENUITEM_SIGNAL_SHOW_TO_USER,
+	                                           G_TYPE_FROM_CLASS(klass),
+	                                           G_SIGNAL_RUN_LAST,
+	                                           G_STRUCT_OFFSET(DbusmenuMenuitemClass, show_to_user),
+	                                           NULL, NULL,
+	                                           g_cclosure_marshal_VOID__UINT,
+	                                           G_TYPE_NONE, 1, G_TYPE_UINT, G_TYPE_NONE);
 
 	g_object_class_install_property (object_class, PROP_ID,
 	                                 g_param_spec_int(PROP_ID_S, "ID for the menu item",
@@ -1349,3 +1366,22 @@
 
 	return;
 }
+
+/**
+	dbusmenu_menuitem_show_to_user:
+	@mi: #DbusmenuMenuitem to show
+	@timestamp: The time that the user requested it to be shown
+
+	Signals that this menu item should be shown to the user.  If this is
+	server side the server will then take it and send it over the
+	bus.
+*/
+void
+dbusmenu_menuitem_show_to_user (DbusmenuMenuitem * mi, guint timestamp)
+{
+	g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
+
+	g_signal_emit(G_OBJECT(mi), signals[SHOW_TO_USER], 0, timestamp, TRUE);
+
+	return;
+}

=== modified file 'libdbusmenu-glib/menuitem.h'
--- libdbusmenu-glib/menuitem.h	2010-06-21 19:47:08 +0000
+++ libdbusmenu-glib/menuitem.h	2010-08-20 22:08:49 +0000
@@ -49,6 +49,7 @@
 #define DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED         "child-moved"
 #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_SIGNAL_SHOW_TO_USER        "show-to-user"
 
 #define DBUSMENU_MENUITEM_PROP_TYPE                  "type"
 #define DBUSMENU_MENUITEM_PROP_VISIBLE               "visible"
@@ -124,10 +125,7 @@
  * @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.
+ * @show_to_user: Slot for #DbusmenuMenuitem::show-to-user.
  */
 typedef struct _DbusmenuMenuitemClass DbusmenuMenuitemClass;
 struct _DbusmenuMenuitemClass
@@ -147,7 +145,8 @@
 	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);
 
-	void (*reserved1) (void);
+	void (*show_to_user) (DbusmenuMenuitem * mi, guint timestamp, gpointer cb_data);
+	/* void (*reserved1) (void); */
 	/* void (*reserved2) (void); */
 	/* void (*reserved3) (void); */
 	/* void (*reserved4) (void); -- realized, realloc when bumping lib version */
@@ -192,6 +191,8 @@
 void dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
 void dbusmenu_menuitem_send_about_to_show (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data);
 
+void dbusmenu_menuitem_show_to_user (DbusmenuMenuitem * mi, guint timestamp);
+
 /**
  * SECTION:menuitem
  * @short_description: A lowlevel represenation of a menuitem

=== modified file 'libdbusmenu-glib/server.c'
--- libdbusmenu-glib/server.c	2010-08-02 22:02:47 +0000
+++ libdbusmenu-glib/server.c	2010-08-20 22:08:49 +0000
@@ -410,7 +410,7 @@
 /* Called when a menu item emits its activated signal so it
    gets passed across the bus. */
 static void 
-menuitem_activated (DbusmenuMenuitem * mi, guint timestamp, DbusmenuServer * server)
+menuitem_shown (DbusmenuMenuitem * mi, guint timestamp, DbusmenuServer * server)
 {
 	g_signal_emit(G_OBJECT(server), signals[ITEM_ACTIVATION], 0, dbusmenu_menuitem_get_id(mi), timestamp, TRUE);
 	return;
@@ -425,7 +425,7 @@
 	g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(menuitem_child_removed), data);
 	g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(menuitem_child_moved), data);
 	g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menuitem_property_changed), data);
-	g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(menuitem_activated), data);
+	g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_SHOW_TO_USER, G_CALLBACK(menuitem_shown), data);
 	return;
 }
 

=== modified file 'libdbusmenu-gtk/client.c'
--- libdbusmenu-gtk/client.c	2010-07-22 08:44:33 +0000
+++ libdbusmenu-gtk/client.c	2010-08-20 22:08:49 +0000
@@ -54,6 +54,7 @@
 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_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,50 @@
 	return;
 }
 
+/* Goes through the tree of items and ensure's that all the items
+   above us are also displayed. */
+static void
+activate_helper (GtkMenuShell * shell)
+{
+	if (shell == NULL) {
+		return;
+	}
+
+	if (GTK_IS_MENU(shell)) {
+		GtkWidget * attach = gtk_menu_get_attach_widget(GTK_MENU(shell));
+
+		if (attach != NULL) {
+			GtkWidget * parent = gtk_widget_get_parent(GTK_WIDGET(attach));
+
+			if (parent != NULL) {
+				if (GTK_IS_MENU(parent)) {
+					activate_helper(GTK_MENU_SHELL(parent));
+				}
+				gtk_menu_shell_select_item(GTK_MENU_SHELL(parent), attach);
+			}
+		}
+	}
+
+	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;
+	}
+
+	activate_helper(GTK_MENU_SHELL(pmenu));
+	gtk_menu_shell_select_first(GTK_MENU_SHELL(pmenu), FALSE);
+
+	return;
+}
+
 #ifdef MASSIVEDEBUGGING
 static void
 destroy_gmi (GtkMenuItem * gmi, DbusmenuMenuitem * mi)

=== modified file 'tests/test-gtk-submenu-client.c'
--- tests/test-gtk-submenu-client.c	2010-07-22 08:44:33 +0000
+++ tests/test-gtk-submenu-client.c	2010-08-20 22:08:49 +0000
@@ -102,6 +102,12 @@
 	}
 
 	passed = TRUE;
+	return FALSE;
+}
+
+gboolean
+finished_func (gpointer user_data)
+{
 	g_main_loop_quit(mainloop);
 	return FALSE;
 }
@@ -127,7 +133,8 @@
 	gtk_window_set_title(GTK_WINDOW(window), "libdbusmenu-gtk test");
 	gtk_widget_show(window);
 
-	g_timeout_add_seconds(1, timer_func, menuitem);
+	g_timeout_add_seconds(2, timer_func, menuitem);
+	g_timeout_add_seconds(6, finished_func, menuitem);
 
 	g_debug("Entering Mainloop");
 	mainloop = g_main_loop_new(NULL, FALSE);

=== modified file 'tests/test-gtk-submenu-server.c'
--- tests/test-gtk-submenu-server.c	2010-07-22 19:05:53 +0000
+++ tests/test-gtk-submenu-server.c	2010-08-20 22:08:49 +0000
@@ -39,6 +39,17 @@
   return FALSE;
 }
 
+static gboolean
+show_item (gpointer pmi)
+{
+	DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(pmi);
+	g_debug("Showing item");
+
+	dbusmenu_menuitem_show_to_user(mi, 0);
+
+	return FALSE;
+}
+
 DbusmenuMenuitem *
 add_item(DbusmenuMenuitem * parent, const char * label)
 {
@@ -81,12 +92,16 @@
 	add_item(item, "1.2");
 	add_item(item, "1.3");
 
+	g_timeout_add_seconds(2, show_item, item);
+
 	item = add_item(root, "Folder 2");
 	add_item(item, "2.1");
 	add_item(item, "2.2");
 	add_item(item, "2.3");
 
-        g_timeout_add_seconds(3, timer_func, NULL);
+	g_timeout_add_seconds(4, show_item, item);
+
+    g_timeout_add_seconds(6, timer_func, NULL);
 
 	mainloop = g_main_loop_new(NULL, FALSE);
 	g_main_loop_run(mainloop);

_______________________________________________
Mailing list: https://launchpad.net/~ayatana-commits
Post to     : ayatana-commits@lists.launchpad.net
Unsubscribe : https://launchpad.net/~ayatana-commits
More help   : https://help.launchpad.net/ListHelp

Reply via email to