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