92dbc786d5bfefea7ae1e2700f7688b6f9147493
[framework/uifw/elementary.git] / src / lib / elm_widget.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char SMART_NAME[] = "elm_widget";
5
6 #define API_ENTRY                                    \
7   Smart_Data * sd = evas_object_smart_data_get(obj); \
8   if ((!obj) || (!sd) || (!_elm_widget_is(obj)))
9 #define INTERNAL_ENTRY                               \
10   Smart_Data * sd = evas_object_smart_data_get(obj); \
11   if (!sd) return;
12
13 #undef elm_widget_text_set_hook_set
14 #undef elm_widget_text_get_hook_set
15 #undef elm_widget_content_set_hook_set
16 #undef elm_widget_content_get_hook_set
17 #undef elm_widget_content_unset_hook_set
18
19 typedef struct _Smart_Data        Smart_Data;
20 typedef struct _Edje_Signal_Data  Edje_Signal_Data;
21 typedef struct _Elm_Event_Cb_Data Elm_Event_Cb_Data;
22 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
23
24 struct _Smart_Data
25 {
26    Evas_Object *obj;
27    const char  *type;
28    Evas_Object *parent_obj;
29    Evas_Object *parent2;
30    Evas_Coord   x, y, w, h;
31    Eina_List   *subobjs;
32    Evas_Object *resize_obj;
33    Evas_Object *hover_obj;
34    Eina_List   *tooltips, *cursors;
35    void       (*del_func)(Evas_Object *obj);
36    void       (*del_pre_func)(Evas_Object *obj);
37    void       (*focus_func)(Evas_Object *obj);
38    void       (*activate_func)(Evas_Object *obj);
39    void       (*disable_func)(Evas_Object *obj);
40    void       (*theme_func)(Evas_Object *obj);
41    void       (*translate_func)(Evas_Object *obj);
42    Eina_Bool  (*event_func)(Evas_Object       *obj,
43                             Evas_Object       *source,
44                             Evas_Callback_Type type,
45                             void              *event_info);
46    void       (*signal_func)(Evas_Object *obj,
47                              const char  *emission,
48                              const char  *source);
49    void       (*callback_add_func)(Evas_Object   *obj,
50                                    const char    *emission,
51                                    const char    *source,
52                                    Edje_Signal_Cb func,
53                                    void          *data);
54    void       (*callback_del_func)(Evas_Object   *obj,
55                                    const char    *emission,
56                                    const char    *source,
57                                    Edje_Signal_Cb func,
58                                    void          *data);
59    void       (*changed_func)(Evas_Object *obj);
60    Eina_Bool  (*focus_next_func)(const Evas_Object  *obj,
61                                  Elm_Focus_Direction dir,
62                                  Evas_Object       **next);
63    void       (*on_focus_func)(void        *data,
64                                Evas_Object *obj);
65    void        *on_focus_data;
66    void       (*on_change_func)(void        *data,
67                                 Evas_Object *obj);
68    void        *on_change_data;
69    void       (*on_show_region_func)(void        *data,
70                                      Evas_Object *obj);
71    void        *on_show_region_data;
72    void       (*focus_region_func)(Evas_Object *obj,
73                                    Evas_Coord   x,
74                                    Evas_Coord   y,
75                                    Evas_Coord   w,
76                                    Evas_Coord   h);
77    void       (*on_focus_region_func)(const Evas_Object *obj,
78                                       Evas_Coord        *x,
79                                       Evas_Coord        *y,
80                                       Evas_Coord        *w,
81                                       Evas_Coord        *h);
82    Elm_Widget_On_Text_Set_Cb on_text_set_func;
83    Elm_Widget_On_Text_Get_Cb on_text_get_func;
84    Elm_Widget_On_Content_Set_Cb on_content_set_func;
85    Elm_Widget_On_Content_Get_Cb on_content_get_func;
86    Elm_Widget_On_Content_Unset_Cb on_content_unset_func;
87    void        *data;
88    Evas_Coord   rx, ry, rw, rh;
89    int          scroll_hold;
90    int          scroll_freeze;
91    double       scale;
92    Elm_Theme   *theme;
93    const char  *style;
94    const char  *access_info;
95    unsigned int focus_order;
96    Eina_Bool    focus_order_on_calc;
97
98    int          child_drag_x_locked;
99    int          child_drag_y_locked;
100
101    Eina_List   *edje_signals;
102    Eina_List   *translate_strings;
103
104    Eina_Bool    drag_x_locked : 1;
105    Eina_Bool    drag_y_locked : 1;
106
107    Eina_Bool    can_focus : 1;
108    Eina_Bool    child_can_focus : 1;
109    Eina_Bool    focused : 1;
110    Eina_Bool    top_win_focused : 1;
111    Eina_Bool    tree_unfocusable : 1;
112    Eina_Bool    highlight_ignore : 1;
113    Eina_Bool    highlight_in_theme : 1;
114    Eina_Bool    disabled : 1;
115    Eina_Bool    is_mirrored : 1;
116    Eina_Bool    mirrored_auto_mode : 1;   /* This is TRUE by default */
117
118    Eina_List   *focus_chain;
119    Eina_List   *event_cb;
120 };
121
122 struct _Edje_Signal_Data
123 {
124    Evas_Object   *obj;
125    Edje_Signal_Cb func;
126    const char    *emission;
127    const char    *source;
128    void          *data;
129 };
130
131 struct _Elm_Event_Cb_Data
132 {
133    Elm_Event_Cb func;
134    const void  *data;
135 };
136
137 struct _Elm_Translate_String_Data
138 {
139    const char *id;
140    const char *domain;
141    const char *string;
142 };
143
144 /* local subsystem functions */
145 static void _smart_reconfigure(Smart_Data *sd);
146 static void _smart_add(Evas_Object *obj);
147 static void _smart_del(Evas_Object *obj);
148 static void _smart_move(Evas_Object *obj,
149                         Evas_Coord   x,
150                         Evas_Coord   y);
151 static void _smart_resize(Evas_Object *obj,
152                           Evas_Coord   w,
153                           Evas_Coord   h);
154 static void _smart_show(Evas_Object *obj);
155 static void _smart_hide(Evas_Object *obj);
156 static void _smart_color_set(Evas_Object *obj,
157                              int          r,
158                              int          g,
159                              int          b,
160                              int          a);
161 static void _smart_clip_set(Evas_Object *obj,
162                             Evas_Object *clip);
163 static void _smart_clip_unset(Evas_Object *obj);
164 static void _smart_calculate(Evas_Object *obj);
165 static void _smart_init(void);
166
167 static void _if_focused_revert(Evas_Object *obj,
168                                Eina_Bool    can_focus_only);
169 static Evas_Object *_newest_focus_order_get(Evas_Object  *obj,
170                                             unsigned int *newest_focus_order,
171                                             Eina_Bool     can_focus_only);
172
173 /* local subsystem globals */
174 static Evas_Smart *_e_smart = NULL;
175 static Eina_List  *widtypes = NULL;
176
177 static unsigned int focus_order = 0;
178
179 // internal funcs
180 static inline Eina_Bool
181 _elm_widget_is(const Evas_Object *obj)
182 {
183    const char *type = evas_object_type_get(obj);
184    return type == SMART_NAME;
185 }
186
187 static inline Eina_Bool
188 _is_focusable(Evas_Object *obj)
189 {
190    API_ENTRY return EINA_FALSE;
191    return sd->can_focus || (sd->child_can_focus);
192 }
193
194 static void
195 _unfocus_parents(Evas_Object *obj)
196 {
197    for (; obj; obj = elm_widget_parent_get(obj))
198      {
199         INTERNAL_ENTRY
200         if (!sd->focused) return;
201         sd->focused = 0;
202      }
203 }
204
205 static void
206 _focus_parents(Evas_Object *obj)
207 {
208    for (; obj; obj = elm_widget_parent_get(obj))
209      {
210         INTERNAL_ENTRY
211         if (sd->focused) return;
212         sd->focused = 1;
213      }
214 }
215
216 static void
217 _sub_obj_del(void        *data,
218              Evas        *e __UNUSED__,
219              Evas_Object *obj,
220              void        *event_info __UNUSED__)
221 {
222    Smart_Data *sd = data;
223
224    if (_elm_widget_is(obj))
225      {
226         if (elm_widget_focus_get(obj)) _unfocus_parents(sd->obj);
227      }
228    if (obj == sd->resize_obj)
229      sd->resize_obj = NULL;
230    else if (obj == sd->hover_obj)
231      sd->hover_obj = NULL;
232    else
233      sd->subobjs = eina_list_remove(sd->subobjs, obj);
234    evas_object_smart_callback_call(sd->obj, "sub-object-del", obj);
235 }
236
237 static void
238 _sub_obj_hide(void        *data __UNUSED__,
239               Evas        *e __UNUSED__,
240               Evas_Object *obj,
241               void        *event_info __UNUSED__)
242 {
243    elm_widget_focus_hide_handle(obj);
244 }
245
246 static void
247 _sub_obj_mouse_up(void        *data __UNUSED__,
248                   Evas        *e __UNUSED__,
249                   Evas_Object *obj,
250                   void        *event_info)
251 {
252    Evas_Event_Mouse_Up *ev = event_info;
253    if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
254       elm_widget_focus_mouse_up_handle(obj);
255 }
256
257 static void
258 _propagate_x_drag_lock(Evas_Object *obj,
259                        int          dir)
260 {
261    INTERNAL_ENTRY
262    if (sd->parent_obj)
263      {
264         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
265         if (sd2)
266           {
267              sd2->child_drag_x_locked += dir;
268              _propagate_x_drag_lock(sd->parent_obj, dir);
269           }
270      }
271 }
272
273 static void
274 _propagate_y_drag_lock(Evas_Object *obj,
275                        int          dir)
276 {
277    INTERNAL_ENTRY
278    if (sd->parent_obj)
279      {
280         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
281         if (sd2)
282           {
283              sd2->child_drag_y_locked += dir;
284              _propagate_y_drag_lock(sd->parent_obj, dir);
285           }
286      }
287 }
288
289 static void
290 _propagate_event(void        *data,
291                  Evas        *e __UNUSED__,
292                  Evas_Object *obj,
293                  void        *event_info)
294 {
295    INTERNAL_ENTRY
296    Evas_Callback_Type type = (Evas_Callback_Type)(long)data;
297    Evas_Event_Flags *event_flags = NULL;
298
299    switch (type)
300      {
301       case EVAS_CALLBACK_KEY_DOWN:
302           {
303             Evas_Event_Key_Down *ev = event_info;
304             event_flags = &(ev->event_flags);
305           }
306         break;
307
308       case EVAS_CALLBACK_KEY_UP:
309           {
310              Evas_Event_Key_Up *ev = event_info;
311              event_flags = &(ev->event_flags);
312           }
313         break;
314
315       case EVAS_CALLBACK_MOUSE_WHEEL:
316           {
317             Evas_Event_Mouse_Wheel *ev = event_info;
318             event_flags = &(ev->event_flags);
319           }
320         break;
321
322       default:
323         break;
324      }
325
326    elm_widget_event_propagate(obj, type, event_info, event_flags);
327 }
328
329 static void
330 _parent_focus(Evas_Object *obj)
331 {
332    API_ENTRY return;
333    if (sd->focused) return;
334
335    Evas_Object *o = elm_widget_parent_get(obj);
336    sd->focus_order_on_calc = EINA_TRUE;
337
338    if (o) _parent_focus(o);
339
340    if (!sd->focus_order_on_calc)
341      return; /* we don't want to override it if by means of any of the
342                 callbacks below one gets to calculate our order
343                 first. */
344
345    focus_order++;
346    sd->focus_order = focus_order;
347    if (sd->top_win_focused)
348      {
349         sd->focused = EINA_TRUE;
350         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
351         if (sd->focus_func) sd->focus_func(obj);
352         _elm_widget_focus_region_show(obj);
353      }
354    sd->focus_order_on_calc = EINA_FALSE;
355 }
356
357 static void
358 _elm_object_focus_chain_del_cb(void        *data,
359                                Evas        *e __UNUSED__,
360                                Evas_Object *obj,
361                                void        *event_info __UNUSED__)
362 {
363    Smart_Data *sd = data;
364
365    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
366 }
367
368 // exposed util funcs to elm
369 void
370 _elm_widget_type_clear(void)
371 {
372    const char **ptr;
373
374    EINA_LIST_FREE(widtypes, ptr)
375      {
376         eina_stringshare_del(*ptr);
377         *ptr = NULL;
378      }
379 }
380
381 void
382 _elm_widget_focus_region_show(const Evas_Object *obj)
383 {
384    Evas_Coord x, y, w, h, ox, oy;
385    Smart_Data *sd2;
386    Evas_Object *o;
387
388    API_ENTRY return;
389
390    o = elm_widget_parent_get(obj);
391    if (!o) return;
392
393    elm_widget_focus_region_get(obj, &x, &y, &w, &h);
394    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
395    while (o)
396      {
397         Evas_Coord px, py;
398         sd2 = evas_object_smart_data_get(o);
399         if (sd2->focus_region_func)
400           {
401              sd2->focus_region_func(o, x, y, w, h);
402              elm_widget_focus_region_get(o, &x, &y, &w, &h);
403           }
404         else
405           {
406              evas_object_geometry_get(o, &px, &py, NULL, NULL);
407              x += ox - px;
408              y += oy - py;
409              ox = px;
410              oy = py;
411           }
412         o = elm_widget_parent_get(o);
413      }
414 }
415
416 /**
417  * @defgroup Widget Widget
418  *
419  * @internal
420  * Exposed api for making widgets
421  */
422 EAPI void
423 elm_widget_type_register(const char **ptr)
424 {
425    widtypes = eina_list_append(widtypes, (void *)ptr);
426 }
427
428 /**
429  * @defgroup Widget Widget
430  *
431  * @internal
432  * Disposed api for making widgets
433  */
434 EAPI void
435 elm_widget_type_unregister(const char **ptr)
436 {
437    widtypes = eina_list_remove(widtypes, (void *)ptr);
438 }
439
440 EAPI Eina_Bool
441 elm_widget_api_check(int ver)
442 {
443    if (ver != ELM_INTERNAL_API_VERSION)
444      {
445         CRITICAL("Elementary widget api versions do not match");
446         return EINA_FALSE;
447      }
448    return EINA_TRUE;
449 }
450
451 EAPI Evas_Object *
452 elm_widget_add(Evas *evas)
453 {
454    Evas_Object *obj;
455    _smart_init();
456    obj = evas_object_smart_add(evas, _e_smart);
457    elm_widget_mirrored_set(obj, elm_mirrored_get());
458    return obj;
459 }
460
461 EAPI void
462 elm_widget_del_hook_set(Evas_Object *obj,
463                         void       (*func)(Evas_Object *obj))
464 {
465    API_ENTRY return;
466    sd->del_func = func;
467 }
468
469 EAPI void
470 elm_widget_del_pre_hook_set(Evas_Object *obj,
471                             void       (*func)(Evas_Object *obj))
472 {
473    API_ENTRY return;
474    sd->del_pre_func = func;
475 }
476
477 EAPI void
478 elm_widget_focus_hook_set(Evas_Object *obj,
479                           void       (*func)(Evas_Object *obj))
480 {
481    API_ENTRY return;
482    sd->focus_func = func;
483 }
484
485 EAPI void
486 elm_widget_activate_hook_set(Evas_Object *obj,
487                              void       (*func)(Evas_Object *obj))
488 {
489    API_ENTRY return;
490    sd->activate_func = func;
491 }
492
493 EAPI void
494 elm_widget_disable_hook_set(Evas_Object *obj,
495                             void       (*func)(Evas_Object *obj))
496 {
497    API_ENTRY return;
498    sd->disable_func = func;
499 }
500
501 EAPI void
502 elm_widget_theme_hook_set(Evas_Object *obj,
503                           void       (*func)(Evas_Object *obj))
504 {
505    API_ENTRY return;
506    sd->theme_func = func;
507 }
508
509 EAPI void
510 elm_widget_translate_hook_set(Evas_Object *obj,
511                               void       (*func)(Evas_Object *obj))
512 {
513    API_ENTRY return;
514    sd->translate_func = func;
515 }
516
517 EAPI void
518 elm_widget_event_hook_set(Evas_Object *obj,
519                           Eina_Bool  (*func)(Evas_Object       *obj,
520                                              Evas_Object       *source,
521                                              Evas_Callback_Type type,
522                                              void              *event_info))
523 {
524    API_ENTRY return;
525    sd->event_func = func;
526 }
527
528 EAPI void
529 elm_widget_text_set_hook_set(Evas_Object *obj,
530                              Elm_Widget_On_Text_Set_Cb func)
531 {
532    API_ENTRY return;
533    sd->on_text_set_func = func;
534 }
535
536 EAPI void
537 elm_widget_text_get_hook_set(Evas_Object *obj,
538                              Elm_Widget_On_Text_Get_Cb func)
539 {
540    API_ENTRY return;
541    sd->on_text_get_func = func;
542 }
543
544 EAPI void
545 elm_widget_content_set_hook_set(Evas_Object *obj,
546                                 Elm_Widget_On_Content_Set_Cb func)
547 {
548    API_ENTRY return;
549    sd->on_content_set_func = func;
550 }
551
552 EAPI void
553 elm_widget_content_get_hook_set(Evas_Object *obj,
554                                 Elm_Widget_On_Content_Get_Cb func)
555 {
556    API_ENTRY return;
557    sd->on_content_get_func = func;
558 }
559
560 EAPI void
561 elm_widget_content_unset_hook_set(Evas_Object *obj,
562                                   Elm_Widget_On_Content_Unset_Cb func)
563 {
564    API_ENTRY return;
565    sd->on_content_unset_func = func;
566 }
567
568 EAPI void
569 elm_widget_changed_hook_set(Evas_Object *obj,
570                             void       (*func)(Evas_Object *obj))
571 {
572    API_ENTRY return;
573    sd->changed_func = func;
574 }
575
576 EAPI void
577 elm_widget_signal_emit_hook_set(Evas_Object *obj,
578                                 void       (*func)(Evas_Object *obj,
579                                                    const char *emission,
580                                                    const char *source))
581 {
582    API_ENTRY return;
583    sd->signal_func = func;
584 }
585
586 EAPI void
587 elm_widget_signal_callback_add_hook_set(Evas_Object *obj,
588                                         void       (*func)(Evas_Object   *obj,
589                                                            const char    *emission,
590                                                            const char    *source,
591                                                            Edje_Signal_Cb func_cb,
592                                                            void          *data))
593 {
594    API_ENTRY return;
595    sd->callback_add_func = func;
596 }
597
598 EAPI void
599 elm_widget_signal_callback_del_hook_set(Evas_Object *obj,
600                                         void       (*func)(Evas_Object   *obj,
601                                                            const char    *emission,
602                                                            const char    *source,
603                                                            Edje_Signal_Cb func_cb,
604                                                            void          *data))
605 {
606    API_ENTRY return;
607    sd->callback_del_func = func;
608 }
609
610 EAPI void
611 elm_widget_theme(Evas_Object *obj)
612 {
613    const Eina_List *l;
614    Evas_Object *child;
615    Elm_Tooltip *tt;
616    Elm_Cursor *cur;
617
618    API_ENTRY return;
619    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_theme(child);
620    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
621    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
622    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
623    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
624    if (sd->theme_func) sd->theme_func(obj);
625 }
626
627 EAPI void
628 elm_widget_theme_specific(Evas_Object *obj,
629                           Elm_Theme   *th,
630                           Eina_Bool    force)
631 {
632    const Eina_List *l;
633    Evas_Object *child;
634    Elm_Tooltip *tt;
635    Elm_Cursor *cur;
636    Elm_Theme *th2, *thdef;
637
638    API_ENTRY return;
639    thdef = elm_theme_default_get();
640    if (!th) th = thdef;
641    if (!force)
642      {
643         th2 = sd->theme;
644         if (!th2) th2 = thdef;
645         while (th2)
646           {
647              if (th2 == th)
648                {
649                   force = EINA_TRUE;
650                   break;
651                }
652              if (th2 == thdef) break;
653              th2 = th2->ref_theme;
654              if (!th2) th2 = thdef;
655           }
656      }
657    if (!force) return;
658    EINA_LIST_FOREACH(sd->subobjs, l, child)
659      elm_widget_theme_specific(child, th, force);
660    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
661    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
662    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
663    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
664    if (sd->theme_func) sd->theme_func(obj);
665 }
666
667 /**
668  * @internal
669  *
670  * Set hook to get next object in object focus chain.
671  *
672  * @param obj The widget object.
673  * @param func The hook to be used with this widget.
674  *
675  * @ingroup Widget
676  */
677 EAPI void
678 elm_widget_focus_next_hook_set(Evas_Object *obj,
679                                Eina_Bool  (*func)(const Evas_Object   *obj,
680                                                    Elm_Focus_Direction dir,
681                                                    Evas_Object       **next))
682 {
683    API_ENTRY return;
684    sd->focus_next_func = func;
685 }
686
687 /**
688  * Returns the widget's mirrored mode.
689  *
690  * @param obj The widget.
691  * @return mirrored mode of the object.
692  *
693  **/
694 EAPI Eina_Bool
695 elm_widget_mirrored_get(const Evas_Object *obj)
696 {
697    API_ENTRY return EINA_FALSE;
698    return sd->is_mirrored;
699 }
700
701 /**
702  * Sets the widget's mirrored mode.
703  *
704  * @param obj The widget.
705  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
706  */
707 EAPI void
708 elm_widget_mirrored_set(Evas_Object *obj,
709                         Eina_Bool    mirrored)
710 {
711    API_ENTRY return;
712    if (sd->is_mirrored != mirrored)
713      {
714         sd->is_mirrored = mirrored;
715         elm_widget_theme(obj);
716      }
717 }
718
719 /**
720  * @internal
721  * Resets the mirrored mode from the system mirror mode for widgets that are in
722  * automatic mirroring mode. This function does not call elm_widget_theme.
723  *
724  * @param obj The widget.
725  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
726  */
727 void
728 _elm_widget_mirrored_reload(Evas_Object *obj)
729 {
730    API_ENTRY return;
731    Eina_Bool mirrored = elm_mirrored_get();
732    if (elm_widget_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
733      {
734         sd->is_mirrored = mirrored;
735      }
736 }
737
738 /**
739  * Returns the widget's mirrored mode setting.
740  *
741  * @param obj The widget.
742  * @return mirrored mode setting of the object.
743  *
744  **/
745 EAPI Eina_Bool
746 elm_widget_mirrored_automatic_get(const Evas_Object *obj)
747 {
748    API_ENTRY return EINA_FALSE;
749    return sd->mirrored_auto_mode;
750 }
751
752 /**
753  * Sets the widget's mirrored mode setting.
754  * When widget in automatic mode, it follows the system mirrored mode set by
755  * elm_mirrored_set().
756  * @param obj The widget.
757  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
758  */
759 EAPI void
760 elm_widget_mirrored_automatic_set(Evas_Object *obj,
761                                   Eina_Bool    automatic)
762 {
763    API_ENTRY return;
764    if (sd->mirrored_auto_mode != automatic)
765      {
766         sd->mirrored_auto_mode = automatic;
767
768         if (automatic)
769           {
770              elm_widget_mirrored_set(obj, elm_mirrored_get());
771           }
772      }
773 }
774
775 EAPI void
776 elm_widget_on_focus_hook_set(Evas_Object *obj,
777                              void       (*func)(void *data,
778                                                 Evas_Object *obj),
779                              void        *data)
780 {
781    API_ENTRY return;
782    sd->on_focus_func = func;
783    sd->on_focus_data = data;
784 }
785
786 EAPI void
787 elm_widget_on_change_hook_set(Evas_Object *obj,
788                               void       (*func)(void *data,
789                                                  Evas_Object *obj),
790                               void        *data)
791 {
792    API_ENTRY return;
793    sd->on_change_func = func;
794    sd->on_change_data = data;
795 }
796
797 EAPI void
798 elm_widget_on_show_region_hook_set(Evas_Object *obj,
799                                    void       (*func)(void *data,
800                                                       Evas_Object *obj),
801                                    void        *data)
802 {
803    API_ENTRY return;
804    sd->on_show_region_func = func;
805    sd->on_show_region_data = data;
806 }
807
808 /**
809  * @internal
810  *
811  * Set the hook to use to show the focused region.
812  *
813  * Whenever a new widget gets focused or it's needed to show the focused
814  * area of the current one, this hook will be called on objects that may
815  * want to move their children into their visible area.
816  * The area given in the hook function is relative to the @p obj widget.
817  *
818  * @param obj The widget object
819  * @param func The function to call to show the specified area.
820  *
821  * @ingroup Widget
822  */
823 EAPI void
824 elm_widget_focus_region_hook_set(Evas_Object *obj,
825                                  void       (*func)(Evas_Object *obj,
826                                                     Evas_Coord x,
827                                                     Evas_Coord y,
828                                                     Evas_Coord w,
829                                                     Evas_Coord h))
830 {
831    API_ENTRY return;
832    sd->focus_region_func = func;
833 }
834
835 /**
836  * @internal
837  *
838  * Set the hook to retrieve the focused region of a widget.
839  *
840  * This hook will be called by elm_widget_focus_region_get() whenever
841  * it's needed to get the focused area of a widget. The area must be relative
842  * to the widget itself and if no hook is set, it will default to the entire
843  * object.
844  *
845  * @param obj The widget object
846  * @param func The function used to retrieve the focus region.
847  *
848  * @ingroup Widget
849  */
850 EAPI void
851 elm_widget_on_focus_region_hook_set(Evas_Object *obj,
852                                     void       (*func)(const Evas_Object *obj,
853                                                        Evas_Coord *x,
854                                                        Evas_Coord *y,
855                                                        Evas_Coord *w,
856                                                        Evas_Coord *h))
857 {
858    API_ENTRY return;
859    sd->on_focus_region_func = func;
860 }
861
862 EAPI void
863 elm_widget_data_set(Evas_Object *obj,
864                     void        *data)
865 {
866    API_ENTRY return;
867    sd->data = data;
868 }
869
870 EAPI void *
871 elm_widget_data_get(const Evas_Object *obj)
872 {
873    API_ENTRY return NULL;
874    return sd->data;
875 }
876
877 EAPI void
878 elm_widget_sub_object_add(Evas_Object *obj,
879                           Evas_Object *sobj)
880 {
881    API_ENTRY return;
882    double scale, pscale = elm_widget_scale_get(sobj);
883    Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
884    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
885
886    if (_elm_widget_is(sobj))
887      {
888         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
889         if (sd2)
890           {
891              if (sd2->parent_obj == obj)
892                return;
893              if (sd2->parent_obj)
894                elm_widget_sub_object_del(sd2->parent_obj, sobj);
895              sd2->parent_obj = obj;
896              sd2->top_win_focused = sd->top_win_focused;
897              if (!sd->child_can_focus && (_is_focusable(sobj)))
898                sd->child_can_focus = EINA_TRUE;
899           }
900      }
901    else
902      {
903         void *data = evas_object_data_get(sobj, "elm-parent");
904         if (data)
905           {
906              if (data == obj) return;
907              evas_object_event_callback_del(sobj, EVAS_CALLBACK_DEL,
908                                             _sub_obj_del);
909           }
910      }
911
912    sd->subobjs = eina_list_append(sd->subobjs, sobj);
913    evas_object_data_set(sobj, "elm-parent", obj);
914    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
915    if (_elm_widget_is(sobj))
916      evas_object_event_callback_add(sobj, EVAS_CALLBACK_HIDE, _sub_obj_hide, sd);
917    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
918    scale = elm_widget_scale_get(sobj);
919    th = elm_widget_theme_get(sobj);
920    mirrored = elm_widget_mirrored_get(sobj);
921    if ((scale != pscale) || (th != pth) || (pmirrored != mirrored)) elm_widget_theme(sobj);
922    if (elm_widget_focus_get(sobj)) _focus_parents(obj);
923 }
924
925 EAPI void
926 elm_widget_sub_object_del(Evas_Object *obj,
927                           Evas_Object *sobj)
928 {
929    Evas_Object *sobj_parent;
930    API_ENTRY return;
931    if (!sobj) return;
932
933    sobj_parent = evas_object_data_del(sobj, "elm-parent");
934    if (sobj_parent != obj)
935      {
936         static int abort_on_warn = -1;
937         ERR("removing sub object %p from parent %p, "
938             "but elm-parent is different %p!",
939             sobj, obj, sobj_parent);
940         if (EINA_UNLIKELY(abort_on_warn == -1))
941           {
942              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
943              else abort_on_warn = 0;
944           }
945         if (abort_on_warn == 1) abort();
946      }
947    if (_elm_widget_is(sobj))
948      {
949         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
950         if (sd2)
951           {
952              sd2->parent_obj = NULL;
953              if (sd2->resize_obj == sobj)
954                sd2->resize_obj = NULL;
955              else
956                sd->subobjs = eina_list_remove(sd->subobjs, sobj);
957           }
958         else
959           sd->subobjs = eina_list_remove(sd->subobjs, sobj);
960         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
961         if ((sd->child_can_focus) && (_is_focusable(sobj)))
962           {
963              Evas_Object *subobj;
964              const Eina_List *l;
965              sd->child_can_focus = EINA_FALSE;
966              EINA_LIST_FOREACH(sd->subobjs, l, subobj)
967                {
968                   if (_is_focusable(subobj))
969                     {
970                        sd->child_can_focus = EINA_TRUE;
971                        break;
972                     }
973                }
974           }
975      }
976    else
977      sd->subobjs = eina_list_remove(sd->subobjs, sobj);
978    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
979                                        _sub_obj_del, sd);
980    if (_elm_widget_is(sobj))
981      evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
982                                          _sub_obj_hide, sd);
983    evas_object_smart_callback_call(obj, "sub-object-del", sobj);
984 }
985
986 EAPI void
987 elm_widget_resize_object_set(Evas_Object *obj,
988                              Evas_Object *sobj)
989 {
990    API_ENTRY return;
991    // orphan previous resize obj
992    if (sd->resize_obj)
993      {
994         evas_object_clip_unset(sd->resize_obj);
995         evas_object_data_del(sd->resize_obj, "elm-parent");
996         if (_elm_widget_is(sd->resize_obj))
997           {
998              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
999              if (sd2) sd2->parent_obj = NULL;
1000              evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_HIDE,
1001                                                  _sub_obj_hide, sd);
1002           }
1003         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_DEL,
1004                                             _sub_obj_del, sd);
1005         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_UP,
1006                                             _sub_obj_mouse_up, sd);
1007         evas_object_smart_member_del(sd->resize_obj);
1008         if (_elm_widget_is(sd->resize_obj))
1009           {
1010              if (elm_widget_focus_get(sd->resize_obj)) _unfocus_parents(obj);
1011           }
1012      }
1013
1014    sd->resize_obj = sobj;
1015    if (!sobj) return;
1016
1017    // orphan new resize obj
1018    evas_object_data_del(sobj, "elm-parent");
1019    if (_elm_widget_is(sobj))
1020      {
1021         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
1022         if (sd2) sd2->parent_obj = NULL;
1023         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
1024                                             _sub_obj_hide, sd);
1025      }
1026    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
1027                                        _sub_obj_del, sd);
1028    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_UP,
1029                                        _sub_obj_mouse_up, sd);
1030    evas_object_smart_member_del(sobj);
1031    if (_elm_widget_is(sobj))
1032      {
1033         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
1034      }
1035
1036    // set the resize obj up
1037    if (_elm_widget_is(sobj))
1038      {
1039         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
1040         if (sd2)
1041           {
1042              sd2->parent_obj = obj;
1043              sd2->top_win_focused = sd->top_win_focused;
1044           }
1045         evas_object_event_callback_add(sobj, EVAS_CALLBACK_HIDE,
1046                                        _sub_obj_hide, sd);
1047      }
1048    evas_object_clip_set(sobj, evas_object_clip_get(obj));
1049    evas_object_smart_member_add(sobj, obj);
1050    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1051                                   _sub_obj_del, sd);
1052    evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_UP,
1053                                   _sub_obj_mouse_up, sd);
1054    _smart_reconfigure(sd);
1055    evas_object_data_set(sobj, "elm-parent", obj);
1056    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
1057    if (_elm_widget_is(sobj))
1058      {
1059         if (elm_widget_focus_get(sobj)) _focus_parents(obj);
1060      }
1061 }
1062
1063 EAPI void
1064 elm_widget_hover_object_set(Evas_Object *obj,
1065                             Evas_Object *sobj)
1066 {
1067    API_ENTRY return;
1068    if (sd->hover_obj)
1069      {
1070         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
1071                                             _sub_obj_del, sd);
1072      }
1073    sd->hover_obj = sobj;
1074    if (sd->hover_obj)
1075      {
1076         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1077                                        _sub_obj_del, sd);
1078         _smart_reconfigure(sd);
1079      }
1080 }
1081
1082 EAPI void
1083 elm_widget_can_focus_set(Evas_Object *obj,
1084                          Eina_Bool    can_focus)
1085 {
1086    API_ENTRY return;
1087    sd->can_focus = can_focus;
1088    if (can_focus)
1089      {
1090         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1091                                        _propagate_event,
1092                                        (void *)(long)EVAS_CALLBACK_KEY_DOWN);
1093         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
1094                                        _propagate_event,
1095                                        (void *)(long)EVAS_CALLBACK_KEY_UP);
1096         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1097                                        _propagate_event,
1098                                        (void *)(long)EVAS_CALLBACK_MOUSE_WHEEL);
1099      }
1100    else
1101      {
1102         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
1103                                        _propagate_event);
1104         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
1105                                        _propagate_event);
1106         evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1107                                        _propagate_event);
1108      }
1109 }
1110
1111 EAPI Eina_Bool
1112 elm_widget_can_focus_get(const Evas_Object *obj)
1113 {
1114    API_ENTRY return EINA_FALSE;
1115    return sd->can_focus;
1116 }
1117
1118 EAPI Eina_Bool
1119 elm_widget_child_can_focus_get(const Evas_Object *obj)
1120 {
1121    API_ENTRY return EINA_FALSE;
1122    return sd->child_can_focus;
1123 }
1124
1125 /**
1126  * @internal
1127  *
1128  * This API makes the widget object and its children to be unfocusable.
1129  *
1130  * This API can be helpful for an object to be deleted.
1131  * When an object will be deleted soon, it and its children may not
1132  * want to get focus (by focus reverting or by other focus controls).
1133  * Then, just use this API before deleting.
1134  *
1135  * @param obj The widget root of sub-tree
1136  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1137  *
1138  * @ingroup Widget
1139  */
1140 EAPI void
1141 elm_widget_tree_unfocusable_set(Evas_Object *obj,
1142                                 Eina_Bool    tree_unfocusable)
1143 {
1144    API_ENTRY return;
1145
1146    if (sd->tree_unfocusable == tree_unfocusable) return;
1147    sd->tree_unfocusable = !!tree_unfocusable;
1148    elm_widget_focus_tree_unfocusable_handle(obj);
1149 }
1150
1151 /**
1152  * @internal
1153  *
1154  * This returns true, if the object sub-tree is unfocusable.
1155  *
1156  * @param obj The widget root of sub-tree
1157  * @return EINA_TRUE if the object sub-tree is unfocusable
1158  *
1159  * @ingroup Widget
1160  */
1161 EAPI Eina_Bool
1162 elm_widget_tree_unfocusable_get(const Evas_Object *obj)
1163 {
1164    API_ENTRY return EINA_FALSE;
1165    return sd->tree_unfocusable;
1166 }
1167
1168 /**
1169  * @internal
1170  *
1171  * Get the list of focusable child objects.
1172  *
1173  * This function retruns list of child objects which can get focus.
1174  *
1175  * @param obj The parent widget
1176  * @retrun list of focusable child objects.
1177  *
1178  * @ingroup Widget
1179  */
1180 EAPI Eina_List *
1181 elm_widget_can_focus_child_list_get(const Evas_Object *obj)
1182 {
1183    API_ENTRY return NULL;
1184
1185    const Eina_List *l;
1186    Eina_List *child_list = NULL;
1187    Evas_Object *child;
1188
1189    if (sd->subobjs)
1190      {
1191         EINA_LIST_FOREACH(sd->subobjs, l, child)
1192           {
1193              if ((elm_widget_can_focus_get(child)) &&
1194                  (evas_object_visible_get(child)) &&
1195                  (!elm_widget_disabled_get(child)))
1196                child_list = eina_list_append(child_list, child);
1197              else if (elm_widget_is(child))
1198                {
1199                   Eina_List *can_focus_list;
1200                   can_focus_list = elm_widget_can_focus_child_list_get(child);
1201                   if (can_focus_list)
1202                     child_list = eina_list_merge(child_list, can_focus_list);
1203                }
1204           }
1205      }
1206    return child_list;
1207 }
1208
1209 EAPI void
1210 elm_widget_highlight_ignore_set(Evas_Object *obj,
1211                                 Eina_Bool    ignore)
1212 {
1213    API_ENTRY return;
1214    sd->highlight_ignore = !!ignore;
1215 }
1216
1217 EAPI Eina_Bool
1218 elm_widget_highlight_ignore_get(const Evas_Object *obj)
1219 {
1220    API_ENTRY return EINA_FALSE;
1221    return sd->highlight_ignore;
1222 }
1223
1224 EAPI void
1225 elm_widget_highlight_in_theme_set(Evas_Object *obj,
1226                                   Eina_Bool    highlight)
1227 {
1228    API_ENTRY return;
1229    sd->highlight_in_theme = !!highlight;
1230    /* FIXME: if focused, it should switch from one mode to the other */
1231 }
1232
1233 EAPI Eina_Bool
1234 elm_widget_highlight_in_theme_get(const Evas_Object *obj)
1235 {
1236    API_ENTRY return EINA_FALSE;
1237    return sd->highlight_in_theme;
1238 }
1239
1240 EAPI Eina_Bool
1241 elm_widget_focus_get(const Evas_Object *obj)
1242 {
1243    API_ENTRY return EINA_FALSE;
1244    return sd->focused;
1245 }
1246
1247 EAPI Evas_Object *
1248 elm_widget_focused_object_get(const Evas_Object *obj)
1249 {
1250    const Evas_Object *subobj;
1251    const Eina_List *l;
1252    API_ENTRY return NULL;
1253
1254    if (!sd->focused) return NULL;
1255    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1256      {
1257         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
1258         if (fobj) return fobj;
1259      }
1260    return (Evas_Object *)obj;
1261 }
1262
1263 EAPI Evas_Object *
1264 elm_widget_top_get(const Evas_Object *obj)
1265 {
1266    API_ENTRY return NULL;
1267    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
1268    return (Evas_Object *)obj;
1269 }
1270
1271 EAPI Eina_Bool
1272 elm_widget_is(const Evas_Object *obj)
1273 {
1274    return _elm_widget_is(obj);
1275 }
1276
1277 EAPI Evas_Object *
1278 elm_widget_parent_widget_get(const Evas_Object *obj)
1279 {
1280    Evas_Object *parent;
1281
1282    if (_elm_widget_is(obj))
1283      {
1284         Smart_Data *sd = evas_object_smart_data_get(obj);
1285         if (!sd) return NULL;
1286         parent = sd->parent_obj;
1287      }
1288    else
1289      {
1290         parent = evas_object_data_get(obj, "elm-parent");
1291         if (!parent) parent = evas_object_smart_parent_get(obj);
1292      }
1293
1294    while (parent)
1295      {
1296         Evas_Object *elm_parent;
1297         if (_elm_widget_is(parent)) break;
1298         elm_parent = evas_object_data_get(parent, "elm-parent");
1299         if (elm_parent) parent = elm_parent;
1300         else parent = evas_object_smart_parent_get(parent);
1301      }
1302    return parent;
1303 }
1304
1305 EAPI Evas_Object *
1306 elm_widget_parent2_get(const Evas_Object *obj)
1307 {
1308    if (_elm_widget_is(obj))
1309      {
1310         Smart_Data *sd = evas_object_smart_data_get(obj);
1311         if (sd) return sd->parent2;
1312      }
1313    return NULL;
1314 }
1315
1316 EAPI void
1317 elm_widget_parent2_set(Evas_Object *obj, Evas_Object *parent)
1318 {
1319    API_ENTRY return;
1320    sd->parent2 = parent;
1321 }
1322
1323 EAPI void
1324 elm_widget_event_callback_add(Evas_Object *obj,
1325                               Elm_Event_Cb func,
1326                               const void  *data)
1327 {
1328    API_ENTRY return;
1329    EINA_SAFETY_ON_NULL_RETURN(func);
1330    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1331    ecb->func = func;
1332    ecb->data = data;
1333    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1334 }
1335
1336 EAPI void *
1337 elm_widget_event_callback_del(Evas_Object *obj,
1338                               Elm_Event_Cb func,
1339                               const void  *data)
1340 {
1341    API_ENTRY return NULL;
1342    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1343    Eina_List *l;
1344    Elm_Event_Cb_Data *ecd;
1345    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1346      if ((ecd->func == func) && (ecd->data == data))
1347        {
1348           free(ecd);
1349           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1350           return (void *)data;
1351        }
1352    return NULL;
1353 }
1354
1355 EAPI Eina_Bool
1356 elm_widget_event_propagate(Evas_Object       *obj,
1357                            Evas_Callback_Type type,
1358                            void              *event_info,
1359                            Evas_Event_Flags  *event_flags)
1360 {
1361    API_ENTRY return EINA_FALSE; //TODO reduce.
1362    if (!_elm_widget_is(obj)) return EINA_FALSE;
1363    Evas_Object *parent = obj;
1364    Elm_Event_Cb_Data *ecd;
1365    Eina_List *l, *l_prev;
1366
1367    while (parent &&
1368           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1369      {
1370         sd = evas_object_smart_data_get(parent);
1371         if ((!sd) || (!_elm_widget_is(obj)))
1372           return EINA_FALSE; //Not Elm Widget
1373
1374         if (sd->event_func && (sd->event_func(parent, obj, type, event_info)))
1375           return EINA_TRUE;
1376
1377         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1378           {
1379              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1380                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1381                return EINA_TRUE;
1382           }
1383         parent = sd->parent_obj;
1384      }
1385
1386    return EINA_FALSE;
1387 }
1388
1389 /**
1390  * @internal
1391  *
1392  * Set custom focus chain.
1393  *
1394  * This function i set one new and overwrite any previous custom focus chain
1395  * with the list of objects. The previous list will be deleted and this list
1396  * will be managed. After setted, don't modity it.
1397  *
1398  * @note On focus cycle, only will be evaluated children of this container.
1399  *
1400  * @param obj The container widget
1401  * @param objs Chain of objects to pass focus
1402  * @ingroup Widget
1403  */
1404 EAPI void
1405 elm_widget_focus_custom_chain_set(Evas_Object *obj,
1406                                   Eina_List   *objs)
1407 {
1408    API_ENTRY return;
1409    if (!sd->focus_next_func)
1410      return;
1411
1412    elm_widget_focus_custom_chain_unset(obj);
1413
1414    Eina_List *l;
1415    Evas_Object *o;
1416
1417    EINA_LIST_FOREACH(objs, l, o)
1418      {
1419         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1420                                        _elm_object_focus_chain_del_cb, sd);
1421      }
1422
1423    sd->focus_chain = objs;
1424 }
1425
1426 /**
1427  * @internal
1428  *
1429  * Get custom focus chain
1430  *
1431  * @param obj The container widget
1432  * @ingroup Widget
1433  */
1434 EAPI const Eina_List *
1435 elm_widget_focus_custom_chain_get(const Evas_Object *obj)
1436 {
1437    API_ENTRY return NULL;
1438    return (const Eina_List *)sd->focus_chain;
1439 }
1440
1441 /**
1442  * @internal
1443  *
1444  * Unset custom focus chain
1445  *
1446  * @param obj The container widget
1447  * @ingroup Widget
1448  */
1449 EAPI void
1450 elm_widget_focus_custom_chain_unset(Evas_Object *obj)
1451 {
1452    API_ENTRY return;
1453    Eina_List *l, *l_next;
1454    Evas_Object *o;
1455
1456    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1457      {
1458         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1459                                             _elm_object_focus_chain_del_cb, sd);
1460         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1461      }
1462 }
1463
1464 /**
1465  * @internal
1466  *
1467  * Append object to custom focus chain.
1468  *
1469  * @note If relative_child equal to NULL or not in custom chain, the object
1470  * will be added in end.
1471  *
1472  * @note On focus cycle, only will be evaluated children of this container.
1473  *
1474  * @param obj The container widget
1475  * @param child The child to be added in custom chain
1476  * @param relative_child The relative object to position the child
1477  * @ingroup Widget
1478  */
1479 EAPI void
1480 elm_widget_focus_custom_chain_append(Evas_Object *obj,
1481                                      Evas_Object *child,
1482                                      Evas_Object *relative_child)
1483 {
1484    API_ENTRY return;
1485    EINA_SAFETY_ON_NULL_RETURN(child);
1486    if (!sd->focus_next_func)
1487      return;
1488
1489    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1490                                        _elm_object_focus_chain_del_cb, sd);
1491
1492    if (!relative_child)
1493      {
1494         sd->focus_chain = eina_list_append(sd->focus_chain, child);
1495         return;
1496      }
1497
1498    sd->focus_chain = eina_list_append_relative(sd->focus_chain, child, relative_child);
1499    return;
1500 }
1501
1502 /**
1503  * @internal
1504  *
1505  * Prepend object to custom focus chain.
1506  *
1507  * @note If relative_child equal to NULL or not in custom chain, the object
1508  * will be added in begin.
1509  *
1510  * @note On focus cycle, only will be evaluated children of this container.
1511  *
1512  * @param obj The container widget
1513  * @param child The child to be added in custom chain
1514  * @param relative_child The relative object to position the child
1515  * @ingroup Widget
1516  */
1517 EAPI void
1518 elm_widget_focus_custom_chain_prepend(Evas_Object *obj,
1519                                       Evas_Object *child,
1520                                       Evas_Object *relative_child)
1521 {
1522    API_ENTRY return;
1523    EINA_SAFETY_ON_NULL_RETURN(child);
1524    if (!sd->focus_next_func)
1525      return;
1526
1527    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1528                                        _elm_object_focus_chain_del_cb, sd);
1529
1530    if (!relative_child)
1531      {
1532         sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1533         return;
1534      }
1535
1536    sd->focus_chain = eina_list_prepend_relative(sd->focus_chain, child, relative_child);
1537    return;
1538 }
1539
1540 /**
1541  * @internal
1542  *
1543  * Give focus to next object in object tree.
1544  *
1545  * Give focus to next object in focus chain of one object sub-tree.
1546  * If the last object of chain already have focus, the focus will go to the
1547  * first object of chain.
1548  *
1549  * @param obj The widget root of sub-tree
1550  * @param dir Direction to cycle the focus
1551  *
1552  * @ingroup Widget
1553  */
1554 EAPI void
1555 elm_widget_focus_cycle(Evas_Object        *obj,
1556                        Elm_Focus_Direction dir)
1557 {
1558    Evas_Object *target = NULL;
1559    if (!_elm_widget_is(obj))
1560      return;
1561    elm_widget_focus_next_get(obj, dir, &target);
1562    if (target)
1563      elm_widget_focus_steal(target);
1564 }
1565
1566 /**
1567  * @internal
1568  *
1569  * Give focus to near object in one direction.
1570  *
1571  * Give focus to near object in direction of one object.
1572  * If none focusable object in given direction, the focus will not change.
1573  *
1574  * @param obj The reference widget
1575  * @param x Horizontal component of direction to focus
1576  * @param y Vertical component of direction to focus
1577  *
1578  * @ingroup Widget
1579  */
1580 EAPI void
1581 elm_widget_focus_direction_go(Evas_Object *obj __UNUSED__,
1582                               int          x __UNUSED__,
1583                               int          y __UNUSED__)
1584 {
1585    return; /* TODO */
1586 }
1587
1588 /**
1589  * @internal
1590  *
1591  * Get next object in focus chain of object tree.
1592  *
1593  * Get next object in focus chain of one object sub-tree.
1594  * Return the next object by reference. If don't have any candidate to receive
1595  * focus before chain end, the first candidate will be returned.
1596  *
1597  * @param obj The widget root of sub-tree
1598  * @param dir Direction os focus chain
1599  * @param next The next object in focus chain
1600  * @return EINA_TRUE if don't need focus chain restart/loop back
1601  *         to use 'next' obj.
1602  *
1603  * @ingroup Widget
1604  */
1605 EAPI Eina_Bool
1606 elm_widget_focus_next_get(const Evas_Object  *obj,
1607                           Elm_Focus_Direction dir,
1608                           Evas_Object       **next)
1609 {
1610    if (!next)
1611      return EINA_FALSE;
1612    *next = NULL;
1613
1614    API_ENTRY return EINA_FALSE;
1615
1616    /* Ignore if disabled */
1617    if ((!evas_object_visible_get(obj))
1618        || (elm_widget_disabled_get(obj))
1619        || (elm_widget_tree_unfocusable_get(obj)))
1620      return EINA_FALSE;
1621
1622    /* Try use hook */
1623    if (sd->focus_next_func)
1624      return sd->focus_next_func(obj, dir, next);
1625
1626    if (!elm_widget_can_focus_get(obj))
1627      return EINA_FALSE;
1628
1629    /* Return */
1630    *next = (Evas_Object *)obj;
1631    return !elm_widget_focus_get(obj);
1632 }
1633
1634 /**
1635  * @internal
1636  *
1637  * Get next object in focus chain of object tree in list.
1638  *
1639  * Get next object in focus chain of one object sub-tree ordered by one list.
1640  * Return the next object by reference. If don't have any candidate to receive
1641  * focus before list end, the first candidate will be returned.
1642  *
1643  * @param obj The widget root of sub-tree
1644  * @param dir Direction os focus chain
1645  * @param items list with ordered objects
1646  * @param list_data_get function to get the object from one item of list
1647  * @param next The next object in focus chain
1648  * @return EINA_TRUE if don't need focus chain restart/loop back
1649  *         to use 'next' obj.
1650  *
1651  * @ingroup Widget
1652  */
1653 EAPI Eina_Bool
1654 elm_widget_focus_list_next_get(const Evas_Object  *obj,
1655                                const Eina_List    *items,
1656                                void *(*list_data_get)(const Eina_List * list),
1657                                Elm_Focus_Direction dir,
1658                                Evas_Object       **next)
1659 {
1660    Eina_List *(*list_next)(const Eina_List * list) = NULL;
1661
1662    if (!next)
1663      return EINA_FALSE;
1664    *next = NULL;
1665
1666    if (!_elm_widget_is(obj))
1667      return EINA_FALSE;
1668
1669    if (!items)
1670      return EINA_FALSE;
1671
1672    /* Direction */
1673    if (dir == ELM_FOCUS_PREVIOUS)
1674      {
1675         items = eina_list_last(items);
1676         list_next = eina_list_prev;
1677      }
1678    else if (dir == ELM_FOCUS_NEXT)
1679      list_next = eina_list_next;
1680    else
1681      return EINA_FALSE;
1682
1683    const Eina_List *l = items;
1684
1685    /* Recovery last focused sub item */
1686    if (elm_widget_focus_get(obj))
1687      for (; l; l = list_next(l))
1688        {
1689           Evas_Object *cur = list_data_get(l);
1690           if (elm_widget_focus_get(cur)) break;
1691        }
1692
1693    const Eina_List *start = l;
1694    Evas_Object *to_focus = NULL;
1695
1696    /* Interate sub items */
1697    /* Go to end of list */
1698    for (; l; l = list_next(l))
1699      {
1700         Evas_Object *tmp = NULL;
1701         Evas_Object *cur = list_data_get(l);
1702
1703         if (elm_widget_parent_get(cur) != obj)
1704           continue;
1705
1706         /* Try Focus cycle in subitem */
1707         if (elm_widget_focus_next_get(cur, dir, &tmp))
1708           {
1709              *next = tmp;
1710              return EINA_TRUE;
1711           }
1712         else if ((tmp) && (!to_focus))
1713           to_focus = tmp;
1714      }
1715
1716    l = items;
1717
1718    /* Get First possible */
1719    for (; l != start; l = list_next(l))
1720      {
1721         Evas_Object *tmp = NULL;
1722         Evas_Object *cur = list_data_get(l);
1723
1724         if (elm_widget_parent_get(cur) != obj)
1725           continue;
1726
1727         /* Try Focus cycle in subitem */
1728         elm_widget_focus_next_get(cur, dir, &tmp);
1729         if (tmp)
1730           {
1731              *next = tmp;
1732              return EINA_FALSE;
1733           }
1734      }
1735
1736    *next = to_focus;
1737    return EINA_FALSE;
1738 }
1739
1740 EAPI void
1741 elm_widget_signal_emit(Evas_Object *obj,
1742                        const char  *emission,
1743                        const char  *source)
1744 {
1745    API_ENTRY return;
1746    if (!sd->signal_func) return;
1747    sd->signal_func(obj, emission, source);
1748 }
1749
1750 static void
1751 _edje_signal_callback(void        *data,
1752                       Evas_Object *obj __UNUSED__,
1753                       const char  *emission,
1754                       const char  *source)
1755 {
1756    Edje_Signal_Data *esd = data;
1757    esd->func(esd->data, esd->obj, emission, source);
1758 }
1759
1760 EAPI void
1761 elm_widget_signal_callback_add(Evas_Object   *obj,
1762                                const char    *emission,
1763                                const char    *source,
1764                                Edje_Signal_Cb func,
1765                                void          *data)
1766 {
1767    Edje_Signal_Data *esd;
1768    API_ENTRY return;
1769    if (!sd->callback_add_func) return;
1770    EINA_SAFETY_ON_NULL_RETURN(func);
1771
1772    esd = ELM_NEW(Edje_Signal_Data);
1773    if (!esd) return;
1774
1775    esd->obj = obj;
1776    esd->func = func;
1777    esd->emission = eina_stringshare_add(emission);
1778    esd->source = eina_stringshare_add(source);
1779    esd->data = data;
1780    sd->edje_signals = eina_list_append(sd->edje_signals, esd);
1781    sd->callback_add_func(obj, emission, source, _edje_signal_callback, esd);
1782 }
1783
1784 EAPI void *
1785 elm_widget_signal_callback_del(Evas_Object   *obj,
1786                                const char    *emission,
1787                                const char    *source,
1788                                Edje_Signal_Cb func)
1789 {
1790    Edje_Signal_Data *esd;
1791    Eina_List *l;
1792    void *data = NULL;
1793    API_ENTRY return NULL;
1794    if (!sd->callback_del_func) return NULL;
1795
1796    EINA_LIST_FOREACH(sd->edje_signals, l, esd)
1797      {
1798         if ((esd->func == func) && (!strcmp(esd->emission, emission)) &&
1799             (!strcmp(esd->source, source)))
1800           {
1801              sd->edje_signals = eina_list_remove_list(sd->edje_signals, l);
1802              eina_stringshare_del(esd->emission);
1803              eina_stringshare_del(esd->source);
1804              data = esd->data;
1805              free(esd);
1806              break;
1807           }
1808      }
1809    sd->callback_del_func(obj, emission, source, _edje_signal_callback, esd);
1810    return data;
1811 }
1812
1813 EAPI void
1814 elm_widget_focus_set(Evas_Object *obj,
1815                      int          first)
1816 {
1817    API_ENTRY return;
1818    if (!sd->focused)
1819      {
1820         focus_order++;
1821         sd->focus_order = focus_order;
1822         sd->focused = EINA_TRUE;
1823         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1824      }
1825    if (sd->focus_func)
1826      {
1827         sd->focus_func(obj);
1828         return;
1829      }
1830    else
1831      {
1832         if (first)
1833           {
1834              if ((_is_focusable(sd->resize_obj)) &&
1835                  (!elm_widget_disabled_get(sd->resize_obj)))
1836                {
1837                   elm_widget_focus_set(sd->resize_obj, first);
1838                }
1839              else
1840                {
1841                   const Eina_List *l;
1842                   Evas_Object *child;
1843                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1844                     {
1845                        if ((_is_focusable(child)) &&
1846                            (!elm_widget_disabled_get(child)))
1847                          {
1848                             elm_widget_focus_set(child, first);
1849                             break;
1850                          }
1851                     }
1852                }
1853           }
1854         else
1855           {
1856              const Eina_List *l;
1857              Evas_Object *child;
1858              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
1859                {
1860                   if ((_is_focusable(child)) &&
1861                       (!elm_widget_disabled_get(child)))
1862                     {
1863                        elm_widget_focus_set(child, first);
1864                        break;
1865                     }
1866                }
1867              if (!l)
1868                {
1869                   if ((_is_focusable(sd->resize_obj)) &&
1870                       (!elm_widget_disabled_get(sd->resize_obj)))
1871                     {
1872                        elm_widget_focus_set(sd->resize_obj, first);
1873                     }
1874                }
1875           }
1876      }
1877 }
1878
1879 EAPI Evas_Object *
1880 elm_widget_parent_get(const Evas_Object *obj)
1881 {
1882    API_ENTRY return NULL;
1883    return sd->parent_obj;
1884 }
1885
1886 EAPI void
1887 elm_widget_focused_object_clear(Evas_Object *obj)
1888 {
1889    API_ENTRY return;
1890    if (!sd->focused) return;
1891    if (elm_widget_focus_get(sd->resize_obj))
1892      elm_widget_focused_object_clear(sd->resize_obj);
1893    else
1894      {
1895         const Eina_List *l;
1896         Evas_Object *child;
1897         EINA_LIST_FOREACH(sd->subobjs, l, child)
1898           {
1899              if (elm_widget_focus_get(child))
1900                {
1901                   elm_widget_focused_object_clear(child);
1902                   break;
1903                }
1904           }
1905      }
1906    sd->focused = EINA_FALSE;
1907    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1908    if (sd->focus_func) sd->focus_func(obj);
1909 }
1910
1911 EAPI void
1912 elm_widget_focus_steal(Evas_Object *obj)
1913 {
1914    Evas_Object *parent, *parent2, *o;
1915    API_ENTRY return;
1916
1917    if (sd->focused) return;
1918    if (sd->disabled) return;
1919    if (!sd->can_focus) return;
1920    if (sd->tree_unfocusable) return;
1921    parent = obj;
1922    for (;;)
1923      {
1924         o = elm_widget_parent_get(parent);
1925         if (!o) break;
1926         sd = evas_object_smart_data_get(o);
1927         if (sd->disabled || sd->tree_unfocusable) return;
1928         if (sd->focused) break;
1929         parent = o;
1930      }
1931    if ((!elm_widget_parent_get(parent)) &&
1932        (!elm_widget_parent2_get(parent)))
1933       elm_widget_focused_object_clear(parent);
1934    else
1935      {
1936         parent2 = elm_widget_parent_get(parent);
1937         if (!parent2) parent2 = elm_widget_parent2_get(parent);
1938         parent = parent2;
1939         sd = evas_object_smart_data_get(parent);
1940         if (sd)
1941           {
1942              if ((sd->resize_obj) && (elm_widget_focus_get(sd->resize_obj)))
1943                 elm_widget_focused_object_clear(sd->resize_obj);
1944              else
1945                {
1946                   const Eina_List *l;
1947                   Evas_Object *child;
1948                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1949                     {
1950                        if (elm_widget_focus_get(child))
1951                          {
1952                             elm_widget_focused_object_clear(child);
1953                             break;
1954                          }
1955                     }
1956                }
1957           }
1958      }
1959    _parent_focus(obj);
1960    return;
1961 }
1962
1963 EAPI void
1964 elm_widget_focus_restore(Evas_Object *obj)
1965 {
1966    Evas_Object *newest = NULL;
1967    unsigned int newest_focus_order = 0;
1968    API_ENTRY return;
1969
1970    newest = _newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
1971    if (newest)
1972      {
1973         elm_object_focus_set(newest, EINA_FALSE);
1974         elm_object_focus_set(newest, EINA_TRUE);
1975      }
1976 }
1977
1978 void
1979 _elm_widget_top_win_focused_set(Evas_Object *obj, Eina_Bool top_win_focused)
1980 {
1981    const Eina_List *l;
1982    Evas_Object *child;
1983    API_ENTRY return;
1984
1985    if (sd->top_win_focused == top_win_focused) return;
1986    if (sd->resize_obj)
1987      _elm_widget_top_win_focused_set(sd->resize_obj, top_win_focused);
1988    EINA_LIST_FOREACH(sd->subobjs, l, child)
1989      {
1990         _elm_widget_top_win_focused_set(child, top_win_focused);
1991      }
1992    sd->top_win_focused = top_win_focused;
1993 }
1994
1995 Eina_Bool
1996 _elm_widget_top_win_focused_get(const Evas_Object *obj)
1997 {
1998    API_ENTRY return EINA_FALSE;
1999    return sd->top_win_focused;
2000 }
2001
2002 EAPI void
2003 elm_widget_activate(Evas_Object *obj)
2004 {
2005    API_ENTRY return;
2006    elm_widget_change(obj);
2007    if (sd->activate_func) sd->activate_func(obj);
2008 }
2009
2010 EAPI void
2011 elm_widget_change(Evas_Object *obj)
2012 {
2013    API_ENTRY return;
2014    elm_widget_change(elm_widget_parent_get(obj));
2015    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
2016 }
2017
2018 EAPI void
2019 elm_widget_disabled_set(Evas_Object *obj,
2020                         Eina_Bool    disabled)
2021 {
2022    API_ENTRY return;
2023
2024    if (sd->disabled == disabled) return;
2025    sd->disabled = !!disabled;
2026    elm_widget_focus_disabled_handle(obj);
2027    if (sd->disable_func) sd->disable_func(obj);
2028 }
2029
2030 EAPI Eina_Bool
2031 elm_widget_disabled_get(const Evas_Object *obj)
2032 {
2033    API_ENTRY return 0;
2034    return sd->disabled;
2035 }
2036
2037 EAPI void
2038 elm_widget_show_region_set(Evas_Object *obj,
2039                            Evas_Coord   x,
2040                            Evas_Coord   y,
2041                            Evas_Coord   w,
2042                            Evas_Coord   h,
2043                            Eina_Bool    forceshow)
2044 {
2045    Evas_Object *parent_obj, *child_obj;
2046    Evas_Coord px, py, cx, cy;
2047
2048    API_ENTRY return;
2049    if (!forceshow && (x == sd->rx) && (y == sd->ry)
2050             && (w == sd->rw) && (h == sd->rh)) return;
2051    sd->rx = x;
2052    sd->ry = y;
2053    sd->rw = w;
2054    sd->rh = h;
2055    if (sd->on_show_region_func)
2056      sd->on_show_region_func(sd->on_show_region_data, obj);
2057
2058    do
2059      {
2060         parent_obj = sd->parent_obj;
2061         child_obj = sd->obj;
2062         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
2063         sd = evas_object_smart_data_get(parent_obj);
2064         if (!sd) break;
2065
2066         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
2067         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
2068
2069         x += (cx - px);
2070         y += (cy - py);
2071         sd->rx = x;
2072         sd->ry = y;
2073         sd->rw = w;
2074         sd->rh = h;
2075
2076         if (sd->on_show_region_func)
2077           {
2078              sd->on_show_region_func(sd->on_show_region_data, parent_obj);
2079           }
2080      }
2081    while (parent_obj);
2082 }
2083
2084 EAPI void
2085 elm_widget_show_region_get(const Evas_Object *obj,
2086                            Evas_Coord        *x,
2087                            Evas_Coord        *y,
2088                            Evas_Coord        *w,
2089                            Evas_Coord        *h)
2090 {
2091    API_ENTRY return;
2092    if (x) *x = sd->rx;
2093    if (y) *y = sd->ry;
2094    if (w) *w = sd->rw;
2095    if (h) *h = sd->rh;
2096 }
2097
2098 /**
2099  * @internal
2100  *
2101  * Get the focus region of the given widget.
2102  *
2103  * The focus region is the area of a widget that should brought into the
2104  * visible area when the widget is focused. Mostly used to show the part of
2105  * an entry where the cursor is, for example. The area returned is relative
2106  * to the object @p obj.
2107  * If the @p obj doesn't have the proper on_focus_region_hook set, this
2108  * function will return the full size of the object.
2109  *
2110  * @param obj The widget object
2111  * @param x Where to store the x coordinate of the area
2112  * @param y Where to store the y coordinate of the area
2113  * @param w Where to store the width of the area
2114  * @param h Where to store the height of the area
2115  *
2116  * @ingroup Widget
2117  */
2118 EAPI void
2119 elm_widget_focus_region_get(const Evas_Object *obj,
2120                             Evas_Coord        *x,
2121                             Evas_Coord        *y,
2122                             Evas_Coord        *w,
2123                             Evas_Coord        *h)
2124 {
2125    Smart_Data *sd;
2126
2127    if (!obj) return;
2128
2129    sd = evas_object_smart_data_get(obj);
2130    if (!sd || !_elm_widget_is(obj) || !sd->on_focus_region_func)
2131      {
2132         evas_object_geometry_get(obj, NULL, NULL, w, h);
2133         if (x) *x = 0;
2134         if (y) *y = 0;
2135         return;
2136      }
2137    sd->on_focus_region_func(obj, x, y, w, h);
2138 }
2139
2140 EAPI void
2141 elm_widget_scroll_hold_push(Evas_Object *obj)
2142 {
2143    API_ENTRY return;
2144    sd->scroll_hold++;
2145    if (sd->scroll_hold == 1)
2146      evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
2147    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
2148    // FIXME: on delete/reparent hold pop
2149 }
2150
2151 EAPI void
2152 elm_widget_scroll_hold_pop(Evas_Object *obj)
2153 {
2154    API_ENTRY return;
2155    sd->scroll_hold--;
2156    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
2157    if (!sd->scroll_hold)
2158      evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
2159    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
2160 }
2161
2162 EAPI int
2163 elm_widget_scroll_hold_get(const Evas_Object *obj)
2164 {
2165    API_ENTRY return 0;
2166    return sd->scroll_hold;
2167 }
2168
2169 EAPI void
2170 elm_widget_scroll_freeze_push(Evas_Object *obj)
2171 {
2172    API_ENTRY return;
2173    sd->scroll_freeze++;
2174    if (sd->scroll_freeze == 1)
2175      evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
2176    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
2177    // FIXME: on delete/reparent freeze pop
2178 }
2179
2180 EAPI void
2181 elm_widget_scroll_freeze_pop(Evas_Object *obj)
2182 {
2183    API_ENTRY return;
2184    sd->scroll_freeze--;
2185    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
2186    if (!sd->scroll_freeze)
2187      evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
2188    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
2189 }
2190
2191 EAPI int
2192 elm_widget_scroll_freeze_get(const Evas_Object *obj)
2193 {
2194    API_ENTRY return 0;
2195    return sd->scroll_freeze;
2196 }
2197
2198 EAPI void
2199 elm_widget_scale_set(Evas_Object *obj,
2200                      double       scale)
2201 {
2202    API_ENTRY return;
2203    if (scale <= 0.0) scale = 0.0;
2204    if (sd->scale != scale)
2205      {
2206         sd->scale = scale;
2207         elm_widget_theme(obj);
2208      }
2209 }
2210
2211 EAPI double
2212 elm_widget_scale_get(const Evas_Object *obj)
2213 {
2214    API_ENTRY return 1.0;
2215    // FIXME: save walking up the tree by storing/caching parent scale
2216    if (sd->scale == 0.0)
2217      {
2218         if (sd->parent_obj)
2219           return elm_widget_scale_get(sd->parent_obj);
2220         else
2221           return 1.0;
2222      }
2223    return sd->scale;
2224 }
2225
2226 EAPI void
2227 elm_widget_theme_set(Evas_Object *obj,
2228                      Elm_Theme   *th)
2229 {
2230    API_ENTRY return;
2231    if (sd->theme != th)
2232      {
2233         if (sd->theme) elm_theme_free(sd->theme);
2234         sd->theme = th;
2235         if (th) th->ref++;
2236         elm_widget_theme(obj);
2237      }
2238 }
2239
2240 EAPI void
2241 elm_widget_text_part_set(Evas_Object *obj, const char *part, const char *label)
2242 {
2243    API_ENTRY return;
2244
2245    if (!sd->on_text_set_func)
2246      return;
2247
2248    sd->on_text_set_func(obj, part, label);
2249 }
2250
2251 EAPI const char *
2252 elm_widget_text_part_get(const Evas_Object *obj, const char *part)
2253 {
2254    API_ENTRY return NULL;
2255
2256    if (!sd->on_text_get_func)
2257      return NULL;
2258
2259    return sd->on_text_get_func(obj, part);
2260 }
2261
2262 EAPI void
2263 elm_widget_domain_translatable_text_part_set(Evas_Object *obj, const char *part, const char *domain, const char *label)
2264 {
2265    const char *str;
2266    Eina_List *l;
2267    Elm_Translate_String_Data *ts = NULL;
2268    API_ENTRY return;
2269
2270    str = eina_stringshare_add(part);
2271    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2272       if (ts->id == str)
2273         break;
2274       else
2275         ts = NULL;
2276
2277    if (!ts && !label)
2278      eina_stringshare_del(str);
2279    else if (!ts)
2280      {
2281         ts = malloc(sizeof(Elm_Translate_String_Data));
2282         if (!ts) return;
2283
2284         ts->id = str;
2285         ts->domain = eina_stringshare_add(domain);
2286         ts->string = eina_stringshare_add(label);
2287         sd->translate_strings = eina_list_append(sd->translate_strings, ts);
2288      }
2289    else
2290      {
2291         if (label)
2292           {
2293              eina_stringshare_replace(&ts->domain, domain);
2294              eina_stringshare_replace(&ts->string, label);
2295           }
2296         else
2297           {
2298              sd->translate_strings = eina_list_remove_list(
2299                                                 sd->translate_strings, l);
2300              eina_stringshare_del(ts->id);
2301              eina_stringshare_del(ts->domain);
2302              eina_stringshare_del(ts->string);
2303              free(ts);
2304           }
2305         eina_stringshare_del(str);
2306      }
2307
2308 #ifdef HAVE_GETTEXT
2309    if (label && label[0])
2310      label = dgettext(domain, label);
2311 #endif
2312    elm_widget_text_part_set(obj, part, label);
2313 }
2314
2315 EAPI const char *
2316 elm_widget_translatable_text_part_get(const Evas_Object *obj, const char *part)
2317 {
2318    const char *str, *ret = NULL;
2319    Eina_List *l;
2320    Elm_Translate_String_Data *ts;
2321    API_ENTRY return NULL;
2322
2323    str = eina_stringshare_add(part);
2324    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2325       if (ts->id == str)
2326         {
2327            ret = ts->string;
2328            break;
2329         }
2330    eina_stringshare_del(str);
2331    return ret;
2332 }
2333
2334 EAPI void
2335 elm_widget_translate(Evas_Object *obj)
2336 {
2337    const Eina_List *l;
2338    Evas_Object *child;
2339    Elm_Translate_String_Data *ts;
2340
2341    API_ENTRY return;
2342    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_translate(child);
2343    if (sd->resize_obj) elm_widget_translate(sd->resize_obj);
2344    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
2345    if (sd->translate_func) sd->translate_func(obj);
2346
2347 #ifdef HAVE_GETTEXT
2348    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2349      {
2350         const char *s = dgettext(ts->domain, ts->string);
2351         elm_widget_text_part_set(obj, ts->id, s);
2352      }
2353 #endif
2354 }
2355
2356 EAPI void
2357 elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content)
2358 {
2359    API_ENTRY return;
2360
2361    if (!sd->on_content_set_func)  return;
2362    sd->on_content_set_func(obj, part, content);
2363 }
2364
2365 EAPI Evas_Object *
2366 elm_widget_content_part_get(const Evas_Object *obj, const char *part)
2367 {
2368    API_ENTRY return NULL;
2369
2370    if (!sd->on_content_get_func) return NULL;
2371    return sd->on_content_get_func(obj, part);
2372 }
2373
2374 EAPI Evas_Object *
2375 elm_widget_content_part_unset(Evas_Object *obj, const char *part)
2376 {
2377    API_ENTRY return NULL;
2378
2379    if (!sd->on_content_unset_func) return NULL;
2380    return sd->on_content_unset_func(obj, part);
2381 }
2382
2383 EAPI void
2384 elm_widget_access_info_set(Evas_Object *obj, const char *txt)
2385 {
2386    API_ENTRY return;
2387    if (sd->access_info) eina_stringshare_del(sd->access_info);
2388    if (!txt) sd->access_info = NULL;
2389    else sd->access_info = eina_stringshare_add(txt);
2390 }
2391
2392 EAPI const char *
2393 elm_widget_access_info_get(Evas_Object *obj)
2394 {
2395    API_ENTRY return NULL;
2396    return sd->access_info;
2397 }
2398
2399 EAPI Elm_Theme *
2400 elm_widget_theme_get(const Evas_Object *obj)
2401 {
2402    API_ENTRY return NULL;
2403    if (!sd->theme)
2404      {
2405         if (sd->parent_obj)
2406           return elm_widget_theme_get(sd->parent_obj);
2407         else
2408           return NULL;
2409      }
2410    return sd->theme;
2411 }
2412
2413 EAPI void
2414 elm_widget_style_set(Evas_Object *obj,
2415                      const char  *style)
2416 {
2417    API_ENTRY return;
2418
2419    if (eina_stringshare_replace(&sd->style, style))
2420      elm_widget_theme(obj);
2421 }
2422
2423 EAPI const char *
2424 elm_widget_style_get(const Evas_Object *obj)
2425 {
2426    API_ENTRY return NULL;
2427    if (sd->style) return sd->style;
2428    return "default";
2429 }
2430
2431 EAPI void
2432 elm_widget_type_set(Evas_Object *obj,
2433                     const char  *type)
2434 {
2435    API_ENTRY return;
2436    eina_stringshare_replace(&sd->type, type);
2437 }
2438
2439 EAPI const char *
2440 elm_widget_type_get(const Evas_Object *obj)
2441 {
2442    API_ENTRY return NULL;
2443    if (sd->type) return sd->type;
2444    return "";
2445 }
2446
2447 EAPI void
2448 elm_widget_tooltip_add(Evas_Object *obj,
2449                        Elm_Tooltip *tt)
2450 {
2451    API_ENTRY return;
2452    sd->tooltips = eina_list_append(sd->tooltips, tt);
2453 }
2454
2455 EAPI void
2456 elm_widget_tooltip_del(Evas_Object *obj,
2457                        Elm_Tooltip *tt)
2458 {
2459    API_ENTRY return;
2460    sd->tooltips = eina_list_remove(sd->tooltips, tt);
2461 }
2462
2463 EAPI void
2464 elm_widget_cursor_add(Evas_Object *obj,
2465                       Elm_Cursor  *cur)
2466 {
2467    API_ENTRY return;
2468    sd->cursors = eina_list_append(sd->cursors, cur);
2469 }
2470
2471 EAPI void
2472 elm_widget_cursor_del(Evas_Object *obj,
2473                       Elm_Cursor  *cur)
2474 {
2475    API_ENTRY return;
2476    sd->cursors = eina_list_remove(sd->cursors, cur);
2477 }
2478
2479 EAPI void
2480 elm_widget_drag_lock_x_set(Evas_Object *obj,
2481                            Eina_Bool    lock)
2482 {
2483    API_ENTRY return;
2484    if (sd->drag_x_locked == lock) return;
2485    sd->drag_x_locked = lock;
2486    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
2487    else _propagate_x_drag_lock(obj, -1);
2488 }
2489
2490 EAPI void
2491 elm_widget_drag_lock_y_set(Evas_Object *obj,
2492                            Eina_Bool    lock)
2493 {
2494    API_ENTRY return;
2495    if (sd->drag_y_locked == lock) return;
2496    sd->drag_y_locked = lock;
2497    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
2498    else _propagate_y_drag_lock(obj, -1);
2499 }
2500
2501 EAPI Eina_Bool
2502 elm_widget_drag_lock_x_get(const Evas_Object *obj)
2503 {
2504    API_ENTRY return EINA_FALSE;
2505    return sd->drag_x_locked;
2506 }
2507
2508 EAPI Eina_Bool
2509 elm_widget_drag_lock_y_get(const Evas_Object *obj)
2510 {
2511    API_ENTRY return EINA_FALSE;
2512    return sd->drag_y_locked;
2513 }
2514
2515 EAPI int
2516 elm_widget_drag_child_locked_x_get(const Evas_Object *obj)
2517 {
2518    API_ENTRY return 0;
2519    return sd->child_drag_x_locked;
2520 }
2521
2522 EAPI int
2523 elm_widget_drag_child_locked_y_get(const Evas_Object *obj)
2524 {
2525    API_ENTRY return 0;
2526    return sd->child_drag_y_locked;
2527 }
2528
2529 EAPI Eina_Bool
2530 elm_widget_theme_object_set(Evas_Object *obj,
2531                             Evas_Object *edj,
2532                             const char  *wname,
2533                             const char  *welement,
2534                             const char  *wstyle)
2535 {
2536    API_ENTRY return EINA_FALSE;
2537    return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
2538 }
2539
2540 EAPI Eina_Bool
2541 elm_widget_is_check(const Evas_Object *obj)
2542 {
2543    static int abort_on_warn = -1;
2544    if (elm_widget_is(obj))
2545       return EINA_TRUE;
2546
2547    ERR("Passing Object: %p.", obj);
2548    if (abort_on_warn == -1)
2549      {
2550         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2551         else abort_on_warn = 0;
2552      }
2553    if (abort_on_warn == 1) abort();
2554    return EINA_FALSE;
2555 }
2556
2557 EAPI Eina_Bool
2558 elm_widget_type_check(const Evas_Object *obj,
2559                       const char        *type,
2560                       const char        *func)
2561 {
2562    const char *provided, *expected = "(unknown)";
2563    static int abort_on_warn = -1;
2564    provided = elm_widget_type_get(obj);
2565    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
2566    if (type) expected = type;
2567    if ((!provided) || (!provided[0]))
2568      {
2569         provided = evas_object_type_get(obj);
2570         if ((!provided) || (!provided[0]))
2571           provided = "(unknown)";
2572      }
2573    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting type: '%s'", obj, func, provided, expected);
2574    if (abort_on_warn == -1)
2575      {
2576         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2577         else abort_on_warn = 0;
2578      }
2579    if (abort_on_warn == 1) abort();
2580    return EINA_FALSE;
2581 }
2582
2583 /**
2584  * @internal
2585  *
2586  * Split string in words
2587  *
2588  * @param str Source string
2589  * @return List of const words
2590  *
2591  * @see elm_widget_stringlist_free()
2592  * @ingroup Widget
2593  */
2594 EAPI Eina_List *
2595 elm_widget_stringlist_get(const char *str)
2596 {
2597    Eina_List *list = NULL;
2598    const char *s, *b;
2599    if (!str) return NULL;
2600    for (b = s = str; 1; s++)
2601      {
2602         if ((*s == ' ') || (!*s))
2603           {
2604              char *t = malloc(s - b + 1);
2605              if (t)
2606                {
2607                   strncpy(t, b, s - b);
2608                   t[s - b] = 0;
2609                   list = eina_list_append(list, eina_stringshare_add(t));
2610                   free(t);
2611                }
2612              b = s + 1;
2613           }
2614         if (!*s) break;
2615      }
2616    return list;
2617 }
2618
2619 EAPI void
2620 elm_widget_stringlist_free(Eina_List *list)
2621 {
2622    const char *s;
2623    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
2624 }
2625
2626 EAPI void
2627 elm_widget_focus_hide_handle(Evas_Object *obj)
2628 {
2629    _if_focused_revert(obj, EINA_TRUE);
2630 }
2631
2632 EAPI void
2633 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
2634 {
2635    Evas_Object *o = obj;
2636    do
2637      {
2638         if (_elm_widget_is(o)) break;
2639         o = evas_object_smart_parent_get(o);
2640      }
2641    while (o);
2642    if (!o) return;
2643    if (!_is_focusable(o)) return;
2644    elm_widget_focus_steal(o);
2645 }
2646
2647 EAPI void
2648 elm_widget_focus_tree_unfocusable_handle(Evas_Object *obj)
2649 {
2650    API_ENTRY return;
2651
2652    if (!elm_widget_parent_get(obj))
2653      elm_widget_focused_object_clear(obj);
2654    else
2655      _if_focused_revert(obj, EINA_TRUE);
2656 }
2657
2658 EAPI void
2659 elm_widget_focus_disabled_handle(Evas_Object *obj)
2660 {
2661    API_ENTRY return;
2662
2663    elm_widget_focus_tree_unfocusable_handle(obj);
2664 }
2665
2666 /**
2667  * @internal
2668  *
2669  * Allocate a new Elm_Widget_Item-derived structure.
2670  *
2671  * The goal of this structure is to provide common ground for actions
2672  * that a widget item have, such as the owner widget, callback to
2673  * notify deletion, data pointer and maybe more.
2674  *
2675  * @param widget the owner widget that holds this item, must be an elm_widget!
2676  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
2677  *        be used to allocate memory.
2678  *
2679  * @return allocated memory that is already zeroed out, or NULL on errors.
2680  *
2681  * @see elm_widget_item_new() convenience macro.
2682  * @see elm_widget_item_del() to release memory.
2683  * @ingroup Widget
2684  */
2685 EAPI Elm_Widget_Item *
2686 _elm_widget_item_new(Evas_Object *widget,
2687                      size_t       alloc_size)
2688 {
2689    if (!_elm_widget_is(widget))
2690      return NULL;
2691
2692    Elm_Widget_Item *item;
2693
2694    EINA_SAFETY_ON_TRUE_RETURN_VAL(alloc_size < sizeof(Elm_Widget_Item), NULL);
2695    EINA_SAFETY_ON_TRUE_RETURN_VAL(!_elm_widget_is(widget), NULL);
2696
2697    item = calloc(1, alloc_size);
2698    EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
2699
2700    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
2701    item->widget = widget;
2702    return item;
2703 }
2704
2705 /**
2706  * @internal
2707  *
2708  * Releases widget item memory, calling back del_cb() if it exists.
2709  *
2710  * If there is a Elm_Widget_Item::del_cb, then it will be called prior
2711  * to memory release. Note that elm_widget_item_pre_notify_del() calls
2712  * this function and then unset it, thus being useful for 2 step
2713  * cleanup whenever the del_cb may use any of the data that must be
2714  * deleted from item.
2715  *
2716  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
2717  * is presented!
2718  *
2719  * @param item a valid #Elm_Widget_Item to be deleted.
2720  * @see elm_widget_item_del() convenience macro.
2721  * @ingroup Widget
2722  */
2723 EAPI void
2724 _elm_widget_item_del(Elm_Widget_Item *item)
2725 {
2726    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2727
2728    if (item->del_cb)
2729      item->del_cb((void *)item->data, item->widget, item);
2730
2731    if (item->view)
2732      evas_object_del(item->view);
2733
2734    if (item->access)
2735      {
2736         _elm_access_clear(item->access);
2737         free(item->access);
2738         item->access = NULL;
2739      }
2740    if (item->access_info)
2741      {
2742         eina_stringshare_del(item->access_info);
2743         item->access_info = NULL;
2744      }
2745
2746    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
2747    free(item);
2748 }
2749
2750 /**
2751  * @internal
2752  *
2753  * Notify object will be deleted without actually deleting it.
2754  *
2755  * This function will callback Elm_Widget_Item::del_cb if it is set
2756  * and then unset it so it is not called twice (ie: from
2757  * elm_widget_item_del()).
2758  *
2759  * @param item a valid #Elm_Widget_Item to be notified
2760  * @see elm_widget_item_pre_notify_del() convenience macro.
2761  * @ingroup Widget
2762  */
2763 EAPI void
2764 _elm_widget_item_pre_notify_del(Elm_Widget_Item *item)
2765 {
2766    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2767    if (!item->del_cb) return;
2768    item->del_cb((void *)item->data, item->widget, item);
2769    item->del_cb = NULL;
2770 }
2771
2772 /**
2773  * @internal
2774  *
2775  * Set the function to notify when item is being deleted.
2776  *
2777  * This function will complain if there was a callback set already,
2778  * however it will set the new one.
2779  *
2780  * The callback will be called from elm_widget_item_pre_notify_del()
2781  * or elm_widget_item_del() will be called with:
2782  *   - data: the Elm_Widget_Item::data value.
2783  *   - obj: the Elm_Widget_Item::widget evas object.
2784  *   - event_info: the item being deleted.
2785  *
2786  * @param item a valid #Elm_Widget_Item to be notified
2787  * @see elm_widget_item_del_cb_set() convenience macro.
2788  * @ingroup Widget
2789  */
2790 EAPI void
2791 _elm_widget_item_del_cb_set(Elm_Widget_Item *item,
2792                             Evas_Smart_Cb    del_cb)
2793 {
2794    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2795
2796    if ((item->del_cb) && (item->del_cb != del_cb))
2797      WRN("You're replacing a previously set del_cb %p of item %p with %p",
2798          item->del_cb, item, del_cb);
2799
2800    item->del_cb = del_cb;
2801 }
2802
2803 /**
2804  * @internal
2805  *
2806  * Set user-data in this item.
2807  *
2808  * User data may be used to identify this item or just store any
2809  * application data. It is automatically given as the first parameter
2810  * of the deletion notify callback.
2811  *
2812  * @param item a valid #Elm_Widget_Item to store data in.
2813  * @param data user data to store.
2814  * @see elm_widget_item_del_cb_set() convenience macro.
2815  * @ingroup Widget
2816  */
2817 EAPI void
2818 _elm_widget_item_data_set(Elm_Widget_Item *item,
2819                           const void      *data)
2820 {
2821    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2822    if ((item->data) && (item->data != data))
2823      DBG("Replacing item %p data %p with %p", item, item->data, data);
2824    item->data = data;
2825 }
2826
2827 /**
2828  * @internal
2829  *
2830  * Retrieves user-data of this item.
2831  *
2832  * @param item a valid #Elm_Widget_Item to get data from.
2833  * @see elm_widget_item_data_set()
2834  * @ingroup Widget
2835  */
2836 EAPI void *
2837 _elm_widget_item_data_get(const Elm_Widget_Item *item)
2838 {
2839    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2840    return (void *)item->data;
2841 }
2842
2843 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
2844
2845 struct _Elm_Widget_Item_Tooltip
2846 {
2847    Elm_Widget_Item            *item;
2848    Elm_Tooltip_Item_Content_Cb func;
2849    Evas_Smart_Cb               del_cb;
2850    const void                 *data;
2851 };
2852
2853 static Evas_Object *
2854 _elm_widget_item_tooltip_label_create(void        *data,
2855                                       Evas_Object *obj __UNUSED__,
2856                                       Evas_Object *tooltip,
2857                                       void        *item __UNUSED__)
2858 {
2859    Evas_Object *label = elm_label_add(tooltip);
2860    if (!label)
2861      return NULL;
2862    elm_object_style_set(label, "tooltip");
2863    elm_object_text_set(label, data);
2864    return label;
2865 }
2866
2867 static Evas_Object *
2868 _elm_widget_item_tooltip_trans_label_create(void        *data,
2869                                             Evas_Object *obj __UNUSED__,
2870                                             Evas_Object *tooltip,
2871                                             void        *item __UNUSED__)
2872 {
2873    Evas_Object *label = elm_label_add(tooltip);
2874    if (!label)
2875      return NULL;
2876    elm_object_style_set(label, "tooltip");
2877    elm_object_translatable_text_set(label, data);
2878    return label;
2879 }
2880
2881 static void
2882 _elm_widget_item_tooltip_label_del_cb(void        *data,
2883                                       Evas_Object *obj __UNUSED__,
2884                                       void        *event_info __UNUSED__)
2885 {
2886    eina_stringshare_del(data);
2887 }
2888
2889 /**
2890  * @internal
2891  *
2892  * Set the text to be shown in the widget item.
2893  *
2894  * @param item Target item
2895  * @param text The text to set in the content
2896  *
2897  * Setup the text as tooltip to object. The item can have only one tooltip,
2898  * so any previous tooltip data is removed.
2899  *
2900  * @ingroup Widget
2901  */
2902 EAPI void
2903 _elm_widget_item_tooltip_text_set(Elm_Widget_Item *item,
2904                                   const char      *text)
2905 {
2906    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2907    EINA_SAFETY_ON_NULL_RETURN(text);
2908
2909    text = eina_stringshare_add(text);
2910    _elm_widget_item_tooltip_content_cb_set
2911      (item, _elm_widget_item_tooltip_label_create, text,
2912      _elm_widget_item_tooltip_label_del_cb);
2913 }
2914
2915 EAPI void
2916 _elm_widget_item_tooltip_translatable_text_set(Elm_Widget_Item *item,
2917                                                const char      *text)
2918 {
2919    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2920    EINA_SAFETY_ON_NULL_RETURN(text);
2921
2922    text = eina_stringshare_add(text);
2923    _elm_widget_item_tooltip_content_cb_set
2924      (item, _elm_widget_item_tooltip_trans_label_create, text,
2925      _elm_widget_item_tooltip_label_del_cb);
2926 }
2927
2928 static Evas_Object *
2929 _elm_widget_item_tooltip_create(void        *data,
2930                                 Evas_Object *obj,
2931                                 Evas_Object *tooltip)
2932 {
2933    Elm_Widget_Item_Tooltip *wit = data;
2934    return wit->func((void *)wit->data, obj, tooltip, wit->item);
2935 }
2936
2937 static void
2938 _elm_widget_item_tooltip_del_cb(void        *data,
2939                                 Evas_Object *obj,
2940                                 void        *event_info __UNUSED__)
2941 {
2942    Elm_Widget_Item_Tooltip *wit = data;
2943    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item);
2944    free(wit);
2945 }
2946
2947 /**
2948  * @internal
2949  *
2950  * Set the content to be shown in the tooltip item
2951  *
2952  * Setup the tooltip to item. The item can have only one tooltip,
2953  * so any previous tooltip data is removed. @p func(with @p data) will
2954  * be called every time that need show the tooltip and it should
2955  * return a valid Evas_Object. This object is then managed fully by
2956  * tooltip system and is deleted when the tooltip is gone.
2957  *
2958  * @param item the widget item being attached a tooltip.
2959  * @param func the function used to create the tooltip contents.
2960  * @param data what to provide to @a func as callback data/context.
2961  * @param del_cb called when data is not needed anymore, either when
2962  *        another callback replaces @func, the tooltip is unset with
2963  *        elm_widget_item_tooltip_unset() or the owner @a item
2964  *        dies. This callback receives as the first parameter the
2965  *        given @a data, and @c event_info is the item.
2966  *
2967  * @ingroup Widget
2968  */
2969 EAPI void
2970 _elm_widget_item_tooltip_content_cb_set(Elm_Widget_Item            *item,
2971                                         Elm_Tooltip_Item_Content_Cb func,
2972                                         const void                 *data,
2973                                         Evas_Smart_Cb               del_cb)
2974 {
2975    Elm_Widget_Item_Tooltip *wit;
2976
2977    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
2978
2979    if (!func)
2980      {
2981         _elm_widget_item_tooltip_unset(item);
2982         return;
2983      }
2984
2985    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
2986    if (!wit) goto error;
2987    wit->item = item;
2988    wit->func = func;
2989    wit->data = data;
2990    wit->del_cb = del_cb;
2991
2992    elm_object_sub_tooltip_content_cb_set
2993      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
2994      _elm_widget_item_tooltip_del_cb);
2995
2996    return;
2997
2998 error_noitem:
2999    if (del_cb) del_cb((void *)data, NULL, item);
3000    return;
3001 error:
3002    if (del_cb) del_cb((void *)data, item->widget, item);
3003 }
3004
3005 /**
3006  * @internal
3007  *
3008  * Unset tooltip from item
3009  *
3010  * @param item widget item to remove previously set tooltip.
3011  *
3012  * Remove tooltip from item. The callback provided as del_cb to
3013  * elm_widget_item_tooltip_content_cb_set() will be called to notify
3014  * it is not used anymore.
3015  *
3016  * @see elm_widget_item_tooltip_content_cb_set()
3017  *
3018  * @ingroup Widget
3019  */
3020 EAPI void
3021 _elm_widget_item_tooltip_unset(Elm_Widget_Item *item)
3022 {
3023    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3024    elm_object_tooltip_unset(item->view);
3025 }
3026
3027 /**
3028  * @internal
3029  *
3030  * Sets a different style for this item tooltip.
3031  *
3032  * @note before you set a style you should define a tooltip with
3033  *       elm_widget_item_tooltip_content_cb_set() or
3034  *       elm_widget_item_tooltip_text_set()
3035  *
3036  * @param item widget item with tooltip already set.
3037  * @param style the theme style to use (default, transparent, ...)
3038  *
3039  * @ingroup Widget
3040  */
3041 EAPI void
3042 _elm_widget_item_tooltip_style_set(Elm_Widget_Item *item,
3043                                    const char      *style)
3044 {
3045    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3046    elm_object_tooltip_style_set(item->view, style);
3047 }
3048
3049 EAPI Eina_Bool
3050 _elm_widget_item_tooltip_size_restrict_disable(Elm_Widget_Item *item, Eina_Bool disable)
3051 {
3052    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3053    return elm_tooltip_size_restrict_disable(item->view, disable);
3054 }
3055
3056 EAPI Eina_Bool
3057 _elm_widget_item_tooltip_size_restrict_disabled_get(const Elm_Widget_Item *item)
3058 {
3059    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3060    return elm_tooltip_size_restrict_disabled_get(item->view);
3061 }
3062
3063 /**
3064  * @internal
3065  *
3066  * Get the style for this item tooltip.
3067  *
3068  * @param item widget item with tooltip already set.
3069  * @return style the theme style in use, defaults to "default". If the
3070  *         object does not have a tooltip set, then NULL is returned.
3071  *
3072  * @ingroup Widget
3073  */
3074 EAPI const char *
3075 _elm_widget_item_tooltip_style_get(const Elm_Widget_Item *item)
3076 {
3077    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3078    return elm_object_tooltip_style_get(item->view);
3079 }
3080
3081 EAPI void
3082 _elm_widget_item_cursor_set(Elm_Widget_Item *item,
3083                             const char      *cursor)
3084 {
3085    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3086    elm_object_sub_cursor_set(item->view, item->widget, cursor);
3087 }
3088
3089 EAPI const char *
3090 _elm_widget_item_cursor_get(const Elm_Widget_Item *item)
3091 {
3092    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3093    return elm_object_cursor_get(item->view);
3094 }
3095
3096 EAPI void
3097 _elm_widget_item_cursor_unset(Elm_Widget_Item *item)
3098 {
3099    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3100    elm_object_cursor_unset(item->view);
3101 }
3102
3103 /**
3104  * @internal
3105  *
3106  * Sets a different style for this item cursor.
3107  *
3108  * @note before you set a style you should define a cursor with
3109  *       elm_widget_item_cursor_set()
3110  *
3111  * @param item widget item with cursor already set.
3112  * @param style the theme style to use (default, transparent, ...)
3113  *
3114  * @ingroup Widget
3115  */
3116 EAPI void
3117 _elm_widget_item_cursor_style_set(Elm_Widget_Item *item,
3118                                   const char      *style)
3119 {
3120    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3121    elm_object_cursor_style_set(item->view, style);
3122 }
3123
3124 /**
3125  * @internal
3126  *
3127  * Get the style for this item cursor.
3128  *
3129  * @param item widget item with cursor already set.
3130  * @return style the theme style in use, defaults to "default". If the
3131  *         object does not have a cursor set, then NULL is returned.
3132  *
3133  * @ingroup Widget
3134  */
3135 EAPI const char *
3136 _elm_widget_item_cursor_style_get(const Elm_Widget_Item *item)
3137 {
3138    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3139    return elm_object_cursor_style_get(item->view);
3140 }
3141
3142 /**
3143  * @internal
3144  *
3145  * Set if the cursor set should be searched on the theme or should use
3146  * the provided by the engine, only.
3147  *
3148  * @note before you set if should look on theme you should define a cursor
3149  * with elm_object_cursor_set(). By default it will only look for cursors
3150  * provided by the engine.
3151  *
3152  * @param item widget item with cursor already set.
3153  * @param engine_only boolean to define it cursors should be looked only
3154  * between the provided by the engine or searched on widget's theme as well.
3155  *
3156  * @ingroup Widget
3157  */
3158 EAPI void
3159 _elm_widget_item_cursor_engine_only_set(Elm_Widget_Item *item,
3160                                         Eina_Bool        engine_only)
3161 {
3162    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3163    elm_object_cursor_engine_only_set(item->view, engine_only);
3164 }
3165
3166 /**
3167  * @internal
3168  *
3169  * Get the cursor engine only usage for this item cursor.
3170  *
3171  * @param item widget item with cursor already set.
3172  * @return engine_only boolean to define it cursors should be looked only
3173  * between the provided by the engine or searched on widget's theme as well. If
3174  *         the object does not have a cursor set, then EINA_FALSE is returned.
3175  *
3176  * @ingroup Widget
3177  */
3178 EAPI Eina_Bool
3179 _elm_widget_item_cursor_engine_only_get(const Elm_Widget_Item *item)
3180 {
3181    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3182    return elm_object_cursor_engine_only_get(item->view);
3183 }
3184
3185 // smart object funcs
3186 static void
3187 _smart_reconfigure(Smart_Data *sd)
3188 {
3189    if (sd->resize_obj)
3190      {
3191         evas_object_move(sd->resize_obj, sd->x, sd->y);
3192         evas_object_resize(sd->resize_obj, sd->w, sd->h);
3193      }
3194    if (sd->hover_obj)
3195      {
3196         evas_object_move(sd->hover_obj, sd->x, sd->y);
3197         evas_object_resize(sd->hover_obj, sd->w, sd->h);
3198      }
3199 }
3200
3201 EAPI void
3202 _elm_widget_item_content_part_set(Elm_Widget_Item *item,
3203                                  const char *part,
3204                                  Evas_Object *content)
3205 {
3206    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3207    if (!item->on_content_set_func) return;
3208    item->on_content_set_func((Elm_Object_Item *) item, part, content);
3209 }
3210
3211 EAPI Evas_Object *
3212 _elm_widget_item_content_part_get(const Elm_Widget_Item *item,
3213                                   const char *part)
3214 {
3215    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3216    if (!item->on_content_get_func) return NULL;
3217    return item->on_content_get_func((Elm_Object_Item *) item, part);
3218 }
3219
3220 EAPI Evas_Object *
3221 _elm_widget_item_content_part_unset(Elm_Widget_Item *item,
3222                                     const char *part)
3223 {
3224    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3225    if (!item->on_content_unset_func) return NULL;
3226    return item->on_content_unset_func((Elm_Object_Item *) item, part);
3227 }
3228
3229 EAPI void
3230 _elm_widget_item_text_part_set(Elm_Widget_Item *item,
3231                               const char *part,
3232                               const char *label)
3233 {
3234    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3235    if (!item->on_text_set_func) return;
3236    item->on_text_set_func((Elm_Object_Item *) item, part, label);
3237 }
3238
3239 EAPI void
3240 _elm_widget_item_signal_emit(Elm_Widget_Item *item,
3241                              const char *emission,
3242                              const char *source)
3243 {
3244    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3245    if (item->on_signal_emit_func)
3246      item->on_signal_emit_func((Elm_Object_Item *) item, emission, source);
3247 }
3248
3249 EAPI const char *
3250 _elm_widget_item_text_part_get(const Elm_Widget_Item *item,
3251                                const char *part)
3252 {
3253    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3254    if (!item->on_text_get_func) return NULL;
3255    return item->on_text_get_func((Elm_Object_Item *) item, part);
3256 }
3257
3258 EAPI void
3259 _elm_widget_item_content_set_hook_set(Elm_Widget_Item *item,
3260                                       Elm_Widget_On_Content_Set_Cb func)
3261 {
3262    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3263    item->on_content_set_func = func;
3264 }
3265
3266 EAPI void
3267 _elm_widget_item_content_get_hook_set(Elm_Widget_Item *item,
3268                                       Elm_Widget_On_Content_Get_Cb func)
3269 {
3270    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3271    item->on_content_get_func = func;
3272 }
3273
3274 EAPI void
3275 _elm_widget_item_content_unset_hook_set(Elm_Widget_Item *item,
3276                                         Elm_Widget_On_Content_Unset_Cb func)
3277 {
3278    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3279    item->on_content_unset_func = func;
3280 }
3281
3282 EAPI void
3283 _elm_widget_item_text_set_hook_set(Elm_Widget_Item *item,
3284                                    Elm_Widget_On_Text_Set_Cb func)
3285 {
3286    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3287    item->on_text_set_func = func;
3288 }
3289
3290 EAPI void
3291 _elm_widget_item_text_get_hook_set(Elm_Widget_Item *item,
3292                                    Elm_Widget_On_Text_Get_Cb func)
3293 {
3294    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3295    item->on_text_get_func = func;
3296 }
3297
3298 EAPI void
3299 _elm_widget_item_signal_emit_hook_set(Elm_Widget_Item *item,
3300                                       Elm_Widget_On_Signal_Emit_Cb func)
3301 {
3302    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3303    item->on_signal_emit_func = func;
3304 }
3305
3306 EAPI void
3307 _elm_widget_item_access_info_set(Elm_Widget_Item *item, const char *txt)
3308 {
3309    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3310    if (item->access_info) eina_stringshare_del(item->access_info);
3311    if (!txt) item->access_info = NULL;
3312    else item->access_info = eina_stringshare_add(txt);
3313 }
3314
3315
3316 static void
3317 _smart_add(Evas_Object *obj)
3318 {
3319    Smart_Data *sd;
3320
3321    sd = calloc(1, sizeof(Smart_Data));
3322    if (!sd) return;
3323    sd->obj = obj;
3324    sd->x = sd->y = sd->w = sd->h = 0;
3325    sd->can_focus = 1;
3326    sd->mirrored_auto_mode = EINA_TRUE; /* will follow system locale settings */
3327    evas_object_smart_data_set(obj, sd);
3328 }
3329
3330 static Evas_Object *
3331 _newest_focus_order_get(Evas_Object  *obj,
3332                         unsigned int *newest_focus_order,
3333                         Eina_Bool     can_focus_only)
3334 {
3335    const Eina_List *l;
3336    Evas_Object *child, *ret, *best;
3337
3338    API_ENTRY return NULL;
3339
3340    if (!evas_object_visible_get(obj)
3341        || (elm_widget_disabled_get(obj))
3342        || (elm_widget_tree_unfocusable_get(obj)))
3343      return NULL;
3344
3345    best = NULL;
3346    if (*newest_focus_order < sd->focus_order)
3347      {
3348         *newest_focus_order = sd->focus_order;
3349         best = obj;
3350      }
3351    EINA_LIST_FOREACH(sd->subobjs, l, child)
3352      {
3353         ret = _newest_focus_order_get(child, newest_focus_order, can_focus_only);
3354         if (!ret) continue;
3355         best = ret;
3356      }
3357    if (can_focus_only)
3358      {
3359         if ((!best) || (!elm_widget_can_focus_get(best)))
3360           return NULL;
3361      }
3362    return best;
3363 }
3364
3365 static void
3366 _if_focused_revert(Evas_Object *obj,
3367                    Eina_Bool    can_focus_only)
3368 {
3369    Evas_Object *top;
3370    Evas_Object *newest = NULL;
3371    unsigned int newest_focus_order = 0;
3372
3373    INTERNAL_ENTRY
3374
3375    if (!sd->focused) return;
3376    if (!sd->parent_obj) return;
3377
3378    top = elm_widget_top_get(sd->parent_obj);
3379    if (top)
3380      {
3381         newest = _newest_focus_order_get(top, &newest_focus_order, can_focus_only);
3382         if (newest)
3383           {
3384              elm_object_focus_set(newest, EINA_FALSE);
3385              elm_object_focus_set(newest, EINA_TRUE);
3386           }
3387      }
3388 }
3389
3390 static void
3391 _smart_del(Evas_Object *obj)
3392 {
3393    Evas_Object *sobj;
3394    Edje_Signal_Data *esd;
3395    Elm_Translate_String_Data *ts;
3396
3397    INTERNAL_ENTRY
3398
3399    if (sd->del_pre_func) sd->del_pre_func(obj);
3400    if (sd->resize_obj)
3401      {
3402         sobj = sd->resize_obj;
3403         sd->resize_obj = NULL;
3404         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3405         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3406         evas_object_del(sobj);
3407         sd->resize_obj = NULL;
3408      }
3409    if (sd->hover_obj)
3410      {
3411         sobj = sd->hover_obj;
3412         sd->hover_obj = NULL;
3413         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3414         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3415         evas_object_del(sobj);
3416         sd->hover_obj = NULL;
3417      }
3418    EINA_LIST_FREE(sd->subobjs, sobj)
3419      {
3420         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3421         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3422         evas_object_del(sobj);
3423      }
3424    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
3425    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
3426    EINA_LIST_FREE(sd->edje_signals, esd)
3427      {
3428         eina_stringshare_del(esd->emission);
3429         eina_stringshare_del(esd->source);
3430         free(esd);
3431      }
3432    EINA_LIST_FREE(sd->translate_strings, ts)
3433      {
3434         eina_stringshare_del(ts->id);
3435         eina_stringshare_del(ts->domain);
3436         eina_stringshare_del(ts->string);
3437         free(ts);
3438      }
3439    sd->event_cb = eina_list_free(sd->event_cb); /* should be empty anyway */
3440    if (sd->del_func) sd->del_func(obj);
3441    if (sd->style) eina_stringshare_del(sd->style);
3442    if (sd->type) eina_stringshare_del(sd->type);
3443    if (sd->theme) elm_theme_free(sd->theme);
3444    sd->data = NULL;
3445    _if_focused_revert(obj, EINA_TRUE);
3446    if (sd->access_info) eina_stringshare_del(sd->access_info);
3447    free(sd);
3448    evas_object_smart_data_set(obj, NULL);
3449 }
3450
3451 static void
3452 _smart_move(Evas_Object *obj,
3453             Evas_Coord   x,
3454             Evas_Coord   y)
3455 {
3456    INTERNAL_ENTRY
3457    sd->x = x;
3458    sd->y = y;
3459    _smart_reconfigure(sd);
3460 }
3461
3462 static void
3463 _smart_resize(Evas_Object *obj,
3464               Evas_Coord   w,
3465               Evas_Coord   h)
3466 {
3467    INTERNAL_ENTRY
3468    sd->w = w;
3469    sd->h = h;
3470    _smart_reconfigure(sd);
3471 }
3472
3473 static void
3474 _smart_show(Evas_Object *obj)
3475 {
3476    Eina_List *list;
3477    Evas_Object *o;
3478    INTERNAL_ENTRY
3479    if ((list = evas_object_smart_members_get(obj)))
3480      {
3481         EINA_LIST_FREE(list, o)
3482           {
3483              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3484              evas_object_show(o);
3485           }
3486      }
3487 }
3488
3489 static void
3490 _smart_hide(Evas_Object *obj)
3491 {
3492    Eina_List *list;
3493    Evas_Object *o;
3494    INTERNAL_ENTRY
3495
3496    list = evas_object_smart_members_get(obj);
3497    EINA_LIST_FREE(list, o)
3498      {
3499         if (evas_object_data_get(o, "_elm_leaveme")) continue;
3500         evas_object_hide(o);
3501      }
3502 }
3503
3504 static void
3505 _smart_color_set(Evas_Object *obj,
3506                  int          r,
3507                  int          g,
3508                  int          b,
3509                  int          a)
3510 {
3511    Eina_List *list;
3512    Evas_Object *o;
3513    INTERNAL_ENTRY
3514    if ((list = evas_object_smart_members_get(obj)))
3515      {
3516         EINA_LIST_FREE(list, o)
3517           {
3518              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3519              evas_object_color_set(o, r, g, b, a);
3520           }
3521      }
3522 }
3523
3524 static void
3525 _smart_clip_set(Evas_Object *obj,
3526                 Evas_Object *clip)
3527 {
3528    Eina_List *list;
3529    Evas_Object *o;
3530    INTERNAL_ENTRY
3531    if ((list = evas_object_smart_members_get(obj)))
3532      {
3533         EINA_LIST_FREE(list, o)
3534           {
3535              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3536              evas_object_clip_set(o, clip);
3537           }
3538      }
3539 }
3540
3541 static void
3542 _smart_clip_unset(Evas_Object *obj)
3543 {
3544    Eina_List *list;
3545    Evas_Object *o;
3546    INTERNAL_ENTRY
3547    if ((list = evas_object_smart_members_get(obj)))
3548      {
3549         EINA_LIST_FREE(list, o)
3550           {
3551              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3552              evas_object_clip_unset(o);
3553           }
3554      }
3555 }
3556
3557 static void
3558 _smart_calculate(Evas_Object *obj)
3559 {
3560    INTERNAL_ENTRY
3561    if (sd->changed_func) sd->changed_func(obj);
3562 }
3563
3564 /* never need to touch this */
3565 static void
3566 _smart_init(void)
3567 {
3568    if (_e_smart) return;
3569      {
3570         static const Evas_Smart_Class sc =
3571           {
3572              SMART_NAME,
3573              EVAS_SMART_CLASS_VERSION,
3574              _smart_add,
3575              _smart_del,
3576              _smart_move,
3577              _smart_resize,
3578              _smart_show,
3579              _smart_hide,
3580              _smart_color_set,
3581              _smart_clip_set,
3582              _smart_clip_unset,
3583              _smart_calculate,
3584              NULL,
3585              NULL,
3586              NULL,
3587              NULL,
3588              NULL,
3589              NULL
3590           };
3591         _e_smart = evas_smart_class_new(&sc);
3592      }
3593 }
3594
3595 /* happy debug functions */
3596 #ifdef ELM_DEBUG
3597 static void
3598 _sub_obj_tree_dump(const Evas_Object *obj,
3599                    int                lvl)
3600 {
3601    int i;
3602
3603    for (i = 0; i < lvl * 3; i++)
3604      putchar(' ');
3605
3606    if (_elm_widget_is(obj))
3607      {
3608         Eina_List *l;
3609         INTERNAL_ENTRY
3610         printf("+ %s(%p)\n",
3611                sd->type,
3612                obj);
3613         if (sd->resize_obj)
3614           _sub_obj_tree_dump(sd->resize_obj, lvl + 1);
3615         EINA_LIST_FOREACH(sd->subobjs, l, obj)
3616           {
3617              if (obj != sd->resize_obj)
3618                _sub_obj_tree_dump(obj, lvl + 1);
3619           }
3620      }
3621    else
3622      printf("+ %s(%p)\n", evas_object_type_get(obj), obj);
3623 }
3624
3625 static void
3626 _sub_obj_tree_dot_dump(const Evas_Object *obj,
3627                        FILE              *output)
3628 {
3629    if (!_elm_widget_is(obj))
3630      return;
3631    INTERNAL_ENTRY
3632
3633    Eina_Bool visible = evas_object_visible_get(obj);
3634    Eina_Bool disabled = elm_widget_disabled_get(obj);
3635    Eina_Bool focused = elm_widget_focus_get(obj);
3636    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
3637
3638    if (sd->parent_obj)
3639      {
3640         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
3641
3642         if (focused)
3643           fprintf(output, ", style=bold");
3644
3645         if (!visible)
3646           fprintf(output, ", color=gray28");
3647
3648         fprintf(output, " ];\n");
3649      }
3650
3651    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
3652                    "disabled: %d|focused: %d/%d|focus order:%d}\"", obj, obj, sd->type,
3653            evas_object_name_get(obj), visible, disabled, focused, can_focus,
3654            sd->focus_order);
3655
3656    if (focused)
3657      fprintf(output, ", style=bold");
3658
3659    if (!visible)
3660      fprintf(output, ", fontcolor=gray28");
3661
3662    if ((disabled) || (!visible))
3663      fprintf(output, ", color=gray");
3664
3665    fprintf(output, " ];\n");
3666
3667    Eina_List *l;
3668    Evas_Object *o;
3669    EINA_LIST_FOREACH(sd->subobjs, l, o)
3670      _sub_obj_tree_dot_dump(o, output);
3671 }
3672 #endif
3673
3674 EAPI void
3675 elm_widget_tree_dump(const Evas_Object *top)
3676 {
3677 #ifdef ELM_DEBUG
3678    _sub_obj_tree_dump(top, 0);
3679 #else
3680    return;
3681    (void)top;
3682 #endif
3683 }
3684
3685 EAPI void
3686 elm_widget_tree_dot_dump(const Evas_Object *top,
3687                          FILE              *output)
3688 {
3689 #ifdef ELM_DEBUG
3690    if (!_elm_widget_is(top))
3691      return;
3692    fprintf(output, "graph " " { node [shape=record];\n");
3693    _sub_obj_tree_dot_dump(top, output);
3694    fprintf(output, "}\n");
3695 #else
3696    return;
3697    (void)top;
3698    (void)output;
3699 #endif
3700 }