← Back to team overview

ayatana-commits team mailing list archive

[Branch ~dbusmenu-team/dbusmenu/trunk] Rev 91: Merging in support for sending AboutToShow events.

 

Merge authors:
  Aurélien Gâteau (agateau)
  Ted Gould (ted)
Related merge proposals:
  https://code.launchpad.net/~agateau/dbusmenu/about-to-show/+merge/20570
  proposed by: Aurélien Gâteau (agateau)
  review: Needs Information - David Barth (dbarth)
------------------------------------------------------------
revno: 91 [merge]
committer: Ted Gould <ted@xxxxxxxx>
branch nick: trunk
timestamp: Wed 2010-03-31 13:58:29 -0500
message:
  Merging in support for sending AboutToShow events.
modified:
  libdbusmenu-glib/client-menuitem.c
  libdbusmenu-glib/client.c
  libdbusmenu-glib/client.h
  libdbusmenu-glib/dbus-menu.xml
  libdbusmenu-glib/menuitem.c
  libdbusmenu-glib/menuitem.h
  libdbusmenu-glib/server.c
  libdbusmenu-gtk/client.c
  libdbusmenu-gtk/menu.c


--
lp:dbusmenu
https://code.launchpad.net/~dbusmenu-team/dbusmenu/trunk

Your team ayatana-commits is subscribed to branch lp:dbusmenu.
To unsubscribe from this branch go to https://code.launchpad.net/~dbusmenu-team/dbusmenu/trunk/+edit-subscription
=== modified file 'libdbusmenu-glib/client-menuitem.c'
--- libdbusmenu-glib/client-menuitem.c	2010-02-04 02:45:12 +0000
+++ libdbusmenu-glib/client-menuitem.c	2010-03-31 18:47:27 +0000
@@ -46,6 +46,7 @@
 static void dbusmenu_client_menuitem_dispose    (GObject *object);
 static void dbusmenu_client_menuitem_finalize   (GObject *object);
 static void handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp);
+static void send_about_to_show (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data);
 
 G_DEFINE_TYPE (DbusmenuClientMenuitem, dbusmenu_client_menuitem, DBUSMENU_TYPE_MENUITEM);
 
@@ -61,6 +62,7 @@
 
 	DbusmenuMenuitemClass * mclass = DBUSMENU_MENUITEM_CLASS(klass);
 	mclass->handle_event = handle_event;
+	mclass->send_about_to_show = send_about_to_show;
 
 	return;
 }
@@ -88,6 +90,7 @@
 	return;
 }
 
+/* Creates the item and associates the client */
 DbusmenuClientMenuitem *
 dbusmenu_client_menuitem_new (gint id, DbusmenuClient * client)
 {
@@ -97,6 +100,7 @@
 	return mi;
 }
 
+/* Passes the event signal on through the client. */
 static void
 handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp)
 {
@@ -104,3 +108,44 @@
 	dbusmenu_client_send_event(priv->client, dbusmenu_menuitem_get_id(mi), name, value, timestamp);
 	return;
 }
+
+typedef struct _about_to_show_t about_to_show_t;
+struct _about_to_show_t {
+	DbusmenuMenuitem * mi;
+	dbusmenu_menuitem_about_to_show_cb cb;
+	gpointer cb_data;
+};
+
+/* Handles calling the callback that we were called with */
+static void
+about_to_show_cb (gpointer user_data)
+{
+	about_to_show_t * data = (about_to_show_t *)user_data;
+
+	data->cb(data->mi, data->cb_data);
+
+	g_object_unref(data->mi);
+	g_free(user_data);
+	return;
+}
+
+/* Passes the about to show signal on through the client. */
+static void
+send_about_to_show (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data)
+{
+	DbusmenuClientMenuitemPrivate * priv = DBUSMENU_CLIENT_MENUITEM_GET_PRIVATE(mi);
+	if (cb == NULL) {
+		/* Common enough that we don't want to bother
+		   with the allocation */
+		dbusmenu_client_send_about_to_show(priv->client, dbusmenu_menuitem_get_id(mi), NULL, NULL);
+	} else {
+		about_to_show_t * data = g_new0(about_to_show_t, 1);
+		data->mi = mi;
+		data->cb = cb;
+		data->cb_data = cb_data;
+		g_object_ref(mi);
+
+		dbusmenu_client_send_about_to_show(priv->client, dbusmenu_menuitem_get_id(mi), about_to_show_cb, data);
+	}
+	return;
+}

=== modified file 'libdbusmenu-glib/client.c'
--- libdbusmenu-glib/client.c	2010-03-31 13:59:36 +0000
+++ libdbusmenu-glib/client.c	2010-03-31 18:51:48 +0000
@@ -668,6 +668,8 @@
 	return;
 }
 
+/* Sends the event over DBus to the server on the other side
+   of the bus. */
 void
 dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name, const GValue * value, guint timestamp)
 {
@@ -676,6 +678,58 @@
 	return;
 }
 
+typedef struct _about_to_show_t about_to_show_t;
+struct _about_to_show_t {
+	DbusmenuClient * client;
+	void (*cb) (gpointer data);
+	gpointer cb_data;
+};
+
+/* Reports errors and responds to update request that were a result
+   of sending the about to show signal. */
+static void
+about_to_show_cb (DBusGProxy * proxy, gboolean need_update, GError * error, gpointer userdata)
+{
+	about_to_show_t * data = (about_to_show_t *)userdata;
+
+	if (error != NULL) {
+		g_warning("Unable to send about_to_show: %s", error->message);
+		/* Note: we're just ensuring only the callback gets called */
+		need_update = FALSE;
+	}
+
+	/* If we need to update, do that first. */
+	if (need_update) {
+		update_layout(data->client);
+	}
+
+	if (data->cb != NULL) {
+		data->cb(data->cb_data);
+	}
+
+	g_object_unref(data->client);
+	g_free(data);
+
+	return;
+}
+
+/* Sends the about to show signal for a given id to the
+   server on the other side of DBus */
+void
+dbusmenu_client_send_about_to_show(DbusmenuClient * client, gint id, void (*cb)(gpointer data), gpointer cb_data)
+{
+	DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
+
+	about_to_show_t * data = g_new0(about_to_show_t, 1);
+	data->client = client;
+	data->cb = cb;
+	data->cb_data = cb_data;
+	g_object_ref(client);
+
+	org_ayatana_dbusmenu_about_to_show_async (priv->menuproxy, id, about_to_show_cb, data);
+	return;
+}
+
 /* Parse recursively through the XML and make it into
    objects as need be */
 static DbusmenuMenuitem *

=== modified file 'libdbusmenu-glib/client.h'
--- libdbusmenu-glib/client.h	2010-02-04 17:59:00 +0000
+++ libdbusmenu-glib/client.h	2010-03-31 18:47:27 +0000
@@ -109,6 +109,10 @@
                                                         const gchar * name,
                                                         const GValue * value,
                                                         guint timestamp);
+void                 dbusmenu_client_send_about_to_show(DbusmenuClient * client,
+                                                        gint id,
+                                                        void (*cb) (gpointer user_data),
+                                                        gpointer cb_data);
 
 /**
 	SECTION:client

=== modified file 'libdbusmenu-glib/dbus-menu.xml'
--- libdbusmenu-glib/dbus-menu.xml	2010-02-04 23:56:30 +0000
+++ libdbusmenu-glib/dbus-menu.xml	2010-03-31 17:29:20 +0000
@@ -265,6 +265,23 @@
 			</arg>
 		</method>
 
+		<method name="AboutToShow">
+			<dox:d>
+			This is called by the applet to notify the application that it is about
+			to show the menu under the specified item.
+			</dox:d>
+			<arg type="i" name="id" direction="in">
+				<dox:d>
+				Which menu item represents the parent of the item about to be shown.
+				</dox:d>
+			</arg>
+			<arg type="b" name="needUpdate" direction="out">
+				<dox:d>
+				Whether this AboutToShow event should result in the menu being updated.
+				</dox:d>
+			</arg>
+		</method>
+
 <!-- Signals -->
 		<signal name="ItemPropertyUpdated">
 			<dox:d>

=== modified file 'libdbusmenu-glib/menuitem.c'
--- libdbusmenu-glib/menuitem.c	2010-03-10 07:00:02 +0000
+++ libdbusmenu-glib/menuitem.c	2010-03-31 18:51:48 +0000
@@ -1203,3 +1203,32 @@
 	}
 	return;
 }
+
+/**
+	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.
+
+	This function is used to send the even that the submenu
+	of this item is about to be shown.  Callers to this event
+	should delay showing the menu until their callback is
+	called if possible.
+*/
+void
+dbusmenu_menuitem_send_about_to_show (DbusmenuMenuitem * mi, dbusmenu_menuitem_about_to_show_cb cb, gpointer cb_data)
+{
+	g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
+	#ifdef MASSIVEDEBUGGING
+	g_debug("Submenu for menuitem %d (%s) is about to be shown", ID(mi), LABEL(mi));
+	#endif
+	DbusmenuMenuitemClass * class = DBUSMENU_MENUITEM_GET_CLASS(mi);
+
+	if (class->send_about_to_show != NULL) {
+		return class->send_about_to_show(mi, cb, cb_data);
+	} else if (cb != NULL) {
+		cb(mi, cb_data);
+	}
+
+	return;
+}

=== modified file 'libdbusmenu-glib/menuitem.h'
--- libdbusmenu-glib/menuitem.h	2010-03-18 05:01:40 +0000
+++ libdbusmenu-glib/menuitem.h	2010-03-31 18:51:48 +0000
@@ -85,6 +85,17 @@
 };
 
 /**
+	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.
+*/
+typedef void (*dbusmenu_menuitem_about_to_show_cb) (DbusmenuMenuitem * mi, gpointer user_data);
+
+
+/**
 	DbusmenuMenuitemClass:
 	@property_changed: Slot for #DbusmenuMenuitem::property-changed.
 	@item_activated: Slot for #DbusmenuMenuitem::item-activated.
@@ -97,6 +108,8 @@
 	@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.
@@ -118,9 +131,10 @@
 	/* Virtual functions */
 	void (*buildxml) (GPtrArray * stringarray);
 	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 (*reserved2) (void);
+	/* void (*reserved2) (void); */
 	/* void (*reserved3) (void); */
 	/* void (*reserved4) (void); -- realized, realloc when bumping lib version */
 };
@@ -161,6 +175,7 @@
 
 void dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem * mi, gpointer data), gpointer data);
 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);
 
 /**
 	SECTION:menuitem

=== modified file 'libdbusmenu-glib/server.c'
--- libdbusmenu-glib/server.c	2010-02-18 16:27:53 +0000
+++ libdbusmenu-glib/server.c	2010-03-31 17:29:20 +0000
@@ -41,6 +41,7 @@
 static gboolean _dbusmenu_server_get_group_properties (DbusmenuServer * server, GArray * ids, GArray * properties, GHashTable ** values, GError ** error);
 static gboolean _dbusmenu_server_event (DbusmenuServer * server, gint id, gchar * eventid, GValue * data, guint timestamp, GError ** error);
 static gboolean _dbusmenu_server_get_children (DbusmenuServer * server, gint id, GPtrArray * properties, GPtrArray ** output, GError ** error);
+static gboolean _dbusmenu_server_about_to_show (DbusmenuServer * server, gint id, gboolean * need_update, GError ** error);
 
 #include "dbusmenu-server.h"
 
@@ -578,6 +579,29 @@
 	return TRUE;
 }
 
+/* Recieve the About To Show function.  Pass it to our menu item. */
+static gboolean
+_dbusmenu_server_about_to_show (DbusmenuServer * server, gint id, gboolean * need_update, GError ** error)
+{
+	DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server);
+	DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id);
+
+	if (mi == NULL) {
+		if (error != NULL) {
+			g_set_error(error,
+			            error_quark(),
+			            INVALID_MENUITEM_ID,
+			            "The ID supplied %d does not refer to a menu item we have",
+			            id);
+		}
+		return FALSE;
+	}
+
+	/* GTK+ does not support about-to-show concept for now */
+	*need_update = FALSE;
+	return TRUE;
+}
+
 /* Public Interface */
 /**
 	dbusmenu_server_new:

=== modified file 'libdbusmenu-gtk/client.c'
--- libdbusmenu-gtk/client.c	2010-03-24 17:33:45 +0000
+++ libdbusmenu-gtk/client.c	2010-03-31 18:51:48 +0000
@@ -109,10 +109,16 @@
 static gboolean
 menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
 {
-	GValue value = {0};
-	g_value_init(&value, G_TYPE_INT);
-	g_value_set_int(&value, 0);
-	dbusmenu_menuitem_handle_event(mi, "clicked", &value, gtk_get_current_event_time());
+	if (gtk_menu_item_get_submenu(gmi) == NULL) {
+		GValue value = {0};
+		g_value_init(&value, G_TYPE_INT);
+		g_value_set_int(&value, 0);
+		dbusmenu_menuitem_handle_event(mi, "clicked", &value, gtk_get_current_event_time());
+	} else {
+		/* TODO: We need to stop the display of the submenu
+		         until this callback returns. */
+		dbusmenu_menuitem_send_about_to_show(mi, NULL, NULL);
+	}
 	return TRUE;
 }
 

=== modified file 'libdbusmenu-gtk/menu.c'
--- libdbusmenu-gtk/menu.c	2009-10-05 14:00:34 +0000
+++ libdbusmenu-gtk/menu.c	2010-03-31 18:49:32 +0000
@@ -96,6 +96,18 @@
 }
 
 static void
+menu_focus_cb(DbusmenuGtkMenu * menu, gpointer userdata)
+{
+	DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu);
+	if (priv->client != NULL) {
+		/* TODO: We should stop the display of the menu
+		         until the about to show call returns. */
+		dbusmenu_client_send_about_to_show(DBUSMENU_CLIENT(priv->client), 0, NULL, NULL);
+	}
+	return;
+}
+
+static void
 dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self)
 {
 	DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(self);
@@ -105,6 +117,8 @@
 	priv->dbus_object = NULL;
 	priv->dbus_name = NULL;
 
+	g_signal_connect(G_OBJECT(self), "focus", G_CALLBACK(menu_focus_cb), self);
+
 	return;
 }