elementary/map - map supports language,changed
[framework/uifw/elementary.git] / src / lib / elm_theme.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static Elm_Theme theme_default =
5 {
6    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1
7 };
8
9 static Eina_List *themes = NULL;
10
11 static void
12 _elm_theme_clear(Elm_Theme *th)
13 {
14    const char *p;
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);
21    if (th->cache)
22      {
23         eina_hash_free(th->cache);
24         th->cache = NULL;
25      }
26    if (th->cache_data)
27      {
28         eina_hash_free(th->cache_data);
29         th->cache_data = NULL;
30      }
31    if (th->theme)
32      {
33         eina_stringshare_del(th->theme);
34         th->theme = NULL;
35      }
36    if (th->ref_theme)
37      {
38         th->ref_theme->referrers =
39            eina_list_remove(th->ref_theme->referrers, th);
40         elm_theme_free(th->ref_theme);
41         th->ref_theme = NULL;
42      }
43 }
44
45 static const char *
46 _elm_theme_find_try(Elm_Theme *th, const char *f, const char *group)
47 {
48    const char *file;
49
50    if (edje_file_group_exists(f, group))
51      {
52         file = eina_stringshare_add(f);
53         if (file)
54           {
55              eina_hash_add(th->cache, group, file);
56              return file;
57           }
58      }
59    return NULL;
60 }
61
62 static const char *
63 _elm_theme_theme_element_try(Elm_Theme *th, const char *home, const char *f, const char *group)
64 {
65    char buf[PATH_MAX];
66    const char *file = NULL;
67
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] == '/')))
73      {
74         snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
75         return _elm_theme_find_try(th, buf, group);
76      }
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);
82    return file;
83 }
84
85 static const char *
86 _elm_theme_group_file_find(Elm_Theme *th, const char *group)
87 {
88    const Eina_List *l;
89    const char *f;
90    static const char *home = NULL;
91    const char *file = eina_hash_find(th->cache, group);
92
93    if (file) return file;
94    if (!home)
95      {
96         home = getenv("HOME");
97         if (!home) home = "";
98      }
99    EINA_LIST_FOREACH(th->overlay, l, f)
100      {
101         file = _elm_theme_theme_element_try(th, home, f, group);
102         if (file) return file;
103      }
104    EINA_LIST_FOREACH(th->themes, l, f)
105      {
106         file = _elm_theme_theme_element_try(th, home, f, group);
107         if (file) return file;
108      }
109    EINA_LIST_FOREACH(th->extension, l, f)
110      {
111         file = _elm_theme_theme_element_try(th, home, f, group);
112         if (file) return file;
113      }
114    if (th->ref_theme) return _elm_theme_group_file_find(th->ref_theme, group);
115    return NULL;
116 }
117
118 static const char *
119 _elm_theme_find_data_try(Elm_Theme *th, const char *f, const char *key)
120 {
121    char *data;
122    const char *t;
123
124    data = edje_file_data_get(f, key);
125    t = eina_stringshare_add(data);
126    free(data);
127    if (t)
128      {
129         eina_hash_add(th->cache, key, t);
130         return t;
131      }
132    return NULL;
133 }
134
135 static const char *
136 _elm_theme_theme_data_try(Elm_Theme *th, const char *home, const char *f, const char *key)
137 {
138    char buf[PATH_MAX];
139    const char *data = NULL;
140
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] == '/')))
146      {
147         snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
148         return _elm_theme_find_try(th, buf, key);
149      }
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);
155    return data;
156 }
157
158 static const char *
159 _elm_theme_data_find(Elm_Theme *th, const char *key)
160 {
161    const Eina_List *l;
162    const char *f;
163    static const char *home = NULL;
164    const char *data = eina_hash_find(th->cache_data, key);
165
166    if (data) return data;
167    if (!home)
168      {
169         home = getenv("HOME");
170         if (!home) home = "";
171      }
172    EINA_LIST_FOREACH(th->overlay, l, f)
173      {
174         data = _elm_theme_theme_data_try(th, home, f, key);
175         if (data) return data;
176      }
177    EINA_LIST_FOREACH(th->themes, l, f)
178      {
179         data = _elm_theme_theme_data_try(th, home, f, key);
180         if (data) return data;
181      }
182    EINA_LIST_FOREACH(th->extension, l, f)
183      {
184         data = _elm_theme_theme_data_try(th, home, f, key);
185         if (data) return data;
186      }
187    if (th->ref_theme) return _elm_theme_data_find(th->ref_theme, key);
188    return NULL;
189 }
190
191 static void _elm_theme_idler_clean(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
192
193 static Eina_Bool
194 _elm_theme_reload_idler(void *data)
195 {
196    Evas_Object *elm = data;
197
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);
201    return EINA_FALSE;
202 }
203
204 static void
205 _elm_theme_idler_clean(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
206 {
207    Ecore_Idler *idler;
208
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");
212 }
213
214 static void
215 _elm_theme_reload(void *data __UNUSED__, Evas_Object *obj,
216                   const char *emission __UNUSED__, const char *source __UNUSED__)
217 {
218    Evas_Object *elm;
219
220    elm = evas_object_data_get(obj, "elm-parent");
221    if (elm)
222      {
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));
225      }
226 }
227
228 Eina_Bool
229 _elm_theme_object_set(Evas_Object *parent, Evas_Object *o, const char *clas, const char *group, const char *style)
230 {
231    Elm_Theme *th = NULL;
232    void *test;
233
234    if (parent) th = elm_widget_theme_get(parent);
235    if (!_elm_theme_set(th, o, clas, group, style)) return EINA_FALSE;
236
237    test = evas_object_data_get(o, "edje,theme,watcher");
238    if (!test)
239      {
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);
243      }
244    return EINA_TRUE;
245 }
246
247 /* only issued by elm_icon.c */
248 Eina_Bool
249 _elm_theme_object_icon_set(Evas_Object *o,
250                            const char *group,
251                            const char *style)
252 {
253    Elm_Theme *th = elm_widget_theme_get(o);
254
255    return _elm_theme_icon_set(th, o, group, style);
256 }
257
258 Eina_Bool
259 _elm_theme_set(Elm_Theme *th, Evas_Object *o, const char *clas, const char *group, const char *style)
260 {
261    const char *file;
262    char buf2[1024];
263
264    if ((!clas) || (!group) || (!style)) return EINA_FALSE;
265    if (!th) th = &(theme_default);
266
267    snprintf(buf2, sizeof(buf2), "elm/%s/%s/%s", clas, group, style);
268    file = _elm_theme_group_file_find(th, buf2);
269    if (file)
270      {
271         if (edje_object_file_set(o, file, buf2))
272           return EINA_TRUE;
273         else
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)));
276      }
277
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)));
284
285    return EINA_FALSE;
286 }
287
288 Eina_Bool
289 _elm_theme_icon_set(Elm_Theme *th,
290                     Evas_Object *o,
291                     const char *group,
292                     const char *style)
293 {
294    const char *file;
295    char buf2[1024];
296    int w, h;
297
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);
301    if (file)
302      {
303         elm_image_file_set(o, file, buf2);
304         elm_image_object_size_get(o, &w, &h);
305         if (w > 0) return EINA_TRUE;
306      }
307    snprintf(buf2, sizeof(buf2), "elm/icon/%s/default", group);
308    file = _elm_theme_group_file_find(th, buf2);
309
310    if (!file) return EINA_FALSE;
311
312    elm_image_file_set(o, file, buf2);
313    elm_image_object_size_get(o, &w, &h);
314
315    return w > 0;
316 }
317
318 Eina_Bool
319 _elm_theme_parse(Elm_Theme *th, const char *theme)
320 {
321    Eina_List *names = NULL;
322    const char *p, *pe;
323
324    if (!th) th = &(theme_default);
325    if (theme)
326      {
327         Eina_Strbuf *buf;
328
329         buf = eina_strbuf_new();
330
331         p = theme;
332         pe = p;
333         for (;;)
334           {
335              if ((pe[0] == '\\') && (pe[1] == ':'))
336                {
337                   eina_strbuf_append_char(buf, ':');
338                   pe += 2;
339                }
340              else if ((*pe == ':') || (!*pe))
341                { // p -> pe == 'name:'
342                   if (pe > p)
343                     {
344                        const char *nn;
345
346                        nn = eina_stringshare_add(eina_strbuf_string_get(buf));
347                        if (nn) names = eina_list_append(names, nn);
348                        eina_strbuf_reset(buf);
349                     }
350                   if (!*pe) break;
351                   p = pe + 1;
352                   pe = p;
353                }
354              else
355                {
356                   eina_strbuf_append_char(buf, *pe);
357                   pe++;
358                }
359           }
360
361         eina_strbuf_free(buf);
362      }
363    p = eina_list_data_get(eina_list_last(names));
364    if ((!p) || ((p) && (strcmp(p, "default"))))
365      {
366         p = eina_stringshare_add("default");
367         if (p) names = eina_list_append(names, p);
368      }
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));
373
374    EINA_LIST_FREE(th->themes, p) eina_stringshare_del(p);
375
376    th->themes = names;
377    return EINA_TRUE;
378 }
379
380 void
381 _elm_theme_shutdown(void)
382 {
383    _elm_theme_clear(&(theme_default));
384 }
385
386 EAPI Elm_Theme *
387 elm_theme_new(void)
388 {
389    Elm_Theme *th = calloc(1, sizeof(Elm_Theme));
390    if (!th) return NULL;
391    th->ref = 1;
392    th->themes = eina_list_append(th->themes, eina_stringshare_add("default"));
393    themes = eina_list_append(themes, th);
394    return th;
395 }
396
397 EAPI void
398 elm_theme_free(Elm_Theme *th)
399 {
400    EINA_SAFETY_ON_NULL_RETURN(th);
401    th->ref--;
402    if (th->ref < 1)
403      {
404         _elm_theme_clear(th);
405         themes = eina_list_remove(themes, th);
406         free(th);
407      }
408 }
409
410 EAPI void
411 elm_theme_copy(Elm_Theme *th, Elm_Theme *thdst)
412 {
413    const Eina_List *l;
414    const char *f;
415
416    if (!th) th = &(theme_default);
417    if (!thdst) thdst = &(theme_default);
418    _elm_theme_clear(thdst);
419    if (th->ref_theme)
420      {
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++;
425      }
426    EINA_LIST_FOREACH(th->overlay, l, f)
427      {
428         const char *s = eina_stringshare_add(f);
429         if (s) thdst->overlay = eina_list_append(thdst->overlay, s);
430      }
431    EINA_LIST_FOREACH(th->themes, l, f)
432      {
433         const char *s = eina_stringshare_add(f);
434         if (s) thdst->themes = eina_list_append(thdst->themes, s);
435      }
436    EINA_LIST_FOREACH(th->extension, l, f)
437      {
438         const char *s = eina_stringshare_add(f);
439         if (s) thdst->extension = eina_list_append(thdst->extension, s);
440      }
441    if (th->theme) thdst->theme = eina_stringshare_add(th->theme);
442    elm_theme_flush(thdst);
443 }
444
445 EAPI void
446 elm_theme_ref_set(Elm_Theme *th, Elm_Theme *thref)
447 {
448    if (!th) th = &(theme_default);
449    if (!thref) thref = &(theme_default);
450    if (th->ref_theme == thref) return;
451    _elm_theme_clear(th);
452    if (thref)
453      {
454         thref->referrers = eina_list_append(thref->referrers, th);
455         thref->ref++;
456      }
457    th->ref_theme = thref;
458    elm_theme_flush(th);
459 }
460
461 EAPI Elm_Theme *
462 elm_theme_ref_get(Elm_Theme *th)
463 {
464    if (!th) th = &(theme_default);
465    return th->ref_theme;
466 }
467
468 EAPI Elm_Theme *
469 elm_theme_default_get(void)
470 {
471    return &theme_default;
472 }
473
474 EAPI void
475 elm_theme_overlay_add(Elm_Theme *th, const char *item)
476 {
477    const char *f = eina_stringshare_add(item);
478
479    if (!th) th = &(theme_default);
480    if (f) th->overlay = eina_list_prepend(th->overlay, f);
481    elm_theme_flush(th);
482 }
483
484 EAPI void
485 elm_theme_overlay_del(Elm_Theme *th, const char *item)
486 {
487    const Eina_List *l;
488    const char *f, *s;
489
490    if (!th) th = &(theme_default);
491    s = eina_stringshare_add(item);
492    EINA_LIST_FOREACH(th->overlay, l, f)
493       if (f == s)
494         {
495            eina_stringshare_del(f);
496            th->overlay = eina_list_remove_list(th->overlay, (Eina_List *)l);
497            break;
498         }
499    eina_stringshare_del(s);
500    elm_theme_flush(th);
501 }
502
503 EAPI const Eina_List *
504 elm_theme_overlay_list_get(const Elm_Theme *th)
505 {
506    if (!th) th = &(theme_default);
507    return th->overlay;
508 }
509
510 EAPI void
511 elm_theme_extension_add(Elm_Theme *th, const char *item)
512 {
513    const char *f = eina_stringshare_add(item);
514
515    if (!th) th = &(theme_default);
516    if (f) th->extension = eina_list_append(th->extension, f);
517    elm_theme_flush(th);
518 }
519
520 EAPI void
521 elm_theme_extension_del(Elm_Theme *th, const char *item)
522 {
523    const Eina_List *l;
524    const char *f, *s;
525
526    if (!th) th = &(theme_default);
527    s = eina_stringshare_add(item);
528    EINA_LIST_FOREACH(th->extension, l, f)
529       if (f == s)
530         {
531            eina_stringshare_del(f);
532            th->extension = eina_list_remove_list(th->extension, (Eina_List *)l);
533            break;
534         }
535    eina_stringshare_del(s);
536    elm_theme_flush(th);
537 }
538
539 EAPI const Eina_List *
540 elm_theme_extension_list_get(const Elm_Theme *th)
541 {
542    if (!th) th = &(theme_default);
543    return th->extension;
544 }
545
546 EAPI void
547 elm_theme_set(Elm_Theme *th, const char *theme)
548 {
549    if (!th) th = &(theme_default);
550    _elm_theme_parse(th, theme);
551    if (th->theme)
552      {
553         eina_stringshare_del(th->theme);
554         th->theme = NULL;
555      }
556    elm_theme_flush(th);
557    if (th == &(theme_default))
558      eina_stringshare_replace(&_elm_config->theme, theme);
559 }
560
561 EAPI const char *
562 elm_theme_get(Elm_Theme *th)
563 {
564    if (!th) th = &(theme_default);
565    if (!th->theme)
566      {
567         Eina_Strbuf *buf;
568         Eina_List *l;
569         const char *f;
570
571         buf = eina_strbuf_new();
572         EINA_LIST_FOREACH(th->themes, l, f)
573           {
574              while (*f)
575                {
576                   if (*f == ':')
577                     eina_strbuf_append_char(buf, '\\');
578                   eina_strbuf_append_char(buf, *f);
579
580                   f++;
581                }
582              if (l->next) eina_strbuf_append_char(buf, ':');
583           }
584         th->theme = eina_stringshare_add(eina_strbuf_string_get(buf));
585         eina_strbuf_free(buf);
586      }
587    return th->theme;
588 }
589
590 EAPI const Eina_List *
591 elm_theme_list_get(const Elm_Theme *th)
592 {
593    if (!th) th = &(theme_default);
594    return th->themes;
595 }
596
597 EAPI char *
598 elm_theme_list_item_path_get(const char *f, Eina_Bool *in_search_path)
599 {
600    static const char *home = NULL;
601    char buf[PATH_MAX];
602
603    if (!f)
604      {
605         if (in_search_path) *in_search_path = EINA_FALSE;
606         return NULL;
607      }
608
609    if (!home)
610      {
611         home = getenv("HOME");
612         if (!home) home = "";
613      }
614
615    if ((f[0] == '/') || ((f[0] == '.') && (f[1] == '/')) ||
616        ((f[0] == '.') && (f[1] == '.') && (f[2] == '/')) ||
617        ((isalpha(f[0])) && (f[1] == ':')))
618      {
619         if (in_search_path) *in_search_path = EINA_FALSE;
620         return strdup(f);
621      }
622    else if (((f[0] == '~') && (f[1] == '/')))
623      {
624         if (in_search_path) *in_search_path = EINA_FALSE;
625         snprintf(buf, sizeof(buf), "%s/%s", home, f + 2);
626         return strdup(buf);
627      }
628    snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes/%s.edj", home, f);
629    if (ecore_file_exists(buf))
630      {
631         if (in_search_path) *in_search_path = EINA_TRUE;
632         return strdup(buf);
633      }
634
635    snprintf(buf, sizeof(buf), "%s/themes/%s.edj", _elm_data_dir, f);
636    if (ecore_file_exists(buf))
637      {
638         if (in_search_path) *in_search_path = EINA_TRUE;
639         return strdup(buf);
640      }
641
642    if (in_search_path) *in_search_path = EINA_FALSE;
643    return NULL;
644 }
645
646 EAPI void
647 elm_theme_flush(Elm_Theme *th)
648 {
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);
656    if (th->referrers)
657      {
658         Eina_List *l;
659         Elm_Theme *th2;
660
661         EINA_LIST_FOREACH(th->referrers, l, th2) elm_theme_flush(th2);
662      }
663 }
664
665 EAPI void
666 elm_theme_full_flush(void)
667 {
668    Eina_List *l;
669    Elm_Theme *th;
670
671    EINA_LIST_FOREACH(themes, l, th)
672      {
673         elm_theme_flush(th);
674      }
675    elm_theme_flush(&(theme_default));
676 }
677
678 EAPI Eina_List *
679 elm_theme_name_available_list_new(void)
680 {
681    Eina_List *list = NULL;
682    Eina_List *dir, *l;
683    char buf[PATH_MAX], *file, *s, *th;
684    static const char *home = NULL;
685
686    if (!home)
687      {
688         home = getenv("HOME");
689         if (!home) home = "";
690      }
691
692    snprintf(buf, sizeof(buf), "%s/"ELEMENTARY_BASE_DIR"/themes", home);
693    dir = ecore_file_ls(buf);
694    EINA_LIST_FREE(dir, file)
695      {
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))
698           {
699              s = strchr(file, '.');
700              if ((s) && (!strcasecmp(s, ".edj")))
701                {
702                   th = strdup(file);
703                   s = strchr(th, '.');
704                   *s = 0;
705                   list = eina_list_append(list, th);
706                }
707           }
708         free(file);
709      }
710
711    snprintf(buf, sizeof(buf), "%s/themes", _elm_data_dir);
712    dir = ecore_file_ls(buf);
713    EINA_LIST_FREE(dir, file)
714      {
715         snprintf(buf, sizeof(buf), "%s/themes/%s", _elm_data_dir, file);
716         if ((!ecore_file_is_dir(buf)) && (ecore_file_size(buf) > 0))
717           {
718              s = strchr(file, '.');
719              if ((s) && (!strcasecmp(s, ".edj")))
720                {
721                   int dupp;
722
723                   th = strdup(file);
724                   s = strchr(th, '.');
725                   *s = 0;
726                   dupp = 0;
727                   EINA_LIST_FOREACH(list, l, s)
728                     {
729                        if (!strcmp(s, th))
730                          {
731                             dupp = 1;
732                             break;
733                          }
734                     }
735                   if (dupp) free(th);
736                   else list = eina_list_append(list, th);
737                }
738           }
739         free(file);
740      }
741    list = eina_list_sort(list, 0, EINA_COMPARE_CB(strcasecmp));
742    return list;
743 }
744
745 EAPI void
746 elm_theme_name_available_list_free(Eina_List *list)
747 {
748    char *s;
749    EINA_LIST_FREE(list, s) free(s);
750 }
751
752 EAPI void
753 elm_object_theme_set(Evas_Object *obj, Elm_Theme *th)
754 {
755    EINA_SAFETY_ON_NULL_RETURN(obj);
756    elm_widget_theme_set(obj, th);
757 }
758
759 EAPI Elm_Theme *
760 elm_object_theme_get(const Evas_Object *obj)
761 {
762    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
763    return elm_widget_theme_get(obj);
764 }
765
766 EAPI const char *
767 elm_theme_data_get(Elm_Theme *th, const char *key)
768 {
769    if (!th) th = &(theme_default);
770    return _elm_theme_data_find(th, key);
771 }