]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconhelper.c
Updated Norwegian nynorsk translation
[~andy/gtk] / gtk / gtkiconhelper.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Red Hat, Inc.
3  *
4  * Authors: Cosimo Cecchi <cosimoc@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21
22 #include "gtkiconhelperprivate.h"
23
24 G_DEFINE_TYPE (GtkIconHelper, _gtk_icon_helper, G_TYPE_OBJECT)
25
26 struct _GtkIconHelperPrivate {
27   GtkImageType storage_type;
28
29   GdkPixbuf *orig_pixbuf;
30   GdkPixbufAnimation *animation;
31   GIcon *gicon;
32   GtkIconSet *icon_set;
33   gchar *icon_name;
34   gchar *stock_id;
35
36   GtkIconSize icon_size;
37   gint pixel_size;
38
39   gboolean use_fallback;
40
41   GdkPixbuf *rendered_pixbuf;
42   GtkStateFlags last_rendered_state;
43 };
44
45 void
46 _gtk_icon_helper_clear (GtkIconHelper *self)
47 {
48   g_clear_object (&self->priv->gicon);
49   g_clear_object (&self->priv->orig_pixbuf);
50   g_clear_object (&self->priv->animation);
51   g_clear_object (&self->priv->rendered_pixbuf);
52
53   if (self->priv->icon_set != NULL)
54     {
55       gtk_icon_set_unref (self->priv->icon_set);
56       self->priv->icon_set = NULL;
57     }
58
59   g_free (self->priv->icon_name);
60   self->priv->icon_name = NULL;
61
62   g_free (self->priv->stock_id);
63   self->priv->stock_id = NULL;
64
65   self->priv->storage_type = GTK_IMAGE_EMPTY;
66   self->priv->icon_size = GTK_ICON_SIZE_INVALID;
67   self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
68 }
69
70 void
71 _gtk_icon_helper_invalidate (GtkIconHelper *self)
72 {
73   g_clear_object (&self->priv->rendered_pixbuf);
74 }
75
76 static void
77 gtk_icon_helper_finalize (GObject *object)
78 {
79   GtkIconHelper *self = GTK_ICON_HELPER (object);
80
81   _gtk_icon_helper_clear (self);
82   
83   G_OBJECT_CLASS (_gtk_icon_helper_parent_class)->finalize (object);
84 }
85
86 static void
87 _gtk_icon_helper_class_init (GtkIconHelperClass *klass)
88 {
89   GObjectClass *oclass;
90
91   oclass = G_OBJECT_CLASS (klass);
92   oclass->finalize = gtk_icon_helper_finalize;
93
94   g_type_class_add_private (klass, sizeof (GtkIconHelperPrivate));
95 }
96
97 static void
98 _gtk_icon_helper_init (GtkIconHelper *self)
99 {
100   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_ICON_HELPER, GtkIconHelperPrivate);
101
102   self->priv->storage_type = GTK_IMAGE_EMPTY;
103   self->priv->icon_size = GTK_ICON_SIZE_INVALID;
104   self->priv->pixel_size = -1;
105   self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
106 }
107
108 static void
109 ensure_icon_size (GtkIconHelper *self,
110                   GtkStyleContext *context,
111                   gint *width_out,
112                   gint *height_out)
113 {
114   gint width, height;
115   GtkSettings *settings;
116   GdkScreen *screen;
117
118   screen = gtk_style_context_get_screen (context);
119   settings = gtk_settings_get_for_screen (screen);
120
121   if (self->priv->pixel_size != -1)
122     {
123       width = height = self->priv->pixel_size;
124     }
125   else if (!gtk_icon_size_lookup_for_settings (settings,
126                                                self->priv->icon_size,
127                                                &width, &height))
128     {
129       if (self->priv->icon_size == GTK_ICON_SIZE_INVALID)
130         {
131           width = height = 0;
132         }
133       else
134         {
135           g_warning ("Invalid icon size %d\n", self->priv->icon_size);
136           width = height = 24;
137         }
138     }
139
140   *width_out = width;
141   *height_out = height;
142 }
143
144 static GdkPixbuf *
145 ensure_stated_icon_from_info (GtkIconHelper *self,
146                               GtkStyleContext *context,
147                               GtkIconInfo *info)
148 {
149   GdkPixbuf *destination = NULL;
150   gboolean symbolic;
151
152   symbolic = FALSE;
153
154   if (info)
155     destination =
156       gtk_icon_info_load_symbolic_for_context (info,
157                                                context,
158                                                &symbolic,
159                                                NULL);
160
161   if (destination == NULL)
162     {
163       GtkIconSet *icon_set;
164       icon_set = gtk_style_context_lookup_icon_set (context, GTK_STOCK_MISSING_IMAGE);
165
166       destination =
167         gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
168     }
169   else if (!symbolic)
170     {
171       GtkIconSource *source;
172       GdkPixbuf *rendered;
173
174       source = gtk_icon_source_new ();
175       gtk_icon_source_set_pixbuf (source, destination);
176       /* The size here is arbitrary; since size isn't
177        * wildcarded in the source, it isn't supposed to be
178        * scaled by the engine function
179        */
180       gtk_icon_source_set_size (source,
181                                 GTK_ICON_SIZE_SMALL_TOOLBAR);
182       gtk_icon_source_set_size_wildcarded (source, FALSE);
183
184       rendered = gtk_render_icon_pixbuf (context, source, (GtkIconSize) -1);
185       gtk_icon_source_free (source);
186
187       g_object_unref (destination);
188       destination = rendered;
189     }
190
191   return destination;
192 }
193
194 static gboolean
195 check_invalidate_pixbuf (GtkIconHelper *self,
196                          GtkStyleContext *context)
197 {
198   GtkStateFlags state;
199
200   state = gtk_style_context_get_state (context);
201
202   if ((self->priv->rendered_pixbuf != NULL) &&
203       (self->priv->last_rendered_state == state))
204     return FALSE;
205
206   self->priv->last_rendered_state = state;
207   g_clear_object (&self->priv->rendered_pixbuf);
208
209   return TRUE;
210 }
211
212 static GtkIconLookupFlags
213 get_icon_lookup_flags (GtkIconHelper *self)
214 {
215   GtkIconLookupFlags flags = GTK_ICON_LOOKUP_USE_BUILTIN;
216
217   if (self->priv->use_fallback)
218     flags |= GTK_ICON_LOOKUP_GENERIC_FALLBACK;
219   if (self->priv->pixel_size != -1)
220     flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
221
222   return flags;
223 }
224
225 static void
226 ensure_pixbuf_for_icon_name_or_gicon (GtkIconHelper *self,
227                                       GtkStyleContext *context)
228 {
229   GtkIconTheme *icon_theme;
230   gint width, height;
231   GtkIconInfo *info;
232   GtkIconLookupFlags flags;
233
234   if (!check_invalidate_pixbuf (self, context))
235     return;
236
237   icon_theme = gtk_icon_theme_get_default ();
238   flags = get_icon_lookup_flags (self);
239
240   ensure_icon_size (self, context, &width, &height);
241
242   if (self->priv->storage_type == GTK_IMAGE_ICON_NAME &&
243       self->priv->icon_name != NULL)
244     {
245       info = gtk_icon_theme_lookup_icon (icon_theme,
246                                          self->priv->icon_name,
247                                          MIN (width, height), flags);
248     }
249   else if (self->priv->storage_type == GTK_IMAGE_GICON &&
250            self->priv->gicon != NULL)
251     {
252       info = gtk_icon_theme_lookup_by_gicon (icon_theme,
253                                              self->priv->gicon,
254                                              MIN (width, height), flags);
255     }
256   else
257     {
258       g_assert_not_reached ();
259       return;
260     }
261
262   self->priv->rendered_pixbuf = ensure_stated_icon_from_info (self, context, info);
263
264   if (info)
265     gtk_icon_info_free (info);
266 }
267
268 static void
269 ensure_pixbuf_for_icon_set (GtkIconHelper *self,
270                             GtkStyleContext *context,
271                             GtkIconSet *icon_set)
272 {
273   if (!check_invalidate_pixbuf (self, context))
274     return;
275
276   self->priv->rendered_pixbuf = 
277     gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
278 }
279
280 GdkPixbuf *
281 _gtk_icon_helper_ensure_pixbuf (GtkIconHelper *self,
282                                 GtkStyleContext *context)
283 {
284   GdkPixbuf *pixbuf = NULL;
285   GtkIconSet *icon_set;
286
287   switch (self->priv->storage_type)
288     {
289     case GTK_IMAGE_PIXBUF:
290       pixbuf = g_object_ref (self->priv->orig_pixbuf);
291       break;
292
293     case GTK_IMAGE_STOCK:
294       icon_set = gtk_style_context_lookup_icon_set (context, self->priv->stock_id);
295       ensure_pixbuf_for_icon_set (self, context, icon_set);
296       break;
297
298     case GTK_IMAGE_ICON_SET:
299       icon_set = self->priv->icon_set;
300       ensure_pixbuf_for_icon_set (self, context, icon_set);
301       break;
302
303     case GTK_IMAGE_ICON_NAME:
304     case GTK_IMAGE_GICON:
305       ensure_pixbuf_for_icon_name_or_gicon (self, context);
306       break;
307
308     case GTK_IMAGE_ANIMATION:
309     case GTK_IMAGE_EMPTY:
310     default:
311       pixbuf = NULL;
312       break;
313     }
314
315   if (pixbuf == NULL &&
316       self->priv->rendered_pixbuf != NULL)
317     pixbuf = g_object_ref (self->priv->rendered_pixbuf);
318
319   return pixbuf;
320 }
321
322 void
323 _gtk_icon_helper_get_size (GtkIconHelper *self,
324                            GtkStyleContext *context,
325                            gint *width_out,
326                            gint *height_out)
327 {
328   GdkPixbuf *pix;
329   gint width, height;
330
331   width = height = 0;
332   pix = _gtk_icon_helper_ensure_pixbuf (self, context);
333
334   if (pix != NULL)
335     {
336       width = gdk_pixbuf_get_width (pix);
337       height = gdk_pixbuf_get_height (pix);
338
339       g_object_unref (pix);
340     }
341   else if (self->priv->storage_type == GTK_IMAGE_ANIMATION)
342     {
343       width = gdk_pixbuf_animation_get_width (self->priv->animation);
344       height = gdk_pixbuf_animation_get_height (self->priv->animation);
345     }
346   else if (self->priv->icon_size != -1)
347     {
348       ensure_icon_size (self, context, &width, &height);
349     }
350
351   if (width_out)
352     *width_out = width;
353   if (height_out)
354     *height_out = height;
355 }
356
357 void 
358 _gtk_icon_helper_set_gicon (GtkIconHelper *self,
359                             GIcon *gicon,
360                             GtkIconSize icon_size)
361 {
362   _gtk_icon_helper_clear (self);
363
364   if (gicon != NULL)
365     {
366       self->priv->storage_type = GTK_IMAGE_GICON;
367       self->priv->gicon = g_object_ref (gicon);
368       _gtk_icon_helper_set_icon_size (self, icon_size);
369     }
370 }
371
372 void 
373 _gtk_icon_helper_set_icon_name (GtkIconHelper *self,
374                                 const gchar *icon_name,
375                                 GtkIconSize icon_size)
376 {
377   _gtk_icon_helper_clear (self);
378
379   if (icon_name != NULL &&
380       g_strcmp0 (icon_name, "") != 0)
381     {
382       self->priv->storage_type = GTK_IMAGE_ICON_NAME;
383       self->priv->icon_name = g_strdup (icon_name);
384       _gtk_icon_helper_set_icon_size (self, icon_size);
385     }
386 }
387
388 void 
389 _gtk_icon_helper_set_icon_set (GtkIconHelper *self,
390                                GtkIconSet *icon_set,
391                                GtkIconSize icon_size)
392 {
393   _gtk_icon_helper_clear (self);
394
395   if (icon_set != NULL)
396     {
397       self->priv->storage_type = GTK_IMAGE_ICON_SET;
398       self->priv->icon_set = gtk_icon_set_ref (icon_set);
399       _gtk_icon_helper_set_icon_size (self, icon_size);
400     }
401 }
402
403 void 
404 _gtk_icon_helper_set_pixbuf (GtkIconHelper *self,
405                              GdkPixbuf *pixbuf)
406 {
407   _gtk_icon_helper_clear (self);
408
409   if (pixbuf != NULL)
410     {
411       self->priv->storage_type = GTK_IMAGE_PIXBUF;
412       self->priv->orig_pixbuf = g_object_ref (pixbuf);
413     }
414 }
415
416 void 
417 _gtk_icon_helper_set_animation (GtkIconHelper *self,
418                                 GdkPixbufAnimation *animation)
419 {
420   _gtk_icon_helper_clear (self);
421
422   if (animation != NULL)
423     {
424       self->priv->storage_type = GTK_IMAGE_ANIMATION;
425       self->priv->animation = g_object_ref (animation);
426     }
427 }
428
429 void 
430 _gtk_icon_helper_set_stock_id (GtkIconHelper *self,
431                                const gchar *stock_id,
432                                GtkIconSize icon_size)
433 {
434   _gtk_icon_helper_clear (self);
435
436   if (stock_id != NULL)
437     {
438       self->priv->storage_type = GTK_IMAGE_STOCK;
439       self->priv->stock_id = g_strdup (stock_id);
440       _gtk_icon_helper_set_icon_size (self, icon_size);
441     }
442 }
443
444 void 
445 _gtk_icon_helper_set_icon_size (GtkIconHelper *self,
446                                 GtkIconSize icon_size)
447 {
448   if (self->priv->icon_size != icon_size)
449     {
450       self->priv->icon_size = icon_size;
451       _gtk_icon_helper_invalidate (self);
452     }
453 }
454
455 void 
456 _gtk_icon_helper_set_pixel_size (GtkIconHelper *self,
457                                  gint pixel_size)
458 {
459   if (self->priv->pixel_size != pixel_size)
460     {
461       self->priv->pixel_size = pixel_size;
462       _gtk_icon_helper_invalidate (self);
463     }
464 }
465
466 void 
467 _gtk_icon_helper_set_use_fallback (GtkIconHelper *self,
468                                    gboolean use_fallback)
469 {
470   if (self->priv->use_fallback != use_fallback)
471     {
472       self->priv->use_fallback = use_fallback;
473       _gtk_icon_helper_invalidate (self);
474     }
475 }
476
477 GtkImageType
478 _gtk_icon_helper_get_storage_type (GtkIconHelper *self)
479 {
480   return self->priv->storage_type;
481 }
482
483 gboolean
484 _gtk_icon_helper_get_use_fallback (GtkIconHelper *self)
485 {
486   return self->priv->use_fallback;
487 }
488
489 GtkIconSize
490 _gtk_icon_helper_get_icon_size (GtkIconHelper *self)
491 {
492   return self->priv->icon_size;
493 }
494
495 gint
496 _gtk_icon_helper_get_pixel_size (GtkIconHelper *self)
497 {
498   return self->priv->pixel_size;
499 }
500
501 GdkPixbuf *
502 _gtk_icon_helper_peek_pixbuf (GtkIconHelper *self)
503 {
504   return self->priv->orig_pixbuf;
505 }
506
507 GIcon *
508 _gtk_icon_helper_peek_gicon (GtkIconHelper *self)
509 {
510   return self->priv->gicon;
511 }
512
513 GdkPixbufAnimation *
514 _gtk_icon_helper_peek_animation (GtkIconHelper *self)
515 {
516   return self->priv->animation;
517 }
518
519 GtkIconSet *
520 _gtk_icon_helper_peek_icon_set (GtkIconHelper *self)
521 {
522   return self->priv->icon_set;
523 }
524
525 const gchar *
526 _gtk_icon_helper_get_stock_id (GtkIconHelper *self)
527 {
528   return self->priv->stock_id;
529 }
530
531 const gchar *
532 _gtk_icon_helper_get_icon_name (GtkIconHelper *self)
533 {
534   return self->priv->icon_name;
535 }
536
537 GtkIconHelper *
538 _gtk_icon_helper_new (void)
539 {
540   return g_object_new (GTK_TYPE_ICON_HELPER, NULL);
541 }
542
543 void
544 _gtk_icon_helper_draw (GtkIconHelper *self,
545                        GtkStyleContext *context,
546                        cairo_t *cr,
547                        gdouble x,
548                        gdouble y)
549 {
550   GdkPixbuf *pixbuf;
551
552   pixbuf = _gtk_icon_helper_ensure_pixbuf (self, context);
553
554   if (pixbuf != NULL)
555     {
556       gtk_render_icon (context, cr, pixbuf, x, y);
557       g_object_unref (pixbuf);
558     }
559 }
560
561 gboolean
562 _gtk_icon_helper_get_is_empty (GtkIconHelper *self)
563 {
564   return (self->priv->storage_type == GTK_IMAGE_EMPTY);
565 }