1 #include <Elementary.h>
7 * Functions to modify the theme in the currently running app.
10 static Elm_Theme theme_default =
12 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1
15 static Eina_List *themes = NULL;
18 _elm_theme_clear(Elm_Theme *th)
21 EINA_LIST_FREE(th->themes, p)
22 eina_stringshare_del(p);
23 EINA_LIST_FREE(th->overlay, p)
24 eina_stringshare_del(p);
25 EINA_LIST_FREE(th->extension, p)
26 eina_stringshare_del(p);
29 eina_hash_free(th->cache);
34 eina_stringshare_del(th->theme);
39 th->ref_theme->referrers =
40 eina_list_remove(th->ref_theme->referrers, th);
41 elm_theme_free(th->ref_theme);
47 _elm_theme_find_try(Elm_Theme *th, const char *f, const char *group)
51 if (edje_file_group_exists(f, group))
53 file = eina_stringshare_add(f);
56 eina_hash_add(th->cache, group, file);
64 _elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group)
67 const char *file = NULL;
69 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
70 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
71 ((isalpha(f[0])) && (f[1] == ':')))
72 return _elm_theme_find_try(th, f, group);
73 else if (((f[0] == '~') && (f[1] == '/')))
75 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
76 return _elm_theme_find_try(th, buf, group);
78 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, f);
79 file = _elm_theme_find_try(th, buf, group);
80 if (file) return file;
81 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
82 file = _elm_theme_find_try(th, buf, group);
87 _elm_theme_group_file_find(Elm_Theme *th, const char *group)
91 static const char *home = NULL;
92 const char *file = eina_hash_find(th->cache, group);
94 if (file) return file;
97 home = getenv("HOME");
100 EINA_LIST_FOREACH(th->overlay, l, f)
102 file = _elm_theme_theme_element_try(th, home, f, group);
103 if (file) return file;
105 EINA_LIST_FOREACH(th->themes, l, f)
107 file = _elm_theme_theme_element_try(th, home, f, group);
108 if (file) return file;
110 EINA_LIST_FOREACH(th->extension, l, f)
112 file = _elm_theme_theme_element_try(th, home, f, group);
113 if (file) return file;
115 if (th->ref_theme) return _elm_theme_group_file_find(th->ref_theme, group);
120 _elm_theme_object_set(Evas_Object *parent, Evas_Object *o, const char *clas, const char *group, const char *style)
122 Elm_Theme *th = NULL;
123 if (parent) th = elm_widget_theme_get(parent);
124 return _elm_theme_set(th, o, clas, group, style);
128 _elm_theme_object_icon_set(Evas_Object *parent, Evas_Object *o, const char *group, const char *style)
130 Elm_Theme *th = NULL;
131 if (parent) th = elm_widget_theme_get(parent);
132 return _elm_theme_icon_set(th, o, group, style);
136 _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *group, const char *style)
142 if (!th) th = &(theme_default);
143 snprintf(buf2, sizeof(buf2), "elm/%s/%s/%s", clas, group, style);
144 file = _elm_theme_group_file_find(th, buf2);
147 ok = edje_object_file_set(o, file, buf2);
148 if (ok) return EINA_TRUE;
150 DBG("could not set theme group '%s' from file '%s': %s",
151 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
153 snprintf(buf2, sizeof(buf2), "elm/%s/%s/default", clas, group);
154 file = _elm_theme_group_file_find(th, buf2);
155 if (!file) return EINA_FALSE;
156 ok = edje_object_file_set(o, file, buf2);
158 DBG("could not set theme group '%s' from file '%s': %s",
159 buf2, file, edje_load_error_str(edje_object_load_error_get(o)));
164 _elm_theme_icon_set(Elm_Theme *th, Evas_Object *o, const char *group, const char *style)
170 if (!th) th = &(theme_default);
171 snprintf(buf2, sizeof(buf2), "elm/icon/%s/%s", group, style);
172 file = _elm_theme_group_file_find(th, buf2);
175 _els_smart_icon_file_edje_set(o, file, buf2);
176 _els_smart_icon_size_get(o, &w, &h);
177 if (w > 0) return EINA_TRUE;
179 snprintf(buf2, sizeof(buf2), "elm/icon/%s/default", group);
180 file = _elm_theme_group_file_find(th, buf2);
181 if (!file) return EINA_FALSE;
182 _els_smart_icon_file_edje_set(o, file, buf2);
183 _els_smart_icon_size_get(o, &w, &h);
188 _elm_theme_parse(Elm_Theme *th, const char *theme)
190 Eina_List *names = NULL;
193 if (!th) th = &(theme_default);
200 if ((*pe == ':') || (!*pe))
201 { // p -> pe == 'name:'
204 char *n = malloc(pe - p + 1);
209 strncpy(n, p, pe - p);
211 nn = eina_stringshare_add(n);
212 if (nn) names = eina_list_append(names, nn);
224 p = eina_list_data_get(eina_list_last(names));
225 if ((!p) || ((p) && (strcmp(p, "default"))))
227 p = eina_stringshare_add("default");
228 if (p) names = eina_list_append(names, p);
230 if (th->cache) eina_hash_free(th->cache);
231 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
233 EINA_LIST_FREE(th->themes, p) eina_stringshare_del(p);
240 _elm_theme_shutdown(void)
242 _elm_theme_clear(&(theme_default));
246 * Create a new specific theme
248 * This creates an empty specific theme that only uses the default theme. A
249 * specific theme has its own private set of extensions and overlays too
250 * (which are empty by default). Specific themes do not fall back to themes
251 * of parent objects. They are not intended for this use. Use styles, overlays
252 * and extensions when needed, but avoid specific themes unless there is no
253 * other way (example: you want to have a preview of a new theme you are
254 * selecting in a "theme selector" window. The preview is inside a scroller
255 * and should display what the theme you selected will look like, but not
256 * actually apply it yet. The child of the scroller will have a specific
257 * theme set to show this preview before the user decides to apply it to all
265 Elm_Theme *th = calloc(1, sizeof(Elm_Theme));
266 if (!th) return NULL;
268 th->themes = eina_list_append(th->themes, eina_stringshare_add("default"));
269 themes = eina_list_append(themes, th);
274 * Free a specific theme
276 * @param th The theme to free
278 * This frees a theme created with elm_theme_new().
283 elm_theme_free(Elm_Theme *th)
285 EINA_SAFETY_ON_NULL_RETURN(th);
289 _elm_theme_clear(th);
290 themes = eina_list_remove(themes, th);
296 * Copy the theme fom the source to the destination theme
298 * @param th The source theme to copy from
299 * @param thdst The destination theme to copy data to
301 * This makes a one-time static copy of all the theme config, extensions
302 * and overlays from @p th to @p thdst. If @p th references a theme, then
303 * @p thdst is also set to reference it, with all the theme settings,
304 * overlays and extensions that @p th had.
307 elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst)
312 if (!th) th = &(theme_default);
313 if (!thdst) thdst = &(theme_default);
314 _elm_theme_clear(thdst);
317 thdst->ref_theme = th->ref_theme;
318 thdst->ref_theme->referrers =
319 eina_list_append(thdst->ref_theme->referrers, thdst);
320 thdst->ref_theme->ref++;
322 EINA_LIST_FOREACH(th->overlay, l, f)
324 const char *s = eina_stringshare_add(f);
325 if (s) thdst->overlay = eina_list_append(thdst->overlay, s);
327 EINA_LIST_FOREACH(th->themes, l, f)
329 const char *s = eina_stringshare_add(f);
330 if (s) thdst->themes = eina_list_append(thdst->themes, s);
332 EINA_LIST_FOREACH(th->extension, l, f)
334 const char *s = eina_stringshare_add(f);
335 if (s) thdst->extension = eina_list_append(thdst->extension, s);
337 if (th->theme) thdst->theme = eina_stringshare_add(th->theme);
338 elm_theme_flush(thdst);
342 * Tell the source theme to reference the ref theme
344 * @param th The theme that will do the referencing
345 * @param thref The theme that is the reference source
347 * This clears @p th to be empty and then sets it to refer to @p thref
348 * so @p th acts as an override to @p thdst, but where its overrides
349 * don't apply, it will fall through to @pthref for configuration.
352 elm_theme_ref_set(Elm_Theme *th, Elm_Theme *thref)
354 if (!th) th = &(theme_default);
355 if (!thref) thref = &(theme_default);
356 if (th->ref_theme == thref) return;
357 _elm_theme_clear(th);
360 thref->referrers = eina_list_append(thref->referrers, th);
363 th->ref_theme = thref;
368 * Return the theme referred to
370 * @param th The theme to get the reference from
371 * @return The referenced theme handle
373 * This gets the theme set as the reference theme by elm_theme_ref_set().
374 * If no theme is set as a reference, NULL is returned.
377 elm_theme_ref_get(Elm_Theme *th)
379 if (!th) th = &(theme_default);
380 return th->ref_theme;
384 * Return the default theme
386 * @return The default theme handle
388 * This returns the internal default theme setup handle that all widgets
389 * use implicitly unless a specific theme is set. This is also often use
390 * as a shorthand of NULL.
393 elm_theme_default_get(void)
395 return &theme_default;
399 * Prepends a theme overlay to the list of overlays
401 * @param th The theme to add to, or if NULL, the default theme
402 * @param item The Edje file path to be used
404 * Use this if your application needs to provide some custom overlay theme
405 * (An Edje file that replaces some default styles of widgets) where adding
406 * new styles, or changing system theme configuration is not possible. Do
407 * NOT use this instead of a proper system theme configuration. Use proper
408 * configuration files, profiles, environment variables etc. to set a theme
409 * so that the theme can be altered by simple confiugration by a user. Using
410 * this call to achieve that effect is abusing the API and will create lots
416 elm_theme_overlay_add(Elm_Theme *th, const char *item)
418 const char *f = eina_stringshare_add(item);
420 if (!th) th = &(theme_default);
421 if (f) th->overlay = eina_list_prepend(th->overlay, f);
426 * Delete a theme overlay from the list of overlays
428 * @param th The theme to delete from, or if NULL, the default theme
429 * @param item The name of the theme overlay
431 * See elm_theme_overlay_add().
436 elm_theme_overlay_del(Elm_Theme *th, const char *item)
441 if (!th) th = &(theme_default);
442 s = eina_stringshare_add(item);
443 EINA_LIST_FOREACH(th->overlay, l, f)
446 eina_stringshare_del(f);
447 th->overlay = eina_list_remove_list(th->overlay, (Eina_List *)l);
450 eina_stringshare_del(s);
455 * Appends a theme extension to the list of extensions.
457 * @param th The theme to add to, or if NULL, the default theme
458 * @param item The Edje file path to be used
460 * This is intended when an application needs more styles of widgets or new
461 * widget themes that the default does not provide (or may not provide). The
462 * application has "extended" usage by coming up with new custom style names
463 * for widgets for specific uses, but as these are not "standard", they are
464 * not guaranteed to be provided by a default theme. This means the
465 * application is required to provide these extra elements itself in specific
466 * Edje files. This call adds one of those Edje files to the theme search
467 * path to be search after the default theme. The use of this call is
468 * encouraged when default styles do not meet the needs of the application.
469 * Use this call instead of elm_theme_overlay_add() for almost all cases.
474 elm_theme_extension_add(Elm_Theme *th, const char *item)
476 const char *f = eina_stringshare_add(item);
478 if (!th) th = &(theme_default);
479 if (f) th->extension = eina_list_append(th->extension, f);
484 * Deletes a theme extension from the list of extensions.
486 * @param th The theme to delete from, or if NULL, the default theme
487 * @param item The name of the theme extension
489 * See elm_theme_extension_add().
494 elm_theme_extension_del(Elm_Theme *th, const char *item)
499 if (!th) th = &(theme_default);
500 s = eina_stringshare_add(item);
501 EINA_LIST_FOREACH(th->extension, l, f)
504 eina_stringshare_del(f);
505 th->extension = eina_list_remove_list(th->extension, (Eina_List *)l);
508 eina_stringshare_del(s);
513 * Set the theme search order for the given theme
515 * @param th The theme to set the search order, or if NULL, the default theme
516 * @param theme Theme search string
518 * This sets the search string for the theme in path-notation from first
519 * theme to search, to last, delimited by the : character. Example:
521 * "shiny:/path/to/file.edj:default"
523 * See the ELM_THEME environment variable for more information.
528 elm_theme_set(Elm_Theme *th, const char *theme)
530 if (!th) th = &(theme_default);
531 _elm_theme_parse(th, theme);
534 eina_stringshare_del(th->theme);
541 * Return the theme search order
543 * @param th The theme to get the search order, or if NULL, the default theme
544 * @return The internal search order path
546 * See elm_theme_set() for more information.
551 elm_theme_get(Elm_Theme *th)
553 if (!th) th = &(theme_default);
562 EINA_LIST_FOREACH(th->themes, l, f)
565 if (l->next) len += 1;
567 tmp = alloca(len + 1);
569 EINA_LIST_FOREACH(th->themes, l, f)
572 if (l->next) strcat(tmp, ":");
574 th->theme = eina_stringshare_add(tmp);
580 * Return a list of theme elements to be used in a theme.
582 * @param th Theme to get the list of theme elements from.
583 * @return The internal list of theme elements
585 * This returns the internal list of theme elements (will only be valid as
586 * long as the theme is not modified by elm_theme_set() or theme is not
587 * freed by elm_theme_free(). This is a list of strings which must not be
588 * altered as they are also internal. If @p th is NULL, then the default
589 * theme element list is returned.
591 EAPI const Eina_List *
592 elm_theme_list_get(const Elm_Theme *th)
594 if (!th) th = &(theme_default);
599 * Return the full patrh for a theme element
601 * @param f The theme element name
602 * @param in_search_path Pointer to a boolean to indicate if item is in the search path or not
603 * @return The full path to the file found.
605 * This returns a string you should free with free() on success, NULL on
606 * failure. This will search for the given theme element, and if it is a
607 * full or relative path element or a simple searchable name. The returned
608 * path is the full path to the file, if searched, and the file exists, or it
609 * is simply the full path given in the element or a resolved path if
610 * relative to home. The @p in_search_path boolean pointed to is set to
611 * EINA_TRUE if the file was a searchable file andis in the search path,
612 * and EINA_FALSE otherwise.
615 elm_theme_list_item_path_get(const char *f, Eina_Bool *in_search_path)
617 static const char *home = NULL;
622 if (in_search_path) *in_search_path = EINA_FALSE;
628 home = getenv("HOME");
629 if (!home) home = "";
632 if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
633 ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
634 ((isalpha(f[0])) && (f[1] == ':')))
636 if (in_search_path) *in_search_path = EINA_FALSE;
639 else if (((f[0] == '~') && (f[1] == '/')))
641 if (in_search_path) *in_search_path = EINA_FALSE;
642 snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
645 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, f);
646 if (ecore_file_exists(buf))
648 if (in_search_path) *in_search_path = EINA_TRUE;
652 snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
653 if (ecore_file_exists(buf))
655 if (in_search_path) *in_search_path = EINA_TRUE;
659 if (in_search_path) *in_search_path = EINA_FALSE;
664 * Flush the current theme.
666 * @param th Theme to flush
668 * This flushes caches that let elementary know where to find theme elements
669 * in the given theme. If @p th is NULL, then the default theme is flushed.
670 * Call this call if source theme data has changed in such a way as to
671 * make any caches Elementary kept invalid.
676 elm_theme_flush(Elm_Theme *th)
678 if (!th) th = &(theme_default);
679 if (th->cache) eina_hash_free(th->cache);
680 th->cache = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
681 _elm_win_rescale(th, EINA_TRUE);
687 EINA_LIST_FOREACH(th->referrers, l, th2) elm_theme_flush(th2);
692 * This flushes all themes (default and specific ones).
694 * This will flush all themes in the current application context, by calling
695 * elm_theme_flush() on each of them.
700 elm_theme_full_flush(void)
705 EINA_LIST_FOREACH(themes, l, th)
709 elm_theme_flush(&(theme_default));
713 * Set the theme for all elementary using applications on the current display
715 * @param theme The name of the theme to use. Format same as the ELM_THEME
716 * environment variable.
721 elm_theme_all_set(const char *theme)
723 #ifdef HAVE_ELEMENTARY_X
724 static Ecore_X_Atom atom = 0;
726 if (!atom) atom = ecore_x_atom_get("ENLIGHTENMENT_THEME");
727 ecore_x_window_prop_string_set(ecore_x_window_root_first_get(),
730 elm_theme_set(NULL, theme);
734 * Return a list of theme elements in the theme search path
736 * @return A list of strings that are the theme element names.
738 * This lists all available theme files in the standard Elementary search path
739 * for theme elements, and returns them in alphabetical order as theme
740 * element names in a list of strings. Free this with
741 * elm_theme_name_available_list_free() when you are done with the list.
744 elm_theme_name_available_list_new(void)
746 Eina_List *list = NULL;
748 char buf[PATH_MAX], *file, *s, *th;
749 static const char *home = NULL;
753 home = getenv("HOME");
754 if (!home) home = "";
757 snprintf(buf, sizeof(buf), "%s/.elementary/themes", home);
758 dir = ecore_file_ls(buf);
759 EINA_LIST_FREE(dir, file)
761 snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s", home, file);
762 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
764 s = strchr(file, '.');
765 if ((s) && (!strcasecmp(s, ".edj")))
770 list = eina_list_append(list, th);
776 snprintf(buf, sizeof(buf), "%s/themes", _elm_data_dir);
777 dir = ecore_file_ls(buf);
778 EINA_LIST_FREE(dir, file)
780 snprintf(buf, sizeof(buf), "%s/themes/%s", _elm_data_dir, file);
781 if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
783 s = strchr(file, '.');
784 if ((s) && (!strcasecmp(s, ".edj")))
792 EINA_LIST_FOREACH(list, l, s)
801 else list = eina_list_append(list, th);
806 list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcasecmp));
811 * Free the list returned by elm_theme_name_available_list_new()
813 * This frees the list of themes returned by
814 * elm_theme_name_available_list_new(). Once freed the list should no longer
815 * be used. a new list mys be created.
818 elm_theme_name_available_list_free(Eina_List *list)
821 EINA_LIST_FREE(list, s) free(s);
825 * Set a specific theme to be used for this object and its children
827 * @param obj The object to set the theme on
828 * @param th The theme to set
830 * This sets a specific theme that will be used for the given object and any
831 * child objects it has. If @p th is NULL then the theme to be used is
832 * cleared and the object will inherit its theme from its parent (which
833 * ultimately will use the default theme if no specific themes are set).
835 * Use special themes with great care as this will annoy users and make
836 * configuration difficult. Avoid any custom themes at all if it can be
842 elm_object_theme_set(Evas_Object *obj, Elm_Theme *th)
844 EINA_SAFETY_ON_NULL_RETURN(obj);
845 elm_widget_theme_set(obj, th);
849 * Get the specific theme to be used
851 * @param obj The object to get the specific theme from
852 * @return The specifc theme set.
854 * This will return a specific theme set, or NULL if no specific theme is
855 * set on that object. It will not return inherited themes from parents, only
856 * the specific theme set for that specific object. See elm_object_theme_set()
857 * for more information.
862 elm_object_theme_get(const Evas_Object *obj)
864 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
865 return elm_widget_theme_get(obj);