elm_theme: use Eina_File all over the place in an attempt to reduce race condition.
authorCedric Bail <cedric.bail@samsung.com>
Mon, 4 Nov 2013 03:17:58 +0000 (12:17 +0900)
committerCedric Bail <cedric.bail@samsung.com>
Mon, 4 Nov 2013 03:19:04 +0000 (12:19 +0900)
src/lib/elm_priv.h
src/lib/elm_theme.c

index e6f91cc..fc1c063 100644 (file)
@@ -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;
index 65f09d1..17e25aa 100644 (file)
 
 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_clear(Elm_Theme *th)
+_elm_theme_file_item_add(Elm_Theme_Files *files, const char *item)
 {
-   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);
+   Eina_Strbuf *buf = NULL;
+   Eina_File *f = NULL;
+   const char *home;
 
-   ELM_SAFE_FREE(th->cache, eina_hash_free);
-   ELM_SAFE_FREE(th->cache_data, eina_hash_free);
-   ELM_SAFE_FREE(th->theme, eina_stringshare_del);
-   if (th->ref_theme)
+   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] == ':')))
      {
-        th->ref_theme->referrers =
-           eina_list_remove(th->ref_theme->referrers, th);
-        elm_theme_free(th->ref_theme);
-        th->ref_theme = NULL;
+        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 const char *
-_elm_theme_find_try(Elm_Theme *th, const char *f, const char *group)
+static void
+_elm_theme_file_item_del(Elm_Theme_Files *files, const char *str)
 {
-   const char *file;
+   Eina_List *l, *ll;
+   Eina_List *l2, *ll2;
+   const char *item;
+
+   str = eina_stringshare_add(str);
+   l2 = files->handles;
 
-   if (edje_file_group_exists(f, group))
+   EINA_LIST_FOREACH_SAFE(files->items, l, ll, item)
      {
-        file = eina_stringshare_add(f);
-        if (file)
+        ll2 = l2->next;
+
+        if (item == str)
           {
-             eina_hash_add(th->cache, group, file);
-             return file;
+             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;
      }
-   return NULL;
+
+   eina_stringshare_del(str);
 }
 
-static const char *
-_elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group)
+static void
+_elm_theme_file_clean(Elm_Theme_Files *files)
 {
-   char buf[PATH_MAX];
-   const char *file = NULL;
+   const char *item;
+   Eina_File *f;
 
-   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] == '/')))
+   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)
+{
+   _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);
+   ELM_SAFE_FREE(th->theme, eina_stringshare_del);
+   if (th->ref_theme)
      {
-        snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
-        return _elm_theme_find_try(th, buf, group);
+        th->ref_theme->referrers =
+           eina_list_remove(th->ref_theme->referrers, th);
+        elm_theme_free(th->ref_theme);
+        th->ref_theme = NULL;
      }
-   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)
-     {
-        home = getenv("HOME");
-        if (!home) home = "";
-     }
-   EINA_LIST_FOREACH(th->overlay, l, f)
+
+   EINA_LIST_FOREACH(th->overlay.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->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)
@@ -127,55 +189,27 @@ _elm_theme_find_data_try(Elm_Theme *th, const char *f, const char *key)
 }
 
 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)
-     {
-        home = getenv("HOME");
-        if (!home) home = "";
-     }
-   EINA_LIST_FOREACH(th->overlay, l, f)
+
+   EINA_LIST_FOREACH(th->overlay.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->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)
      }
 }
 
-EAPI void
-elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst)
+static void
+elm_theme_files_copy(Elm_Theme_Files *dst, Elm_Theme_Files *src)
 {
    const Eina_List *l;
-   const char *f;
+   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)
+{
    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...