From eaeda2ecdd149369226422344b431f4e8c18b3e8 Mon Sep 17 00:00:00 2001 From: Cedric Bail Date: Mon, 4 Nov 2013 12:17:58 +0900 Subject: [PATCH] elm_theme: use Eina_File all over the place in an attempt to reduce race condition. --- legacy/elementary/src/lib/elm_priv.h | 18 +- legacy/elementary/src/lib/elm_theme.c | 444 +++++++++++++------------- 2 files changed, 238 insertions(+), 224 deletions(-) diff --git a/legacy/elementary/src/lib/elm_priv.h b/legacy/elementary/src/lib/elm_priv.h index e6f91ccf37..fc1c06320c 100644 --- a/legacy/elementary/src/lib/elm_priv.h +++ b/legacy/elementary/src/lib/elm_priv.h @@ -75,6 +75,7 @@ #endif #define N_(string) (string) +typedef struct _Elm_Theme_Files Elm_Theme_Files; typedef struct _Edje_Signal_Data Edje_Signal_Data; typedef struct _Elm_Config Elm_Config; typedef struct _Elm_Module Elm_Module; @@ -89,11 +90,22 @@ struct _Edje_Signal_Data void *data; }; +struct _Elm_Theme_Files +{ + /* + * We are conserving a list of path even if that's duplicated + * because we expose those directly to the outside world :'( + */ + Eina_List *items; + Eina_List *handles; +}; + struct _Elm_Theme { - Eina_List *overlay; - Eina_List *themes; - Eina_List *extension; + Elm_Theme_Files overlay; + Elm_Theme_Files themes; + Elm_Theme_Files extension; + Eina_Hash *cache; Eina_Hash *cache_data; Elm_Theme *ref_theme; diff --git a/legacy/elementary/src/lib/elm_theme.c b/legacy/elementary/src/lib/elm_theme.c index 65f09d11b4..17e25aa716 100644 --- a/legacy/elementary/src/lib/elm_theme.c +++ b/legacy/elementary/src/lib/elm_theme.c @@ -8,21 +8,129 @@ static Elm_Theme theme_default = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1 + { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, + NULL, NULL, NULL, NULL, NULL, 1 }; static Eina_List *themes = NULL; +static Eina_File * +_elm_theme_find_try(Elm_Theme *th, Eina_File *f, const char *group) +{ + if (edje_mmap_group_exists(f, group)) + { + eina_hash_add(th->cache, group, eina_file_dup(f)); + return f; + } + return NULL; +} + +static inline void +_elm_theme_item_finalize(Elm_Theme_Files *files, + const char *item, + Eina_File *f) +{ + if (!f) return ; + + files->items = eina_list_append(files->items, + eina_stringshare_add(item)); + files->handles = eina_list_append(files->handles, f); +} + +static void +_elm_theme_file_item_add(Elm_Theme_Files *files, const char *item) +{ + Eina_Strbuf *buf = NULL; + Eina_File *f = NULL; + const char *home; + + home = getenv("HOME") ? getenv("HOME") : ""; + buf = eina_strbuf_new(); + + if ((item[0] == '/') || + ((item[0] == '.') && (item[1] == '/')) || + ((item[0] == '.') && (item[1] == '.') && (item[2] == '/')) || + ((isalpha(item[0])) && (item[1] == ':'))) + { + f = eina_file_open(item, EINA_FALSE); + if (!f) goto on_error; + } + else if (((item[0] == '~') && (item[1] == '/'))) + { + eina_strbuf_append_printf(buf, "%s/%s", home, item + 2); + + f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE); + if (!f) goto on_error; + } + else + { + eina_strbuf_append_printf(buf, + "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", + home, item); + f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE); + _elm_theme_item_finalize(files, item, f); + + eina_strbuf_reset(buf); + eina_strbuf_append_printf(buf, + "%s/themes/%s.edj", + _elm_data_dir, item); + f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE); + /* Finalize will be done by the common one */ + } + + _elm_theme_item_finalize(files, item, f); + + on_error: + if (buf) eina_strbuf_free(buf); +} + +static void +_elm_theme_file_item_del(Elm_Theme_Files *files, const char *str) +{ + Eina_List *l, *ll; + Eina_List *l2, *ll2; + const char *item; + + str = eina_stringshare_add(str); + l2 = files->handles; + + EINA_LIST_FOREACH_SAFE(files->items, l, ll, item) + { + ll2 = l2->next; + + if (item == str) + { + eina_file_close(eina_list_data_get(l2)); + eina_stringshare_del(item); + + files->handles = eina_list_remove_list(files->handles, l2); + files->items = eina_list_remove_list(files->items, l); + } + + l2 = ll2; + } + + eina_stringshare_del(str); +} + +static void +_elm_theme_file_clean(Elm_Theme_Files *files) +{ + const char *item; + Eina_File *f; + + EINA_LIST_FREE(files->items, item) + eina_stringshare_del(item); + EINA_LIST_FREE(files->handles, f) + eina_file_close(f); +} + static void _elm_theme_clear(Elm_Theme *th) { - const char *p; - EINA_LIST_FREE(th->themes, p) - eina_stringshare_del(p); - EINA_LIST_FREE(th->overlay, p) - eina_stringshare_del(p); - EINA_LIST_FREE(th->extension, p) - eina_stringshare_del(p); + _elm_theme_file_clean(&th->themes); + _elm_theme_file_clean(&th->overlay); + _elm_theme_file_clean(&th->extension); ELM_SAFE_FREE(th->cache, eina_hash_free); ELM_SAFE_FREE(th->cache_data, eina_hash_free); @@ -36,73 +144,27 @@ _elm_theme_clear(Elm_Theme *th) } } -static const char * -_elm_theme_find_try(Elm_Theme *th, const char *f, const char *group) -{ - const char *file; - - if (edje_file_group_exists(f, group)) - { - file = eina_stringshare_add(f); - if (file) - { - eina_hash_add(th->cache, group, file); - return file; - } - } - return NULL; -} - -static const char * -_elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group) -{ - char buf[PATH_MAX]; - const char *file = NULL; - - if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) || - ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) || - ((isalpha(f[0])) && (f[1] == ':'))) - return _elm_theme_find_try(th, f, group); - else if (((f[0] == '~') && (f[1] == '/'))) - { - snprintf(buf, sizeof(buf), "%s/%s", home, f + 2); - return _elm_theme_find_try(th, buf, group); - } - snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f); - file = _elm_theme_find_try(th, buf, group); - if (file) return file; - snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f); - file = _elm_theme_find_try(th, buf, group); - return file; -} - -static const char * +static Eina_File * _elm_theme_group_file_find(Elm_Theme *th, const char *group) { const Eina_List *l; - const char *f; - static const char *home = NULL; - const char *file = eina_hash_find(th->cache, group); + Eina_File *file = eina_hash_find(th->cache, group); if (file) return file; - if (!home) + + EINA_LIST_FOREACH(th->overlay.handles, l, file) { - home = getenv("HOME"); - if (!home) home = ""; - } - EINA_LIST_FOREACH(th->overlay, l, f) - { - file = _elm_theme_theme_element_try(th, home, f, group); + file = _elm_theme_find_try(th, file, group); if (file) return file; } - EINA_LIST_FOREACH(th->themes, l, f) + EINA_LIST_FOREACH(th->themes.handles, l, file) { - file = _elm_theme_theme_element_try(th, home, f, group); + file = _elm_theme_find_try(th, file, group); if (file) return file; } - EINA_LIST_FOREACH(th->extension, l, f) + EINA_LIST_FOREACH(th->extension.handles, l, file) { - file = _elm_theme_theme_element_try(th, home, f, group); + file = _elm_theme_find_try(th, file, group); if (file) return file; } if (th->ref_theme) return _elm_theme_group_file_find(th->ref_theme, group); @@ -110,12 +172,12 @@ _elm_theme_group_file_find(Elm_Theme *th, const char *group) } static const char * -_elm_theme_find_data_try(Elm_Theme *th, const char *f, const char *key) +_elm_theme_find_data_try(Elm_Theme *th, const Eina_File *f, const char *key) { char *data; const char *t; - data = edje_file_data_get(f, key); + data = edje_mmap_data_get(f, key); t = eina_stringshare_add(data); free(data); if (t) @@ -126,56 +188,28 @@ _elm_theme_find_data_try(Elm_Theme *th, const char *f, const char *key) return NULL; } -static const char * -_elm_theme_theme_data_try(Elm_Theme *th, const char *home, const char *f, const char *key) -{ - char buf[PATH_MAX]; - const char *data = NULL; - - if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) || - ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) || - ((isalpha(f[0])) && (f[1] == ':'))) - return _elm_theme_find_data_try(th, f, key); - else if (((f[0] == '~') && (f[1] == '/'))) - { - snprintf(buf, sizeof(buf), "%s/%s", home, f + 2); - return _elm_theme_find_try(th, buf, key); - } - snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f); - data = _elm_theme_find_data_try(th, buf, key); - if (data) return data; - snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f); - data = _elm_theme_find_data_try(th, buf, key); - return data; -} - static const char * _elm_theme_data_find(Elm_Theme *th, const char *key) { const Eina_List *l; - const char *f; - static const char *home = NULL; - const char *data = eina_hash_find(th->cache_data, key); + const Eina_File *f; + const char *data = eina_hash_find(th->cache_data, key); if (data) return data; - if (!home) + + EINA_LIST_FOREACH(th->overlay.handles, l, f) { - home = getenv("HOME"); - if (!home) home = ""; - } - EINA_LIST_FOREACH(th->overlay, l, f) - { - data = _elm_theme_theme_data_try(th, home, f, key); + data = _elm_theme_find_data_try(th, f, key); if (data) return data; } - EINA_LIST_FOREACH(th->themes, l, f) + EINA_LIST_FOREACH(th->themes.handles, l, f) { - data = _elm_theme_theme_data_try(th, home, f, key); + data = _elm_theme_find_data_try(th, f, key); if (data) return data; } - EINA_LIST_FOREACH(th->extension, l, f) + EINA_LIST_FOREACH(th->extension.handles, l, f) { - data = _elm_theme_theme_data_try(th, home, f, key); + data = _elm_theme_find_data_try(th, f, key); if (data) return data; } if (th->ref_theme) return _elm_theme_data_find(th->ref_theme, key); @@ -252,7 +286,7 @@ _elm_theme_object_icon_set(Evas_Object *o, Eina_Bool _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *group, const char *style) { - const char *file; + Eina_File *file; char buf2[1024]; if ((!clas) || (!group) || (!style)) return EINA_FALSE; @@ -262,11 +296,13 @@ _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *grou file = _elm_theme_group_file_find(th, buf2); if (file) { - if (edje_object_file_set(o, file, buf2)) return EINA_TRUE; + if (edje_object_mmap_set(o, file, buf2)) return EINA_TRUE; else { DBG("could not set theme group '%s' from file '%s': %s", - buf2, file, edje_load_error_str(edje_object_load_error_get(o))); + buf2, + eina_file_filename_get(file), + edje_load_error_str(edje_object_load_error_get(o))); } } @@ -274,9 +310,11 @@ _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *grou snprintf(buf2, sizeof(buf2), "elm/%s/%s/default", clas, group); file = _elm_theme_group_file_find(th, buf2); if (!file) return EINA_FALSE; - if (edje_object_file_set(o, file, buf2)) return EINA_TRUE; + if (edje_object_mmap_set(o, file, buf2)) return EINA_TRUE; DBG("could not set theme group '%s' from file '%s': %s", - buf2, file, edje_load_error_str(edje_object_load_error_get(o))); + buf2, + eina_file_filename_get(file), + edje_load_error_str(edje_object_load_error_get(o))); return EINA_FALSE; } @@ -287,7 +325,7 @@ _elm_theme_icon_set(Elm_Theme *th, const char *group, const char *style) { - const char *file; + Eina_File *file; char buf2[1024]; int w, h; @@ -296,7 +334,7 @@ _elm_theme_icon_set(Elm_Theme *th, file = _elm_theme_group_file_find(th, buf2); if (file) { - elm_image_file_set(o, file, buf2); + elm_image_mmap_set(o, file, buf2); elm_image_object_size_get(o, &w, &h); if (w > 0) return EINA_TRUE; } @@ -305,7 +343,7 @@ _elm_theme_icon_set(Elm_Theme *th, if (!file) return EINA_FALSE; - elm_image_file_set(o, file, buf2); + elm_image_mmap_set(o, file, buf2); elm_image_object_size_get(o, &w, &h); return w > 0; @@ -315,6 +353,7 @@ Eina_Bool _elm_theme_parse(Elm_Theme *th, const char *theme) { Eina_List *names = NULL; + Eina_File *f; const char *p, *pe; if (!th) th = &(theme_default); @@ -363,13 +402,15 @@ _elm_theme_parse(Elm_Theme *th, const char *theme) if (p) names = eina_list_append(names, p); } if (th->cache) eina_hash_free(th->cache); - th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_file_close)); if (th->cache_data) eina_hash_free(th->cache_data); th->cache_data = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); - EINA_LIST_FREE(th->themes, p) eina_stringshare_del(p); + EINA_LIST_FREE(th->themes.items, p) eina_stringshare_del(p); + EINA_LIST_FREE(th->themes.handles, f) eina_file_close(f); - th->themes = names; + EINA_LIST_FREE(names, p) + _elm_theme_file_item_add(&th->themes, p); return EINA_TRUE; } @@ -391,7 +432,7 @@ elm_theme_new(void) Elm_Theme *th = calloc(1, sizeof(Elm_Theme)); if (!th) return NULL; th->ref = 1; - th->themes = eina_list_append(th->themes, eina_stringshare_add("default")); + _elm_theme_file_item_add(&th->themes, "default"); themes = eina_list_append(themes, th); return th; } @@ -409,12 +450,24 @@ elm_theme_free(Elm_Theme *th) } } +static void +elm_theme_files_copy(Elm_Theme_Files *dst, Elm_Theme_Files *src) +{ + const Eina_List *l; + const Eina_File *f; + const char *item; + + EINA_LIST_FOREACH(src->items, l, item) + dst->items = eina_list_append(dst->items, + eina_stringshare_ref(item)); + EINA_LIST_FOREACH(src->handles, l, f) + dst->handles = eina_list_append(dst->handles, + eina_file_dup(f)); +} + EAPI void elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst) { - const Eina_List *l; - const char *f; - if (!th) th = &(theme_default); if (!thdst) thdst = &(theme_default); _elm_theme_clear(thdst); @@ -425,21 +478,10 @@ elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst) eina_list_append(thdst->ref_theme->referrers, thdst); thdst->ref_theme->ref++; } - EINA_LIST_FOREACH(th->overlay, l, f) - { - const char *s = eina_stringshare_add(f); - if (s) thdst->overlay = eina_list_append(thdst->overlay, s); - } - EINA_LIST_FOREACH(th->themes, l, f) - { - const char *s = eina_stringshare_add(f); - if (s) thdst->themes = eina_list_append(thdst->themes, s); - } - EINA_LIST_FOREACH(th->extension, l, f) - { - const char *s = eina_stringshare_add(f); - if (s) thdst->extension = eina_list_append(thdst->extension, s); - } + elm_theme_files_copy(&thdst->overlay, &th->overlay); + elm_theme_files_copy(&thdst->themes, &th->themes); + elm_theme_files_copy(&thdst->extension, &th->extension); + if (th->theme) thdst->theme = eina_stringshare_add(th->theme); elm_theme_flush(thdst); } @@ -476,29 +518,18 @@ elm_theme_default_get(void) EAPI void elm_theme_overlay_add(Elm_Theme *th, const char *item) { - const char *f = eina_stringshare_add(item); - + if (!item) return; if (!th) th = &(theme_default); - if (f) th->overlay = eina_list_prepend(th->overlay, f); + _elm_theme_file_item_add(&th->overlay, item); elm_theme_flush(th); } EAPI void elm_theme_overlay_del(Elm_Theme *th, const char *item) { - const Eina_List *l; - const char *f, *s; - + if (!item) return ; if (!th) th = &(theme_default); - s = eina_stringshare_add(item); - EINA_LIST_FOREACH(th->overlay, l, f) - if (f == s) - { - eina_stringshare_del(f); - th->overlay = eina_list_remove_list(th->overlay, (Eina_List *)l); - break; - } - eina_stringshare_del(s); + _elm_theme_file_item_del(&th->overlay, item); elm_theme_flush(th); } @@ -506,35 +537,24 @@ EAPI const Eina_List * elm_theme_overlay_list_get(const Elm_Theme *th) { if (!th) th = &(theme_default); - return th->overlay; + return th->overlay.items; } EAPI void elm_theme_extension_add(Elm_Theme *th, const char *item) { - const char *f = eina_stringshare_add(item); - + if (!item) return ; if (!th) th = &(theme_default); - if (f) th->extension = eina_list_append(th->extension, f); + _elm_theme_file_item_add(&th->extension, item); elm_theme_flush(th); } EAPI void elm_theme_extension_del(Elm_Theme *th, const char *item) { - const Eina_List *l; - const char *f, *s; - + if (!item) return ; if (!th) th = &(theme_default); - s = eina_stringshare_add(item); - EINA_LIST_FOREACH(th->extension, l, f) - if (f == s) - { - eina_stringshare_del(f); - th->extension = eina_list_remove_list(th->extension, (Eina_List *)l); - break; - } - eina_stringshare_del(s); + _elm_theme_file_item_del(&th->extension, item); elm_theme_flush(th); } @@ -542,7 +562,7 @@ EAPI const Eina_List * elm_theme_extension_list_get(const Elm_Theme *th) { if (!th) th = &(theme_default); - return th->extension; + return th->extension.items; } EAPI void @@ -567,7 +587,7 @@ elm_theme_get(Elm_Theme *th) const char *f; buf = eina_strbuf_new(); - EINA_LIST_FOREACH(th->themes, l, f) + EINA_LIST_FOREACH(th->themes.items, l, f) { while (*f) { @@ -589,7 +609,7 @@ EAPI const Eina_List * elm_theme_list_get(const Elm_Theme *th) { if (!th) th = &(theme_default); - return th->themes; + return th->themes.items; } EAPI char * @@ -646,7 +666,7 @@ elm_theme_flush(Elm_Theme *th) { if (!th) th = &(theme_default); if (th->cache) eina_hash_free(th->cache); - th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_file_close)); if (th->cache_data) eina_hash_free(th->cache_data); th->cache_data = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); _elm_win_rescale(th, EINA_TRUE); @@ -773,80 +793,62 @@ elm_theme_group_path_find(Elm_Theme *th, const char *group) { EINA_SAFETY_ON_NULL_RETURN_VAL(group, NULL); if (!th) th = &(theme_default); - return _elm_theme_group_file_find(th, group); + return eina_file_filename_get(_elm_theme_group_file_find(th, group)); } static Eina_List * -_file_find_append(Eina_List *list, const char *home, const char *f) +_elm_theme_file_group_base_list(Eina_List *list, + Eina_List *handles, + const char *base, int len) { - char buf[PATH_MAX]; + Eina_Stringshare *c, *c2; + Eina_List *coll; + Eina_List *in, *l, *ll; + Eina_File *f; - if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) || - ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) || - ((isalpha(f[0])) && (f[1] == ':'))) + EINA_LIST_FOREACH(handles, l, f) { - list = eina_list_append(list, eina_stringshare_add(f)); - } - else if (((f[0] == '~') && (f[1] == '/'))) - { - snprintf(buf, sizeof(buf), "%s/%s", home, f + 2); - list = eina_list_append(list, eina_stringshare_add(buf)); - } - else - { - snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f); - list = eina_list_append(list, eina_stringshare_add(buf)); - snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f); - list = eina_list_append(list, eina_stringshare_add(buf)); + coll = edje_mmap_collection_list(f); + EINA_LIST_FOREACH(coll, ll, c) + { + // if base == start of collection str + if (!strncmp(c, base, len)) + { + // check if already in list + EINA_LIST_FOREACH(list, in, c2) + if (c == c2) + break; + + // if not already in list append shared str to list + if (!in) + list = eina_list_append(list, eina_stringshare_ref(c)); + } + } + edje_mmap_collection_list_free(coll); } + return list; } EAPI Eina_List * elm_theme_group_base_list(Elm_Theme *th, const char *base) { - Eina_List *list = NULL, *files = NULL, *coll, *l; + Eina_List *list; int len; - Eina_Stringshare *c, *c2, *f; - static const char *home = NULL; + EINA_SAFETY_ON_NULL_RETURN_VAL(base, NULL); if (!th) th = &(theme_default); // XXX: look results up in a hash for speed len = strlen(base); - if (!home) // get homedir once only - { - home = getenv("HOME"); - if (!home) home = ""; - } - // go through overlay, themes and extensions in that order and build list - EINA_LIST_FOREACH(th->overlay, l, f) - files = _file_find_append(files, home, f); - EINA_LIST_FOREACH(th->themes, l, f) - files = _file_find_append(files, home, f); - EINA_LIST_FOREACH(th->extension, l, f) - files = _file_find_append(files, home, f); // go through all possible theme files and find collections that match - EINA_LIST_FREE(files, f) - { - coll = edje_file_collection_list(f); - EINA_LIST_FREE(coll, c) - { - if (!strncmp(c, base, len)) // if base == start of collection str - { - EINA_LIST_FOREACH(list, l, c2) // check if already in list - { - if (!strcmp(c, c2)) break; - } - if (!l) // if not already in list append shared str to list - { - c2 = eina_stringshare_add(c); - list = eina_list_append(list, c2); - } - } - eina_stringshare_del(c); - } - } + list = _elm_theme_file_group_base_list(NULL, th->overlay.handles, + base, len); + list = _elm_theme_file_group_base_list(list, th->themes.handles, + base, len); + list = _elm_theme_file_group_base_list(list, th->extension.handles, + base, len); + // sort the list nicely at the end list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcmp)); // XXX: store results in hash for fast lookup...