efl/src/lib/efreet/efreet_cache.c

1573 lines
50 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* TODO: Consider flushing local icons cache after idling.
* Icon requests will probably come in batches, f.ex. during menu
* browsing.
*/
#include <libgen.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <Eet.h>
#include <Ecore.h>
#include <Ecore_File.h>
#include <Ecore_Ipc.h>
#include <Ecore_Con.h>
/* define macros and variable for using the eina logging system */
#define EFREET_MODULE_LOG_DOM _efreet_cache_log_dom
static int _efreet_cache_log_dom = -1;
#include "Efreet.h"
#include "efreet_private.h"
#include "efreet_cache_private.h"
#include "../../static_libs/buildsystem/buildsystem.h"
#define NON_EXISTING (void *)-1
typedef struct _Efreet_Old_Cache Efreet_Old_Cache;
struct _Efreet_Old_Cache
{
Eina_Hash *hash;
Eet_File *ef;
};
static Ecore_Ipc_Server *ipc = NULL;
static Ecore_Event_Handler *hnd_add = NULL;
static Ecore_Event_Handler *hnd_del = NULL;
static Ecore_Event_Handler *hnd_data = NULL;
static Eina_Lock _lock;
/**
* Data for cache files
*/
static Eet_Data_Descriptor *directory_edd = NULL;
static Eet_Data_Descriptor *icon_theme_edd = NULL;
static Eet_Data_Descriptor *icon_theme_directory_edd = NULL;
static Eet_Data_Descriptor *icon_fallback_edd = NULL;
static Eet_Data_Descriptor *icon_element_pointer_edd = NULL;
static Eet_Data_Descriptor *icon_element_edd = NULL;
static Eet_Data_Descriptor *icon_edd = NULL;
static Eet_File *icon_cache = NULL;
static Eet_File *fallback_cache = NULL;
static Eet_File *icon_theme_cache = NULL;
static Eina_Hash *themes = NULL;
static Eina_Hash *icons = NULL;
static Eina_Hash *fallbacks = NULL;
static const char *icon_theme_cache_file = NULL;
static const char *theme_name = NULL;
static Eet_Data_Descriptor *version_edd = NULL;
static Eet_Data_Descriptor *desktop_edd = NULL;
static Eet_Data_Descriptor *desktop_action_edd = NULL;
static Eet_Data_Descriptor *hash_array_string_edd = NULL;
static Eet_Data_Descriptor *array_string_edd = NULL;
static Eet_Data_Descriptor *hash_string_edd = NULL;
static Eina_Hash *desktops = NULL;
static Eet_File *desktop_cache = NULL;
static const char *desktop_cache_file = NULL;
static Eina_List *old_desktop_caches = NULL;
static const char *util_cache_file = NULL;
static Eet_File *util_cache = NULL;
static Efreet_Cache_Hash *util_cache_hash = NULL;
static const char *util_cache_hash_key = NULL;
static Efreet_Cache_Array_String *util_cache_names = NULL;
static const char *util_cache_names_key = NULL;
static void efreet_cache_edd_shutdown(void);
static void efreet_cache_icon_free(Efreet_Cache_Icon *icon);
static void efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon);
static void efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme);
static Eina_Bool efreet_cache_check(Eet_File **ef, const char *path, int major);
static void *efreet_cache_close(Eet_File *ef);
static void icon_cache_update_free(void *data, void *ev);
static void *hash_array_string_add(void *hash, const char *key, void *data);
static Eina_Bool disable_cache;
static Eina_Bool run_in_tree;
static int relaunch_try = 0;
EAPI int EFREET_EVENT_ICON_CACHE_UPDATE = 0;
EAPI int EFREET_EVENT_DESKTOP_CACHE_UPDATE = 0;
EAPI int EFREET_EVENT_DESKTOP_CACHE_BUILD = 0;
#define IPC_HEAD(_type) \
Ecore_Ipc_Event_Server_##_type *e = event; \
if (e->server != ipc) \
return ECORE_CALLBACK_PASS_ON
static void
_ipc_launch(void)
{
char buf[PATH_MAX];
int num;
int try_gap = 10000; // 10ms
int tries = 1000; // 1000 * 10ms == 10sec
const char *s;
if (relaunch_try == 0)
{
ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
if (ipc)
{
relaunch_try++;
return;
}
}
relaunch_try--;
s = getenv("EFREETD_CONNECT_TRIES");
if (s)
{
num = atoi(s);
if (num >= 0) tries = num;
}
s = getenv("EFREETD_CONNECT_TRY_GAP");
if (s)
{
num = atoi(s);
if (num >= 0) try_gap = num;
}
if (run_in_tree)
bs_binary_get(buf, sizeof(buf), "efreet", "efreetd");
else
snprintf(buf, sizeof(buf), PACKAGE_BIN_DIR "/efreetd");
ecore_exe_run(buf, NULL);
num = 0;
while ((!ipc) && (num < tries))
{
num++;
usleep(try_gap);
ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
}
if (!ipc) ERR("Timeout in trying to start and then connect to efreetd");
}
static Eina_Bool
_cb_server_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
IPC_HEAD(Add);
relaunch_try--;
return ECORE_CALLBACK_DONE;
}
static Ecore_Timer *reconnect_timer = NULL;
static unsigned int reconnect_count = 0;
static Eina_Bool
_cb_server_reconnect(void *data EINA_UNUSED)
{
if (reconnect_timer) ecore_timer_del(reconnect_timer);
reconnect_timer = NULL;
reconnect_count++;
_ipc_launch();
if (ipc)
{
const char *s;
int len = 0;
s = efreet_language_get();
if (s) len = strlen(s);
ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
efreet_icon_extensions_refresh();
}
return EINA_FALSE;
}
static Eina_Bool
_cb_server_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
double t;
IPC_HEAD(Del);
ipc = NULL;
if (disable_cache) return ECORE_CALLBACK_RENEW;
if (reconnect_count > 10)
{
char *address = ecore_con_local_path_new(EINA_FALSE, "efreetd", 0);
reconnect_timer = NULL;
ERR("efreetd connection failed 10 times! check for stale socket file at %s", address);
free(address);
return EINA_FALSE;
}
// random 0.5 -> 1.0 sec from now
t = (((double)((rand() + (int)getpid()) & 0xff) / 255.0) * 0.5) + 0.5;
if (reconnect_timer) ecore_timer_del(reconnect_timer);
reconnect_timer = ecore_timer_add(t, _cb_server_reconnect, NULL);
return ECORE_CALLBACK_DONE;
}
static void
_efreet_cache_reset()
{
const char *s;
int len = 0;
if (ipc) ecore_ipc_server_del(ipc);
ipc = NULL;
if (!disable_cache)
ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
if (!ipc) return;
s = efreet_language_get();
if (s) len = strlen(s);
ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
efreet_icon_extensions_refresh();
}
static void
_icon_desktop_cache_update_event_add(int event_type)
{
Efreet_Event_Cache_Update *ev;
Efreet_Old_Cache *d = NULL;
Eina_List *l = NULL;
efreet_cache_desktop_close();
ev = NEW(Efreet_Event_Cache_Update, 1);
if (!ev) return;
IF_RELEASE(theme_name);
// Save all old caches
d = NEW(Efreet_Old_Cache, 1);
if (d)
{
d->hash = themes;
d->ef = icon_theme_cache;
l = eina_list_append(l, d);
}
d = NEW(Efreet_Old_Cache, 1);
if (d)
{
d->hash = icons;
d->ef = icon_cache;
l = eina_list_append(l, d);
}
d = NEW(Efreet_Old_Cache, 1);
if (d)
{
d->hash = fallbacks;
d->ef = fallback_cache;
l = eina_list_append(l, d);
}
// Create new empty caches
themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
icon_theme_cache = NULL;
icon_cache = NULL;
fallback_cache = NULL;
// Send event
ecore_event_add(event_type, ev, icon_cache_update_free, l);
}
EAPI void (*_efreet_mime_update_func) (void) = NULL;
static Eina_Bool
_cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
IPC_HEAD(Data);
if (e->major == 1) // registration
{
if (e->minor == 1)
ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL);
}
else if (e->major == 2) // icon cache update
{
if (e->minor == 1)
_icon_desktop_cache_update_event_add(EFREET_EVENT_ICON_CACHE_UPDATE);
else
ecore_event_add(EFREET_EVENT_ICON_CACHE_UPDATE, NULL, NULL, NULL);
}
else if (e->major == 3) // desktop cache update
{
_icon_desktop_cache_update_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE);
}
else if (e->major == 4) // mime cache update
{
if (_efreet_mime_update_func) _efreet_mime_update_func();
}
return ECORE_CALLBACK_DONE;
}
int
efreet_cache_init(void)
{
char buf[PATH_MAX];
_efreet_cache_log_dom = eina_log_domain_register("efreet_cache", EFREET_DEFAULT_LOG_COLOR);
if (_efreet_cache_log_dom < 0)
return 0;
if (!eina_lock_new(&_lock))
{
ERR("Could not create lock");
goto error;
}
snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get());
if (!ecore_file_mkpath(buf))
{
ERR("Failed to create directory '%s'", buf);
}
run_in_tree = !!getenv("EFL_RUN_IN_TREE");
EFREET_EVENT_ICON_CACHE_UPDATE = ecore_event_type_new();
EFREET_EVENT_DESKTOP_CACHE_UPDATE = ecore_event_type_new();
EFREET_EVENT_DESKTOP_CACHE_BUILD = ecore_event_type_new();
themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
desktops = eina_hash_string_superfast_new(NULL);
ecore_ipc_init();
// XXX: connect to efreetd
if (efreet_cache_update)
{
if (disable_cache)
ipc = NULL;
else
{
ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
if (!ipc) _ipc_launch();
}
if (ipc)
{
const char *s;
int len = 0;
hnd_add = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD,
_cb_server_add, NULL);
hnd_del = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL,
_cb_server_del, NULL);
hnd_data = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA,
_cb_server_data, NULL);
s = efreet_language_get();
if (s) len = strlen(s);
ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
}
else
{
Efreet_Event_Cache_Update *ev;
if (!disable_cache)
WRN("Can't contact efreetd daemon for desktop/icon etc. changes");
ev = NEW(Efreet_Event_Cache_Update, 1);
if (ev)
{
ev->error = 1;
ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, ev, NULL, NULL);
}
}
}
ecore_fork_reset_callback_add(_efreet_cache_reset, NULL);
return 1;
error:
if (themes) eina_hash_free(themes);
themes = NULL;
if (icons) eina_hash_free(icons);
icons = NULL;
if (fallbacks) eina_hash_free(fallbacks);
fallbacks = NULL;
if (desktops) eina_hash_free(desktops);
desktops = NULL;
efreet_cache_edd_shutdown();
return 0;
}
void
efreet_cache_shutdown(void)
{
Efreet_Old_Cache *d;
ecore_event_type_flush(EFREET_EVENT_ICON_CACHE_UPDATE,
EFREET_EVENT_DESKTOP_CACHE_UPDATE,
EFREET_EVENT_DESKTOP_CACHE_BUILD);
ecore_fork_reset_callback_del(_efreet_cache_reset, NULL);
IF_RELEASE(theme_name);
icon_cache = efreet_cache_close(icon_cache);
icon_theme_cache = efreet_cache_close(icon_theme_cache);
fallback_cache = efreet_cache_close(fallback_cache);
IF_FREE_HASH(themes);
IF_FREE_HASH(icons);
IF_FREE_HASH(fallbacks);
IF_FREE_HASH_CB(desktops, EINA_FREE_CB(efreet_cache_desktop_free));
desktop_cache = efreet_cache_close(desktop_cache);
IF_RELEASE(desktop_cache_file);
efreet_cache_edd_shutdown();
IF_RELEASE(icon_theme_cache_file);
if (old_desktop_caches)
ERR("This application has not properly closed all its desktop references!");
EINA_LIST_FREE(old_desktop_caches, d)
{
eina_hash_free(d->hash);
eet_close(d->ef);
free(d);
}
IF_RELEASE(util_cache_names_key);
efreet_cache_array_string_free(util_cache_names);
util_cache_names = NULL;
IF_RELEASE(util_cache_hash_key);
if (util_cache_hash)
{
eina_hash_free(util_cache_hash->hash);
free(util_cache_hash);
util_cache_hash = NULL;
}
util_cache = efreet_cache_close(util_cache);
IF_RELEASE(util_cache_file);
if (ipc) ecore_ipc_server_del(ipc);
if (hnd_add) ecore_event_handler_del(hnd_add);
if (hnd_del) ecore_event_handler_del(hnd_del);
if (hnd_data) ecore_event_handler_del(hnd_data);
ecore_ipc_shutdown();
ipc = NULL;
hnd_add = NULL;
hnd_del = NULL;
hnd_data = NULL;
eina_lock_free(&_lock);
eina_log_domain_unregister(_efreet_cache_log_dom);
_efreet_cache_log_dom = -1;
}
/*
* 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 *cache;
EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
cache = efreet_cache_home_get();
snprintf(cache_file, sizeof(cache_file), "%s/efreet/icons_%s_%s.eet", cache, theme, efreet_hostname_get());
return cache_file;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI const char *
efreet_icon_theme_cache_file(void)
{
char tmp[PATH_MAX] = { '\0' };
if (icon_theme_cache_file) return icon_theme_cache_file;
snprintf(tmp, sizeof(tmp), "%s/efreet/icon_themes_%s.eet",
efreet_cache_home_get(), efreet_hostname_get());
icon_theme_cache_file = eina_stringshare_add(tmp);
return icon_theme_cache_file;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI const char *
efreet_desktop_util_cache_file(void)
{
char tmp[PATH_MAX] = { '\0' };
const char *cache_dir, *lang, *country, *modifier;
if (util_cache_file) return util_cache_file;
cache_dir = efreet_cache_home_get();
lang = efreet_lang_get();
country = efreet_lang_country_get();
modifier = efreet_lang_modifier_get();
if (lang && country && modifier)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s@%s.eet", cache_dir, efreet_hostname_get(), lang, country, modifier);
else if (lang && country)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s.eet", cache_dir, efreet_hostname_get(), lang, country);
else if (lang)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s.eet", cache_dir, efreet_hostname_get(), lang);
else
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s.eet", cache_dir, efreet_hostname_get());
util_cache_file = eina_stringshare_add(tmp);
return util_cache_file;
}
/*
* Needs EAPI because of helper binaries
*/
#define SHSH(n, v) ((((v) << (n)) & 0xffffffff) | ((v) >> (32 - (n))))
static inline int
int_to_bigendian(int in)
{
static const unsigned char test[4] = { 0x11, 0x22, 0x33, 0x44 };
static const unsigned int *test_i = (const unsigned int *)test;
if (test_i[0] == 0x44332211) return eina_swap32(in);
return in;
}
static void
sha1(unsigned char *data, int size, unsigned char *dst)
{
unsigned int digest[5], word[80], wa, wb, wc, wd, we, t;
unsigned char buf[64], *d;
int idx, left, i;
const unsigned int magic[4] =
{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
idx = 0;
digest[0] = 0x67452301; digest[1] = 0xefcdab89; digest[2] = 0x98badcfe;
digest[3] = 0x10325476; digest[4] = 0xc3d2e1f0;
memset(buf, 0, sizeof(buf));
for (left = size, d = data; left > 0; left--, d++)
{
if ((idx == 0) && (left < 64))
{
memset(buf, 0, 60);
buf[60] = (size >> 24) & 0xff;
buf[61] = (size >> 16) & 0xff;
buf[62] = (size >> 8) & 0xff;
buf[63] = (size) & 0xff;
}
buf[idx] = *d;
idx++;
if ((idx == 64) || (left == 1))
{
if ((left == 1) && (idx < 64)) buf[idx] = 0x80;
for (i = 0; i < 16; i++)
{
word[i] = (unsigned int)buf[(i * 4) ] << 24;
word[i] |= (unsigned int)buf[(i * 4) + 1] << 16;
word[i] |= (unsigned int)buf[(i * 4) + 2] << 8;
word[i] |= (unsigned int)buf[(i * 4) + 3];
}
for (i = 16; i < 80; i++)
word[i] = SHSH(1,
word[i - 3 ] ^ word[i - 8 ] ^
word[i - 14] ^ word[i - 16]);
wa = digest[0]; wb = digest[1]; wc = digest[2];
wd = digest[3]; we = digest[4];
for (i = 0; i < 80; i++)
{
if (i < 20)
t = SHSH(5, wa) + ((wb & wc) | ((~wb) & wd)) +
we + word[i] + magic[0];
else if (i < 40)
t = SHSH(5, wa) + (wb ^ wc ^ wd) +
we + word[i] + magic[1];
else if (i < 60)
t = SHSH(5, wa) + ((wb & wc) | (wb & wd) | (wc & wd)) +
we + word[i] + magic[2];
else if (i < 80)
t = SHSH(5, wa) + (wb ^ wc ^ wd) +
we + word[i] + magic[3];
we = wd;
wd = wc;
wc = SHSH(30, wb);
wb = wa;
wa = t;
}
digest[0] += wa; digest[1] += wb; digest[2] += wc;
digest[3] += wd; digest[4] += we;
idx = 0;
}
}
t = int_to_bigendian(digest[0]); digest[0] = t;
t = int_to_bigendian(digest[1]); digest[1] = t;
t = int_to_bigendian(digest[2]); digest[2] = t;
t = int_to_bigendian(digest[3]); digest[3] = t;
t = int_to_bigendian(digest[4]); digest[4] = t;
memcpy(dst, digest, 5 * 4);
}
EAPI Eina_Bool
efreet_file_cache_fill(const char *file, Efreet_Cache_Check *check)
{
struct stat st;
ssize_t size = 0;
char link[PATH_MAX];
memset(check, 0, sizeof(Efreet_Cache_Check));
#ifndef _WIN32
if (lstat(file, &st) != 0) return EINA_FALSE;
if (S_ISLNK(st.st_mode))
{
size = readlink(file, link, sizeof(link));
if ((size > 0) && ((size_t)size >= sizeof(link))) return EINA_FALSE;
if (stat(file, &st) != 0) return EINA_FALSE;
}
if (size > 0) sha1((unsigned char *)link, size, check->link_sha1);
else
#endif
memset(check->link_sha1, 0, sizeof(check->link_sha1));
check->uid = st.st_uid;
check->gid = st.st_gid;
check->size = st.st_size;
#ifndef _WIN32
check->blocks = st.st_blocks;
#else
check->blocks = 0;
#endif
check->mtime = st.st_mtime;
check->chtime = st.st_ctime;
check->mode = st.st_mode;
return EINA_TRUE;
}
EAPI Eina_Bool // true if matches
efreet_file_cache_check(const Efreet_Cache_Check *check1, const Efreet_Cache_Check *check2)
{
if ((check1->mtime != check2->mtime ) ||
(check1->size != check2->size ) ||
(check1->chtime != check2->chtime ) ||
(check1->blocks != check2->blocks) ||
(check1->mode != check2->mode ) ||
(check1->uid != check2->uid ) ||
(check1->gid != check2->gid ) ||
(memcmp(check1->link_sha1, check2->link_sha1, 20) != 0))
{
return EINA_FALSE;
}
return EINA_TRUE; // matches
}
EAPI Eet_Data_Descriptor *
efreet_version_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (version_edd) return version_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Version);
version_edd = eet_data_descriptor_file_new(&eddc);
if (!version_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
"minor", minor, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
"major", major, EET_T_UCHAR);
return version_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_hash_array_string_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (hash_array_string_edd) return hash_array_string_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
eddc.func.hash_add = hash_array_string_add;
hash_array_string_edd = eet_data_descriptor_file_new(&eddc);
if (!hash_array_string_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_HASH(hash_array_string_edd, Efreet_Cache_Hash,
"hash", hash, efreet_array_string_edd());
return hash_array_string_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_hash_string_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (hash_string_edd) return hash_string_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
hash_string_edd = eet_data_descriptor_file_new(&eddc);
if (!hash_string_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_HASH_STRING(hash_string_edd, Efreet_Cache_Hash,
"hash", hash);
return hash_string_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_array_string_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (array_string_edd) return array_string_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Array_String);
array_string_edd = eet_data_descriptor_file_new(&eddc);
if (!array_string_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(array_string_edd, Efreet_Cache_Array_String,
"array", array);
return array_string_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI const char *
efreet_desktop_cache_file(void)
{
char tmp[PATH_MAX] = { '\0' };
const char *cache, *lang, *country, *modifier;
if (desktop_cache_file) return desktop_cache_file;
cache = efreet_cache_home_get();
lang = efreet_lang_get();
country = efreet_lang_country_get();
modifier = efreet_lang_modifier_get();
if (lang && country && modifier)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s@%s.eet", cache, efreet_hostname_get(), lang, country, modifier);
else if (lang && country)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s.eet", cache, efreet_hostname_get(), lang, country);
else if (lang)
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s.eet", cache, efreet_hostname_get(), lang);
else
snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s.eet", cache, efreet_hostname_get());
desktop_cache_file = eina_stringshare_add(tmp);
return desktop_cache_file;
}
#define EDD_SHUTDOWN(Edd) \
if (Edd) eet_data_descriptor_free(Edd); \
Edd = NULL;
static void
efreet_cache_edd_shutdown(void)
{
EDD_SHUTDOWN(version_edd);
EDD_SHUTDOWN(desktop_edd);
EDD_SHUTDOWN(desktop_action_edd);
EDD_SHUTDOWN(hash_array_string_edd);
EDD_SHUTDOWN(array_string_edd);
EDD_SHUTDOWN(hash_string_edd);
EDD_SHUTDOWN(icon_theme_edd);
EDD_SHUTDOWN(icon_theme_directory_edd);
EDD_SHUTDOWN(directory_edd);
EDD_SHUTDOWN(icon_fallback_edd);
EDD_SHUTDOWN(icon_element_pointer_edd);
EDD_SHUTDOWN(icon_element_edd);
EDD_SHUTDOWN(icon_edd);
}
#define EFREET_POINTER_TYPE(Edd_Dest, Edd_Source, Type) \
{ \
typedef struct _Efreet_##Type##_Pointer Efreet_##Type##_Pointer; \
struct _Efreet_##Type##_Pointer \
{ \
Efreet_##Type *pointer; \
}; \
\
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_##Type##_Pointer); \
Edd_Dest = eet_data_descriptor_file_new(&eddc); \
EET_DATA_DESCRIPTOR_ADD_SUB(Edd_Dest, Efreet_##Type##_Pointer, \
"pointer", pointer, Edd_Source); \
}
static Eet_Data_Descriptor *
efreet_icon_directory_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (directory_edd) return directory_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Directory);
directory_edd = eet_data_descriptor_file_new(&eddc);
if (!directory_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.uid", check.uid, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.gid", check.gid, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.size", check.size, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.blocks", check.blocks, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.mtime", check.mtime, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.chtime", check.chtime, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
"check.mode", check.mode, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC_ARRAY(directory_edd, Efreet_Cache_Directory,
"check.link_sha1", check.link_sha1, EET_T_CHAR);
return directory_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_icon_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (icon_edd) return icon_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Element);
icon_element_edd = eet_data_descriptor_file_new(&eddc);
if (!icon_element_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
"type", type, EET_T_USHORT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
"normal", normal, EET_T_USHORT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
"normal", normal, EET_T_USHORT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
"min", min, EET_T_USHORT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
"max", max, EET_T_USHORT);
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_element_edd, Efreet_Cache_Icon_Element,
"paths", paths);
EFREET_POINTER_TYPE(icon_element_pointer_edd, icon_element_edd, Cache_Icon_Element);
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon);
icon_edd = eet_data_descriptor_file_new(&eddc);
if (!icon_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_edd, Efreet_Cache_Icon,
"theme", theme, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(icon_edd, Efreet_Cache_Icon,
"icons", icons, icon_element_pointer_edd);
return icon_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_icon_theme_edd(Eina_Bool cache)
{
Eet_Data_Descriptor_Class eddc;
if (icon_theme_edd) return icon_theme_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Icon_Theme_Directory);
icon_theme_directory_edd = eet_data_descriptor_file_new(&eddc);
if (!icon_theme_directory_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"name", name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"context", context, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"type", type, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"size.normal", size.normal, EET_T_UINT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"size.min", size.min, EET_T_UINT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"size.max", size.max, EET_T_UINT);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
"size.threshold", size.threshold, EET_T_UINT);
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Theme);
icon_theme_edd = eet_data_descriptor_file_new(&eddc);
if (!icon_theme_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"name.internal", theme.name.internal, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"name.name", theme.name.name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"comment", theme.comment, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"example_icon", theme.example_icon, EET_T_STRING);
eet_data_descriptor_element_add(icon_theme_edd, "paths", EET_T_STRING, EET_G_LIST,
offsetof(Efreet_Cache_Icon_Theme, theme.paths), 0, NULL, NULL);
eet_data_descriptor_element_add(icon_theme_edd, "inherits", EET_T_STRING, EET_G_LIST,
offsetof(Efreet_Cache_Icon_Theme, theme.inherits), 0, NULL, NULL);
EET_DATA_DESCRIPTOR_ADD_LIST(icon_theme_edd, Efreet_Cache_Icon_Theme,
"directories", theme.directories, icon_theme_directory_edd);
if (cache)
{
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.uid", check.uid, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.gid", check.gid, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.size", check.size, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.blocks", check.blocks, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.mtime", check.mtime, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.chtime", check.chtime, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.mode", check.mode, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC_ARRAY(icon_theme_edd, Efreet_Cache_Icon_Theme,
"check.link_sha1", check.link_sha1, EET_T_CHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
"path", path, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_HASH(icon_theme_edd, Efreet_Cache_Icon_Theme,
"dirs", dirs, efreet_icon_directory_edd());
}
return icon_theme_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_icon_fallback_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (icon_fallback_edd) return icon_fallback_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Fallback_Icon);
icon_fallback_edd = eet_data_descriptor_file_new(&eddc);
if (!icon_fallback_edd) return NULL;
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_fallback_edd,
Efreet_Cache_Fallback_Icon, "icons", icons);
return icon_fallback_edd;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI Eet_Data_Descriptor *
efreet_desktop_edd(void)
{
Eet_Data_Descriptor_Class eddc;
if (desktop_edd) return desktop_edd;
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Desktop_Action);
desktop_action_edd = eet_data_descriptor_file_new(&eddc);
if (!desktop_action_edd) return NULL;
/* Desktop Spec 1.1 */
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "key", key, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "name", name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "icon", icon, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "exec", exec, EET_T_STRING);
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Desktop);
desktop_edd = eet_data_descriptor_file_new(&eddc);
if (!desktop_edd) return NULL;
/* Desktop Spec 1.0 */
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "type", desktop.type, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "version", desktop.version, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "orig_path", desktop.orig_path, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "load_time", desktop.load_time, EET_T_LONG_LONG);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "name", desktop.name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "generic_name", desktop.generic_name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "comment", desktop.comment, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "icon", desktop.icon, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "try_exec", desktop.try_exec, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "exec", desktop.exec, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "path", desktop.path, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_wm_class", desktop.startup_wm_class, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "url", desktop.url, EET_T_STRING);
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);
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);
eet_data_descriptor_element_add(desktop_edd, "categories", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.categories), 0, NULL, NULL);
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);
eet_data_descriptor_element_add(desktop_edd, "x", EET_T_STRING, EET_G_HASH, offsetof(Efreet_Cache_Desktop, desktop.x), 0, NULL, NULL);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "no_display", desktop.no_display, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "hidden", desktop.hidden, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "terminal", desktop.terminal, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_notify", desktop.startup_notify, EET_T_UCHAR);
/* Desktop Spec 1.1 */
EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "dbus_activatable", desktop.dbus_activatable, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_LIST(desktop_edd, Efreet_Cache_Desktop,
"actions", desktop.actions, desktop_action_edd);
eet_data_descriptor_element_add(desktop_edd, "implements", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.implements), 0, NULL, NULL);
eet_data_descriptor_element_add(desktop_edd, "keywords", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.keywords), 0, NULL, NULL);
return desktop_edd;
}
Efreet_Cache_Icon *
efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon)
{
Efreet_Cache_Icon *cache = NULL;
if (theme_name && strcmp(theme_name, theme->name.internal))
{
/* FIXME: this is bad if people have pointer to this cache, things will go wrong */
INF("theme_name change from '%s' to '%s'", theme_name, theme->name.internal);
IF_RELEASE(theme_name);
icon_cache = efreet_cache_close(icon_cache);
eina_hash_free(icons);
icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
}
if (!efreet_cache_check(&icon_cache, efreet_icon_cache_file(theme->name.internal), EFREET_ICON_CACHE_MAJOR)) return NULL;
if (!theme_name)
theme_name = eina_stringshare_add(theme->name.internal);
cache = eina_hash_find(icons, icon);
if (cache == NON_EXISTING) return NULL;
if (cache) return cache;
cache = eet_data_read(icon_cache, efreet_icon_edd(), icon);
if (cache)
eina_hash_add(icons, icon, cache);
else
eina_hash_add(icons, icon, NON_EXISTING);
return cache;
}
Efreet_Cache_Fallback_Icon *
efreet_cache_icon_fallback_find(const char *icon)
{
Efreet_Cache_Fallback_Icon *cache;
if (!efreet_cache_check(&fallback_cache, efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EFREET_ICON_CACHE_MAJOR)) return NULL;
cache = eina_hash_find(fallbacks, icon);
if (cache == NON_EXISTING) return NULL;
if (cache) return cache;
cache = eet_data_read(fallback_cache, efreet_icon_fallback_edd(), icon);
if (cache)
eina_hash_add(fallbacks, icon, cache);
else
eina_hash_add(fallbacks, icon, NON_EXISTING);
return cache;
}
Efreet_Icon_Theme *
efreet_cache_icon_theme_find(const char *theme)
{
Efreet_Cache_Icon_Theme *cache;
if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
cache = eina_hash_find(themes, theme);
if (cache == NON_EXISTING) return NULL;
if (cache) return &(cache->theme);
cache = eet_data_read(icon_theme_cache, efreet_icon_theme_edd(EINA_FALSE), theme);
if (cache)
{
eina_hash_add(themes, theme, cache);
return &(cache->theme);
}
else
eina_hash_add(themes, theme, NON_EXISTING);
return NULL;
}
static void
efreet_cache_icon_free(Efreet_Cache_Icon *icon)
{
unsigned int i;
if (!icon) return;
if (icon == NON_EXISTING) return;
for (i = 0; i < icon->icons_count; ++i)
{
free(icon->icons[i]->paths);
free(icon->icons[i]);
}
free(icon->icons);
free(icon);
}
static void
efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon)
{
if (!icon) return;
if (icon == NON_EXISTING) return;
free(icon->icons);
free(icon);
}
static void
efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme)
{
void *data;
if (!theme) return;
if (theme == NON_EXISTING) return;
eina_list_free(theme->paths);
eina_list_free(theme->inherits);
EINA_LIST_FREE(theme->directories, data)
free(data);
free(theme);
}
Eina_List *
efreet_cache_icon_theme_list(void)
{
Eina_List *ret = NULL;
char **keys;
int i, num;
if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
keys = eet_list(icon_theme_cache, "*", &num);
if (!keys) return NULL;
for (i = 0; i < num; i++)
{
Efreet_Icon_Theme *theme;
if (!strncmp(keys[i], "__efreet", 8)) continue;
theme = eina_hash_find(themes, keys[i]);
if (!theme)
theme = efreet_cache_icon_theme_find(keys[i]);
if (theme && theme != NON_EXISTING)
ret = eina_list_append(ret, theme);
}
free(keys);
return ret;
}
/*
* Needs EAPI because of helper binaries
*/
EAPI void
efreet_cache_array_string_free(Efreet_Cache_Array_String *array)
{
if (!array) return;
free(array->array);
free(array);
}
Efreet_Desktop *
efreet_cache_desktop_find(const char *file)
{
Efreet_Cache_Desktop *cache = NULL;
eina_lock_take(&_lock);
if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) goto error;
cache = eina_hash_find(desktops, file);
if (cache == NON_EXISTING) goto error;
if (cache)
{
/* If less than one second since last stat, return desktop */
if ((ecore_time_get() - cache->check_time) < 1)
{
INF("Return without stat %f %f for file '%s'", ecore_time_get(), cache->check_time, file);
eina_lock_release(&_lock);
return &cache->desktop;
}
if (cache->desktop.load_time == ecore_file_mod_time(cache->desktop.orig_path))
{
INF("Return with stat %f %f for file '%s'", ecore_time_get(), cache->check_time, file);
cache->check_time = ecore_time_get();
eina_lock_release(&_lock);
return &cache->desktop;
}
/* We got stale data. The desktop will be free'd eventually as
* users will call efreet_desktop_free */
eina_hash_set(desktops, file, NON_EXISTING);
cache = NULL;
}
cache = eet_data_read(desktop_cache, efreet_desktop_edd(), file);
if (cache)
{
if (cache->desktop.load_time != ecore_file_mod_time(cache->desktop.orig_path))
{
/* Don't return stale data */
INF("We got stale data in the desktop cache for file '%s'", cache->desktop.orig_path);
efreet_cache_desktop_free(&cache->desktop);
eina_hash_set(desktops, file, NON_EXISTING);
}
else
{
cache->desktop.eet = 1;
cache->check_time = ecore_time_get();
eina_hash_set(desktops, cache->desktop.orig_path, cache);
eina_lock_release(&_lock);
return &cache->desktop;
}
}
else
eina_hash_set(desktops, file, NON_EXISTING);
error:
eina_lock_release(&_lock);
return NULL;
}
void
efreet_cache_desktop_free(Efreet_Desktop *desktop)
{
Efreet_Old_Cache *d;
Efreet_Desktop *curr;
Eina_List *l;
if (!desktop ||
desktop == NON_EXISTING ||
!desktop->eet) return;
eina_lock_take(&_lock);
curr = eina_hash_find(desktops, desktop->orig_path);
if (curr == desktop)
{
INF("Found '%s' in current cache, purge", desktop->orig_path);
eina_hash_del_by_key(desktops, desktop->orig_path);
}
EINA_LIST_FOREACH(old_desktop_caches, l, d)
{
curr = eina_hash_find(d->hash, desktop->orig_path);
if (curr == desktop)
{
INF("Found '%s' in old cache, purge", desktop->orig_path);
eina_hash_del_by_key(d->hash, desktop->orig_path);
if (eina_hash_population(d->hash) == 0)
{
INF("Cache empty, close file");
eina_hash_free(d->hash);
eet_close(d->ef);
free(d);
old_desktop_caches = eina_list_remove_list(old_desktop_caches, l);
}
break;
}
}
/* Desktop Spec 1.0 */
eina_list_free(desktop->only_show_in);
eina_list_free(desktop->not_show_in);
eina_list_free(desktop->categories);
eina_list_free(desktop->mime_types);
IF_FREE_HASH(desktop->x);
/* Desktop Spec 1.1 */
eina_list_free(desktop->actions);
eina_list_free(desktop->implements);
eina_list_free(desktop->keywords);
free(desktop);
eina_lock_release(&_lock);
}
void
efreet_cache_desktop_add(Efreet_Desktop *desktop)
{
char *path;
if ((!efreet_cache_update) || (!ipc)) return;
if (!eina_main_loop_is()) return;
/*
* TODO: Call in thread with:
* ecore_thread_main_loop_begin();
* ecore_thread_main_loop_end();
*/
path = ecore_file_dir_get(desktop->orig_path);
if (!path) return;
ecore_ipc_server_send(ipc, 2, 0, 0, 0, 0, path, strlen(path));
free(path);
}
void
efreet_cache_icon_exts_add(Eina_List *exts)
{
Eina_List *l;
const char *s;
Eina_Binbuf *buf;
int num = 0;
unsigned char nil[1] = { 0 };
if ((!efreet_cache_update) || (!ipc)) return;
buf = eina_binbuf_new();
if (!buf) return;
EINA_LIST_FOREACH(exts, l, s)
{
if (num > 0) eina_binbuf_append_length(buf, nil, 1);
eina_binbuf_append_length(buf, (unsigned char *)s, strlen(s));
num++;
}
ecore_ipc_server_send(ipc, 5 /* add icon exts */, 0, 0, 0, 0,
eina_binbuf_string_get(buf),
eina_binbuf_length_get(buf));
eina_binbuf_free(buf);
}
void
efreet_cache_icon_dirs_add(Eina_List *dirs)
{
Eina_List *l;
const char *s;
Eina_Binbuf *buf;
int num = 0;
unsigned char nil[1] = { 0 };
if ((!efreet_cache_update) || (!ipc)) return;
buf = eina_binbuf_new();
if (!buf) return;
EINA_LIST_FOREACH(dirs, l, s)
{
if (num > 0) eina_binbuf_append_length(buf, nil, 1);
eina_binbuf_append_length(buf, (unsigned char *)s, strlen(s));
num++;
}
ecore_ipc_server_send(ipc, 4 /* add icon dirs */, 0, 0, 0, 0,
eina_binbuf_string_get(buf),
eina_binbuf_length_get(buf));
eina_binbuf_free(buf);
}
void
efreet_cache_desktop_close(void)
{
IF_RELEASE(util_cache_names_key);
IF_RELEASE(util_cache_hash_key);
eina_lock_take(&_lock);
if ((desktop_cache) && (desktop_cache != NON_EXISTING))
{
Efreet_Old_Cache *d = NEW(Efreet_Old_Cache, 1);
if (d)
{
d->hash = desktops;
d->ef = desktop_cache;
old_desktop_caches = eina_list_append(old_desktop_caches, d);
}
desktops = eina_hash_string_superfast_new(NULL);
}
desktop_cache = NULL;
IF_RELEASE(desktop_cache_file);
eina_lock_release(&_lock);
efreet_cache_array_string_free(util_cache_names);
util_cache_names = NULL;
if (util_cache_hash)
{
eina_hash_free(util_cache_hash->hash);
free(util_cache_hash);
util_cache_hash = NULL;
}
util_cache = efreet_cache_close(util_cache);
IF_RELEASE(util_cache_file);
}
void
efreet_cache_desktop_build(void)
{
const char *s;
int len = 0;
if ((!efreet_cache_update) || (!ipc)) return;
s = efreet_language_get();
if (s) len = strlen(s);
ecore_ipc_server_send(ipc, 3 /* build desktop cache */, 0, 0, 0, 0, s, len);
}
static Eina_Bool
efreet_cache_check(Eet_File **ef, const char *path, int major)
{
Efreet_Cache_Version *version;
if (*ef == NON_EXISTING) return EINA_FALSE;
if (*ef) return EINA_TRUE;
if (!*ef)
*ef = eet_open(path, EET_FILE_MODE_READ);
if (!*ef)
{
*ef = NON_EXISTING;
return EINA_FALSE;
}
version = eet_data_read(*ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if ((!version) || (version->major != major))
{
IF_FREE(version);
eet_close(*ef);
*ef = NON_EXISTING;
return EINA_FALSE;
}
free(version);
return EINA_TRUE;
}
static void *
efreet_cache_close(Eet_File *ef)
{
if (ef && ef != NON_EXISTING)
eet_close(ef);
return NULL;
}
Efreet_Cache_Hash *
efreet_cache_util_hash_string(const char *key)
{
if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
return util_cache_hash;
if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
if (util_cache_hash)
{
/* free previous util_cache */
IF_RELEASE(util_cache_hash_key);
eina_hash_free(util_cache_hash->hash);
free(util_cache_hash);
}
util_cache_hash_key = eina_stringshare_add(key);
util_cache_hash = eet_data_read(util_cache, efreet_hash_string_edd(), key);
return util_cache_hash;
}
Efreet_Cache_Hash *
efreet_cache_util_hash_array_string(const char *key)
{
if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
return util_cache_hash;
if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
IF_RELEASE(util_cache_hash_key);
if (util_cache_hash)
{
/* free previous cache */
eina_hash_free(util_cache_hash->hash);
free(util_cache_hash);
}
util_cache_hash_key = eina_stringshare_add(key);
util_cache_hash = eet_data_read(util_cache, efreet_hash_array_string_edd(), key);
return util_cache_hash;
}
Efreet_Cache_Array_String *
efreet_cache_util_names(const char *key)
{
if (util_cache_names_key && !strcmp(key, util_cache_names_key))
return util_cache_names;
if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
if (util_cache_names)
{
/* free previous util_cache */
IF_RELEASE(util_cache_names_key);
efreet_cache_array_string_free(util_cache_names);
}
util_cache_names_key = eina_stringshare_add(key);
util_cache_names = eet_data_read(util_cache, efreet_array_string_edd(), key);
return util_cache_names;
}
static void
icon_cache_update_free(void *data, void *ev)
{
Efreet_Old_Cache *d;
Eina_List *l;
l = data;
EINA_LIST_FREE(l, d)
{
if (d->hash)
eina_hash_free(d->hash);
efreet_cache_close(d->ef);
free(d);
}
free(ev);
}
static void *
hash_array_string_add(void *hash, const char *key, void *data)
{
if (!hash)
hash = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
if (!hash)
return NULL;
eina_hash_add(hash, key, data);
return hash;
}
EAPI void
efreet_cache_disable(void)
{
Eina_Bool prev = disable_cache;
disable_cache = EINA_TRUE;
if (_efreet_cache_log_dom < 0) return; // not yet initialized
if (prev == disable_cache) return; // same value
if (ipc)
{
ecore_ipc_server_del(ipc);
ipc = NULL;
}
}
EAPI void
efreet_cache_enable(void)
{
Eina_Bool prev = disable_cache;
disable_cache = EINA_FALSE;
if (_efreet_cache_log_dom < 0) return; // not yet initialized
if (prev == disable_cache) return; // same value
if (!ipc) _ipc_launch();
}