ayatana-commits team mailing list archive
-
ayatana-commits team
-
Mailing list archive
-
Message #02863
[Merge] lp:~ted/appmenu-gtk/dbusmenu-parser into lp:appmenu-gtk
Ted Gould has proposed merging lp:~ted/appmenu-gtk/dbusmenu-parser into lp:appmenu-gtk with lp:~mterry/appmenu-gtk/misc-fixes as a prerequisite.
Requested reviews:
Canonical Desktop Experience Team (canonical-dx-team)
For more details, see:
https://code.launchpad.net/~ted/appmenu-gtk/dbusmenu-parser/+merge/47623
Switch to using the dbusmenu parser for parsing menu items.
--
https://code.launchpad.net/~ted/appmenu-gtk/dbusmenu-parser/+merge/47623
Your team ayatana-commits is subscribed to branch lp:appmenu-gtk.
=== modified file 'src/bridge.c'
--- src/bridge.c 2011-01-27 02:01:27 +0000
+++ src/bridge.c 2011-01-27 02:01:27 +0000
@@ -28,6 +28,7 @@
#include <gio/gio.h>
#include <libdbusmenu-gtk/menuitem.h>
+#include <libdbusmenu-gtk/parser.h>
#include <libdbusmenu-glib/menuitem.h>
#include <libdbusmenu-glib/server.h>
@@ -65,7 +66,6 @@
{
GtkWidget *window;
DbusmenuServer *server;
- DbusmenuMenuitem *root;
gchar *path;
gboolean registered;
AppMenuBridge *bridge;
@@ -171,12 +171,6 @@
context->path = NULL;
}
- if (context->root != NULL)
- {
- g_object_unref (context->root);
- context->root = NULL;
- }
-
if (context->server != NULL)
{
g_object_unref (context->server);
@@ -335,7 +329,7 @@
}
}
- if (!context->registered && context->server != NULL && context->root != NULL && GTK_IS_WINDOW (widget) && bridge->priv->appmenuproxy != NULL)
+ if (!context->registered && context->server != NULL && GTK_IS_WINDOW (widget) && bridge->priv->appmenuproxy != NULL)
{
g_dbus_proxy_call(bridge->priv->appmenuproxy,
"RegisterWindow",
@@ -443,584 +437,6 @@
return;
}
-
-static GtkWidget *
-find_menu_label (GtkWidget *widget)
-{
- GtkWidget *label = NULL;
-
- if (GTK_IS_LABEL (widget))
- return widget;
-
- if (GTK_IS_CONTAINER (widget))
- {
- GList *children;
- GList *l;
-
- children = gtk_container_get_children (GTK_CONTAINER (widget));
-
- for (l = children; l; l = l->next)
- {
- label = find_menu_label (l->data);
-
- if (label)
- break;
- }
-
- g_list_free (children);
- }
-
- return label;
-}
-
-static void
-item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data)
-{
- GtkWidget *child;
-
- if (user_data != NULL)
- {
- child = (GtkWidget *)user_data;
-
- if (GTK_IS_MENU_ITEM (child))
- {
- gtk_menu_item_activate (GTK_MENU_ITEM (child));
- }
- }
-}
-
-static gboolean
-item_about_to_show (DbusmenuMenuitem *item, gpointer user_data)
-{
- GtkWidget *child;
-
- if (user_data != NULL)
- {
- child = (GtkWidget *)user_data;
-
- if (GTK_IS_MENU_ITEM (child))
- {
- // Only called for items with submens. So we activate it here in
- // case the program dynamically creates menus (like empathy does)
- gtk_menu_item_activate (GTK_MENU_ITEM (child));
- }
- }
-
- return TRUE;
-}
-
-static gboolean
-should_show_image (GtkImage *image)
-{
- GtkWidget *item;
-
- item = gtk_widget_get_ancestor (GTK_WIDGET (image),
- GTK_TYPE_IMAGE_MENU_ITEM);
-
- if (item)
- {
- GtkSettings *settings;
- gboolean gtk_menu_images;
-
- settings = gtk_widget_get_settings (item);
-
- g_object_get (settings, "gtk-menu-images", >k_menu_images, NULL);
-
- if (gtk_menu_images)
- return TRUE;
-
- return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item));
- }
-
- return FALSE;
-}
-
-static gboolean
-update_stock_item (DbusmenuMenuitem *menuitem,
- GtkWidget *widget)
-{
- GtkStockItem stock;
- GtkImage *image;
-
- g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
-
- image = GTK_IMAGE (widget);
-
- if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK)
- return FALSE;
-
- gtk_stock_lookup (image->data.stock.stock_id, &stock);
-
- if (should_show_image (image))
- dbusmenu_menuitem_property_set (menuitem,
- DBUSMENU_MENUITEM_PROP_ICON_NAME,
- image->data.stock.stock_id);
- else
- dbusmenu_menuitem_property_remove (menuitem,
- DBUSMENU_MENUITEM_PROP_ICON_NAME);
-
- const gchar *label = dbusmenu_menuitem_property_get (menuitem,
- DBUSMENU_MENUITEM_PROP_LABEL);
-
- if (stock.label != NULL && label != NULL)
- {
- dbusmenu_menuitem_property_set (menuitem,
- DBUSMENU_MENUITEM_PROP_LABEL,
- stock.label);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-update_icon_name (DbusmenuMenuitem *menuitem,
- GtkWidget *widget)
-{
- GtkImage *image;
-
- g_return_if_fail (GTK_IS_IMAGE (widget));
-
- image = GTK_IMAGE (widget);
-
- if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME)
- return;
-
- if (should_show_image (image))
- dbusmenu_menuitem_property_set (menuitem,
- DBUSMENU_MENUITEM_PROP_ICON_NAME,
- image->data.name.icon_name);
- else
- dbusmenu_menuitem_property_remove (menuitem,
- DBUSMENU_MENUITEM_PROP_ICON_NAME);
-}
-
-static void
-widget_notify_cb (GtkWidget *widget,
- GParamSpec *pspec,
- gpointer data)
-{
- DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
-
- if (pspec->name == g_intern_static_string ("sensitive"))
- {
- dbusmenu_menuitem_property_set_bool (child,
- DBUSMENU_MENUITEM_PROP_ENABLED,
- gtk_widget_get_sensitive (widget));
- }
- else if (pspec->name == g_intern_static_string ("label"))
- {
- dbusmenu_menuitem_property_set (child,
- DBUSMENU_MENUITEM_PROP_LABEL,
- gtk_menu_item_get_label (GTK_MENU_ITEM (widget)));
- }
- else if (pspec->name == g_intern_static_string ("visible"))
- {
- dbusmenu_menuitem_property_set_bool (child,
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- gtk_widget_get_visible (widget));
- }
- else if (pspec->name == g_intern_static_string ("stock"))
- {
- update_stock_item (child, widget);
- }
- else if (pspec->name == g_intern_static_string ("icon-name"))
- {
- update_icon_name (child, widget);
- }
- else if (pspec->name == g_intern_static_string ("parent"))
- {
- /*
- * We probably should have added a 'remove' method to the
- * UbuntuMenuProxy early on, but it's late in the cycle now.
- */
- if (gtk_widget_get_parent (widget) == NULL)
- {
- g_signal_handlers_disconnect_by_func (widget,
- G_CALLBACK (widget_notify_cb),
- child);
-
- DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent");
-
- if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child))
- {
- dbusmenu_menuitem_child_delete (parent, child);
- }
- }
- }
-}
-
-static void
-label_notify_cb (GtkWidget *widget,
- GParamSpec *pspec,
- gpointer data)
-{
- DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
-
- if (pspec->name == g_intern_static_string ("label"))
- {
- dbusmenu_menuitem_property_set (child,
- DBUSMENU_MENUITEM_PROP_LABEL,
- gtk_label_get_text (GTK_LABEL (widget)));
- }
-}
-
-static void
-menuitem_notify_cb (GtkWidget *widget,
- GParamSpec *pspec,
- gpointer data)
-{
- if (pspec->name == g_intern_static_string ("visible"))
- {
- AppWindowContext *context = (AppWindowContext *)data;
- GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
- GtkWidget *window = NULL;
-
- if (context != NULL)
- window = context->window;
-
- if (toplevel == window)
- {
- rebuild (context->bridge, window);
- }
-
- /* We only care about this once, so let's disconnect now. */
- g_signal_handlers_disconnect_by_func (widget,
- G_CALLBACK (menuitem_notify_cb),
- data);
- }
-}
-
-static void
-checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
-{
- dbusmenu_menuitem_property_set_int (mi,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
-}
-
-static void
-accel_changed (GtkWidget *widget,
- gpointer data)
-{
- DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
- dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
-}
-
-static void
-action_notify_cb (GtkAction *action,
- GParamSpec *pspec,
- gpointer data)
-{
- DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
-
- if (pspec->name == g_intern_static_string ("sensitive"))
- {
- dbusmenu_menuitem_property_set_bool (mi,
- DBUSMENU_MENUITEM_PROP_ENABLED,
- gtk_action_is_sensitive (action));
- }
- else if (pspec->name == g_intern_static_string ("visible"))
- {
- dbusmenu_menuitem_property_set_bool (mi,
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- gtk_action_is_visible (action));
- }
- else if (pspec->name == g_intern_static_string ("active"))
- {
- dbusmenu_menuitem_property_set_bool (mi,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
- }
- else if (pspec->name == g_intern_static_string ("label"))
- {
- dbusmenu_menuitem_property_set (mi,
- DBUSMENU_MENUITEM_PROP_LABEL,
- gtk_action_get_label (action));
- }
-}
-
-static DbusmenuMenuitem *
-construct_dbusmenu_for_widget (GtkWidget *widget)
-{
- DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();
-
- if (GTK_IS_MENU_ITEM (widget))
- {
- gboolean visible = FALSE;
- gboolean sensitive = FALSE;
- if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
- {
- dbusmenu_menuitem_property_set (mi,
- "type",
- "separator");
-
- visible = gtk_widget_get_visible (widget);
- sensitive = gtk_widget_get_sensitive (widget);
- }
- else
- {
- gboolean label_set = FALSE;
-
- g_signal_connect (widget,
- "accel-closures-changed",
- G_CALLBACK (accel_changed),
- mi);
-
- if (GTK_IS_CHECK_MENU_ITEM (widget))
- {
- dbusmenu_menuitem_property_set (mi,
- DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
- gtk_check_menu_item_get_draw_as_radio (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
-
- dbusmenu_menuitem_property_set_int (mi,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
-
- g_signal_connect (widget,
- "activate",
- G_CALLBACK (checkbox_toggled),
- mi);
- }
-
- if (GTK_IS_IMAGE_MENU_ITEM (widget))
- {
- GtkWidget *image;
- GtkImageType image_type;
-
- image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
-
- if (GTK_IS_IMAGE (image))
- {
- image_type = gtk_image_get_storage_type (GTK_IMAGE (image));
-
- if (image_type == GTK_IMAGE_STOCK)
- {
- label_set = update_stock_item (mi, image);
- }
- else if (image_type == GTK_IMAGE_ICON_NAME)
- {
- update_icon_name (mi, image);
- }
- else if (image_type == GTK_IMAGE_PIXBUF)
- {
- dbusmenu_menuitem_property_set_image (mi,
- DBUSMENU_MENUITEM_PROP_ICON_DATA,
- gtk_image_get_pixbuf (GTK_IMAGE (image)));
- }
- }
- }
-
- GtkWidget *label = find_menu_label (widget);
-
- dbusmenu_menuitem_property_set (mi,
- "label",
- label ? gtk_label_get_text (GTK_LABEL (label)) : NULL);
-
- if (label)
- {
- // Sometimes, an app will directly find and modify the label
- // (like empathy), so watch the label especially for that.
- g_signal_connect (G_OBJECT (label),
- "notify",
- G_CALLBACK (label_notify_cb),
- mi);
- }
-
- if (GTK_IS_ACTIVATABLE (widget))
- {
- GtkActivatable *activatable = GTK_ACTIVATABLE (widget);
-
- if (gtk_activatable_get_use_action_appearance (activatable))
- {
- GtkAction *action = gtk_activatable_get_related_action (activatable);
-
- if (action)
- {
- visible = gtk_action_is_visible (action);
- sensitive = gtk_action_is_sensitive (action);
-
- g_signal_connect_object (action, "notify",
- G_CALLBACK (action_notify_cb),
- mi,
- G_CONNECT_AFTER);
- }
- }
- }
-
- if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
- {
- visible = gtk_widget_get_visible (widget);
- sensitive = gtk_widget_get_sensitive (widget);
- }
-
- dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
-
- g_signal_connect (G_OBJECT (mi),
- DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK (item_activated),
- widget);
-
- g_signal_connect (G_OBJECT (mi),
- DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
- G_CALLBACK (item_about_to_show),
- widget);
- }
-
- dbusmenu_menuitem_property_set_bool (mi,
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- visible);
-
- dbusmenu_menuitem_property_set_bool (mi,
- DBUSMENU_MENUITEM_PROP_ENABLED,
- sensitive);
-
- g_signal_connect (widget,
- "notify",
- G_CALLBACK (widget_notify_cb),
- mi);
- }
-
- return mi;
-}
-
-static void
-rebuild_item (GtkWidget *widget,
- RecurseContext *recurse)
-{
- if (GTK_IS_CONTAINER (widget))
- {
- gboolean increment = GTK_IS_MENU_BAR (widget) || GTK_IS_MENU_ITEM (widget);
-
- if (increment)
- recurse->count++;
-
- /* Okay, this is a little janky and all.. but some applications update some
- * menuitem properties such as sensitivity on the activate callback. This
- * seems a little weird, but it's not our place to judge when all this code
- * is so crazy. So we're going to get ever crazier and activate all the
- * menus that are directly below the menubar and force the applications to
- * update their sensitivity. The menus won't actually popup in the app
- * window due to our gtk+ patches.
- *
- * Note that this will not force menuitems in submenus to be updated as well.
- */
- if (recurse->count == 0 && GTK_IS_MENU_BAR (widget))
- {
- GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
-
- for (; children != NULL; children = children->next)
- {
- gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
- children->data,
- TRUE);
- }
-
- g_list_free (children);
- }
-
- if (recurse->count > -1 && increment)
- {
- DbusmenuMenuitem *dmi = g_hash_table_lookup (recurse->context->lookup, widget);
- if (dmi != NULL)
- {
- if (increment)
- recurse->count--;
-
- return;
- }
- else
- {
- recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget);
- g_hash_table_insert (recurse->context->lookup, widget, recurse->stack[recurse->count]);
- }
-
- if (!gtk_widget_get_visible (widget))
- {
- g_signal_connect (G_OBJECT (widget),
- "notify",
- G_CALLBACK (menuitem_notify_cb),
- recurse->context);
- }
-
- if (GTK_IS_TEAROFF_MENU_ITEM (widget))
- {
- dbusmenu_menuitem_property_set_bool (recurse->stack[recurse->count],
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- FALSE);
- }
-
- if (recurse->count > 0)
- {
- GList *children = NULL;
- GList *peek = NULL;
-
- if (recurse->stack[recurse->count - 1])
- {
- children = dbusmenu_menuitem_get_children (recurse->stack[recurse->count - 1]);
-
- if (children)
- {
- peek = g_list_find (children, recurse->stack[recurse->count]);
- }
-
- if (!peek)
- {
- /* Should we set a weak ref on the parent? */
- g_object_set_data (G_OBJECT (recurse->stack[recurse->count]),
- "dbusmenu-parent",
- recurse->stack[recurse->count - 1]);
- dbusmenu_menuitem_child_append (recurse->stack[recurse->count - 1],
- recurse->stack[recurse->count]);
- }
- }
- else
- {
- DbusmenuMenuitem *item = g_hash_table_lookup (recurse->context->lookup,
- gtk_widget_get_parent (widget));
-
- if (item)
- {
- children = dbusmenu_menuitem_get_children (item);
-
- if (children)
- {
- peek = g_list_find (children, recurse->stack[recurse->count]);
- }
-
- if (!peek)
- {
- g_object_set_data (G_OBJECT (recurse->stack[recurse->count]),
- "dbusmenu-parent",
- recurse->stack[recurse->count - 1]);
-
- dbusmenu_menuitem_child_append (item, recurse->stack[recurse->count]);
- }
- }
- }
- }
- }
-
- gtk_container_foreach (GTK_CONTAINER (widget),
- (GtkCallback)rebuild_item,
- recurse);
-
- if (GTK_IS_MENU_ITEM (widget))
- {
- GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
-
- if (menu != NULL)
- {
- rebuild_item (menu, recurse);
- }
- }
-
- if (increment)
- recurse->count--;
- }
-}
-
typedef struct _RebuildData {
AppMenuBridge *bridge;
GtkWidget *widget;
@@ -1076,15 +492,48 @@
g_hash_table_insert (rebuild_ids, toplevel, GUINT_TO_POINTER (id));
}
+static DbusmenuMenuitem * find_menu_bar (GtkWidget * widget);
+
+static void
+find_menu_bar_helper (GtkWidget * widget, gpointer data)
+{
+ DbusmenuMenuitem ** mi = (DbusmenuMenuitem **)data;
+
+ /* We've already found a menu, let's get through the
+ foreach as quickly as possible */
+ if (*mi != NULL) {
+ return;
+ }
+
+ *mi = find_menu_bar(widget);
+ return;
+}
+
+static DbusmenuMenuitem *
+find_menu_bar (GtkWidget * widget)
+{
+ if (GTK_IS_MENU_BAR(widget) || GTK_IS_MENU_ITEM(widget)) {
+ return dbusmenu_gtk_parse_menu_structure(widget);
+ }
+
+ if (GTK_IS_CONTAINER(widget)) {
+ DbusmenuMenuitem * mi = NULL;
+
+ gtk_container_foreach(GTK_CONTAINER(widget), find_menu_bar_helper, &mi);
+
+ return mi;
+ }
+
+ return NULL;
+}
+
+
static void
rebuild_window_items (AppMenuBridge *bridge,
GtkWidget *toplevel)
{
XID xid;
AppWindowContext *context = NULL;
- RecurseContext recurse;
-
- memset (&recurse, 0, sizeof (RecurseContext));
if (!GTK_IS_WINDOW (toplevel))
{
@@ -1147,14 +596,6 @@
context->bridge = bridge;
context->lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
bridge->priv->windows = g_list_prepend (bridge->priv->windows, context);
-
- recurse.previous = FALSE;
- recurse.count = -1;
- }
- else
- {
- recurse.previous = TRUE;
- recurse.count = 0;
}
if (context->window)
@@ -1183,24 +624,15 @@
if (!context->server)
context->server = dbusmenu_server_new (context->path);
- recurse.bridge = bridge;
- recurse.context = context;
-
- gtk_container_foreach (GTK_CONTAINER (toplevel),
- (GtkCallback)rebuild_item,
- &recurse);
-
- if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM (recurse.stack[0]))
- {
- context->root = recurse.stack[0];
-
- dbusmenu_server_set_root (context->server, context->root);
- }
+ DbusmenuMenuitem * mi = find_menu_bar(toplevel);
+ dbusmenu_server_set_root(context->server, mi);
+ if (mi != NULL) {
+ g_object_unref(G_OBJECT(mi));
+ }
register_application_windows (bridge);
}
-
static void
toplevel_realized (GtkWidget *widget,
gpointer user_data)
@@ -1316,7 +748,7 @@
if (mi != NULL)
{
- DbusmenuMenuitem *child_dmi = construct_dbusmenu_for_widget (child);
+ DbusmenuMenuitem *child_dmi = dbusmenu_gtk_parse_menu_structure (child);
g_object_set_data (G_OBJECT (child_dmi), "dbusmenu-parent", mi);
dbusmenu_menuitem_child_add_position (mi,
Follow ups