You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1070 lines
31 KiB

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "efreet_alloca.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <Eina.h>
#include <Eet.h>
#include <Ecore.h>
#include <Ecore_File.h>
#define EFREET_MODULE_LOG_DOM _efreet_icon_cache_log_dom
static int _efreet_icon_cache_log_dom = -1;
#include "Efreet.h"
#include "efreet_private.h"
#include "efreet_cache_private.h"
static Eina_Array *exts = NULL;
static Eina_Array *extra_dirs = NULL;
static Eina_Array *strs = NULL;
static Eina_Hash *icon_themes = NULL;
static Eina_Bool
cache_directory_modified(Eina_Hash *dirs, const char *dir)
{
Efreet_Cache_Directory *dcache;
struct stat st;
if (!dirs) return EINA_TRUE;
if (stat(dir, &st) < 0) return EINA_FALSE;
dcache = eina_hash_find(dirs, dir);
if (!dcache)
{
dcache = malloc(sizeof (Efreet_Cache_Directory));
if (!dcache) return EINA_TRUE;
dcache->modified_time = (long long) st.st_mtime;
eina_hash_add(dirs, dir, dcache);
}
else if (dcache->modified_time == (long long) st.st_mtime) return EINA_FALSE;
dcache->modified_time = st.st_mtime;
return EINA_TRUE;
}
static Eina_Bool
cache_extension_lookup(const char *ext)
{
unsigned int i;
for (i = 0; i < exts->count; ++i)
if (!strcmp(exts->data[i], ext))
return EINA_TRUE;
return EINA_FALSE;
}
static Eina_Bool
cache_fallback_scan_dir(Eina_Hash *icons, Eina_Hash *dirs, const char *dir)
{
Eina_Iterator *it;
Eina_File_Direct_Info *entry;
if (!cache_directory_modified(dirs, dir)) return EINA_TRUE;
it = eina_file_stat_ls(dir);
if (!it) return EINA_TRUE;
EINA_ITERATOR_FOREACH(it, entry)
{
Efreet_Cache_Fallback_Icon *icon;
char *name;
char *ext;
unsigned int i;
if (entry->type == EINA_FILE_DIR)
continue;
ext = strrchr(entry->path + entry->name_start, '.');
if (!ext || !cache_extension_lookup(ext))
continue;
/* icon with known extension */
name = entry->path + entry->name_start;
*ext = '\0';
icon = eina_hash_find(icons, name);
if (!icon)
{
icon = NEW(Efreet_Cache_Fallback_Icon, 1);
icon->theme = NULL;
eina_hash_add(icons, name, icon);
}
*ext = '.';
for (i = 0; i < icon->icons_count; ++i)
if (!strcmp(icon->icons[i], entry->path))
break;
if (i != icon->icons_count)
continue;
icon->icons = realloc(icon->icons, sizeof (char *) * (icon->icons_count + 1));
icon->icons[icon->icons_count] = eina_stringshare_add(entry->path);
eina_array_push(strs, icon->icons[icon->icons_count++]);
}
eina_iterator_free(it);
return EINA_TRUE;
}
static Eina_Bool
cache_fallback_scan(Eina_Hash *icons, Eina_Hash *dirs)
{
unsigned int i;
Eina_List *xdg_dirs, *l;
const char *dir;
char path[PATH_MAX];
for (i = 0; i < extra_dirs->count; i++)
cache_fallback_scan_dir(icons, dirs, extra_dirs->data[i]);
cache_fallback_scan_dir(icons, dirs, efreet_icon_deprecated_user_dir_get());
cache_fallback_scan_dir(icons, dirs, efreet_icon_user_dir_get());
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/icons", dir);
cache_fallback_scan_dir(icons, dirs, path);
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/pixmaps", dir);
cache_fallback_scan_dir(icons, dirs, path);
}
#endif
cache_fallback_scan_dir(icons, dirs, "/usr/share/pixmaps");
return EINA_TRUE;
}
static Eina_Bool
check_fallback_changed(Efreet_Cache_Icon_Theme *theme)
{
unsigned int i;
Eina_List *xdg_dirs, *l;
const char *dir;
char path[PATH_MAX];
/* Check if the dirs we have cached are changed */
if (theme->dirs)
{
Eina_Iterator *it;
Eina_Bool changed = EINA_FALSE;
it = eina_hash_iterator_key_new(theme->dirs);
EINA_ITERATOR_FOREACH(it, dir)
{
changed = !ecore_file_exists(dir);
if (changed) break;
changed = cache_directory_modified(theme->dirs, dir);
if (changed) break;
}
eina_iterator_free(it);
if (changed) return EINA_TRUE;
}
/* Check if spec dirs have changed */
for (i = 0; i < extra_dirs->count; i++)
if (cache_directory_modified(theme->dirs, extra_dirs->data[i])) return EINA_TRUE;
if (cache_directory_modified(theme->dirs, efreet_icon_deprecated_user_dir_get())) return EINA_TRUE;
if (cache_directory_modified(theme->dirs, efreet_icon_user_dir_get())) return EINA_TRUE;
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/icons", dir);
if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/pixmaps", dir);
if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
}
#endif
if (cache_directory_modified(theme->dirs, "/usr/share/pixmaps")) return EINA_TRUE;
return EINA_FALSE;
}
static Eina_Bool
cache_scan_path_dir(Efreet_Icon_Theme *theme,
const char *path,
Efreet_Icon_Theme_Directory *dir,
Eina_Hash *icons)
{
Eina_Iterator *it;
char buf[PATH_MAX];
Eina_File_Direct_Info *entry;
snprintf(buf, sizeof(buf), "%s/%s", path, dir->name);
it = eina_file_stat_ls(buf);
if (!it) return EINA_TRUE;
EINA_ITERATOR_FOREACH(it, entry)
{
Efreet_Cache_Icon *icon;
char *name;
char *ext;
unsigned int i;
if (entry->type == EINA_FILE_DIR)
continue;
ext = strrchr(entry->path + entry->name_start, '.');
if (!ext || !cache_extension_lookup(ext))
continue;
/* icon with known extension */
name = entry->path + entry->name_start;
*ext = '\0';
icon = eina_hash_find(icons, name);
if (!icon)
{
icon = NEW(Efreet_Cache_Icon, 1);
icon->theme = eina_stringshare_add(theme->name.internal);
eina_array_push(strs, icon->theme);
eina_hash_add(icons, name, icon);
}
/* find if we have the same icon in another type */
for (i = 0; i < icon->icons_count; ++i)
{
if ((icon->icons[i]->type == dir->type) &&
(icon->icons[i]->normal == dir->size.normal) &&
(icon->icons[i]->max == dir->size.max) &&
(icon->icons[i]->min == dir->size.min))
break;
}
*ext = '.';
if (i != icon->icons_count)
{
unsigned int j;
/* check if the path already exist */
for (j = 0; j < icon->icons[i]->paths_count; ++j)
if (!strcmp(icon->icons[i]->paths[j], entry->path))
break;
if (j != icon->icons[i]->paths_count)
continue;
/* If we are inherited, check if we already have extension */
if (strcmp(icon->theme, theme->name.internal))
{
const char *ext2;
int has_ext = 0;
for (j = 0; j < icon->icons[i]->paths_count; ++j)
{
ext2 = strrchr(icon->icons[i]->paths[j], '.');
if (ext2)
{
ext2++;
has_ext = !strcmp((ext + 1), ext2);
if (has_ext) break;
}
}
if (has_ext)
continue;
}
}
/* no icon match so add a new one */
/* only allow to add new icon for main theme
* if we allow inherited theme to add new icons,
* we will get weird effects when icon scales
*/
else if (!strcmp(icon->theme, theme->name.internal))
{
icon->icons = realloc(icon->icons,
sizeof (Efreet_Cache_Icon_Element*) * (++icon->icons_count));
icon->icons[i] = NEW(Efreet_Cache_Icon_Element, 1);
icon->icons[i]->type = dir->type;
icon->icons[i]->normal = dir->size.normal;
icon->icons[i]->min = dir->size.min;
icon->icons[i]->max = dir->size.max;
icon->icons[i]->paths = NULL;
icon->icons[i]->paths_count = 0;
}
else
{
continue;
}
/* and finally store the path */
icon->icons[i]->paths = realloc(icon->icons[i]->paths,
sizeof (char*) * (icon->icons[i]->paths_count + 1));
icon->icons[i]->paths[icon->icons[i]->paths_count] = eina_stringshare_add(entry->path);
eina_array_push(strs, icon->icons[i]->paths[icon->icons[i]->paths_count++]);
}
eina_iterator_free(it);
return EINA_TRUE;
}
static Eina_Bool
cache_scan_path(Efreet_Icon_Theme *theme, Eina_Hash *icons, const char *path)
{
Eina_List *l;
Efreet_Icon_Theme_Directory *dir;
EINA_LIST_FOREACH(theme->directories, l, dir)
if (!cache_scan_path_dir(theme, path, dir, icons)) return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eina_Hash *icons)
{
Eina_List *l;
const char *path;
const char *name;
if (!theme) return EINA_TRUE;
if (eina_hash_find(themes, theme->name.internal)) return EINA_TRUE;
eina_hash_direct_add(themes, theme->name.internal, theme);
/* scan theme */
EINA_LIST_FOREACH(theme->paths, l, path)
if (!cache_scan_path(theme, icons, path)) return EINA_FALSE;
/* scan inherits */
if (theme->inherits)
{
EINA_LIST_FOREACH(theme->inherits, l, name)
{
Efreet_Icon_Theme *inherit;
inherit = eina_hash_find(icon_themes, name);
if (!inherit)
INF("Theme `%s` not found for `%s`.",
name, theme->name.internal);
if (!cache_scan(inherit, themes, icons)) return EINA_FALSE;
}
}
else if (strcmp(theme->name.internal, "hicolor"))
{
theme = eina_hash_find(icon_themes, "hicolor");
if (!cache_scan(theme, themes, icons)) return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
check_changed(Efreet_Cache_Icon_Theme *theme)
{
Eina_List *l;
const char *name;
if (!theme) return EINA_FALSE;
if (theme->changed) return EINA_TRUE;
if (theme->theme.inherits)
{
EINA_LIST_FOREACH(theme->theme.inherits, l, name)
{
Efreet_Cache_Icon_Theme *inherit;
inherit = eina_hash_find(icon_themes, name);
if (!inherit)
INF("Theme `%s` not found for `%s`.",
name, theme->theme.name.internal);
if (check_changed(inherit)) return EINA_TRUE;
}
}
else if (strcmp(theme->theme.name.internal, "hicolor"))
{
theme = eina_hash_find(icon_themes, "hicolor");
if (check_changed(theme)) return EINA_TRUE;
}
return EINA_FALSE;
}
static Efreet_Icon_Theme_Directory *
icon_theme_directory_new(Efreet_Ini *ini, const char *name)
{
Efreet_Icon_Theme_Directory *dir;
int val;
const char *tmp;
if (!ini) return NULL;
dir = NEW(Efreet_Icon_Theme_Directory, 1);
if (!dir) return NULL;
dir->name = eina_stringshare_add(name);
eina_array_push(strs, dir->name);
efreet_ini_section_set(ini, name);
tmp = efreet_ini_string_get(ini, "Context");
if (tmp)
{
if (!strcasecmp(tmp, "Actions"))
dir->context = EFREET_ICON_THEME_CONTEXT_ACTIONS;
else if (!strcasecmp(tmp, "Devices"))
dir->context = EFREET_ICON_THEME_CONTEXT_DEVICES;
else if (!strcasecmp(tmp, "FileSystems"))
dir->context = EFREET_ICON_THEME_CONTEXT_FILESYSTEMS;
else if (!strcasecmp(tmp, "MimeTypes"))
dir->context = EFREET_ICON_THEME_CONTEXT_MIMETYPES;
}
/* Threshold is fallback */
dir->type = EFREET_ICON_SIZE_TYPE_THRESHOLD;
tmp = efreet_ini_string_get(ini, "Type");
if (tmp)
{
if (!strcasecmp(tmp, "Fixed"))
dir->type = EFREET_ICON_SIZE_TYPE_FIXED;
else if (!strcasecmp(tmp, "Scalable"))
dir->type = EFREET_ICON_SIZE_TYPE_SCALABLE;
}
dir->size.normal = efreet_ini_int_get(ini, "Size");
if (dir->type == EFREET_ICON_SIZE_TYPE_THRESHOLD)
{
val = efreet_ini_int_get(ini, "Threshold");
if (val < 0) val = 2;
dir->size.max = dir->size.normal + val;
dir->size.min = dir->size.normal - val;
}
else if (dir->type == EFREET_ICON_SIZE_TYPE_SCALABLE)
{
val = efreet_ini_int_get(ini, "MinSize");
if (val < 0) dir->size.min = dir->size.normal;
else dir->size.min = val;
val = efreet_ini_int_get(ini, "MaxSize");
if (val < 0) dir->size.max = dir->size.normal;
else dir->size.max = val;
}
return dir;
}
static Eina_Bool
icon_theme_index_read(Efreet_Cache_Icon_Theme *theme, const char *path)
{
Efreet_Ini *ini;
Efreet_Icon_Theme_Directory *dir;
const char *tmp;
struct stat st;
if (!theme || !path) return EINA_FALSE;
if (stat(path, &st) < 0) return EINA_FALSE;
if (theme->path && !strcmp(theme->path, path) && theme->last_cache_check >= (long long) st.st_mtime)
{
/* no change */
theme->valid = 1;
return EINA_TRUE;
}
if (!theme->path || strcmp(theme->path, path))
{
theme->path = eina_stringshare_add(path);
eina_array_push(strs, theme->path);
}
if ((long long) st.st_mtime > theme->last_cache_check)
theme->last_cache_check = (long long) st.st_mtime;
theme->changed = 1;
ini = efreet_ini_new(path);
if (!ini) return EINA_FALSE;
if (!ini->data)
{
efreet_ini_free(ini);
return EINA_FALSE;
}
efreet_ini_section_set(ini, "Icon Theme");
tmp = efreet_ini_localestring_get(ini, "Name");
if (tmp)
{
theme->theme.name.name = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.name.name);
}
tmp = efreet_ini_localestring_get(ini, "Comment");
if (tmp)
{
theme->theme.comment = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.comment);
}
tmp = efreet_ini_string_get(ini, "Example");
if (tmp)
{
theme->theme.example_icon = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.example_icon);
}
theme->hidden = efreet_ini_boolean_get(ini, "Hidden");
theme->valid = 1;
/* Check the inheritance. If there is none we inherit from the hicolor theme */
tmp = efreet_ini_string_get(ini, "Inherits");
if (tmp)
{
char *t, *s, *p;
const char *i;
size_t len;
len = strlen(tmp) + 1;
t = alloca(len);
memcpy(t, tmp, len);
s = t;
p = strchr(s, ',');
while (p)
{
*p = '\0';
i = eina_stringshare_add(s);
theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
eina_array_push(strs, i);
s = ++p;
p = strchr(s, ',');
}
i = eina_stringshare_add(s);
theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
eina_array_push(strs, i);
}
/* make sure this one is done last as setting the directory will change
* the ini section ... */
tmp = efreet_ini_string_get(ini, "Directories");
if (tmp)
{
char *t, *s, *p;
size_t len;
len = strlen(tmp) + 1;
t = alloca(len);
memcpy(t, tmp, len);
s = t;
p = s;
while ((p) && (*s))
{
p = strchr(s, ',');
if (p) *p = '\0';
dir = icon_theme_directory_new(ini, s);
if (!dir) goto error;
theme->theme.directories = eina_list_append(theme->theme.directories, dir);
if (p) s = ++p;
}
}
error:
efreet_ini_free(ini);
return EINA_TRUE;
}
static Eina_Bool
cache_theme_scan(const char *dir)
{
Eina_Iterator *it;
Eina_File_Direct_Info *entry;
it = eina_file_stat_ls(dir);
if (!it) return EINA_TRUE;
EINA_ITERATOR_FOREACH(it, entry)
{
Efreet_Cache_Icon_Theme *theme;
const char *name;
const char *path;
char buf[PATH_MAX];
struct stat st;
if (stat(entry->path, &st) < 0) continue;
if ((entry->type != EINA_FILE_DIR) &&
(entry->type != EINA_FILE_LNK))
continue;
name = entry->path + entry->name_start;
theme = eina_hash_find(icon_themes, name);
if (!theme)
{
theme = NEW(Efreet_Cache_Icon_Theme, 1);
theme->theme.name.internal = eina_stringshare_add(name);
eina_array_push(strs, theme->theme.name.internal);
eina_hash_direct_add(icon_themes,
(void *)theme->theme.name.internal, theme);
theme->changed = 1;
}
if ((long long) st.st_mtime > theme->last_cache_check)
{
theme->last_cache_check = (long long) st.st_mtime;
theme->changed = 1;
}
/* TODO: We need to handle change in order of included paths */
if (!eina_list_search_unsorted(theme->theme.paths, EINA_COMPARE_CB(strcmp), entry->path))
{
path = eina_stringshare_add(entry->path);
theme->theme.paths = eina_list_append(theme->theme.paths, path);
eina_array_push(strs, path);
theme->changed = 1;
}
/* we're already valid so no reason to check for an index.theme file */
if (theme->valid) continue;
/* if the index.theme file exists we parse it into the theme */
memcpy(buf, entry->path, entry->path_length);
memcpy(buf + entry->path_length, "/index.theme", sizeof("/index.theme"));
if (ecore_file_exists(buf))
{
if (!icon_theme_index_read(theme, buf))
theme->valid = 0;
}
}
eina_iterator_free(it);
return EINA_TRUE;
}
static int
cache_lock_file(void)
{
char file[PATH_MAX];
struct flock fl;
int lockfd;
snprintf(file, sizeof(file), "%s/efreet/icon_data.lock", efreet_cache_home_get());
lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (lockfd < 0) return -1;
efreet_fsetowner(lockfd);
memset(&fl, 0, sizeof(struct flock));
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
if (fcntl(lockfd, F_SETLK, &fl) < 0)
{
WRN("LOCKED! You may want to delete %s if this persists", file);
close(lockfd);
return -1;
}
return lockfd;
}
static void
icon_theme_free(Efreet_Cache_Icon_Theme *theme)
{
void *data;
eina_list_free(theme->theme.paths);
eina_list_free(theme->theme.inherits);
EINA_LIST_FREE(theme->theme.directories, data)
free(data);
if (theme->dirs) efreet_hash_free(theme->dirs, free);
free(theme);
}
int
main(int argc, char **argv)
{
/* TODO:
* - Add file monitor on files, so that we catch changes on files
* during whilst this program runs.
* - Maybe linger for a while to reduce number of cache re-creates.
*/
Eina_Iterator *it;
Efreet_Cache_Version *icon_version;
Efreet_Cache_Version *theme_version;
Efreet_Cache_Icon_Theme *theme;
Eet_Data_Descriptor *theme_edd;
Eet_Data_Descriptor *icon_edd;
Eet_Data_Descriptor *fallback_edd;
Eet_File *icon_ef;
Eet_File *theme_ef;
Eina_List *xdg_dirs = NULL;
Eina_List *l = NULL;
char file[PATH_MAX];
const char *path;
char *dir = NULL;
Eina_Bool changed = EINA_FALSE;
Eina_Bool flush = EINA_FALSE;
int lockfd = -1;
char **keys;
int num, i;
/* init external subsystems */
if (!eina_init()) return -1;
_efreet_icon_cache_log_dom =
eina_log_domain_register("efreet_icon_cache", EFREET_DEFAULT_LOG_COLOR);
if (_efreet_icon_cache_log_dom < 0)
{
EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_icon_cache.");
return -1;
}
eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_ERR);
exts = eina_array_new(10);
extra_dirs = eina_array_new(10);
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-v"))
eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_DBG);
else if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--h")) ||
(!strcmp(argv[i], "--help")))
{
printf("Options:\n");
printf(" -v Verbose mode\n");
printf(" -e .ext1 .ext2 Extensions\n");
printf(" -d dir1 dir2 Extra dirs\n");
printf(" -f Flush\n");
exit(0);
}
else if (!strcmp(argv[i], "-e"))
{
while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
eina_array_push(exts, argv[++i]);
}
else if (!strcmp(argv[i], "-d"))
{
while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
eina_array_push(extra_dirs, argv[++i]);
}
else if (!strcmp(argv[i], "-d"))
flush = EINA_TRUE;
}
if (!eet_init()) return -1;
if (!ecore_init()) return -1;
efreet_cache_update = 0;
/* finish efreet init */
if (!efreet_init()) goto on_error;
strs = eina_array_new(32);
/* create homedir */
snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get());
if (!ecore_file_exists(file))
{
if (!ecore_file_mkpath(file)) return -1;
efreet_setowner(file);
}
/* lock process, so that we only run one copy of this program */
lockfd = cache_lock_file();
if (lockfd == -1) goto on_error;
/* Need to init edd's, so they are like we want, not like userspace wants */
icon_edd = efreet_icon_edd();
fallback_edd = efreet_icon_fallback_edd();
theme_edd = efreet_icon_theme_edd(EINA_TRUE);
icon_themes = eina_hash_string_superfast_new(EINA_FREE_CB(icon_theme_free));
INF("opening theme cache");
/* open theme file */
theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
if (!theme_ef) goto on_error_efreet;
theme_version = eet_data_read(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if (theme_version &&
((theme_version->major != EFREET_ICON_CACHE_MAJOR) ||
(theme_version->minor != EFREET_ICON_CACHE_MINOR)))
{
// delete old cache
eet_close(theme_ef);
if (unlink(efreet_icon_theme_cache_file()) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
if (!theme_ef) goto on_error_efreet;
}
if (!theme_version)
theme_version = NEW(Efreet_Cache_Version, 1);
theme_version->major = EFREET_ICON_CACHE_MAJOR;
theme_version->minor = EFREET_ICON_CACHE_MINOR;
if (flush)
changed = EINA_TRUE;
if (exts->count == 0)
{
ERR("Need to pass extensions to icon cache create process");
goto on_error_efreet;
}
keys = eet_list(theme_ef, "*", &num);
if (keys)
{
for (i = 0; i < num; i++)
{
if (!strncmp(keys[i], "__efreet", 8)) continue;
theme = eet_data_read(theme_ef, theme_edd, keys[i]);
if (theme)
{
theme->valid = 0;
eina_hash_direct_add(icon_themes, theme->theme.name.internal, theme);
}
}
free(keys);
}
INF("scan for themes");
/* scan themes */
cache_theme_scan(efreet_icon_deprecated_user_dir_get());
cache_theme_scan(efreet_icon_user_dir_get());
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(file, sizeof(file), "%s/icons", dir);
cache_theme_scan(file);
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(file, sizeof(file), "%s/pixmaps", dir);
cache_theme_scan(file);
}
#endif
cache_theme_scan("/usr/share/pixmaps");
/* scan icons */
it = eina_hash_iterator_data_new(icon_themes);
EINA_ITERATOR_FOREACH(it, theme)
{
if (!theme->valid) continue;
#ifndef STRICT_SPEC
if (!theme->theme.name.name) continue;
#endif
INF("scan theme %s", theme->theme.name.name);
theme->changed = check_changed(theme);
if (flush)
theme->changed = EINA_TRUE;
INF("open icon file");
/* open icon file */
icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if (theme->changed || (icon_version &&
((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
(icon_version->minor != EFREET_ICON_CACHE_MINOR))))
{
// delete old cache
eet_close(icon_ef);
if (unlink(efreet_icon_cache_file(theme->theme.name.internal)) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
theme->changed = EINA_TRUE;
}
if (theme->changed)
changed = EINA_TRUE;
if (!icon_version)
icon_version = NEW(Efreet_Cache_Version, 1);
icon_version->major = EFREET_ICON_CACHE_MAJOR;
icon_version->minor = EFREET_ICON_CACHE_MINOR;
if (theme->changed)
{
Eina_Hash *themes;
Eina_Hash *icons;
themes = eina_hash_string_superfast_new(NULL);
icons = eina_hash_string_superfast_new(NULL);
INF("scan icons\n");
if (cache_scan(&(theme->theme), themes, icons))
{
Eina_Iterator *icons_it;
Eina_Hash_Tuple *tuple;
INF("generated: '%s' %i (%i)",
theme->theme.name.internal,
theme->changed,
eina_hash_population(icons));
icons_it = eina_hash_iterator_tuple_new(icons);
EINA_ITERATOR_FOREACH(icons_it, tuple)
eet_data_write(icon_ef, icon_edd, tuple->key, tuple->data, 1);
eina_iterator_free(icons_it);
INF("theme change: %s %lld", theme->theme.name.internal, theme->last_cache_check);
eet_data_write(theme_ef, theme_edd, theme->theme.name.internal, theme, 1);
}
eina_hash_free(themes);
eina_hash_free(icons);
changed = EINA_TRUE;
}
eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1);
eet_close(icon_ef);
efreet_setowner(efreet_icon_cache_file(theme->theme.name.internal));
free(icon_version);
}
eina_iterator_free(it);
INF("scan fallback icons");
theme = eet_data_read(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK);
if (!theme)
{
theme = NEW(Efreet_Cache_Icon_Theme, 1);
theme->changed = EINA_TRUE;
}
if (flush)
theme->changed = EINA_TRUE;
INF("open fallback file");
/* open icon file */
icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if (theme->changed || (icon_version &&
((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
(icon_version->minor != EFREET_ICON_CACHE_MINOR))))
{
// delete old cache
eet_close(icon_ef);
if (unlink(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
theme->changed = EINA_TRUE;
}
if (!theme->changed)
theme->changed = check_fallback_changed(theme);
if (theme->changed && theme->dirs)
{
efreet_hash_free(theme->dirs, free);
theme->dirs = NULL;
}
if (!theme->dirs)
theme->dirs = eina_hash_string_superfast_new(NULL);
if (theme->changed)
changed = EINA_TRUE;
if (!icon_version)
icon_version = NEW(Efreet_Cache_Version, 1);
icon_version->major = EFREET_ICON_CACHE_MAJOR;
icon_version->minor = EFREET_ICON_CACHE_MINOR;
if (theme->changed)
{
Eina_Hash *icons;
icons = eina_hash_string_superfast_new(NULL);
INF("scan fallback icons");
/* Save fallback in the right part */
if (cache_fallback_scan(icons, theme->dirs))
{
Eina_Iterator *icons_it;
Eina_Hash_Tuple *tuple;
INF("generated: fallback %i (%i)", theme->changed, eina_hash_population(icons));
icons_it = eina_hash_iterator_tuple_new(icons);
EINA_ITERATOR_FOREACH(icons_it, tuple)
eet_data_write(icon_ef, fallback_edd, tuple->key, tuple->data, 1);
eina_iterator_free(icons_it);
}
eina_hash_free(icons);
eet_data_write(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK, theme, 1);
}
icon_theme_free(theme);
eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1);
eet_close(icon_ef);
efreet_setowner(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK));
free(icon_version);
eina_hash_free(icon_themes);
/* save data */
eet_data_write(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION, theme_version, 1);
eet_close(theme_ef);
efreet_setowner(efreet_icon_theme_cache_file());
free(theme_version);
{
char c = 'n';
if (changed) c = 'c';
printf("%c\n", c);
}
INF("done");
on_error_efreet:
efreet_shutdown();
if (theme_ef) eet_close(theme_ef);
on_error:
if (lockfd >= 0) close(lockfd);
while ((path = eina_array_pop(strs)))
eina_stringshare_del(path);
eina_array_free(strs);
eina_array_free(exts);
eina_array_free(extra_dirs);
ecore_shutdown();
eet_shutdown();
eina_log_domain_unregister(_efreet_icon_cache_log_dom);
eina_shutdown();
return 0;
}