1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <Ecore.h>
6 #include <Ecore_File.h>
7 
8 /* define macros and variable for using the eina logging system  */
9 #define EFREET_MODULE_LOG_DOM _efreet_icon_log_dom
10 static int _efreet_icon_log_dom = -1;
11 
12 #include "Efreet.h"
13 #include "efreet_private.h"
14 
15 static const char *efreet_icon_deprecated_user_dir = NULL;
16 static const char *efreet_icon_user_dir = NULL;
17 static Eina_List *efreet_icon_extensions = NULL;
18 static Eina_List *efreet_extra_icon_dirs = NULL;
19 
20 typedef struct Efreet_Icon_Cache Efreet_Icon_Cache;
21 struct Efreet_Icon_Cache
22 {
23     const char *key;
24     const char *path;
25     time_t lasttime;
26 };
27 
28 #ifdef SLOPPY_SPEC
29 static char *efreet_icon_remove_extension(const char *icon);
30 #endif
31 
32 static Efreet_Icon *efreet_icon_new(const char *path);
33 static void efreet_icon_populate(Efreet_Icon *icon, const char *file);
34 
35 static const char *efreet_icon_lookup_icon(Efreet_Cache_Icon *icon, unsigned int size);
36 static const char *efreet_icon_list_lookup_icon(Efreet_Icon_Theme *theme, Eina_List *icons, unsigned int size);
37 static int efreet_icon_size_match(Efreet_Cache_Icon_Element *elem, unsigned int size);
38 static double efreet_icon_size_distance(Efreet_Cache_Icon_Element *elem, unsigned int size);
39 static const char *efreet_icon_lookup_path(Efreet_Cache_Icon_Element *elem);
40 static const char *efreet_icon_lookup_path_path(Efreet_Cache_Icon_Element *elem, const char *path);
41 static const char *efreet_icon_fallback_lookup_path(Efreet_Cache_Fallback_Icon *icon);
42 static const char *efreet_icon_fallback_lookup_path_path(Efreet_Cache_Fallback_Icon *icon,
43                                                                const char *path);
44 static void efreet_cache_icon_dirs_add_cb(void *data);
45 
46 /**
47  * @internal
48  * @return Returns 1 on success or 0 on failure
49  * @brief Initializes the icon system
50  */
51 int
efreet_icon_init(void)52 efreet_icon_init(void)
53 {
54     const char *default_exts[] = {".png", ".xpm", ".svg", NULL};
55     int i;
56 
57     _efreet_icon_log_dom = eina_log_domain_register
58         ("efreet_icon", EFREET_DEFAULT_LOG_COLOR);
59     if (_efreet_icon_log_dom < 0)
60         return 0;
61 
62     /* setup the default extension list */
63     for (i = 0; default_exts[i]; i++)
64         efreet_icon_extensions = eina_list_append(efreet_icon_extensions, eina_stringshare_add(default_exts[i]));
65 
66     efreet_extra_icon_dirs = NULL;
67     efreet_icon_extensions_refresh();
68 
69     return 1;
70 }
71 
72 /**
73  * @internal
74  * @return Returns no value
75  * @brief Shuts down the icon system
76  */
77 void
efreet_icon_shutdown(void)78 efreet_icon_shutdown(void)
79 {
80     IF_RELEASE(efreet_icon_user_dir);
81     IF_RELEASE(efreet_icon_deprecated_user_dir);
82 
83     IF_FREE_LIST(efreet_icon_extensions, eina_stringshare_del);
84     efreet_extra_icon_dirs = eina_list_free(efreet_extra_icon_dirs);
85 
86     eina_log_domain_unregister(_efreet_icon_log_dom);
87     _efreet_icon_log_dom = -1;
88 }
89 
90 void
efreet_icon_extensions_refresh(void)91 efreet_icon_extensions_refresh(void)
92 {
93    efreet_cache_icon_exts_add(efreet_icon_extensions);
94 }
95 
96 EAPI const char *
efreet_icon_deprecated_user_dir_get(void)97 efreet_icon_deprecated_user_dir_get(void)
98 {
99     const char *user;
100     char *tmp;
101     int len;
102 
103     if (efreet_icon_deprecated_user_dir) return efreet_icon_deprecated_user_dir;
104 
105     user = efreet_home_dir_get();
106     len = strlen(user) + strlen("/.icons") + 1;
107     tmp = alloca(len);
108     snprintf(tmp, len, "%s/.icons", user);
109 
110     tmp = eina_file_path_sanitize(tmp);
111     efreet_icon_deprecated_user_dir = eina_stringshare_add_length(tmp, len - 1);
112     free(tmp);
113 
114     return efreet_icon_deprecated_user_dir;
115 }
116 
117 EAPI const char *
efreet_icon_user_dir_get(void)118 efreet_icon_user_dir_get(void)
119 {
120     const char *user;
121     char *tmp;
122     int len;
123 
124     if (efreet_icon_user_dir) return efreet_icon_user_dir;
125 
126     user = efreet_data_home_get();
127     len = strlen(user) + strlen("/icons") + 1;
128     tmp = alloca(len);
129     snprintf(tmp, len, "%s/icons", user);
130 
131     tmp = eina_file_path_sanitize(tmp);
132     efreet_icon_user_dir = eina_stringshare_add_length(tmp, len - 1);
133     free(tmp);
134 
135     return efreet_icon_user_dir;
136 }
137 
138 EAPI void
efreet_icon_extension_add(const char * ext)139 efreet_icon_extension_add(const char *ext)
140 {
141     Eina_List *l;
142 
143     EINA_SAFETY_ON_NULL_RETURN(ext);
144 
145     ext = eina_stringshare_add(ext);
146 
147     if ((l = eina_list_data_find_list(efreet_icon_extensions, ext)))
148     {
149         efreet_icon_extensions = eina_list_promote_list(efreet_icon_extensions, l);
150         eina_stringshare_del(ext);
151     }
152     else
153         efreet_icon_extensions = eina_list_prepend(efreet_icon_extensions, ext);
154     efreet_icon_extensions_refresh();
155 }
156 
157 EAPI Eina_List **
efreet_icon_extra_list_get(void)158 efreet_icon_extra_list_get(void)
159 {
160     ecore_job_add(efreet_cache_icon_dirs_add_cb, NULL);
161     return &efreet_extra_icon_dirs;
162 }
163 
164 EAPI Eina_List *
efreet_icon_extensions_list_get(void)165 efreet_icon_extensions_list_get(void)
166 {
167     return efreet_icon_extensions;
168 }
169 
170 EAPI Eina_List *
efreet_icon_theme_list_get(void)171 efreet_icon_theme_list_get(void)
172 {
173     return efreet_cache_icon_theme_list();
174 }
175 
176 EAPI Efreet_Icon_Theme *
efreet_icon_theme_find(const char * theme_name)177 efreet_icon_theme_find(const char *theme_name)
178 {
179     if (!theme_name) return NULL;
180 
181     return efreet_cache_icon_theme_find(theme_name);
182 }
183 
184 #ifdef SLOPPY_SPEC
185 /**
186  * @internal
187  * @param icon The icon name to strip extension
188  * @return Extension removed if in list of extensions, else untouched.
189  * @brief Removes extension from icon name if in list of extensions.
190  */
191 static char *
efreet_icon_remove_extension(const char * icon)192 efreet_icon_remove_extension(const char *icon)
193 {
194     Eina_List *l;
195     char *tmp = NULL, *ext = NULL;
196 
197     if (!icon) return NULL;
198 
199     tmp = strdup(icon);
200     ext = strrchr(tmp, '.');
201     if (ext)
202     {
203         const char *ext2;
204         EINA_LIST_FOREACH(efreet_icon_extensions, l, ext2)
205         {
206             if (!strcmp(ext, ext2))
207             {
208 #ifdef STRICT_SPEC
209                 WRN("Requesting an icon with an extension: %s",
210                     icon);
211 #endif
212                 *ext = '\0';
213                 break;
214             }
215         }
216     }
217 
218     return tmp;
219 }
220 #endif
221 
222 EAPI const char *
efreet_icon_path_find(const char * theme_name,const char * icon,unsigned int size)223 efreet_icon_path_find(const char *theme_name, const char *icon, unsigned int size)
224 {
225 #ifdef SLOPPY_SPEC
226     char *tmp;
227 #else
228     const char *tmp;
229 #endif
230     const char *value = NULL;
231     Efreet_Icon_Theme *theme;
232 
233     EINA_SAFETY_ON_NULL_RETURN_VAL(icon, NULL);
234 
235     theme = efreet_icon_theme_find(theme_name);
236 
237 #ifdef SLOPPY_SPEC
238     tmp = efreet_icon_remove_extension(icon);
239     if (!tmp) return NULL;
240 #else
241     tmp = icon;
242 #endif
243 
244     if (theme)
245     {
246         Efreet_Cache_Icon *cache;
247         cache = efreet_cache_icon_find(theme, tmp);
248         value = efreet_icon_lookup_icon(cache, size);
249         if (!value) INF("lookup for '%s' failed in theme '%s' with %p.", icon, theme_name, cache);
250     }
251 
252     /* we didn't find the icon in the theme or in the inherited directories
253      * then just look for a non theme icon
254      */
255     if (!value)
256     {
257         Efreet_Cache_Fallback_Icon *cache;
258 
259         cache = efreet_cache_icon_fallback_find(tmp);
260         value = efreet_icon_fallback_lookup_path(cache);
261         if (!value) INF("lookup for '%s' failed in fallback too with %p.", icon, cache);
262     }
263 
264 #ifdef SLOPPY_SPEC
265     FREE(tmp);
266 #endif
267     return value;
268 }
269 
270 EAPI const char *
efreet_icon_list_find(const char * theme_name,Eina_List * icons,unsigned int size)271 efreet_icon_list_find(const char *theme_name, Eina_List *icons,
272                       unsigned int size)
273 {
274     Eina_List *l;
275     Eina_List *tmps = NULL;
276     const char *icon = NULL;
277     const char *value = NULL;
278 #ifdef SLOPPY_SPEC
279     char *data;
280 #endif
281     Efreet_Icon_Theme *theme;
282 
283     EINA_SAFETY_ON_NULL_RETURN_VAL(icons, NULL);
284 
285     theme = efreet_icon_theme_find(theme_name);
286 
287 #ifdef SLOPPY_SPEC
288     EINA_LIST_FOREACH(icons, l, icon)
289     {
290         data = efreet_icon_remove_extension(icon);
291         if (!data) return NULL;
292         tmps = eina_list_append(tmps, data);
293     }
294 #else
295     tmps = icons;
296 #endif
297 
298     if (theme)
299     {
300         Eina_List *tmps2 = NULL;
301         Efreet_Cache_Icon *cache;
302 
303         EINA_LIST_FOREACH(tmps, l, icon)
304         {
305             cache = efreet_cache_icon_find(theme, icon);
306             if (cache)
307             {
308                 /* If the icon is in the asked for theme, return it */
309                 if (!strcmp(cache->theme, theme->name.internal))
310                 {
311                     value = efreet_icon_lookup_icon(cache, size);
312                     break;
313                 }
314                 else
315                     tmps2 = eina_list_append(tmps2, cache);
316             }
317         }
318         if (tmps2)
319         {
320             if (!value)
321                 value = efreet_icon_list_lookup_icon(theme, tmps2, size);
322             eina_list_free(tmps2);
323         }
324     }
325 
326     /* we didn't find the icons in the theme or in the inherited directories
327      * then just look for a non theme icon
328      */
329     if (!value)
330     {
331         Efreet_Cache_Fallback_Icon *cache;
332         EINA_LIST_FOREACH(tmps, l, icon)
333         {
334             cache = efreet_cache_icon_fallback_find(icon);
335             value = efreet_icon_fallback_lookup_path(cache);
336             if (value)
337                 break;
338         }
339     }
340 
341 #ifdef SLOPPY_SPEC
342     EINA_LIST_FREE(tmps, data)
343         free(data);
344 #endif
345 
346     return value;
347 }
348 
349 EAPI Efreet_Icon *
efreet_icon_find(const char * theme_name,const char * icon,unsigned int size)350 efreet_icon_find(const char *theme_name, const char *icon, unsigned int size)
351 {
352     const char *path;
353 
354     EINA_SAFETY_ON_NULL_RETURN_VAL(icon, NULL);
355 
356     path = efreet_icon_path_find(theme_name, icon, size);
357     if (path)
358     {
359         Efreet_Icon *ic;
360 
361         ic = efreet_icon_new(path);
362         return ic;
363     }
364 
365     return NULL;
366 }
367 
368 /**
369  * @internal
370  * @return Returns a new Efreet_Icon struct on success or NULL on failure
371  * @brief Creates a new Efreet_Icon struct
372  */
373 static Efreet_Icon *
efreet_icon_new(const char * path)374 efreet_icon_new(const char *path)
375 {
376     Efreet_Icon *icon;
377     char *p;
378 
379     icon = NEW(Efreet_Icon, 1);
380     if (!icon) return NULL;
381     icon->path = eina_stringshare_add(path);
382 
383     /* load the .icon file if it's available */
384     p = strrchr(icon->path, '.');
385     if (p)
386     {
387         char ico_path[PATH_MAX];
388 
389         *p = '\0';
390 
391         snprintf(ico_path, sizeof(ico_path), "%s.icon", icon->path);
392         *p = '.';
393 
394         efreet_icon_populate(icon, ico_path);
395     }
396 
397     if (!icon->name)
398     {
399         const char *file;
400 
401         file = ecore_file_file_get(icon->path);
402         p = strrchr(icon->path, '.');
403         if (p) *p = '\0';
404         icon->name = eina_stringshare_add(file);
405         if (p) *p = '.';
406     }
407 
408     return icon;
409 }
410 
411 EAPI void
efreet_icon_free(Efreet_Icon * icon)412 efreet_icon_free(Efreet_Icon *icon)
413 {
414     if (!icon) return;
415 
416     icon->ref_count --;
417     if (icon->ref_count > 0) return;
418 
419     IF_RELEASE(icon->path);
420     IF_RELEASE(icon->name);
421     IF_FREE_LIST(icon->attach_points, free);
422 
423     FREE(icon);
424 }
425 
426 /**
427  * @internal
428  * @param icon The icon to populate
429  * @param file The file to populate from
430  * @return Returns no value
431  * @brief Tries to populate the icon information from the given file
432  */
433 static void
efreet_icon_populate(Efreet_Icon * icon,const char * file)434 efreet_icon_populate(Efreet_Icon *icon, const char *file)
435 {
436     Efreet_Ini *ini;
437     const char *tmp;
438 
439     ini = efreet_ini_new(file);
440     if (!ini) return;
441     if (!ini->data)
442     {
443         efreet_ini_free(ini);
444         return;
445     }
446 
447     efreet_ini_section_set(ini, "Icon Data");
448     tmp = efreet_ini_localestring_get(ini, "DisplayName");
449     if (tmp) icon->name = eina_stringshare_add(tmp);
450 
451     tmp = efreet_ini_string_get(ini, "EmbeddedTextRectangle");
452     if (tmp)
453     {
454         int points[4];
455         char *t, *s, *p;
456         int i;
457         size_t len;
458 
459         len = strlen(tmp) + 1;
460         t = alloca(len);
461         memcpy(t, tmp, len);
462         s = t;
463         for (i = 0; i < 4; i++)
464         {
465             if (s)
466             {
467                 p = strchr(s, ',');
468 
469                 if (p) *p = '\0';
470                 points[i] = atoi(s);
471 
472                 if (p) s = ++p;
473                 else s = NULL;
474             }
475             else
476             {
477                 points[i] = 0;
478             }
479         }
480 
481         icon->has_embedded_text_rectangle = 1;
482         icon->embedded_text_rectangle.x0 = points[0];
483         icon->embedded_text_rectangle.y0 = points[1];
484         icon->embedded_text_rectangle.x1 = points[2];
485         icon->embedded_text_rectangle.y1 = points[3];
486     }
487 
488     tmp = efreet_ini_string_get(ini, "AttachPoints");
489     if (tmp)
490     {
491         char *t, *s, *p;
492         size_t len;
493 
494         len = strlen(tmp) + 1;
495         t = alloca(len);
496         memcpy(t, tmp, len);
497         s = t;
498         while (s)
499         {
500             Efreet_Icon_Point *point;
501 
502             p = strchr(s, ',');
503             /* If this happens there is something wrong with the .icon file */
504             if (!p) break;
505 
506             point = NEW(Efreet_Icon_Point, 1);
507             if (!point) goto error;
508 
509             *p = '\0';
510             point->x = atoi(s);
511 
512             s = ++p;
513             p = strchr(s, '|');
514             if (p) *p = '\0';
515 
516             point->y = atoi(s);
517 
518             icon->attach_points = eina_list_append(icon->attach_points, point);
519 
520             if (p) s = ++p;
521             else s = NULL;
522         }
523     }
524 
525 error:
526     efreet_ini_free(ini);
527 }
528 
529 static const char *
efreet_icon_lookup_icon(Efreet_Cache_Icon * icon,unsigned int size)530 efreet_icon_lookup_icon(Efreet_Cache_Icon *icon, unsigned int size)
531 {
532     const char *path = NULL;
533     double minimal_distance = INT_MAX;
534     unsigned int ret_size = 0;
535     unsigned int i;
536 
537     if (!icon) return NULL;
538 
539     /* search for allowed size == requested size */
540     for (i = 0; i < icon->icons_count; ++i)
541     {
542         if (!efreet_icon_size_match(icon->icons[i], size)) continue;
543         path = efreet_icon_lookup_path(icon->icons[i]);
544         if (path) return path;
545     }
546 
547     /* search for any icon that matches */
548     for (i = 0; i < icon->icons_count; ++i)
549     {
550         const char *tmp = NULL;
551         double distance;
552 
553         distance = efreet_icon_size_distance(icon->icons[i], size);
554         if (distance > minimal_distance) continue;
555         // prefer downsizing
556         if ((EINA_DBL_EQ(distance, minimal_distance)) &&
557             (icon->icons[i]->normal < ret_size))
558          continue;
559 
560         tmp = efreet_icon_lookup_path(icon->icons[i]);
561 
562         if (tmp)
563         {
564             path = tmp;
565             minimal_distance = distance;
566             ret_size = icon->icons[i]->normal;
567         }
568     }
569 
570     return path;
571 }
572 
573 static const char *
efreet_icon_list_lookup_icon(Efreet_Icon_Theme * theme,Eina_List * icons,unsigned int size)574 efreet_icon_list_lookup_icon(Efreet_Icon_Theme *theme, Eina_List *icons, unsigned int size)
575 {
576     const char *value = NULL;
577     Efreet_Cache_Icon *cache;
578     Eina_List *l;
579 
580     EINA_LIST_FOREACH(icons, l, cache)
581     {
582         if (!strcmp(cache->theme, theme->name.internal))
583         {
584             value = efreet_icon_lookup_icon(cache, size);
585             if (value) break;
586         }
587     }
588     if (value) return value;
589     if (theme->inherits)
590     {
591         const char *parent;
592         EINA_LIST_FOREACH(theme->inherits, l, parent)
593         {
594             Efreet_Icon_Theme *parent_theme;
595 
596             parent_theme = efreet_icon_theme_find(parent);
597             if ((!parent_theme) || (parent_theme == theme)) continue;
598 
599             value = efreet_icon_list_lookup_icon(parent_theme, icons, size);
600             if (value) break;
601         }
602     }
603     /* if this isn't the hicolor theme, and we have no other fallbacks
604      * check hicolor */
605     else if (strcmp(theme->name.internal, "hicolor"))
606     {
607         Efreet_Icon_Theme *parent_theme;
608 
609         parent_theme = efreet_icon_theme_find("hicolor");
610         if (parent_theme)
611             value = efreet_icon_list_lookup_icon(parent_theme, icons, size);
612     }
613     return value;
614 }
615 
616 static int
efreet_icon_size_match(Efreet_Cache_Icon_Element * elem,unsigned int size)617 efreet_icon_size_match(Efreet_Cache_Icon_Element *elem, unsigned int size)
618 {
619     if (elem->type == EFREET_ICON_SIZE_TYPE_FIXED)
620         return (elem->normal == size);
621 
622     if ((elem->type == EFREET_ICON_SIZE_TYPE_SCALABLE) ||
623         (elem->type == EFREET_ICON_SIZE_TYPE_THRESHOLD))
624         return ((elem->min < size) && (size < elem->max));
625 
626     return 0;
627 }
628 
629 static double
efreet_icon_size_distance(Efreet_Cache_Icon_Element * elem,unsigned int size)630 efreet_icon_size_distance(Efreet_Cache_Icon_Element *elem, unsigned int size)
631 {
632     if (elem->type == EFREET_ICON_SIZE_TYPE_FIXED)
633     {
634         if (elem->normal > size) return elem->normal - size;
635         else return size - elem->normal;
636     }
637 
638     if ((elem->type == EFREET_ICON_SIZE_TYPE_SCALABLE) ||
639         (elem->type == EFREET_ICON_SIZE_TYPE_THRESHOLD))
640     {
641 #ifdef STRICT_SPEC
642         if (size < elem->min)
643             return (elem->min - size);
644         if (elem->max < size)
645             return (size - elem->max);
646 #else
647         if (size < elem->min)
648             return (elem->min / (double)size);
649         if (elem->max < size)
650             return (size / (double)elem->max);
651 #endif
652     }
653 
654     return 0;
655 }
656 
657 static const char *
efreet_icon_lookup_path(Efreet_Cache_Icon_Element * elem)658 efreet_icon_lookup_path(Efreet_Cache_Icon_Element *elem)
659 {
660     Eina_List *xdg_dirs, *l;
661     const char *path;
662     const char *dir;
663     char buf[PATH_MAX];
664 
665     if (elem->paths_count == 1)
666     {
667         const char *pp, *ext;
668 
669         pp = strrchr(elem->paths[0], '.');
670         if (!pp) return NULL;
671 
672         EINA_LIST_FOREACH(efreet_icon_extensions, l, ext)
673             if (!strcmp(pp, ext))
674                 return elem->paths[0];
675         return NULL;
676     }
677 
678     path = efreet_icon_lookup_path_path(elem, efreet_icon_deprecated_user_dir_get());
679     if (path) return path;
680 
681     path = efreet_icon_lookup_path_path(elem, efreet_icon_user_dir_get());
682     if (path) return path;
683 
684 #if 0
685     EINA_LIST_FOREACH(efreet_extra_icon_dirs, l, dir)
686     {
687         path = efreet_icon_lookup_path_path(elem, dir);
688         if (path) return path;
689     }
690 #endif
691 
692     xdg_dirs = efreet_data_dirs_get();
693 
694     EINA_LIST_FOREACH(xdg_dirs, l, dir)
695     {
696         snprintf(buf, sizeof(buf), "%s/icons", dir);
697 
698         path = efreet_icon_lookup_path_path(elem, buf);
699         if (path) return path;
700     }
701 
702     return NULL;
703 }
704 
705 static const char *
efreet_icon_lookup_path_path(Efreet_Cache_Icon_Element * elem,const char * path)706 efreet_icon_lookup_path_path(Efreet_Cache_Icon_Element *elem, const char *path)
707 {
708     Eina_List *ll;
709     const char *ext, *pp;
710     const char *r = NULL;
711     unsigned int i;
712     int len;
713 
714     path = eina_file_path_sanitize(path);
715     len = strlen(path);
716 
717     for (i = 0; i < elem->paths_count; ++i)
718     {
719         if (strncmp(path, elem->paths[i], len)) continue;
720         pp = strrchr(elem->paths[i], '.');
721         if (!pp) continue;
722 
723         EINA_LIST_FOREACH(efreet_icon_extensions, ll, ext)
724             if (!strcmp(pp, ext))
725             {
726                 r = elem->paths[i];
727                 break;
728             }
729         if (r)
730           break;
731     }
732 
733     free((void*) path);
734 
735     return r;
736 }
737 
738 static const char *
efreet_icon_fallback_lookup_path(Efreet_Cache_Fallback_Icon * icon)739 efreet_icon_fallback_lookup_path(Efreet_Cache_Fallback_Icon *icon)
740 {
741     const char *path;
742     Eina_List *xdg_dirs, *l;
743     const char *dir;
744     char buf[PATH_MAX];
745 
746     if (!icon) return NULL;
747 
748     if (icon->icons_count == 1)
749     {
750         const char *pp, *ext;
751 
752         pp = strrchr(icon->icons[0], '.');
753         if (!pp) return NULL;
754 
755         EINA_LIST_FOREACH(efreet_icon_extensions, l, ext)
756             if (!strcmp(pp, ext))
757                 return icon->icons[0];
758         return NULL;
759     }
760 
761     path = efreet_icon_fallback_lookup_path_path(icon, efreet_icon_deprecated_user_dir_get());
762     if (path) return path;
763 
764     path = efreet_icon_fallback_lookup_path_path(icon, efreet_icon_user_dir_get());
765     if (path) return path;
766 
767     EINA_LIST_FOREACH(efreet_extra_icon_dirs, l, dir)
768     {
769         path = efreet_icon_fallback_lookup_path_path(icon, dir);
770         if (path) return path;
771     }
772 
773     xdg_dirs = efreet_data_dirs_get();
774 
775     EINA_LIST_FOREACH(xdg_dirs, l, dir)
776     {
777         snprintf(buf, sizeof(buf), "%s/icons", dir);
778 
779         path = efreet_icon_fallback_lookup_path_path(icon, buf);
780         if (path) return path;
781     }
782 
783 #ifndef STRICT_SPEC
784     EINA_LIST_FOREACH(xdg_dirs, l, dir)
785     {
786         snprintf(buf, sizeof(buf), "%s/pixmaps", dir);
787 
788         path = efreet_icon_fallback_lookup_path_path(icon, buf);
789         if (path) return path;
790     }
791 #endif
792 
793     path = efreet_icon_fallback_lookup_path_path(icon, "/usr/local/share/pixmaps");
794     if (path) return path;
795     path = efreet_icon_fallback_lookup_path_path(icon, "/usr/share/pixmaps");
796     if (path) return path;
797 
798     return NULL;
799 }
800 
801 static const char *
efreet_icon_fallback_lookup_path_path(Efreet_Cache_Fallback_Icon * icon,const char * path)802 efreet_icon_fallback_lookup_path_path(Efreet_Cache_Fallback_Icon *icon, const char *path)
803 {
804     Eina_List *ll;
805     const char *ext, *pp;
806     const char *r = NULL;
807     unsigned int i;
808     int len;
809 
810     path = eina_file_path_sanitize(path);
811     len = strlen(path);
812 
813     for (i = 0; i < icon->icons_count; ++i)
814     {
815         if (strncmp(path, icon->icons[i], len)) continue;
816 
817         pp = strrchr(icon->icons[i], '.');
818         if (!pp) continue;
819 
820         EINA_LIST_FOREACH(efreet_icon_extensions, ll, ext)
821             if (!strcmp(pp, ext))
822             {
823                 r = icon->icons[i];
824                 break;
825             }
826     }
827 
828     free((void*) path);
829 
830     return r;
831 }
832 
833 static void
efreet_cache_icon_dirs_add_cb(void * data EINA_UNUSED)834 efreet_cache_icon_dirs_add_cb(void *data EINA_UNUSED)
835 {
836     efreet_cache_icon_dirs_add(efreet_extra_icon_dirs);
837 }
838