1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* caja-icon-info.c
3  * Copyright (C) 2007  Red Hat, Inc.,  Alexander Larsson <alexl@redhat.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include <config.h>
22 #include <string.h>
23 #include "caja-icon-info.h"
24 #include "caja-icon-names.h"
25 #include "caja-default-file-icon.h"
26 #include <gtk/gtk.h>
27 #include <gio/gio.h>
28 
29 struct _CajaIconInfo
30 {
31     GObject parent;
32 
33     gboolean sole_owner;
34     gint64 last_use_time;
35     GdkPixbuf *pixbuf;
36 
37     gboolean got_embedded_rect;
38     GdkRectangle embedded_rect;
39     gint n_attach_points;
40     GdkPoint *attach_points;
41     char *display_name;
42     char *icon_name;
43 
44     gint  orig_scale;
45 };
46 
47 struct _CajaIconInfoClass
48 {
49     GObjectClass parent_class;
50 };
51 
52 static void schedule_reap_cache (void);
53 
54 G_DEFINE_TYPE (CajaIconInfo,
55                caja_icon_info,
56                G_TYPE_OBJECT);
57 
58 static void
caja_icon_info_init(CajaIconInfo * icon)59 caja_icon_info_init (CajaIconInfo *icon)
60 {
61     icon->last_use_time = g_get_monotonic_time ();
62     icon->sole_owner = TRUE;
63 }
64 
65 gboolean
caja_icon_info_is_fallback(CajaIconInfo * icon)66 caja_icon_info_is_fallback (CajaIconInfo  *icon)
67 {
68     return icon->pixbuf == NULL;
69 }
70 
71 static void
pixbuf_toggle_notify(gpointer info,GObject * object,gboolean is_last_ref)72 pixbuf_toggle_notify (gpointer      info,
73                       GObject      *object,
74                       gboolean      is_last_ref)
75 {
76     CajaIconInfo  *icon = info;
77 
78     if (is_last_ref)
79     {
80         icon->sole_owner = TRUE;
81         g_object_remove_toggle_ref (object,
82                                     pixbuf_toggle_notify,
83                                     info);
84         icon->last_use_time = g_get_monotonic_time ();
85         schedule_reap_cache ();
86     }
87 }
88 
89 static void
caja_icon_info_finalize(GObject * object)90 caja_icon_info_finalize (GObject *object)
91 {
92     CajaIconInfo *icon;
93 
94     icon = CAJA_ICON_INFO (object);
95 
96     if (!icon->sole_owner && icon->pixbuf)
97     {
98         g_object_remove_toggle_ref (G_OBJECT (icon->pixbuf),
99                                     pixbuf_toggle_notify,
100                                     icon);
101     }
102 
103     if (icon->pixbuf)
104     {
105         g_object_unref (icon->pixbuf);
106     }
107     g_free (icon->attach_points);
108     g_free (icon->display_name);
109     g_free (icon->icon_name);
110 
111     G_OBJECT_CLASS (caja_icon_info_parent_class)->finalize (object);
112 }
113 
114 static void
caja_icon_info_class_init(CajaIconInfoClass * icon_info_class)115 caja_icon_info_class_init (CajaIconInfoClass *icon_info_class)
116 {
117     GObjectClass *gobject_class;
118 
119     gobject_class = (GObjectClass *) icon_info_class;
120 
121     gobject_class->finalize = caja_icon_info_finalize;
122 
123 }
124 
125 CajaIconInfo *
caja_icon_info_new_for_pixbuf(GdkPixbuf * pixbuf,gint scale)126 caja_icon_info_new_for_pixbuf (GdkPixbuf *pixbuf,
127                                gint       scale)
128 {
129     CajaIconInfo *icon;
130 
131     icon = g_object_new (CAJA_TYPE_ICON_INFO, NULL);
132 
133     if (pixbuf)
134     {
135         icon->pixbuf = g_object_ref (pixbuf);
136     }
137 
138     icon->orig_scale = scale;
139 
140     return icon;
141 }
142 
143 static CajaIconInfo *
caja_icon_info_new_for_icon_info(GtkIconInfo * icon_info,gint scale)144 caja_icon_info_new_for_icon_info (GtkIconInfo *icon_info,
145                                   gint         scale)
146 {
147     CajaIconInfo *icon;
148     GdkPoint *points;
149     gint n_points;
150     const char *filename;
151     char *basename;
152 
153     icon = g_object_new (CAJA_TYPE_ICON_INFO, NULL);
154 
155     icon->pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
156 
157     icon->got_embedded_rect = gtk_icon_info_get_embedded_rect (icon_info,
158                               &icon->embedded_rect);
159 
160     if (gtk_icon_info_get_attach_points (icon_info, &points, &n_points))
161     {
162         icon->n_attach_points = n_points;
163         icon->attach_points = points;
164     }
165 
166     icon->display_name = g_strdup (gtk_icon_info_get_display_name (icon_info));
167 
168     filename = gtk_icon_info_get_filename (icon_info);
169     if (filename != NULL)
170     {
171         char *p;
172 
173         basename = g_path_get_basename (filename);
174         p = strrchr (basename, '.');
175         if (p)
176         {
177             *p = 0;
178         }
179         icon->icon_name = basename;
180     }
181 
182     icon->orig_scale = scale;
183 
184     return icon;
185 }
186 
187 
188 typedef struct
189 {
190     GIcon *icon;
191     int scale;
192     int size;
193 } IconKey;
194 
195 static GHashTable *loadable_icon_cache = NULL;
196 static GHashTable *themed_icon_cache = NULL;
197 static guint reap_cache_timeout = 0;
198 
199 #define MICROSEC_PER_SEC ((guint64)1000000L)
200 
201 static guint time_now;
202 
203 static gboolean
reap_old_icon(gpointer key,gpointer value,gpointer user_info)204 reap_old_icon (gpointer  key,
205                gpointer  value,
206                gpointer  user_info)
207 {
208     CajaIconInfo *icon = value;
209     gboolean *reapable_icons_left = user_info;
210 
211     if (icon->sole_owner)
212     {
213         if (time_now - icon->last_use_time > 30 * MICROSEC_PER_SEC)
214         {
215             /* This went unused 30 secs ago. reap */
216             return TRUE;
217         }
218         else
219         {
220             /* We can reap this soon */
221             *reapable_icons_left = TRUE;
222         }
223     }
224 
225     return FALSE;
226 }
227 
228 static gboolean
reap_cache(gpointer data)229 reap_cache (gpointer data)
230 {
231     gboolean reapable_icons_left;
232 
233     reapable_icons_left = TRUE;
234 
235     time_now = g_get_monotonic_time ();
236 
237     if (loadable_icon_cache)
238     {
239         g_hash_table_foreach_remove (loadable_icon_cache,
240                                      reap_old_icon,
241                                      &reapable_icons_left);
242     }
243 
244     if (themed_icon_cache)
245     {
246         g_hash_table_foreach_remove (themed_icon_cache,
247                                      reap_old_icon,
248                                      &reapable_icons_left);
249     }
250 
251     if (reapable_icons_left)
252     {
253         return TRUE;
254     }
255     else
256     {
257         reap_cache_timeout = 0;
258         return FALSE;
259     }
260 }
261 
262 static void
schedule_reap_cache(void)263 schedule_reap_cache (void)
264 {
265     if (reap_cache_timeout == 0)
266     {
267         reap_cache_timeout = g_timeout_add_seconds_full (0, 5,
268                              reap_cache,
269                              NULL, NULL);
270     }
271 }
272 
273 void
caja_icon_info_clear_caches(void)274 caja_icon_info_clear_caches (void)
275 {
276     if (loadable_icon_cache)
277     {
278         g_hash_table_remove_all (loadable_icon_cache);
279     }
280 
281     if (themed_icon_cache)
282     {
283         g_hash_table_remove_all (themed_icon_cache);
284     }
285 }
286 
287 static guint
icon_key_hash(IconKey * key)288 icon_key_hash (IconKey *key)
289 {
290     return g_icon_hash (key->icon) ^ key->size;
291 }
292 
293 static gboolean
icon_key_equal(const IconKey * a,const IconKey * b)294 icon_key_equal (const IconKey *a,
295                          const IconKey *b)
296 {
297     return a->size == b->size &&
298            a->scale == b->scale &&
299            g_icon_equal (a->icon, b->icon);
300 }
301 
302 static IconKey *
icon_key_new(GIcon * icon,int scale,int size)303 icon_key_new (GIcon *icon,
304               int scale,
305               int    size)
306 {
307     IconKey *key;
308 
309     key = g_slice_new (IconKey);
310     key->icon = g_object_ref (icon);
311     key->size = size;
312 
313     return key;
314 }
315 
316 static void
icon_key_free(IconKey * key)317 icon_key_free (IconKey *key)
318 {
319     g_object_unref (key->icon);
320     g_slice_free (IconKey, key);
321 }
322 
323 CajaIconInfo *
caja_icon_info_lookup(GIcon * icon,int size,int scale)324 caja_icon_info_lookup (GIcon *icon,
325                        int size,
326                        int scale)
327 {
328     GtkIconTheme *icon_theme;
329     GtkIconInfo *gtkicon_info;
330 
331     CajaIconInfo *icon_info;
332 
333     icon_theme = gtk_icon_theme_get_default ();
334 
335     if (G_IS_LOADABLE_ICON (icon)) {
336         GdkPixbuf *pixbuf;
337         IconKey lookup_key;
338         IconKey *key;
339         GInputStream *stream;
340 
341         if (loadable_icon_cache == NULL) {
342             loadable_icon_cache = g_hash_table_new_full ((GHashFunc) icon_key_hash,
343                                                          (GEqualFunc) icon_key_equal,
344                                                          (GDestroyNotify) icon_key_free,
345                                                          (GDestroyNotify) g_object_unref);
346         }
347 
348         lookup_key.icon = icon;
349         lookup_key.scale = scale;
350         lookup_key.size = size * scale;
351 
352         icon_info = g_hash_table_lookup (loadable_icon_cache, &lookup_key);
353         if (icon_info)
354         {
355             return g_object_ref (icon_info);
356         }
357 
358         pixbuf = NULL;
359         stream = g_loadable_icon_load (G_LOADABLE_ICON (icon),
360                                        size * scale,
361                                        NULL, NULL, NULL);
362         if (stream)
363         {
364             pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
365                                                           size * scale, size * scale,
366                                                           TRUE,
367                                                           NULL, NULL);
368             g_input_stream_close (stream, NULL, NULL);
369             g_object_unref (stream);
370         }
371 
372         if (!pixbuf) {
373             gtkicon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme,
374                                                                  "text-x-generic",
375                                                                  size,
376                                                                  scale,
377                                                                  GTK_ICON_LOOKUP_FORCE_SIZE);
378             pixbuf = gtk_icon_info_load_icon (gtkicon_info, NULL);
379         }
380 
381 
382         icon_info = caja_icon_info_new_for_pixbuf (pixbuf, scale);
383 
384         key = icon_key_new (icon, scale, size);
385         g_hash_table_insert (loadable_icon_cache, key, icon_info);
386         g_clear_object (&pixbuf);
387 
388         return g_object_ref (icon_info);
389     }   else  {
390         IconKey lookup_key;
391         IconKey *key;
392         if (themed_icon_cache == NULL) {
393             themed_icon_cache = g_hash_table_new_full ((GHashFunc) icon_key_hash,
394                                                        (GEqualFunc) icon_key_equal,
395                                                        (GDestroyNotify) icon_key_free,
396                                                        (GDestroyNotify) g_object_unref);
397         }
398         lookup_key.icon = icon;
399         lookup_key.scale = scale;
400         lookup_key.size = size;
401 
402         icon_info = g_hash_table_lookup (themed_icon_cache, &lookup_key);
403         if (icon_info) {
404             return g_object_ref (icon_info);
405         }
406 
407         gtkicon_info = NULL;
408 
409         gtkicon_info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme,
410                                                                  icon,
411                                                                  size,
412                                                                  scale,
413                                                                  GTK_ICON_LOOKUP_FORCE_SIZE);
414 
415         if (!gtkicon_info) {
416             gtkicon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme,
417                                                                  "text-x-generic",
418                                                                  size,
419                                                                  scale,
420                                                                  GTK_ICON_LOOKUP_FORCE_SIZE);
421         }
422 
423         icon_info = caja_icon_info_new_for_icon_info (gtkicon_info, scale);
424         g_object_unref (gtkicon_info);
425 
426         key = icon_key_new (icon,scale, size);
427         g_hash_table_insert (themed_icon_cache, key, icon_info);
428 
429         return g_object_ref (icon_info);
430     }
431 
432 }
433 
434 CajaIconInfo *
caja_icon_info_lookup_from_name(const char * name,int size,int scale)435 caja_icon_info_lookup_from_name (const char *name,
436                                  int size,
437                                  int scale)
438 {
439     GIcon *icon;
440     CajaIconInfo *info;
441 
442     icon = g_themed_icon_new (name);
443     info = caja_icon_info_lookup (icon, size, scale);
444     g_object_unref (icon);
445     return info;
446 }
447 
448 CajaIconInfo *
caja_icon_info_lookup_from_path(const char * path,int size,int scale)449 caja_icon_info_lookup_from_path (const char *path,
450                                  int size,
451                                  int scale)
452 {
453     GFile *icon_file;
454     GIcon *icon;
455     CajaIconInfo *info;
456 
457     icon_file = g_file_new_for_path (path);
458     icon = g_file_icon_new (icon_file);
459     info = caja_icon_info_lookup (icon, size, scale);
460     g_object_unref (icon);
461     g_object_unref (icon_file);
462     return info;
463 }
464 
465 GdkPixbuf *
caja_icon_info_get_pixbuf_nodefault(CajaIconInfo * icon)466 caja_icon_info_get_pixbuf_nodefault (CajaIconInfo  *icon)
467 {
468     GdkPixbuf *res;
469 
470     if (icon->pixbuf == NULL)
471     {
472         res = NULL;
473     }
474     else
475     {
476         res = g_object_ref (icon->pixbuf);
477 
478         if (icon->sole_owner)
479         {
480             icon->sole_owner = FALSE;
481             g_object_add_toggle_ref (G_OBJECT (res),
482                                      pixbuf_toggle_notify,
483                                      icon);
484         }
485     }
486 
487     return res;
488 }
489 
490 cairo_surface_t *
caja_icon_info_get_surface_nodefault(CajaIconInfo * icon)491 caja_icon_info_get_surface_nodefault (CajaIconInfo *icon)
492 {
493     GdkPixbuf *pixbuf;
494     cairo_surface_t *surface;
495 
496     pixbuf = caja_icon_info_get_pixbuf_nodefault (icon);
497     surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, icon->orig_scale, NULL);
498     g_object_unref (pixbuf);
499 
500     return surface;
501 }
502 
503 GdkPixbuf *
caja_icon_info_get_pixbuf(CajaIconInfo * icon)504 caja_icon_info_get_pixbuf (CajaIconInfo *icon)
505 {
506     GdkPixbuf *res;
507 
508     res = caja_icon_info_get_pixbuf_nodefault (icon);
509     if (res == NULL)
510     {
511         res = gdk_pixbuf_new_from_data (caja_default_file_icon,
512                                         GDK_COLORSPACE_RGB,
513                                         TRUE,
514                                         8,
515                                         caja_default_file_icon_width,
516                                         caja_default_file_icon_height,
517                                         caja_default_file_icon_width * 4, /* stride */
518                                         NULL, /* don't destroy info */
519                                         NULL);
520     }
521 
522     return res;
523 }
524 
525 cairo_surface_t *
caja_icon_info_get_surface(CajaIconInfo * icon)526 caja_icon_info_get_surface (CajaIconInfo *icon)
527 {
528     GdkPixbuf *pixbuf;
529     cairo_surface_t *surface;
530 
531     pixbuf = caja_icon_info_get_pixbuf (icon);
532     surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, icon->orig_scale, NULL);
533     g_object_unref (pixbuf);
534 
535     return surface;
536 }
537 
538 GdkPixbuf *
caja_icon_info_get_pixbuf_nodefault_at_size(CajaIconInfo * icon,gsize forced_size)539 caja_icon_info_get_pixbuf_nodefault_at_size (CajaIconInfo  *icon,
540         gsize              forced_size)
541 {
542     GdkPixbuf *pixbuf, *scaled_pixbuf;
543     int w, h, s;
544     double scale;
545 
546     pixbuf = caja_icon_info_get_pixbuf_nodefault (icon);
547 
548     if (pixbuf == NULL)
549         return NULL;
550 
551     w = gdk_pixbuf_get_width (pixbuf) / icon->orig_scale;
552     h = gdk_pixbuf_get_height (pixbuf) / icon->orig_scale;
553     s = MAX (w, h);
554     if (s == forced_size)
555     {
556         return pixbuf;
557     }
558 
559     scale = (double)forced_size / s;
560     scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
561                     w * scale, h * scale,
562                     GDK_INTERP_BILINEAR);
563     g_object_unref (pixbuf);
564     return scaled_pixbuf;
565 }
566 
567 cairo_surface_t *
caja_icon_info_get_surface_nodefault_at_size(CajaIconInfo * icon,gsize forced_size)568 caja_icon_info_get_surface_nodefault_at_size (CajaIconInfo *icon,
569                                               gsize         forced_size)
570 {
571     GdkPixbuf *pixbuf;
572     cairo_surface_t *surface;
573 
574     pixbuf = caja_icon_info_get_pixbuf_nodefault_at_size (icon, forced_size);
575     /*catch the case of caja_icon_info_get_pixbuf_nodefault_at_size returning NULL */
576     if (!pixbuf)
577         return NULL;
578     surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, icon->orig_scale, NULL);
579     g_object_unref (pixbuf);
580 
581     return surface;
582 }
583 
584 GdkPixbuf *
caja_icon_info_get_pixbuf_at_size(CajaIconInfo * icon,gsize forced_size)585 caja_icon_info_get_pixbuf_at_size (CajaIconInfo  *icon,
586                                    gsize              forced_size)
587 {
588     GdkPixbuf *pixbuf, *scaled_pixbuf;
589     int w, h, s;
590     double scale;
591 
592     pixbuf = caja_icon_info_get_pixbuf (icon);
593 
594     if (pixbuf == NULL)
595         return NULL;
596 
597     w = gdk_pixbuf_get_width (pixbuf) / icon->orig_scale;
598     h = gdk_pixbuf_get_height (pixbuf) / icon->orig_scale;
599     s = MAX (w, h);
600     if (s == forced_size)
601     {
602         return pixbuf;
603     }
604 
605     scale = (double)forced_size / s;
606     scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
607                     w * scale, h * scale,
608                     GDK_INTERP_BILINEAR);
609     g_object_unref (pixbuf);
610     return scaled_pixbuf;
611 }
612 
613 cairo_surface_t *
caja_icon_info_get_surface_at_size(CajaIconInfo * icon,gsize forced_size)614 caja_icon_info_get_surface_at_size (CajaIconInfo *icon,
615                                     gsize         forced_size)
616 {
617     GdkPixbuf *pixbuf;
618     cairo_surface_t *surface;
619 
620     pixbuf = caja_icon_info_get_pixbuf_at_size (icon, forced_size);
621     surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, icon->orig_scale, NULL);
622     g_object_unref (pixbuf);
623 
624     return surface;
625 }
626 
627 gboolean
caja_icon_info_get_embedded_rect(CajaIconInfo * icon,GdkRectangle * rectangle)628 caja_icon_info_get_embedded_rect (CajaIconInfo  *icon,
629                                   GdkRectangle      *rectangle)
630 {
631     *rectangle = icon->embedded_rect;
632     return icon->got_embedded_rect;
633 }
634 
635 gboolean
caja_icon_info_get_attach_points(CajaIconInfo * icon,GdkPoint ** points,gint * n_points)636 caja_icon_info_get_attach_points (CajaIconInfo  *icon,
637                                   GdkPoint         **points,
638                                   gint              *n_points)
639 {
640     *n_points = icon->n_attach_points;
641     *points = icon->attach_points;
642     return icon->n_attach_points != 0;
643 }
644 
caja_icon_info_get_display_name(CajaIconInfo * icon)645 const char* caja_icon_info_get_display_name(CajaIconInfo* icon)
646 {
647     return icon->display_name;
648 }
649 
caja_icon_info_get_used_name(CajaIconInfo * icon)650 const char* caja_icon_info_get_used_name(CajaIconInfo* icon)
651 {
652     return icon->icon_name;
653 }
654 
655 /* Return nominal icon size for given zoom level.
656  * @zoom_level: zoom level for which to find matching icon size.
657  *
658  * Return value: icon size between CAJA_ICON_SIZE_SMALLEST and
659  * CAJA_ICON_SIZE_LARGEST, inclusive.
660  */
661 guint
caja_get_icon_size_for_zoom_level(CajaZoomLevel zoom_level)662 caja_get_icon_size_for_zoom_level (CajaZoomLevel zoom_level)
663 {
664     switch (zoom_level)
665     {
666     case CAJA_ZOOM_LEVEL_SMALLEST:
667         return CAJA_ICON_SIZE_SMALLEST;
668     case CAJA_ZOOM_LEVEL_SMALLER:
669         return CAJA_ICON_SIZE_SMALLER;
670     case CAJA_ZOOM_LEVEL_SMALL:
671         return CAJA_ICON_SIZE_SMALL;
672     case CAJA_ZOOM_LEVEL_STANDARD:
673         return CAJA_ICON_SIZE_STANDARD;
674     case CAJA_ZOOM_LEVEL_LARGE:
675         return CAJA_ICON_SIZE_LARGE;
676     case CAJA_ZOOM_LEVEL_LARGER:
677         return CAJA_ICON_SIZE_LARGER;
678     case CAJA_ZOOM_LEVEL_LARGEST:
679         return CAJA_ICON_SIZE_LARGEST;
680     }
681     g_return_val_if_reached (CAJA_ICON_SIZE_STANDARD);
682 }
683 
684 float
caja_get_relative_icon_size_for_zoom_level(CajaZoomLevel zoom_level)685 caja_get_relative_icon_size_for_zoom_level (CajaZoomLevel zoom_level)
686 {
687     return (float)caja_get_icon_size_for_zoom_level (zoom_level) / CAJA_ICON_SIZE_STANDARD;
688 }
689 
690 guint
caja_icon_get_larger_icon_size(guint size)691 caja_icon_get_larger_icon_size (guint size)
692 {
693     if (size < CAJA_ICON_SIZE_SMALLEST)
694     {
695         return CAJA_ICON_SIZE_SMALLEST;
696     }
697     if (size < CAJA_ICON_SIZE_SMALLER)
698     {
699         return CAJA_ICON_SIZE_SMALLER;
700     }
701     if (size < CAJA_ICON_SIZE_SMALL)
702     {
703         return CAJA_ICON_SIZE_SMALL;
704     }
705     if (size < CAJA_ICON_SIZE_STANDARD)
706     {
707         return CAJA_ICON_SIZE_STANDARD;
708     }
709     if (size < CAJA_ICON_SIZE_LARGE)
710     {
711         return CAJA_ICON_SIZE_LARGE;
712     }
713     if (size < CAJA_ICON_SIZE_LARGER)
714     {
715         return CAJA_ICON_SIZE_LARGER;
716     }
717     return CAJA_ICON_SIZE_LARGEST;
718 }
719 
720 guint
caja_icon_get_smaller_icon_size(guint size)721 caja_icon_get_smaller_icon_size (guint size)
722 {
723     if (size > CAJA_ICON_SIZE_LARGEST)
724     {
725         return CAJA_ICON_SIZE_LARGEST;
726     }
727     if (size > CAJA_ICON_SIZE_LARGER)
728     {
729         return CAJA_ICON_SIZE_LARGER;
730     }
731     if (size > CAJA_ICON_SIZE_LARGE)
732     {
733         return CAJA_ICON_SIZE_LARGE;
734     }
735     if (size > CAJA_ICON_SIZE_STANDARD)
736     {
737         return CAJA_ICON_SIZE_STANDARD;
738     }
739     if (size > CAJA_ICON_SIZE_SMALL)
740     {
741         return CAJA_ICON_SIZE_SMALL;
742     }
743     if (size > CAJA_ICON_SIZE_SMALLER)
744     {
745         return CAJA_ICON_SIZE_SMALLER;
746     }
747     return CAJA_ICON_SIZE_SMALLEST;
748 }
749 
750 gint
caja_get_icon_size_for_stock_size(GtkIconSize size)751 caja_get_icon_size_for_stock_size (GtkIconSize size)
752 {
753     gint w, h;
754 
755     if (gtk_icon_size_lookup (size, &w, &h))
756     {
757         return MAX (w, h);
758     }
759     return CAJA_ZOOM_LEVEL_STANDARD;
760 }
761 
762 
763 guint
caja_icon_get_emblem_size_for_icon_size(guint size)764 caja_icon_get_emblem_size_for_icon_size (guint size)
765 {
766     if (size >= 96)
767         return 48;
768     if (size >= 64)
769         return 32;
770     if (size >= 48)
771         return 24;
772     if (size >= 24)
773         return 16;
774     if (size >= 16)
775         return 12;
776 
777     return 0; /* no emblems for smaller sizes */
778 }
779 
780 gboolean
caja_icon_theme_can_render(GThemedIcon * icon)781 caja_icon_theme_can_render (GThemedIcon *icon)
782 {
783 	GtkIconTheme *icon_theme;
784 	const gchar * const *names;
785 	gint idx;
786 
787 	names = g_themed_icon_get_names (icon);
788 
789 	icon_theme = gtk_icon_theme_get_default ();
790 
791 	for (idx = 0; names[idx] != NULL; idx++) {
792 		if (gtk_icon_theme_has_icon (icon_theme, names[idx])) {
793 			return TRUE;
794 		}
795 	}
796 
797 	return FALSE;
798 }
799 
800 GIcon *
caja_user_special_directory_get_gicon(GUserDirectory directory)801 caja_user_special_directory_get_gicon (GUserDirectory directory)
802 {
803 
804 	#define ICON_CASE(x) \
805 		case G_USER_DIRECTORY_ ## x:\
806 			return g_themed_icon_new (CAJA_ICON_FOLDER_ ## x);
807 
808 	switch (directory) {
809 
810 		ICON_CASE (DESKTOP);
811 		ICON_CASE (DOCUMENTS);
812 		ICON_CASE (DOWNLOAD);
813 		ICON_CASE (MUSIC);
814 		ICON_CASE (PICTURES);
815 		ICON_CASE (PUBLIC_SHARE);
816 		ICON_CASE (TEMPLATES);
817 		ICON_CASE (VIDEOS);
818 
819 	default:
820 		return g_themed_icon_new ("folder");
821 	}
822 
823 	#undef ICON_CASE
824 }
825