diff --git a/src/bin/efreet/efreet_desktop_cache_create.c b/src/bin/efreet/efreet_desktop_cache_create.c index 2fc6e917d7..fd8c613305 100644 --- a/src/bin/efreet/efreet_desktop_cache_create.c +++ b/src/bin/efreet/efreet_desktop_cache_create.c @@ -128,54 +128,75 @@ cache_add(const char *path, const char *file_id, int priority EINA_UNUSED, int * static int -cache_scan(const char *path, const char *base_id, int priority, int recurse, int *changed) +cache_scan(Eina_Inarray *stack, const char *path, const char *base_id, + int priority, int recurse, int *changed) { char *file_id = NULL; char id[PATH_MAX]; - char buf[PATH_MAX]; Eina_Iterator *it; Eina_File_Direct_Info *info; + Eina_Bool free_stack = EINA_FALSE; + struct stat st; + unsigned int i; + int ret = 1; if (!ecore_file_is_dir(path)) return 1; - it = eina_file_stat_ls(path); - if (!it) return 1; + if (!stack) + { + free_stack = EINA_TRUE; + stack = eina_inarray_new(sizeof(struct stat), 16); + if (!stack) goto end; + } + if (stat(path, &st) == -1) goto end; + for (i = 0; i < eina_inarray_count(stack); i++) + { + struct stat *st2 = eina_inarray_nth(stack, i); + if ((st2->st_dev == st.st_dev) && (st2->st_ino == st.st_ino)) + goto end; + } + eina_inarray_push(stack, &st); + + it = eina_file_stat_ls(path); + if (!it) goto end; id[0] = '\0'; EINA_ITERATOR_FOREACH(it, info) { - const char *fname; - - fname = info->path + info->name_start; + const char *fname = info->path + info->name_start; + + if (info->path[info->name_start] == '.') continue; if (base_id) { - if (*base_id) - snprintf(id, sizeof(id), "%s-%s", base_id, fname); + if (*base_id) snprintf(id, sizeof(id), "%s-%s", base_id, fname); else { strncpy(id, fname, PATH_MAX); - id[PATH_MAX - 1] = '\0'; + id[PATH_MAX - 1] = 0; } file_id = id; } - snprintf(buf, sizeof(buf), "%s/%s", path, fname); - if (info->type == EINA_FILE_DIR) + if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || + (info->type == EINA_FILE_DIR)) { if (recurse) - cache_scan(buf, file_id, priority, recurse, changed); + cache_scan(stack, info->path, file_id, priority, recurse, changed); } else { - if (!cache_add(buf, file_id, priority, changed)) + if (!cache_add(info->path, file_id, priority, changed)) { eina_iterator_free(it); - return 0; + ret = 0; + goto end; } } } eina_iterator_free(it); - return 1; +end: + if (free_stack) eina_inarray_free(stack); + return ret; } static int @@ -342,15 +363,16 @@ main(int argc, char **argv) if (!dirs) goto error; EINA_LIST_FREE(dirs, path) - { + { char file_id[PATH_MAX] = { '\0' }; - if (!cache_scan(path, file_id, priority++, 1, &changed)) goto error; + if (!cache_scan(NULL, path, file_id, priority++, 1, &changed)) + goto error; systemdirs = eina_list_append(systemdirs, path); - } + } EINA_LIST_FOREACH(extra_dirs, l, path) - if (!cache_scan(path, NULL, priority, 0, &changed)) goto error; + if (!cache_scan(NULL, path, NULL, priority, 0, &changed)) goto error; /* store util */ #define STORE_HASH_ARRAY(_hash) \ diff --git a/src/bin/efreet/efreet_icon_cache_create.c b/src/bin/efreet/efreet_icon_cache_create.c index 3b22e0cc00..9759b758ca 100644 --- a/src/bin/efreet/efreet_icon_cache_create.c +++ b/src/bin/efreet/efreet_icon_cache_create.c @@ -618,6 +618,10 @@ cache_theme_scan(const char *dir) (entry->type != EINA_FILE_LNK)) continue; + if ((entry->type == EINA_FILE_LNK) && + (!ecore_file_is_dir(entry->path))) + continue; + name = entry->path + entry->name_start; theme = eina_hash_find(icon_themes, name); diff --git a/src/bin/efreet/efreetd_cache.c b/src/bin/efreet/efreetd_cache.c index 23ff1ab656..6ca556ad25 100644 --- a/src/bin/efreet/efreetd_cache.c +++ b/src/bin/efreet/efreetd_cache.c @@ -14,7 +14,12 @@ #include "efreet_private.h" #include "efreetd_cache.h" -static Eina_Hash *change_monitors = NULL; +#include +#include +#include + +static Eina_Hash *icon_change_monitors = NULL; +static Eina_Hash *desktop_change_monitors = NULL; static Ecore_Event_Handler *cache_exe_del_handler = NULL; static Ecore_Event_Handler *cache_exe_data_handler = NULL; @@ -37,6 +42,9 @@ static Eina_Bool icon_queue = EINA_FALSE; static void desktop_changes_monitor_add(const char *path); +static void icon_changes_listen(void); +static void desktop_changes_listen(void); + /* internal */ static Eina_Bool icon_cache_update_cache_cb(void *data EINA_UNUSED) @@ -53,6 +61,11 @@ icon_cache_update_cache_cb(void *data EINA_UNUSED) icon_queue = EINA_FALSE; if ((!icon_flush) && (!icon_exts)) return ECORE_CALLBACK_CANCEL; + if (icon_change_monitors) eina_hash_free(icon_change_monitors); + icon_change_monitors = eina_hash_string_superfast_new + (EINA_FREE_CB(ecore_file_monitor_del)); + icon_changes_listen(); + /* TODO: Queue if already running */ snprintf(file, sizeof(file), "%s/efreet/" MODULE_ARCH "/efreet_icon_cache_create", @@ -90,16 +103,6 @@ icon_cache_update_cache_cb(void *data EINA_UNUSED) return ECORE_CALLBACK_CANCEL; } -static void -cache_icon_update(Eina_Bool flush) -{ - if (icon_cache_timer) - ecore_timer_del(icon_cache_timer); - if (flush) - icon_flush = flush; - icon_cache_timer = ecore_timer_add(1.0, icon_cache_update_cache_cb, NULL); -} - static Eina_Bool desktop_cache_update_cache_cb(void *data EINA_UNUSED) { @@ -114,6 +117,11 @@ desktop_cache_update_cache_cb(void *data EINA_UNUSED) } desktop_queue = EINA_FALSE; + if (desktop_change_monitors) eina_hash_free(desktop_change_monitors); + desktop_change_monitors = eina_hash_string_superfast_new + (EINA_FREE_CB(ecore_file_monitor_del)); + desktop_changes_listen(); + snprintf(file, sizeof(file), "%s/efreet/" MODULE_ARCH "/efreet_desktop_cache_create", eina_prefix_lib_get(pfx)); @@ -130,64 +138,31 @@ desktop_cache_update_cache_cb(void *data EINA_UNUSED) } } INF("Run desktop cache creation: %s", file); - desktop_cache_exe = - ecore_exe_pipe_run(file, ECORE_EXE_PIPE_READ|ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); + desktop_cache_exe = ecore_exe_pipe_run + (file, ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); return ECORE_CALLBACK_CANCEL; } -static Eina_Bool -cache_exe_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +static void +cache_icon_update(Eina_Bool flush) { - Ecore_Exe_Event_Data *ev; - - ev = event; - if (ev->exe == desktop_cache_exe) - { - Eina_Bool update = EINA_FALSE; - - if ((ev->lines) && (*ev->lines->line == 'c')) - update = EINA_TRUE; - - desktop_exists = EINA_TRUE; - send_signal_desktop_cache_update(update); - } - else if (ev->exe == icon_cache_exe) - { - Eina_Bool update = EINA_FALSE; - - if ((ev->lines) && (*ev->lines->line == 'c')) - update = EINA_TRUE; - - send_signal_icon_cache_update(update); - } - return ECORE_CALLBACK_RENEW; + if (icon_cache_timer) ecore_timer_del(icon_cache_timer); + if (flush) icon_flush = flush; + icon_cache_timer = ecore_timer_add(0.2, icon_cache_update_cache_cb, NULL); } -static Eina_Bool -cache_exe_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +void +cache_desktop_update(void) { - Ecore_Exe_Event_Del *ev; - - ev = event; - if (ev->exe == desktop_cache_exe) - { - desktop_cache_exe = NULL; - if (desktop_queue) cache_desktop_update(); - } - else if (ev->exe == icon_cache_exe) - { - icon_cache_exe = NULL; - if (icon_queue) cache_icon_update(EINA_FALSE); - } - return ECORE_CALLBACK_RENEW; + if (desktop_cache_timer) ecore_timer_del(desktop_cache_timer); + desktop_cache_timer = ecore_timer_add(0.2, desktop_cache_update_cache_cb, NULL); } static void icon_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, - Ecore_File_Event event, const char *path) + Ecore_File_Event event, const char *path EINA_UNUSED) { - /* TODO: If we get a stale symlink, we need to rerun cache creation */ switch (event) { case ECORE_FILE_EVENT_NONE: @@ -198,15 +173,52 @@ icon_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, case ECORE_FILE_EVENT_DELETED_FILE: case ECORE_FILE_EVENT_MODIFIED: case ECORE_FILE_EVENT_CLOSED: + // a FILE was changed, added or removed + cache_icon_update(EINA_FALSE); + break; + case ECORE_FILE_EVENT_DELETED_DIRECTORY: case ECORE_FILE_EVENT_CREATED_DIRECTORY: - cache_icon_update(EINA_FALSE); - break; + // the whole tree needs re-monitoring + cache_icon_update(EINA_FALSE); + break; case ECORE_FILE_EVENT_DELETED_SELF: - eina_hash_del_by_key(change_monitors, path); - cache_icon_update(EINA_FALSE); + // the whole tree needs re-monitoring + cache_icon_update(EINA_FALSE); + break; + } +} + +static void +desktop_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, + Ecore_File_Event event, const char *path EINA_UNUSED) +{ + /* TODO: Check for desktop*.cache, as this will be created when app is installed */ + switch (event) + { + case ECORE_FILE_EVENT_NONE: + /* noop */ break; + + case ECORE_FILE_EVENT_CREATED_FILE: + case ECORE_FILE_EVENT_DELETED_FILE: + case ECORE_FILE_EVENT_MODIFIED: + case ECORE_FILE_EVENT_CLOSED: + // a FILE was changed, added or removed + cache_desktop_update(); + break; + + case ECORE_FILE_EVENT_DELETED_DIRECTORY: + case ECORE_FILE_EVENT_CREATED_DIRECTORY: + // the whole tree needs re-monitoring + cache_desktop_update(); + break; + + case ECORE_FILE_EVENT_DELETED_SELF: + // the whole tree needs re-monitoring + cache_desktop_update(); + break; } } @@ -214,21 +226,52 @@ static void icon_changes_monitor_add(const char *path) { Ecore_File_Monitor *mon; + char *realp; - if (eina_hash_find(change_monitors, path)) return; - /* TODO: Check for symlink and monitor the real path */ - mon = ecore_file_monitor_add(path, - icon_changes_cb, - NULL); - if (mon) - eina_hash_add(change_monitors, path, mon); + if (eina_hash_find(icon_change_monitors, path)) return; + realp = ecore_file_realpath(path); + if (!realp) return; + mon = ecore_file_monitor_add(realp, icon_changes_cb, NULL); + free(realp); + if (mon) eina_hash_add(icon_change_monitors, path, mon); } static void -icon_changes_listen_recursive(const char *path, Eina_Bool base) +desktop_changes_monitor_add(const char *path) +{ + Ecore_File_Monitor *mon; + + if (eina_hash_find(desktop_change_monitors, path)) return; + /* TODO: Check for symlink and monitor the real path */ + mon = ecore_file_monitor_add(path, desktop_changes_cb, NULL); + if (mon) + eina_hash_add(desktop_change_monitors, path, mon); +} + +static void +icon_changes_listen_recursive(Eina_Inarray *stack, const char *path, Eina_Bool base) { Eina_Iterator *it; Eina_File_Direct_Info *info; + Eina_Bool free_stack = EINA_FALSE; + struct stat st; + unsigned int i; + + if (!stack) + { + free_stack = EINA_TRUE; + stack = eina_inarray_new(sizeof(struct stat), 16); + if (!stack) return; + } + if (stat(path, &st) == -1) return; + for (i = 0; i < eina_inarray_count(stack); i++) + { + struct stat *st2 = eina_inarray_nth(stack, i); + + if ((st2->st_dev == st.st_dev) && (st2->st_ino == st.st_ino)) + return; + } + eina_inarray_push(stack, &st); if ((!ecore_file_is_dir(path)) && (base)) { @@ -240,16 +283,68 @@ icon_changes_listen_recursive(const char *path, Eina_Bool base) // monitoring the next specific child dir down until we are // monitoring the original path again. } - icon_changes_monitor_add(path); + if (ecore_file_is_dir(path)) icon_changes_monitor_add(path); it = eina_file_stat_ls(path); - if (!it) return; + if (!it) goto end; EINA_ITERATOR_FOREACH(it, info) { + if (info->path[info->name_start] == '.') continue; if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || (info->type == EINA_FILE_DIR)) - icon_changes_monitor_add(info->path); + icon_changes_listen_recursive(stack, info->path, EINA_FALSE); } eina_iterator_free(it); +end: + if (free_stack) eina_inarray_free(stack); +} + +static void +desktop_changes_listen_recursive(Eina_Inarray *stack, const char *path, Eina_Bool base) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *info; + Eina_Bool free_stack = EINA_FALSE; + struct stat st; + unsigned int i; + + if (!stack) + { + free_stack = EINA_TRUE; + stack = eina_inarray_new(sizeof(struct stat), 16); + if (!stack) return; + } + if (stat(path, &st) == -1) return; + for (i = 0; i < eina_inarray_count(stack); i++) + { + struct stat *st2 = eina_inarray_nth(stack, i); + + if ((st2->st_dev == st.st_dev) && (st2->st_ino == st.st_ino)) + return; + } + eina_inarray_push(stack, &st); + if ((!ecore_file_is_dir(path)) && (base)) + { + // XXX: if it doesn't exist... walk the parent dirs back down + // to this path until we find one that doesn't exist, then + // monitor its parent, and treat it specially as it needs + // to look for JUST the creation of this specific child + // and when this child is created, replace this monitor with + // monitoring the next specific child dir down until we are + // monitoring the original path again. + } + if (ecore_file_is_dir(path)) desktop_changes_monitor_add(path); + it = eina_file_stat_ls(path); + if (!it) goto end; + EINA_ITERATOR_FOREACH(it, info) + { + if (info->path[info->name_start] == '.') continue; + if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || + (info->type == EINA_FILE_DIR)) + desktop_changes_listen_recursive(stack, info->path, EINA_FALSE); + } + eina_iterator_free(it); +end: + if (free_stack) eina_inarray_free(stack); } static void @@ -260,102 +355,30 @@ icon_changes_listen(void) char buf[PATH_MAX]; const char *dir; - icon_changes_listen_recursive(efreet_icon_deprecated_user_dir_get(), EINA_TRUE); - icon_changes_listen_recursive(efreet_icon_user_dir_get(), EINA_TRUE); + icon_changes_listen_recursive(NULL, efreet_icon_deprecated_user_dir_get(), EINA_TRUE); + icon_changes_listen_recursive(NULL, efreet_icon_user_dir_get(), EINA_TRUE); EINA_LIST_FOREACH(icon_extra_dirs, l, dir) { - icon_changes_listen_recursive(dir, EINA_TRUE); + icon_changes_listen_recursive(NULL, dir, EINA_TRUE); } xdg_dirs = efreet_data_dirs_get(); EINA_LIST_FOREACH(xdg_dirs, l, dir) { snprintf(buf, sizeof(buf), "%s/icons", dir); - icon_changes_listen_recursive(buf, EINA_TRUE); + icon_changes_listen_recursive(NULL, buf, EINA_TRUE); } #ifndef STRICT_SPEC EINA_LIST_FOREACH(xdg_dirs, l, dir) { snprintf(buf, sizeof(buf), "%s/pixmaps", dir); - icon_changes_listen_recursive(buf, EINA_TRUE); + icon_changes_listen_recursive(NULL, buf, EINA_TRUE); } #endif - icon_changes_monitor_add("/usr/share/pixmaps"); } -static void -desktop_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, - Ecore_File_Event event, const char *path) -{ - const char *ext; - - /* TODO: If we get a stale symlink, we need to rerun cache creation */ - /* TODO: Check for desktop*.cache, as this will be created when app is installed */ - /* TODO: Do efreet_cache_icon_update() when app is installed, as it has the same - * symlink problem */ - switch (event) - { - case ECORE_FILE_EVENT_NONE: - /* noop */ - break; - - case ECORE_FILE_EVENT_CREATED_FILE: - case ECORE_FILE_EVENT_DELETED_FILE: - case ECORE_FILE_EVENT_MODIFIED: - case ECORE_FILE_EVENT_CLOSED: - ext = strrchr(path, '.'); - if (ext && (!strcmp(ext, ".desktop") || !strcmp(ext, ".directory"))) - cache_desktop_update(); - break; - - case ECORE_FILE_EVENT_DELETED_SELF: - case ECORE_FILE_EVENT_DELETED_DIRECTORY: - eina_hash_del_by_key(change_monitors, path); - cache_desktop_update(); - break; - - case ECORE_FILE_EVENT_CREATED_DIRECTORY: - desktop_changes_monitor_add(path); - cache_desktop_update(); - break; - } -} - -static void -desktop_changes_monitor_add(const char *path) -{ - Ecore_File_Monitor *mon; - - if (eina_hash_find(change_monitors, path)) return; - /* TODO: Check for symlink and monitor the real path */ - mon = ecore_file_monitor_add(path, - desktop_changes_cb, - NULL); - if (mon) - eina_hash_add(change_monitors, path, mon); -} - -static void -desktop_changes_listen_recursive(const char *path) -{ - Eina_Iterator *it; - Eina_File_Direct_Info *info; - - if (!ecore_file_is_dir(path)) return; - desktop_changes_monitor_add(path); - it = eina_file_stat_ls(path); - if (!it) return; - EINA_ITERATOR_FOREACH(it, info) - { - if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || - (info->type == EINA_FILE_DIR)) - desktop_changes_listen_recursive(info->path); - } - eina_iterator_free(it); -} - static void desktop_changes_listen(void) { @@ -363,10 +386,9 @@ desktop_changes_listen(void) const char *path; EINA_LIST_FOREACH(desktop_system_dirs, l, path) - desktop_changes_listen_recursive(path); - + desktop_changes_listen_recursive(NULL, path, EINA_TRUE); EINA_LIST_FOREACH(desktop_extra_dirs, l, path) - desktop_changes_listen_recursive(path); + desktop_changes_listen_recursive(NULL, path, EINA_TRUE); } static void @@ -420,7 +442,48 @@ save_list(const char *file, Eina_List *l) static int strcmplen(const void *data1, const void *data2) { - return strncmp(data1, data2, eina_stringshare_strlen(data1)); + return strncmp(data1, data2, eina_stringshare_strlen(data1)); +} + +static Eina_Bool +cache_exe_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Exe_Event_Data *ev = event; + + if (ev->exe == desktop_cache_exe) + { + Eina_Bool update = EINA_FALSE; + + if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE; + desktop_exists = EINA_TRUE; + send_signal_desktop_cache_update(update); + } + else if (ev->exe == icon_cache_exe) + { + Eina_Bool update = EINA_FALSE; + + if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE; + send_signal_icon_cache_update(update); + } + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +cache_exe_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Exe_Event_Del *ev = event; + + if (ev->exe == desktop_cache_exe) + { + desktop_cache_exe = NULL; + if (desktop_queue) cache_desktop_update(); + } + else if (ev->exe == icon_cache_exe) + { + icon_cache_exe = NULL; + if (icon_queue) cache_icon_update(EINA_FALSE); + } + return ECORE_CALLBACK_RENEW; } /* external */ @@ -436,7 +499,7 @@ cache_desktop_dir_add(const char *dir) { /* Path is registered, but maybe not monitored */ const char *path = eina_list_data_get(l); - if (!eina_hash_find(change_monitors, path)) + if (!eina_hash_find(desktop_change_monitors, path)) cache_desktop_update(); } else if (!eina_list_search_unsorted_list(desktop_extra_dirs, EINA_COMPARE_CB(strcmp), san)) @@ -476,14 +539,6 @@ cache_icon_ext_add(const char *ext) } } -void -cache_desktop_update(void) -{ - if (desktop_cache_timer) - ecore_timer_del(desktop_cache_timer); - desktop_cache_timer = ecore_timer_add(1.0, desktop_cache_update_cache_cb, NULL); -} - Eina_Bool cache_desktop_exists(void) { @@ -519,7 +574,10 @@ cache_init(void) goto error; } - change_monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del)); + icon_change_monitors = eina_hash_string_superfast_new + (EINA_FREE_CB(ecore_file_monitor_del)); + desktop_change_monitors = eina_hash_string_superfast_new + (EINA_FREE_CB(ecore_file_monitor_del)); efreet_cache_update = 0; if (!efreet_init()) goto error; @@ -561,9 +619,10 @@ cache_shutdown(void) if (cache_exe_data_handler) ecore_event_handler_del(cache_exe_data_handler); cache_exe_data_handler = NULL; - if (change_monitors) - eina_hash_free(change_monitors); - change_monitors = NULL; + if (icon_change_monitors) eina_hash_free(icon_change_monitors); + icon_change_monitors = NULL; + if (desktop_change_monitors) eina_hash_free(desktop_change_monitors); + desktop_change_monitors = NULL; EINA_LIST_FREE(desktop_system_dirs, data) eina_stringshare_del(data); EINA_LIST_FREE(desktop_extra_dirs, data)