diff options
-rw-r--r-- | libdbusmenu-glib/client-menuitem.c | 45 | ||||
-rw-r--r-- | libdbusmenu-glib/client.c | 54 | ||||
-rw-r--r-- | libdbusmenu-glib/client.h | 4 | ||||
-rw-r--r-- | libdbusmenu-glib/dbus-menu.xml | 17 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.c | 29 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.h | 17 | ||||
-rw-r--r-- | libdbusmenu-glib/server.c | 24 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 14 | ||||
-rw-r--r-- | libdbusmenu-gtk/menu.c | 14 |
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; } |