Cody Russell has proposed merging lp:~bratsche/appmenu-gtk/window-registration 
into lp:appmenu-gtk.

Requested reviews:
  Canonical Desktop Experience Team (canonical-dx-team)


This changes several things:
  register toplevel window XID with the service
  maintains multiple root DbusmenuMenuitems
  tries to manage visibility of items more smartly, particularly in apps that 
change out entire menubars (such as shotwell)
-- 
https://code.launchpad.net/~bratsche/appmenu-gtk/window-registration/+merge/26547
Your team ayatana-commits is subscribed to branch lp:appmenu-gtk.
=== modified file 'src/bridge.c'
--- src/bridge.c	2010-05-27 20:02:28 +0000
+++ src/bridge.c	2010-06-01 22:22:21 +0000
@@ -28,6 +28,8 @@
 #include <dbus/dbus-glib-bindings.h>
 
 #include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
 #include <libdbusmenu-glib/menuitem.h>
 #include <libdbusmenu-glib/server.h>
 
@@ -47,12 +49,14 @@
 struct _AppMenuBridgePrivate
 {
   GHashTable *items;      /* <GtkWidget *, DbusmenuMenuitem *> */
-  GHashTable *unparented; /* <GtkWidget *, DbusmenuMenuitem *> */
 
   DbusmenuServer   *server;
   DbusmenuMenuitem *root;
 };
 
+static DBusGProxy *dbusproxy = NULL;
+static gboolean    registered = FALSE;
+
 G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, GTK_TYPE_MENU_PROXY)
 
 static void
@@ -64,10 +68,6 @@
   bridge->priv->items = g_hash_table_new (g_direct_hash, g_direct_equal);
 
   bridge->priv->server = dbusmenu_server_new (APP_MENU_PATH);
-  bridge->priv->root = dbusmenu_menuitem_new ();
-
-  dbusmenu_server_set_root (bridge->priv->server,
-                            bridge->priv->root);
 }
 
 static void
@@ -180,9 +180,70 @@
                                            DBUSMENU_MENUITEM_PROP_VISIBLE,
                                            gtk_widget_get_visible (widget));
     }
-  else if (pspec->name == g_intern_static_string ("parent-set"))
+}
+
+static void
+toplevel_realized (GtkWidget *widget,
+                   gpointer   user_data)
+{
+  /* Register the toplevel window now that it's been realized. */
+  org_ayatana_WindowMenu_Registrar_register_window (dbusproxy,
+                                                    GDK_WINDOW_XID (gtk_widget_get_window (widget)),
+                                                    APP_MENU_PATH,
+                                                    NULL);
+  registered = TRUE;
+}
+
+static void
+toplevel_notify_cb (GtkWidget    *widget,
+                    GParamSpec   *pspec,
+                    GtkMenuProxy *proxy)
+{
+  if (pspec->name == g_intern_static_string ("parent"))
     {
-      g_print (" ** parent set!!\n");
+      AppMenuBridge *bridge = APP_MENU_BRIDGE (proxy);
+      DbusmenuMenuitem *root = g_hash_table_lookup (bridge->priv->items, widget);
+
+      if (root)
+        {
+          dbusmenu_server_set_root (bridge->priv->server, root);
+        }
+
+      if (!registered)
+        {
+          GtkWidget *parent = gtk_widget_get_toplevel (widget);
+
+          if (!GTK_IS_WINDOW (parent))
+            {
+              /* The current toplevel widget is not our final toplevel widget, as it's
+               * not a GtkWindow.  Let's defer registration until we have a real toplevel.
+               */
+              g_signal_connect (G_OBJECT (parent),
+                                "notify",
+                                G_CALLBACK (toplevel_notify_cb),
+                                proxy);
+
+              return;
+            }
+          else
+            {
+              /* This is the real toplevel window widget.  If it's already
+               * realized then go ahead and register it, otherwise wait until
+               * it's been realized.
+               */
+              if (gtk_widget_get_realized (widget)) {
+                org_ayatana_WindowMenu_Registrar_register_window (dbusproxy,
+                                                                  GDK_WINDOW_XID (gtk_widget_get_window (widget)),
+                                                                  APP_MENU_PATH,
+                                                                  NULL);
+                registered = TRUE;
+              } else {
+                g_signal_connect (parent, "realize",
+                                  G_CALLBACK (toplevel_realized),
+                                  NULL);
+              }
+            }
+        }
     }
 }
 
@@ -192,47 +253,73 @@
                         GtkWidget    *child,
                         guint         position)
 {
-  AppMenuBridge    *bridge;
-  DbusmenuMenuitem *item;
-  GtkWidget        *submenu;
-  DbusmenuMenuitem *parent_item = NULL;
-
-  if (GTK_IS_TEAROFF_MENU_ITEM (child) || GTK_IS_MENU (child))
-    return;
-
-  if (!gtk_widget_get_visible (child))
-    return;
-
+  AppMenuBridge        *bridge;
+  AppMenuBridgePrivate *priv;
+  DbusmenuMenuitem     *item;
+  DbusmenuMenuitem     *parent_item = NULL;
+  gboolean              append = FALSE;
+
+  if (GTK_IS_TEAROFF_MENU_ITEM (child))
+    return;
 
   bridge = APP_MENU_BRIDGE (proxy);
+  priv = bridge->priv;
+
+  if (g_hash_table_lookup (bridge->priv->items, child) != NULL)
+    return;
 
   if (GTK_IS_MENU_BAR (parent))
     {
-      if (!g_hash_table_lookup (bridge->priv->items, parent))
-        {
-          g_hash_table_insert (bridge->priv->items, parent, bridge->priv->root);
-        }
-
-      parent_item = bridge->priv->root;
+      if (g_hash_table_lookup (bridge->priv->items, parent) == NULL)
+        {
+          DbusmenuMenuitem *root = dbusmenu_menuitem_new ();
+          g_hash_table_insert (bridge->priv->items, parent, root);
+          parent_item = root;
+        }
+      else
+        {
+          parent_item = g_hash_table_lookup (bridge->priv->items, parent);
+        }
+
+      GtkWidget *toplevel = gtk_widget_get_toplevel (parent);
+
+      g_signal_connect (G_OBJECT (toplevel),
+                        "notify",
+                        G_CALLBACK (toplevel_notify_cb),
+                        proxy);
+
+      append = TRUE;
     }
   else if (GTK_IS_MENU (parent))
     {
-      GtkWidget *attached_to;
-
-      g_object_get (parent,
-                    "attach-widget", &attached_to,
-                    NULL);
-
-      if (attached_to)
-        {
-          parent_item = g_hash_table_lookup (bridge->priv->items, attached_to);
+      GtkWidget *attach;
+
+      g_object_get (parent, "attach-widget", &attach, NULL);
+
+      if (attach == NULL)
+        return;
+
+      if (g_hash_table_lookup (bridge->priv->items, parent) != NULL)
+        {
+          parent_item = g_hash_table_lookup (bridge->priv->items, parent);
+        }
+      else
+        {
+          if (g_hash_table_lookup (bridge->priv->items, attach) != NULL)
+            {
+              parent_item = g_hash_table_lookup (bridge->priv->items, attach);
+            }
+          else
+            {
+              // XXX insert the attach item?
+            }
         }
     }
 
   if (GTK_IS_MENU_ITEM (child))
     {
       item = dbusmenu_menuitem_new ();
-      g_hash_table_insert (bridge->priv->items, child, item); // move to end?
+      g_hash_table_insert (bridge->priv->items, child, item);
 
       if (GTK_IS_SEPARATOR_MENU_ITEM (child))
         {
@@ -246,39 +333,28 @@
                                           "label",
                                           get_menu_label_text (child));
 
-          if (!gtk_menu_item_get_submenu (GTK_MENU_ITEM (child)))
+          dbusmenu_menuitem_property_set_bool (item,
+                                               DBUSMENU_MENUITEM_PROP_ENABLED,
+                                               gtk_widget_get_sensitive (child));
+
+          g_signal_connect (G_OBJECT (child),
+                            "notify",
+                            G_CALLBACK (widget_notify_cb),
+                            item);
+
+          g_signal_connect (G_OBJECT (item),
+                            "item_activated",
+                            G_CALLBACK (item_activated),
+                            child);
+
+          if (parent_item)
             {
-              g_signal_connect (G_OBJECT (item),
-                                "item_activated",
-                                G_CALLBACK (item_activated),
-                                child);
+              if (append)
+                dbusmenu_menuitem_child_append (parent_item, item);
+              else
+                dbusmenu_menuitem_child_prepend (parent_item, item);
             }
         }
-
-      g_signal_connect (G_OBJECT (child),
-                        "notify",
-                        G_CALLBACK (widget_notify_cb),
-                        item);
-
-      submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (child));
-      if (submenu != NULL && !g_hash_table_lookup (bridge->priv->items, submenu))
-        {
-          g_hash_table_insert (bridge->priv->items, submenu, item);
-        }
-
-      if (parent == NULL)
-        {
-          parent_item = bridge->priv->root;
-        }
-
-      if (parent_item)
-        {
-          /* XXX - not sure about this. :)   */
-          if (GTK_IS_MENU_BAR (parent))
-            dbusmenu_menuitem_child_append (parent_item, item);
-          else
-            dbusmenu_menuitem_child_prepend (parent_item, item);
-        }
     }
 }
 
@@ -289,27 +365,19 @@
 
   if (!registered)
     {
-      DBusGProxy *proxy;
       DBusGConnection *connection;
 
-      g_print ("** About to register...\n");
-
       connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
 
       g_return_if_fail (connection != NULL);
 
-      proxy = dbus_g_proxy_new_for_name_owner (connection,
-                                               APP_MENU_DBUS_NAME,
-                                               APP_MENU_DBUS_OBJECT,
-                                               APP_MENU_INTERFACE,
-                                               NULL);
-
-      g_return_if_fail (proxy != NULL);
-
-      org_ayatana_WindowMenu_Registrar_register_window (proxy,
-                                                        0,
-                                                        APP_MENU_PATH,
-                                                        NULL);
+      dbusproxy = dbus_g_proxy_new_for_name_owner (connection,
+                                                   APP_MENU_DBUS_NAME,
+                                                   APP_MENU_DBUS_OBJECT,
+                                                   APP_MENU_INTERFACE,
+                                                   NULL);
+
+      g_return_if_fail (dbusproxy != NULL);
 
       app_menu_bridge_register_type (G_TYPE_MODULE (module));
 

_______________________________________________
Mailing list: https://launchpad.net/~ayatana-commits
Post to     : ayatana-commits@lists.launchpad.net
Unsubscribe : https://launchpad.net/~ayatana-commits
More help   : https://help.launchpad.net/ListHelp

Reply via email to