[gtk+/composite-templates] modelmenu: listen for toplevel changes on the attach widget



commit be2c4e895e88d31c4dcb5945249b1ea7223bb07e
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Jul 5 10:49:39 2012 -0400

    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 files changed, 49 insertions(+), 11 deletions(-)
---
diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c
index 1f12595..9dd9aa5 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);
     }
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]