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));
247 * Create a new specific theme
249 * This creates an empty specific theme that only uses the default theme. A
250 * specific theme has its own private set of extensions and overlays too
251 * (which are empty by default). Specific themes do not fall back to themes
252 * of parent objects. They are not intended for this use. Use styles, overlays
253 * and extensions when needed, but avoid specific themes unless there is no
254 * other way (example: you want to have a preview of a new theme you are
255 * selecting in a "theme selector" window. The preview is inside a scroller
256 * and should display what the theme you selected will look like, but not
257 * actually apply it yet. The child of the scroller will have a specific
258 * theme set to show this preview before the user decides to apply it to all
266 Elm_Theme *th = calloc(1, sizeof(Elm_Theme));
267 if (!th) return NULL;
269 th->themes = eina_list_append(th->themes, eina_stringshare_add("default"));
270 themes = eina_list_append(themes, th);
275 * Free a specific theme
277 * @param th The theme to free
279 * This frees a theme created with elm_theme_new().
284 elm_theme_free(Elm_Theme *th)
286 EINA_SAFETY_ON_NULL_RETURN(th);
290 _elm_theme_clear(th);
291 themes = eina_list_remove(themes, th);
297 * Copy the theme fom the source to the destination theme
299 * @param th The source theme to copy from
300 * @param thdst The destination theme to copy data to
302 * This makes a one-time static copy of all the theme config, extensions
303 * and overlays from @p th to @p thdst. If @p th references a theme, then
304 * @p thdst is also set to reference it, with all the theme settings,
305 * overlays and extensions that @p th had.
308 elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst)
313 if (!th) th = &(theme_default);
314 if (!thdst) thdst = &(theme_default);
315 _elm_theme_clear(thdst);
318 thdst->ref_theme = th->ref_theme;
319 thdst->ref_theme->referrers =
320 eina_list_append(thdst->ref_theme->referrers, thdst);
321 thdst->ref_theme->ref++;
323 EINA_LIST_FOREACH(th->overlay, l, f)
325 const char *s = eina_stringshare_add(f);
326 if (s) thdst->overlay = eina_list_append(thdst->overlay, s);
328 EINA_LIST_FOREACH(th->themes, l, f)
330 const char *s = eina_stringshare_add(f);
331 if (s) thdst->themes = eina_list_append(thdst->themes, s);
333 EINA_LIST_FOREACH(th->extension, l, f)
335 const char *s = eina_stringshare_add(f);
336 if (s) thdst->extension = eina_list_append(thdst->extension, s);
338 if (th->theme) thdst->theme = eina_stringshare_add(th->theme);
339 elm_theme_flush(thdst);
343 * Tell the source theme to reference the ref theme
345 * @param th The theme that will do the referencing
346 * @param thref The theme that is the reference source
348 * This clears @p th to be empty and then sets it to refer to @p thref
349 * so @p th acts as an override to @p thdst, but where its overrides
350 * don't apply, it will fall through to @pthref for configuration.
353 elm_theme_ref_set(Elm_Theme *th, Elm_Theme *thref)
355 if (!th) th = &(theme_default);
356 if (!thref) thref = &(theme_default);
357 if (th->ref_theme == thref) return;
358 _elm_theme_clear(th);
361 thref->referrers = eina_list_append(thref->referrers, th);
364 th->ref_theme = thref;
369 * Return the theme referred to
371 * @param th The theme to get the reference from
372 * @return The referenced theme handle
374 * This gets the theme set as the reference theme by elm_theme_ref_set().
375 * If no theme is set as a reference, NULL is returned.
378 elm_theme_ref_get(Elm_Theme *th)
380 if (!th) th = &(theme_default);
381 return th->ref_theme;
385 * Return the default theme
387 * @return The default theme handle
389 * This returns the internal default theme setup handle that all widgets
390 * use implicitly unless a specific theme is set. This is also often use
391 * as a shorthand of NULL.
394 elm_theme_default_get(void)
396 return &theme_default;
400 * Prepends a theme overlay to the list of overlays
402 * @param th The theme to add to, or if NULL, the default theme
403 * @param item The Edje file path to be used
405 * Use this if your application needs to provide some custom overlay theme
406 * (An Edje file that replaces some default styles of widgets) where adding
407 * new styles, or changing system theme configuration is not possible. Do
408 * NOT use this instead of a proper system theme configuration. Use proper
409 * configuration files, profiles, environment variables etc. to set a theme
410 * so that the theme can be altered by simple confiugration by a user. Using
411 * this call to achieve that effect is abusing the API and will create lots
417 elm_theme_overlay_add(Elm_Theme *th, const char *item)
419 const char *f = eina_stringshare_add(item);
421 if (!th) th = &(theme_default);
422 if (f) th->overlay = eina_list_prepend(th->overlay, f);
427 * Delete a theme overlay from the list of overlays
429 * @param th The theme to delete from, or if NULL, the default theme
430 * @param item The name of the theme overlay
432 * See elm_theme_overlay_add().
437 elm_theme_overlay_del(Elm_Theme *th, const char *item)
442 if (!th) th = &(theme_default);
443 s = eina_stringshare_add(item);
444 EINA_LIST_FOREACH(th->overlay, l, f)
447 eina_stringshare_del(f);
448 th->overlay = eina_list_remove_list(th->overlay, (Eina_List *)l);
451 eina_stringshare_del(s);
456 * Appends a theme extension to the list of extensions.
458 * @param th The theme to add to, or if NULL, the default theme
459 * @param item The Edje file path to be used
461 * This is intended when an application needs more styles of widgets or new
462 * widget themes that the default does not provide (or may not provide). The
463 * application has "extended" usage by coming up with new custom style names
464 * for widgets for specific uses, but as these are not "standard", they are
465 * not guaranteed to be provided by a default theme. This means the
466 * application is required to provide these extra elements itself in specific
467 * Edje files. This call adds one of those Edje files to the theme search
468 * path to be search after the default theme. The use of this call is
469 * encouraged when default styles do not meet the needs of the application.
470 * Use this call instead of elm_theme_overlay_add() for almost all cases.
475 elm_theme_extension_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->extension = eina_list_append(th->extension, f);
485 * Deletes a theme extension from the list of extensions.
487 * @param th The theme to delete from, or if NULL, the default theme
488 * @param item The name of the theme extension
490 * See elm_theme_extension_add().
495 elm_theme_extension_del(Elm_Theme *th, const char *item)
500 if (!th) th = &(theme_default);
501 s = eina_stringshare_add(item);
502 EINA_LIST_FOREACH(th->extension, l, f)
505 eina_stringshare_del(f);
506 th->extension = eina_list_remove_list(th->extension, (Eina_List *)l);
509 eina_stringshare_del(s);
514 * Set the theme search order for the given theme
516 * @param th The theme to set the search order, or if NULL, the default theme
517 * @param theme Theme search string
519 * This sets the search string for the theme in path-notation from first
520 * theme to search, to last, delimited by the : character. Example:
522 * "shiny:/path/to/file.edj:default"
524 * See the ELM_THEME environment variable for more information.
529 elm_theme_set(Elm_Theme *th, const char *theme)
531 if (!th) th = &(theme_default);
532 _elm_theme_parse(th, theme);
535 eina_stringshare_del(th->theme);
542 * Return the theme search order
544 * @param th The theme to get the search order, or if NULL, the default theme
545 * @return The internal search order path
547 * See elm_theme_set() for more information.
552 elm_theme_get(Elm_Theme *th)
554 if (!th) th = &(theme_default);
563 EINA_LIST_FOREACH(th->themes, l, f)
566 if (l->next) len += 1;
568 tmp = alloca(len + 1);
570 EINA_LIST_FOREACH(th->themes, l, f)
573 if (l->next) strcat(tmp, ":");
575 th->theme = eina_stringshare_add(tmp);
581 * Return a list of theme elements to be used in a theme.
583 * @param th Theme to get the list of theme elements from.
584 * @return The internal list of theme elements
586 * This returns the internal list of theme elements (will only be valid as
587 * long as the theme is not modified by elm_theme_set() or theme is not
588 * freed by elm_theme_free(). This is a list of strings which must not be
589 * altered as they are also internal. If @p th is NULL, then the default
590 * theme element list is returned.
592 EAPI const Eina_List *
593 elm_theme_list_get(const Elm_Theme *th)
595 if (!th) th = &(theme_default);
600 * Return the full patrh for a theme element
602 * @param f The theme element name
603 * @param in_search_path Pointer to a boolean to indicate if item is in the search path or not
604 * @return The full path to the file found.
606 * This returns a string you should free with free() on success, NULL on
607 * failure. This will search for the given theme element, and if it is a
608 * full or relative path element or a simple searchable name. The returned
609 * path is the full path to the file, if searched, and the file exists, or it
610 * is simply the full path given in the element or a resolved path if
611 * relative to home. The @p in_search_path boolean pointed to is set to
612 * EINA_TRUE if the file was a searchable file andis in the search path,
613 * and EINA_FALSE otherwise.
616 elm_theme_list_item_path_get(const char *f, Eina_Bool *in_search_path)
618 static const char *home = NULL;
623 if (in_search_path) *in_search_path = EINA_FALSE;
629 home = getenv("HOME");
630 if (!home) home = "";
633 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
634 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
635 ((isalpha(f[0])) && (f[1] == ':')))
637 if (in_search_path) *in_search_path = EINA_FALSE;
640 else if (((f[0] == '~') && (f[1] == '/')))
642 if (in_search_path) *in_search_path = EINA_FALSE;
643 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
646 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, f);
647 if (ecore_file_exists(buf))
649 if (in_search_path) *in_search_path = EINA_TRUE;
653 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
654 if (ecore_file_exists(buf))
656 if (in_search_path) *in_search_path = EINA_TRUE;
660 if (in_search_path) *in_search_path = EINA_FALSE;
665 * Flush the current theme.
667 * @param th Theme to flush
669 * This flushes caches that let elementary know where to find theme elements
670 * in the given theme. If @p th is NULL, then the default theme is flushed.
671 * Call this call if source theme data has changed in such a way as to
672 * make any caches Elementary kept invalid.
677 elm_theme_flush(Elm_Theme *th)
679 if (!th) th = &(theme_default);
680 if (th->cache) eina_hash_free(th->cache);
681 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
682 _elm_win_rescale(th, EINA_TRUE);
688 EINA_LIST_FOREACH(th->referrers, l, th2) elm_theme_flush(th2);
693 * This flushes all themes (default and specific ones).
695 * This will flush all themes in the current application context, by calling
696 * elm_theme_flush() on each of them.
701 elm_theme_full_flush(void)
706 EINA_LIST_FOREACH(themes, l, th)
710 elm_theme_flush(&(theme_default));
714 * Set the theme for all elementary using applications on the current display
716 * @param theme The name of the theme to use. Format same as the ELM_THEME
717 * environment variable.
722 elm_theme_all_set(const char *theme)
724 #ifdef HAVE_ELEMENTARY_X
725 static Ecore_X_Atom atom = 0;
727 if (!atom) atom = ecore_x_atom_get("ENLIGHTENMENT_THEME");
728 ecore_x_window_prop_string_set(ecore_x_window_root_first_get(),
730 //FIXME - ecore_x_window_prop_string_set() works properly only after ecore_x_window_prop_string_get() is called.
731 ecore_x_window_prop_string_get(ecore_x_window_root_first_get(), atom);
733 elm_theme_set(NULL, theme);
737 * Return a list of theme elements in the theme search path
739 * @return A list of strings that are the theme element names.
741 * This lists all available theme files in the standard Elementary search path
742 * for theme elements, and returns them in alphabetical order as theme
743 * element names in a list of strings. Free this with
744 * elm_theme_name_available_list_free() when you are done with the list.
747 elm_theme_name_available_list_new(void)
749 Eina_List *list = NULL;
751 char buf[PATH_MAX], *file, *s, *th;
752 static const char *home = NULL;
756 home = getenv("HOME");
757 if (!home) home = "";
760 snprintf(buf, sizeof(buf), "%s/.elementary/themes", home);
761 dir = ecore_file_ls(buf);
762 EINA_LIST_FREE(dir, file)
764 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s", home, file);
765 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
767 s = strchr(file, '.');
768 if ((s) && (!strcasecmp(s, ".edj")))
773 list = eina_list_append(list, th);
779 snprintf(buf, sizeof(buf), "%s/themes", _elm_data_dir);
780 dir = ecore_file_ls(buf);
781 EINA_LIST_FREE(dir, file)
783 snprintf(buf, sizeof(buf), "%s/themes/%s", _elm_data_dir, file);
784 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
786 s = strchr(file, '.');
787 if ((s) && (!strcasecmp(s, ".edj")))
795 EINA_LIST_FOREACH(list, l, s)
804 else list = eina_list_append(list, th);
809 list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcasecmp));
814 * Free the list returned by elm_theme_name_available_list_new()
816 * This frees the list of themes returned by
817 * elm_theme_name_available_list_new(). Once freed the list should no longer
818 * be used. a new list mys be created.
821 elm_theme_name_available_list_free(Eina_List *list)
824 EINA_LIST_FREE(list, s) free(s);
828 * Set a specific theme to be used for this object and its children
830 * @param obj The object to set the theme on
831 * @param th The theme to set
833 * This sets a specific theme that will be used for the given object and any
834 * child objects it has. If @p th is NULL then the theme to be used is
835 * cleared and the object will inherit its theme from its parent (which
836 * ultimately will use the default theme if no specific themes are set).
838 * Use special themes with great care as this will annoy users and make
839 * configuration difficult. Avoid any custom themes at all if it can be
845 elm_object_theme_set(Evas_Object *obj, Elm_Theme *th)
847 EINA_SAFETY_ON_NULL_RETURN(obj);
848 elm_widget_theme_set(obj, th);
852 * Get the specific theme to be used
854 * @param obj The object to get the specific theme from
855 * @return The specifc theme set.
857 * This will return a specific theme set, or NULL if no specific theme is
858 * set on that object. It will not return inherited themes from parents, only
859 * the specific theme set for that specific object. See elm_object_theme_set()
860 * for more information.
865 elm_object_theme_get(const Evas_Object *obj)
867 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
868 return elm_widget_theme_get(obj);