Tizen 2.1 base
[platform/upstream/glib2.0.git] / gio / gemblemedicon.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  * 
5  * Copyright (C) 2006-2007 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * Author: Matthias Clasen <mclasen@redhat.com>
23  *         Clemens N. Buss <cebuzz@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include "gemblemedicon.h"
31 #include "glibintl.h"
32 #include "gioerror.h"
33
34
35 /**
36  * SECTION:gemblemedicon
37  * @short_description: Icon with emblems
38  * @include: gio/gio.h
39  * @see_also: #GIcon, #GLoadableIcon, #GThemedIcon, #GEmblem
40  *
41  * #GEmblemedIcon is an implementation of #GIcon that supports
42  * adding an emblem to an icon. Adding multiple emblems to an
43  * icon is ensured via g_emblemed_icon_add_emblem(). 
44  *
45  * Note that #GEmblemedIcon allows no control over the position
46  * of the emblems. See also #GEmblem for more information.
47  **/
48
49 enum {
50   PROP_GICON = 1,
51   NUM_PROPERTIES
52 };
53
54 struct _GEmblemedIconPrivate {
55   GIcon *icon;
56   GList *emblems;
57 };
58
59 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
60
61 static void g_emblemed_icon_icon_iface_init (GIconIface *iface);
62
63 G_DEFINE_TYPE_WITH_CODE (GEmblemedIcon, g_emblemed_icon, G_TYPE_OBJECT,
64                          G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
65                          g_emblemed_icon_icon_iface_init))
66
67
68 static void
69 g_emblemed_icon_finalize (GObject *object)
70 {
71   GEmblemedIcon *emblemed;
72
73   emblemed = G_EMBLEMED_ICON (object);
74
75   g_object_unref (emblemed->priv->icon);
76   g_list_free_full (emblemed->priv->emblems, g_object_unref);
77
78   (*G_OBJECT_CLASS (g_emblemed_icon_parent_class)->finalize) (object);
79 }
80
81 static void
82 g_emblemed_icon_set_property (GObject  *object,
83                               guint property_id,
84                               const GValue *value,
85                               GParamSpec *pspec)
86 {
87   GEmblemedIcon *self = G_EMBLEMED_ICON (object);
88
89   switch (property_id)
90     {
91     case PROP_GICON:
92       self->priv->icon = g_value_dup_object (value);
93       break;
94     default:
95       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
96       break;
97     }
98 }
99
100 static void
101 g_emblemed_icon_get_property (GObject  *object,
102                               guint property_id,
103                               GValue *value,
104                               GParamSpec *pspec)
105 {
106   GEmblemedIcon *self = G_EMBLEMED_ICON (object);
107
108   switch (property_id)
109     {
110     case PROP_GICON:
111       g_value_set_object (value, self->priv->icon);
112       break;
113     default:
114       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
115       break;
116     }
117 }
118
119 static void
120 g_emblemed_icon_class_init (GEmblemedIconClass *klass)
121 {
122   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
123
124   gobject_class->finalize = g_emblemed_icon_finalize;
125   gobject_class->set_property = g_emblemed_icon_set_property;
126   gobject_class->get_property = g_emblemed_icon_get_property;
127
128   properties[PROP_GICON] =
129     g_param_spec_object ("gicon",
130                          P_("The base GIcon"),
131                          P_("The GIcon to attach emblems to"),
132                          G_TYPE_ICON,
133                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
134
135   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
136
137   g_type_class_add_private (klass, sizeof (GEmblemedIconPrivate));
138 }
139
140 static void
141 g_emblemed_icon_init (GEmblemedIcon *emblemed)
142 {
143   emblemed->priv =
144     G_TYPE_INSTANCE_GET_PRIVATE (emblemed, G_TYPE_EMBLEMED_ICON,
145                                  GEmblemedIconPrivate);
146 }
147
148 /**
149  * g_emblemed_icon_new:
150  * @icon: a #GIcon
151  * @emblem: (allow-none): a #GEmblem, or %NULL
152  *
153  * Creates a new emblemed icon for @icon with the emblem @emblem.
154  *
155  * Returns: (transfer full) (type GEmblemedIcon): a new #GIcon
156  *
157  * Since: 2.18
158  **/
159 GIcon *
160 g_emblemed_icon_new (GIcon   *icon,
161                      GEmblem *emblem)
162 {
163   GEmblemedIcon *emblemed;
164   
165   g_return_val_if_fail (G_IS_ICON (icon), NULL);
166   g_return_val_if_fail (!G_IS_EMBLEM (icon), NULL);
167
168   emblemed = G_EMBLEMED_ICON (g_object_new (G_TYPE_EMBLEMED_ICON,
169                                             "gicon", icon,
170                                             NULL));
171
172   if (emblem != NULL)
173     g_emblemed_icon_add_emblem (emblemed, emblem);
174
175   return G_ICON (emblemed);
176 }
177
178
179 /**
180  * g_emblemed_icon_get_icon:
181  * @emblemed: a #GEmblemedIcon
182  *
183  * Gets the main icon for @emblemed.
184  *
185  * Returns: (transfer none): a #GIcon that is owned by @emblemed
186  *
187  * Since: 2.18
188  **/
189 GIcon *
190 g_emblemed_icon_get_icon (GEmblemedIcon *emblemed)
191 {
192   g_return_val_if_fail (G_IS_EMBLEMED_ICON (emblemed), NULL);
193
194   return emblemed->priv->icon;
195 }
196
197 /**
198  * g_emblemed_icon_get_emblems:
199  * @emblemed: a #GEmblemedIcon
200  *
201  * Gets the list of emblems for the @icon.
202  *
203  * Returns: (element-type Gio.Emblem) (transfer none): a #GList of
204  *          #GEmblem <!-- -->s that is owned by @emblemed
205  *
206  * Since: 2.18
207  **/
208
209 GList *
210 g_emblemed_icon_get_emblems (GEmblemedIcon *emblemed)
211 {
212   g_return_val_if_fail (G_IS_EMBLEMED_ICON (emblemed), NULL);
213
214   return emblemed->priv->emblems;
215 }
216
217 /**
218  * g_emblemed_icon_clear_emblems:
219  * @emblemed: a #GEmblemedIcon
220  *
221  * Removes all the emblems from @icon.
222  *
223  * Since: 2.28
224  **/
225 void
226 g_emblemed_icon_clear_emblems (GEmblemedIcon *emblemed)
227 {
228   g_return_if_fail (G_IS_EMBLEMED_ICON (emblemed));
229
230   if (emblemed->priv->emblems == NULL)
231     return;
232
233   g_list_free_full (emblemed->priv->emblems, g_object_unref);
234   emblemed->priv->emblems = NULL;
235 }
236
237 static gint
238 g_emblem_comp (GEmblem *a,
239                GEmblem *b)
240 {
241   guint hash_a = g_icon_hash (G_ICON (a));
242   guint hash_b = g_icon_hash (G_ICON (b));
243
244   if(hash_a < hash_b)
245     return -1;
246
247   if(hash_a == hash_b)
248     return 0;
249
250   return 1;
251 }
252
253 /**
254  * g_emblemed_icon_add_emblem:
255  * @emblemed: a #GEmblemedIcon
256  * @emblem: a #GEmblem
257  *
258  * Adds @emblem to the #GList of #GEmblem <!-- -->s.
259  *
260  * Since: 2.18
261  **/
262 void 
263 g_emblemed_icon_add_emblem (GEmblemedIcon *emblemed,
264                             GEmblem       *emblem)
265 {
266   g_return_if_fail (G_IS_EMBLEMED_ICON (emblemed));
267   g_return_if_fail (G_IS_EMBLEM (emblem));
268
269   g_object_ref (emblem);
270   emblemed->priv->emblems = g_list_insert_sorted (emblemed->priv->emblems, emblem,
271                                                   (GCompareFunc) g_emblem_comp);
272 }
273
274 static guint
275 g_emblemed_icon_hash (GIcon *icon)
276 {
277   GEmblemedIcon *emblemed = G_EMBLEMED_ICON (icon);
278   GList *list;
279   guint hash = g_icon_hash (emblemed->priv->icon);
280
281   for (list = emblemed->priv->emblems; list != NULL; list = list->next)
282     hash ^= g_icon_hash (G_ICON (list->data));
283
284   return hash;
285 }
286
287 static gboolean
288 g_emblemed_icon_equal (GIcon *icon1,
289                        GIcon *icon2)
290 {
291   GEmblemedIcon *emblemed1 = G_EMBLEMED_ICON (icon1);
292   GEmblemedIcon *emblemed2 = G_EMBLEMED_ICON (icon2);
293   GList *list1, *list2;
294
295   if (!g_icon_equal (emblemed1->priv->icon, emblemed2->priv->icon))
296     return FALSE;
297
298   list1 = emblemed1->priv->emblems;
299   list2 = emblemed2->priv->emblems;
300
301   while (list1 && list2)
302   {
303     if (!g_icon_equal (G_ICON (list1->data), G_ICON (list2->data)))
304         return FALSE;
305     
306     list1 = list1->next;
307     list2 = list2->next;
308   }
309   
310   return list1 == NULL && list2 == NULL;
311 }
312
313 static gboolean
314 g_emblemed_icon_to_tokens (GIcon *icon,
315                            GPtrArray *tokens,
316                            gint  *out_version)
317 {
318   GEmblemedIcon *emblemed_icon = G_EMBLEMED_ICON (icon);
319   GList *l;
320   char *s;
321
322   /* GEmblemedIcons are encoded as
323    *
324    *   <encoded_icon> [<encoded_emblem_icon>]*
325    */
326
327   g_return_val_if_fail (out_version != NULL, FALSE);
328
329   *out_version = 0;
330
331   s = g_icon_to_string (emblemed_icon->priv->icon);
332   if (s == NULL)
333     return FALSE;
334
335   g_ptr_array_add (tokens, s);
336
337   for (l = emblemed_icon->priv->emblems; l != NULL; l = l->next)
338     {
339       GIcon *emblem_icon = G_ICON (l->data);
340
341       s = g_icon_to_string (emblem_icon);
342       if (s == NULL)
343         return FALSE;
344       
345       g_ptr_array_add (tokens, s);
346     }
347
348   return TRUE;
349 }
350
351 static GIcon *
352 g_emblemed_icon_from_tokens (gchar  **tokens,
353                              gint     num_tokens,
354                              gint     version,
355                              GError **error)
356 {
357   GEmblemedIcon *emblemed_icon;
358   int n;
359
360   emblemed_icon = NULL;
361
362   if (version != 0)
363     {
364       g_set_error (error,
365                    G_IO_ERROR,
366                    G_IO_ERROR_INVALID_ARGUMENT,
367                    _("Can't handle version %d of GEmblemedIcon encoding"),
368                    version);
369       goto fail;
370     }
371
372   if (num_tokens < 1)
373     {
374       g_set_error (error,
375                    G_IO_ERROR,
376                    G_IO_ERROR_INVALID_ARGUMENT,
377                    _("Malformed number of tokens (%d) in GEmblemedIcon encoding"),
378                    num_tokens);
379       goto fail;
380     }
381
382   emblemed_icon = g_object_new (G_TYPE_EMBLEMED_ICON, NULL);
383   emblemed_icon->priv->icon = g_icon_new_for_string (tokens[0], error);
384   if (emblemed_icon->priv->icon == NULL)
385     goto fail;
386
387   for (n = 1; n < num_tokens; n++)
388     {
389       GIcon *emblem;
390
391       emblem = g_icon_new_for_string (tokens[n], error);
392       if (emblem == NULL)
393         goto fail;
394
395       if (!G_IS_EMBLEM (emblem))
396         {
397           g_set_error_literal (error,
398                                G_IO_ERROR,
399                                G_IO_ERROR_INVALID_ARGUMENT,
400                                _("Expected a GEmblem for GEmblemedIcon"));
401           g_object_unref (emblem);
402           goto fail;
403         }
404
405       emblemed_icon->priv->emblems = g_list_append (emblemed_icon->priv->emblems, emblem);
406     }
407
408   return G_ICON (emblemed_icon);
409
410  fail:
411   if (emblemed_icon != NULL)
412     g_object_unref (emblemed_icon);
413   return NULL;
414 }
415
416 static void
417 g_emblemed_icon_icon_iface_init (GIconIface *iface)
418 {
419   iface->hash = g_emblemed_icon_hash;
420   iface->equal = g_emblemed_icon_equal;
421   iface->to_tokens = g_emblemed_icon_to_tokens;
422   iface->from_tokens = g_emblemed_icon_from_tokens;
423 }