]> Pileus Git - ~andy/gtk/blob - gtk/gtknumerableicon.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtknumerableicon.c
1 /*
2  * gtknumerableicon.c: an emblemed icon with number emblems
3  *
4  * Copyright (C) 2010 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * 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  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Cosimo Cecchi <cosimoc@redhat.com>
20  */
21
22 /**
23  * SECTION:gtknumerableicon
24  * @Title: GtkNumerableIcon
25  * @Short_description: A GIcon that allows numbered emblems
26  *
27  * GtkNumerableIcon is a subclass of #GEmblemedIcon that can
28  * show a number or short string as an emblem. The number can
29  * be overlayed on top of another emblem, if desired.
30  *
31  * It supports theming by taking font and color information
32  * from a provided #GtkStyleContext; see
33  * gtk_numerable_icon_set_style_context().
34  *
35  * <example>
36  * <title>Typical numerable icons</title>
37  * <inlinegraphic fileref="numerableicon.png" format="PNG"/>
38  * <inlinegraphic fileref="numerableicon2.png" format="PNG"/>
39  * </example>
40  */
41 #include <config.h>
42
43 #include "gtknumerableicon.h"
44 #include "gtknumerableiconprivate.h"
45
46 #include "gtkicontheme.h"
47 #include "gtkintl.h"
48 #include "gtkwidget.h"
49 #include "gtkwidgetpath.h"
50 #include "gtkwindow.h"
51
52 #include <gdk/gdk.h>
53 #include <pango/pango.h>
54 #include <math.h>
55
56 struct _GtkNumerableIconPrivate {
57   gint count;
58   gint icon_size;
59
60   gchar *label;
61
62   GIcon *background_icon;
63   gchar *background_icon_name;
64
65   GdkRGBA *background;
66   GdkRGBA *foreground;
67
68   PangoFontDescription *font;
69   cairo_pattern_t *background_image;
70   gint border_size;
71
72   GtkStyleContext *style;
73   gulong style_changed_id;
74
75   gchar *rendered_string;
76 };
77
78 enum {
79   PROP_COUNT = 1,
80   PROP_LABEL,
81   PROP_STYLE,
82   PROP_BACKGROUND_ICON,
83   PROP_BACKGROUND_ICON_NAME,
84   NUM_PROPERTIES
85 };
86
87 #define DEFAULT_SURFACE_SIZE 256
88 #define DEFAULT_BORDER_SIZE DEFAULT_SURFACE_SIZE * 0.06
89 #define DEFAULT_RADIUS DEFAULT_SURFACE_SIZE / 2
90
91 #define DEFAULT_BACKGROUND "#000000"
92 #define DEFAULT_FOREGROUND "#ffffff"
93
94 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
95
96 G_DEFINE_TYPE (GtkNumerableIcon, gtk_numerable_icon, G_TYPE_EMBLEMED_ICON);
97
98 static gint
99 get_surface_size (cairo_surface_t *surface)
100 {
101   return MAX (cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface));
102 }
103
104 static gdouble
105 get_border_size (GtkNumerableIcon *self)
106 {
107   return self->priv->border_size;
108 }
109
110 static cairo_surface_t *
111 draw_default_surface (GtkNumerableIcon *self)
112 {
113   cairo_surface_t *surface;
114   cairo_t *cr;
115
116   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
117                                         DEFAULT_SURFACE_SIZE, DEFAULT_SURFACE_SIZE);
118
119   cr = cairo_create (surface);
120
121   cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2.,
122              DEFAULT_RADIUS, 0., 2 * G_PI);
123
124   gdk_cairo_set_source_rgba (cr, self->priv->background);
125   cairo_fill (cr);
126
127   cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2.,
128              DEFAULT_RADIUS - DEFAULT_BORDER_SIZE, 0., 2 * G_PI);
129   gdk_cairo_set_source_rgba  (cr, self->priv->foreground);
130   cairo_fill (cr);
131
132   cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2.,
133              DEFAULT_RADIUS - 2 * DEFAULT_BORDER_SIZE, 0., 2 * G_PI);
134   gdk_cairo_set_source_rgba  (cr, self->priv->background);
135   cairo_fill (cr);
136
137   cairo_destroy (cr);
138
139   return surface;
140 }
141
142 static cairo_surface_t *
143 draw_from_gradient (cairo_pattern_t *pattern)
144 {
145   cairo_surface_t *surface;
146   cairo_matrix_t matrix;
147   cairo_t *cr;
148
149   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
150                                         DEFAULT_SURFACE_SIZE, DEFAULT_SURFACE_SIZE);
151
152   cr = cairo_create (surface);
153
154   /* scale the gradient points to the user space coordinates */
155   cairo_matrix_init_scale (&matrix,
156                            1. / (double) DEFAULT_SURFACE_SIZE,
157                            1. / (double) DEFAULT_SURFACE_SIZE);
158   cairo_pattern_set_matrix (pattern, &matrix);
159
160   cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2.,
161              DEFAULT_RADIUS, 0., 2 * G_PI);
162
163   cairo_set_source (cr, pattern);
164   cairo_fill (cr);
165
166   cairo_destroy (cr);
167
168   return surface;
169 }
170
171 /* copy the surface */
172 static cairo_surface_t *
173 draw_from_image (cairo_surface_t *image)
174 {
175   cairo_surface_t *surface;
176   cairo_t *cr;
177
178   surface = cairo_surface_create_similar (image, CAIRO_CONTENT_COLOR_ALPHA,
179                                           cairo_image_surface_get_width (image),
180                                           cairo_image_surface_get_height (image));
181   cr = cairo_create (surface);
182
183   cairo_set_source_surface (cr, image, 0, 0);
184   cairo_paint (cr);
185
186   cairo_destroy (cr);
187
188   return surface;
189 }
190
191 static cairo_surface_t *
192 draw_from_gicon (GtkNumerableIcon *self)
193 {
194   GtkIconTheme *theme;
195   GdkScreen *screen;
196   GtkIconInfo *info;
197   GdkPixbuf *pixbuf;
198   cairo_surface_t *surface;
199   cairo_t *cr;
200
201   if (self->priv->style != NULL)
202     {
203       screen = gtk_style_context_get_screen (self->priv->style);
204       theme = gtk_icon_theme_get_for_screen (screen);
205     }
206   else
207     {
208       theme = gtk_icon_theme_get_default ();
209     }
210
211   info = gtk_icon_theme_lookup_by_gicon (theme, self->priv->background_icon,
212                                          self->priv->icon_size,
213                                          GTK_ICON_LOOKUP_GENERIC_FALLBACK);
214   if (info == NULL)
215     return NULL;
216
217   pixbuf = gtk_icon_info_load_icon (info, NULL);
218   g_object_unref (info);
219
220   if (pixbuf == NULL)
221     return NULL;
222
223   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
224                                         gdk_pixbuf_get_width (pixbuf),
225                                         gdk_pixbuf_get_height (pixbuf));
226
227   cr = cairo_create (surface);
228
229   gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
230   cairo_paint (cr);
231
232   cairo_destroy (cr);
233   g_object_unref (pixbuf);
234
235   return surface;
236 }
237
238 static cairo_surface_t *
239 get_image_surface (GtkNumerableIcon *self)
240 {
241   cairo_surface_t *retval = NULL, *image;
242
243   if (self->priv->background_icon != NULL)
244     {
245       retval = draw_from_gicon (self);
246       self->priv->border_size = 0;
247     }
248   else if (self->priv->background_image != NULL)
249     {
250       if (cairo_pattern_get_surface (self->priv->background_image, &image) == CAIRO_STATUS_SUCCESS)
251         retval = draw_from_image (image);
252       else
253         retval = draw_from_gradient (self->priv->background_image);
254
255       self->priv->border_size = 0;
256     }
257
258   if (retval == NULL)
259     {
260       retval = draw_default_surface (self);
261       self->priv->border_size = DEFAULT_BORDER_SIZE;
262     }
263
264   return retval;
265 }
266
267 static PangoLayout *
268 get_pango_layout (GtkNumerableIcon *self)
269 {
270   PangoContext *context;
271   GdkScreen *screen;
272   PangoLayout *layout;
273
274   if (self->priv->style != NULL)
275     {
276       screen = gtk_style_context_get_screen (self->priv->style);
277       context = gdk_pango_context_get_for_screen (screen);
278       layout = pango_layout_new (context);
279
280       if (self->priv->font != NULL)
281         pango_layout_set_font_description (layout, self->priv->font);
282
283       pango_layout_set_text (layout, self->priv->rendered_string, -1);
284
285       g_object_unref (context);
286     }
287   else
288     {
289       GtkWidget *fake;
290
291       /* steal gtk text settings from the window */
292       fake = gtk_window_new (GTK_WINDOW_TOPLEVEL);
293       layout = gtk_widget_create_pango_layout (fake, self->priv->rendered_string);
294       gtk_widget_destroy (fake);
295     }
296
297   return layout;
298 }
299
300 static void
301 gtk_numerable_icon_ensure_emblem (GtkNumerableIcon *self)
302 {
303   cairo_t *cr;
304   cairo_surface_t *surface;
305   PangoLayout *layout;
306   GEmblem *emblem;
307   gint width, height;
308   gdouble scale;
309   PangoAttrList *attr_list;
310   PangoAttribute *attr;
311   GdkPixbuf *pixbuf;
312
313   /* don't draw anything if the count is zero */
314   if (self->priv->rendered_string == NULL)
315     {
316       g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self));
317       return;
318     }
319
320   surface = get_image_surface (self);
321   cr = cairo_create (surface);
322
323   layout = get_pango_layout (self);
324   pango_layout_get_pixel_size (layout, &width, &height);
325
326   /* scale the layout to be 0.75 of the size still available for drawing */
327   scale = ((get_surface_size (surface) - 2 * get_border_size (self)) * 0.75) / (MAX (height, width));
328   attr_list = pango_attr_list_new ();
329
330   attr = pango_attr_scale_new (scale);
331   pango_attr_list_insert (attr_list, attr);
332
333   attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
334   pango_attr_list_insert (attr_list, attr);
335
336   pango_layout_set_attributes (layout, attr_list);
337
338   /* update these values */
339   pango_layout_get_pixel_size (layout, &width, &height);
340
341   /* move to the center */
342   cairo_move_to (cr,
343                  get_surface_size (surface) / 2. - (gdouble) width / 2.,
344                  get_surface_size (surface) / 2. - (gdouble) height / 2.);
345
346   gdk_cairo_set_source_rgba (cr, self->priv->foreground);
347   pango_cairo_show_layout (cr, layout);
348
349   cairo_destroy (cr);
350
351   pixbuf =
352     gdk_pixbuf_get_from_surface (surface, 0, 0,
353                                  get_surface_size (surface), get_surface_size (surface));
354
355   emblem = g_emblem_new (G_ICON (pixbuf));
356   g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self));
357   g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (self), emblem);
358
359   g_object_unref (layout);
360   g_object_unref (emblem);
361   g_object_unref (pixbuf);
362
363   cairo_surface_destroy (surface);
364   pango_attr_list_unref (attr_list);
365 }
366
367 static void
368 gtk_numerable_icon_update_properties_from_style (GtkNumerableIcon *self)
369 {
370   GtkStyleContext *style = self->priv->style;
371   GtkWidgetPath *path, *saved;
372   cairo_pattern_t *pattern = NULL;
373   GdkRGBA background, foreground;
374   PangoFontDescription *font = NULL;
375
376   /* save an unmodified copy of the original widget path, in order
377    * to restore it later */
378   path = gtk_widget_path_copy (gtk_style_context_get_path (style));
379   saved = gtk_widget_path_copy (path);
380
381   if (!gtk_widget_path_is_type (path, GTK_TYPE_NUMERABLE_ICON))
382     {
383       /* append our GType to the style context to fetch appropriate colors */
384       gtk_widget_path_append_type (path, GTK_TYPE_NUMERABLE_ICON);
385       gtk_style_context_set_path (style, path);
386     }
387
388   gtk_style_context_get_background_color (style, gtk_style_context_get_state (style),
389                                           &background);
390   gtk_style_context_get_color (style, gtk_style_context_get_state (style),
391                                &foreground);
392
393   if (self->priv->background != NULL)
394     gdk_rgba_free (self->priv->background);
395
396   self->priv->background = gdk_rgba_copy (&background);
397
398   if (self->priv->foreground != NULL)
399     gdk_rgba_free (self->priv->foreground);
400
401   self->priv->foreground = gdk_rgba_copy (&foreground);
402
403   gtk_style_context_get (style, gtk_style_context_get_state (style),
404                          GTK_STYLE_PROPERTY_BACKGROUND_IMAGE, &pattern,
405                          NULL);
406
407   if (pattern != NULL)
408     {
409       if (self->priv->background_image != NULL)
410         cairo_pattern_destroy (self->priv->background_image);
411
412       self->priv->background_image = pattern;
413     }
414
415   gtk_style_context_get (style, gtk_style_context_get_state (style),
416                          GTK_STYLE_PROPERTY_FONT, &font,
417                          NULL);
418
419   if (font != NULL)
420     {
421       if (self->priv->font != NULL)
422         pango_font_description_free (self->priv->font);
423
424       self->priv->font = font;
425     }
426
427   gtk_numerable_icon_ensure_emblem (self);
428
429   /* restore original widget path */
430   gtk_style_context_set_path (style, saved);
431
432   gtk_widget_path_free (path);
433   gtk_widget_path_free (saved);
434 }
435
436 static void
437 gtk_numerable_icon_init_style (GtkNumerableIcon *self)
438 {
439   GtkStyleContext *style = self->priv->style;
440
441   if (style == NULL)
442     return;
443
444   gtk_numerable_icon_update_properties_from_style (self);
445
446   self->priv->style_changed_id =
447     g_signal_connect_swapped (style, "changed",
448                               G_CALLBACK (gtk_numerable_icon_update_properties_from_style), self);
449 }
450
451 static void
452 gtk_numerable_icon_ensure_and_replace_label (GtkNumerableIcon *self,
453                                              gint              count,
454                                              const gchar      *label)
455 {
456   g_assert (!(label != NULL && count != 0));
457
458   g_free (self->priv->rendered_string);
459   self->priv->rendered_string = NULL;
460
461   if (count != 0)
462     {
463       if (self->priv->label != NULL)
464         {
465           g_free (self->priv->label);
466           self->priv->label = NULL;
467
468           g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]);
469         }
470
471       if (count > 99)
472         count = 99;
473
474       if (count < -99)
475         count = -99;
476
477       self->priv->count = count;
478
479       /* Translators: the format here is used to build the string that will be rendered
480        * in the number emblem.
481        */
482       self->priv->rendered_string = g_strdup_printf (C_("Number format", "%d"), count);
483
484       return;
485     }
486
487   if (label != NULL)
488     {
489       if (self->priv->count != 0)
490         {
491           self->priv->count = 0;
492
493           g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COUNT]);
494         }
495
496       g_free (self->priv->label);
497
498       if (g_strcmp0 (label, "") == 0)
499         {
500           self->priv->label = NULL;
501           return;
502         }
503
504       self->priv->label = g_strdup (label);
505       self->priv->rendered_string = g_strdup (label);
506     }
507 }
508
509 static gboolean
510 real_set_background_icon (GtkNumerableIcon *self,
511                           GIcon            *icon)
512 {
513   if (!g_icon_equal (self->priv->background_icon, icon))
514     {
515       g_clear_object (&self->priv->background_icon);
516
517       if (icon != NULL)
518         self->priv->background_icon = g_object_ref (icon);
519
520       gtk_numerable_icon_ensure_emblem (self);
521
522       return TRUE;
523     }
524
525   return FALSE;
526 }
527
528 static void
529 gtk_numerable_icon_constructed (GObject *object)
530 {
531   GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object);
532
533   if (G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->constructed != NULL)
534     G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->constructed (object);
535
536   gtk_numerable_icon_ensure_emblem (self);
537 }
538
539 static void
540 gtk_numerable_icon_finalize (GObject *object)
541 {
542   GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object);
543
544   g_free (self->priv->label);
545   g_free (self->priv->rendered_string);
546
547   gdk_rgba_free (self->priv->background);
548   gdk_rgba_free (self->priv->foreground);
549
550   pango_font_description_free (self->priv->font);
551
552   cairo_pattern_destroy (self->priv->background_image);
553
554   G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->finalize (object);
555 }
556
557 static void
558 gtk_numerable_icon_dispose (GObject *object)
559 {
560   GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object);
561
562   if (self->priv->style_changed_id != 0)
563     {
564       g_signal_handler_disconnect (self->priv->style,
565                                    self->priv->style_changed_id);
566       self->priv->style_changed_id = 0;
567     }
568
569   g_clear_object (&self->priv->style);
570   g_clear_object (&self->priv->background_icon);
571
572   G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->dispose (object);
573 }
574
575 static void
576 gtk_numerable_icon_set_property (GObject      *object,
577                                  guint         property_id,
578                                  const GValue *value,
579                                  GParamSpec   *pspec)
580 {
581   GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object);
582
583   switch (property_id)
584     {
585     case PROP_COUNT:
586       gtk_numerable_icon_set_count (self, g_value_get_int (value));
587       break;
588     case PROP_LABEL:
589       gtk_numerable_icon_set_label (self, g_value_get_string (value));
590       break;
591     case PROP_STYLE:
592       gtk_numerable_icon_set_style_context (self, g_value_get_object (value));
593       break;
594     case PROP_BACKGROUND_ICON:
595       gtk_numerable_icon_set_background_gicon (self, g_value_get_object (value));
596       break;
597     case PROP_BACKGROUND_ICON_NAME:
598       gtk_numerable_icon_set_background_icon_name (self, g_value_get_string (value));
599       break;
600     default:
601       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
602       break;
603     }
604 }
605
606 static void
607 gtk_numerable_icon_get_property (GObject    *object,
608                                  guint       property_id,
609                                  GValue     *value,
610                                  GParamSpec *pspec)
611 {
612   GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object);
613
614   switch (property_id)
615     {
616     case PROP_COUNT:
617       g_value_set_int (value, self->priv->count);
618       break;
619     case PROP_LABEL:
620       g_value_set_string (value, self->priv->label);
621       break;
622     case PROP_STYLE:
623       g_value_set_object (value, self->priv->style);
624       break;
625     case PROP_BACKGROUND_ICON:
626       if (self->priv->background_icon != NULL)
627         g_value_set_object (value, self->priv->background_icon);
628       break;
629     case PROP_BACKGROUND_ICON_NAME:
630       g_value_set_string (value, self->priv->background_icon_name);
631       break;
632     default:
633       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
634       break;
635     }
636 }
637
638 static void
639 gtk_numerable_icon_class_init (GtkNumerableIconClass *klass)
640 {
641   GObjectClass *oclass = G_OBJECT_CLASS (klass);
642
643   oclass->get_property = gtk_numerable_icon_get_property;
644   oclass->set_property = gtk_numerable_icon_set_property;
645   oclass->constructed = gtk_numerable_icon_constructed;
646   oclass->dispose = gtk_numerable_icon_dispose;
647   oclass->finalize = gtk_numerable_icon_finalize;
648
649   g_type_class_add_private (klass, sizeof (GtkNumerableIconPrivate));
650
651   properties[PROP_COUNT] =
652     g_param_spec_int ("count",
653                       P_("Icon's count"),
654                       P_("The count of the emblem currently displayed"),
655                       -99, 99, 0,
656                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
657
658   properties[PROP_LABEL] =
659     g_param_spec_string ("label",
660                          P_("Icon's label"),
661                          P_("The label to be displayed over the icon"),
662                          NULL,
663                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
664
665   properties[PROP_STYLE] =
666     g_param_spec_object ("style-context",
667                          P_("Icon's style context"),
668                          P_("The style context to theme the icon appearance"),
669                          GTK_TYPE_STYLE_CONTEXT,
670                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
671
672   properties[PROP_BACKGROUND_ICON] =
673     g_param_spec_object ("background-icon",
674                          P_("Background icon"),
675                          P_("The icon for the number emblem background"),
676                          G_TYPE_ICON,
677                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
678
679   properties[PROP_BACKGROUND_ICON_NAME] =
680     g_param_spec_string ("background-icon-name",
681                          P_("Background icon name"),
682                          P_("The icon name for the number emblem background"),
683                          NULL,
684                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
685
686   g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
687 }
688
689 static void
690 gtk_numerable_icon_init (GtkNumerableIcon *self)
691 {
692   GdkRGBA bg;
693   GdkRGBA fg;
694
695   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
696                                             GTK_TYPE_NUMERABLE_ICON,
697                                             GtkNumerableIconPrivate);
698
699   gdk_rgba_parse (&bg, DEFAULT_BACKGROUND);
700   gdk_rgba_parse (&fg, DEFAULT_FOREGROUND);
701
702   self->priv->background = gdk_rgba_copy (&bg);
703   self->priv->foreground = gdk_rgba_copy (&fg);
704
705   self->priv->icon_size = 48;
706 }
707
708 /* private */
709 void
710 _gtk_numerable_icon_set_background_icon_size (GtkNumerableIcon *self,
711                                               gint              icon_size)
712 {
713   if (self->priv->background_icon == NULL)
714     return;
715
716   if (self->priv->icon_size != icon_size)
717     {
718       self->priv->icon_size = icon_size;
719       gtk_numerable_icon_ensure_emblem (self);
720     }
721 }
722
723 /**
724  * gtk_numerable_icon_get_label:
725  * @self: a #GtkNumerableIcon
726  *
727  * Returns the currently displayed label of the icon, or %NULL.
728  *
729  * Returns: the currently displayed label
730  *
731  * Since: 3.0
732  */
733 const gchar *
734 gtk_numerable_icon_get_label (GtkNumerableIcon *self)
735 {
736   g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL);
737
738   return self->priv->label;
739 }
740
741 /**
742  * gtk_numerable_icon_set_label:
743  * @self: a #GtkNumerableIcon
744  * @label: (allow-none): a short label, or %NULL
745  *
746  * Sets the currently displayed value of @self to the string
747  * in @label. Setting an empty label removes the emblem.
748  *
749  * Note that this is meant for displaying short labels, such as
750  * roman numbers, or single letters. For roman numbers, consider
751  * using the Unicode characters U+2160 - U+217F. Strings longer
752  * than two characters will likely not be rendered very well.
753  *
754  * If this method is called, and a number was already set on the
755  * icon, it will automatically be reset to zero before rendering
756  * the label, i.e. the last method called between
757  * gtk_numerable_icon_set_label() and gtk_numerable_icon_set_count()
758  * has always priority.
759  *
760  * Since: 3.0
761  */
762 void
763 gtk_numerable_icon_set_label (GtkNumerableIcon *self,
764                               const gchar      *label)
765 {
766   g_return_if_fail (GTK_IS_NUMERABLE_ICON (self));
767
768   if (g_strcmp0 (label, self->priv->label) != 0)
769     {
770       gtk_numerable_icon_ensure_and_replace_label (self, 0, label);
771       gtk_numerable_icon_ensure_emblem (self);
772
773       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]);
774     }
775 }
776
777 /**
778  * gtk_numerable_icon_get_count:
779  * @self: a #GtkNumerableIcon
780  *
781  * Returns the value currently displayed by @self.
782  *
783  * Returns: the currently displayed value
784  *
785  * Since: 3.0
786  */
787 gint
788 gtk_numerable_icon_get_count (GtkNumerableIcon *self)
789 {
790   g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), 0);
791
792   return self->priv->count;
793 }
794
795 /**
796  * gtk_numerable_icon_set_count:
797  * @self: a #GtkNumerableIcon
798  * @count: a number between -99 and 99
799  *
800  * Sets the currently displayed value of @self to @count.
801  *
802  * The numeric value is always clamped to make it two digits, i.e.
803  * between -99 and 99. Setting a count of zero removes the emblem.
804  * If this method is called, and a label was already set on the icon,
805  * it will automatically be reset to %NULL before rendering the number,
806  * i.e. the last method called between gtk_numerable_icon_set_count()
807  * and gtk_numerable_icon_set_label() has always priority.
808  *
809  * Since: 3.0
810  */
811 void
812 gtk_numerable_icon_set_count (GtkNumerableIcon *self,
813                               gint              count)
814 {
815   g_return_if_fail (GTK_IS_NUMERABLE_ICON (self));
816
817   if (count != self->priv->count)
818     {
819       gtk_numerable_icon_ensure_and_replace_label (self, count, NULL);
820       gtk_numerable_icon_ensure_emblem (self);
821
822       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COUNT]);
823     }
824 }
825
826 /**
827  * gtk_numerable_icon_get_style_context:
828  * @self: a #GtkNumerableIcon
829  *
830  * Returns the #GtkStyleContext used by the icon for theming,
831  * or %NULL if there's none.
832  *
833  * Returns: (transfer none): a #GtkStyleContext, or %NULL.
834  *     This object is internal to GTK+ and should not be unreffed.
835  *     Use g_object_ref() if you want to keep it around
836  *
837  * Since: 3.0
838  */
839 GtkStyleContext *
840 gtk_numerable_icon_get_style_context (GtkNumerableIcon *self)
841 {
842   g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL);
843
844   return self->priv->style;
845 }
846
847 /**
848  * gtk_numerable_icon_set_style_context:
849  * @self: a #GtkNumerableIcon
850  * @style: a #GtkStyleContext
851  *
852  * Updates the icon to fetch theme information from the
853  * given #GtkStyleContext.
854  *
855  * Since: 3.0
856  */
857 void
858 gtk_numerable_icon_set_style_context (GtkNumerableIcon *self,
859                                       GtkStyleContext  *style)
860 {
861   g_return_if_fail (GTK_IS_NUMERABLE_ICON (self));
862   g_return_if_fail (GTK_IS_STYLE_CONTEXT (style));
863
864   if (style != self->priv->style)
865     {
866       if (self->priv->style_changed_id != 0)
867         g_signal_handler_disconnect (self->priv->style,
868                                      self->priv->style_changed_id);
869
870       if (self->priv->style != NULL)
871         g_object_unref (self->priv->style);
872
873       self->priv->style = g_object_ref (style);
874
875       gtk_numerable_icon_init_style (self);
876
877       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STYLE]);
878     }
879 }
880
881 /**
882  * gtk_numerable_icon_set_background_gicon:
883  * @self: a #GtkNumerableIcon
884  * @icon: (allow-none): a #GIcon, or %NULL
885  *
886  * Updates the icon to use @icon as the base background image.
887  * If @icon is %NULL, @self will go back using style information
888  * or default theming for its background image.
889  *
890  * If this method is called and an icon name was already set as
891  * background for the icon, @icon will be used, i.e. the last method
892  * called between gtk_numerable_icon_set_background_gicon() and
893  * gtk_numerable_icon_set_background_icon_name() has always priority.
894  *
895  * Since: 3.0
896  */
897 void
898 gtk_numerable_icon_set_background_gicon (GtkNumerableIcon *self,
899                                          GIcon            *icon)
900 {
901   gboolean res;
902
903   g_return_if_fail (GTK_IS_NUMERABLE_ICON (self));
904
905   if (self->priv->background_icon_name != NULL)
906     {
907       g_free (self->priv->background_icon_name);
908       self->priv->background_icon_name = NULL;
909     }
910
911   res = real_set_background_icon (self, icon);
912
913   if (res)
914     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND_ICON]);
915 }
916
917 /**
918  * gtk_numerable_icon_get_background_gicon:
919  * @self: a #GtkNumerableIcon
920  *
921  * Returns the #GIcon that was set as the base background image, or
922  * %NULL if there's none. The caller of this function does not own
923  * a reference to the returned #GIcon.
924  *
925  * Returns: (transfer none): a #GIcon, or %NULL
926  *
927  * Since: 3.0
928  */
929 GIcon *
930 gtk_numerable_icon_get_background_gicon (GtkNumerableIcon *self)
931 {
932   GIcon *retval = NULL;
933
934   g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL);
935
936   /* return the GIcon only if it wasn't created from an icon name */
937   if (self->priv->background_icon_name == NULL)
938     retval = self->priv->background_icon;
939
940   return retval;
941 }
942
943 /**
944  * gtk_numerable_icon_set_background_icon_name:
945  * @self: a #GtkNumerableIcon
946  * @icon_name: (allow-none): an icon name, or %NULL
947  *
948  * Updates the icon to use the icon named @icon_name from the
949  * current icon theme as the base background image. If @icon_name
950  * is %NULL, @self will go back using style information or default
951  * theming for its background image.
952  *
953  * If this method is called and a #GIcon was already set as
954  * background for the icon, @icon_name will be used, i.e. the
955  * last method called between gtk_numerable_icon_set_background_icon_name()
956  * and gtk_numerable_icon_set_background_gicon() has always priority.
957  *
958  * Since: 3.0
959  */
960 void
961 gtk_numerable_icon_set_background_icon_name (GtkNumerableIcon *self,
962                                              const gchar      *icon_name)
963 {
964   GIcon *icon = NULL;
965   gboolean res;
966
967   g_return_if_fail (GTK_IS_NUMERABLE_ICON (self));
968
969   if (g_strcmp0 (icon_name, self->priv->background_icon_name) != 0)
970     {
971       g_free (self->priv->background_icon_name);
972       self->priv->background_icon_name = g_strdup (icon_name);
973     }
974
975   if (icon_name != NULL)
976     icon = g_themed_icon_new_with_default_fallbacks (icon_name);
977
978   res = real_set_background_icon (self, icon);
979
980   if (res)
981     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND_ICON_NAME]);
982
983   if (icon != NULL)
984     g_object_unref (icon);
985 }
986
987 /**
988  * gtk_numerable_icon_get_background_icon_name:
989  * @self: a #GtkNumerableIcon
990  *
991  * Returns the icon name used as the base background image,
992  * or %NULL if there's none.
993  *
994  * Returns: an icon name, or %NULL
995  *
996  * Since: 3.0
997  */
998 const gchar *
999 gtk_numerable_icon_get_background_icon_name (GtkNumerableIcon *self)
1000 {
1001   g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL);
1002
1003   return self->priv->background_icon_name;
1004 }
1005
1006 /**
1007  * gtk_numerable_icon_new:
1008  * @base_icon: a #GIcon to overlay on
1009  *
1010  * Creates a new unthemed #GtkNumerableIcon.
1011  *
1012  * Returns: (transfer full): a new #GIcon
1013  *
1014  * Since: 3.0
1015  */
1016 GIcon *
1017 gtk_numerable_icon_new (GIcon *base_icon)
1018 {
1019   g_return_val_if_fail (G_IS_ICON (base_icon), NULL);
1020
1021   return g_object_new (GTK_TYPE_NUMERABLE_ICON,
1022                        "gicon", base_icon,
1023                        NULL);
1024 }
1025
1026 /**
1027  * gtk_numerable_icon_new_with_style_context:
1028  * @base_icon: a #GIcon to overlay on
1029  * @context: a #GtkStyleContext
1030  *
1031  * Creates a new #GtkNumerableIcon which will themed according
1032  * to the passed #GtkStyleContext. This is a convenience constructor
1033  * that calls gtk_numerable_icon_set_style_context() internally.
1034  *
1035  * Returns: (transfer full): a new #GIcon
1036  *
1037  * Since: 3.0
1038  */
1039 GIcon *
1040 gtk_numerable_icon_new_with_style_context (GIcon           *base_icon,
1041                                            GtkStyleContext *context)
1042 {
1043   g_return_val_if_fail (G_IS_ICON (base_icon), NULL);
1044
1045   return g_object_new (GTK_TYPE_NUMERABLE_ICON,
1046                        "gicon", base_icon,
1047                        "style-context", context,
1048                        NULL);
1049 }