From c644e10c9da09e443a00422df00a6ba9df7a7e83 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 12:45:05 -0600 Subject: Adding the base files for the parser --- libdbusmenu-gtk/parser.c | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 libdbusmenu-gtk/parser.c (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c new file mode 100644 index 0000000..98b3f7d --- /dev/null +++ b/libdbusmenu-gtk/parser.c @@ -0,0 +1,9 @@ + +#include "parser.h" + +DbusmenuMenuitem * +dbusmenu_gtk_parse_menu_structure (GtkMenuItem * mi) +{ + + return NULL; +} -- cgit v1.2.3 From b39a625defde44aa345253237d4f186abedf7196 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Sun, 23 Jan 2011 13:05:28 -0600 Subject: Taking the menu parsing code from appmenu-gtk --- libdbusmenu-gtk/parser.c | 426 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 425 insertions(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 98b3f7d..8fd0d12 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -1,9 +1,433 @@ #include "parser.h" +#include "menuitem.h" + +static void accel_changed (GtkWidget *widget, gpointer data); +static gboolean update_stock_item (DbusmenuMenuitem *menuitem, GtkWidget *widget); +static void checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi); +static void update_icon_name (DbusmenuMenuitem *menuitem, GtkWidget *widget); +static GtkWidget * find_menu_label (GtkWidget *widget); +static void label_notify_cb (GtkWidget *widget, GParamSpec *pspec, gpointer data); +static void action_notify_cb (GtkAction *action, GParamSpec *pspec, gpointer data); +static void item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data); +static gboolean item_about_to_show (DbusmenuMenuitem *item, gpointer user_data); +static void widget_notify_cb (GtkWidget *widget, GParamSpec *pspec, gpointer data); +static gboolean should_show_image (GtkImage *image); DbusmenuMenuitem * -dbusmenu_gtk_parse_menu_structure (GtkMenuItem * mi) +dbusmenu_gtk_parse_menu_structure (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; return NULL; } + +static void +accel_changed (GtkWidget *widget, + gpointer data) +{ + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; + dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); +} + +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 +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 +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 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 +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 +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 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 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 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; +} + -- cgit v1.2.3 From 708ccab44c2c88b43ad35048dc0aee81023e61f9 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 13:11:46 -0600 Subject: Reformating prototypes because it makes the code run faster. --- libdbusmenu-gtk/parser.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 8fd0d12..f0c22be 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -2,17 +2,30 @@ #include "parser.h" #include "menuitem.h" -static void accel_changed (GtkWidget *widget, gpointer data); -static gboolean update_stock_item (DbusmenuMenuitem *menuitem, GtkWidget *widget); -static void checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi); -static void update_icon_name (DbusmenuMenuitem *menuitem, GtkWidget *widget); -static GtkWidget * find_menu_label (GtkWidget *widget); -static void label_notify_cb (GtkWidget *widget, GParamSpec *pspec, gpointer data); -static void action_notify_cb (GtkAction *action, GParamSpec *pspec, gpointer data); -static void item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data); -static gboolean item_about_to_show (DbusmenuMenuitem *item, gpointer user_data); -static void widget_notify_cb (GtkWidget *widget, GParamSpec *pspec, gpointer data); -static gboolean should_show_image (GtkImage *image); +static void accel_changed (GtkWidget * widget, + gpointer data); +static gboolean update_stock_item (DbusmenuMenuitem * menuitem, + GtkWidget * widget); +static void checkbox_toggled (GtkWidget * widget, + DbusmenuMenuitem * mi); +static void update_icon_name (DbusmenuMenuitem * menuitem, + GtkWidget * widget); +static GtkWidget * find_menu_label (GtkWidget * widget); +static void label_notify_cb (GtkWidget * widget, + GParamSpec * pspec, + gpointer data); +static void action_notify_cb (GtkAction * action, + GParamSpec * pspec, + gpointer data); +static void item_activated (DbusmenuMenuitem * item, + guint timestamp, + gpointer user_data); +static gboolean item_about_to_show (DbusmenuMenuitem * item, + gpointer user_data); +static void widget_notify_cb (GtkWidget * widget, + GParamSpec * pspec, + gpointer data); +static gboolean should_show_image (GtkImage * image); DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) -- cgit v1.2.3 From 401bc7c326c518ad01c1edd38155d89d9e35fd49 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 13:16:20 -0600 Subject: Adding copyright headers --- libdbusmenu-gtk/parser.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index f0c22be..cba6b42 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -1,3 +1,30 @@ +/* +Parse to take a set of GTK Menus and turn them into something that can +be sent over the wire. + +Copyright 2011 Canonical Ltd. + +Authors: + Numerous (check Bazaar) + +This program is free software: you can redistribute it and/or modify it +under the terms of either or both of the following licenses: + +1) the GNU Lesser General Public License version 3, as published by the +Free Software Foundation; and/or +2) the GNU Lesser General Public License version 2.1, as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +PURPOSE. See the applicable version of the GNU Lesser General Public +License for more details. + +You should have received a copy of both the GNU Lesser General Public +License version 3 and version 2.1 along with this program. If not, see + +*/ #include "parser.h" #include "menuitem.h" -- cgit v1.2.3 From 32a7eb938893bcc1bc5644aa95c63041e9d4db01 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 15:09:51 -0600 Subject: Needed to go up a level to get recursion code. --- libdbusmenu-gtk/parser.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index cba6b42..08613ac 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -29,6 +29,14 @@ License version 3 and version 2.1 along with this program. If not, see #include "parser.h" #include "menuitem.h" +typedef struct _RecurseContext +{ + gint count; + DbusmenuMenuitem *stack[30]; +} RecurseContext; + +static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse); +static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget); static void accel_changed (GtkWidget * widget, gpointer data); static gboolean update_stock_item (DbusmenuMenuitem * menuitem, @@ -56,6 +64,156 @@ static gboolean should_show_image (GtkImage * image); DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) +{ + RecurseContext recurse = {0}; + recurse.count = -1; + + parse_menu_structure_helper(widget, &recurse); + + if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM(recurse.stack[0])) { + return recurse.stack[0]; + } + + return NULL; +} + +static void +parse_menu_structure_helper (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 = NULL; //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 = NULL; /* 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)parse_menu_structure_helper, + recurse); + + if (GTK_IS_MENU_ITEM (widget)) + { + GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); + + if (menu != NULL) + { + parse_menu_structure_helper (menu, recurse); + } + } + + if (increment) + recurse->count--; + } +} + +static DbusmenuMenuitem * +construct_dbusmenu_for_widget (GtkWidget * widget) { DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); -- cgit v1.2.3 From 65b9cda89a5bef2c541f5ed2624e6e199f136435 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 15:40:26 -0600 Subject: Trying to put back in the visibility notifier to force the rebuild, but I'm not quite sure how to do that yet. --- libdbusmenu-gtk/parser.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 08613ac..9d0f9b4 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -31,6 +31,7 @@ License version 3 and version 2.1 along with this program. If not, see typedef struct _RecurseContext { + GtkWidget * toplevel; gint count; DbusmenuMenuitem *stack[30]; } RecurseContext; @@ -61,12 +62,17 @@ static void widget_notify_cb (GtkWidget * widget, GParamSpec * pspec, gpointer data); static gboolean should_show_image (GtkImage * image); +static void menuitem_notify_cb (GtkWidget * widget, + GParamSpec * pspec, + gpointer data); DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) { RecurseContext recurse = {0}; + recurse.count = -1; + recurse.toplevel = gtk_widget_get_toplevel(widget); parse_menu_structure_helper(widget, &recurse); @@ -129,10 +135,10 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) if (!gtk_widget_get_visible (widget)) { - /*g_signal_connect (G_OBJECT (widget), - "notify", + g_signal_connect (G_OBJECT (widget), + "notify::visible", G_CALLBACK (menuitem_notify_cb), - recurse->context); */ + recurse->toplevel); } if (GTK_IS_TEAROFF_MENU_ITEM (widget)) @@ -358,6 +364,27 @@ construct_dbusmenu_for_widget (GtkWidget * widget) return NULL; } +static void +menuitem_notify_cb (GtkWidget *widget, + GParamSpec *pspec, + gpointer data) +{ + if (pspec->name == g_intern_static_string ("visible")) + { + GtkWidget * new_toplevel = gtk_widget_get_toplevel (widget); + GtkWidget * old_toplevel = GTK_WIDGET(data); + + if (new_toplevel == old_toplevel) { + /* TODO: Figure this out -> 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 accel_changed (GtkWidget *widget, gpointer data) -- cgit v1.2.3 From a439aeb8fd08d9858055bbb2ae1326a1335600d1 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 15:53:27 -0600 Subject: Reimplementing the cache based on object data with signals to cleanup --- libdbusmenu-gtk/parser.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 9d0f9b4..f1c46ba 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -29,6 +29,8 @@ License version 3 and version 2.1 along with this program. If not, see #include "parser.h" #include "menuitem.h" +#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item" + typedef struct _RecurseContext { GtkWidget * toplevel; @@ -83,6 +85,20 @@ dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) return NULL; } +static void +dbusmenu_cache_freed (gpointer data, GObject * obj) +{ + g_object_set_data(G_OBJECT(data), CACHED_MENUITEM, NULL); + return; +} + +static void +object_cache_freed (gpointer data) +{ + g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data); + return; +} + static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) { @@ -119,7 +135,10 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) if (recurse->count > -1 && increment) { - DbusmenuMenuitem *dmi = NULL; //g_hash_table_lookup (recurse->context->lookup, widget); + gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM); + DbusmenuMenuitem *dmi = NULL; + if (pmi != NULL) dmi = DBUSMENU_MENUITEM(pmi); + if (dmi != NULL) { if (increment) @@ -130,7 +149,8 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) else { recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget); - //g_hash_table_insert (recurse->context->lookup, widget, recurse->stack[recurse->count]); + g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, recurse->stack[recurse->count], object_cache_freed); + g_object_weak_ref(G_OBJECT(recurse->stack[recurse->count]), dbusmenu_cache_freed, widget); } if (!gtk_widget_get_visible (widget)) -- cgit v1.2.3 From fc096ca12b152461dfddbfdf74720b98691448ce Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Sun, 23 Jan 2011 16:08:39 -0600 Subject: Stop using the data field in gtk image for GTK3 --- libdbusmenu-gtk/parser.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index f1c46ba..cfce42a 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -427,12 +427,15 @@ update_stock_item (DbusmenuMenuitem *menuitem, if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK) return FALSE; - gtk_stock_lookup (image->data.stock.stock_id, &stock); + gchar * stock_id = NULL; + gtk_image_get_stock(image, &stock_id, NULL); + + gtk_stock_lookup (stock_id, &stock); if (should_show_image (image)) dbusmenu_menuitem_property_set (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME, - image->data.stock.stock_id); + stock_id); else dbusmenu_menuitem_property_remove (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME); @@ -473,13 +476,16 @@ update_icon_name (DbusmenuMenuitem *menuitem, if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME) return; - if (should_show_image (image)) + if (should_show_image (image)) { + const gchar * icon_name = NULL; + gtk_image_get_icon_name(image, &icon_name, NULL); dbusmenu_menuitem_property_set (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME, - image->data.name.icon_name); - else + icon_name); + } else { dbusmenu_menuitem_property_remove (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME); + } } static GtkWidget * -- cgit v1.2.3 From 25ab785826d59d8ca7860b0d0bc39d6187a3a1ed Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 24 Jan 2011 14:56:07 -0600 Subject: Fixing referencing warnings on destruction. --- libdbusmenu-gtk/parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index cfce42a..52bd8a8 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -88,7 +88,9 @@ dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) static void dbusmenu_cache_freed (gpointer data, GObject * obj) { - g_object_set_data(G_OBJECT(data), CACHED_MENUITEM, NULL); + /* If the dbusmenu item is killed we don't need to remove + the weak ref as well. */ + g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); return; } -- cgit v1.2.3 From 32def89e3191d994a43d222c1e81c746922b688d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 25 Jan 2011 11:50:46 -0600 Subject: Moving one up the stack so GtkMenu works as well --- libdbusmenu-gtk/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 52bd8a8..d26f8fb 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -106,7 +106,7 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) { if (GTK_IS_CONTAINER (widget)) { - gboolean increment = GTK_IS_MENU_BAR (widget) || GTK_IS_MENU_ITEM (widget); + gboolean increment = GTK_IS_MENU_SHELL (widget) || GTK_IS_MENU_ITEM (widget); if (increment) recurse->count++; -- cgit v1.2.3 From 275bd0eec2e28b708ff6cda14531f63a8aa16e8e Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 25 Jan 2011 16:51:31 -0600 Subject: Looking for the serializable menu item and using it's build function if it is one. --- libdbusmenu-gtk/parser.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index d26f8fb..6d95f10 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -28,6 +28,7 @@ License version 3 and version 2.1 along with this program. If not, see #include "parser.h" #include "menuitem.h" +#include "serializablemenuitem.h" #define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item" @@ -240,13 +241,23 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) } } +/* Turn a widget into a dbusmenu item depending on the type of GTK + object that it is. */ static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget) { - DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); - + /* If it's a subclass of our serializable menu item then we can + use its own build function */ + if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) { + DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget); + return dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem(smi); + } + + /* If it's a standard GTK Menu Item we need to do some of our own work */ if (GTK_IS_MENU_ITEM (widget)) { + DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); + gboolean visible = FALSE; gboolean sensitive = FALSE; if (GTK_IS_SEPARATOR_MENU_ITEM (widget)) @@ -379,11 +390,12 @@ construct_dbusmenu_for_widget (GtkWidget * widget) "notify", G_CALLBACK (widget_notify_cb), mi); + return mi; } - return mi; - - return NULL; + /* If it's none of those we're going to just create a + generic menuitem as a place holder for it. */ + return dbusmenu_menuitem_new(); } static void -- cgit v1.2.3 From 1039a4dd88243938e8871c307c20841c375b78d2 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 26 Jan 2011 15:11:16 -0600 Subject: Adding comments and a check to ensure the item is valid. --- libdbusmenu-gtk/parser.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index d26f8fb..1936d2d 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -85,6 +85,8 @@ dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) return NULL; } +/* Called when the dbusmenu item that we're keeping around + is finalized */ static void dbusmenu_cache_freed (gpointer data, GObject * obj) { @@ -94,9 +96,12 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) return; } +/* Called if we replace the cache on the object with a new + dbusmenu menuitem */ static void object_cache_freed (gpointer data) { + if (!G_IS_OBJECT(data)) return; g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data); return; } -- cgit v1.2.3 From 81032fae461250e5e73aaa49896fd92dd58ad674 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 26 Jan 2011 16:09:41 -0600 Subject: Factoring out the stack and just tracking the parent as that's all we were using it for really. --- libdbusmenu-gtk/parser.c | 236 ++++++++++++++++++++--------------------------- 1 file changed, 99 insertions(+), 137 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 1936d2d..5f0ef48 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -34,8 +34,7 @@ License version 3 and version 2.1 along with this program. If not, see typedef struct _RecurseContext { GtkWidget * toplevel; - gint count; - DbusmenuMenuitem *stack[30]; + DbusmenuMenuitem * parent; } RecurseContext; static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse); @@ -68,21 +67,17 @@ static void menuitem_notify_cb (GtkWidget * widget, GParamSpec * pspec, gpointer data); + DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) { RecurseContext recurse = {0}; - recurse.count = -1; recurse.toplevel = gtk_widget_get_toplevel(widget); parse_menu_structure_helper(widget, &recurse); - if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM(recurse.stack[0])) { - return recurse.stack[0]; - } - - return NULL; + return recurse.parent; } /* Called when the dbusmenu item that we're keeping around @@ -93,6 +88,7 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) /* If the dbusmenu item is killed we don't need to remove the weak ref as well. */ g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); + g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj); return; } @@ -109,140 +105,106 @@ object_cache_freed (gpointer data) static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) { - if (GTK_IS_CONTAINER (widget)) - { - gboolean increment = GTK_IS_MENU_SHELL (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) - { - gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM); - DbusmenuMenuitem *dmi = NULL; - if (pmi != NULL) dmi = DBUSMENU_MENUITEM(pmi); - if (dmi != NULL) - { - if (increment) - recurse->count--; - - return; - } - else - { - recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget); - g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, recurse->stack[recurse->count], object_cache_freed); - g_object_weak_ref(G_OBJECT(recurse->stack[recurse->count]), dbusmenu_cache_freed, widget); + /* If this is a shell, then let's handle the items in it. */ + if (GTK_IS_MENU_SHELL (widget)) { + /* 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. + */ + 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->parent == NULL) { + recurse->parent = dbusmenu_menuitem_new(); + } + + gtk_container_foreach (GTK_CONTAINER (widget), + (GtkCallback)parse_menu_structure_helper, + recurse); + return; + } + + if (GTK_IS_MENU_ITEM(widget)) { + DbusmenuMenuitem * thisitem = NULL; + + /* Check to see if we're cached already */ + gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM); + if (pmi != NULL) { + thisitem = DBUSMENU_MENUITEM(pmi); + g_object_ref(G_OBJECT(thisitem)); + } + + /* We don't have one, so we'll need to build it */ + if (thisitem == NULL) { + thisitem = construct_dbusmenu_for_widget (widget); + g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, thisitem, object_cache_freed); + g_object_weak_ref(G_OBJECT(thisitem), dbusmenu_cache_freed, widget); + + if (!gtk_widget_get_visible (widget)) { + g_signal_connect (G_OBJECT (widget), + "notify::visible", + G_CALLBACK (menuitem_notify_cb), + recurse->toplevel); } - if (!gtk_widget_get_visible (widget)) - { - g_signal_connect (G_OBJECT (widget), - "notify::visible", - G_CALLBACK (menuitem_notify_cb), - recurse->toplevel); + if (GTK_IS_TEAROFF_MENU_ITEM (widget)) { + dbusmenu_menuitem_property_set_bool (thisitem, + DBUSMENU_MENUITEM_PROP_VISIBLE, + FALSE); } + } + + /* Check to see if we're in our parents list of children, if we have + a parent. */ + if (recurse->parent != NULL) { + GList * children = dbusmenu_menuitem_get_children (recurse->parent); + GList * peek = NULL; + + if (children != NULL) { + peek = g_list_find (children, thisitem); + } + + /* Oops, let's tell our parents about us */ + if (peek == NULL) { + /* TODO: Should we set a weak ref on the parent? */ + g_object_set_data (G_OBJECT (thisitem), + "dbusmenu-parent", + recurse->parent); + dbusmenu_menuitem_child_append (recurse->parent, + thisitem); + } + } + + GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); + if (menu != NULL) { + DbusmenuMenuitem * parent_save = recurse->parent; + recurse->parent = thisitem; + parse_menu_structure_helper (menu, recurse); + recurse->parent = parent_save; + } + + if (recurse->parent == NULL) { + recurse->parent = thisitem; + } else { + g_object_unref(thisitem); + } + } - 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 = NULL; /* 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)parse_menu_structure_helper, - recurse); - - if (GTK_IS_MENU_ITEM (widget)) - { - GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); - - if (menu != NULL) - { - parse_menu_structure_helper (menu, recurse); - } - } - - if (increment) - recurse->count--; - } + return; } static DbusmenuMenuitem * -- cgit v1.2.3 From fe464dc002ed3e2e713f64145e689f66ad51f275 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Wed, 26 Jan 2011 16:13:56 -0600 Subject: Fix to the type of toggle-state to int --- libdbusmenu-gtk/parser.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 5f0ef48..b1e7e01 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -522,9 +522,9 @@ action_notify_cb (GtkAction *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))); + dbusmenu_menuitem_property_set_int (mi, + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); } else if (pspec->name == g_intern_static_string ("label")) { -- cgit v1.2.3 From e5078ed1027e8c466d081183eeee6888b10ef510 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 26 Jan 2011 16:27:50 -0600 Subject: No really, read the comment and make sure that only happens on the highest level --- libdbusmenu-gtk/parser.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index b1e7e01..27ac926 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -118,15 +118,17 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) * * Note that this will not force menuitems in submenus to be updated as well. */ - GList *children = gtk_container_get_children (GTK_CONTAINER (widget)); + if (recurse->parent == NULL) { + 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); - } + for (; children != NULL; children = children->next) { + gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget), + children->data, + TRUE); + } - g_list_free (children); + g_list_free (children); + } if (recurse->parent == NULL) { recurse->parent = dbusmenu_menuitem_new(); -- cgit v1.2.3 From c6da3667cae61d1606eb66e6b7be01c2cbf9cbff Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 26 Jan 2011 16:53:54 -0600 Subject: Only activating on menu bars. --- libdbusmenu-gtk/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 27ac926..5dea9de 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -118,7 +118,7 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) * * Note that this will not force menuitems in submenus to be updated as well. */ - if (recurse->parent == NULL) { + if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) { GList *children = gtk_container_get_children (GTK_CONTAINER (widget)); for (; children != NULL; children = children->next) { -- cgit v1.2.3 From 7e55758aa584a9e4080411cbd663d1fa30725a57 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Thu, 27 Jan 2011 08:48:37 -0600 Subject: Adding documentation of the public API. --- libdbusmenu-gtk/parser.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 5dea9de..8537a07 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -67,7 +67,17 @@ static void menuitem_notify_cb (GtkWidget * widget, GParamSpec * pspec, gpointer data); +/** + dbusmenu_gtk_parse_menu_structure: + @widget: A #GtkMenuItem or #GtkMenuShell to turn into a #DbusmenuMenuitem + Goes through the GTK structures and turns them into the appropraite + Dbusmenu structures along with setting up all the relationships + between the objects. It also stores the dbusmenu items as a cache + on the GTK items so that they'll be reused if necissary. + + Return value: A dbusmenu item representing the menu structure +*/ DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) { -- cgit v1.2.3 From 321935e1678923454a97bcb41f9ddc6714e4ac88 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Thu, 27 Jan 2011 08:50:24 -0600 Subject: Adding an early check on the type of widget coming into the function. --- libdbusmenu-gtk/parser.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 8537a07..ead653a 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -81,6 +81,8 @@ static void menuitem_notify_cb (GtkWidget * widget, DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) { + g_return_val_if_fail(GTK_IS_MENU_ITEM(widget) || GTK_IS_MENU_SHELL(widget), NULL); + RecurseContext recurse = {0}; recurse.toplevel = gtk_widget_get_toplevel(widget); -- cgit v1.2.3 From 07666d7543bfce7fe925c15d3350519fd711a8f0 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Thu, 27 Jan 2011 09:44:11 -0600 Subject: Fix changing prototypes. --- libdbusmenu-gtk/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 6d95f10..cdbc001 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -250,7 +250,7 @@ construct_dbusmenu_for_widget (GtkWidget * widget) use its own build function */ if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) { DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget); - return dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem(smi); + return dbusmenu_gtk_serializable_menu_item_build_menuitem(smi); } /* If it's a standard GTK Menu Item we need to do some of our own work */ -- cgit v1.2.3 From 7be86c5778e58bbe231655ed58b7597ad61f5310 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Fri, 28 Jan 2011 14:35:36 -0500 Subject: notice new submenus --- libdbusmenu-gtk/parser.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 5d71585..5f42ed5 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -649,6 +649,27 @@ widget_notify_cb (GtkWidget *widget, } } } + else if (pspec->name == g_intern_static_string ("submenu")) + { + /* The underlying submenu got swapped out. Let's see what it is now. */ + /* First, delete any children that may exist currently. */ + DbusmenuMenuitem * item = DBUSMENU_MENUITEM(g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM)); + if (item != NULL) + { + GList * children = dbusmenu_menuitem_get_children (item); + while (children != NULL) { + dbusmenu_menuitem_child_delete (item, DBUSMENU_MENUITEM(children->data)); + children = children->next; + } + } + + /* Now parse new submenu. */ + GtkWidget * menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); + RecurseContext recurse = {0}; + recurse.toplevel = gtk_widget_get_toplevel(widget); + recurse.parent = item; + parse_menu_structure_helper(menu, &recurse); + } } static gboolean -- cgit v1.2.3 From 591583b6e602b93399fd125da1f658146e5d717d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 31 Jan 2011 11:55:39 -0600 Subject: Switching to take_children() so that we can ensure all the data remains valid --- libdbusmenu-gtk/parser.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 5f42ed5..4941bf4 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -656,11 +656,13 @@ widget_notify_cb (GtkWidget *widget, DbusmenuMenuitem * item = DBUSMENU_MENUITEM(g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM)); if (item != NULL) { - GList * children = dbusmenu_menuitem_get_children (item); - while (children != NULL) { - dbusmenu_menuitem_child_delete (item, DBUSMENU_MENUITEM(children->data)); - children = children->next; + GList * children = dbusmenu_menuitem_take_children (item); + GList * child = children; + while (child != NULL) { + g_object_unref (G_OBJECT(child->data)); + child = child->next; } + g_list_free(children); } /* Now parse new submenu. */ -- cgit v1.2.3 From 74a0afebe8d3c1fa28d969739ea5c718f00e8c0d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 31 Jan 2011 12:08:57 -0600 Subject: Handle the case where we don't have a cached item. Not sure how that'd be, but we shouldn't let it drop. --- libdbusmenu-gtk/parser.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 4941bf4..7e5e7e1 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -666,11 +666,19 @@ widget_notify_cb (GtkWidget *widget, } /* Now parse new submenu. */ - GtkWidget * menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); RecurseContext recurse = {0}; recurse.toplevel = gtk_widget_get_toplevel(widget); recurse.parent = item; - parse_menu_structure_helper(menu, &recurse); + + if (item != NULL) { + GtkWidget * menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); + parse_menu_structure_helper(menu, &recurse); + } else { + /* Note: it would be really odd that we wouldn't have a cached + item, but we should handle that appropriately. */ + parse_menu_structure_helper(widget, &recurse); + g_object_unref(G_OBJECT(recurse.parent)); + } } } -- cgit v1.2.3 From a3da704b473f3ab75786501a6ec20d7b735fe8d9 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Wed, 2 Feb 2011 13:44:53 -0500 Subject: disconnect signals when done with menuitem --- libdbusmenu-gtk/parser.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 7e5e7e1..317dba2 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -102,6 +102,21 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) the weak ref as well. */ g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj); + + GtkWidget *widget = GTK_WIDGET(data); + GtkWidget *label = find_menu_label (widget); + if (label != NULL) { + g_signal_handlers_disconnect_by_func(label, G_CALLBACK(label_notify_cb), obj); + } + + if (GTK_IS_ACTIVATABLE (widget)) { + GtkAction *action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget)); + + if (action) { + g_signal_handlers_disconnect_by_func(action, G_CALLBACK(action_notify_cb), obj); + } + } + return; } -- cgit v1.2.3 From 51e68e1efe0eff4de283d2a0095357115ae514f4 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Thu, 3 Feb 2011 08:43:56 -0500 Subject: keep track of objects that we set notifies for --- libdbusmenu-gtk/parser.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 317dba2..db1d8dd 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -31,6 +31,14 @@ License version 3 and version 2.1 along with this program. If not, see #include "serializablemenuitem.h" #define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item" +#define PARSER_DATA "dbusmenu-gtk-parser-data" + +typedef struct _ParserData +{ + GtkWidget *label; + GtkAction *action; + GtkWidget *widget; +} ParserData; typedef struct _RecurseContext { @@ -103,18 +111,21 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj); - GtkWidget *widget = GTK_WIDGET(data); - GtkWidget *label = find_menu_label (widget); - if (label != NULL) { - g_signal_handlers_disconnect_by_func(label, G_CALLBACK(label_notify_cb), obj); + ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA); + + if (pdata != NULL && pdata->label != NULL) { + g_signal_handlers_disconnect_by_func(pdata->label, G_CALLBACK(label_notify_cb), obj); + g_object_remove_weak_pointer(G_OBJECT(pdata->label), (gpointer*)&pdata->label); } - if (GTK_IS_ACTIVATABLE (widget)) { - GtkAction *action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget)); + if (pdata != NULL && pdata->action != NULL) { + g_signal_handlers_disconnect_by_func(pdata->action, G_CALLBACK(action_notify_cb), obj); + g_object_remove_weak_pointer(G_OBJECT(pdata->action), (gpointer*)&pdata->action); + } - if (action) { - g_signal_handlers_disconnect_by_func(action, G_CALLBACK(action_notify_cb), obj); - } + if (pdata != NULL && pdata->widget != NULL) { + g_signal_handlers_disconnect_by_func(pdata->widget, G_CALLBACK(widget_notify_cb), obj); + g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget); } return; @@ -125,8 +136,10 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) static void object_cache_freed (gpointer data) { - if (!G_IS_OBJECT(data)) return; - g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data); + // TODO: make this have access to both data and obj so we can call these + //if (!G_IS_OBJECT(obj)) return; + //g_object_weak_unref(G_OBJECT(obj), dbusmenu_cache_freed, data); + //dbusmenu_cache_freed(data, obj); return; } @@ -254,6 +267,9 @@ construct_dbusmenu_for_widget (GtkWidget * widget) { DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); + ParserData *pdata = g_new0 (ParserData, 1); + g_object_set_data_full (G_OBJECT (mi), PARSER_DATA, pdata, g_free); + gboolean visible = FALSE; gboolean sensitive = FALSE; if (GTK_IS_SEPARATOR_MENU_ITEM (widget)) @@ -328,10 +344,12 @@ construct_dbusmenu_for_widget (GtkWidget * widget) { // Sometimes, an app will directly find and modify the label // (like empathy), so watch the label especially for that. + pdata->label = label; g_signal_connect (G_OBJECT (label), "notify", G_CALLBACK (label_notify_cb), mi); + g_object_add_weak_pointer(G_OBJECT (label), (gpointer*)&pdata->label); } if (GTK_IS_ACTIVATABLE (widget)) @@ -347,10 +365,12 @@ construct_dbusmenu_for_widget (GtkWidget * widget) visible = gtk_action_is_visible (action); sensitive = gtk_action_is_sensitive (action); + pdata->action = action; g_signal_connect_object (action, "notify", G_CALLBACK (action_notify_cb), mi, G_CONNECT_AFTER); + g_object_add_weak_pointer(G_OBJECT (action), (gpointer*)&pdata->action); } } } @@ -382,10 +402,13 @@ construct_dbusmenu_for_widget (GtkWidget * widget) DBUSMENU_MENUITEM_PROP_ENABLED, sensitive); + pdata->widget = widget; g_signal_connect (widget, "notify", G_CALLBACK (widget_notify_cb), mi); + g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->widget); + return mi; } -- cgit v1.2.3 From 4da7e99010b1dbf2a6f28660570e9ad79f538136 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Fri, 4 Feb 2011 14:05:52 -0500 Subject: watch for new menu items being added to existing menu shells --- libdbusmenu-gtk/parser.c | 97 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 12 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index db1d8dd..96418b3 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -38,6 +38,7 @@ typedef struct _ParserData GtkWidget *label; GtkAction *action; GtkWidget *widget; + GtkWidget *shell; } ParserData; typedef struct _RecurseContext @@ -63,6 +64,9 @@ static void label_notify_cb (GtkWidget * widget, static void action_notify_cb (GtkAction * action, GParamSpec * pspec, gpointer data); +static void child_added_cb (GtkContainer * menu, + GtkWidget * widget, + gpointer data); static void item_activated (DbusmenuMenuitem * item, guint timestamp, gpointer user_data); @@ -109,7 +113,6 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) /* If the dbusmenu item is killed we don't need to remove the weak ref as well. */ g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); - g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj); ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA); @@ -128,6 +131,11 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget); } + if (pdata != NULL && pdata->shell != NULL) { + g_signal_handlers_disconnect_by_func(pdata->shell, G_CALLBACK(child_added_cb), obj); + g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell); + } + return; } @@ -143,6 +151,45 @@ object_cache_freed (gpointer data) return; } +static gint +get_child_position (GtkWidget * child) +{ + GtkWidget * parent = gtk_widget_get_parent (child); + if (parent == NULL || !GTK_IS_CONTAINER (parent)) + return -1; + + GList * children = gtk_container_get_children (GTK_CONTAINER (parent)); + GList * iter; + gint position = 0; + + for (iter = children; iter != NULL; iter = iter->next) { + if (iter->data == child) + break; + ++position; + } + + g_list_free (children); + + if (iter == NULL) + return -1; + else + return position; +} + +static DbusmenuMenuitem * +new_menuitem (GtkWidget * widget) +{ + DbusmenuMenuitem * item = dbusmenu_menuitem_new(); + + ParserData *pdata = g_new0 (ParserData, 1); + g_object_set_data_full(G_OBJECT(item), PARSER_DATA, pdata, g_free); + + g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, item, object_cache_freed); + g_object_weak_ref(G_OBJECT(item), dbusmenu_cache_freed, widget); + + return item; +} + static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) { @@ -161,10 +208,11 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) */ if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) { GList *children = gtk_container_get_children (GTK_CONTAINER (widget)); + GList *iter; - for (; children != NULL; children = children->next) { + for (iter = children; iter != NULL; iter = iter->next) { gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget), - children->data, + iter->data, TRUE); } @@ -172,9 +220,18 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) } if (recurse->parent == NULL) { - recurse->parent = dbusmenu_menuitem_new(); + recurse->parent = new_menuitem(widget); } + ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(recurse->parent), PARSER_DATA); + + pdata->shell = widget; + g_signal_connect (G_OBJECT (widget), + "child-added", + G_CALLBACK (child_added_cb), + recurse->parent); + g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->shell); + gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback)parse_menu_structure_helper, recurse); @@ -194,8 +251,6 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) /* We don't have one, so we'll need to build it */ if (thisitem == NULL) { thisitem = construct_dbusmenu_for_widget (widget); - g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, thisitem, object_cache_freed); - g_object_weak_ref(G_OBJECT(thisitem), dbusmenu_cache_freed, widget); if (!gtk_widget_get_visible (widget)) { g_signal_connect (G_OBJECT (widget), @@ -227,8 +282,14 @@ parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) g_object_set_data (G_OBJECT (thisitem), "dbusmenu-parent", recurse->parent); - dbusmenu_menuitem_child_append (recurse->parent, - thisitem); + gint pos = get_child_position (widget); + if (pos >= 0) + dbusmenu_menuitem_child_add_position (recurse->parent, + thisitem, + pos); + else + dbusmenu_menuitem_child_append (recurse->parent, + thisitem); } } @@ -265,10 +326,9 @@ construct_dbusmenu_for_widget (GtkWidget * widget) /* If it's a standard GTK Menu Item we need to do some of our own work */ if (GTK_IS_MENU_ITEM (widget)) { - DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); + DbusmenuMenuitem *mi = new_menuitem(widget); - ParserData *pdata = g_new0 (ParserData, 1); - g_object_set_data_full (G_OBJECT (mi), PARSER_DATA, pdata, g_free); + ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(mi), PARSER_DATA); gboolean visible = FALSE; gboolean sensitive = FALSE; @@ -414,7 +474,7 @@ construct_dbusmenu_for_widget (GtkWidget * widget) /* If it's none of those we're going to just create a generic menuitem as a place holder for it. */ - return dbusmenu_menuitem_new(); + return new_menuitem(widget); } static void @@ -720,6 +780,19 @@ widget_notify_cb (GtkWidget *widget, } } +/* A child item was added to a menu we're watching. Let's try to integrate it. */ +static void +child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data) +{ + DbusmenuMenuitem *menuitem = (DbusmenuMenuitem *)data; + + RecurseContext recurse = {0}; + recurse.toplevel = gtk_widget_get_toplevel(GTK_WIDGET(menu)); + recurse.parent = menuitem; + + parse_menu_structure_helper(widget, &recurse); +} + static gboolean should_show_image (GtkImage *image) { -- cgit v1.2.3 From e342bd662608d2557bb79d6d6cea5947a58fb09f Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Thu, 10 Feb 2011 18:27:40 -0500 Subject: fix icon usage -- watch more signals, handle gicons, respect always-show-image better --- libdbusmenu-gtk/parser.c | 234 +++++++++++++++++++++++++++++------------------ 1 file changed, 146 insertions(+), 88 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 70cde53..38528d8 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -39,6 +39,7 @@ typedef struct _ParserData GtkAction *action; GtkWidget *widget; GtkWidget *shell; + GtkWidget *image; } ParserData; typedef struct _RecurseContext @@ -51,22 +52,25 @@ static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * re static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget); static void accel_changed (GtkWidget * widget, gpointer data); -static gboolean update_stock_item (DbusmenuMenuitem * menuitem, - GtkWidget * widget); static void checkbox_toggled (GtkWidget * widget, DbusmenuMenuitem * mi); -static void update_icon_name (DbusmenuMenuitem * menuitem, - GtkWidget * widget); +static void update_icon (DbusmenuMenuitem * menuitem, + GtkImage * image); static GtkWidget * find_menu_label (GtkWidget * widget); static void label_notify_cb (GtkWidget * widget, GParamSpec * pspec, gpointer data); +static void image_notify_cb (GtkWidget * widget, + GParamSpec * pspec, + gpointer data); static void action_notify_cb (GtkAction * action, GParamSpec * pspec, gpointer data); static void child_added_cb (GtkContainer * menu, GtkWidget * widget, gpointer data); +static void theme_changed_cb (GtkIconTheme * theme, + gpointer data); static void item_activated (DbusmenuMenuitem * item, guint timestamp, gpointer user_data); @@ -136,6 +140,11 @@ dbusmenu_cache_freed (gpointer data, GObject * obj) g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell); } + if (pdata != NULL && pdata->image != NULL) { + g_signal_handlers_disconnect_by_func(pdata->image, G_CALLBACK(image_notify_cb), obj); + g_object_remove_weak_pointer(G_OBJECT(pdata->image), (gpointer*)&pdata->image); + } + return; } @@ -148,6 +157,9 @@ object_cache_freed (gpointer data) //if (!G_IS_OBJECT(obj)) return; //g_object_weak_unref(G_OBJECT(obj), dbusmenu_cache_freed, data); //dbusmenu_cache_freed(data, obj); + + g_signal_handlers_disconnect_by_func(gtk_icon_theme_get_default(), G_CALLBACK(theme_changed_cb), data); + return; } @@ -347,8 +359,6 @@ construct_dbusmenu_for_widget (GtkWidget * widget) } else { - gboolean label_set = FALSE; - g_signal_connect (widget, "accel-closures-changed", G_CALLBACK (accel_changed), @@ -373,41 +383,37 @@ construct_dbusmenu_for_widget (GtkWidget * widget) 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))); - } + update_icon (mi, GTK_IMAGE (image)); + + /* Watch for theme changes because if gicon changes, we want to send a + different pixbuf. */ + g_signal_connect(G_OBJECT(gtk_icon_theme_get_default()), + "changed", G_CALLBACK(theme_changed_cb), widget); + + pdata->image = image; + g_signal_connect (G_OBJECT (image), + "notify", + G_CALLBACK (image_notify_cb), + mi); + g_object_add_weak_pointer(G_OBJECT (image), (gpointer*)&pdata->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. + dbusmenu_menuitem_property_set (mi, + "label", + gtk_label_get_text (GTK_LABEL (label))); + pdata->label = label; g_signal_connect (G_OBJECT (label), "notify", @@ -510,48 +516,6 @@ accel_changed (GtkWidget *widget, dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); } -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; - - gchar * stock_id = NULL; - gtk_image_get_stock(image, &stock_id, NULL); - - gtk_stock_lookup (stock_id, &stock); - - if (should_show_image (image)) - dbusmenu_menuitem_property_set (menuitem, - DBUSMENU_MENUITEM_PROP_ICON_NAME, - 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 checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi) { @@ -561,27 +525,82 @@ checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi) } static void -update_icon_name (DbusmenuMenuitem *menuitem, - GtkWidget *widget) +update_icon (DbusmenuMenuitem *menuitem, GtkImage *image) { - GtkImage *image; - - g_return_if_fail (GTK_IS_IMAGE (widget)); - - image = GTK_IMAGE (widget); + GdkPixbuf * pixbuf = NULL; + const gchar * icon_name = NULL; + GtkStockItem stock; + GIcon * gicon; + GtkIconInfo * info; + gint width; + + if (image != NULL && should_show_image (image)) { + switch (gtk_image_get_storage_type (image)) { + case GTK_IMAGE_PIXBUF: + pixbuf = g_object_ref (gtk_image_get_pixbuf (image)); + break; + + case GTK_IMAGE_ICON_NAME: + gtk_image_get_icon_name (image, &icon_name, NULL); + break; + + case GTK_IMAGE_STOCK: + gtk_image_get_stock (image, (gchar **) &icon_name, NULL); + if (gtk_stock_lookup (icon_name, &stock)) { + /* Now set label too */ + const gchar * label = NULL; + 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); + } + } + break; + + case GTK_IMAGE_GICON: + /* Load up a pixbuf and send that over. We don't bother differentiating + between icon-name gicons and pixbuf gicons because even when given a + icon-name gicon, there's no easy way to lookup which icon-name among + its set is present and should be used among the icon themes available. + So instead, we render to a pixbuf and watch icon theme changes. */ + gtk_image_get_gicon (image, &gicon, NULL); + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, NULL); + info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), + gicon, width, + GTK_ICON_LOOKUP_FORCE_SIZE); + if (info != NULL) { + pixbuf = gtk_icon_info_load_icon (info, NULL); + gtk_icon_info_free (info); + } + break; - if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME) - return; + default: + g_debug ("Could not handle image type %i\n", gtk_image_get_storage_type (image)); + break; + } + } - if (should_show_image (image)) { - const gchar * icon_name = NULL; - gtk_image_get_icon_name(image, &icon_name, NULL); + if (icon_name != NULL) { dbusmenu_menuitem_property_set (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME, icon_name); - } else { + } + else if (pixbuf != NULL) { + dbusmenu_menuitem_property_set_image (menuitem, + DBUSMENU_MENUITEM_PROP_ICON_DATA, + pixbuf); + } + else { dbusmenu_menuitem_property_remove (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME); + dbusmenu_menuitem_property_remove (menuitem, + DBUSMENU_MENUITEM_PROP_ICON_DATA); + } + + if (pixbuf != NULL) { + g_object_unref (pixbuf); } } @@ -629,6 +648,29 @@ label_notify_cb (GtkWidget *widget, } } +static void +image_notify_cb (GtkWidget *widget, + GParamSpec *pspec, + gpointer data) +{ + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; + + if (pspec->name == g_intern_static_string ("file") || + pspec->name == g_intern_static_string ("gicon") || + pspec->name == g_intern_static_string ("icon-name") || + pspec->name == g_intern_static_string ("icon-set") || + pspec->name == g_intern_static_string ("image") || + pspec->name == g_intern_static_string ("mask") || + pspec->name == g_intern_static_string ("pixbuf") || + pspec->name == g_intern_static_string ("pixbuf-animation") || + pspec->name == g_intern_static_string ("pixmap") || + pspec->name == g_intern_static_string ("stock") || + pspec->name == g_intern_static_string ("storage-type")) + { + update_icon (mi, GTK_IMAGE (widget)); + } +} + static void action_notify_cb (GtkAction *action, GParamSpec *pspec, @@ -723,13 +765,12 @@ widget_notify_cb (GtkWidget *widget, 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")) + else if (pspec->name == g_intern_static_string ("image") || + pspec->name == g_intern_static_string ("always-show-image")) { - update_icon_name (child, widget); + GtkWidget *image; + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget)); + update_icon (child, GTK_IMAGE (image)); } else if (pspec->name == g_intern_static_string ("parent")) { @@ -797,6 +838,23 @@ child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data) parse_menu_structure_helper(widget, &recurse); } +static void +theme_changed_cb (GtkIconTheme *theme, gpointer data) +{ + GtkWidget *image; + + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (data)); + + gpointer pmi = g_object_get_data(G_OBJECT(data), CACHED_MENUITEM); + if (pmi != NULL) { + update_icon(DBUSMENU_MENUITEM(pmi), GTK_IMAGE(image)); + } + + /* Switch signal to new theme */ + g_signal_handlers_disconnect_by_func(theme, G_CALLBACK(theme_changed_cb), data); + g_signal_connect(gtk_icon_theme_get_default(), "changed", G_CALLBACK(theme_changed_cb), data); +} + static gboolean should_show_image (GtkImage *image) { -- cgit v1.2.3 From 558fa9265c05452de03ddd9f8543dfdce1b81e7b Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Wed, 16 Feb 2011 21:06:14 +0100 Subject: Fix GI annotations for DbusmenuGtk --- libdbusmenu-gtk/parser.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 70cde53..d00870a 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -81,16 +81,16 @@ static void menuitem_notify_cb (GtkWidget * widget, gpointer data); /** - dbusmenu_gtk_parse_menu_structure: - @widget: A #GtkMenuItem or #GtkMenuShell to turn into a #DbusmenuMenuitem - - Goes through the GTK structures and turns them into the appropraite - Dbusmenu structures along with setting up all the relationships - between the objects. It also stores the dbusmenu items as a cache - on the GTK items so that they'll be reused if necissary. - - Return value: A dbusmenu item representing the menu structure -*/ + * dbusmenu_gtk_parse_menu_structure: + * @widget: A #GtkMenuItem or #GtkMenuShell to turn into a #DbusmenuMenuitem + * + * Goes through the GTK structures and turns them into the appropraite + * Dbusmenu structures along with setting up all the relationships + * between the objects. It also stores the dbusmenu items as a cache + * on the GTK items so that they'll be reused if necissary. + * + * Return value: (transfer none): A dbusmenu item representing the menu structure + */ DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) { -- cgit v1.2.3 From 2ee586c80b9cd334cc98559a9754c3492d01e8b3 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Thu, 17 Feb 2011 07:48:27 -0500 Subject: make sure other icon property is removed when setting one --- libdbusmenu-gtk/parser.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 38528d8..8aa2837 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -586,8 +586,12 @@ update_icon (DbusmenuMenuitem *menuitem, GtkImage *image) dbusmenu_menuitem_property_set (menuitem, DBUSMENU_MENUITEM_PROP_ICON_NAME, icon_name); + dbusmenu_menuitem_property_remove (menuitem, + DBUSMENU_MENUITEM_PROP_ICON_DATA); } else if (pixbuf != NULL) { + dbusmenu_menuitem_property_remove (menuitem, + DBUSMENU_MENUITEM_PROP_ICON_NAME); dbusmenu_menuitem_property_set_image (menuitem, DBUSMENU_MENUITEM_PROP_ICON_DATA, pixbuf); -- cgit v1.2.3 From fec6317262d94b29c41fa0632236910b4bd11244 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 21 Feb 2011 09:54:31 -0600 Subject: Fixing transfer from the parser to be full --- libdbusmenu-gtk/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdbusmenu-gtk/parser.c') diff --git a/libdbusmenu-gtk/parser.c b/libdbusmenu-gtk/parser.c index 180b66e..f516dde 100644 --- a/libdbusmenu-gtk/parser.c +++ b/libdbusmenu-gtk/parser.c @@ -93,7 +93,7 @@ static void menuitem_notify_cb (GtkWidget * widget, * between the objects. It also stores the dbusmenu items as a cache * on the GTK items so that they'll be reused if necissary. * - * Return value: (transfer none): A dbusmenu item representing the menu structure + * Return value: (transfer full): A dbusmenu item representing the menu structure */ DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) -- cgit v1.2.3