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