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