1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Red Hat, Inc.
4 * Authors: Cosimo Cecchi <cosimoc@gnome.org>
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.
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.
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/>.
22 #include "gtkiconhelperprivate.h"
24 G_DEFINE_TYPE (GtkIconHelper, _gtk_icon_helper, G_TYPE_OBJECT)
26 struct _GtkIconHelperPrivate {
27 GtkImageType storage_type;
29 GdkPixbuf *orig_pixbuf;
30 GdkPixbufAnimation *animation;
36 GtkIconSize icon_size;
39 guint use_fallback : 1;
40 guint force_scale_pixbuf : 1;
42 GdkPixbuf *rendered_pixbuf;
43 GtkStateFlags last_rendered_state;
47 _gtk_icon_helper_clear (GtkIconHelper *self)
49 g_clear_object (&self->priv->gicon);
50 g_clear_object (&self->priv->orig_pixbuf);
51 g_clear_object (&self->priv->animation);
52 g_clear_object (&self->priv->rendered_pixbuf);
54 if (self->priv->icon_set != NULL)
56 gtk_icon_set_unref (self->priv->icon_set);
57 self->priv->icon_set = NULL;
60 g_free (self->priv->icon_name);
61 self->priv->icon_name = NULL;
63 g_free (self->priv->stock_id);
64 self->priv->stock_id = NULL;
66 self->priv->storage_type = GTK_IMAGE_EMPTY;
67 self->priv->icon_size = GTK_ICON_SIZE_INVALID;
68 self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
72 _gtk_icon_helper_invalidate (GtkIconHelper *self)
74 g_clear_object (&self->priv->rendered_pixbuf);
78 gtk_icon_helper_finalize (GObject *object)
80 GtkIconHelper *self = GTK_ICON_HELPER (object);
82 _gtk_icon_helper_clear (self);
84 G_OBJECT_CLASS (_gtk_icon_helper_parent_class)->finalize (object);
88 _gtk_icon_helper_class_init (GtkIconHelperClass *klass)
92 oclass = G_OBJECT_CLASS (klass);
93 oclass->finalize = gtk_icon_helper_finalize;
95 g_type_class_add_private (klass, sizeof (GtkIconHelperPrivate));
99 _gtk_icon_helper_init (GtkIconHelper *self)
101 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_ICON_HELPER, GtkIconHelperPrivate);
103 self->priv->storage_type = GTK_IMAGE_EMPTY;
104 self->priv->icon_size = GTK_ICON_SIZE_INVALID;
105 self->priv->pixel_size = -1;
106 self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
110 ensure_icon_size (GtkIconHelper *self,
111 GtkStyleContext *context,
116 GtkSettings *settings;
119 screen = gtk_style_context_get_screen (context);
120 settings = gtk_settings_get_for_screen (screen);
122 if (self->priv->pixel_size != -1)
124 width = height = self->priv->pixel_size;
126 else if (!gtk_icon_size_lookup_for_settings (settings,
127 self->priv->icon_size,
130 if (self->priv->icon_size == GTK_ICON_SIZE_INVALID)
136 g_warning ("Invalid icon size %d\n", self->priv->icon_size);
142 *height_out = height;
146 ensure_stated_icon_from_info (GtkIconHelper *self,
147 GtkStyleContext *context,
150 GdkPixbuf *destination = NULL;
157 gtk_icon_info_load_symbolic_for_context (info,
162 if (destination == NULL)
164 GtkIconSet *icon_set;
165 icon_set = gtk_style_context_lookup_icon_set (context, GTK_STOCK_MISSING_IMAGE);
168 gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
172 GtkIconSource *source;
175 source = gtk_icon_source_new ();
176 gtk_icon_source_set_pixbuf (source, destination);
177 /* The size here is arbitrary; since size isn't
178 * wildcarded in the source, it isn't supposed to be
179 * scaled by the engine function
181 gtk_icon_source_set_size (source,
182 GTK_ICON_SIZE_SMALL_TOOLBAR);
183 gtk_icon_source_set_size_wildcarded (source, FALSE);
185 rendered = gtk_render_icon_pixbuf (context, source, (GtkIconSize) -1);
186 gtk_icon_source_free (source);
188 g_object_unref (destination);
189 destination = rendered;
196 check_invalidate_pixbuf (GtkIconHelper *self,
197 GtkStyleContext *context)
201 state = gtk_style_context_get_state (context);
203 if ((self->priv->rendered_pixbuf != NULL) &&
204 (self->priv->last_rendered_state == state))
207 self->priv->last_rendered_state = state;
208 g_clear_object (&self->priv->rendered_pixbuf);
213 static GtkIconLookupFlags
214 get_icon_lookup_flags (GtkIconHelper *self)
216 GtkIconLookupFlags flags = GTK_ICON_LOOKUP_USE_BUILTIN;
218 if (self->priv->use_fallback)
219 flags |= GTK_ICON_LOOKUP_GENERIC_FALLBACK;
220 if (self->priv->pixel_size != -1)
221 flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
227 ensure_pixbuf_for_icon_name_or_gicon (GtkIconHelper *self,
228 GtkStyleContext *context)
230 GtkIconTheme *icon_theme;
233 GtkIconLookupFlags flags;
235 if (!check_invalidate_pixbuf (self, context))
238 icon_theme = gtk_icon_theme_get_default ();
239 flags = get_icon_lookup_flags (self);
241 ensure_icon_size (self, context, &width, &height);
243 if (self->priv->storage_type == GTK_IMAGE_ICON_NAME &&
244 self->priv->icon_name != NULL)
246 info = gtk_icon_theme_lookup_icon (icon_theme,
247 self->priv->icon_name,
248 MIN (width, height), flags);
250 else if (self->priv->storage_type == GTK_IMAGE_GICON &&
251 self->priv->gicon != NULL)
253 info = gtk_icon_theme_lookup_by_gicon (icon_theme,
255 MIN (width, height), flags);
259 g_assert_not_reached ();
263 self->priv->rendered_pixbuf = ensure_stated_icon_from_info (self, context, info);
266 gtk_icon_info_free (info);
270 ensure_pixbuf_for_icon_set (GtkIconHelper *self,
271 GtkStyleContext *context,
272 GtkIconSet *icon_set)
274 if (!check_invalidate_pixbuf (self, context))
277 self->priv->rendered_pixbuf =
278 gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
282 ensure_pixbuf_at_size (GtkIconHelper *self,
283 GtkStyleContext *context)
287 if (!check_invalidate_pixbuf (self, context))
290 if (self->priv->rendered_pixbuf)
293 if (self->priv->pixel_size != -1 ||
294 self->priv->icon_size != GTK_ICON_SIZE_INVALID)
296 ensure_icon_size (self, context, &width, &height);
298 if (width < gdk_pixbuf_get_width (self->priv->orig_pixbuf) ||
299 height < gdk_pixbuf_get_height (self->priv->orig_pixbuf))
300 self->priv->rendered_pixbuf =
301 gdk_pixbuf_scale_simple (self->priv->orig_pixbuf,
303 GDK_INTERP_BILINEAR);
306 if (!self->priv->rendered_pixbuf)
307 self->priv->rendered_pixbuf = g_object_ref (self->priv->orig_pixbuf);
311 _gtk_icon_helper_ensure_pixbuf (GtkIconHelper *self,
312 GtkStyleContext *context)
314 GdkPixbuf *pixbuf = NULL;
315 GtkIconSet *icon_set;
317 switch (self->priv->storage_type)
319 case GTK_IMAGE_PIXBUF:
320 if (self->priv->force_scale_pixbuf)
321 ensure_pixbuf_at_size (self, context);
323 pixbuf = g_object_ref (self->priv->orig_pixbuf);
326 case GTK_IMAGE_STOCK:
327 icon_set = gtk_style_context_lookup_icon_set (context, self->priv->stock_id);
328 if (icon_set != NULL)
329 ensure_pixbuf_for_icon_set (self, context, icon_set);
334 case GTK_IMAGE_ICON_SET:
335 icon_set = self->priv->icon_set;
336 ensure_pixbuf_for_icon_set (self, context, icon_set);
339 case GTK_IMAGE_ICON_NAME:
340 case GTK_IMAGE_GICON:
341 ensure_pixbuf_for_icon_name_or_gicon (self, context);
344 case GTK_IMAGE_ANIMATION:
345 case GTK_IMAGE_EMPTY:
351 if (pixbuf == NULL &&
352 self->priv->rendered_pixbuf != NULL)
353 pixbuf = g_object_ref (self->priv->rendered_pixbuf);
359 _gtk_icon_helper_get_size (GtkIconHelper *self,
360 GtkStyleContext *context,
368 pix = _gtk_icon_helper_ensure_pixbuf (self, context);
372 width = gdk_pixbuf_get_width (pix);
373 height = gdk_pixbuf_get_height (pix);
375 g_object_unref (pix);
377 else if (self->priv->storage_type == GTK_IMAGE_ANIMATION)
379 width = gdk_pixbuf_animation_get_width (self->priv->animation);
380 height = gdk_pixbuf_animation_get_height (self->priv->animation);
382 else if (self->priv->icon_size != -1)
384 ensure_icon_size (self, context, &width, &height);
390 *height_out = height;
394 _gtk_icon_helper_set_gicon (GtkIconHelper *self,
396 GtkIconSize icon_size)
398 _gtk_icon_helper_clear (self);
402 self->priv->storage_type = GTK_IMAGE_GICON;
403 self->priv->gicon = g_object_ref (gicon);
404 _gtk_icon_helper_set_icon_size (self, icon_size);
409 _gtk_icon_helper_set_icon_name (GtkIconHelper *self,
410 const gchar *icon_name,
411 GtkIconSize icon_size)
413 _gtk_icon_helper_clear (self);
415 if (icon_name != NULL &&
416 icon_name[0] != '\0')
418 self->priv->storage_type = GTK_IMAGE_ICON_NAME;
419 self->priv->icon_name = g_strdup (icon_name);
420 _gtk_icon_helper_set_icon_size (self, icon_size);
425 _gtk_icon_helper_set_icon_set (GtkIconHelper *self,
426 GtkIconSet *icon_set,
427 GtkIconSize icon_size)
429 _gtk_icon_helper_clear (self);
431 if (icon_set != NULL)
433 self->priv->storage_type = GTK_IMAGE_ICON_SET;
434 self->priv->icon_set = gtk_icon_set_ref (icon_set);
435 _gtk_icon_helper_set_icon_size (self, icon_size);
440 _gtk_icon_helper_set_pixbuf (GtkIconHelper *self,
443 _gtk_icon_helper_clear (self);
447 self->priv->storage_type = GTK_IMAGE_PIXBUF;
448 self->priv->orig_pixbuf = g_object_ref (pixbuf);
453 _gtk_icon_helper_set_animation (GtkIconHelper *self,
454 GdkPixbufAnimation *animation)
456 _gtk_icon_helper_clear (self);
458 if (animation != NULL)
460 self->priv->storage_type = GTK_IMAGE_ANIMATION;
461 self->priv->animation = g_object_ref (animation);
466 _gtk_icon_helper_set_stock_id (GtkIconHelper *self,
467 const gchar *stock_id,
468 GtkIconSize icon_size)
470 _gtk_icon_helper_clear (self);
472 if (stock_id != NULL &&
475 self->priv->storage_type = GTK_IMAGE_STOCK;
476 self->priv->stock_id = g_strdup (stock_id);
477 _gtk_icon_helper_set_icon_size (self, icon_size);
482 _gtk_icon_helper_set_icon_size (GtkIconHelper *self,
483 GtkIconSize icon_size)
485 if (self->priv->icon_size != icon_size)
487 self->priv->icon_size = icon_size;
488 _gtk_icon_helper_invalidate (self);
493 _gtk_icon_helper_set_pixel_size (GtkIconHelper *self,
496 if (self->priv->pixel_size != pixel_size)
498 self->priv->pixel_size = pixel_size;
499 _gtk_icon_helper_invalidate (self);
504 _gtk_icon_helper_set_use_fallback (GtkIconHelper *self,
505 gboolean use_fallback)
507 if (self->priv->use_fallback != use_fallback)
509 self->priv->use_fallback = use_fallback;
510 _gtk_icon_helper_invalidate (self);
515 _gtk_icon_helper_get_storage_type (GtkIconHelper *self)
517 return self->priv->storage_type;
521 _gtk_icon_helper_get_use_fallback (GtkIconHelper *self)
523 return self->priv->use_fallback;
527 _gtk_icon_helper_get_icon_size (GtkIconHelper *self)
529 return self->priv->icon_size;
533 _gtk_icon_helper_get_pixel_size (GtkIconHelper *self)
535 return self->priv->pixel_size;
539 _gtk_icon_helper_peek_pixbuf (GtkIconHelper *self)
541 return self->priv->orig_pixbuf;
545 _gtk_icon_helper_peek_gicon (GtkIconHelper *self)
547 return self->priv->gicon;
551 _gtk_icon_helper_peek_animation (GtkIconHelper *self)
553 return self->priv->animation;
557 _gtk_icon_helper_peek_icon_set (GtkIconHelper *self)
559 return self->priv->icon_set;
563 _gtk_icon_helper_get_stock_id (GtkIconHelper *self)
565 return self->priv->stock_id;
569 _gtk_icon_helper_get_icon_name (GtkIconHelper *self)
571 return self->priv->icon_name;
575 _gtk_icon_helper_new (void)
577 return g_object_new (GTK_TYPE_ICON_HELPER, NULL);
581 _gtk_icon_helper_draw (GtkIconHelper *self,
582 GtkStyleContext *context,
589 pixbuf = _gtk_icon_helper_ensure_pixbuf (self, context);
593 gtk_render_icon (context, cr, pixbuf, x, y);
594 g_object_unref (pixbuf);
599 _gtk_icon_helper_get_is_empty (GtkIconHelper *self)
601 return (self->priv->storage_type == GTK_IMAGE_EMPTY);
605 _gtk_icon_helper_get_force_scale_pixbuf (GtkIconHelper *self)
607 return self->priv->force_scale_pixbuf;
611 _gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self,
612 gboolean force_scale)
614 if (self->priv->force_scale_pixbuf != force_scale)
616 self->priv->force_scale_pixbuf = force_scale;
617 _gtk_icon_helper_invalidate (self);