Please test efreet_icon_cache_create and efreet_icon_cache_dump, and check if it is fast enough on a slow system. SVN revision: 54575devs/devilhorns/wayland_egl
parent
e8ce2014b0
commit
b83238ae14
8 changed files with 642 additions and 1 deletions
@ -0,0 +1,319 @@ |
||||
#ifdef HAVE_CONFIG_H |
||||
# include <config.h> |
||||
#endif |
||||
#include <limits.h> |
||||
#include <stdio.h> |
||||
#include <dirent.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/mman.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <errno.h> |
||||
|
||||
#include <Eina.h> |
||||
#include <Ecore.h> |
||||
#include <Ecore_File.h> |
||||
|
||||
#include "Efreet.h" |
||||
#include "efreet_private.h" |
||||
|
||||
static Eet_Data_Descriptor *edd = NULL; |
||||
|
||||
static Eina_List *extensions; |
||||
|
||||
int verbose = 0; |
||||
|
||||
static int |
||||
cache_scan_path_dir(Efreet_Icon_Theme *theme, const char *path, Efreet_Icon_Theme_Directory *dir, Eet_File *ef, int *changed) |
||||
{ |
||||
Eina_Iterator *it; |
||||
char buf[PATH_MAX]; |
||||
const char *ext, *file; |
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", path, dir->name); |
||||
it = eina_file_ls(buf); |
||||
if (!it) return 1; |
||||
EINA_ITERATOR_FOREACH(it, file) |
||||
{ |
||||
Eina_List *l; |
||||
Efreet_Cache_Icon *icon; |
||||
Efreet_Cache_Icon_Element *elem = NULL, *oelem = NULL; |
||||
char *name, *tmp; |
||||
|
||||
ext = strrchr(file, '.'); |
||||
if (!ext) continue; |
||||
ext = eina_stringshare_add(ext); |
||||
if (!eina_list_data_find(extensions, ext)) |
||||
{ |
||||
eina_stringshare_del(ext); |
||||
continue; |
||||
} |
||||
/* icon with known extension */ |
||||
name = strdup(ecore_file_file_get(file)); |
||||
tmp = strrchr(name, '.'); |
||||
if (tmp) *tmp = '\0'; |
||||
icon = eet_data_read(ef, edd, name); |
||||
if (!icon) |
||||
{ |
||||
icon = NEW(Efreet_Cache_Icon, 1); |
||||
icon->free = 1; |
||||
#if 0 |
||||
icon->name = eina_stringshare_add(name); |
||||
#endif |
||||
icon->theme = eina_stringshare_add(theme->name.internal); |
||||
#if 0 |
||||
icon->context = dir->context; |
||||
#endif |
||||
} |
||||
else if (strcmp(icon->theme, theme->name.internal)) |
||||
{ |
||||
/* We got this icon from a parent theme */ |
||||
free(name); |
||||
continue; |
||||
} |
||||
|
||||
/* find if we have the same icon in another type */ |
||||
EINA_LIST_FOREACH(icon->icons, l, oelem) |
||||
{ |
||||
if ((oelem->type == dir->type) && |
||||
(oelem->size.normal == dir->size.normal) && |
||||
(oelem->size.max == dir->size.max) && |
||||
(oelem->size.min == dir->size.min)) |
||||
{ |
||||
elem = oelem; |
||||
break; |
||||
} |
||||
} |
||||
if (elem) |
||||
{ |
||||
elem->paths = eina_list_append(elem->paths, eina_stringshare_ref(file)); |
||||
} |
||||
else |
||||
{ |
||||
elem = NEW(Efreet_Cache_Icon_Element, 1); |
||||
elem->paths = eina_list_append(elem->paths, eina_stringshare_ref(file)); |
||||
elem->type = dir->type; |
||||
elem->size.normal = dir->size.normal; |
||||
elem->size.min = dir->size.min; |
||||
elem->size.max = dir->size.max; |
||||
icon->icons = eina_list_append(icon->icons, elem); |
||||
} |
||||
if (!eet_data_write(ef, edd, name, icon, 1)) |
||||
{ |
||||
free(name); |
||||
break; |
||||
} |
||||
efreet_cache_icon_free(icon); |
||||
free(name); |
||||
} |
||||
eina_iterator_free(it); |
||||
return 1; |
||||
} |
||||
|
||||
static int |
||||
cache_scan_path(Efreet_Icon_Theme *theme, const char *path, Eet_File *ef, int *changed) |
||||
{ |
||||
Eina_List *l; |
||||
Efreet_Icon_Theme_Directory *dir; |
||||
|
||||
EINA_LIST_FOREACH(theme->directories, l, dir) |
||||
if (!cache_scan_path_dir(theme, path, dir, ef, changed)) return 0; |
||||
return 1; |
||||
} |
||||
|
||||
static int |
||||
cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eet_File *ef, int *changed) |
||||
{ |
||||
Eina_List *l; |
||||
const char *path; |
||||
const char *name; |
||||
|
||||
if (!theme) return 1; |
||||
if (eina_hash_find(themes, theme->name.internal)) return 1; |
||||
eina_hash_direct_add(themes, theme->name.internal, theme); |
||||
/* TODO: flush icons after each theme */ |
||||
/* TODO: Maybe always read entry from eet, so when can check changed */ |
||||
|
||||
/* scan theme */ |
||||
EINA_LIST_FOREACH(theme->paths, l, path) |
||||
if (!cache_scan_path(theme, path, ef, changed)) return 0; |
||||
|
||||
/* scan inherits */ |
||||
if (theme->inherits) |
||||
{ |
||||
EINA_LIST_FOREACH(theme->inherits, l, name) |
||||
{ |
||||
theme = efreet_icon_theme_find(name); |
||||
if (!cache_scan(theme, themes, ef, changed)) return 0; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
theme = efreet_icon_theme_find("hicolor"); |
||||
if (!cache_scan(theme, themes, ef, changed)) return 0; |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
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. |
||||
*/ |
||||
char file[PATH_MAX]; |
||||
Eina_List *l = NULL; |
||||
Efreet_Icon_Theme *theme; |
||||
char *dir = NULL; |
||||
int fd = -1, tmpfd; |
||||
int changed = 0; |
||||
int i; |
||||
struct flock fl; |
||||
const char *exts[] = { ".png", ".xpm", ".svg", NULL }; |
||||
|
||||
for (i = 1; i < argc; i++) |
||||
{ |
||||
if (!strcmp(argv[i], "-v")) verbose = 1; |
||||
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"); |
||||
exit(0); |
||||
} |
||||
} |
||||
/* init external subsystems */ |
||||
if (!eina_init()) goto eina_error; |
||||
if (!eet_init()) goto eet_error; |
||||
if (!ecore_init()) goto eet_error; |
||||
|
||||
for (i = 0; exts[i]; i++) |
||||
extensions = eina_list_append(extensions, eina_stringshare_add(exts[i])); |
||||
|
||||
efreet_cache_update = 0; |
||||
|
||||
/* create homedir */ |
||||
snprintf(file, sizeof(file), "%s/.efreet", efreet_home_dir_get()); |
||||
if (!ecore_file_mkpath(file)) goto efreet_error; |
||||
|
||||
/* lock process, so that we only run one copy of this program */ |
||||
snprintf(file, sizeof(file), "%s/.efreet/icon_data.lock", efreet_home_dir_get()); |
||||
fd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
||||
if (fd < 0) goto efreet_error; |
||||
memset(&fl, 0, sizeof(struct flock)); |
||||
fl.l_type = F_WRLCK; |
||||
fl.l_whence = SEEK_SET; |
||||
if (fcntl(fd, F_SETLK, &fl) < 0) |
||||
{ |
||||
if (verbose) |
||||
{ |
||||
printf("LOCKED! You may want to delete %s if this persists\n", file); |
||||
} |
||||
goto efreet_error; |
||||
} |
||||
|
||||
/* create dir for icon cache */ |
||||
dir = ecore_file_dir_get(efreet_icon_cache_file("")); |
||||
if (!ecore_file_mkpath(dir)) goto efreet_error; |
||||
free(dir); |
||||
|
||||
/* finish efreet init */ |
||||
if (!efreet_init()) goto efreet_error; |
||||
edd = efreet_icon_edd_init(); |
||||
if (!edd) goto edd_error; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
for (i = 1; i < argc; i++) |
||||
{ |
||||
theme = efreet_icon_theme_find(argv[i]); |
||||
if (theme) l = eina_list_append(l, theme); |
||||
} |
||||
} |
||||
if (!l) |
||||
l = efreet_icon_theme_list_get(); |
||||
EINA_LIST_FREE(l, theme) |
||||
{ |
||||
Eet_File *ef; |
||||
Eina_Hash *themes; |
||||
changed = 0; |
||||
|
||||
/* create cache */ |
||||
/* TODO: Copy old cache to temp file, so we can check whether something has changed */ |
||||
snprintf(file, sizeof(file), "%s.XXXXXX", efreet_icon_cache_file(theme->name.internal)); |
||||
tmpfd = mkstemp(file); |
||||
if (tmpfd < 0) goto error; |
||||
close(tmpfd); |
||||
ef = eet_open(file, EET_FILE_MODE_READ_WRITE); |
||||
if (!ef) goto error; |
||||
|
||||
themes = eina_hash_string_superfast_new(NULL); |
||||
if (!cache_scan(theme, themes, ef, &changed)) |
||||
{ |
||||
eet_close(ef); |
||||
eina_hash_free(themes); |
||||
goto error; |
||||
} |
||||
|
||||
changed = 1; |
||||
/* check if old and new caches contain the same number of entries */ |
||||
#if 0 |
||||
if (!changed) |
||||
{ |
||||
Eet_File *old; |
||||
|
||||
old = eet_open(efreet_icon_cache_file(), EET_FILE_MODE_READ); |
||||
if (!old || eet_num_entries(old) != eet_num_entries(ef)) changed = 1; |
||||
if (old) eet_close(old); |
||||
|
||||
} |
||||
#endif |
||||
|
||||
/* cleanup */ |
||||
eet_close(ef); |
||||
eina_hash_free(themes); |
||||
|
||||
/* unlink old cache files */ |
||||
if (changed) |
||||
{ |
||||
if (unlink(efreet_icon_cache_file(theme->name.internal)) < 0) |
||||
{ |
||||
if (errno != ENOENT) goto error; |
||||
} |
||||
/* rename tmp files to real files */ |
||||
if (rename(file, efreet_icon_cache_file(theme->name.internal)) < 0) goto error; |
||||
} |
||||
else |
||||
{ |
||||
unlink(file); |
||||
} |
||||
|
||||
eet_clearcache(); |
||||
} |
||||
|
||||
eina_list_free(extensions); |
||||
|
||||
efreet_shutdown(); |
||||
ecore_shutdown(); |
||||
eet_shutdown(); |
||||
eina_shutdown(); |
||||
close(fd); |
||||
return 0; |
||||
error: |
||||
printf("error\n"); |
||||
IF_FREE(dir); |
||||
edd_error: |
||||
efreet_shutdown(); |
||||
efreet_error: |
||||
eet_shutdown(); |
||||
eet_error: |
||||
eina_shutdown(); |
||||
eina_error: |
||||
if (fd > 0) close(fd); |
||||
return 1; |
||||
} |
@ -0,0 +1,100 @@ |
||||
#ifdef HAVE_CONFIG_H |
||||
# include <config.h> |
||||
#endif |
||||
#include <limits.h> |
||||
#include <stdio.h> |
||||
#include <dirent.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/mman.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <errno.h> |
||||
|
||||
#include <Eina.h> |
||||
#include <Ecore.h> |
||||
#include <Ecore_File.h> |
||||
|
||||
#include "Efreet.h" |
||||
#include "efreet_private.h" |
||||
|
||||
static Eet_Data_Descriptor *edd = NULL; |
||||
|
||||
int verbose = 0; |
||||
|
||||
static void |
||||
dump(Efreet_Icon_Theme *theme) |
||||
{ |
||||
Eet_File *ef; |
||||
char **keys; |
||||
int i, num; |
||||
double start, max, avg; |
||||
|
||||
start = ecore_time_get(); |
||||
ef = eet_open(efreet_icon_cache_file(theme->name.internal), EET_FILE_MODE_READ); |
||||
printf("open: %s %f\n", theme->name.internal, ecore_time_get() - start); |
||||
if (!ef) return; |
||||
start = ecore_time_get(); |
||||
keys = eet_list(ef, "*", &num); |
||||
printf("list: %s %d, %f\n", theme->name.internal, num, ecore_time_get() - start); |
||||
if (!keys) |
||||
{ |
||||
eet_close(ef); |
||||
return; |
||||
} |
||||
start = ecore_time_get(); |
||||
for (i = 0; i < num; i++) |
||||
{ |
||||
Efreet_Cache_Icon *icon; |
||||
double dt; |
||||
|
||||
dt = ecore_time_get(); |
||||
icon = eet_data_read(ef, edd, keys[i]); |
||||
if (!icon) continue; |
||||
dt = ecore_time_get() - dt; |
||||
if (dt > max) |
||||
max = dt; |
||||
efreet_cache_icon_free(icon); |
||||
} |
||||
start = ecore_time_get() - start; |
||||
avg = start / num; |
||||
printf("read: %s %f %f %f\n", theme->name.internal, start, avg, max); |
||||
free(keys); |
||||
eet_close(ef); |
||||
} |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
Eina_List *l = NULL; |
||||
Efreet_Icon_Theme *theme; |
||||
int i; |
||||
|
||||
efreet_cache_update = 0; |
||||
|
||||
if (!efreet_init()) goto efreet_error; |
||||
edd = efreet_icon_edd_init(); |
||||
if (!edd) goto edd_error; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
for (i = 1; i < argc; i++) |
||||
{ |
||||
theme = efreet_icon_theme_find(argv[i]); |
||||
if (theme) l = eina_list_append(l, theme); |
||||
} |
||||
} |
||||
if (!l) |
||||
l = efreet_icon_theme_list_get(); |
||||
EINA_LIST_FREE(l, theme) |
||||
{ |
||||
dump(theme); |
||||
} |
||||
|
||||
efreet_shutdown(); |
||||
return 0; |
||||
edd_error: |
||||
efreet_shutdown(); |
||||
efreet_error: |
||||
return 1; |
||||
} |
@ -0,0 +1,123 @@ |
||||
#ifdef HAVE_CONFIG_H |
||||
# include <config.h> |
||||
#endif |
||||
|
||||
#include "Efreet.h" |
||||
#include "efreet_private.h" |
||||
|
||||
/**
|
||||
* Data for cache files |
||||
*/ |
||||
static Eet_Data_Descriptor *cache_icon_edd = NULL; |
||||
static Eet_Data_Descriptor *cache_icon_element_edd = NULL; |
||||
|
||||
static void efreet_icon_edd_shutdown(void); |
||||
|
||||
int |
||||
efreet_cache_init(void) |
||||
{ |
||||
if (!efreet_icon_edd_init()) return 0; |
||||
return 1; |
||||
} |
||||
|
||||
void |
||||
efreet_cache_shutdown(void) |
||||
{ |
||||
efreet_icon_edd_shutdown(); |
||||
} |
||||
|
||||
/*
|
||||
* Needs EAPI because of helper binaries |
||||
*/ |
||||
EAPI const char * |
||||
efreet_icon_cache_file(const char *theme) |
||||
{ |
||||
static char cache_file[PATH_MAX] = { '\0' }; |
||||
const char *home; |
||||
|
||||
home = efreet_home_dir_get(); |
||||
|
||||
snprintf(cache_file, sizeof(cache_file), "%s/.efreet/icon_%s.cache", home, theme); |
||||
|
||||
return cache_file; |
||||
} |
||||
|
||||
/*
|
||||
* Needs EAPI because of helper binaries |
||||
*/ |
||||
EAPI Eet_Data_Descriptor * |
||||
efreet_icon_edd_init(void) |
||||
{ |
||||
Eet_Data_Descriptor_Class iconeddc; |
||||
Eet_Data_Descriptor_Class elemeddc; |
||||
|
||||
if (!cache_icon_edd) |
||||
{ |
||||
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&iconeddc, Efreet_Cache_Icon); |
||||
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&elemeddc, Efreet_Cache_Icon_Element); |
||||
cache_icon_edd = eet_data_descriptor_file_new(&iconeddc); |
||||
if (!cache_icon_edd) |
||||
goto error; |
||||
cache_icon_element_edd = eet_data_descriptor_file_new(&elemeddc); |
||||
if (!cache_icon_element_edd) |
||||
goto error; |
||||
|
||||
#if 0 |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_edd, Efreet_Cache_Icon, "name", name, EET_T_STRING); |
||||
#endif |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_edd, Efreet_Cache_Icon, "theme", theme, EET_T_STRING); |
||||
#if 0 |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_edd, Efreet_Cache_Icon, "context", context, EET_T_INT); |
||||
#endif |
||||
EET_DATA_DESCRIPTOR_ADD_LIST(cache_icon_edd, Efreet_Cache_Icon, "icons", icons, cache_icon_element_edd); |
||||
#if 0 |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_element_edd, Efreet_Cache_Icon_Element, "type", type, EET_T_INT); |
||||
#endif |
||||
eet_data_descriptor_element_add(cache_icon_element_edd, "paths", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Icon_Element, paths), 0, NULL, NULL); |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_element_edd, Efreet_Cache_Icon_Element, "size.normal", size.normal, EET_T_USHORT); |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_element_edd, Efreet_Cache_Icon_Element, "size.min", size.min, EET_T_USHORT); |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(cache_icon_element_edd, Efreet_Cache_Icon_Element, "size.max", size.max, EET_T_USHORT); |
||||
} |
||||
return cache_icon_edd; |
||||
error: |
||||
efreet_icon_edd_shutdown(); |
||||
return NULL; |
||||
} |
||||
|
||||
static void |
||||
efreet_icon_edd_shutdown(void) |
||||
{ |
||||
if (cache_icon_edd) eet_data_descriptor_free(cache_icon_edd); |
||||
cache_icon_edd = NULL; |
||||
if (cache_icon_element_edd) eet_data_descriptor_free(cache_icon_element_edd); |
||||
cache_icon_element_edd = NULL; |
||||
} |
||||
|
||||
/*
|
||||
* Needs EAPI because of helper binaries |
||||
*/ |
||||
EAPI void |
||||
efreet_cache_icon_free(Efreet_Cache_Icon *icon) |
||||
{ |
||||
Efreet_Cache_Icon_Element *elem; |
||||
if (icon->free) |
||||
{ |
||||
#if 0 |
||||
eina_stringshare_del(icon->name); |
||||
#endif |
||||
eina_stringshare_del(icon->theme); |
||||
} |
||||
|
||||
EINA_LIST_FREE(icon->icons, elem) |
||||
{ |
||||
const char *path; |
||||
|
||||
if (icon->free) |
||||
EINA_LIST_FREE(elem->paths, path) |
||||
eina_stringshare_del(path); |
||||
else |
||||
eina_list_free(elem->paths); |
||||
free(elem); |
||||
} |
||||
free(icon); |
||||
} |
Loading…
Reference in new issue