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