Merge lp:~mterry/libdbusmenu/handle-icons-better into lp:libdbusmenu/0.5

Proposed by Michael Terry
Status: Merged
Merged at revision: 211
Proposed branch: lp:~mterry/libdbusmenu/handle-icons-better
Merge into: lp:libdbusmenu/0.5
Diff against target: 358 lines (+155/-93)
1 file modified
libdbusmenu-gtk/parser.c (+155/-93)
To merge this branch: bzr merge lp:~mterry/libdbusmenu/handle-icons-better
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+49321@code.launchpad.net

Description of the change

This branch does several things:

 * Consolidates the various update_*_icon methods into one giant update_icon method that handles any type of icon. This makes it easier to handle when images switch icon types and just generally keeps similar logic in one place.

 * Handles GIcon images

 * Watches always-show-image status of the GtkMenuItem

 * Watches lots of properties of the embedded GtkImage in a GtkMenuItem for changes

This was spurred on by bug 715864 and in particular, the menus of nautilus. They should now show up excellently.

To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2011-02-10 at 23:32 +0000, Michael Terry wrote:
> + 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);
> + }

I think in this statement it should remove the opposite property so that
we know only one is set in the end.

  review needsfixing

review: Needs Fixing
209. By Michael Terry

make sure other icon property is removed when setting one

Revision history for this message
Michael Terry (mterry) wrote :

OK, done.

Revision history for this message
Ted Gould (ted) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libdbusmenu-gtk/parser.c'
2--- libdbusmenu-gtk/parser.c 2011-02-04 19:31:59 +0000
3+++ libdbusmenu-gtk/parser.c 2011-02-17 12:52:44 +0000
4@@ -39,6 +39,7 @@
5 GtkAction *action;
6 GtkWidget *widget;
7 GtkWidget *shell;
8+ GtkWidget *image;
9 } ParserData;
10
11 typedef struct _RecurseContext
12@@ -51,22 +52,25 @@
13 static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget);
14 static void accel_changed (GtkWidget * widget,
15 gpointer data);
16-static gboolean update_stock_item (DbusmenuMenuitem * menuitem,
17- GtkWidget * widget);
18 static void checkbox_toggled (GtkWidget * widget,
19 DbusmenuMenuitem * mi);
20-static void update_icon_name (DbusmenuMenuitem * menuitem,
21- GtkWidget * widget);
22+static void update_icon (DbusmenuMenuitem * menuitem,
23+ GtkImage * image);
24 static GtkWidget * find_menu_label (GtkWidget * widget);
25 static void label_notify_cb (GtkWidget * widget,
26 GParamSpec * pspec,
27 gpointer data);
28+static void image_notify_cb (GtkWidget * widget,
29+ GParamSpec * pspec,
30+ gpointer data);
31 static void action_notify_cb (GtkAction * action,
32 GParamSpec * pspec,
33 gpointer data);
34 static void child_added_cb (GtkContainer * menu,
35 GtkWidget * widget,
36 gpointer data);
37+static void theme_changed_cb (GtkIconTheme * theme,
38+ gpointer data);
39 static void item_activated (DbusmenuMenuitem * item,
40 guint timestamp,
41 gpointer user_data);
42@@ -136,6 +140,11 @@
43 g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell);
44 }
45
46+ if (pdata != NULL && pdata->image != NULL) {
47+ g_signal_handlers_disconnect_by_func(pdata->image, G_CALLBACK(image_notify_cb), obj);
48+ g_object_remove_weak_pointer(G_OBJECT(pdata->image), (gpointer*)&pdata->image);
49+ }
50+
51 return;
52 }
53
54@@ -148,6 +157,9 @@
55 //if (!G_IS_OBJECT(obj)) return;
56 //g_object_weak_unref(G_OBJECT(obj), dbusmenu_cache_freed, data);
57 //dbusmenu_cache_freed(data, obj);
58+
59+ g_signal_handlers_disconnect_by_func(gtk_icon_theme_get_default(), G_CALLBACK(theme_changed_cb), data);
60+
61 return;
62 }
63
64@@ -347,8 +359,6 @@
65 }
66 else
67 {
68- gboolean label_set = FALSE;
69-
70 g_signal_connect (widget,
71 "accel-closures-changed",
72 G_CALLBACK (accel_changed),
73@@ -373,41 +383,37 @@
74 if (GTK_IS_IMAGE_MENU_ITEM (widget))
75 {
76 GtkWidget *image;
77- GtkImageType image_type;
78
79 image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
80
81 if (GTK_IS_IMAGE (image))
82 {
83- image_type = gtk_image_get_storage_type (GTK_IMAGE (image));
84-
85- if (image_type == GTK_IMAGE_STOCK)
86- {
87- label_set = update_stock_item (mi, image);
88- }
89- else if (image_type == GTK_IMAGE_ICON_NAME)
90- {
91- update_icon_name (mi, image);
92- }
93- else if (image_type == GTK_IMAGE_PIXBUF)
94- {
95- dbusmenu_menuitem_property_set_image (mi,
96- DBUSMENU_MENUITEM_PROP_ICON_DATA,
97- gtk_image_get_pixbuf (GTK_IMAGE (image)));
98- }
99+ update_icon (mi, GTK_IMAGE (image));
100+
101+ /* Watch for theme changes because if gicon changes, we want to send a
102+ different pixbuf. */
103+ g_signal_connect(G_OBJECT(gtk_icon_theme_get_default()),
104+ "changed", G_CALLBACK(theme_changed_cb), widget);
105+
106+ pdata->image = image;
107+ g_signal_connect (G_OBJECT (image),
108+ "notify",
109+ G_CALLBACK (image_notify_cb),
110+ mi);
111+ g_object_add_weak_pointer(G_OBJECT (image), (gpointer*)&pdata->image);
112 }
113 }
114
115 GtkWidget *label = find_menu_label (widget);
116
117- dbusmenu_menuitem_property_set (mi,
118- "label",
119- label ? gtk_label_get_text (GTK_LABEL (label)) : NULL);
120-
121 if (label)
122 {
123 // Sometimes, an app will directly find and modify the label
124 // (like empathy), so watch the label especially for that.
125+ dbusmenu_menuitem_property_set (mi,
126+ "label",
127+ gtk_label_get_text (GTK_LABEL (label)));
128+
129 pdata->label = label;
130 g_signal_connect (G_OBJECT (label),
131 "notify",
132@@ -510,48 +516,6 @@
133 dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
134 }
135
136-static gboolean
137-update_stock_item (DbusmenuMenuitem *menuitem,
138- GtkWidget *widget)
139-{
140- GtkStockItem stock;
141- GtkImage *image;
142-
143- g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
144-
145- image = GTK_IMAGE (widget);
146-
147- if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK)
148- return FALSE;
149-
150- gchar * stock_id = NULL;
151- gtk_image_get_stock(image, &stock_id, NULL);
152-
153- gtk_stock_lookup (stock_id, &stock);
154-
155- if (should_show_image (image))
156- dbusmenu_menuitem_property_set (menuitem,
157- DBUSMENU_MENUITEM_PROP_ICON_NAME,
158- stock_id);
159- else
160- dbusmenu_menuitem_property_remove (menuitem,
161- DBUSMENU_MENUITEM_PROP_ICON_NAME);
162-
163- const gchar *label = dbusmenu_menuitem_property_get (menuitem,
164- DBUSMENU_MENUITEM_PROP_LABEL);
165-
166- if (stock.label != NULL && label != NULL)
167- {
168- dbusmenu_menuitem_property_set (menuitem,
169- DBUSMENU_MENUITEM_PROP_LABEL,
170- stock.label);
171-
172- return TRUE;
173- }
174-
175- return FALSE;
176-}
177-
178 static void
179 checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
180 {
181@@ -561,27 +525,86 @@
182 }
183
184 static void
185-update_icon_name (DbusmenuMenuitem *menuitem,
186- GtkWidget *widget)
187+update_icon (DbusmenuMenuitem *menuitem, GtkImage *image)
188 {
189- GtkImage *image;
190-
191- g_return_if_fail (GTK_IS_IMAGE (widget));
192-
193- image = GTK_IMAGE (widget);
194-
195- if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME)
196- return;
197-
198- if (should_show_image (image)) {
199- const gchar * icon_name = NULL;
200- gtk_image_get_icon_name(image, &icon_name, NULL);
201+ GdkPixbuf * pixbuf = NULL;
202+ const gchar * icon_name = NULL;
203+ GtkStockItem stock;
204+ GIcon * gicon;
205+ GtkIconInfo * info;
206+ gint width;
207+
208+ if (image != NULL && should_show_image (image)) {
209+ switch (gtk_image_get_storage_type (image)) {
210+ case GTK_IMAGE_PIXBUF:
211+ pixbuf = g_object_ref (gtk_image_get_pixbuf (image));
212+ break;
213+
214+ case GTK_IMAGE_ICON_NAME:
215+ gtk_image_get_icon_name (image, &icon_name, NULL);
216+ break;
217+
218+ case GTK_IMAGE_STOCK:
219+ gtk_image_get_stock (image, (gchar **) &icon_name, NULL);
220+ if (gtk_stock_lookup (icon_name, &stock)) {
221+ /* Now set label too */
222+ const gchar * label = NULL;
223+ label = dbusmenu_menuitem_property_get (menuitem,
224+ DBUSMENU_MENUITEM_PROP_LABEL);
225+ if (stock.label != NULL && label != NULL) {
226+ dbusmenu_menuitem_property_set (menuitem,
227+ DBUSMENU_MENUITEM_PROP_LABEL,
228+ stock.label);
229+ }
230+ }
231+ break;
232+
233+ case GTK_IMAGE_GICON:
234+ /* Load up a pixbuf and send that over. We don't bother differentiating
235+ between icon-name gicons and pixbuf gicons because even when given a
236+ icon-name gicon, there's no easy way to lookup which icon-name among
237+ its set is present and should be used among the icon themes available.
238+ So instead, we render to a pixbuf and watch icon theme changes. */
239+ gtk_image_get_gicon (image, &gicon, NULL);
240+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, NULL);
241+ info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
242+ gicon, width,
243+ GTK_ICON_LOOKUP_FORCE_SIZE);
244+ if (info != NULL) {
245+ pixbuf = gtk_icon_info_load_icon (info, NULL);
246+ gtk_icon_info_free (info);
247+ }
248+ break;
249+
250+ default:
251+ g_debug ("Could not handle image type %i\n", gtk_image_get_storage_type (image));
252+ break;
253+ }
254+ }
255+
256+ if (icon_name != NULL) {
257 dbusmenu_menuitem_property_set (menuitem,
258 DBUSMENU_MENUITEM_PROP_ICON_NAME,
259 icon_name);
260- } else {
261- dbusmenu_menuitem_property_remove (menuitem,
262- DBUSMENU_MENUITEM_PROP_ICON_NAME);
263+ dbusmenu_menuitem_property_remove (menuitem,
264+ DBUSMENU_MENUITEM_PROP_ICON_DATA);
265+ }
266+ else if (pixbuf != NULL) {
267+ dbusmenu_menuitem_property_remove (menuitem,
268+ DBUSMENU_MENUITEM_PROP_ICON_NAME);
269+ dbusmenu_menuitem_property_set_image (menuitem,
270+ DBUSMENU_MENUITEM_PROP_ICON_DATA,
271+ pixbuf);
272+ }
273+ else {
274+ dbusmenu_menuitem_property_remove (menuitem,
275+ DBUSMENU_MENUITEM_PROP_ICON_NAME);
276+ dbusmenu_menuitem_property_remove (menuitem,
277+ DBUSMENU_MENUITEM_PROP_ICON_DATA);
278+ }
279+
280+ if (pixbuf != NULL) {
281+ g_object_unref (pixbuf);
282 }
283 }
284
285@@ -630,6 +653,29 @@
286 }
287
288 static void
289+image_notify_cb (GtkWidget *widget,
290+ GParamSpec *pspec,
291+ gpointer data)
292+{
293+ DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
294+
295+ if (pspec->name == g_intern_static_string ("file") ||
296+ pspec->name == g_intern_static_string ("gicon") ||
297+ pspec->name == g_intern_static_string ("icon-name") ||
298+ pspec->name == g_intern_static_string ("icon-set") ||
299+ pspec->name == g_intern_static_string ("image") ||
300+ pspec->name == g_intern_static_string ("mask") ||
301+ pspec->name == g_intern_static_string ("pixbuf") ||
302+ pspec->name == g_intern_static_string ("pixbuf-animation") ||
303+ pspec->name == g_intern_static_string ("pixmap") ||
304+ pspec->name == g_intern_static_string ("stock") ||
305+ pspec->name == g_intern_static_string ("storage-type"))
306+ {
307+ update_icon (mi, GTK_IMAGE (widget));
308+ }
309+}
310+
311+static void
312 action_notify_cb (GtkAction *action,
313 GParamSpec *pspec,
314 gpointer data)
315@@ -723,13 +769,12 @@
316 DBUSMENU_MENUITEM_PROP_VISIBLE,
317 gtk_widget_get_visible (widget));
318 }
319- else if (pspec->name == g_intern_static_string ("stock"))
320- {
321- update_stock_item (child, widget);
322- }
323- else if (pspec->name == g_intern_static_string ("icon-name"))
324- {
325- update_icon_name (child, widget);
326+ else if (pspec->name == g_intern_static_string ("image") ||
327+ pspec->name == g_intern_static_string ("always-show-image"))
328+ {
329+ GtkWidget *image;
330+ image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
331+ update_icon (child, GTK_IMAGE (image));
332 }
333 else if (pspec->name == g_intern_static_string ("parent"))
334 {
335@@ -797,6 +842,23 @@
336 parse_menu_structure_helper(widget, &recurse);
337 }
338
339+static void
340+theme_changed_cb (GtkIconTheme *theme, gpointer data)
341+{
342+ GtkWidget *image;
343+
344+ image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (data));
345+
346+ gpointer pmi = g_object_get_data(G_OBJECT(data), CACHED_MENUITEM);
347+ if (pmi != NULL) {
348+ update_icon(DBUSMENU_MENUITEM(pmi), GTK_IMAGE(image));
349+ }
350+
351+ /* Switch signal to new theme */
352+ g_signal_handlers_disconnect_by_func(theme, G_CALLBACK(theme_changed_cb), data);
353+ g_signal_connect(gtk_icon_theme_get_default(), "changed", G_CALLBACK(theme_changed_cb), data);
354+}
355+
356 static gboolean
357 should_show_image (GtkImage *image)
358 {

Subscribers

People subscribed via source and target branches