1 #include <Elementary.h>
5 * @defgroup Theme Theme
8 * Functions to modify the theme in the currently running app.
11 static Elm_Theme theme_default =
13 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1
16 static Eina_List *themes = NULL;
19 _elm_theme_clear(Elm_Theme *th)
22 EINA_LIST_FREE(th->themes, p)
23 eina_stringshare_del(p);
24 EINA_LIST_FREE(th->overlay, p)
25 eina_stringshare_del(p);
26 EINA_LIST_FREE(th->extension, p)
27 eina_stringshare_del(p);
30 eina_hash_free(th->cache);
35 eina_stringshare_del(th->theme);
40 th->ref_theme->referrers =
41 eina_list_remove(th->ref_theme->referrers, th);
42 elm_theme_free(th->ref_theme);
48 _elm_theme_find_try(Elm_Theme *th, const char *f, const char *group)
52 if (edje_file_group_exists(f, group))
54 file = eina_stringshare_add(f);
57 eina_hash_add(th->cache, group, file);
65 _elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group)
68 const char *file = NULL;
70 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
71 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
72 ((isalpha(f[0])) && (f[1] == ':')))
73 return _elm_theme_find_try(th, f, group);
74 else if (((f[0] == '~') && (f[1] == '/')))
76 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
77 return _elm_theme_find_try(th, buf, group);
79 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, f);
80 file = _elm_theme_find_try(th, buf, group);
81 if (file) return file;
82 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
83 file = _elm_theme_find_try(th, buf, group);
88 _elm_theme_group_file_find(Elm_Theme *th, const char *group)
92 static const char *home = NULL;
93 const char *file = eina_hash_find(th->cache, group);
95 if (file) return file;
98 home = getenv("HOME");
101 EINA_LIST_FOREACH(th->overlay, l, f)
103 file = _elm_theme_theme_element_try(th, home, f, group);
104 if (file) return file;
106 EINA_LIST_FOREACH(th->themes, l, f)
108 file = _elm_theme_theme_element_try(th, home, f, group);
109 if (file) return file;
111 EINA_LIST_FOREACH(th->extension, l, f)
113 file = _elm_theme_theme_element_try(th, home, f, group);
114 if (file) return file;
116 if (th->ref_theme) return _elm_theme_group_file_find(th->ref_theme, group);
121 _elm_theme_object_set(Evas_Object *parent, Evas_Object *o, const char *clas, const char *group, const char *style)
123 Elm_Theme *th = NULL;
124 if (parent) th = elm_widget_theme_get(parent);
125 return _elm_theme_set(th, o, clas, group, style);
129 _elm_theme_object_icon_set(Evas_Object *parent, Evas_Object *o, const char *group, const char *style)
131 Elm_Theme *th = NULL;
132 if (parent) th = elm_widget_theme_get(parent);
133 return _elm_theme_icon_set(th, o, group, style);
137 _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *group, const char *style)
143 if (!th) th = &(theme_default);
144 snprintf(buf2, sizeof(buf2), "elm/%s/%s/%s", clas, group, style);
145 file = _elm_theme_group_file_find(th, buf2);
148 ok = edje_object_file_set(o, file, buf2);
149 if (ok) return EINA_TRUE;
151 DBG("could not set theme group '%s' from file '%s': %s",
152 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
154 snprintf(buf2, sizeof(buf2), "elm/%s/%s/default", clas, group);
155 file = _elm_theme_group_file_find(th, buf2);
156 if (!file) return EINA_FALSE;
157 ok = edje_object_file_set(o, file, buf2);
159 DBG("could not set theme group '%s' from file '%s': %s",
160 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
165 _elm_theme_icon_set(Elm_Theme *th, Evas_Object *o, const char *group, const char *style)
171 if (!th) th = &(theme_default);
172 snprintf(buf2, sizeof(buf2), "elm/icon/%s/%s", group, style);
173 file = _elm_theme_group_file_find(th, buf2);
176 _els_smart_icon_file_edje_set(o, file, buf2);
177 _els_smart_icon_size_get(o, &w, &h);
178 if (w > 0) return EINA_TRUE;
180 snprintf(buf2, sizeof(buf2), "elm/icon/%s/default", group);
181 file = _elm_theme_group_file_find(th, buf2);
182 if (!file) return EINA_FALSE;
183 _els_smart_icon_file_edje_set(o, file, buf2);
184 _els_smart_icon_size_get(o, &w, &h);
189 _elm_theme_parse(Elm_Theme *th, const char *theme)
191 Eina_List *names = NULL;
194 if (!th) th = &(theme_default);
201 if ((*pe == ':') || (!*pe))
202 { // p -> pe == 'name:'
205 char *n = malloc(pe - p + 1);
210 strncpy(n, p, pe - p);
212 nn = eina_stringshare_add(n);
213 if (nn) names = eina_list_append(names, nn);
225 p = eina_list_data_get(eina_list_last(names));
226 if ((!p) || ((p) && (strcmp(p, "default"))))
228 p = eina_stringshare_add("default");
229 if (p) names = eina_list_append(names, p);
231 if (th->cache) eina_hash_free(th->cache);
232 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
234 EINA_LIST_FREE(th->themes, p) eina_stringshare_del(p);
241 _elm_theme_shutdown(void)
243 _elm_theme_clear(&(theme_default));
249 Elm_Theme *th = calloc(1, sizeof(Elm_Theme));
250 if (!th) return NULL;
252 th->themes = eina_list_append(th->themes, eina_stringshare_add("default"));
253 themes = eina_list_append(themes, th);
258 elm_theme_free(Elm_Theme *th)
260 EINA_SAFETY_ON_NULL_RETURN(th);
264 _elm_theme_clear(th);
265 themes = eina_list_remove(themes, th);
271 elm_theme_ref_set(Elm_Theme *th, Elm_Theme *thref)
273 if (!th) th = &(theme_default);
274 if (!thref) thref = &(theme_default);
275 if (th->ref_theme == thref) return;
276 _elm_theme_clear(th);
279 thref->referrers = eina_list_append(thref->referrers, th);
282 th->ref_theme = thref;
287 elm_theme_ref_get(Elm_Theme *th)
289 if (!th) th = &(theme_default);
290 return th->ref_theme;
294 elm_theme_default_get(void)
296 return &theme_default;
300 elm_theme_overlay_add(Elm_Theme *th, const char *item)
302 const char *f = eina_stringshare_add(item);
304 if (!th) th = &(theme_default);
305 if (f) th->overlay = eina_list_prepend(th->overlay, f);
310 elm_theme_extension_add(Elm_Theme *th, const char *item)
312 const char *f = eina_stringshare_add(item);
314 if (!th) th = &(theme_default);
315 if (f) th->extension = eina_list_append(th->extension, f);
320 elm_theme_extension_del(Elm_Theme *th, const char *item)
325 if (!th) th = &(theme_default);
326 s = eina_stringshare_add(item);
327 EINA_LIST_FOREACH(th->extension, l, f)
330 eina_stringshare_del(f);
331 th->extension = eina_list_remove_list(th->extension, (Eina_List *)l);
334 eina_stringshare_del(s);
339 elm_theme_set(Elm_Theme *th, const char *theme)
341 if (!th) th = &(theme_default);
342 _elm_theme_parse(th, theme);
345 eina_stringshare_del(th->theme);
352 elm_theme_get(Elm_Theme *th)
354 if (!th) th = &(theme_default);
363 EINA_LIST_FOREACH(th->themes, l, f)
366 if (l->next) len += 1;
368 tmp = alloca(len + 1);
370 EINA_LIST_FOREACH(th->themes, l, f)
373 if (l->next) strcat(tmp, ":");
375 th->theme = eina_stringshare_add(tmp);
380 EAPI const Eina_List *
381 elm_theme_list_get(const Elm_Theme *th)
383 if (!th) th = &(theme_default);
388 elm_theme_list_item_path_get(const char *f, Eina_Bool *in_search_path)
390 static const char *home = NULL;
395 if (in_search_path) *in_search_path = EINA_FALSE;
401 home = getenv("HOME");
402 if (!home) home = "";
405 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
406 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
407 ((isalpha(f[0])) && (f[1] == ':')))
409 if (in_search_path) *in_search_path = EINA_FALSE;
412 else if (((f[0] == '~') && (f[1] == '/')))
414 if (in_search_path) *in_search_path = EINA_FALSE;
415 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
418 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, f);
419 if (ecore_file_exists(buf))
421 if (in_search_path) *in_search_path = EINA_TRUE;
425 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
426 if (ecore_file_exists(buf))
428 if (in_search_path) *in_search_path = EINA_TRUE;
432 if (in_search_path) *in_search_path = EINA_FALSE;
437 elm_theme_flush(Elm_Theme *th)
439 if (!th) th = &(theme_default);
440 if (th->cache) eina_hash_free(th->cache);
441 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
442 _elm_win_rescale(th, EINA_TRUE);
448 EINA_LIST_FOREACH(th->referrers, l, th2) elm_theme_flush(th2);
453 elm_theme_full_flush(void)
458 EINA_LIST_FOREACH(themes, l, th)
462 elm_theme_flush(&(theme_default));
466 elm_theme_all_set(const char *theme)
468 #ifdef HAVE_ELEMENTARY_X
469 static Ecore_X_Atom atom = 0;
471 if (!atom) atom = ecore_x_atom_get("ENLIGHTENMENT_THEME");
472 ecore_x_window_prop_string_set(ecore_x_window_root_first_get(),
474 //FIXME - ecore_x_window_prop_string_set() works properly only after ecore_x_window_prop_string_get() is called.
475 ecore_x_window_prop_string_get(ecore_x_window_root_first_get(), atom);
477 elm_theme_set(NULL, theme);
481 elm_theme_name_available_list_new(void)
483 Eina_List *list = NULL;
485 char buf[PATH_MAX], *file, *s, *th;
486 static const char *home = NULL;
490 home = getenv("HOME");
491 if (!home) home = "";
494 snprintf(buf, sizeof(buf), "%s/.elementary/themes", home);
495 dir = ecore_file_ls(buf);
496 EINA_LIST_FREE(dir, file)
498 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s", home, file);
499 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
501 s = strchr(file, '.');
502 if ((s) && (!strcasecmp(s, ".edj")))
507 list = eina_list_append(list, th);
513 snprintf(buf, sizeof(buf), "%s/themes", _elm_data_dir);
514 dir = ecore_file_ls(buf);
515 EINA_LIST_FREE(dir, file)
517 snprintf(buf, sizeof(buf), "%s/themes/%s", _elm_data_dir, file);
518 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
520 s = strchr(file, '.');
521 if ((s) && (!strcasecmp(s, ".edj")))
529 EINA_LIST_FOREACH(list, l, s)
538 else list = eina_list_append(list, th);
543 list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcasecmp));
548 elm_theme_name_available_list_free(Eina_List *list)
551 EINA_LIST_FREE(list, s) free(s);
555 elm_object_theme_set(Evas_Object *obj, Elm_Theme *th)
557 EINA_SAFETY_ON_NULL_RETURN(obj);
558 elm_widget_theme_set(obj, th);
562 elm_object_theme_get(const Evas_Object *obj)
564 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
565 return elm_widget_theme_get(obj);