5 /* TODO: Consider flushing local icons cache after idling.
6 * Icon requests will probably come in batches, f.ex. during menu
17 #include <Ecore_File.h>
19 /* define macros and variable for using the eina logging system */
20 #define EFREET_MODULE_LOG_DOM _efreet_cache_log_dom
21 static int _efreet_cache_log_dom = -1;
24 #include "efreet_private.h"
25 #include "efreet_cache_private.h"
27 #define NON_EXISTING (void *)-1
29 typedef struct _Efreet_Old_Cache Efreet_Old_Cache;
31 struct _Efreet_Old_Cache
38 * Data for cache files
40 static Eet_Data_Descriptor *directory_edd = NULL;
41 static Eet_Data_Descriptor *icon_theme_edd = NULL;
42 static Eet_Data_Descriptor *icon_theme_directory_edd = NULL;
44 static Eet_Data_Descriptor *icon_fallback_edd = NULL;
45 static Eet_Data_Descriptor *icon_element_pointer_edd = NULL;
46 static Eet_Data_Descriptor *icon_element_edd = NULL;
47 static Eet_Data_Descriptor *icon_edd = NULL;
49 static Eet_File *icon_cache = NULL;
50 static Eet_File *fallback_cache = NULL;
51 static Eet_File *icon_theme_cache = NULL;
53 static Eina_Hash *themes = NULL;
54 static Eina_Hash *icons = NULL;
55 static Eina_Hash *fallbacks = NULL;
57 static const char *icon_theme_cache_file = NULL;
59 static const char *theme_name = NULL;
61 static Eet_Data_Descriptor *version_edd = NULL;
62 static Eet_Data_Descriptor *desktop_edd = NULL;
63 static Eet_Data_Descriptor *hash_array_string_edd = NULL;
64 static Eet_Data_Descriptor *array_string_edd = NULL;
65 static Eet_Data_Descriptor *hash_string_edd = NULL;
67 static Eina_Hash *desktops = NULL;
68 static Eina_List *desktop_dirs_add = NULL;
69 static Eet_File *desktop_cache = NULL;
70 static const char *desktop_cache_file = NULL;
72 static Ecore_File_Monitor *cache_monitor = NULL;
74 static Ecore_Event_Handler *cache_exe_handler = NULL;
75 static Ecore_Timer *icon_cache_timer = NULL;
76 static Ecore_Exe *icon_cache_exe = NULL;
77 static int icon_cache_exe_lock = -1;
78 static Ecore_Timer *desktop_cache_timer = NULL;
79 static Ecore_Exe *desktop_cache_exe = NULL;
80 static int desktop_cache_exe_lock = -1;
82 static Eina_List *old_desktop_caches = NULL;
84 static const char *util_cache_file = NULL;
85 static Eet_File *util_cache = NULL;
86 static Efreet_Cache_Hash *util_cache_hash = NULL;
87 static const char *util_cache_hash_key = NULL;
88 static Efreet_Cache_Array_String *util_cache_names = NULL;
89 static const char *util_cache_names_key = NULL;
91 static void efreet_cache_edd_shutdown(void);
92 static void efreet_cache_icon_free(Efreet_Cache_Icon *icon);
93 static void efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon);
94 static void efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme);
96 static Eina_Bool efreet_cache_check(Eet_File **ef, const char *path, int major);
97 static void *efreet_cache_close(Eet_File *ef);
99 static Eina_Bool cache_exe_cb(void *data, int type, void *event);
100 static Eina_Bool cache_check_change(const char *path);
101 static void cache_update_cb(void *data, Ecore_File_Monitor *em,
102 Ecore_File_Event event, const char *path);
104 static Eina_Bool desktop_cache_update_cache_cb(void *data);
105 static Eina_Bool icon_cache_update_cache_cb(void *data);
106 static void desktop_cache_update_free(void *data, void *ev);
107 static void icon_cache_update_free(void *data, void *ev);
109 static void *hash_array_string_add(void *hash, const char *key, void *data);
111 EAPI int EFREET_EVENT_ICON_CACHE_UPDATE = 0;
112 EAPI int EFREET_EVENT_DESKTOP_CACHE_UPDATE = 0;
113 EAPI int EFREET_EVENT_DESKTOP_CACHE_BUILD = 0;
116 efreet_cache_init(void)
120 _efreet_cache_log_dom = eina_log_domain_register("efreet_cache", EFREET_DEFAULT_LOG_COLOR);
121 if (_efreet_cache_log_dom < 0)
124 EFREET_EVENT_ICON_CACHE_UPDATE = ecore_event_type_new();
125 EFREET_EVENT_DESKTOP_CACHE_UPDATE = ecore_event_type_new();
126 EFREET_EVENT_DESKTOP_CACHE_BUILD = ecore_event_type_new();
128 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
129 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
130 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
131 desktops = eina_hash_string_superfast_new(NULL);
133 if (efreet_cache_update)
135 snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get());
136 if (!ecore_file_exists(buf))
138 if (!ecore_file_mkpath(buf))
140 ERR("Failed to create directory '%s'", buf);
143 efreet_setowner(buf);
146 cache_exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
148 if (!cache_exe_handler)
150 ERR("Failed to add exe del handler");
154 cache_monitor = ecore_file_monitor_add(buf,
159 ERR("Failed to set up ecore file monitor for '%s'", buf);
163 efreet_cache_icon_update();
164 efreet_cache_desktop_update();
169 if (themes) eina_hash_free(themes);
171 if (icons) eina_hash_free(icons);
173 if (fallbacks) eina_hash_free(fallbacks);
175 if (desktops) eina_hash_free(desktops);
178 if (cache_exe_handler) ecore_event_handler_del(cache_exe_handler);
179 cache_exe_handler = NULL;
180 if (cache_monitor) ecore_file_monitor_del(cache_monitor);
181 cache_monitor = NULL;
182 efreet_cache_edd_shutdown();
187 efreet_cache_shutdown(void)
192 IF_RELEASE(theme_name);
194 icon_cache = efreet_cache_close(icon_cache);
195 icon_theme_cache = efreet_cache_close(icon_theme_cache);
197 IF_FREE_HASH(themes);
199 IF_FREE_HASH(fallbacks);
201 IF_FREE_HASH_CB(desktops, EINA_FREE_CB(efreet_cache_desktop_free));
202 EINA_LIST_FREE(desktop_dirs_add, data)
203 eina_stringshare_del(data);
204 desktop_cache = efreet_cache_close(desktop_cache);
205 IF_RELEASE(desktop_cache_file);
207 if (cache_exe_handler) ecore_event_handler_del(cache_exe_handler);
208 cache_exe_handler = NULL;
209 if (cache_monitor) ecore_file_monitor_del(cache_monitor);
210 cache_monitor = NULL;
212 efreet_cache_edd_shutdown();
213 if (desktop_cache_timer)
215 ecore_timer_del(desktop_cache_timer);
216 desktop_cache_timer = NULL;
218 IF_RELEASE(icon_theme_cache_file);
219 if (icon_cache_exe_lock > 0)
221 close(icon_cache_exe_lock);
222 icon_cache_exe_lock = -1;
225 if (desktop_cache_exe_lock > 0)
227 close(desktop_cache_exe_lock);
228 desktop_cache_exe_lock = -1;
231 if (old_desktop_caches)
232 ERR("This application has not properly closed all its desktop references!");
233 EINA_LIST_FREE(old_desktop_caches, d)
235 eina_hash_free(d->hash);
240 IF_RELEASE(util_cache_names_key);
241 efreet_cache_array_string_free(util_cache_names);
242 util_cache_names = NULL;
244 IF_RELEASE(util_cache_hash_key);
247 eina_hash_free(util_cache_hash->hash);
248 free(util_cache_hash);
249 util_cache_hash = NULL;
252 util_cache = efreet_cache_close(util_cache);
253 IF_RELEASE(util_cache_file);
255 eina_log_domain_unregister(_efreet_cache_log_dom);
256 _efreet_cache_log_dom = -1;
260 * Needs EAPI because of helper binaries
263 efreet_icon_cache_file(const char *theme)
265 static char cache_file[PATH_MAX] = { '\0' };
268 EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
270 cache = efreet_cache_home_get();
272 snprintf(cache_file, sizeof(cache_file), "%s/efreet/icons_%s_%s.eet", cache, theme, efreet_hostname_get());
278 * Needs EAPI because of helper binaries
281 efreet_icon_theme_cache_file(void)
283 char tmp[PATH_MAX] = { '\0' };
285 if (icon_theme_cache_file) return icon_theme_cache_file;
287 snprintf(tmp, sizeof(tmp), "%s/efreet/icon_themes_%s.eet",
288 efreet_cache_home_get(), efreet_hostname_get());
289 icon_theme_cache_file = eina_stringshare_add(tmp);
291 return icon_theme_cache_file;
295 * Needs EAPI because of helper binaries
298 efreet_desktop_util_cache_file(void)
300 char tmp[PATH_MAX] = { '\0' };
301 const char *cache_dir, *lang, *country, *modifier;
303 if (util_cache_file) return util_cache_file;
305 cache_dir = efreet_cache_home_get();
306 lang = efreet_lang_get();
307 country = efreet_lang_country_get();
308 modifier = efreet_lang_modifier_get();
310 if (lang && country && modifier)
311 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s@%s.eet", cache_dir, efreet_hostname_get(), lang, country, modifier);
312 else if (lang && country)
313 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s.eet", cache_dir, efreet_hostname_get(), lang, country);
315 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s.eet", cache_dir, efreet_hostname_get(), lang);
317 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s.eet", cache_dir, efreet_hostname_get());
319 util_cache_file = eina_stringshare_add(tmp);
320 return util_cache_file;
324 * Needs EAPI because of helper binaries
326 EAPI Eet_Data_Descriptor *
327 efreet_version_edd(void)
329 Eet_Data_Descriptor_Class eddc;
331 if (version_edd) return version_edd;
333 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Version);
334 version_edd = eet_data_descriptor_file_new(&eddc);
335 if (!version_edd) return NULL;
337 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
338 "minor", minor, EET_T_UCHAR);
339 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
340 "major", major, EET_T_UCHAR);
346 * Needs EAPI because of helper binaries
348 EAPI Eet_Data_Descriptor *
349 efreet_hash_array_string_edd(void)
351 Eet_Data_Descriptor_Class eddc;
353 if (hash_array_string_edd) return hash_array_string_edd;
355 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
356 eddc.func.hash_add = hash_array_string_add;
357 hash_array_string_edd = eet_data_descriptor_file_new(&eddc);
358 if (!hash_array_string_edd) return NULL;
360 EET_DATA_DESCRIPTOR_ADD_HASH(hash_array_string_edd, Efreet_Cache_Hash,
361 "hash", hash, efreet_array_string_edd());
363 return hash_array_string_edd;
367 * Needs EAPI because of helper binaries
369 EAPI Eet_Data_Descriptor *
370 efreet_hash_string_edd(void)
372 Eet_Data_Descriptor_Class eddc;
374 if (hash_string_edd) return hash_string_edd;
376 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
377 hash_string_edd = eet_data_descriptor_file_new(&eddc);
378 if (!hash_string_edd) return NULL;
380 EET_DATA_DESCRIPTOR_ADD_HASH_STRING(hash_string_edd, Efreet_Cache_Hash,
383 return hash_string_edd;
387 * Needs EAPI because of helper binaries
389 EAPI Eet_Data_Descriptor *
390 efreet_array_string_edd(void)
392 Eet_Data_Descriptor_Class eddc;
394 if (array_string_edd) return array_string_edd;
396 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Array_String);
397 array_string_edd = eet_data_descriptor_file_new(&eddc);
398 if (!array_string_edd) return NULL;
399 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(array_string_edd, Efreet_Cache_Array_String,
402 return array_string_edd;
406 * Needs EAPI because of helper binaries
409 efreet_desktop_cache_file(void)
411 char tmp[PATH_MAX] = { '\0' };
412 const char *cache, *lang, *country, *modifier;
414 if (desktop_cache_file) return desktop_cache_file;
416 cache = efreet_cache_home_get();
417 lang = efreet_lang_get();
418 country = efreet_lang_country_get();
419 modifier = efreet_lang_modifier_get();
421 if (lang && country && modifier)
422 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s@%s.eet", cache, efreet_hostname_get(), lang, country, modifier);
423 else if (lang && country)
424 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s.eet", cache, efreet_hostname_get(), lang, country);
426 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s.eet", cache, efreet_hostname_get(), lang);
428 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s.eet", cache, efreet_hostname_get());
430 desktop_cache_file = eina_stringshare_add(tmp);
431 return desktop_cache_file;
434 #define EDD_SHUTDOWN(Edd) \
435 if (Edd) eet_data_descriptor_free(Edd); \
439 efreet_cache_edd_shutdown(void)
441 EDD_SHUTDOWN(version_edd);
442 EDD_SHUTDOWN(desktop_edd);
443 EDD_SHUTDOWN(hash_array_string_edd);
444 EDD_SHUTDOWN(array_string_edd);
445 EDD_SHUTDOWN(hash_string_edd);
446 EDD_SHUTDOWN(icon_theme_edd);
447 EDD_SHUTDOWN(icon_theme_directory_edd);
448 EDD_SHUTDOWN(directory_edd);
449 EDD_SHUTDOWN(icon_fallback_edd);
450 EDD_SHUTDOWN(icon_element_pointer_edd);
451 EDD_SHUTDOWN(icon_element_edd);
452 EDD_SHUTDOWN(icon_edd);
455 #define EFREET_POINTER_TYPE(Edd_Dest, Edd_Source, Type) \
457 typedef struct _Efreet_##Type##_Pointer Efreet_##Type##_Pointer; \
458 struct _Efreet_##Type##_Pointer \
460 Efreet_##Type *pointer; \
463 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_##Type##_Pointer); \
464 Edd_Dest = eet_data_descriptor_file_new(&eddc); \
465 EET_DATA_DESCRIPTOR_ADD_SUB(Edd_Dest, Efreet_##Type##_Pointer, \
466 "pointer", pointer, Edd_Source); \
469 static Eet_Data_Descriptor *
470 efreet_icon_directory_edd(void)
472 Eet_Data_Descriptor_Class eddc;
474 if (directory_edd) return directory_edd;
476 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Directory);
477 directory_edd = eet_data_descriptor_file_new(&eddc);
478 if (!directory_edd) return NULL;
480 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
481 "modified_time", modified_time, EET_T_LONG_LONG);
483 return directory_edd;
487 * Needs EAPI because of helper binaries
489 EAPI Eet_Data_Descriptor *
490 efreet_icon_edd(void)
492 Eet_Data_Descriptor_Class eddc;
494 if (icon_edd) return icon_edd;
496 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Element);
497 icon_element_edd = eet_data_descriptor_file_new(&eddc);
498 if (!icon_element_edd) return NULL;
500 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
501 "type", type, EET_T_USHORT);
502 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
503 "normal", normal, EET_T_USHORT);
504 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
505 "normal", normal, EET_T_USHORT);
506 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
507 "min", min, EET_T_USHORT);
508 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
509 "max", max, EET_T_USHORT);
510 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_element_edd, Efreet_Cache_Icon_Element,
513 EFREET_POINTER_TYPE(icon_element_pointer_edd, icon_element_edd, Cache_Icon_Element);
515 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon);
516 icon_edd = eet_data_descriptor_file_new(&eddc);
517 if (!icon_edd) return NULL;
519 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_edd, Efreet_Cache_Icon,
520 "theme", theme, EET_T_STRING);
521 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(icon_edd, Efreet_Cache_Icon,
522 "icons", icons, icon_element_pointer_edd);
528 * Needs EAPI because of helper binaries
530 EAPI Eet_Data_Descriptor *
531 efreet_icon_theme_edd(Eina_Bool cache)
533 Eet_Data_Descriptor_Class eddc;
535 if (icon_theme_edd) return icon_theme_edd;
537 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Icon_Theme_Directory);
538 icon_theme_directory_edd = eet_data_descriptor_file_new(&eddc);
539 if (!icon_theme_directory_edd) return NULL;
541 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
542 "name", name, EET_T_STRING);
543 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
544 "context", context, EET_T_UCHAR);
545 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
546 "type", type, EET_T_UCHAR);
547 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
548 "size.normal", size.normal, EET_T_UINT);
549 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
550 "size.min", size.min, EET_T_UINT);
551 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
552 "size.max", size.max, EET_T_UINT);
553 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
554 "size.threshold", size.threshold, EET_T_UINT);
556 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Theme);
557 icon_theme_edd = eet_data_descriptor_file_new(&eddc);
558 if (!icon_theme_edd) return NULL;
560 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
561 "name.internal", theme.name.internal, EET_T_STRING);
562 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
563 "name.name", theme.name.name, EET_T_STRING);
564 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
565 "comment", theme.comment, EET_T_STRING);
566 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
567 "example_icon", theme.example_icon, EET_T_STRING);
569 eet_data_descriptor_element_add(icon_theme_edd, "paths", EET_T_STRING, EET_G_LIST,
570 offsetof(Efreet_Cache_Icon_Theme, theme.paths), 0, NULL, NULL);
571 eet_data_descriptor_element_add(icon_theme_edd, "inherits", EET_T_STRING, EET_G_LIST,
572 offsetof(Efreet_Cache_Icon_Theme, theme.inherits), 0, NULL, NULL);
573 EET_DATA_DESCRIPTOR_ADD_LIST(icon_theme_edd, Efreet_Cache_Icon_Theme,
574 "directories", theme.directories, icon_theme_directory_edd);
578 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
579 "last_cache_check", last_cache_check, EET_T_LONG_LONG);
581 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
582 "path", path, EET_T_STRING);
584 EET_DATA_DESCRIPTOR_ADD_HASH(icon_theme_edd, Efreet_Cache_Icon_Theme,
585 "dirs", dirs, efreet_icon_directory_edd());
588 return icon_theme_edd;
592 * Needs EAPI because of helper binaries
594 EAPI Eet_Data_Descriptor *
595 efreet_icon_fallback_edd(void)
597 Eet_Data_Descriptor_Class eddc;
599 if (icon_fallback_edd) return icon_fallback_edd;
601 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Fallback_Icon);
602 icon_fallback_edd = eet_data_descriptor_file_new(&eddc);
603 if (!icon_fallback_edd) return NULL;
605 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_fallback_edd,
606 Efreet_Cache_Fallback_Icon, "icons", icons);
608 return icon_fallback_edd;
612 * Needs EAPI because of helper binaries
614 EAPI Eet_Data_Descriptor *
615 efreet_desktop_edd(void)
617 Eet_Data_Descriptor_Class eddc;
619 if (desktop_edd) return desktop_edd;
621 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Desktop);
622 desktop_edd = eet_data_descriptor_file_new(&eddc);
623 if (!desktop_edd) return NULL;
625 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "type", desktop.type, EET_T_INT);
626 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "version", desktop.version, EET_T_STRING);
627 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "orig_path", desktop.orig_path, EET_T_STRING);
628 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "load_time", desktop.load_time, EET_T_LONG_LONG);
629 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "name", desktop.name, EET_T_STRING);
630 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "generic_name", desktop.generic_name, EET_T_STRING);
631 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "comment", desktop.comment, EET_T_STRING);
632 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "icon", desktop.icon, EET_T_STRING);
633 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "try_exec", desktop.try_exec, EET_T_STRING);
634 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "exec", desktop.exec, EET_T_STRING);
635 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "path", desktop.path, EET_T_STRING);
636 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_wm_class", desktop.startup_wm_class, EET_T_STRING);
637 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "url", desktop.url, EET_T_STRING);
638 eet_data_descriptor_element_add(desktop_edd, "only_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.only_show_in), 0, NULL, NULL);
639 eet_data_descriptor_element_add(desktop_edd, "not_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.not_show_in), 0, NULL, NULL);
640 eet_data_descriptor_element_add(desktop_edd, "categories", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.categories), 0, NULL, NULL);
641 eet_data_descriptor_element_add(desktop_edd, "mime_types", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.mime_types), 0, NULL, NULL);
642 eet_data_descriptor_element_add(desktop_edd, "x", EET_T_STRING, EET_G_HASH, offsetof(Efreet_Cache_Desktop, desktop.x), 0, NULL, NULL);
643 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "no_display", desktop.no_display, EET_T_UCHAR);
644 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "hidden", desktop.hidden, EET_T_UCHAR);
645 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "terminal", desktop.terminal, EET_T_UCHAR);
646 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_notify", desktop.startup_notify, EET_T_UCHAR);
652 efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon)
654 Efreet_Cache_Icon *cache = NULL;
656 if (theme_name && strcmp(theme_name, theme->name.internal))
658 /* FIXME: this is bad if people have pointer to this cache, things will go wrong */
659 INF("theme_name change from `%s` to `%s`", theme_name, theme->name.internal);
660 IF_RELEASE(theme_name);
661 icon_cache = efreet_cache_close(icon_cache);
662 eina_hash_free(icons);
663 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
666 if (!efreet_cache_check(&icon_cache, efreet_icon_cache_file(theme->name.internal), EFREET_ICON_CACHE_MAJOR)) return NULL;
668 theme_name = eina_stringshare_add(theme->name.internal);
670 cache = eina_hash_find(icons, icon);
671 if (cache == NON_EXISTING) return NULL;
672 if (cache) return cache;
674 cache = eet_data_read(icon_cache, efreet_icon_edd(), icon);
676 eina_hash_add(icons, icon, cache);
678 eina_hash_add(icons, icon, NON_EXISTING);
682 Efreet_Cache_Fallback_Icon *
683 efreet_cache_icon_fallback_find(const char *icon)
685 Efreet_Cache_Fallback_Icon *cache;
687 if (!efreet_cache_check(&fallback_cache, efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EFREET_ICON_CACHE_MAJOR)) return NULL;
689 cache = eina_hash_find(fallbacks, icon);
690 if (cache == NON_EXISTING) return NULL;
691 if (cache) return cache;
693 cache = eet_data_read(fallback_cache, efreet_icon_fallback_edd(), icon);
695 eina_hash_add(fallbacks, icon, cache);
697 eina_hash_add(fallbacks, icon, NON_EXISTING);
702 efreet_cache_icon_theme_find(const char *theme)
704 Efreet_Cache_Icon_Theme *cache;
706 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
708 cache = eina_hash_find(themes, theme);
709 if (cache == NON_EXISTING) return NULL;
710 if (cache) return &(cache->theme);
712 cache = eet_data_read(icon_theme_cache, efreet_icon_theme_edd(EINA_FALSE), theme);
715 eina_hash_add(themes, theme, cache);
716 return &(cache->theme);
719 eina_hash_add(themes, theme, NON_EXISTING);
724 efreet_cache_icon_free(Efreet_Cache_Icon *icon)
729 if (icon == NON_EXISTING) return;
731 for (i = 0; i < icon->icons_count; ++i)
733 free(icon->icons[i]->paths);
734 free(icon->icons[i]);
742 efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon)
745 if (icon == NON_EXISTING) return;
752 efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme)
757 if (theme == NON_EXISTING) return;
759 eina_list_free(theme->paths);
760 eina_list_free(theme->inherits);
761 EINA_LIST_FREE(theme->directories, data)
768 efreet_cache_icon_theme_list(void)
770 Eina_List *ret = NULL;
774 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
775 keys = eet_list(icon_theme_cache, "*", &num);
776 for (i = 0; i < num; i++)
778 Efreet_Icon_Theme *theme;
779 if (!strncmp(keys[i], "__efreet", 8)) continue;
781 theme = eina_hash_find(themes, keys[i]);
783 theme = efreet_cache_icon_theme_find(keys[i]);
784 if (theme && theme != NON_EXISTING)
785 ret = eina_list_append(ret, theme);
792 * Needs EAPI because of helper binaries
795 efreet_cache_array_string_free(Efreet_Cache_Array_String *array)
803 efreet_cache_desktop_find(const char *file)
805 Efreet_Cache_Desktop *cache;
808 if (!realpath(file, rp)) return NULL;
810 if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) return NULL;
812 cache = eina_hash_find(desktops, rp);
813 if (cache == NON_EXISTING) return NULL;
816 /* If less than one second since last stat, return desktop */
817 if ((ecore_time_get() - cache->check_time) < 1)
819 INF("Return without stat %f %f", ecore_time_get(), cache->check_time);
820 return &cache->desktop;
822 if (cache->desktop.load_time == ecore_file_mod_time(cache->desktop.orig_path))
824 INF("Return with stat %f %f", ecore_time_get(), cache->check_time);
825 cache->check_time = ecore_time_get();
826 return &cache->desktop;
829 /* We got stale data. The desktop will be free'd eventually as
830 * users will call efreet_desktop_free */
831 eina_hash_set(desktops, rp, NON_EXISTING);
835 cache = eet_data_read(desktop_cache, efreet_desktop_edd(), rp);
838 if (cache->desktop.load_time != ecore_file_mod_time(cache->desktop.orig_path))
840 /* Don't return stale data */
841 INF("We got stale data in the desktop cache");
842 efreet_cache_desktop_free(&cache->desktop);
843 eina_hash_set(desktops, rp, NON_EXISTING);
847 cache->desktop.eet = 1;
848 cache->check_time = ecore_time_get();
849 eina_hash_set(desktops, cache->desktop.orig_path, cache);
850 return &cache->desktop;
854 eina_hash_set(desktops, rp, NON_EXISTING);
859 efreet_cache_desktop_free(Efreet_Desktop *desktop)
862 Efreet_Desktop *curr;
866 desktop == NON_EXISTING ||
867 !desktop->eet) return;
869 curr = eina_hash_find(desktops, desktop->orig_path);
872 INF("Found in current cache, purge\n");
873 eina_hash_del_by_key(desktops, desktop->orig_path);
876 EINA_LIST_FOREACH(old_desktop_caches, l, d)
878 curr = eina_hash_find(d->hash, desktop->orig_path);
881 INF("Found in old cache, purge\n");
882 eina_hash_del_by_key(d->hash, desktop->orig_path);
883 if (eina_hash_population(d->hash) == 0)
885 INF("Cache empty, close file\n");
886 eina_hash_free(d->hash);
889 old_desktop_caches = eina_list_remove_list(old_desktop_caches, l);
895 eina_list_free(desktop->only_show_in);
896 eina_list_free(desktop->not_show_in);
897 eina_list_free(desktop->categories);
898 eina_list_free(desktop->mime_types);
899 IF_FREE_HASH(desktop->x);
904 efreet_cache_desktop_add(Efreet_Desktop *desktop)
908 Efreet_Cache_Array_String *arr;
911 * Read file from disk, save path in cache so it will be included in next
914 strncpy(buf, desktop->orig_path, PATH_MAX);
915 buf[PATH_MAX - 1] = '\0';
917 arr = efreet_cache_desktop_dirs();
922 for (i = 0; i < arr->array_count; i++)
924 /* Check if we already have this dir in cache */
925 if (!strcmp(dir, arr->array[i]))
928 efreet_cache_array_string_free(arr);
930 if (!eina_list_search_unsorted_list(desktop_dirs_add, EINA_COMPARE_CB(strcmp), dir))
931 desktop_dirs_add = eina_list_append(desktop_dirs_add, eina_stringshare_add(dir));
933 efreet_cache_desktop_update();
936 Efreet_Cache_Array_String *
937 efreet_cache_desktop_dirs(void)
939 if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) return NULL;
941 return eet_data_read(desktop_cache, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS);
945 efreet_cache_desktop_update(void)
947 if (!efreet_cache_update) return;
949 if (desktop_cache_timer)
950 ecore_timer_delay(desktop_cache_timer, 0.2);
952 desktop_cache_timer = ecore_timer_add(0.2, desktop_cache_update_cache_cb, NULL);
956 efreet_cache_desktop_close(void)
958 IF_RELEASE(util_cache_names_key);
959 IF_RELEASE(util_cache_hash_key);
961 if ((desktop_cache) && (desktop_cache != NON_EXISTING))
963 Efreet_Old_Cache *d = NEW(Efreet_Old_Cache, 1);
967 d->ef = desktop_cache;
968 old_desktop_caches = eina_list_append(old_desktop_caches, d);
971 desktops = eina_hash_string_superfast_new(NULL);
973 desktop_cache = NULL;
975 efreet_cache_array_string_free(util_cache_names);
976 util_cache_names = NULL;
980 eina_hash_free(util_cache_hash->hash);
981 free(util_cache_hash);
982 util_cache_hash = NULL;
985 util_cache = efreet_cache_close(util_cache);
987 IF_RELEASE(desktop_cache_file);
988 IF_RELEASE(util_cache_file);
992 efreet_cache_icon_update(void)
994 if (!efreet_cache_update) return;
996 if (icon_cache_timer)
997 ecore_timer_delay(icon_cache_timer, 0.2);
999 icon_cache_timer = ecore_timer_add(0.2, icon_cache_update_cache_cb, NULL);
1003 efreet_cache_check(Eet_File **ef, const char *path, int major)
1005 Efreet_Cache_Version *version;
1007 if (*ef == NON_EXISTING) return EINA_FALSE;
1008 if (*ef) return EINA_TRUE;
1010 *ef = eet_open(path, EET_FILE_MODE_READ);
1017 version = eet_data_read(*ef, efreet_version_edd(), EFREET_CACHE_VERSION);
1018 if ((!version) || (version->major != major))
1030 efreet_cache_close(Eet_File *ef)
1032 if (ef && ef != NON_EXISTING)
1038 efreet_cache_util_hash_string(const char *key)
1040 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1041 return util_cache_hash;
1042 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1044 if (util_cache_hash)
1046 /* free previous util_cache */
1047 IF_RELEASE(util_cache_hash_key);
1048 eina_hash_free(util_cache_hash->hash);
1049 free(util_cache_hash);
1051 util_cache_hash_key = eina_stringshare_add(key);
1052 util_cache_hash = eet_data_read(util_cache, efreet_hash_string_edd(), key);
1053 return util_cache_hash;
1057 efreet_cache_util_hash_array_string(const char *key)
1059 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1060 return util_cache_hash;
1061 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1063 IF_RELEASE(util_cache_hash_key);
1064 if (util_cache_hash)
1066 /* free previous cache */
1067 eina_hash_free(util_cache_hash->hash);
1068 free(util_cache_hash);
1070 util_cache_hash_key = eina_stringshare_add(key);
1071 util_cache_hash = eet_data_read(util_cache, efreet_hash_array_string_edd(), key);
1072 return util_cache_hash;
1075 Efreet_Cache_Array_String *
1076 efreet_cache_util_names(const char *key)
1078 if (util_cache_names_key && !strcmp(key, util_cache_names_key))
1079 return util_cache_names;
1080 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1082 if (util_cache_names)
1084 /* free previous util_cache */
1085 IF_RELEASE(util_cache_names_key);
1086 efreet_cache_array_string_free(util_cache_names);
1088 util_cache_names_key = eina_stringshare_add(key);
1089 util_cache_names = eet_data_read(util_cache, efreet_array_string_edd(), key);
1090 return util_cache_names;
1094 cache_exe_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
1096 Ecore_Exe_Event_Del *ev;
1099 if (ev->exe == desktop_cache_exe)
1101 if (desktop_cache_exe_lock > 0)
1103 close(desktop_cache_exe_lock);
1104 desktop_cache_exe_lock = -1;
1106 desktop_cache_exe = NULL;
1108 else if (ev->exe == icon_cache_exe)
1110 if (icon_cache_exe_lock > 0)
1112 close(icon_cache_exe_lock);
1113 icon_cache_exe_lock = -1;
1115 icon_cache_exe = NULL;
1117 return ECORE_CALLBACK_RENEW;
1121 cache_check_change(const char *path)
1124 Eina_Bool changed = EINA_TRUE;
1127 f = eina_file_open(path, EINA_FALSE);
1128 if (!f) return EINA_TRUE;
1129 if (eina_file_size_get(f) < 1) return EINA_TRUE;
1130 data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
1131 if (*data == 'n') changed = EINA_FALSE;
1137 cache_update_cb(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__,
1138 Ecore_File_Event event, const char *path)
1141 Efreet_Event_Cache_Update *ev = NULL;
1142 Efreet_Old_Cache *d = NULL;
1143 Eina_List *l = NULL;
1145 if (event != ECORE_FILE_EVENT_CLOSED)
1148 file = ecore_file_file_get(path);
1150 if (!strcmp(file, "desktop_data.update"))
1152 if (cache_check_change(path))
1154 ev = NEW(Efreet_Event_Cache_Update, 1);
1155 if (!ev) goto error;
1157 efreet_cache_desktop_close();
1159 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE, ev, desktop_cache_update_free, d);
1161 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL);
1162 /* TODO: Check if desktop_dirs_add exists, and rebuild cache if */
1164 else if (!strcmp(file, "icon_data.update"))
1166 if (cache_check_change(path))
1168 ev = NEW(Efreet_Event_Cache_Update, 1);
1169 if (!ev) goto error;
1171 IF_RELEASE(theme_name);
1173 /* Save all old caches */
1174 d = NEW(Efreet_Old_Cache, 1);
1177 d->ef = icon_theme_cache;
1178 l = eina_list_append(l, d);
1180 d = NEW(Efreet_Old_Cache, 1);
1184 l = eina_list_append(l, d);
1186 d = NEW(Efreet_Old_Cache, 1);
1188 d->hash = fallbacks;
1189 d->ef = fallback_cache;
1190 l = eina_list_append(l, d);
1192 /* Create new empty caches */
1193 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
1194 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
1195 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
1197 icon_theme_cache = NULL;
1199 fallback_cache = NULL;
1202 ecore_event_add(EFREET_EVENT_ICON_CACHE_UPDATE, ev, icon_cache_update_free, l);
1209 EINA_LIST_FREE(l, d)
1214 desktop_cache_update_cache_cb(void *data __UNUSED__)
1216 char file[PATH_MAX];
1220 desktop_cache_timer = NULL;
1222 /* TODO: Retry update cache later */
1223 if (desktop_cache_exe_lock > 0) return ECORE_CALLBACK_CANCEL;
1225 snprintf(file, sizeof(file), "%s/efreet/desktop_exec.lock", efreet_cache_home_get());
1227 desktop_cache_exe_lock = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
1228 if (desktop_cache_exe_lock < 0) goto error;
1229 efreet_fsetowner(desktop_cache_exe_lock);
1230 memset(&fl, 0, sizeof(struct flock));
1231 fl.l_type = F_WRLCK;
1232 fl.l_whence = SEEK_SET;
1233 if (fcntl(desktop_cache_exe_lock, F_SETLK, &fl) < 0) goto error;
1234 prio = ecore_exe_run_priority_get();
1235 ecore_exe_run_priority_set(19);
1236 eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_desktop_cache_create", sizeof(file));
1237 if (desktop_dirs_add)
1241 eina_strlcat(file, " -d", sizeof(file));
1242 EINA_LIST_FREE(desktop_dirs_add, str)
1244 eina_strlcat(file, " ", sizeof(file));
1245 eina_strlcat(file, str, sizeof(file));
1246 eina_stringshare_del(str);
1249 INF("Run desktop cache creation: %s", file);
1250 desktop_cache_exe = ecore_exe_run(file, NULL);
1251 ecore_exe_run_priority_set(prio);
1252 if (!desktop_cache_exe) goto error;
1254 return ECORE_CALLBACK_CANCEL;
1256 if (desktop_cache_exe_lock > 0)
1258 close(desktop_cache_exe_lock);
1259 desktop_cache_exe_lock = -1;
1261 return ECORE_CALLBACK_CANCEL;
1265 icon_cache_update_cache_cb(void *data __UNUSED__)
1267 char file[PATH_MAX];
1272 icon_cache_timer = NULL;
1274 /* TODO: Retry update cache later */
1275 if (icon_cache_exe_lock > 0) return ECORE_CALLBACK_CANCEL;
1277 snprintf(file, sizeof(file), "%s/efreet/icon_exec.lock", efreet_cache_home_get());
1279 icon_cache_exe_lock = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
1280 if (icon_cache_exe_lock < 0) goto error;
1281 efreet_fsetowner(icon_cache_exe_lock);
1282 memset(&fl, 0, sizeof(struct flock));
1283 fl.l_type = F_WRLCK;
1284 fl.l_whence = SEEK_SET;
1285 if (fcntl(icon_cache_exe_lock, F_SETLK, &fl) < 0) goto error;
1286 prio = ecore_exe_run_priority_get();
1287 ecore_exe_run_priority_set(19);
1288 eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_icon_cache_create", sizeof(file));
1289 l = efreet_icon_extra_list_get();
1290 if (l && eina_list_count(*l) > 0)
1295 eina_strlcat(file, " -d", sizeof(file));
1296 EINA_LIST_FOREACH(*l, ll, p)
1298 eina_strlcat(file, " ", sizeof(file));
1299 eina_strlcat(file, p, sizeof(file));
1302 l2 = efreet_icon_extensions_list_get();
1303 if (eina_list_count(l2) > 0)
1308 eina_strlcat(file, " -e", sizeof(file));
1309 EINA_LIST_FOREACH(l2, ll, p)
1311 eina_strlcat(file, " ", sizeof(file));
1312 eina_strlcat(file, p, sizeof(file));
1315 icon_cache_exe = ecore_exe_run(file, NULL);
1316 ecore_exe_run_priority_set(prio);
1317 if (!icon_cache_exe) goto error;
1319 return ECORE_CALLBACK_CANCEL;
1322 if (icon_cache_exe_lock > 0)
1324 close(icon_cache_exe_lock);
1325 icon_cache_exe_lock = -1;
1327 return ECORE_CALLBACK_CANCEL;
1331 desktop_cache_update_free(void *data, void *ev)
1333 Efreet_Old_Cache *d;
1337 if (d && (eina_list_data_find(old_desktop_caches, d) == d))
1340 * All users should now had the chance to update their pointers.
1341 * Check whether we still have some dangling and print a warning.
1342 * Programs might close their pointers later.
1347 Eina_Hash_Tuple *tuple;
1349 it = eina_hash_iterator_tuple_new(d->hash);
1350 EINA_ITERATOR_FOREACH(it, tuple)
1352 if (tuple->data == NON_EXISTING) continue;
1353 WRN("%d:%s still in cache after update event!",
1354 ((Efreet_Desktop *)tuple->data)->ref, (char *)tuple->key);
1357 eina_iterator_free(it);
1361 WRN("There are still %i desktop files with old\n"
1362 "dangling references to desktop files. This application\n"
1363 "has not handled the EFREET_EVENT_DESKTOP_CACHE_UPDATE\n"
1364 "fully and released its references. Please fix the application\n"
1373 icon_cache_update_free(void *data, void *ev)
1375 Efreet_Old_Cache *d;
1379 EINA_LIST_FREE(l, d)
1382 eina_hash_free(d->hash);
1383 efreet_cache_close(d->ef);
1390 hash_array_string_add(void *hash, const char *key, void *data)
1393 hash = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
1396 eina_hash_add(hash, key, data);