aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdbusmenu-glib/client-menuitem.c45
-rw-r--r--libdbusmenu-glib/client.c54
-rw-r--r--libdbusmenu-glib/client.h4
-rw-r--r--libdbusmenu-glib/dbus-menu.xml17
-rw-r--r--libdbusmenu-glib/menuitem.c29
-rw-r--r--libdbusmenu-glib/menuitem.h17
-rw-r--r--libdbusmenu-glib/server.c24
-rw-r--r--libdbusmenu-gtk/client.c14
-rw-r--r--libdbusmenu-gtk/menu.c14
9 files changed, 213 insertions, 5 deletions
diff --git a/libdbusmenu-glib/client-menuitem.c b/libdbusmenu-glib/client-menuitem.c
index 5d16a66..979cf79 100644
--- a/libdbusmenu-glib/client-menuitem.c
+++ b/libdbusmenu-glib/client-menuitem.c
@@ -46,6 +46,7 @@ static void dbusmenu_client_menuitem_init (DbusmenuClientMenuitem *self);
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 @@ dbusmenu_client_menuitem_class_init (DbusmenuClientMenuitemClass *klass)
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 @@ dbusmenu_client_menuitem_finalize (GObject *object)
return;
}
+/* Creates the item and associates the client */
DbusmenuClientMenuitem *
dbusmenu_client_menuitem_new (gint id, DbusmenuClient * client)
{
@@ -97,6 +100,7 @@ dbusmenu_client_menuitem_new (gint id, DbusmenuClient * client)
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 @@ handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, g
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;
+}
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c
index fb2a2bc..09a663a 100644
--- a/libdbusmenu-glib/client.c
+++ b/libdbusmenu-glib/client.c
@@ -668,6 +668,8 @@ menuitem_call_cb (DBusGProxy * proxy, GError * error, gpointer userdata)
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 @@ dbusmenu_client_send_event (DbusmenuClient * client, gint id, const gchar * name
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 *
diff --git a/libdbusmenu-glib/client.h b/libdbusmenu-glib/client.h
index 3909578..2b76f5e 100644
--- a/libdbusmenu-glib/client.h
+++ b/libdbusmenu-glib/client.h
@@ -109,6 +109,10 @@ void dbusmenu_client_send_event (DbusmenuClient * client,
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
diff --git a/libdbusmenu-glib/dbus-menu.xml b/libdbusmenu-glib/dbus-menu.xml
index 9af78fa..e5b0efb 100644
--- a/libdbusmenu-glib/dbus-menu.xml
+++ b/libdbusmenu-glib/dbus-menu.xml
@@ -265,6 +265,23 @@ License version 3 and version 2.1 along with this program. If not, see
</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>
diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c
index 28d3134..fce8ed5 100644
--- a/libdbusmenu-glib/menuitem.c
+++ b/libdbusmenu-glib/menuitem.c
@@ -1203,3 +1203,32 @@ dbusmenu_menuitem_handle_event (DbusmenuMenuitem * mi, const gchar * name, const
}
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;
+}
diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h
index 04fd911..cb6b8f4 100644
--- a/libdbusmenu-glib/menuitem.h
+++ b/libdbusmenu-glib/menuitem.h
@@ -85,6 +85,17 @@ 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.
+*/
+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 @@ struct _DbusmenuMenuitem
@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 @@ struct _DbusmenuMenuitemClass
/* 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 @@ gboolean dbusmenu_menuitem_get_root (DbusmenuMenuitem * mi);
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
diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c
index f6dddf1..d87c024 100644
--- a/libdbusmenu-glib/server.c
+++ b/libdbusmenu-glib/server.c
@@ -41,6 +41,7 @@ static gboolean _dbusmenu_server_get_properties (DbusmenuServer * server, gint i
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 @@ _dbusmenu_server_event (DbusmenuServer * server, gint id, gchar * eventid, GValu
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:
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 98f1cb2..3de42fe 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -109,10 +109,16 @@ static const gchar * data_menu = "dbusmenugtk-data-gtkmenu";
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;
}
diff --git a/libdbusmenu-gtk/menu.c b/libdbusmenu-gtk/menu.c
index d2a8620..103ecfe 100644
--- a/libdbusmenu-gtk/menu.c
+++ b/libdbusmenu-gtk/menu.c
@@ -96,6 +96,18 @@ dbusmenu_gtkmenu_class_init (DbusmenuGtkMenuClass *klass)
}
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 @@ dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self)
priv->dbus_object = NULL;
priv->dbus_name = NULL;
+ g_signal_connect(G_OBJECT(self), "focus", G_CALLBACK(menu_focus_cb), self);
+
return;
}