ayatana-commits team mailing list archive
-
ayatana-commits team
-
Mailing list archive
-
Message #01523
[Merge] lp:~bratsche/appmenu-gtk/window-registration into lp:appmenu-gtk
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));
Follow ups