diff options
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r-- | libdbusmenu-glib/client-menuitem.c | 45 | ||||
-rw-r--r-- | libdbusmenu-glib/client.c | 86 | ||||
-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 |
7 files changed, 215 insertions, 7 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 309a11c..f5546a2 100644 --- a/libdbusmenu-glib/client.c +++ b/libdbusmenu-glib/client.c @@ -337,7 +337,12 @@ id_prop_update (DBusGProxy * proxy, gint id, gchar * property, GValue * value, D g_return_if_fail(priv->root != NULL); DbusmenuMenuitem * menuitem = dbusmenu_menuitem_find_id(priv->root, id); - g_return_if_fail(menuitem != NULL); + if (menuitem == NULL) { + #ifdef MASSIVEDEBUGGING + g_debug("Property update '%s' on id %d which couldn't be found", property, id); + #endif + return; + } dbusmenu_menuitem_property_set_value(menuitem, property, value); @@ -444,6 +449,9 @@ proxy_destroyed (GObject * gobj_proxy, gpointer userdata) priv->layoutcall = NULL; } + priv->current_revision = 0; + priv->my_revision = 0; + build_dbus_proxy(DBUSMENU_CLIENT(userdata)); return; } @@ -660,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) { @@ -668,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 * @@ -717,7 +779,7 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it xmlNodePtr children; guint position; - GList * oldchildren = dbusmenu_menuitem_take_children(item); + GList * oldchildren = g_list_copy(dbusmenu_menuitem_get_children(item)); /* g_debug("Starting old children: %d", g_list_length(oldchildren)); */ for (children = node->children, position = 0; children != NULL; children = children->next, position++) { @@ -738,8 +800,16 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it } } - childmi = parse_layout_xml(client, children, childmi, item, proxy); - dbusmenu_menuitem_child_add_position(item, childmi, position); + DbusmenuMenuitem * newchildmi = parse_layout_xml(client, children, childmi, item, proxy); + + if (newchildmi != childmi) { + if (childmi != NULL) { + dbusmenu_menuitem_child_delete(item, childmi); + } + dbusmenu_menuitem_child_add_position(item, newchildmi, position); + } else { + dbusmenu_menuitem_child_reorder(item, childmi, position); + } } /* g_debug("Stopping old children: %d", g_list_length(oldchildren)); */ @@ -749,7 +819,7 @@ parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * it #ifdef MASSIVEDEBUGGING g_debug("Unref'ing menu item with layout update. ID: %d", dbusmenu_menuitem_get_id(oldmi)); #endif - g_object_unref(G_OBJECT(oldmi)); + dbusmenu_menuitem_child_delete(item, oldmi); } g_list_free(oldchildren); @@ -794,13 +864,17 @@ parse_layout (DbusmenuClient * client, const gchar * layout) clean up that old root */ if (oldroot != NULL) { dbusmenu_menuitem_set_root(oldroot, FALSE); - g_object_unref(oldroot); } /* If the root changed we can signal that */ g_signal_emit(G_OBJECT(client), signals[ROOT_CHANGED], 0, priv->root, TRUE); } + /* We need to unref it in this function no matter */ + if (oldroot != NULL) { + g_object_unref(oldroot); + } + return 1; } 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: |