gemblemedicon.c 8.57 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

/* GIO - GLib Input, Output and Streaming Library
 * 
 * Copyright (C) 2006-2007 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: Matthias Clasen <mclasen@redhat.com>
Matthias Clasen's avatar
Matthias Clasen committed
23
 *         Clemens N. Buss <cebuzz@gmail.com>
24 25 26 27 28 29 30 31
 */

#include <config.h>

#include <string.h>

#include "gemblemedicon.h"
#include "glibintl.h"
32
#include "gioerror.h"
33 34 35 36 37 38


/**
 * SECTION:gemblemedicon
 * @short_description: Icon with emblems
 * @include: gio/gio.h
Matthias Clasen's avatar
Matthias Clasen committed
39
 * @see_also: #GIcon, #GLoadableIcon, #GThemedIcon, #GEmblem
40 41
 *
 * #GEmblemedIcon is an implementation of #GIcon that supports
Matthias Clasen's avatar
Matthias Clasen committed
42 43
 * adding an emblem to an icon. Adding multiple emblems to an
 * icon is ensured via g_emblemed_icon_add_emblem(). 
44 45
 *
 * Note that #GEmblemedIcon allows no control over the position
Matthias Clasen's avatar
Matthias Clasen committed
46
 * of the emblems. See also #GEmblem for more information.
47 48 49 50 51 52 53 54 55
 **/

static void g_emblemed_icon_icon_iface_init (GIconIface *iface);

struct _GEmblemedIcon
{
  GObject parent_instance;

  GIcon *icon;
Matthias Clasen's avatar
Matthias Clasen committed
56
  GList *emblems;
57 58 59 60 61 62 63 64
};

struct _GEmblemedIconClass
{
  GObjectClass parent_class;
};

G_DEFINE_TYPE_WITH_CODE (GEmblemedIcon, g_emblemed_icon, G_TYPE_OBJECT,
Matthias Clasen's avatar
Matthias Clasen committed
65 66
                         G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
                         g_emblemed_icon_icon_iface_init))
67 68 69 70 71 72 73 74 75 76


static void
g_emblemed_icon_finalize (GObject *object)
{
  GEmblemedIcon *emblemed;

  emblemed = G_EMBLEMED_ICON (object);

  g_object_unref (emblemed->icon);
Matthias Clasen's avatar
Matthias Clasen committed
77
  g_list_foreach (emblemed->emblems, (GFunc) g_object_unref, NULL);
78
  g_list_free (emblemed->emblems);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

  (*G_OBJECT_CLASS (g_emblemed_icon_parent_class)->finalize) (object);
}

static void
g_emblemed_icon_class_init (GEmblemedIconClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  gobject_class->finalize = g_emblemed_icon_finalize;
}

static void
g_emblemed_icon_init (GEmblemedIcon *emblemed)
{
}

/**
 * g_emblemed_icon_new:
Matthias Clasen's avatar
Matthias Clasen committed
97
 * @icon: a #GIcon
98
 * @emblem: (allow-none): a #GEmblem, or %NULL
99
 *
Matthias Clasen's avatar
Matthias Clasen committed
100
 * Creates a new emblemed icon for @icon with the emblem @emblem.
101
 *
102
 * Returns: (transfer full): a new #GIcon
103 104 105 106
 *
 * Since: 2.18
 **/
GIcon *
Matthias Clasen's avatar
Matthias Clasen committed
107 108
g_emblemed_icon_new (GIcon   *icon,
                     GEmblem *emblem)
109 110
{
  GEmblemedIcon *emblemed;
Matthias Clasen's avatar
Matthias Clasen committed
111 112 113
  
  g_return_val_if_fail (G_IS_ICON (icon), NULL);
  g_return_val_if_fail (!G_IS_EMBLEM (icon), NULL);
114 115 116

  emblemed = G_EMBLEMED_ICON (g_object_new (G_TYPE_EMBLEMED_ICON, NULL));
  emblemed->icon = g_object_ref (icon);
117 118 119

  if (emblem != NULL)
    g_emblemed_icon_add_emblem (emblemed, emblem);
120 121 122 123

  return G_ICON (emblemed);
}

Matthias Clasen's avatar
Matthias Clasen committed
124

125 126
/**
 * g_emblemed_icon_get_icon:
Matthias Clasen's avatar
Matthias Clasen committed
127
 * @emblemed: a #GEmblemedIcon
128
 *
Matthias Clasen's avatar
Matthias Clasen committed
129
 * Gets the main icon for @emblemed.
130
 *
131
 * Returns: (transfer full): a #GIcon that is owned by @emblemed
132 133 134 135
 *
 * Since: 2.18
 **/
GIcon *
Matthias Clasen's avatar
Matthias Clasen committed
136
g_emblemed_icon_get_icon (GEmblemedIcon *emblemed)
137
{
Matthias Clasen's avatar
Matthias Clasen committed
138
  g_return_val_if_fail (G_IS_EMBLEMED_ICON (emblemed), NULL);
139

Matthias Clasen's avatar
Matthias Clasen committed
140
  return emblemed->icon;
141 142 143
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
144 145
 * g_emblemed_icon_get_emblems:
 * @emblemed: a #GEmblemedIcon
146
 *
Matthias Clasen's avatar
Matthias Clasen committed
147
 * Gets the list of emblems for the @icon.
148
 *
149 150
 * Returns: (element-type utf8) (transfer none): a #GList of #GEmblem <!-- -->s that
 * is owned by @emblemed
151 152 153
 *
 * Since: 2.18
 **/
Matthias Clasen's avatar
Matthias Clasen committed
154 155 156 157 158 159 160 161 162

GList *
g_emblemed_icon_get_emblems (GEmblemedIcon *emblemed)
{
  g_return_val_if_fail (G_IS_EMBLEMED_ICON (emblemed), NULL);

  return emblemed->emblems;
}

163 164 165 166
/**
 * g_emblemed_icon_clear_emblems:
 * @emblemed: a #GEmblemedIcon
 *
Cosimo Cecchi's avatar
Cosimo Cecchi committed
167
 * Removes all the emblems from @icon.
168 169 170
 *
 * Since: 2.28
 **/
171 172 173 174 175 176 177 178 179 180 181 182
void
g_emblemed_icon_clear_emblems (GEmblemedIcon *emblemed)
{
  g_return_if_fail (G_IS_EMBLEMED_ICON (emblemed));

  if (emblemed->emblems == NULL)
    return;

  g_list_free_full (emblemed->emblems, g_object_unref);
  emblemed->emblems = NULL;
}

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
static gint
g_emblem_comp (GEmblem *a,
               GEmblem *b)
{
  guint hash_a = g_icon_hash (G_ICON (a));
  guint hash_b = g_icon_hash (G_ICON (b));

  if(hash_a < hash_b)
    return -1;

  if(hash_a == hash_b)
    return 0;

  return 1;
}
Matthias Clasen's avatar
Matthias Clasen committed
198 199 200 201 202 203 204 205 206 207 208 209 210

/**
 * g_emblemed_icon_add_emblem:
 * @emblemed: a #GEmblemedIcon
 * @emblem: a #GEmblem
 *
 * Adds @emblem to the #GList of #GEmblem <!-- -->s.
 *
 * Since: 2.18
 **/
void 
g_emblemed_icon_add_emblem (GEmblemedIcon *emblemed,
                            GEmblem       *emblem)
211
{
Matthias Clasen's avatar
Matthias Clasen committed
212 213
  g_return_if_fail (G_IS_EMBLEMED_ICON (emblemed));
  g_return_if_fail (G_IS_EMBLEM (emblem));
214

Matthias Clasen's avatar
Matthias Clasen committed
215
  g_object_ref (emblem);
216 217
  emblemed->emblems = g_list_insert_sorted (emblemed->emblems, emblem,
                                            (GCompareFunc) g_emblem_comp);
218 219 220 221 222 223
}

static guint
g_emblemed_icon_hash (GIcon *icon)
{
  GEmblemedIcon *emblemed = G_EMBLEMED_ICON (icon);
Matthias Clasen's avatar
Matthias Clasen committed
224 225
  GList *list;
  guint hash = g_icon_hash (emblemed->icon);
226

Matthias Clasen's avatar
Matthias Clasen committed
227 228
  for (list = emblemed->emblems; list != NULL; list = list->next)
    hash ^= g_icon_hash (G_ICON (list->data));
229 230 231 232 233 234 235 236 237 238

  return hash;
}

static gboolean
g_emblemed_icon_equal (GIcon *icon1,
                       GIcon *icon2)
{
  GEmblemedIcon *emblemed1 = G_EMBLEMED_ICON (icon1);
  GEmblemedIcon *emblemed2 = G_EMBLEMED_ICON (icon2);
Matthias Clasen's avatar
Matthias Clasen committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  GList *list1, *list2;

  if (!g_icon_equal (emblemed1->icon, emblemed2->icon))
    return FALSE;

  list1 = emblemed1->emblems;
  list2 = emblemed2->emblems;

  while (list1 && list2)
  {
    if (!g_icon_equal (G_ICON (list1->data), G_ICON (list2->data)))
        return FALSE;
    
    list1 = list1->next;
    list2 = list2->next;
  }
  
  return list1 == NULL && list2 == NULL;
257 258
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
static gboolean
g_emblemed_icon_to_tokens (GIcon *icon,
                           GPtrArray *tokens,
                           gint  *out_version)
{
  GEmblemedIcon *emblemed_icon = G_EMBLEMED_ICON (icon);
  GList *l;
  char *s;

  /* GEmblemedIcons are encoded as
   *
   *   <encoded_icon> [<encoded_emblem_icon>]*
   */

  g_return_val_if_fail (out_version != NULL, FALSE);

  *out_version = 0;

  s = g_icon_to_string (emblemed_icon->icon);
  if (s == NULL)
    return FALSE;

  g_ptr_array_add (tokens, s);

  for (l = emblemed_icon->emblems; l != NULL; l = l->next)
    {
      GIcon *emblem_icon = G_ICON (l->data);

      s = g_icon_to_string (emblem_icon);
      if (s == NULL)
        return FALSE;
      
      g_ptr_array_add (tokens, s);
    }

  return TRUE;
}

static GIcon *
g_emblemed_icon_from_tokens (gchar  **tokens,
                             gint     num_tokens,
                             gint     version,
                             GError **error)
{
  GEmblemedIcon *emblemed_icon;
  int n;

  emblemed_icon = NULL;

  if (version != 0)
    {
      g_set_error (error,
                   G_IO_ERROR,
                   G_IO_ERROR_INVALID_ARGUMENT,
                   _("Can't handle version %d of GEmblemedIcon encoding"),
                   version);
      goto fail;
    }

  if (num_tokens < 1)
    {
      g_set_error (error,
                   G_IO_ERROR,
                   G_IO_ERROR_INVALID_ARGUMENT,
                   _("Malformed number of tokens (%d) in GEmblemedIcon encoding"),
                   num_tokens);
      goto fail;
    }

  emblemed_icon = g_object_new (G_TYPE_EMBLEMED_ICON, NULL);
  emblemed_icon->icon = g_icon_new_for_string (tokens[0], error);
  if (emblemed_icon->icon == NULL)
    goto fail;

  for (n = 1; n < num_tokens; n++)
    {
      GIcon *emblem;

      emblem = g_icon_new_for_string (tokens[n], error);
      if (emblem == NULL)
        goto fail;

      if (!G_IS_EMBLEM (emblem))
        {
          g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_INVALID_ARGUMENT,
                               _("Expected a GEmblem for GEmblemedIcon"));
          g_object_unref (emblem);
          goto fail;
        }

      emblemed_icon->emblems = g_list_append (emblemed_icon->emblems, emblem);
    }

  return G_ICON (emblemed_icon);

 fail:
  if (emblemed_icon != NULL)
    g_object_unref (emblemed_icon);
  return NULL;
}

362 363 364 365 366
static void
g_emblemed_icon_icon_iface_init (GIconIface *iface)
{
  iface->hash = g_emblemed_icon_hash;
  iface->equal = g_emblemed_icon_equal;
367 368
  iface->to_tokens = g_emblemed_icon_to_tokens;
  iface->from_tokens = g_emblemed_icon_from_tokens;
369
}