diff options
Diffstat (limited to 'libdbusmenu-gtk/menu.c')
-rw-r--r-- | libdbusmenu-gtk/menu.c | 99 |
1 files changed, 76 insertions, 23 deletions
diff --git a/libdbusmenu-gtk/menu.c b/libdbusmenu-gtk/menu.c index 4fa546b..236a596 100644 --- a/libdbusmenu-gtk/menu.c +++ b/libdbusmenu-gtk/menu.c @@ -44,16 +44,15 @@ enum { }; /* Private */ -typedef struct _DbusmenuGtkMenuPrivate DbusmenuGtkMenuPrivate; struct _DbusmenuGtkMenuPrivate { DbusmenuGtkClient * client; + DbusmenuMenuitem * root; gchar * dbus_object; gchar * dbus_name; }; -#define DBUSMENU_GTKMENU_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuPrivate)) +#define DBUSMENU_GTKMENU_GET_PRIVATE(o) (DBUSMENU_GTKMENU(o)->priv) /* Prototypes */ static void dbusmenu_gtkmenu_class_init (DbusmenuGtkMenuClass *klass); @@ -65,6 +64,8 @@ static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * /* Internal */ static void build_client (DbusmenuGtkMenu * self); static void child_realized (DbusmenuMenuitem * child, gpointer userdata); +static void remove_child_signals (gpointer data, gpointer user_data); +static void root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu); /* GObject Stuff */ G_DEFINE_TYPE (DbusmenuGtkMenu, dbusmenu_gtkmenu, GTK_TYPE_MENU); @@ -102,7 +103,7 @@ menu_focus_cb(DbusmenuGtkMenu * menu, gpointer userdata) 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); + dbusmenu_menuitem_send_about_to_show(priv->root, NULL, NULL); } return; } @@ -110,6 +111,8 @@ menu_focus_cb(DbusmenuGtkMenu * menu, gpointer userdata) static void dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuPrivate); + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(self); priv->client = NULL; @@ -127,6 +130,12 @@ dbusmenu_gtkmenu_dispose (GObject *object) { DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(object); + /* Remove signals from the root */ + if (priv->root != NULL) { + /* This will clear the root */ + root_changed(priv->client, NULL, DBUSMENU_GTKMENU(object)); + } + if (priv->client != NULL) { g_object_unref(G_OBJECT(priv->client)); priv->client = NULL; @@ -237,7 +246,7 @@ root_child_added (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint posit GtkMenuItem * mi = dbusmenu_gtkclient_menuitem_get(priv->client, child); if (mi != NULL) { GtkWidget * item = GTK_WIDGET(mi); - gtk_menu_insert(GTK_MENU(menu), item, dbusmenu_menuitem_get_position_realized(child, root)); + gtk_menu_shell_insert(GTK_MENU_SHELL(menu), item, dbusmenu_menuitem_get_position_realized(child, root)); #ifdef MASSIVEDEBUGGING menu_pos_t menu_pos; menu_pos.mi = mi; @@ -271,6 +280,10 @@ root_child_delete (DbusmenuMenuitem * root, DbusmenuMenuitem * child, DbusmenuGt #ifdef MASSIVEDEBUGGING g_debug("Root child deleted"); #endif + + /* Remove signal for realized */ + remove_child_signals(child, menu); + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu); GtkWidget * item = GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)); if (item != NULL) { @@ -299,7 +312,7 @@ child_realized (DbusmenuMenuitem * child, gpointer userdata) GtkWidget * child_widget = GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)); if (child_widget != NULL) { - gtk_menu_append(menu, child_widget); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), child_widget); gtk_menu_reorder_child(GTK_MENU(menu), child_widget, dbusmenu_menuitem_get_position_realized(child, dbusmenu_client_get_root(DBUSMENU_CLIENT(priv->client)))); } else { g_warning("Child is realized, but doesn't have a GTK Widget!"); @@ -308,15 +321,55 @@ child_realized (DbusmenuMenuitem * child, gpointer userdata) return; } +/* Remove any signals we attached to children -- just realized right now */ +static void +remove_child_signals (gpointer data, gpointer user_data) +{ + g_signal_handlers_disconnect_by_func(G_OBJECT(data), child_realized, user_data); + return; +} + +/* Handler for all of the menu items on a root change to ensure that + the menus are hidden before we start going and deleting things. */ +static void +popdown_all (DbusmenuMenuitem * mi, gpointer user_data) +{ + GtkMenu * menu = dbusmenu_gtkclient_menuitem_get_submenu(DBUSMENU_GTKCLIENT(user_data), mi); + if (menu != NULL) { + gtk_menu_popdown(menu); + } + return; +} + /* When the root menuitem changes we need to resetup things so that we're back in the game. */ static void root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu) { + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu); + + /* Clear out our interest in the old root */ + if (priv->root != NULL) { + GList * children = dbusmenu_menuitem_get_children(priv->root); + g_list_foreach(children, remove_child_signals, menu); + + g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_added, menu); + g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_moved, menu); + g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), root_child_delete, menu); + + dbusmenu_menuitem_foreach(priv->root, popdown_all, client); + + g_object_unref(priv->root); + priv->root = NULL; + } + if (newroot == NULL) { gtk_widget_hide(GTK_WIDGET(menu)); return; } + priv->root = newroot; + g_object_ref(priv->root); + g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(root_child_added), menu); g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(root_child_moved), menu); g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(root_child_delete), menu); @@ -359,15 +412,15 @@ build_client (DbusmenuGtkMenu * self) /* Public API */ /** - dbusmenu_gtkmenu_new: - @dbus_name: Name of the #DbusmenuServer on DBus - @dbus_name: Name of the object on the #DbusmenuServer - - Creates a new #DbusmenuGtkMenu object and creates a #DbusmenuClient - that connects across DBus to a #DbusmenuServer. - - Return value: A new #DbusmenuGtkMenu sync'd with a server -*/ + * dbusmenu_gtkmenu_new: + * @dbus_name: Name of the #DbusmenuServer on DBus + * @dbus_object: Name of the object on the #DbusmenuServer + * + * Creates a new #DbusmenuGtkMenu object and creates a #DbusmenuClient + * that connects across DBus to a #DbusmenuServer. + * + * Return value: A new #DbusmenuGtkMenu sync'd with a server + */ DbusmenuGtkMenu * dbusmenu_gtkmenu_new (gchar * dbus_name, gchar * dbus_object) { @@ -378,14 +431,14 @@ dbusmenu_gtkmenu_new (gchar * dbus_name, gchar * dbus_object) } /** - dbusmenu_gtkmenu_get_client: - @menu: The #DbusmenuGtkMenu to get the client from - - An accessor for the client that this menu is using to - communicate with the server. - - Return value: A valid #DbusmenuGtkClient or NULL on error. -*/ + * dbusmenu_gtkmenu_get_client: + * @menu: The #DbusmenuGtkMenu to get the client from + * + * An accessor for the client that this menu is using to + * communicate with the server. + * + * Return value: (transfer none): A valid #DbusmenuGtkClient or NULL on error. + */ DbusmenuGtkClient * dbusmenu_gtkmenu_get_client (DbusmenuGtkMenu * menu) { |