3 /* local subsystem functions */
4 typedef struct _E_Theme_Result E_Theme_Result;
13 static Eina_Bool _e_theme_mappings_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
14 static Eina_Bool _e_theme_mappings_quickfind_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
15 static void _e_theme_category_register(const char *category);
16 static Eina_List *_e_theme_collection_item_register(Eina_List *list, const char *name);
17 static Eina_List *_e_theme_collection_items_find(const char *base, const char *collname);
20 /* local subsystem globals */
21 static Eina_Hash *mappings = NULL;
22 static Eina_Hash *group_cache = NULL;
24 static Eina_List *categories = NULL;
25 static E_Fm2_Mime_Handler *theme_hdl = NULL;
27 /* externally accessible functions */
35 /* Register mime handler */
36 theme_hdl = e_fm2_mime_handler_new(_("Set As Theme"), "preferences-desktop-theme",
37 e_theme_handler_set, NULL,
38 e_theme_handler_test, NULL);
39 if (theme_hdl) e_fm2_mime_handler_glob_add(theme_hdl, "*.edj");
41 /* this is a fallback that is ALWAYS there - if all fails things will */
42 /* always fall back to the default theme. the rest after this are config */
43 /* values users can set */
44 e_theme_file_set("base", "default.edj");
46 EINA_LIST_FOREACH(e_config->themes, l, et)
50 snprintf(buf, sizeof(buf), "base/%s", et->category);
51 e_theme_file_set(buf, et->file);
54 if (!mappings) mappings = eina_hash_string_superfast_new(NULL);
55 group_cache = eina_hash_string_superfast_new(NULL);
61 e_theme_shutdown(void)
67 e_fm2_mime_handler_glob_del(theme_hdl, "*.edj");
68 e_fm2_mime_handler_free(theme_hdl);
72 eina_hash_foreach(mappings, _e_theme_mappings_free_cb, NULL);
73 eina_hash_free(mappings);
78 eina_hash_free(group_cache);
81 EINA_LIST_FREE(categories, str)
82 eina_stringshare_del(str);
88 e_theme_edje_object_set(Evas_Object *o, const char *category, const char *group)
94 /* find category -> edje mapping */
95 _e_theme_category_register(category);
96 res = eina_hash_find(mappings, category);
101 /* if found check cached path */
107 /* if its not an absolute path find it */
109 str = e_path_find(path_themes, str);
110 /* save cached value */
111 if (str) res->cache = str;
118 snprintf(buf, sizeof(buf), "%s/::/%s", str, group);
119 tres = eina_hash_find(group_cache, buf);
122 ok = edje_object_file_set(o, str, group);
123 /* save in the group cache hash */
125 eina_hash_add(group_cache, buf, res);
127 eina_hash_add(group_cache, buf, (void *)1);
129 else if (tres == (void *)1)
136 edje_object_file_set(o, str, group);
141 /* no mapping or set failed - fall back */
142 eina_strlcpy(buf, category, sizeof(buf));
143 /* shorten string up to and not including last / char */
144 p = strrchr(buf, '/');
146 /* no / anymore - we are already as far back as we can go */
148 /* try this category */
149 return e_theme_edje_object_set(o, buf, group);
153 _e_theme_edje_file_get(const char *category, const char *group, Eina_Bool fallback_icon)
160 /* find category -> edje mapping */
161 _e_theme_category_register(category);
162 res = eina_hash_find(mappings, category);
164 if (e_config->icon_theme &&
166 (!strcmp(category, "base")) &&
167 (!strncmp(group, "e/icons", 7)))
174 /* if found check cached path */
180 /* if its not an absolute path find it */
182 str = e_path_find(path_themes, str);
183 /* save cached value */
184 if (str) res->cache = str;
192 snprintf(buf, sizeof(buf), "%s/::/%s", str, group);
193 tres = eina_hash_find(group_cache, buf);
196 /* if the group exists - return */
201 res->quickfind = eina_hash_string_superfast_new(NULL);
202 /* create a quick find hash of all group entries */
203 coll = edje_file_collection_list(str);
205 EINA_LIST_FOREACH(coll, l, col)
207 q = eina_stringshare_add(col);
208 eina_hash_direct_add(res->quickfind, q, q);
210 if (coll) edje_file_collection_list_free(coll);
212 /* save in the group cache hash */
213 if (eina_hash_find(res->quickfind, group))
215 eina_hash_add(group_cache, buf, res);
220 eina_hash_add(group_cache, buf, (void *)1);
224 else if (tres == (void *)1) /* special pointer "1" == not there */
231 /* no mapping or set failed - fall back */
232 eina_strlcpy(buf, category, sizeof(buf));
233 /* shorten string up to and not including last / char */
234 p = strrchr(buf, '/');
236 /* no / anymore - we are already as far back as we can go */
238 /* try this category */
239 return e_theme_edje_file_get(buf, group);
243 e_theme_edje_file_get(const char *category, const char *group)
245 return _e_theme_edje_file_get(category, group, EINA_FALSE);
249 e_theme_edje_icon_fallback_file_get(const char *group)
251 return _e_theme_edje_file_get("base", group, EINA_TRUE);
255 * this is used to set the theme for a CATEGORY of E17. "base" is always set
256 * to the default theme - because if a selected theme wants "base/theme", but
257 * does not provide theme elements, it can fall back to the default theme.
259 * the idea is you can actually set a different theme for different parts of
262 * other possible categories...
263 * e_theme_file_set("base/theme/about", "default.edj");
264 * e_theme_file_set("base/theme/borders", "default.edj");
265 * e_theme_file_set("base/theme/background", "default.edj");
266 * e_theme_file_set("base/theme/configure", "default.edj");
267 * e_theme_file_set("base/theme/dialog", "default.edj");
268 * e_theme_file_set("base/theme/menus", "default.edj");
269 * e_theme_file_set("base/theme/error", "default.edj");
270 * e_theme_file_set("base/theme/gadman", "default.edj");
271 * e_theme_file_set("base/theme/dnd", "default.edj");
272 * e_theme_file_set("base/theme/icons", "default.edj");
273 * e_theme_file_set("base/theme/pointer", "default.edj");
274 * e_theme_file_set("base/theme/transitions", "default.edj");
275 * e_theme_file_set("base/theme/widgets", "default.edj");
276 * e_theme_file_set("base/theme/winlist", "default.edj");
277 * e_theme_file_set("base/theme/modules", "default.edj");
278 * e_theme_file_set("base/theme/modules/pager", "default.edj");
279 * e_theme_file_set("base/theme/modules/ibar", "default.edj");
280 * e_theme_file_set("base/theme/modules/ibox", "default.edj");
281 * e_theme_file_set("base/theme/modules/clock", "default.edj");
282 * e_theme_file_set("base/theme/modules/battery", "default.edj");
283 * e_theme_file_set("base/theme/modules/cpufreq", "default.edj");
284 * e_theme_file_set("base/theme/modules/start", "default.edj");
285 * e_theme_file_set("base/theme/modules/temperature", "default.edj");
289 e_theme_file_set(const char *category, const char *file)
295 eina_hash_free(group_cache);
298 _e_theme_category_register(category);
299 res = eina_hash_find(mappings, category);
302 eina_hash_del(mappings, category, res);
305 e_filereg_deregister(res->file);
306 eina_stringshare_del(res->file);
308 if (res->cache) eina_stringshare_del(res->cache);
311 res = E_NEW(E_Theme_Result, 1);
312 res->file = eina_stringshare_add(file);
313 e_filereg_register(res->file);
315 mappings = eina_hash_string_superfast_new(NULL);
316 eina_hash_add(mappings, category, res);
320 e_theme_config_set(const char *category, const char *file)
325 /* Don't accept unused categories */
327 if (!e_theme_category_find(category)) return 0;
330 /* search for the category */
331 EINA_LIST_FOREACH(e_config->themes, next, ect)
333 if (!strcmp(ect->category, category))
335 if (ect->file) eina_stringshare_del(ect->file);
336 ect->file = eina_stringshare_add(file);
341 /* the text class doesnt exist */
342 ect = E_NEW(E_Config_Theme, 1);
343 ect->category = eina_stringshare_add(category);
344 ect->file = eina_stringshare_add(file);
346 e_config->themes = eina_list_append(e_config->themes, ect);
351 * returns a pointer to the data, return null if nothing if found.
353 EAPI E_Config_Theme *
354 e_theme_config_get(const char *category)
356 E_Config_Theme *ect = NULL;
359 /* search for the category */
360 EINA_LIST_FOREACH(e_config->themes, next, ect)
362 if (!strcmp(ect->category, category))
369 e_theme_config_remove(const char *category)
374 /* search for the category */
375 EINA_LIST_FOREACH(e_config->themes, next, ect)
377 if (!strcmp(ect->category, category))
379 e_config->themes = eina_list_remove_list(e_config->themes, next);
380 if (ect->category) eina_stringshare_del(ect->category);
381 if (ect->file) eina_stringshare_del(ect->file);
390 e_theme_config_list(void)
392 return e_config->themes;
396 e_theme_category_find(const char *category)
398 if (eina_list_search_sorted(categories, EINA_COMPARE_CB(strcmp), category))
404 e_theme_category_list(void)
410 e_theme_transition_find(const char *transition)
412 Eina_List *trans = NULL;
417 _e_theme_collection_items_find("base/theme/transitions", "e/transitions");
419 if (eina_list_search_sorted(trans, EINA_COMPARE_CB(strcmp), transition))
422 EINA_LIST_FREE(trans, str)
423 eina_stringshare_del(str);
429 e_theme_transition_list(void)
431 return _e_theme_collection_items_find("base/theme/transitions",
436 e_theme_border_find(const char *border)
438 Eina_List *bds = NULL;
443 _e_theme_collection_items_find("base/theme/borders", "e/widgets/border");
445 if (eina_list_search_sorted(bds, EINA_COMPARE_CB(strcmp), border))
448 EINA_LIST_FREE(bds, str)
449 eina_stringshare_del(str);
455 e_theme_border_list(void)
457 return _e_theme_collection_items_find("base/theme/borders",
462 e_theme_shelf_find(const char *shelf)
464 Eina_List *shelfs = NULL;
469 _e_theme_collection_items_find("base/theme/shelf", "e/shelf");
471 if (eina_list_search_sorted(shelfs, EINA_COMPARE_CB(strcmp), shelf))
474 EINA_LIST_FREE(shelfs, str)
475 eina_stringshare_del(str);
481 e_theme_shelf_list(void)
483 return _e_theme_collection_items_find("base/theme/shelf", "e/shelf");
487 e_theme_comp_find(const char *comp)
489 Eina_List *comps = NULL;
493 comps = _e_theme_collection_items_find("base/theme/borders", "e/comp");
495 if (eina_list_search_sorted(comps, EINA_COMPARE_CB(strcmp), comp))
498 EINA_LIST_FREE(comps, str)
499 eina_stringshare_del(str);
505 e_theme_comp_list(void)
507 return _e_theme_collection_items_find("base/theme/borders", "e/comp");
511 e_theme_handler_set(Evas_Object *obj __UNUSED__, const char *path, void *data __UNUSED__)
519 /* if not in system dir or user dir, copy to user dir */
520 e_prefix_data_concat_static(buf, "data/themes");
521 if (!strncmp(buf, path, strlen(buf)))
525 e_user_dir_concat_static(buf, "themes");
526 if (!strncmp(buf, path, strlen(buf)))
534 file = ecore_file_file_get(path);
535 name = ecore_file_strip_ext(file);
537 e_user_dir_snprintf(buf, sizeof(buf), "themes/%s-%f.edj", name, ecore_time_unix_get());
540 if (!ecore_file_exists(buf))
542 ecore_file_cp(path, buf);
543 e_theme_config_set("theme", buf);
546 e_theme_config_set("theme", path);
549 e_theme_config_set("theme", path);
551 e_config_save_queue();
552 a = e_action_find("restart");
553 if ((a) && (a->func.go)) a->func.go(NULL, NULL);
557 e_theme_handler_test(Evas_Object *obj __UNUSED__, const char *path, void *data __UNUSED__)
560 if (!edje_file_group_exists(path, "e/widgets/border/default/border"))
565 /* local subsystem functions */
567 _e_theme_mappings_free_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
572 if (res->file) eina_stringshare_del(res->file);
573 if (res->cache) eina_stringshare_del(res->cache);
576 eina_hash_foreach(res->quickfind, _e_theme_mappings_quickfind_free_cb, NULL);
577 eina_hash_free(res->quickfind);
584 _e_theme_mappings_quickfind_free_cb(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata __UNUSED__)
586 eina_stringshare_del(key);
591 _e_theme_category_register(const char *category)
597 categories = eina_list_append(categories, eina_stringshare_add(category));
599 l = eina_list_search_sorted_near_list(categories, EINA_COMPARE_CB(strcmp),
605 categories = eina_list_append_relative_list(categories, eina_stringshare_add(category), l);
607 categories = eina_list_prepend_relative_list(categories, eina_stringshare_add(category), l);
611 _e_theme_collection_item_register(Eina_List *list, const char *name)
616 EINA_LIST_FOREACH(list, l, item)
618 if (!strcmp(name, item)) return list;
620 list = eina_list_append(list, eina_stringshare_add(name));
625 _e_theme_collection_items_find(const char *base, const char *collname)
627 Eina_List *list = NULL;
631 category = alloca(strlen(base) + 1);
632 strcpy(category, base);
635 res = eina_hash_find(mappings, category);
640 /* if found check cached path */
646 /* if its not an absolute path find it */
647 if (str[0] != '/') str = e_path_find(path_themes, str);
648 /* save cached value */
649 if (str) res->cache = str;
655 coll = edje_file_collection_list(str);
661 collname_len = strlen(collname);
662 EINA_LIST_FOREACH(coll, l, c)
664 if (!strncmp(c, collname, collname_len))
669 p = trans + collname_len + 1;
674 list = _e_theme_collection_item_register(list, p);
679 edje_file_collection_list_free(coll);
683 p = strrchr(category, '/');
688 list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcmp));