1 #include <Elementary.h>
4 static Elm_Theme theme_default =
6 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1
9 static Eina_List *themes = NULL;
12 _elm_theme_clear(Elm_Theme *th)
15 EINA_LIST_FREE(th->themes, p)
16 eina_stringshare_del(p);
17 EINA_LIST_FREE(th->overlay, p)
18 eina_stringshare_del(p);
19 EINA_LIST_FREE(th->extension, p)
20 eina_stringshare_del(p);
23 eina_hash_free(th->cache);
28 eina_hash_free(th->cache_data);
29 th->cache_data = NULL;
33 eina_stringshare_del(th->theme);
38 th->ref_theme->referrers =
39 eina_list_remove(th->ref_theme->referrers, th);
40 elm_theme_free(th->ref_theme);
46 _elm_theme_find_try(Elm_Theme *th, const char *f, const char *group)
50 if (edje_file_group_exists(f, group))
52 file = eina_stringshare_add(f);
55 eina_hash_add(th->cache, group, file);
63 _elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group)
66 const char *file = NULL;
68 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
69 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
70 ((isalpha(f[0])) && (f[1] == ':')))
71 return _elm_theme_find_try(th, f, group);
72 else if (((f[0] == '~') && (f[1] == '/')))
74 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
75 return _elm_theme_find_try(th, buf, group);
77 snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f);
78 file = _elm_theme_find_try(th, buf, group);
79 if (file) return file;
80 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
81 file = _elm_theme_find_try(th, buf, group);
86 _elm_theme_group_file_find(Elm_Theme *th, const char *group)
90 static const char *home = NULL;
91 const char *file = eina_hash_find(th->cache, group);
93 if (file) return file;
96 home = getenv("HOME");
99 EINA_LIST_FOREACH(th->overlay, l, f)
101 file = _elm_theme_theme_element_try(th, home, f, group);
102 if (file) return file;
104 EINA_LIST_FOREACH(th->themes, l, f)
106 file = _elm_theme_theme_element_try(th, home, f, group);
107 if (file) return file;
109 EINA_LIST_FOREACH(th->extension, l, f)
111 file = _elm_theme_theme_element_try(th, home, f, group);
112 if (file) return file;
114 if (th->ref_theme) return _elm_theme_group_file_find(th->ref_theme, group);
119 _elm_theme_find_data_try(Elm_Theme *th, const char *f, const char *key)
124 data = edje_file_data_get(f, key);
125 t = eina_stringshare_add(data);
129 eina_hash_add(th->cache, key, t);
136 _elm_theme_theme_data_try(Elm_Theme *th, const char *home, const char *f, const char *key)
139 const char *data = NULL;
141 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
142 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
143 ((isalpha(f[0])) && (f[1] == ':')))
144 return _elm_theme_find_data_try(th, f, key);
145 else if (((f[0] == '~') && (f[1] == '/')))
147 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
148 return _elm_theme_find_try(th, buf, key);
150 snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f);
151 data = _elm_theme_find_data_try(th, buf, key);
152 if (data) return data;
153 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
154 data = _elm_theme_find_data_try(th, buf, key);
159 _elm_theme_data_find(Elm_Theme *th, const char *key)
163 static const char *home = NULL;
164 const char *data = eina_hash_find(th->cache_data, key);
166 if (data) return data;
169 home = getenv("HOME");
170 if (!home) home = "";
172 EINA_LIST_FOREACH(th->overlay, l, f)
174 data = _elm_theme_theme_data_try(th, home, f, key);
175 if (data) return data;
177 EINA_LIST_FOREACH(th->themes, l, f)
179 data = _elm_theme_theme_data_try(th, home, f, key);
180 if (data) return data;
182 EINA_LIST_FOREACH(th->extension, l, f)
184 data = _elm_theme_theme_data_try(th, home, f, key);
185 if (data) return data;
187 if (th->ref_theme) return _elm_theme_data_find(th->ref_theme, key);
191 static void _elm_theme_idler_clean(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
194 _elm_theme_reload_idler(void *data)
196 Evas_Object *elm = data;
198 elm_widget_theme(elm);
199 evas_object_data_del(elm, "elm-theme-reload-idler");
200 evas_object_event_callback_del(elm, EVAS_CALLBACK_DEL, _elm_theme_idler_clean);
205 _elm_theme_idler_clean(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
209 idler = evas_object_data_get(obj, "elm-theme-reload-idler");
210 if (idler) ecore_idler_del(idler);
211 evas_object_data_del(obj, "elm-theme-reload-idler");
215 _elm_theme_reload(void *data __UNUSED__, Evas_Object *obj,
216 const char *emission __UNUSED__, const char *source __UNUSED__)
220 elm = evas_object_data_get(obj, "elm-parent");
223 evas_object_event_callback_add(elm, EVAS_CALLBACK_DEL, _elm_theme_idler_clean, NULL);
224 evas_object_data_set(elm, "elm-theme-reload-idler", ecore_idler_add(_elm_theme_reload_idler, elm));
229 _elm_theme_object_set(Evas_Object *parent, Evas_Object *o, const char *clas, const char *group, const char *style)
231 Elm_Theme *th = NULL;
234 if (parent) th = elm_widget_theme_get(parent);
235 if (!_elm_theme_set(th, o, clas, group, style)) return EINA_FALSE;
237 test = evas_object_data_get(o, "edje,theme,watcher");
240 edje_object_signal_callback_add(o, "edje,change,file", "edje",
241 _elm_theme_reload, NULL);
242 evas_object_data_set(o, "edje,theme,watcher", (void*) -1);
247 /* only issued by elm_icon.c */
249 _elm_theme_object_icon_set(Evas_Object *o,
253 Elm_Theme *th = elm_widget_theme_get(o);
255 return _elm_theme_icon_set(th, o, group, style);
259 _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *group, const char *style)
264 if ((!clas) || (!group) || (!style)) return EINA_FALSE;
265 if (!th) th = &(theme_default);
267 snprintf(buf2, sizeof(buf2), "elm/%s/%s/%s", clas, group, style);
268 file = _elm_theme_group_file_find(th, buf2);
271 if (edje_object_file_set(o, file, buf2))
274 DBG("could not set theme group '%s' from file '%s': %s",
275 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
278 snprintf(buf2, sizeof(buf2), "elm/%s/%s/default", clas, group);
279 file = _elm_theme_group_file_find(th, buf2);
280 if (!file) return EINA_FALSE;
281 if (edje_object_file_set(o, file, buf2)) return EINA_TRUE;
282 DBG("could not set theme group '%s' from file '%s': %s",
283 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
289 _elm_theme_icon_set(Elm_Theme *th,
298 if (!th) th = &(theme_default);
299 snprintf(buf2, sizeof(buf2), "elm/icon/%s/%s", group, style);
300 file = _elm_theme_group_file_find(th, buf2);
303 elm_image_file_set(o, file, buf2);
304 elm_image_object_size_get(o, &w, &h);
305 if (w > 0) return EINA_TRUE;
307 snprintf(buf2, sizeof(buf2), "elm/icon/%s/default", group);
308 file = _elm_theme_group_file_find(th, buf2);
310 if (!file) return EINA_FALSE;
312 elm_image_file_set(o, file, buf2);
313 elm_image_object_size_get(o, &w, &h);
319 _elm_theme_parse(Elm_Theme *th, const char *theme)
321 Eina_List *names = NULL;
324 if (!th) th = &(theme_default);
329 buf = eina_strbuf_new();
335 if ((pe[0] == '\\') && (pe[1] == ':'))
337 eina_strbuf_append_char(buf, ':');
340 else if ((*pe == ':') || (!*pe))
341 { // p -> pe == 'name:'
346 nn = eina_stringshare_add(eina_strbuf_string_get(buf));
347 if (nn) names = eina_list_append(names, nn);
348 eina_strbuf_reset(buf);
356 eina_strbuf_append_char(buf, *pe);
361 eina_strbuf_free(buf);
363 p = eina_list_data_get(eina_list_last(names));
364 if ((!p) || ((p) && (strcmp(p, "default"))))
366 p = eina_stringshare_add("default");
367 if (p) names = eina_list_append(names, p);
369 if (th->cache) eina_hash_free(th->cache);
370 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
371 if (th->cache_data) eina_hash_free(th->cache_data);
372 th->cache_data = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
374 EINA_LIST_FREE(th->themes, p) eina_stringshare_del(p);
381 _elm_theme_shutdown(void)
383 _elm_theme_clear(&(theme_default));
389 Elm_Theme *th = calloc(1, sizeof(Elm_Theme));
390 if (!th) return NULL;
392 th->themes = eina_list_append(th->themes, eina_stringshare_add("default"));
393 themes = eina_list_append(themes, th);
398 elm_theme_free(Elm_Theme *th)
400 EINA_SAFETY_ON_NULL_RETURN(th);
404 _elm_theme_clear(th);
405 themes = eina_list_remove(themes, th);
411 elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst)
416 if (!th) th = &(theme_default);
417 if (!thdst) thdst = &(theme_default);
418 _elm_theme_clear(thdst);
421 thdst->ref_theme = th->ref_theme;
422 thdst->ref_theme->referrers =
423 eina_list_append(thdst->ref_theme->referrers, thdst);
424 thdst->ref_theme->ref++;
426 EINA_LIST_FOREACH(th->overlay, l, f)
428 const char *s = eina_stringshare_add(f);
429 if (s) thdst->overlay = eina_list_append(thdst->overlay, s);
431 EINA_LIST_FOREACH(th->themes, l, f)
433 const char *s = eina_stringshare_add(f);
434 if (s) thdst->themes = eina_list_append(thdst->themes, s);
436 EINA_LIST_FOREACH(th->extension, l, f)
438 const char *s = eina_stringshare_add(f);
439 if (s) thdst->extension = eina_list_append(thdst->extension, s);
441 if (th->theme) thdst->theme = eina_stringshare_add(th->theme);
442 elm_theme_flush(thdst);
446 elm_theme_ref_set(Elm_Theme *th, Elm_Theme *thref)
448 if (!th) th = &(theme_default);
449 if (!thref) thref = &(theme_default);
450 if (th->ref_theme == thref) return;
451 _elm_theme_clear(th);
454 thref->referrers = eina_list_append(thref->referrers, th);
457 th->ref_theme = thref;
462 elm_theme_ref_get(Elm_Theme *th)
464 if (!th) th = &(theme_default);
465 return th->ref_theme;
469 elm_theme_default_get(void)
471 return &theme_default;
475 elm_theme_overlay_add(Elm_Theme *th, const char *item)
477 const char *f = eina_stringshare_add(item);
479 if (!th) th = &(theme_default);
480 if (f) th->overlay = eina_list_prepend(th->overlay, f);
485 elm_theme_overlay_del(Elm_Theme *th, const char *item)
490 if (!th) th = &(theme_default);
491 s = eina_stringshare_add(item);
492 EINA_LIST_FOREACH(th->overlay, l, f)
495 eina_stringshare_del(f);
496 th->overlay = eina_list_remove_list(th->overlay, (Eina_List *)l);
499 eina_stringshare_del(s);
503 EAPI const Eina_List *
504 elm_theme_overlay_list_get(const Elm_Theme *th)
506 if (!th) th = &(theme_default);
511 elm_theme_extension_add(Elm_Theme *th, const char *item)
513 const char *f = eina_stringshare_add(item);
515 if (!th) th = &(theme_default);
516 if (f) th->extension = eina_list_append(th->extension, f);
521 elm_theme_extension_del(Elm_Theme *th, const char *item)
526 if (!th) th = &(theme_default);
527 s = eina_stringshare_add(item);
528 EINA_LIST_FOREACH(th->extension, l, f)
531 eina_stringshare_del(f);
532 th->extension = eina_list_remove_list(th->extension, (Eina_List *)l);
535 eina_stringshare_del(s);
539 EAPI const Eina_List *
540 elm_theme_extension_list_get(const Elm_Theme *th)
542 if (!th) th = &(theme_default);
543 return th->extension;
547 elm_theme_set(Elm_Theme *th, const char *theme)
549 if (!th) th = &(theme_default);
550 _elm_theme_parse(th, theme);
553 eina_stringshare_del(th->theme);
557 if (th == &(theme_default))
558 eina_stringshare_replace(&_elm_config->theme, theme);
562 elm_theme_get(Elm_Theme *th)
564 if (!th) th = &(theme_default);
571 buf = eina_strbuf_new();
572 EINA_LIST_FOREACH(th->themes, l, f)
577 eina_strbuf_append_char(buf, '\\');
578 eina_strbuf_append_char(buf, *f);
582 if (l->next) eina_strbuf_append_char(buf, ':');
584 th->theme = eina_stringshare_add(eina_strbuf_string_get(buf));
585 eina_strbuf_free(buf);
590 EAPI const Eina_List *
591 elm_theme_list_get(const Elm_Theme *th)
593 if (!th) th = &(theme_default);
598 elm_theme_list_item_path_get(const char *f, Eina_Bool *in_search_path)
600 static const char *home = NULL;
605 if (in_search_path) *in_search_path = EINA_FALSE;
611 home = getenv("HOME");
612 if (!home) home = "";
615 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
616 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
617 ((isalpha(f[0])) && (f[1] == ':')))
619 if (in_search_path) *in_search_path = EINA_FALSE;
622 else if (((f[0] == '~') && (f[1] == '/')))
624 if (in_search_path) *in_search_path = EINA_FALSE;
625 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
628 snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f);
629 if (ecore_file_exists(buf))
631 if (in_search_path) *in_search_path = EINA_TRUE;
635 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
636 if (ecore_file_exists(buf))
638 if (in_search_path) *in_search_path = EINA_TRUE;
642 if (in_search_path) *in_search_path = EINA_FALSE;
647 elm_theme_flush(Elm_Theme *th)
649 if (!th) th = &(theme_default);
650 if (th->cache) eina_hash_free(th->cache);
651 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
652 if (th->cache_data) eina_hash_free(th->cache_data);
653 th->cache_data = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
654 _elm_win_rescale(th, EINA_TRUE);
655 _elm_ews_wm_rescale(th, EINA_TRUE);
661 EINA_LIST_FOREACH(th->referrers, l, th2) elm_theme_flush(th2);
666 elm_theme_full_flush(void)
671 EINA_LIST_FOREACH(themes, l, th)
675 elm_theme_flush(&(theme_default));
679 elm_theme_name_available_list_new(void)
681 Eina_List *list = NULL;
683 char buf[PATH_MAX], *file, *s, *th;
684 static const char *home = NULL;
688 home = getenv("HOME");
689 if (!home) home = "";
692 snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes", home);
693 dir = ecore_file_ls(buf);
694 EINA_LIST_FREE(dir, file)
696 snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s", home, file);
697 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
699 s = strchr(file, '.');
700 if ((s) && (!strcasecmp(s, ".edj")))
705 list = eina_list_append(list, th);
711 snprintf(buf, sizeof(buf), "%s/themes", _elm_data_dir);
712 dir = ecore_file_ls(buf);
713 EINA_LIST_FREE(dir, file)
715 snprintf(buf, sizeof(buf), "%s/themes/%s", _elm_data_dir, file);
716 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
718 s = strchr(file, '.');
719 if ((s) && (!strcasecmp(s, ".edj")))
727 EINA_LIST_FOREACH(list, l, s)
736 else list = eina_list_append(list, th);
741 list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcasecmp));
746 elm_theme_name_available_list_free(Eina_List *list)
749 EINA_LIST_FREE(list, s) free(s);
753 elm_object_theme_set(Evas_Object *obj, Elm_Theme *th)
755 EINA_SAFETY_ON_NULL_RETURN(obj);
756 elm_widget_theme_set(obj, th);
760 elm_object_theme_get(const Evas_Object *obj)
762 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
763 return elm_widget_theme_get(obj);
767 elm_theme_data_get(Elm_Theme *th, const char *key)
769 if (!th) th = &(theme_default);
770 return _elm_theme_data_find(th, key);