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 #include <math.h>
25
26 #include "gtkcssenumvalueprivate.h"
27 #include "gtkcssiconthemevalueprivate.h"
28 #include "gtkcssnodeprivate.h"
29 #include "gtkcssstyleprivate.h"
30 #include "gtkcssstylepropertyprivate.h"
31 #include "gtkcsstransientnodeprivate.h"
32 #include "gtkiconthemeprivate.h"
33 #include "gtkrendericonprivate.h"
34 #include "deprecated/gtkiconfactoryprivate.h"
35 #include "deprecated/gtkstock.h"
36
37 struct _GtkIconHelperPrivate {
38 GtkImageDefinition *def;
39
40 GtkIconSize icon_size;
41 gint pixel_size;
42
43 guint use_fallback : 1;
44 guint force_scale_pixbuf : 1;
45 guint rendered_surface_is_symbolic : 1;
46
47 cairo_surface_t *rendered_surface;
48 };
49
G_DEFINE_TYPE_WITH_PRIVATE(GtkIconHelper,gtk_icon_helper,GTK_TYPE_CSS_GADGET)50 G_DEFINE_TYPE_WITH_PRIVATE (GtkIconHelper, gtk_icon_helper, GTK_TYPE_CSS_GADGET)
51
52 static void
53 gtk_icon_helper_invalidate (GtkIconHelper *self)
54 {
55 if (self->priv->rendered_surface != NULL)
56 {
57 cairo_surface_destroy (self->priv->rendered_surface);
58 self->priv->rendered_surface = NULL;
59 self->priv->rendered_surface_is_symbolic = FALSE;
60 }
61
62 if (!GTK_IS_CSS_TRANSIENT_NODE (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))))
63 gtk_widget_queue_resize (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)));
64 }
65
66 void
gtk_icon_helper_invalidate_for_change(GtkIconHelper * self,GtkCssStyleChange * change)67 gtk_icon_helper_invalidate_for_change (GtkIconHelper *self,
68 GtkCssStyleChange *change)
69 {
70 GtkIconHelperPrivate *priv = self->priv;
71
72 if (change == NULL ||
73 ((gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SYMBOLIC_ICON) &&
74 priv->rendered_surface_is_symbolic) ||
75 (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_ICON) &&
76 !priv->rendered_surface_is_symbolic)))
77 {
78 gtk_icon_helper_invalidate (self);
79 }
80 }
81
82 static void
gtk_icon_helper_take_definition(GtkIconHelper * self,GtkImageDefinition * def)83 gtk_icon_helper_take_definition (GtkIconHelper *self,
84 GtkImageDefinition *def)
85 {
86 _gtk_icon_helper_clear (self);
87
88 if (def == NULL)
89 return;
90
91 gtk_image_definition_unref (self->priv->def);
92 self->priv->def = def;
93
94 gtk_icon_helper_invalidate (self);
95 }
96
97 void
_gtk_icon_helper_clear(GtkIconHelper * self)98 _gtk_icon_helper_clear (GtkIconHelper *self)
99 {
100 g_clear_pointer (&self->priv->rendered_surface, cairo_surface_destroy);
101
102 gtk_image_definition_unref (self->priv->def);
103 self->priv->def = gtk_image_definition_new_empty ();
104
105 self->priv->icon_size = GTK_ICON_SIZE_INVALID;
106
107 gtk_icon_helper_invalidate (self);
108 }
109
110 static void
gtk_icon_helper_get_preferred_size(GtkCssGadget * gadget,GtkOrientation orientation,gint for_size,gint * minimum,gint * natural,gint * minimum_baseline,gint * natural_baseline)111 gtk_icon_helper_get_preferred_size (GtkCssGadget *gadget,
112 GtkOrientation orientation,
113 gint for_size,
114 gint *minimum,
115 gint *natural,
116 gint *minimum_baseline,
117 gint *natural_baseline)
118 {
119 GtkIconHelper *self = GTK_ICON_HELPER (gadget);
120 int icon_width, icon_height;
121
122 _gtk_icon_helper_get_size (self, &icon_width, &icon_height);
123
124 if (orientation == GTK_ORIENTATION_HORIZONTAL)
125 *minimum = *natural = icon_width;
126 else
127 *minimum = *natural = icon_height;
128 }
129
130 static void
gtk_icon_helper_allocate(GtkCssGadget * gadget,const GtkAllocation * allocation,int baseline,GtkAllocation * out_clip)131 gtk_icon_helper_allocate (GtkCssGadget *gadget,
132 const GtkAllocation *allocation,
133 int baseline,
134 GtkAllocation *out_clip)
135 {
136 GTK_CSS_GADGET_CLASS (gtk_icon_helper_parent_class)->allocate (gadget, allocation, baseline, out_clip);
137 }
138
139 static gboolean
gtk_icon_helper_draw(GtkCssGadget * gadget,cairo_t * cr,int x,int y,int width,int height)140 gtk_icon_helper_draw (GtkCssGadget *gadget,
141 cairo_t *cr,
142 int x,
143 int y,
144 int width,
145 int height)
146 {
147 GtkIconHelper *self = GTK_ICON_HELPER (gadget);
148 int icon_width, icon_height;
149
150 _gtk_icon_helper_get_size (self, &icon_width, &icon_height);
151 _gtk_icon_helper_draw (self,
152 cr,
153 x + (width - icon_width) / 2,
154 y + (height - icon_height) / 2);
155
156 return FALSE;
157 }
158
159 static void
gtk_icon_helper_style_changed(GtkCssGadget * gadget,GtkCssStyleChange * change)160 gtk_icon_helper_style_changed (GtkCssGadget *gadget,
161 GtkCssStyleChange *change)
162 {
163 gtk_icon_helper_invalidate_for_change (GTK_ICON_HELPER (gadget), change);
164
165 if (!GTK_IS_CSS_TRANSIENT_NODE (gtk_css_gadget_get_node (gadget)))
166 GTK_CSS_GADGET_CLASS (gtk_icon_helper_parent_class)->style_changed (gadget, change);
167 }
168
169 static void
gtk_icon_helper_constructed(GObject * object)170 gtk_icon_helper_constructed (GObject *object)
171 {
172 GtkIconHelper *self = GTK_ICON_HELPER (object);
173 GtkWidget *widget;
174
175 widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self));
176
177 g_signal_connect_swapped (widget, "direction-changed", G_CALLBACK (gtk_icon_helper_invalidate), self);
178 g_signal_connect_swapped (widget, "notify::scale-factor", G_CALLBACK (gtk_icon_helper_invalidate), self);
179
180 G_OBJECT_CLASS (gtk_icon_helper_parent_class)->constructed (object);
181 }
182
183 static void
gtk_icon_helper_finalize(GObject * object)184 gtk_icon_helper_finalize (GObject *object)
185 {
186 GtkIconHelper *self = GTK_ICON_HELPER (object);
187 GtkWidget *widget;
188
189 widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self));
190 g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (gtk_icon_helper_invalidate), self);
191
192 _gtk_icon_helper_clear (self);
193 gtk_image_definition_unref (self->priv->def);
194
195 G_OBJECT_CLASS (gtk_icon_helper_parent_class)->finalize (object);
196 }
197
198 static void
gtk_icon_helper_class_init(GtkIconHelperClass * klass)199 gtk_icon_helper_class_init (GtkIconHelperClass *klass)
200 {
201 GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
202 GObjectClass *object_class = G_OBJECT_CLASS (klass);
203
204 gadget_class->get_preferred_size = gtk_icon_helper_get_preferred_size;
205 gadget_class->allocate = gtk_icon_helper_allocate;
206 gadget_class->draw = gtk_icon_helper_draw;
207 gadget_class->style_changed = gtk_icon_helper_style_changed;
208
209 object_class->constructed = gtk_icon_helper_constructed;
210 object_class->finalize = gtk_icon_helper_finalize;
211 }
212
213 static void
gtk_icon_helper_init(GtkIconHelper * self)214 gtk_icon_helper_init (GtkIconHelper *self)
215 {
216 self->priv = gtk_icon_helper_get_instance_private (self);
217
218 self->priv->def = gtk_image_definition_new_empty ();
219
220 self->priv->icon_size = GTK_ICON_SIZE_INVALID;
221 self->priv->pixel_size = -1;
222 self->priv->rendered_surface_is_symbolic = FALSE;
223 }
224
225 static void
ensure_icon_size(GtkIconHelper * self,gint * width_out,gint * height_out)226 ensure_icon_size (GtkIconHelper *self,
227 gint *width_out,
228 gint *height_out)
229 {
230 gint width, height;
231
232 if (self->priv->pixel_size != -1)
233 {
234 width = height = self->priv->pixel_size;
235 }
236 else if (!gtk_icon_size_lookup (self->priv->icon_size, &width, &height))
237 {
238 if (self->priv->icon_size == GTK_ICON_SIZE_INVALID)
239 {
240 width = height = 0;
241 }
242 else
243 {
244 g_warning ("Invalid icon size %d", self->priv->icon_size);
245 width = height = 24;
246 }
247 }
248
249 *width_out = width;
250 *height_out = height;
251 }
252
253 static GtkIconLookupFlags
get_icon_lookup_flags(GtkIconHelper * self,GtkCssStyle * style,GtkTextDirection dir)254 get_icon_lookup_flags (GtkIconHelper *self,
255 GtkCssStyle *style,
256 GtkTextDirection dir)
257 {
258 GtkIconLookupFlags flags;
259 GtkCssIconStyle icon_style;
260
261 flags = GTK_ICON_LOOKUP_USE_BUILTIN;
262
263 if (self->priv->pixel_size != -1 || self->priv->force_scale_pixbuf)
264 flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
265
266 icon_style = _gtk_css_icon_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_STYLE));
267
268 switch (icon_style)
269 {
270 case GTK_CSS_ICON_STYLE_REGULAR:
271 flags |= GTK_ICON_LOOKUP_FORCE_REGULAR;
272 break;
273 case GTK_CSS_ICON_STYLE_SYMBOLIC:
274 flags |= GTK_ICON_LOOKUP_FORCE_SYMBOLIC;
275 break;
276 case GTK_CSS_ICON_STYLE_REQUESTED:
277 break;
278 default:
279 g_assert_not_reached ();
280 return 0;
281 }
282
283 if (dir == GTK_TEXT_DIR_LTR)
284 flags |= GTK_ICON_LOOKUP_DIR_LTR;
285 else if (dir == GTK_TEXT_DIR_RTL)
286 flags |= GTK_ICON_LOOKUP_DIR_RTL;
287
288 return flags;
289 }
290
291 static void
get_surface_size(GtkIconHelper * self,cairo_surface_t * surface,int * width,int * height)292 get_surface_size (GtkIconHelper *self,
293 cairo_surface_t *surface,
294 int *width,
295 int *height)
296 {
297 GdkRectangle clip;
298 cairo_t *cr;
299
300 cr = cairo_create (surface);
301 if (gdk_cairo_get_clip_rectangle (cr, &clip))
302 {
303 if (clip.x != 0 || clip.y != 0)
304 {
305 g_warning ("origin of surface is %d %d, not supported", clip.x, clip.y);
306 }
307 *width = clip.width;
308 *height = clip.height;
309 }
310 else
311 {
312 g_warning ("infinite surface size not supported");
313 ensure_icon_size (self, width, height);
314 }
315
316 cairo_destroy (cr);
317 }
318
319 static cairo_surface_t *
ensure_surface_from_surface(GtkIconHelper * self,cairo_surface_t * orig_surface)320 ensure_surface_from_surface (GtkIconHelper *self,
321 cairo_surface_t *orig_surface)
322 {
323 return cairo_surface_reference (orig_surface);
324 }
325
326 static gboolean
get_pixbuf_size(GtkIconHelper * self,gint scale,GdkPixbuf * orig_pixbuf,gint orig_scale,gint * width_out,gint * height_out,gint * scale_out)327 get_pixbuf_size (GtkIconHelper *self,
328 gint scale,
329 GdkPixbuf *orig_pixbuf,
330 gint orig_scale,
331 gint *width_out,
332 gint *height_out,
333 gint *scale_out)
334 {
335 gboolean scale_pixmap;
336 gint width, height;
337
338 scale_pixmap = FALSE;
339
340 if (self->priv->force_scale_pixbuf &&
341 (self->priv->pixel_size != -1 ||
342 self->priv->icon_size != GTK_ICON_SIZE_INVALID))
343 {
344 ensure_icon_size (self, &width, &height);
345
346 if (scale != orig_scale ||
347 width < gdk_pixbuf_get_width (orig_pixbuf) / orig_scale ||
348 height < gdk_pixbuf_get_height (orig_pixbuf) / orig_scale)
349 {
350 width = MIN (width * scale, gdk_pixbuf_get_width (orig_pixbuf) * scale / orig_scale);
351 height = MIN (height * scale, gdk_pixbuf_get_height (orig_pixbuf) * scale / orig_scale);
352
353 scale_pixmap = TRUE;
354 }
355 else
356 {
357 width = gdk_pixbuf_get_width (orig_pixbuf);
358 height = gdk_pixbuf_get_height (orig_pixbuf);
359 scale = orig_scale;
360 }
361 }
362 else
363 {
364 width = gdk_pixbuf_get_width (orig_pixbuf);
365 height = gdk_pixbuf_get_height (orig_pixbuf);
366 scale = orig_scale;
367 }
368
369 *width_out = width;
370 *height_out = height;
371 *scale_out = scale;
372
373 return scale_pixmap;
374 }
375
376 static cairo_surface_t *
ensure_surface_from_pixbuf(GtkIconHelper * self,GtkCssStyle * style,gint scale,GdkPixbuf * orig_pixbuf,gint orig_scale)377 ensure_surface_from_pixbuf (GtkIconHelper *self,
378 GtkCssStyle *style,
379 gint scale,
380 GdkPixbuf *orig_pixbuf,
381 gint orig_scale)
382 {
383 gint width, height;
384 cairo_surface_t *surface;
385 GdkPixbuf *pixbuf;
386 GtkCssIconEffect icon_effect;
387
388 if (get_pixbuf_size (self,
389 scale,
390 orig_pixbuf,
391 orig_scale,
392 &width, &height, &scale))
393 pixbuf = gdk_pixbuf_scale_simple (orig_pixbuf,
394 width, height,
395 GDK_INTERP_BILINEAR);
396 else
397 pixbuf = g_object_ref (orig_pixbuf);
398
399 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
400 icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT));
401 gtk_css_icon_effect_apply (icon_effect, surface);
402 g_object_unref (pixbuf);
403
404 return surface;
405 }
406
407 static cairo_surface_t *
ensure_surface_for_icon_set(GtkIconHelper * self,GtkCssStyle * style,GtkTextDirection direction,gint scale,GtkIconSet * icon_set)408 ensure_surface_for_icon_set (GtkIconHelper *self,
409 GtkCssStyle *style,
410 GtkTextDirection direction,
411 gint scale,
412 GtkIconSet *icon_set)
413 {
414 cairo_surface_t *surface;
415 GdkPixbuf *pixbuf;
416
417 pixbuf = gtk_icon_set_render_icon_pixbuf_for_scale (icon_set,
418 style,
419 direction,
420 self->priv->icon_size,
421 scale);
422 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf,
423 scale,
424 gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
425 g_object_unref (pixbuf);
426
427 return surface;
428 }
429
430 static cairo_surface_t *
ensure_surface_for_gicon(GtkIconHelper * self,GtkCssStyle * style,GtkTextDirection dir,gint scale,GIcon * gicon)431 ensure_surface_for_gicon (GtkIconHelper *self,
432 GtkCssStyle *style,
433 GtkTextDirection dir,
434 gint scale,
435 GIcon *gicon)
436 {
437 GtkIconHelperPrivate *priv = self->priv;
438 GtkIconTheme *icon_theme;
439 gint width, height;
440 GtkIconInfo *info;
441 GtkIconLookupFlags flags;
442 cairo_surface_t *surface;
443 GdkPixbuf *destination;
444 gboolean symbolic;
445
446 icon_theme = gtk_css_icon_theme_value_get_icon_theme
447 (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_THEME));
448 flags = get_icon_lookup_flags (self, style, dir);
449
450 ensure_icon_size (self, &width, &height);
451
452 info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme,
453 gicon,
454 MIN (width, height),
455 scale, flags);
456 if (info)
457 {
458 symbolic = gtk_icon_info_is_symbolic (info);
459
460 if (symbolic)
461 {
462 GdkRGBA fg, success_color, warning_color, error_color;
463
464 gtk_icon_theme_lookup_symbolic_colors (style, &fg, &success_color, &warning_color, &error_color);
465
466 destination = gtk_icon_info_load_symbolic (info,
467 &fg, &success_color,
468 &warning_color, &error_color,
469 NULL,
470 NULL);
471 }
472 else
473 {
474 destination = gtk_icon_info_load_icon (info, NULL);
475 }
476
477 g_object_unref (info);
478 }
479 else
480 {
481 destination = NULL;
482 }
483
484 if (destination == NULL)
485 {
486 GError *error = NULL;
487 destination = gtk_icon_theme_load_icon (icon_theme,
488 "image-missing",
489 width,
490 flags | GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_GENERIC_FALLBACK,
491 &error);
492 /* We include this image as resource, so we always have it available or
493 * the icontheme code is broken */
494 g_assert_no_error (error);
495 g_assert (destination);
496 symbolic = FALSE;
497 }
498
499 surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
500
501 if (!symbolic)
502 {
503 GtkCssIconEffect icon_effect;
504
505 icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT));
506 gtk_css_icon_effect_apply (icon_effect, surface);
507 }
508 else
509 {
510 priv->rendered_surface_is_symbolic = TRUE;
511 }
512
513 g_object_unref (destination);
514
515 return surface;
516 }
517
518 cairo_surface_t *
gtk_icon_helper_load_surface(GtkIconHelper * self,int scale)519 gtk_icon_helper_load_surface (GtkIconHelper *self,
520 int scale)
521 {
522 cairo_surface_t *surface;
523 GtkIconSet *icon_set;
524 GIcon *gicon;
525
526 switch (gtk_image_definition_get_storage_type (self->priv->def))
527 {
528 case GTK_IMAGE_SURFACE:
529 surface = ensure_surface_from_surface (self, gtk_image_definition_get_surface (self->priv->def));
530 break;
531
532 case GTK_IMAGE_PIXBUF:
533 surface = ensure_surface_from_pixbuf (self,
534 gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
535 scale,
536 gtk_image_definition_get_pixbuf (self->priv->def),
537 gtk_image_definition_get_scale (self->priv->def));
538 break;
539
540 case GTK_IMAGE_STOCK:
541 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
542 icon_set = gtk_icon_factory_lookup_default (gtk_image_definition_get_stock (self->priv->def));
543 G_GNUC_END_IGNORE_DEPRECATIONS;
544 if (icon_set != NULL)
545 surface = ensure_surface_for_icon_set (self,
546 gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
547 gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
548 scale, icon_set);
549 else
550 surface = NULL;
551 break;
552
553 case GTK_IMAGE_ICON_SET:
554 icon_set = gtk_image_definition_get_icon_set (self->priv->def);
555 surface = ensure_surface_for_icon_set (self,
556 gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
557 gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
558 scale, icon_set);
559 break;
560
561 case GTK_IMAGE_ICON_NAME:
562 if (self->priv->use_fallback)
563 gicon = g_themed_icon_new_with_default_fallbacks (gtk_image_definition_get_icon_name (self->priv->def));
564 else
565 gicon = g_themed_icon_new (gtk_image_definition_get_icon_name (self->priv->def));
566 surface = ensure_surface_for_gicon (self,
567 gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
568 gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
569 scale,
570 gicon);
571 g_object_unref (gicon);
572 break;
573
574 case GTK_IMAGE_GICON:
575 surface = ensure_surface_for_gicon (self,
576 gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
577 gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
578 scale,
579 gtk_image_definition_get_gicon (self->priv->def));
580 break;
581
582 case GTK_IMAGE_ANIMATION:
583 case GTK_IMAGE_EMPTY:
584 default:
585 surface = NULL;
586 break;
587 }
588
589 return surface;
590
591 }
592
593 static void
gtk_icon_helper_ensure_surface(GtkIconHelper * self)594 gtk_icon_helper_ensure_surface (GtkIconHelper *self)
595 {
596 int scale;
597
598 if (self->priv->rendered_surface)
599 return;
600
601 scale = gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)));
602
603 self->priv->rendered_surface = gtk_icon_helper_load_surface (self, scale);
604 }
605
606 void
_gtk_icon_helper_get_size(GtkIconHelper * self,gint * width_out,gint * height_out)607 _gtk_icon_helper_get_size (GtkIconHelper *self,
608 gint *width_out,
609 gint *height_out)
610 {
611 gint width, height, scale;
612
613 width = height = 0;
614
615 /* Certain kinds of images are easy to calculate the size for, these
616 we do immediately to avoid having to potentially load the image
617 data for something that may not yet be visible */
618 switch (gtk_image_definition_get_storage_type (self->priv->def))
619 {
620 case GTK_IMAGE_SURFACE:
621 get_surface_size (self,
622 gtk_image_definition_get_surface (self->priv->def),
623 &width,
624 &height);
625 break;
626
627 case GTK_IMAGE_PIXBUF:
628 get_pixbuf_size (self,
629 gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
630 gtk_image_definition_get_pixbuf (self->priv->def),
631 gtk_image_definition_get_scale (self->priv->def),
632 &width, &height, &scale);
633 width = (width + scale - 1) / scale;
634 height = (height + scale - 1) / scale;
635 break;
636
637 case GTK_IMAGE_ANIMATION:
638 {
639 GdkPixbufAnimation *animation = gtk_image_definition_get_animation (self->priv->def);
640 width = gdk_pixbuf_animation_get_width (animation);
641 height = gdk_pixbuf_animation_get_height (animation);
642 break;
643 }
644
645 case GTK_IMAGE_ICON_NAME:
646 case GTK_IMAGE_GICON:
647 if (self->priv->pixel_size != -1 || self->priv->force_scale_pixbuf)
648 ensure_icon_size (self, &width, &height);
649
650 break;
651
652 case GTK_IMAGE_STOCK:
653 case GTK_IMAGE_ICON_SET:
654 case GTK_IMAGE_EMPTY:
655 default:
656 break;
657 }
658
659 /* Otherwise we load the surface to guarantee we get a size */
660 if (width == 0)
661 {
662 gtk_icon_helper_ensure_surface (self);
663
664 if (self->priv->rendered_surface != NULL)
665 {
666 get_surface_size (self, self->priv->rendered_surface, &width, &height);
667 }
668 else if (self->priv->icon_size != GTK_ICON_SIZE_INVALID)
669 {
670 ensure_icon_size (self, &width, &height);
671 }
672 }
673
674 if (width_out)
675 *width_out = width;
676 if (height_out)
677 *height_out = height;
678 }
679
680 void
_gtk_icon_helper_set_definition(GtkIconHelper * self,GtkImageDefinition * def)681 _gtk_icon_helper_set_definition (GtkIconHelper *self,
682 GtkImageDefinition *def)
683 {
684 if (def)
685 gtk_icon_helper_take_definition (self, gtk_image_definition_ref (def));
686 else
687 _gtk_icon_helper_clear (self);
688 }
689
690 void
_gtk_icon_helper_set_gicon(GtkIconHelper * self,GIcon * gicon,GtkIconSize icon_size)691 _gtk_icon_helper_set_gicon (GtkIconHelper *self,
692 GIcon *gicon,
693 GtkIconSize icon_size)
694 {
695 gtk_icon_helper_take_definition (self, gtk_image_definition_new_gicon (gicon));
696 _gtk_icon_helper_set_icon_size (self, icon_size);
697 }
698
699 void
_gtk_icon_helper_set_icon_name(GtkIconHelper * self,const gchar * icon_name,GtkIconSize icon_size)700 _gtk_icon_helper_set_icon_name (GtkIconHelper *self,
701 const gchar *icon_name,
702 GtkIconSize icon_size)
703 {
704 gtk_icon_helper_take_definition (self, gtk_image_definition_new_icon_name (icon_name));
705 _gtk_icon_helper_set_icon_size (self, icon_size);
706 }
707
708 void
_gtk_icon_helper_set_icon_set(GtkIconHelper * self,GtkIconSet * icon_set,GtkIconSize icon_size)709 _gtk_icon_helper_set_icon_set (GtkIconHelper *self,
710 GtkIconSet *icon_set,
711 GtkIconSize icon_size)
712 {
713 gtk_icon_helper_take_definition (self, gtk_image_definition_new_icon_set (icon_set));
714 _gtk_icon_helper_set_icon_size (self, icon_size);
715 }
716
717 void
_gtk_icon_helper_set_pixbuf(GtkIconHelper * self,GdkPixbuf * pixbuf)718 _gtk_icon_helper_set_pixbuf (GtkIconHelper *self,
719 GdkPixbuf *pixbuf)
720 {
721 gtk_icon_helper_take_definition (self, gtk_image_definition_new_pixbuf (pixbuf, 1));
722 }
723
724 void
_gtk_icon_helper_set_animation(GtkIconHelper * self,GdkPixbufAnimation * animation)725 _gtk_icon_helper_set_animation (GtkIconHelper *self,
726 GdkPixbufAnimation *animation)
727 {
728 gtk_icon_helper_take_definition (self, gtk_image_definition_new_animation (animation, 1));
729 }
730
731 void
_gtk_icon_helper_set_surface(GtkIconHelper * self,cairo_surface_t * surface)732 _gtk_icon_helper_set_surface (GtkIconHelper *self,
733 cairo_surface_t *surface)
734 {
735 gtk_icon_helper_take_definition (self, gtk_image_definition_new_surface (surface));
736 }
737
738 void
_gtk_icon_helper_set_stock_id(GtkIconHelper * self,const gchar * stock_id,GtkIconSize icon_size)739 _gtk_icon_helper_set_stock_id (GtkIconHelper *self,
740 const gchar *stock_id,
741 GtkIconSize icon_size)
742 {
743 gtk_icon_helper_take_definition (self, gtk_image_definition_new_stock (stock_id));
744 _gtk_icon_helper_set_icon_size (self, icon_size);
745 }
746
747 gboolean
_gtk_icon_helper_set_icon_size(GtkIconHelper * self,GtkIconSize icon_size)748 _gtk_icon_helper_set_icon_size (GtkIconHelper *self,
749 GtkIconSize icon_size)
750 {
751 if (self->priv->icon_size != icon_size)
752 {
753 self->priv->icon_size = icon_size;
754 gtk_icon_helper_invalidate (self);
755 return TRUE;
756 }
757 return FALSE;
758 }
759
760 gboolean
_gtk_icon_helper_set_pixel_size(GtkIconHelper * self,gint pixel_size)761 _gtk_icon_helper_set_pixel_size (GtkIconHelper *self,
762 gint pixel_size)
763 {
764 if (self->priv->pixel_size != pixel_size)
765 {
766 self->priv->pixel_size = pixel_size;
767 gtk_icon_helper_invalidate (self);
768 return TRUE;
769 }
770 return FALSE;
771 }
772
773 gboolean
_gtk_icon_helper_set_use_fallback(GtkIconHelper * self,gboolean use_fallback)774 _gtk_icon_helper_set_use_fallback (GtkIconHelper *self,
775 gboolean use_fallback)
776 {
777 if (self->priv->use_fallback != use_fallback)
778 {
779 self->priv->use_fallback = use_fallback;
780 gtk_icon_helper_invalidate (self);
781 return TRUE;
782 }
783 return FALSE;
784 }
785
786 GtkImageType
_gtk_icon_helper_get_storage_type(GtkIconHelper * self)787 _gtk_icon_helper_get_storage_type (GtkIconHelper *self)
788 {
789 return gtk_image_definition_get_storage_type (self->priv->def);
790 }
791
792 gboolean
_gtk_icon_helper_get_use_fallback(GtkIconHelper * self)793 _gtk_icon_helper_get_use_fallback (GtkIconHelper *self)
794 {
795 return self->priv->use_fallback;
796 }
797
798 GtkIconSize
_gtk_icon_helper_get_icon_size(GtkIconHelper * self)799 _gtk_icon_helper_get_icon_size (GtkIconHelper *self)
800 {
801 return self->priv->icon_size;
802 }
803
804 gint
_gtk_icon_helper_get_pixel_size(GtkIconHelper * self)805 _gtk_icon_helper_get_pixel_size (GtkIconHelper *self)
806 {
807 return self->priv->pixel_size;
808 }
809
810 GtkImageDefinition *
gtk_icon_helper_get_definition(GtkIconHelper * self)811 gtk_icon_helper_get_definition (GtkIconHelper *self)
812 {
813 return self->priv->def;
814 }
815
816 GdkPixbuf *
_gtk_icon_helper_peek_pixbuf(GtkIconHelper * self)817 _gtk_icon_helper_peek_pixbuf (GtkIconHelper *self)
818 {
819 return gtk_image_definition_get_pixbuf (self->priv->def);
820 }
821
822 GIcon *
_gtk_icon_helper_peek_gicon(GtkIconHelper * self)823 _gtk_icon_helper_peek_gicon (GtkIconHelper *self)
824 {
825 return gtk_image_definition_get_gicon (self->priv->def);
826 }
827
828 GdkPixbufAnimation *
_gtk_icon_helper_peek_animation(GtkIconHelper * self)829 _gtk_icon_helper_peek_animation (GtkIconHelper *self)
830 {
831 return gtk_image_definition_get_animation (self->priv->def);
832 }
833
834 GtkIconSet *
_gtk_icon_helper_peek_icon_set(GtkIconHelper * self)835 _gtk_icon_helper_peek_icon_set (GtkIconHelper *self)
836 {
837 return gtk_image_definition_get_icon_set (self->priv->def);
838 }
839
840 cairo_surface_t *
_gtk_icon_helper_peek_surface(GtkIconHelper * self)841 _gtk_icon_helper_peek_surface (GtkIconHelper *self)
842 {
843 return gtk_image_definition_get_surface (self->priv->def);
844 }
845
846 const gchar *
_gtk_icon_helper_get_stock_id(GtkIconHelper * self)847 _gtk_icon_helper_get_stock_id (GtkIconHelper *self)
848 {
849 return gtk_image_definition_get_stock (self->priv->def);
850 }
851
852 const gchar *
_gtk_icon_helper_get_icon_name(GtkIconHelper * self)853 _gtk_icon_helper_get_icon_name (GtkIconHelper *self)
854 {
855 return gtk_image_definition_get_icon_name (self->priv->def);
856 }
857
858 GtkIconHelper *
gtk_icon_helper_new(GtkCssNode * node,GtkWidget * owner)859 gtk_icon_helper_new (GtkCssNode *node,
860 GtkWidget *owner)
861 {
862 g_return_val_if_fail (GTK_IS_CSS_NODE (node), NULL);
863 g_return_val_if_fail (GTK_IS_WIDGET (owner), NULL);
864
865 return g_object_new (GTK_TYPE_ICON_HELPER,
866 "node", node,
867 "owner", owner,
868 NULL);
869 }
870
871 GtkCssGadget *
gtk_icon_helper_new_named(const char * name,GtkWidget * owner)872 gtk_icon_helper_new_named (const char *name,
873 GtkWidget *owner)
874 {
875 GtkIconHelper *result;
876 GtkCssNode *node;
877
878 g_return_val_if_fail (name != NULL, NULL);
879 g_return_val_if_fail (GTK_IS_WIDGET (owner), NULL);
880
881 node = gtk_css_node_new ();
882 gtk_css_node_set_name (node, g_intern_string (name));
883
884 result = gtk_icon_helper_new (node, owner);
885
886 g_object_unref (node);
887
888 return GTK_CSS_GADGET (result);
889 }
890
891 void
_gtk_icon_helper_draw(GtkIconHelper * self,cairo_t * cr,gdouble x,gdouble y)892 _gtk_icon_helper_draw (GtkIconHelper *self,
893 cairo_t *cr,
894 gdouble x,
895 gdouble y)
896 {
897 GtkCssStyle *style = gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self)));
898 gtk_icon_helper_ensure_surface (self);
899
900 if (self->priv->rendered_surface != NULL)
901 {
902 gtk_css_style_render_icon_surface (style,
903 cr,
904 self->priv->rendered_surface,
905 x, y);
906 }
907 }
908
909 gboolean
_gtk_icon_helper_get_is_empty(GtkIconHelper * self)910 _gtk_icon_helper_get_is_empty (GtkIconHelper *self)
911 {
912 return gtk_image_definition_get_storage_type (self->priv->def) == GTK_IMAGE_EMPTY;
913 }
914
915 gboolean
_gtk_icon_helper_get_force_scale_pixbuf(GtkIconHelper * self)916 _gtk_icon_helper_get_force_scale_pixbuf (GtkIconHelper *self)
917 {
918 return self->priv->force_scale_pixbuf;
919 }
920
921 void
_gtk_icon_helper_set_force_scale_pixbuf(GtkIconHelper * self,gboolean force_scale)922 _gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self,
923 gboolean force_scale)
924 {
925 if (self->priv->force_scale_pixbuf != force_scale)
926 {
927 self->priv->force_scale_pixbuf = force_scale;
928 gtk_icon_helper_invalidate (self);
929 }
930 }
931
932 void
_gtk_icon_helper_set_pixbuf_scale(GtkIconHelper * self,int scale)933 _gtk_icon_helper_set_pixbuf_scale (GtkIconHelper *self,
934 int scale)
935 {
936 switch (gtk_image_definition_get_storage_type (self->priv->def))
937 {
938 case GTK_IMAGE_PIXBUF:
939 gtk_icon_helper_take_definition (self,
940 gtk_image_definition_new_pixbuf (gtk_image_definition_get_pixbuf (self->priv->def),
941 scale));
942 break;
943
944 case GTK_IMAGE_ANIMATION:
945 gtk_icon_helper_take_definition (self,
946 gtk_image_definition_new_animation (gtk_image_definition_get_animation (self->priv->def),
947 scale));
948 break;
949
950 default:
951 break;
952 }
953 }
954