From 5dbf3a576aab1bd33e6e08121690afefad19e50f Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Thu, 5 Jul 2012 10:49:39 -0400 Subject: [PATCH] modelmenu: listen for toplevel changes on the attach widget Right now, when we create a GtkModelMenu for a GMenuModel, we listen to changes to the menu's attach-widget to detect when a toplevel GtkApplicationWindow becomes available to fetch actions from it. This unfortunately breaks this simple code: GtkWidget *application_window = gtk_application_window_new(); GtkWidget *menu_button = gtk_menu_button_new(); GMenuModel *menu_model = get_menu_model(); gtk_menu_button_set_menu_model(menu_button, menu_model); gtk_container_add(GTK_CONTAINER(application_window), menu_button); Since GtkMenuButton creates a GtkModelMenu and sets itself as its attach widget before it's added to a hierarchy containing a GtkApplicationWindow. Fix the bug by simply listening for changes in the window hierarchy, and creating the menu model when the attach widget is added to an application window. https://bugzilla.gnome.org/show_bug.cgi?id=679454 --- gtk/gtkmodelmenu.c | 60 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c index 1f12595e5..9dd9aa5e4 100644 --- a/gtk/gtkmodelmenu.c +++ b/gtk/gtkmodelmenu.c @@ -29,6 +29,8 @@ #include "gtkmodelmenuitem.h" #include "gtkapplicationprivate.h" +#define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data" + typedef struct { GActionObservable *actions; GMenuModel *model; @@ -276,24 +278,60 @@ gtk_model_menu_create_menu (GMenuModel *model, } static void -notify_attach (GtkMenu *menu, - GParamSpec *pspec, - gpointer data) +gtk_model_menu_connect_app_window (GtkMenu *menu, + GtkApplicationWindow *window) { - GtkWidget *widget; - GtkWidget *toplevel; GActionObservable *actions; GtkAccelGroup *accels; - widget = gtk_menu_get_attach_widget (menu); - toplevel = gtk_widget_get_toplevel (widget); + actions = gtk_application_window_get_observable (window); + accels = gtk_application_window_get_accel_group (window); + + gtk_menu_set_accel_group (menu, accels); + gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels); +} + +static void +attach_widget_hierarchy_changed (GtkWidget *attach_widget, + GtkWidget *previous_toplevel, + gpointer user_data) +{ + GtkWidget *toplevel; + GtkMenu *menu = user_data; + + toplevel = gtk_widget_get_toplevel (attach_widget); if (GTK_IS_APPLICATION_WINDOW (toplevel)) + gtk_model_menu_connect_app_window (menu, GTK_APPLICATION_WINDOW (toplevel)); +} + +static void +notify_attach (GtkMenu *menu, + GParamSpec *pspec, + gpointer data) +{ + GtkWidget *attach_widget, *toplevel; + + attach_widget = g_object_get_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA); + if (attach_widget != NULL) { - actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel)); - accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel)); + g_signal_handlers_disconnect_by_func (attach_widget, attach_widget_hierarchy_changed, menu); + g_object_set_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA, NULL); + } + + attach_widget = gtk_menu_get_attach_widget (menu); + if (!attach_widget) + return; - gtk_menu_set_accel_group (menu, accels); - gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels); + toplevel = gtk_widget_get_toplevel (attach_widget); + if (GTK_IS_APPLICATION_WINDOW (toplevel)) + { + gtk_model_menu_connect_app_window (menu, GTK_APPLICATION_WINDOW (toplevel)); + } + else + { + g_object_set_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA, attach_widget); + g_signal_connect_object (attach_widget, "hierarchy-changed", + G_CALLBACK (attach_widget_hierarchy_changed), menu, 0); } } -- 2.43.2