and now add custom access info for items too and clean up nicely.
[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         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
986         if (sd2)
987           {
988              sd2->parent_obj = NULL;
989              if (sd2->resize_obj == sobj)
990                sd2->resize_obj = NULL;
991              else
992                sd->subobjs = eina_list_remove(sd->subobjs, sobj);
993           }
994         else
995           sd->subobjs = eina_list_remove(sd->subobjs, sobj);
996         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
997         if ((sd->child_can_focus) && (_is_focusable(sobj)))
998           {
999              Evas_Object *subobj;
1000              const Eina_List *l;
1001              sd->child_can_focus = EINA_FALSE;
1002              EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1003                {
1004                   if (_is_focusable(subobj))
1005                     {
1006                        sd->child_can_focus = EINA_TRUE;
1007                        break;
1008                     }
1009                }
1010           }
1011      }
1012    else
1013      sd->subobjs = eina_list_remove(sd->subobjs, sobj);
1014    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
1015                                        _sub_obj_del, sd);
1016    if (_elm_widget_is(sobj))
1017      evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
1018                                          _sub_obj_hide, sd);
1019    evas_object_smart_callback_call(obj, "sub-object-del", sobj);
1020 }
1021
1022 EAPI void
1023 elm_widget_resize_object_set(Evas_Object *obj,
1024                              Evas_Object *sobj)
1025 {
1026    API_ENTRY return;
1027    // orphan previous resize obj
1028    if (sd->resize_obj)
1029      {
1030         evas_object_clip_unset(sd->resize_obj);
1031         evas_object_data_del(sd->resize_obj, "elm-parent");
1032         if (_elm_widget_is(sd->resize_obj))
1033           {
1034              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
1035              if (sd2) sd2->parent_obj = NULL;
1036              evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_HIDE,
1037                                                  _sub_obj_hide, sd);
1038           }
1039         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_DEL,
1040                                             _sub_obj_del, sd);
1041         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_DOWN,
1042                                             _sub_obj_mouse_down, sd);
1043         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_MOVE,
1044                                             _sub_obj_mouse_move, sd);
1045         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_UP,
1046                                             _sub_obj_mouse_up, sd);
1047         evas_object_smart_member_del(sd->resize_obj);
1048         if (_elm_widget_is(sd->resize_obj))
1049           {
1050              if (elm_widget_focus_get(sd->resize_obj)) _unfocus_parents(obj);
1051           }
1052      }
1053    // orphan new resize obj
1054    if (sobj)
1055      {
1056         evas_object_data_del(sobj, "elm-parent");
1057         if (_elm_widget_is(sobj))
1058           {
1059              Smart_Data *sd2 = evas_object_smart_data_get(sobj);
1060              if (sd2) sd2->parent_obj = NULL;
1061              evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
1062                                                  _sub_obj_hide, sd);
1063           }
1064         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
1065                                             _sub_obj_del, sd);
1066         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_DOWN,
1067                                             _sub_obj_mouse_down, sd);
1068         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_MOVE,
1069                                             _sub_obj_mouse_move, sd);
1070         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_UP,
1071                                             _sub_obj_mouse_up, sd);
1072         evas_object_smart_member_del(sobj);
1073         if (_elm_widget_is(sobj))
1074           {
1075              if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
1076           }
1077      }
1078    // set the resize obj up
1079    sd->resize_obj = sobj;
1080    if (sd->resize_obj)
1081      {
1082         if (_elm_widget_is(sd->resize_obj))
1083           {
1084              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
1085              if (sd2)
1086                {
1087                   sd2->parent_obj = obj;
1088                   sd2->top_win_focused = sd->top_win_focused;
1089                }
1090              evas_object_event_callback_add(sobj, EVAS_CALLBACK_HIDE,
1091                                             _sub_obj_hide, sd);
1092           }
1093         evas_object_clip_set(sobj, evas_object_clip_get(obj));
1094         evas_object_smart_member_add(sobj, obj);
1095         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1096                                        _sub_obj_del, sd);
1097         evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_DOWN,
1098                                        _sub_obj_mouse_down, sd);
1099         evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_MOVE,
1100                                        _sub_obj_mouse_move, sd);
1101         evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_UP,
1102                                        _sub_obj_mouse_up, sd);
1103         _smart_reconfigure(sd);
1104         evas_object_data_set(sobj, "elm-parent", obj);
1105         evas_object_smart_callback_call(obj, "sub-object-add", sobj);
1106         if (_elm_widget_is(sobj))
1107           {
1108              if (elm_widget_focus_get(sobj)) _focus_parents(obj);
1109           }
1110      }
1111 }
1112
1113 EAPI void
1114 elm_widget_hover_object_set(Evas_Object *obj,
1115                             Evas_Object *sobj)
1116 {
1117    API_ENTRY return;
1118    if (sd->hover_obj)
1119      {
1120         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
1121                                             _sub_obj_del, sd);
1122      }
1123    sd->hover_obj = sobj;
1124    if (sd->hover_obj)
1125      {
1126         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1127                                        _sub_obj_del, sd);
1128         _smart_reconfigure(sd);
1129      }
1130 }
1131
1132 EAPI void
1133 elm_widget_can_focus_set(Evas_Object *obj,
1134                          Eina_Bool    can_focus)
1135 {
1136    API_ENTRY return;
1137    sd->can_focus = can_focus;
1138    if (can_focus)
1139      {
1140         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1141                                        _propagate_event,
1142                                        (void *)(long)EVAS_CALLBACK_KEY_DOWN);
1143         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
1144                                        _propagate_event,
1145                                        (void *)(long)EVAS_CALLBACK_KEY_UP);
1146         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1147                                        _propagate_event,
1148                                        (void *)(long)EVAS_CALLBACK_MOUSE_WHEEL);
1149      }
1150    else
1151      {
1152         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
1153                                        _propagate_event);
1154         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
1155                                        _propagate_event);
1156         evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1157                                        _propagate_event);
1158      }
1159 }
1160
1161 EAPI Eina_Bool
1162 elm_widget_can_focus_get(const Evas_Object *obj)
1163 {
1164    API_ENTRY return EINA_FALSE;
1165    return sd->can_focus;
1166 }
1167
1168 EAPI Eina_Bool
1169 elm_widget_child_can_focus_get(const Evas_Object *obj)
1170 {
1171    API_ENTRY return EINA_FALSE;
1172    return sd->child_can_focus;
1173 }
1174
1175 /**
1176  * @internal
1177  *
1178  * This API makes the widget object and its children to be unfocusable.
1179  *
1180  * This API can be helpful for an object to be deleted.
1181  * When an object will be deleted soon, it and its children may not
1182  * want to get focus (by focus reverting or by other focus controls).
1183  * Then, just use this API before deleting.
1184  *
1185  * @param obj The widget root of sub-tree
1186  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1187  *
1188  * @ingroup Widget
1189  */
1190 EAPI void
1191 elm_widget_tree_unfocusable_set(Evas_Object *obj,
1192                                 Eina_Bool    tree_unfocusable)
1193 {
1194    API_ENTRY return;
1195
1196    if (sd->tree_unfocusable == tree_unfocusable) return;
1197    sd->tree_unfocusable = !!tree_unfocusable;
1198    elm_widget_focus_tree_unfocusable_handle(obj);
1199 }
1200
1201 /**
1202  * @internal
1203  *
1204  * This returns true, if the object sub-tree is unfocusable.
1205  *
1206  * @param obj The widget root of sub-tree
1207  * @return EINA_TRUE if the object sub-tree is unfocusable
1208  *
1209  * @ingroup Widget
1210  */
1211 EAPI Eina_Bool
1212 elm_widget_tree_unfocusable_get(const Evas_Object *obj)
1213 {
1214    API_ENTRY return EINA_FALSE;
1215    return sd->tree_unfocusable;
1216 }
1217
1218 EAPI void
1219 elm_widget_highlight_ignore_set(Evas_Object *obj,
1220                                 Eina_Bool    ignore)
1221 {
1222    API_ENTRY return;
1223    sd->highlight_ignore = !!ignore;
1224 }
1225
1226 EAPI Eina_Bool
1227 elm_widget_highlight_ignore_get(const Evas_Object *obj)
1228 {
1229    API_ENTRY return EINA_FALSE;
1230    return sd->highlight_ignore;
1231 }
1232
1233 EAPI void
1234 elm_widget_highlight_in_theme_set(Evas_Object *obj,
1235                                   Eina_Bool    highlight)
1236 {
1237    API_ENTRY return;
1238    sd->highlight_in_theme = !!highlight;
1239    /* FIXME: if focused, it should switch from one mode to the other */
1240 }
1241
1242 EAPI Eina_Bool
1243 elm_widget_highlight_in_theme_get(const Evas_Object *obj)
1244 {
1245    API_ENTRY return EINA_FALSE;
1246    return sd->highlight_in_theme;
1247 }
1248
1249 EAPI Eina_Bool
1250 elm_widget_focus_get(const Evas_Object *obj)
1251 {
1252    API_ENTRY return EINA_FALSE;
1253    return sd->focused;
1254 }
1255
1256 EAPI Evas_Object *
1257 elm_widget_focused_object_get(const Evas_Object *obj)
1258 {
1259    const Evas_Object *subobj;
1260    const Eina_List *l;
1261    API_ENTRY return NULL;
1262
1263    if (!sd->focused) return NULL;
1264    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1265      {
1266         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
1267         if (fobj) return fobj;
1268      }
1269    return (Evas_Object *)obj;
1270 }
1271
1272 EAPI Evas_Object *
1273 elm_widget_top_get(const Evas_Object *obj)
1274 {
1275    API_ENTRY return NULL;
1276    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
1277    return (Evas_Object *)obj;
1278 }
1279
1280 EAPI Eina_Bool
1281 elm_widget_is(const Evas_Object *obj)
1282 {
1283    return _elm_widget_is(obj);
1284 }
1285
1286 EAPI Evas_Object *
1287 elm_widget_parent_widget_get(const Evas_Object *obj)
1288 {
1289    Evas_Object *parent;
1290
1291    if (_elm_widget_is(obj))
1292      {
1293         Smart_Data *sd = evas_object_smart_data_get(obj);
1294         if (!sd) return NULL;
1295         parent = sd->parent_obj;
1296      }
1297    else
1298      {
1299         parent = evas_object_data_get(obj, "elm-parent");
1300         if (!parent) parent = evas_object_smart_parent_get(obj);
1301      }
1302
1303    while (parent)
1304      {
1305         Evas_Object *elm_parent;
1306         if (_elm_widget_is(parent)) break;
1307         elm_parent = evas_object_data_get(parent, "elm-parent");
1308         if (elm_parent) parent = elm_parent;
1309         else parent = evas_object_smart_parent_get(parent);
1310      }
1311    return parent;
1312 }
1313
1314 EAPI void
1315 elm_widget_event_callback_add(Evas_Object *obj,
1316                               Elm_Event_Cb func,
1317                               const void  *data)
1318 {
1319    API_ENTRY return;
1320    EINA_SAFETY_ON_NULL_RETURN(func);
1321    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1322    ecb->func = func;
1323    ecb->data = data;
1324    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1325 }
1326
1327 EAPI void *
1328 elm_widget_event_callback_del(Evas_Object *obj,
1329                               Elm_Event_Cb func,
1330                               const void  *data)
1331 {
1332    API_ENTRY return NULL;
1333    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1334    Eina_List *l;
1335    Elm_Event_Cb_Data *ecd;
1336    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1337      if ((ecd->func == func) && (ecd->data == data))
1338        {
1339           free(ecd);
1340           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1341           return (void *)data;
1342        }
1343    return NULL;
1344 }
1345
1346 EAPI Eina_Bool
1347 elm_widget_event_propagate(Evas_Object       *obj,
1348                            Evas_Callback_Type type,
1349                            void              *event_info,
1350                            Evas_Event_Flags  *event_flags)
1351 {
1352    API_ENTRY return EINA_FALSE; //TODO reduce.
1353    if (!_elm_widget_is(obj)) return EINA_FALSE;
1354    Evas_Object *parent = obj;
1355    Elm_Event_Cb_Data *ecd;
1356    Eina_List *l, *l_prev;
1357
1358    while (parent &&
1359           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1360      {
1361         sd = evas_object_smart_data_get(parent);
1362         if ((!sd) || (!_elm_widget_is(obj)))
1363           return EINA_FALSE; //Not Elm Widget
1364
1365         if (sd->event_func && (sd->event_func(parent, obj, type, event_info)))
1366           return EINA_TRUE;
1367
1368         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1369           {
1370              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1371                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1372                return EINA_TRUE;
1373           }
1374         parent = sd->parent_obj;
1375      }
1376
1377    return EINA_FALSE;
1378 }
1379
1380 /**
1381  * @internal
1382  *
1383  * Set custom focus chain.
1384  *
1385  * This function i set one new and overwrite any previous custom focus chain
1386  * with the list of objects. The previous list will be deleted and this list
1387  * will be managed. After setted, don't modity it.
1388  *
1389  * @note On focus cycle, only will be evaluated children of this container.
1390  *
1391  * @param obj The container widget
1392  * @param objs Chain of objects to pass focus
1393  * @ingroup Widget
1394  */
1395 EAPI void
1396 elm_widget_focus_custom_chain_set(Evas_Object *obj,
1397                                   Eina_List   *objs)
1398 {
1399    API_ENTRY return;
1400    if (!sd->focus_next_func)
1401      return;
1402
1403    elm_widget_focus_custom_chain_unset(obj);
1404
1405    Eina_List *l;
1406    Evas_Object *o;
1407
1408    EINA_LIST_FOREACH(objs, l, o)
1409      {
1410         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1411                                        _elm_object_focus_chain_del_cb, sd);
1412      }
1413
1414    sd->focus_chain = objs;
1415 }
1416
1417 /**
1418  * @internal
1419  *
1420  * Get custom focus chain
1421  *
1422  * @param obj The container widget
1423  * @ingroup Widget
1424  */
1425 EAPI const Eina_List *
1426 elm_widget_focus_custom_chain_get(const Evas_Object *obj)
1427 {
1428    API_ENTRY return NULL;
1429    return (const Eina_List *)sd->focus_chain;
1430 }
1431
1432 /**
1433  * @internal
1434  *
1435  * Unset custom focus chain
1436  *
1437  * @param obj The container widget
1438  * @ingroup Widget
1439  */
1440 EAPI void
1441 elm_widget_focus_custom_chain_unset(Evas_Object *obj)
1442 {
1443    API_ENTRY return;
1444    Eina_List *l, *l_next;
1445    Evas_Object *o;
1446
1447    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1448      {
1449         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1450                                             _elm_object_focus_chain_del_cb, sd);
1451         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1452      }
1453 }
1454
1455 /**
1456  * @internal
1457  *
1458  * Append object to custom focus chain.
1459  *
1460  * @note If relative_child equal to NULL or not in custom chain, the object
1461  * will be added in end.
1462  *
1463  * @note On focus cycle, only will be evaluated children of this container.
1464  *
1465  * @param obj The container widget
1466  * @param child The child to be added in custom chain
1467  * @param relative_child The relative object to position the child
1468  * @ingroup Widget
1469  */
1470 EAPI void
1471 elm_widget_focus_custom_chain_append(Evas_Object *obj,
1472                                      Evas_Object *child,
1473                                      Evas_Object *relative_child)
1474 {
1475    API_ENTRY return;
1476    EINA_SAFETY_ON_NULL_RETURN(child);
1477    if (!sd->focus_next_func)
1478      return;
1479
1480    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1481                                        _elm_object_focus_chain_del_cb, sd);
1482
1483    if (!relative_child)
1484      {
1485         sd->focus_chain = eina_list_append(sd->focus_chain, child);
1486         return;
1487      }
1488
1489    sd->focus_chain = eina_list_append_relative(sd->focus_chain, child, relative_child);
1490    return;
1491 }
1492
1493 /**
1494  * @internal
1495  *
1496  * Prepend object to custom focus chain.
1497  *
1498  * @note If relative_child equal to NULL or not in custom chain, the object
1499  * will be added in begin.
1500  *
1501  * @note On focus cycle, only will be evaluated children of this container.
1502  *
1503  * @param obj The container widget
1504  * @param child The child to be added in custom chain
1505  * @param relative_child The relative object to position the child
1506  * @ingroup Widget
1507  */
1508 EAPI void
1509 elm_widget_focus_custom_chain_prepend(Evas_Object *obj,
1510                                       Evas_Object *child,
1511                                       Evas_Object *relative_child)
1512 {
1513    API_ENTRY return;
1514    EINA_SAFETY_ON_NULL_RETURN(child);
1515    if (!sd->focus_next_func)
1516      return;
1517
1518    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1519                                        _elm_object_focus_chain_del_cb, sd);
1520
1521    if (!relative_child)
1522      {
1523         sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1524         return;
1525      }
1526
1527    sd->focus_chain = eina_list_prepend_relative(sd->focus_chain, child, relative_child);
1528    return;
1529 }
1530
1531 /**
1532  * @internal
1533  *
1534  * Give focus to next object in object tree.
1535  *
1536  * Give focus to next object in focus chain of one object sub-tree.
1537  * If the last object of chain already have focus, the focus will go to the
1538  * first object of chain.
1539  *
1540  * @param obj The widget root of sub-tree
1541  * @param dir Direction to cycle the focus
1542  *
1543  * @ingroup Widget
1544  */
1545 EAPI void
1546 elm_widget_focus_cycle(Evas_Object        *obj,
1547                        Elm_Focus_Direction dir)
1548 {
1549    Evas_Object *target = NULL;
1550    if (!_elm_widget_is(obj))
1551      return;
1552    elm_widget_focus_next_get(obj, dir, &target);
1553    if (target)
1554      elm_widget_focus_steal(target);
1555 }
1556
1557 /**
1558  * @internal
1559  *
1560  * Give focus to near object in one direction.
1561  *
1562  * Give focus to near object in direction of one object.
1563  * If none focusable object in given direction, the focus will not change.
1564  *
1565  * @param obj The reference widget
1566  * @param x Horizontal component of direction to focus
1567  * @param y Vertical component of direction to focus
1568  *
1569  * @ingroup Widget
1570  */
1571 EAPI void
1572 elm_widget_focus_direction_go(Evas_Object *obj __UNUSED__,
1573                               int          x __UNUSED__,
1574                               int          y __UNUSED__)
1575 {
1576    return; /* TODO */
1577 }
1578
1579 /**
1580  * @internal
1581  *
1582  * Get next object in focus chain of object tree.
1583  *
1584  * Get next object in focus chain of one object sub-tree.
1585  * Return the next object by reference. If don't have any candidate to receive
1586  * focus before chain end, the first candidate will be returned.
1587  *
1588  * @param obj The widget root of sub-tree
1589  * @param dir Direction os focus chain
1590  * @param next The next object in focus chain
1591  * @return EINA_TRUE if don't need focus chain restart/loop back
1592  *         to use 'next' obj.
1593  *
1594  * @ingroup Widget
1595  */
1596 EAPI Eina_Bool
1597 elm_widget_focus_next_get(const Evas_Object  *obj,
1598                           Elm_Focus_Direction dir,
1599                           Evas_Object       **next)
1600 {
1601    if (!next)
1602      return EINA_FALSE;
1603    *next = NULL;
1604
1605    API_ENTRY return EINA_FALSE;
1606
1607    /* Ignore if disabled */
1608    if ((!evas_object_visible_get(obj))
1609        || (elm_widget_disabled_get(obj))
1610        || (elm_widget_tree_unfocusable_get(obj)))
1611      return EINA_FALSE;
1612
1613    /* Try use hook */
1614    if (sd->focus_next_func)
1615      return sd->focus_next_func(obj, dir, next);
1616
1617    if (!elm_widget_can_focus_get(obj))
1618      return EINA_FALSE;
1619
1620    /* Return */
1621    *next = (Evas_Object *)obj;
1622    return !elm_widget_focus_get(obj);
1623 }
1624
1625 /**
1626  * @internal
1627  *
1628  * Get next object in focus chain of object tree in list.
1629  *
1630  * Get next object in focus chain of one object sub-tree ordered by one list.
1631  * Return the next object by reference. If don't have any candidate to receive
1632  * focus before list end, the first candidate will be returned.
1633  *
1634  * @param obj The widget root of sub-tree
1635  * @param dir Direction os focus chain
1636  * @param items list with ordered objects
1637  * @param list_data_get function to get the object from one item of list
1638  * @param next The next object in focus chain
1639  * @return EINA_TRUE if don't need focus chain restart/loop back
1640  *         to use 'next' obj.
1641  *
1642  * @ingroup Widget
1643  */
1644 EAPI Eina_Bool
1645 elm_widget_focus_list_next_get(const Evas_Object  *obj,
1646                                const Eina_List    *items,
1647                                void *(*list_data_get)(const Eina_List * list),
1648                                Elm_Focus_Direction dir,
1649                                Evas_Object       **next)
1650 {
1651    Eina_List *(*list_next)(const Eina_List * list);
1652
1653    if (!next)
1654      return EINA_FALSE;
1655    *next = NULL;
1656
1657    if (!_elm_widget_is(obj))
1658      return EINA_FALSE;
1659
1660    if (!items)
1661      return EINA_FALSE;
1662
1663    /* Direction */
1664    if (dir == ELM_FOCUS_PREVIOUS)
1665      {
1666         items = eina_list_last(items);
1667         list_next = eina_list_prev;
1668      }
1669    else if (dir == ELM_FOCUS_NEXT)
1670      list_next = eina_list_next;
1671    else
1672      return EINA_FALSE;
1673
1674    const Eina_List *l = items;
1675
1676    /* Recovery last focused sub item */
1677    if (elm_widget_focus_get(obj))
1678      for (; l; l = list_next(l))
1679        {
1680           Evas_Object *cur = list_data_get(l);
1681           if (elm_widget_focus_get(cur)) break;
1682        }
1683
1684    const Eina_List *start = l;
1685    Evas_Object *to_focus = NULL;
1686
1687    /* Interate sub items */
1688    /* Go to end of list */
1689    for (; l; l = list_next(l))
1690      {
1691         Evas_Object *tmp = NULL;
1692         Evas_Object *cur = list_data_get(l);
1693
1694         if (elm_widget_parent_get(cur) != obj)
1695           continue;
1696
1697         /* Try Focus cycle in subitem */
1698         if (elm_widget_focus_next_get(cur, dir, &tmp))
1699           {
1700              *next = tmp;
1701              return EINA_TRUE;
1702           }
1703         else if ((tmp) && (!to_focus))
1704           to_focus = tmp;
1705      }
1706
1707    l = items;
1708
1709    /* Get First possible */
1710    for (; l != start; l = list_next(l))
1711      {
1712         Evas_Object *tmp = NULL;
1713         Evas_Object *cur = list_data_get(l);
1714
1715         if (elm_widget_parent_get(cur) != obj)
1716           continue;
1717
1718         /* Try Focus cycle in subitem */
1719         elm_widget_focus_next_get(cur, dir, &tmp);
1720         if (tmp)
1721           {
1722              *next = tmp;
1723              return EINA_FALSE;
1724           }
1725      }
1726
1727    *next = to_focus;
1728    return EINA_FALSE;
1729 }
1730
1731 EAPI void
1732 elm_widget_signal_emit(Evas_Object *obj,
1733                        const char  *emission,
1734                        const char  *source)
1735 {
1736    API_ENTRY return;
1737    if (!sd->signal_func) return;
1738    sd->signal_func(obj, emission, source);
1739 }
1740
1741 static void
1742 _edje_signal_callback(void        *data,
1743                       Evas_Object *obj __UNUSED__,
1744                       const char  *emission,
1745                       const char  *source)
1746 {
1747    Edje_Signal_Data *esd = data;
1748    esd->func(esd->data, esd->obj, emission, source);
1749 }
1750
1751 EAPI void
1752 elm_widget_signal_callback_add(Evas_Object   *obj,
1753                                const char    *emission,
1754                                const char    *source,
1755                                Edje_Signal_Cb func,
1756                                void          *data)
1757 {
1758    Edje_Signal_Data *esd;
1759    API_ENTRY return;
1760    if (!sd->callback_add_func) return;
1761    EINA_SAFETY_ON_NULL_RETURN(func);
1762
1763    esd = ELM_NEW(Edje_Signal_Data);
1764    if (!esd) return;
1765
1766    esd->obj = obj;
1767    esd->func = func;
1768    esd->emission = eina_stringshare_add(emission);
1769    esd->source = eina_stringshare_add(source);
1770    esd->data = data;
1771    sd->edje_signals = eina_list_append(sd->edje_signals, esd);
1772    sd->callback_add_func(obj, emission, source, _edje_signal_callback, esd);
1773 }
1774
1775 EAPI void *
1776 elm_widget_signal_callback_del(Evas_Object   *obj,
1777                                const char    *emission,
1778                                const char    *source,
1779                                Edje_Signal_Cb func)
1780 {
1781    Edje_Signal_Data *esd;
1782    Eina_List *l;
1783    void *data = NULL;
1784    API_ENTRY return NULL;
1785    if (!sd->callback_del_func) return NULL;
1786
1787    EINA_LIST_FOREACH(sd->edje_signals, l, esd)
1788      {
1789         if ((esd->func == func) && (!strcmp(esd->emission, emission)) &&
1790             (!strcmp(esd->source, source)))
1791           {
1792              sd->edje_signals = eina_list_remove_list(sd->edje_signals, l);
1793              eina_stringshare_del(esd->emission);
1794              eina_stringshare_del(esd->source);
1795              data = esd->data;
1796              free(esd);
1797              break;
1798           }
1799      }
1800    sd->callback_del_func(obj, emission, source, _edje_signal_callback, data);
1801    return data;
1802 }
1803
1804 EAPI void
1805 elm_widget_focus_set(Evas_Object *obj,
1806                      int          first)
1807 {
1808    API_ENTRY return;
1809    if (!sd->focused)
1810      {
1811         focus_order++;
1812         sd->focus_order = focus_order;
1813         sd->focused = EINA_TRUE;
1814         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1815      }
1816    if (sd->focus_func)
1817      {
1818         sd->focus_func(obj);
1819         return;
1820      }
1821    else
1822      {
1823         if (first)
1824           {
1825              if ((_is_focusable(sd->resize_obj)) &&
1826                  (!elm_widget_disabled_get(sd->resize_obj)))
1827                {
1828                   elm_widget_focus_set(sd->resize_obj, first);
1829                }
1830              else
1831                {
1832                   const Eina_List *l;
1833                   Evas_Object *child;
1834                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1835                     {
1836                        if ((_is_focusable(child)) &&
1837                            (!elm_widget_disabled_get(child)))
1838                          {
1839                             elm_widget_focus_set(child, first);
1840                             break;
1841                          }
1842                     }
1843                }
1844           }
1845         else
1846           {
1847              const Eina_List *l;
1848              Evas_Object *child;
1849              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
1850                {
1851                   if ((_is_focusable(child)) &&
1852                       (!elm_widget_disabled_get(child)))
1853                     {
1854                        elm_widget_focus_set(child, first);
1855                        break;
1856                     }
1857                }
1858              if (!l)
1859                {
1860                   if ((_is_focusable(sd->resize_obj)) &&
1861                       (!elm_widget_disabled_get(sd->resize_obj)))
1862                     {
1863                        elm_widget_focus_set(sd->resize_obj, first);
1864                     }
1865                }
1866           }
1867      }
1868 }
1869
1870 EAPI Evas_Object *
1871 elm_widget_parent_get(const Evas_Object *obj)
1872 {
1873    API_ENTRY return NULL;
1874    return sd->parent_obj;
1875 }
1876
1877 EAPI void
1878 elm_widget_focused_object_clear(Evas_Object *obj)
1879 {
1880    API_ENTRY return;
1881    if (!sd->focused) return;
1882    if (elm_widget_focus_get(sd->resize_obj))
1883      elm_widget_focused_object_clear(sd->resize_obj);
1884    else
1885      {
1886         const Eina_List *l;
1887         Evas_Object *child;
1888         EINA_LIST_FOREACH(sd->subobjs, l, child)
1889           {
1890              if (elm_widget_focus_get(child))
1891                {
1892                   elm_widget_focused_object_clear(child);
1893                   break;
1894                }
1895           }
1896      }
1897    sd->focused = EINA_FALSE;
1898    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1899    if (sd->focus_func) sd->focus_func(obj);
1900 }
1901
1902 EAPI void
1903 elm_widget_focus_steal(Evas_Object *obj)
1904 {
1905    Evas_Object *parent, *o;
1906    API_ENTRY return;
1907
1908    if (sd->focused) return;
1909    if (sd->disabled) return;
1910    if (!sd->can_focus) return;
1911    if (sd->tree_unfocusable) return;
1912    parent = obj;
1913    for (;;)
1914      {
1915         o = elm_widget_parent_get(parent);
1916         if (!o) break;
1917         sd = evas_object_smart_data_get(o);
1918         if (sd->disabled || sd->tree_unfocusable) return;
1919         if (sd->focused) break;
1920         parent = o;
1921      }
1922    if (!elm_widget_parent_get(parent))
1923      elm_widget_focused_object_clear(parent);
1924    else
1925      {
1926         parent = elm_widget_parent_get(parent);
1927         sd = evas_object_smart_data_get(parent);
1928         if ((sd->resize_obj) && (elm_widget_focus_get(sd->resize_obj)))
1929           elm_widget_focused_object_clear(sd->resize_obj);
1930         else
1931           {
1932              const Eina_List *l;
1933              Evas_Object *child;
1934              EINA_LIST_FOREACH(sd->subobjs, l, child)
1935                {
1936                   if (elm_widget_focus_get(child))
1937                     {
1938                        elm_widget_focused_object_clear(child);
1939                        break;
1940                     }
1941                }
1942           }
1943      }
1944    _parent_focus(obj);
1945    return;
1946 }
1947
1948 EAPI void
1949 elm_widget_focus_restore(Evas_Object *obj)
1950 {
1951    Evas_Object *newest = NULL;
1952    unsigned int newest_focus_order = 0;
1953    API_ENTRY return;
1954
1955    newest = _newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
1956    if (newest)
1957      {
1958         elm_object_unfocus(newest);
1959         elm_object_focus(newest);
1960      }
1961 }
1962
1963 void
1964 _elm_widget_top_win_focused_set(Evas_Object *obj, Eina_Bool top_win_focused)
1965 {
1966    const Eina_List *l;
1967    Evas_Object *child;
1968    API_ENTRY return;
1969
1970    if (sd->top_win_focused == top_win_focused) return;
1971    if (sd->resize_obj)
1972      _elm_widget_top_win_focused_set(sd->resize_obj, top_win_focused);
1973    EINA_LIST_FOREACH(sd->subobjs, l, child)
1974      {
1975         _elm_widget_top_win_focused_set(child, top_win_focused);
1976      }
1977    sd->top_win_focused = top_win_focused;
1978 }
1979
1980 Eina_Bool
1981 _elm_widget_top_win_focused_get(const Evas_Object *obj)
1982 {
1983    API_ENTRY return EINA_FALSE;
1984    return sd->top_win_focused;
1985 }
1986
1987 EAPI void
1988 elm_widget_activate(Evas_Object *obj)
1989 {
1990    API_ENTRY return;
1991    elm_widget_change(obj);
1992    if (sd->activate_func) sd->activate_func(obj);
1993 }
1994
1995 EAPI void
1996 elm_widget_change(Evas_Object *obj)
1997 {
1998    API_ENTRY return;
1999    elm_widget_change(elm_widget_parent_get(obj));
2000    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
2001 }
2002
2003 EAPI void
2004 elm_widget_disabled_set(Evas_Object *obj,
2005                         Eina_Bool    disabled)
2006 {
2007    API_ENTRY return;
2008
2009    if (sd->disabled == disabled) return;
2010    sd->disabled = !!disabled;
2011    elm_widget_focus_disabled_handle(obj);
2012    if (sd->disable_func) sd->disable_func(obj);
2013 }
2014
2015 EAPI Eina_Bool
2016 elm_widget_disabled_get(const Evas_Object *obj)
2017 {
2018    API_ENTRY return 0;
2019    return sd->disabled;
2020 }
2021
2022 EAPI void
2023 elm_widget_show_region_set(Evas_Object *obj,
2024                            Evas_Coord   x,
2025                            Evas_Coord   y,
2026                            Evas_Coord   w,
2027                            Evas_Coord   h,
2028                            Eina_Bool    forceshow)
2029 {
2030    Evas_Object *parent_obj, *child_obj;
2031    Evas_Coord px, py, cx, cy;
2032
2033    API_ENTRY return;
2034    if (!forceshow && (x == sd->rx) && (y == sd->ry)
2035             && (w == sd->rw) && (h == sd->rh)) return;
2036    sd->rx = x;
2037    sd->ry = y;
2038    sd->rw = w;
2039    sd->rh = h;
2040    if (sd->on_show_region_func)
2041      sd->on_show_region_func(sd->on_show_region_data, obj);
2042
2043    do
2044      {
2045         parent_obj = sd->parent_obj;
2046         child_obj = sd->obj;
2047         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
2048         sd = evas_object_smart_data_get(parent_obj);
2049         if (!sd) break;
2050
2051         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
2052         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
2053
2054         x += (cx - px);
2055         y += (cy - py);
2056         sd->rx = x;
2057         sd->ry = y;
2058         sd->rw = w;
2059         sd->rh = h;
2060
2061         if (sd->on_show_region_func)
2062           {
2063              sd->on_show_region_func(sd->on_show_region_data, parent_obj);
2064           }
2065      }
2066    while (parent_obj);
2067 }
2068
2069 EAPI void
2070 elm_widget_show_region_get(const Evas_Object *obj,
2071                            Evas_Coord        *x,
2072                            Evas_Coord        *y,
2073                            Evas_Coord        *w,
2074                            Evas_Coord        *h)
2075 {
2076    API_ENTRY return;
2077    if (x) *x = sd->rx;
2078    if (y) *y = sd->ry;
2079    if (w) *w = sd->rw;
2080    if (h) *h = sd->rh;
2081 }
2082
2083 /**
2084  * @internal
2085  *
2086  * Get the focus region of the given widget.
2087  *
2088  * The focus region is the area of a widget that should brought into the
2089  * visible area when the widget is focused. Mostly used to show the part of
2090  * an entry where the cursor is, for example. The area returned is relative
2091  * to the object @p obj.
2092  * If the @p obj doesn't have the proper on_focus_region_hook set, this
2093  * function will return the full size of the object.
2094  *
2095  * @param obj The widget object
2096  * @param x Where to store the x coordinate of the area
2097  * @param y Where to store the y coordinate of the area
2098  * @param w Where to store the width of the area
2099  * @param h Where to store the height of the area
2100  *
2101  * @ingroup Widget
2102  */
2103 EAPI void
2104 elm_widget_focus_region_get(const Evas_Object *obj,
2105                             Evas_Coord        *x,
2106                             Evas_Coord        *y,
2107                             Evas_Coord        *w,
2108                             Evas_Coord        *h)
2109 {
2110    Smart_Data *sd;
2111
2112    if (!obj) return;
2113
2114    sd = evas_object_smart_data_get(obj);
2115    if (!sd || !_elm_widget_is(obj) || !sd->on_focus_region_func)
2116      {
2117         evas_object_geometry_get(obj, NULL, NULL, w, h);
2118         if (x) *x = 0;
2119         if (y) *y = 0;
2120         return;
2121      }
2122    sd->on_focus_region_func(obj, x, y, w, h);
2123 }
2124
2125 EAPI void
2126 elm_widget_scroll_hold_push(Evas_Object *obj)
2127 {
2128    API_ENTRY return;
2129    sd->scroll_hold++;
2130    if (sd->scroll_hold == 1)
2131      evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
2132    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
2133    // FIXME: on delete/reparent hold pop
2134 }
2135
2136 EAPI void
2137 elm_widget_scroll_hold_pop(Evas_Object *obj)
2138 {
2139    API_ENTRY return;
2140    sd->scroll_hold--;
2141    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
2142    if (!sd->scroll_hold)
2143      evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
2144    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
2145 }
2146
2147 EAPI int
2148 elm_widget_scroll_hold_get(const Evas_Object *obj)
2149 {
2150    API_ENTRY return 0;
2151    return sd->scroll_hold;
2152 }
2153
2154 EAPI void
2155 elm_widget_scroll_freeze_push(Evas_Object *obj)
2156 {
2157    API_ENTRY return;
2158    sd->scroll_freeze++;
2159    if (sd->scroll_freeze == 1)
2160      evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
2161    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
2162    // FIXME: on delete/reparent freeze pop
2163 }
2164
2165 EAPI void
2166 elm_widget_scroll_freeze_pop(Evas_Object *obj)
2167 {
2168    API_ENTRY return;
2169    sd->scroll_freeze--;
2170    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
2171    if (!sd->scroll_freeze)
2172      evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
2173    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
2174 }
2175
2176 EAPI int
2177 elm_widget_scroll_freeze_get(const Evas_Object *obj)
2178 {
2179    API_ENTRY return 0;
2180    return sd->scroll_freeze;
2181 }
2182
2183 EAPI void
2184 elm_widget_scale_set(Evas_Object *obj,
2185                      double       scale)
2186 {
2187    API_ENTRY return;
2188    if (scale <= 0.0) scale = 0.0;
2189    if (sd->scale != scale)
2190      {
2191         sd->scale = scale;
2192         elm_widget_theme(obj);
2193      }
2194 }
2195
2196 EAPI double
2197 elm_widget_scale_get(const Evas_Object *obj)
2198 {
2199    API_ENTRY return 1.0;
2200    // FIXME: save walking up the tree by storing/caching parent scale
2201    if (sd->scale == 0.0)
2202      {
2203         if (sd->parent_obj)
2204           return elm_widget_scale_get(sd->parent_obj);
2205         else
2206           return 1.0;
2207      }
2208    return sd->scale;
2209 }
2210
2211 EAPI void
2212 elm_widget_theme_set(Evas_Object *obj,
2213                      Elm_Theme   *th)
2214 {
2215    API_ENTRY return;
2216    if (sd->theme != th)
2217      {
2218         if (sd->theme) elm_theme_free(sd->theme);
2219         sd->theme = th;
2220         if (th) th->ref++;
2221         elm_widget_theme(obj);
2222      }
2223 }
2224
2225 EAPI void
2226 elm_widget_text_part_set(Evas_Object *obj, const char *item, const char *label)
2227 {
2228    API_ENTRY return;
2229
2230    if (!sd->on_text_set_func)
2231      return;
2232
2233    sd->on_text_set_func(obj, item, label);
2234 }
2235
2236 EAPI const char *
2237 elm_widget_text_part_get(const Evas_Object *obj, const char *item)
2238 {
2239    API_ENTRY return NULL;
2240
2241    if (!sd->on_text_get_func)
2242      return NULL;
2243
2244    return sd->on_text_get_func(obj, item);
2245 }
2246
2247 EAPI void
2248 elm_widget_domain_translatable_text_part_set(Evas_Object *obj, const char *part, const char *domain, const char *label)
2249 {
2250    const char *str;
2251    Eina_List *l;
2252    Elm_Translate_String_Data *ts = NULL;
2253    API_ENTRY return;
2254
2255    str = eina_stringshare_add(part);
2256    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2257       if (ts->id == str)
2258         break;
2259       else
2260         ts = NULL;
2261
2262    if (!ts && !label)
2263      eina_stringshare_del(str);
2264    else if (!ts)
2265      {
2266         ts = malloc(sizeof(Elm_Translate_String_Data));
2267         if (!ts) return;
2268
2269         ts->id = str;
2270         ts->domain = eina_stringshare_add(domain);
2271         ts->string = eina_stringshare_add(label);
2272         sd->translate_strings = eina_list_append(sd->translate_strings, ts);
2273      }
2274    else
2275      {
2276         if (label)
2277           {
2278              eina_stringshare_replace(&ts->domain, domain);
2279              eina_stringshare_replace(&ts->string, label);
2280           }
2281         else
2282           {
2283              sd->translate_strings = eina_list_remove_list(
2284                                                 sd->translate_strings, l);
2285              eina_stringshare_del(ts->id);
2286              eina_stringshare_del(ts->domain);
2287              eina_stringshare_del(ts->string);
2288              free(ts);
2289           }
2290         eina_stringshare_del(str);
2291      }
2292
2293 #ifdef HAVE_GETTEXT
2294    if (label && label[0])
2295      label = dgettext(domain, label);
2296 #endif
2297    elm_widget_text_part_set(obj, part, label);
2298 }
2299
2300 EAPI const char *
2301 elm_widget_translatable_text_part_get(const Evas_Object *obj, const char *part)
2302 {
2303    const char *str, *ret = NULL;
2304    Eina_List *l;
2305    Elm_Translate_String_Data *ts;
2306    API_ENTRY return NULL;
2307
2308    str = eina_stringshare_add(part);
2309    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2310       if (ts->id == str)
2311         {
2312            ret = ts->string;
2313            break;
2314         }
2315    eina_stringshare_del(str);
2316    return ret;
2317 }
2318
2319 EAPI void
2320 elm_widget_translate(Evas_Object *obj)
2321 {
2322    const Eina_List *l;
2323    Evas_Object *child;
2324    Elm_Translate_String_Data *ts;
2325
2326    API_ENTRY return;
2327    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_translate(child);
2328    if (sd->resize_obj) elm_widget_translate(sd->resize_obj);
2329    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
2330    if (sd->translate_func) sd->translate_func(obj);
2331
2332 #ifdef HAVE_GETTEXT
2333    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2334      {
2335         const char *s = dgettext(ts->domain, ts->string);
2336         elm_widget_text_part_set(obj, ts->id, s);
2337      }
2338 #endif
2339 }
2340
2341 EAPI void
2342 elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content)
2343 {
2344    API_ENTRY return;
2345
2346    if (!sd->on_content_set_func)  return;
2347    sd->on_content_set_func(obj, part, content);
2348 }
2349
2350 EAPI Evas_Object *
2351 elm_widget_content_part_get(const Evas_Object *obj, const char *part)
2352 {
2353    API_ENTRY return NULL;
2354
2355    if (!sd->on_content_get_func) return NULL;
2356    return sd->on_content_get_func(obj, part);
2357 }
2358
2359 EAPI Evas_Object *
2360 elm_widget_content_part_unset(Evas_Object *obj, const char *part)
2361 {
2362    API_ENTRY return NULL;
2363
2364    if (!sd->on_content_unset_func) return NULL;
2365    return sd->on_content_unset_func(obj, part);
2366 }
2367
2368 EAPI void
2369 elm_widget_access_info_set(Evas_Object *obj, const char *txt)
2370 {
2371    API_ENTRY return;
2372    if (sd->access_info) eina_stringshare_del(sd->access_info);
2373    if (!txt) sd->access_info = NULL;
2374    else sd->access_info = eina_stringshare_add(txt);
2375 }
2376
2377 EAPI const char *
2378 elm_widget_access_info_get(Evas_Object *obj)
2379 {
2380    API_ENTRY return NULL;
2381    return sd->access_info;
2382 }
2383
2384
2385 EAPI Elm_Theme *
2386 elm_widget_theme_get(const Evas_Object *obj)
2387 {
2388    API_ENTRY return NULL;
2389    if (!sd->theme)
2390      {
2391         if (sd->parent_obj)
2392           return elm_widget_theme_get(sd->parent_obj);
2393         else
2394           return NULL;
2395      }
2396    return sd->theme;
2397 }
2398
2399 EAPI void
2400 elm_widget_style_set(Evas_Object *obj,
2401                      const char  *style)
2402 {
2403    API_ENTRY return;
2404
2405    if (eina_stringshare_replace(&sd->style, style))
2406      elm_widget_theme(obj);
2407 }
2408
2409 EAPI const char *
2410 elm_widget_style_get(const Evas_Object *obj)
2411 {
2412    API_ENTRY return NULL;
2413    if (sd->style) return sd->style;
2414    return "default";
2415 }
2416
2417 EAPI void
2418 elm_widget_type_set(Evas_Object *obj,
2419                     const char  *type)
2420 {
2421    API_ENTRY return;
2422    eina_stringshare_replace(&sd->type, type);
2423 }
2424
2425 EAPI const char *
2426 elm_widget_type_get(const Evas_Object *obj)
2427 {
2428    API_ENTRY return NULL;
2429    if (sd->type) return sd->type;
2430    return "";
2431 }
2432
2433 EAPI void
2434 elm_widget_tooltip_add(Evas_Object *obj,
2435                        Elm_Tooltip *tt)
2436 {
2437    API_ENTRY return;
2438    sd->tooltips = eina_list_append(sd->tooltips, tt);
2439 }
2440
2441 EAPI void
2442 elm_widget_tooltip_del(Evas_Object *obj,
2443                        Elm_Tooltip *tt)
2444 {
2445    API_ENTRY return;
2446    sd->tooltips = eina_list_remove(sd->tooltips, tt);
2447 }
2448
2449 EAPI void
2450 elm_widget_cursor_add(Evas_Object *obj,
2451                       Elm_Cursor  *cur)
2452 {
2453    API_ENTRY return;
2454    sd->cursors = eina_list_append(sd->cursors, cur);
2455 }
2456
2457 EAPI void
2458 elm_widget_cursor_del(Evas_Object *obj,
2459                       Elm_Cursor  *cur)
2460 {
2461    API_ENTRY return;
2462    sd->cursors = eina_list_remove(sd->cursors, cur);
2463 }
2464
2465 EAPI void
2466 elm_widget_drag_lock_x_set(Evas_Object *obj,
2467                            Eina_Bool    lock)
2468 {
2469    API_ENTRY return;
2470    if (sd->drag_x_locked == lock) return;
2471    sd->drag_x_locked = lock;
2472    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
2473    else _propagate_x_drag_lock(obj, -1);
2474 }
2475
2476 EAPI void
2477 elm_widget_drag_lock_y_set(Evas_Object *obj,
2478                            Eina_Bool    lock)
2479 {
2480    API_ENTRY return;
2481    if (sd->drag_y_locked == lock) return;
2482    sd->drag_y_locked = lock;
2483    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
2484    else _propagate_y_drag_lock(obj, -1);
2485 }
2486
2487 EAPI Eina_Bool
2488 elm_widget_drag_lock_x_get(const Evas_Object *obj)
2489 {
2490    API_ENTRY return EINA_FALSE;
2491    return sd->drag_x_locked;
2492 }
2493
2494 EAPI Eina_Bool
2495 elm_widget_drag_lock_y_get(const Evas_Object *obj)
2496 {
2497    API_ENTRY return EINA_FALSE;
2498    return sd->drag_y_locked;
2499 }
2500
2501 EAPI int
2502 elm_widget_drag_child_locked_x_get(const Evas_Object *obj)
2503 {
2504    API_ENTRY return 0;
2505    return sd->child_drag_x_locked;
2506 }
2507
2508 EAPI int
2509 elm_widget_drag_child_locked_y_get(const Evas_Object *obj)
2510 {
2511    API_ENTRY return 0;
2512    return sd->child_drag_y_locked;
2513 }
2514
2515 EAPI Eina_Bool
2516 elm_widget_theme_object_set(Evas_Object *obj,
2517                             Evas_Object *edj,
2518                             const char  *wname,
2519                             const char  *welement,
2520                             const char  *wstyle)
2521 {
2522    API_ENTRY return EINA_FALSE;
2523    return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
2524 }
2525
2526 EAPI Eina_Bool
2527 elm_widget_type_check(const Evas_Object *obj,
2528                       const char        *type)
2529 {
2530    const char *provided, *expected = "(unknown)";
2531    static int abort_on_warn = -1;
2532    provided = elm_widget_type_get(obj);
2533    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
2534    if (type) expected = type;
2535    if ((!provided) || (!provided[0]))
2536      {
2537         provided = evas_object_type_get(obj);
2538         if ((!provided) || (!provided[0]))
2539           provided = "(unknown)";
2540      }
2541    ERR("Passing Object: %p, of type: '%s' when expecting type: '%s'", obj, provided, expected);
2542    if (abort_on_warn == -1)
2543      {
2544         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2545         else abort_on_warn = 0;
2546      }
2547    if (abort_on_warn == 1) abort();
2548    return EINA_FALSE;
2549 }
2550
2551 /**
2552  * @internal
2553  *
2554  * Split string in words
2555  *
2556  * @param str Source string
2557  * @return List of const words
2558  *
2559  * @see elm_widget_stringlist_free()
2560  * @ingroup Widget
2561  */
2562 EAPI Eina_List *
2563 elm_widget_stringlist_get(const char *str)
2564 {
2565    Eina_List *list = NULL;
2566    const char *s, *b;
2567    if (!str) return NULL;
2568    for (b = s = str; 1; s++)
2569      {
2570         if ((*s == ' ') || (!*s))
2571           {
2572              char *t = malloc(s - b + 1);
2573              if (t)
2574                {
2575                   strncpy(t, b, s - b);
2576                   t[s - b] = 0;
2577                   list = eina_list_append(list, eina_stringshare_add(t));
2578                   free(t);
2579                }
2580              b = s + 1;
2581           }
2582         if (!*s) break;
2583      }
2584    return list;
2585 }
2586
2587 EAPI void
2588 elm_widget_stringlist_free(Eina_List *list)
2589 {
2590    const char *s;
2591    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
2592 }
2593
2594 EAPI void
2595 elm_widget_focus_hide_handle(Evas_Object *obj)
2596 {
2597    _if_focused_revert(obj, EINA_TRUE);
2598 }
2599
2600 EAPI void
2601 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
2602 {
2603    Evas_Object *o = obj;
2604    do
2605      {
2606         if (_elm_widget_is(o)) break;
2607         o = evas_object_smart_parent_get(o);
2608      }
2609    while (o);
2610    if (!o) return;
2611    if (!_is_focusable(o)) return;
2612    elm_widget_focus_steal(o);
2613 }
2614
2615 EAPI void
2616 elm_widget_focus_tree_unfocusable_handle(Evas_Object *obj)
2617 {
2618    API_ENTRY return;
2619
2620    if (!elm_widget_parent_get(obj))
2621      elm_widget_focused_object_clear(obj);
2622    else
2623      _if_focused_revert(obj, EINA_TRUE);
2624 }
2625
2626 EAPI void
2627 elm_widget_focus_disabled_handle(Evas_Object *obj)
2628 {
2629    API_ENTRY return;
2630
2631    elm_widget_focus_tree_unfocusable_handle(obj);
2632 }
2633
2634 /**
2635  * @internal
2636  *
2637  * Allocate a new Elm_Widget_Item-derived structure.
2638  *
2639  * The goal of this structure is to provide common ground for actions
2640  * that a widget item have, such as the owner widget, callback to
2641  * notify deletion, data pointer and maybe more.
2642  *
2643  * @param widget the owner widget that holds this item, must be an elm_widget!
2644  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
2645  *        be used to allocate memory.
2646  *
2647  * @return allocated memory that is already zeroed out, or NULL on errors.
2648  *
2649  * @see elm_widget_item_new() convenience macro.
2650  * @see elm_widget_item_del() to release memory.
2651  * @ingroup Widget
2652  */
2653 EAPI Elm_Widget_Item *
2654 _elm_widget_item_new(Evas_Object *widget,
2655                      size_t       alloc_size)
2656 {
2657    if (!_elm_widget_is(widget))
2658      return NULL;
2659
2660    Elm_Widget_Item *item;
2661
2662    EINA_SAFETY_ON_TRUE_RETURN_VAL(alloc_size < sizeof(Elm_Widget_Item), NULL);
2663    EINA_SAFETY_ON_TRUE_RETURN_VAL(!_elm_widget_is(widget), NULL);
2664
2665    item = calloc(1, alloc_size);
2666    EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
2667
2668    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
2669    item->widget = widget;
2670    return item;
2671 }
2672
2673 /**
2674  * @internal
2675  *
2676  * Releases widget item memory, calling back del_cb() if it exists.
2677  *
2678  * If there is a Elm_Widget_Item::del_cb, then it will be called prior
2679  * to memory release. Note that elm_widget_item_pre_notify_del() calls
2680  * this function and then unset it, thus being useful for 2 step
2681  * cleanup whenever the del_cb may use any of the data that must be
2682  * deleted from item.
2683  *
2684  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
2685  * is presented!
2686  *
2687  * @param item a valid #Elm_Widget_Item to be deleted.
2688  * @see elm_widget_item_del() convenience macro.
2689  * @ingroup Widget
2690  */
2691 EAPI void
2692 _elm_widget_item_del(Elm_Widget_Item *item)
2693 {
2694    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2695
2696    if (item->del_cb)
2697      item->del_cb((void *)item->data, item->widget, item);
2698
2699    if (item->view)
2700      evas_object_del(item->view);
2701    
2702    if (item->access)
2703      {
2704         _elm_access_clear(item->access);
2705         free(item->access);
2706         item->access = NULL;
2707      }
2708    if (item->access_info)
2709      {
2710         eina_stringshare_del(item->access_info);
2711         item->access_info = NULL;
2712      }
2713
2714    if (item->access)
2715      {
2716         _elm_access_clear(item->access);
2717         free(item->access);
2718         item->access = NULL;
2719      }
2720    if (item->access_info)
2721      {
2722         eina_stringshare_del(item->access_info);
2723         item->access_info = NULL;
2724      }
2725
2726    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
2727    free(item);
2728 }
2729
2730 /**
2731  * @internal
2732  *
2733  * Notify object will be deleted without actually deleting it.
2734  *
2735  * This function will callback Elm_Widget_Item::del_cb if it is set
2736  * and then unset it so it is not called twice (ie: from
2737  * elm_widget_item_del()).
2738  *
2739  * @param item a valid #Elm_Widget_Item to be notified
2740  * @see elm_widget_item_pre_notify_del() convenience macro.
2741  * @ingroup Widget
2742  */
2743 EAPI void
2744 _elm_widget_item_pre_notify_del(Elm_Widget_Item *item)
2745 {
2746    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2747    if (!item->del_cb) return;
2748    item->del_cb((void *)item->data, item->widget, item);
2749    item->del_cb = NULL;
2750 }
2751
2752 /**
2753  * @internal
2754  *
2755  * Set the function to notify when item is being deleted.
2756  *
2757  * This function will complain if there was a callback set already,
2758  * however it will set the new one.
2759  *
2760  * The callback will be called from elm_widget_item_pre_notify_del()
2761  * or elm_widget_item_del() will be called with:
2762  *   - data: the Elm_Widget_Item::data value.
2763  *   - obj: the Elm_Widget_Item::widget evas object.
2764  *   - event_info: the item being deleted.
2765  *
2766  * @param item a valid #Elm_Widget_Item to be notified
2767  * @see elm_widget_item_del_cb_set() convenience macro.
2768  * @ingroup Widget
2769  */
2770 EAPI void
2771 _elm_widget_item_del_cb_set(Elm_Widget_Item *item,
2772                             Evas_Smart_Cb    del_cb)
2773 {
2774    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2775
2776    if ((item->del_cb) && (item->del_cb != del_cb))
2777      WRN("You're replacing a previously set del_cb %p of item %p with %p",
2778          item->del_cb, item, del_cb);
2779
2780    item->del_cb = del_cb;
2781 }
2782
2783 /**
2784  * @internal
2785  *
2786  * Set user-data in this item.
2787  *
2788  * User data may be used to identify this item or just store any
2789  * application data. It is automatically given as the first parameter
2790  * of the deletion notify callback.
2791  *
2792  * @param item a valid #Elm_Widget_Item to store data in.
2793  * @param data user data to store.
2794  * @see elm_widget_item_del_cb_set() convenience macro.
2795  * @ingroup Widget
2796  */
2797 EAPI void
2798 _elm_widget_item_data_set(Elm_Widget_Item *item,
2799                           const void      *data)
2800 {
2801    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2802    if ((item->data) && (item->data != data))
2803      DBG("Replacing item %p data %p with %p", item, item->data, data);
2804    item->data = data;
2805 }
2806
2807 /**
2808  * @internal
2809  *
2810  * Retrieves user-data of this item.
2811  *
2812  * @param item a valid #Elm_Widget_Item to get data from.
2813  * @see elm_widget_item_data_set()
2814  * @ingroup Widget
2815  */
2816 EAPI void *
2817 _elm_widget_item_data_get(const Elm_Widget_Item *item)
2818 {
2819    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2820    return (void *)item->data;
2821 }
2822
2823 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
2824
2825 struct _Elm_Widget_Item_Tooltip
2826 {
2827    Elm_Widget_Item            *item;
2828    Elm_Tooltip_Item_Content_Cb func;
2829    Evas_Smart_Cb               del_cb;
2830    const void                 *data;
2831 };
2832
2833 static Evas_Object *
2834 _elm_widget_item_tooltip_label_create(void        *data,
2835                                       Evas_Object *obj,
2836                                       void        *item __UNUSED__)
2837 {
2838    Evas_Object *label = elm_label_add(obj);
2839    if (!label)
2840      return NULL;
2841    elm_object_style_set(label, "tooltip");
2842    elm_object_text_set(label, data);
2843    return label;
2844 }
2845
2846 static Evas_Object *
2847 _elm_widget_item_tooltip_trans_label_create(void        *data,
2848                                             Evas_Object *obj __UNUSED__,
2849                                             void        *item __UNUSED__)
2850 {
2851    Evas_Object *label = elm_label_add(obj);
2852    if (!label)
2853      return NULL;
2854    elm_object_style_set(label, "tooltip");
2855    elm_object_translatable_text_set(label, data);
2856    return label;
2857 }
2858
2859 static void
2860 _elm_widget_item_tooltip_label_del_cb(void        *data,
2861                                       Evas_Object *obj __UNUSED__,
2862                                       void        *event_info __UNUSED__)
2863 {
2864    eina_stringshare_del(data);
2865 }
2866
2867 /**
2868  * @internal
2869  *
2870  * Set the text to be shown in the widget item.
2871  *
2872  * @param item Target item
2873  * @param text The text to set in the content
2874  *
2875  * Setup the text as tooltip to object. The item can have only one tooltip,
2876  * so any previous tooltip data is removed.
2877  *
2878  * @ingroup Widget
2879  */
2880 EAPI void
2881 _elm_widget_item_tooltip_text_set(Elm_Widget_Item *item,
2882                                   const char      *text)
2883 {
2884    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2885    EINA_SAFETY_ON_NULL_RETURN(text);
2886
2887    text = eina_stringshare_add(text);
2888    _elm_widget_item_tooltip_content_cb_set
2889      (item, _elm_widget_item_tooltip_label_create, text,
2890      _elm_widget_item_tooltip_label_del_cb);
2891 }
2892
2893 EAPI void
2894 _elm_widget_item_tooltip_translatable_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_trans_label_create, text,
2903      _elm_widget_item_tooltip_label_del_cb);
2904 }
2905
2906 static Evas_Object *
2907 _elm_widget_item_tooltip_create(void        *data,
2908                                 Evas_Object *obj)
2909 {
2910    Elm_Widget_Item_Tooltip *wit = data;
2911    return wit->func((void *)wit->data, obj, wit->item);
2912 }
2913
2914 static void
2915 _elm_widget_item_tooltip_del_cb(void        *data,
2916                                 Evas_Object *obj,
2917                                 void        *event_info __UNUSED__)
2918 {
2919    Elm_Widget_Item_Tooltip *wit = data;
2920    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item);
2921    free(wit);
2922 }
2923
2924 /**
2925  * @internal
2926  *
2927  * Set the content to be shown in the tooltip item
2928  *
2929  * Setup the tooltip to item. The item can have only one tooltip,
2930  * so any previous tooltip data is removed. @p func(with @p data) will
2931  * be called every time that need show the tooltip and it should
2932  * return a valid Evas_Object. This object is then managed fully by
2933  * tooltip system and is deleted when the tooltip is gone.
2934  *
2935  * @param item the widget item being attached a tooltip.
2936  * @param func the function used to create the tooltip contents.
2937  * @param data what to provide to @a func as callback data/context.
2938  * @param del_cb called when data is not needed anymore, either when
2939  *        another callback replaces @func, the tooltip is unset with
2940  *        elm_widget_item_tooltip_unset() or the owner @a item
2941  *        dies. This callback receives as the first parameter the
2942  *        given @a data, and @c event_info is the item.
2943  *
2944  * @ingroup Widget
2945  */
2946 EAPI void
2947 _elm_widget_item_tooltip_content_cb_set(Elm_Widget_Item            *item,
2948                                         Elm_Tooltip_Item_Content_Cb func,
2949                                         const void                 *data,
2950                                         Evas_Smart_Cb               del_cb)
2951 {
2952    Elm_Widget_Item_Tooltip *wit;
2953
2954    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
2955
2956    if (!func)
2957      {
2958         _elm_widget_item_tooltip_unset(item);
2959         return;
2960      }
2961
2962    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
2963    if (!wit) goto error;
2964    wit->item = item;
2965    wit->func = func;
2966    wit->data = data;
2967    wit->del_cb = del_cb;
2968
2969    elm_object_sub_tooltip_content_cb_set
2970      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
2971      _elm_widget_item_tooltip_del_cb);
2972
2973    return;
2974
2975 error_noitem:
2976    if (del_cb) del_cb((void *)data, NULL, item);
2977    return;
2978 error:
2979    if (del_cb) del_cb((void *)data, item->widget, item);
2980 }
2981
2982 /**
2983  * @internal
2984  *
2985  * Unset tooltip from item
2986  *
2987  * @param item widget item to remove previously set tooltip.
2988  *
2989  * Remove tooltip from item. The callback provided as del_cb to
2990  * elm_widget_item_tooltip_content_cb_set() will be called to notify
2991  * it is not used anymore.
2992  *
2993  * @see elm_widget_item_tooltip_content_cb_set()
2994  *
2995  * @ingroup Widget
2996  */
2997 EAPI void
2998 _elm_widget_item_tooltip_unset(Elm_Widget_Item *item)
2999 {
3000    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3001    elm_object_tooltip_unset(item->view);
3002 }
3003
3004 /**
3005  * @internal
3006  *
3007  * Sets a different style for this item tooltip.
3008  *
3009  * @note before you set a style you should define a tooltip with
3010  *       elm_widget_item_tooltip_content_cb_set() or
3011  *       elm_widget_item_tooltip_text_set()
3012  *
3013  * @param item widget item with tooltip already set.
3014  * @param style the theme style to use (default, transparent, ...)
3015  *
3016  * @ingroup Widget
3017  */
3018 EAPI void
3019 _elm_widget_item_tooltip_style_set(Elm_Widget_Item *item,
3020                                    const char      *style)
3021 {
3022    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3023    elm_object_tooltip_style_set(item->view, style);
3024 }
3025
3026 /**
3027  * @internal
3028  *
3029  * Get the style for this item tooltip.
3030  *
3031  * @param item widget item with tooltip already set.
3032  * @return style the theme style in use, defaults to "default". If the
3033  *         object does not have a tooltip set, then NULL is returned.
3034  *
3035  * @ingroup Widget
3036  */
3037 EAPI const char *
3038 _elm_widget_item_tooltip_style_get(const Elm_Widget_Item *item)
3039 {
3040    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3041    return elm_object_tooltip_style_get(item->view);
3042 }
3043
3044 EAPI void
3045 _elm_widget_item_cursor_set(Elm_Widget_Item *item,
3046                             const char      *cursor)
3047 {
3048    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3049    elm_object_sub_cursor_set(item->view, item->widget, cursor);
3050 }
3051
3052 EAPI const char *
3053 _elm_widget_item_cursor_get(const Elm_Widget_Item *item)
3054 {
3055    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3056    return elm_object_cursor_get(item->view);
3057 }
3058
3059 EAPI void
3060 _elm_widget_item_cursor_unset(Elm_Widget_Item *item)
3061 {
3062    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3063    elm_object_cursor_unset(item->view);
3064 }
3065
3066 /**
3067  * @internal
3068  *
3069  * Sets a different style for this item cursor.
3070  *
3071  * @note before you set a style you should define a cursor with
3072  *       elm_widget_item_cursor_set()
3073  *
3074  * @param item widget item with cursor already set.
3075  * @param style the theme style to use (default, transparent, ...)
3076  *
3077  * @ingroup Widget
3078  */
3079 EAPI void
3080 _elm_widget_item_cursor_style_set(Elm_Widget_Item *item,
3081                                   const char      *style)
3082 {
3083    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3084    elm_object_cursor_style_set(item->view, style);
3085 }
3086
3087 /**
3088  * @internal
3089  *
3090  * Get the style for this item cursor.
3091  *
3092  * @param item widget item with cursor already set.
3093  * @return style the theme style in use, defaults to "default". If the
3094  *         object does not have a cursor set, then NULL is returned.
3095  *
3096  * @ingroup Widget
3097  */
3098 EAPI const char *
3099 _elm_widget_item_cursor_style_get(const Elm_Widget_Item *item)
3100 {
3101    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3102    return elm_object_cursor_style_get(item->view);
3103 }
3104
3105 /**
3106  * @internal
3107  *
3108  * Set if the cursor set should be searched on the theme or should use
3109  * the provided by the engine, only.
3110  *
3111  * @note before you set if should look on theme you should define a cursor
3112  * with elm_object_cursor_set(). By default it will only look for cursors
3113  * provided by the engine.
3114  *
3115  * @param item widget item with cursor already set.
3116  * @param engine_only boolean to define it cursors should be looked only
3117  * between the provided by the engine or searched on widget's theme as well.
3118  *
3119  * @ingroup Widget
3120  */
3121 EAPI void
3122 _elm_widget_item_cursor_engine_only_set(Elm_Widget_Item *item,
3123                                         Eina_Bool        engine_only)
3124 {
3125    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3126    elm_object_cursor_engine_only_set(item->view, engine_only);
3127 }
3128
3129 /**
3130  * @internal
3131  *
3132  * Get the cursor engine only usage for this item cursor.
3133  *
3134  * @param item widget item with cursor already set.
3135  * @return engine_only boolean to define it cursors should be looked only
3136  * between the provided by the engine or searched on widget's theme as well. If
3137  *         the object does not have a cursor set, then EINA_FALSE is returned.
3138  *
3139  * @ingroup Widget
3140  */
3141 EAPI Eina_Bool
3142 _elm_widget_item_cursor_engine_only_get(const Elm_Widget_Item *item)
3143 {
3144    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3145    return elm_object_cursor_engine_only_get(item->view);
3146 }
3147
3148 // smart object funcs
3149 static void
3150 _smart_reconfigure(Smart_Data *sd)
3151 {
3152    if (sd->resize_obj)
3153      {
3154         evas_object_move(sd->resize_obj, sd->x, sd->y);
3155         evas_object_resize(sd->resize_obj, sd->w, sd->h);
3156      }
3157    if (sd->hover_obj)
3158      {
3159         evas_object_move(sd->hover_obj, sd->x, sd->y);
3160         evas_object_resize(sd->hover_obj, sd->w, sd->h);
3161      }
3162 }
3163
3164 EAPI void
3165 _elm_widget_item_content_part_set(Elm_Widget_Item *item,
3166                                  const char *part,
3167                                  Evas_Object *content)
3168 {
3169    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3170    if (!item->on_content_set_func) return;
3171    item->on_content_set_func((Elm_Object_Item *) item, part, content);
3172 }
3173
3174 EAPI Evas_Object *
3175 _elm_widget_item_content_part_get(const Elm_Widget_Item *item,
3176                                   const char *part)
3177 {
3178    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3179    if (!item->on_content_get_func) return NULL;
3180    return item->on_content_get_func((Elm_Object_Item *) item, part);
3181 }
3182
3183 EAPI Evas_Object *
3184 _elm_widget_item_content_part_unset(Elm_Widget_Item *item,
3185                                     const char *part)
3186 {
3187    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3188    if (!item->on_content_unset_func) return NULL;
3189    return item->on_content_unset_func((Elm_Object_Item *) item, part);
3190 }
3191
3192 EAPI void
3193 _elm_widget_item_text_part_set(Elm_Widget_Item *item,
3194                               const char *part,
3195                               const char *label)
3196 {
3197    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3198    if (!item->on_text_set_func) return;
3199    item->on_text_set_func((Elm_Object_Item *) item, part, label);
3200 }
3201
3202 EAPI void
3203 _elm_widget_item_signal_emit(Elm_Widget_Item *item,
3204                              const char *emission,
3205                              const char *source)
3206 {
3207    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3208    if (item->on_signal_emit_func)
3209      item->on_signal_emit_func((Elm_Object_Item *) item, emission, source);
3210 }
3211
3212 EAPI const char *
3213 _elm_widget_item_text_part_get(const Elm_Widget_Item *item,
3214                                const char *part)
3215 {
3216    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3217    if (!item->on_text_get_func) return NULL;
3218    return item->on_text_get_func((Elm_Object_Item *) item, part);
3219 }
3220
3221 EAPI void
3222 _elm_widget_item_content_set_hook_set(Elm_Widget_Item *item,
3223                                       Elm_Widget_On_Content_Set_Cb func)
3224 {
3225    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3226    item->on_content_set_func = func;
3227 }
3228
3229 EAPI void
3230 _elm_widget_item_content_get_hook_set(Elm_Widget_Item *item,
3231                                       Elm_Widget_On_Content_Get_Cb func)
3232 {
3233    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3234    item->on_content_get_func = func;
3235 }
3236
3237 EAPI void
3238 _elm_widget_item_content_unset_hook_set(Elm_Widget_Item *item,
3239                                         Elm_Widget_On_Content_Unset_Cb func)
3240 {
3241    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3242    item->on_content_unset_func = func;
3243 }
3244
3245 EAPI void
3246 _elm_widget_item_text_set_hook_set(Elm_Widget_Item *item,
3247                                    Elm_Widget_On_Text_Set_Cb func)
3248 {
3249    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3250    item->on_text_set_func = func;
3251 }
3252
3253 EAPI void
3254 _elm_widget_item_text_get_hook_set(Elm_Widget_Item *item,
3255                                    Elm_Widget_On_Text_Get_Cb func)
3256 {
3257    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3258    item->on_text_get_func = func;
3259 }
3260
3261 EAPI void
3262 _elm_widget_item_signal_emit_hook_set(Elm_Widget_Item *item,
3263                                       Elm_Widget_On_Signal_Emit_Cb func)
3264 {
3265    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3266    item->on_signal_emit_func = func;
3267 }
3268
3269 EAPI void
3270 _elm_widget_item_access_info_set(Elm_Widget_Item *item, const char *txt)
3271 {
3272    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3273    if (item->access_info) eina_stringshare_del(item->access_info);
3274    if (!txt) item->access_info = NULL;
3275    else item->access_info = eina_stringshare_add(txt);
3276 }
3277
3278
3279 static void
3280 _smart_add(Evas_Object *obj)
3281 {
3282    Smart_Data *sd;
3283
3284    sd = calloc(1, sizeof(Smart_Data));
3285    if (!sd) return;
3286    sd->obj = obj;
3287    sd->x = sd->y = sd->w = sd->h = 0;
3288    sd->can_focus = 1;
3289    sd->mirrored_auto_mode = EINA_TRUE; /* will follow system locale settings */
3290    evas_object_smart_data_set(obj, sd);
3291 }
3292
3293 static Evas_Object *
3294 _newest_focus_order_get(Evas_Object  *obj,
3295                         unsigned int *newest_focus_order,
3296                         Eina_Bool     can_focus_only)
3297 {
3298    const Eina_List *l;
3299    Evas_Object *child, *ret, *best;
3300
3301    API_ENTRY return NULL;
3302
3303    if (!evas_object_visible_get(obj)
3304        || (elm_widget_disabled_get(obj))
3305        || (elm_widget_tree_unfocusable_get(obj)))
3306      return NULL;
3307
3308    best = NULL;
3309    if (*newest_focus_order < sd->focus_order)
3310      {
3311         *newest_focus_order = sd->focus_order;
3312         best = obj;
3313      }
3314    EINA_LIST_FOREACH(sd->subobjs, l, child)
3315      {
3316         ret = _newest_focus_order_get(child, newest_focus_order, can_focus_only);
3317         if (!ret) continue;
3318         best = ret;
3319      }
3320    if (can_focus_only)
3321      {
3322         if ((!best) || (!elm_widget_can_focus_get(best)))
3323           return NULL;
3324      }
3325    return best;
3326 }
3327
3328 static void
3329 _if_focused_revert(Evas_Object *obj,
3330                    Eina_Bool    can_focus_only)
3331 {
3332    Evas_Object *top;
3333    Evas_Object *newest = NULL;
3334    unsigned int newest_focus_order = 0;
3335
3336    INTERNAL_ENTRY
3337
3338    if (!sd->focused) return;
3339    if (!sd->parent_obj) return;
3340
3341    top = elm_widget_top_get(sd->parent_obj);
3342    if (top)
3343      {
3344         newest = _newest_focus_order_get(top, &newest_focus_order, can_focus_only);
3345         if (newest)
3346           {
3347              elm_object_focus_set(newest, EINA_FALSE);
3348              elm_object_focus_set(newest, EINA_TRUE);
3349           }
3350      }
3351 }
3352
3353 static void
3354 _smart_del(Evas_Object *obj)
3355 {
3356    Evas_Object *sobj;
3357    Edje_Signal_Data *esd;
3358    Elm_Translate_String_Data *ts;
3359
3360    INTERNAL_ENTRY
3361
3362    if (sd->del_pre_func) sd->del_pre_func(obj);
3363    if (sd->resize_obj)
3364      {
3365         sobj = sd->resize_obj;
3366         sd->resize_obj = NULL;
3367         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3368         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3369         evas_object_del(sobj);
3370      }
3371    if (sd->hover_obj)
3372      {
3373         sobj = sd->hover_obj;
3374         sd->hover_obj = NULL;
3375         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3376         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3377         evas_object_del(sobj);
3378      }
3379    EINA_LIST_FREE(sd->subobjs, sobj)
3380      {
3381         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3382         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3383         evas_object_del(sobj);
3384      }
3385    eina_list_free(sd->tooltips); /* should be empty anyway */
3386    eina_list_free(sd->cursors); /* should be empty anyway */
3387    EINA_LIST_FREE(sd->edje_signals, esd)
3388      {
3389         eina_stringshare_del(esd->emission);
3390         eina_stringshare_del(esd->source);
3391         free(esd);
3392      }
3393    EINA_LIST_FREE(sd->translate_strings, ts)
3394      {
3395         eina_stringshare_del(ts->id);
3396         eina_stringshare_del(ts->domain);
3397         eina_stringshare_del(ts->string);
3398         free(ts);
3399      }
3400    eina_list_free(sd->event_cb); /* should be empty anyway */
3401    if (sd->del_func) sd->del_func(obj);
3402    if (sd->style) eina_stringshare_del(sd->style);
3403    if (sd->type) eina_stringshare_del(sd->type);
3404    if (sd->theme) elm_theme_free(sd->theme);
3405    _if_focused_revert(obj, EINA_TRUE);
3406    if (sd->access_info) eina_stringshare_del(sd->access_info);
3407    free(sd);
3408 }
3409
3410 static void
3411 _smart_move(Evas_Object *obj,
3412             Evas_Coord   x,
3413             Evas_Coord   y)
3414 {
3415    INTERNAL_ENTRY
3416    sd->x = x;
3417    sd->y = y;
3418    _smart_reconfigure(sd);
3419 }
3420
3421 static void
3422 _smart_resize(Evas_Object *obj,
3423               Evas_Coord   w,
3424               Evas_Coord   h)
3425 {
3426    INTERNAL_ENTRY
3427    sd->w = w;
3428    sd->h = h;
3429    _smart_reconfigure(sd);
3430 }
3431
3432 static void
3433 _smart_show(Evas_Object *obj)
3434 {
3435    Eina_List *list;
3436    Evas_Object *o;
3437    INTERNAL_ENTRY
3438    if ((list = evas_object_smart_members_get(obj)))
3439      {
3440         EINA_LIST_FREE(list, o)
3441           {
3442              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3443              evas_object_show(o);
3444           }
3445      }
3446 }
3447
3448 static void
3449 _smart_hide(Evas_Object *obj)
3450 {
3451    Eina_List *list;
3452    Evas_Object *o;
3453    INTERNAL_ENTRY
3454
3455    list = evas_object_smart_members_get(obj);
3456    EINA_LIST_FREE(list, o)
3457      {
3458         if (evas_object_data_get(o, "_elm_leaveme")) continue;
3459         evas_object_hide(o);
3460      }
3461 }
3462
3463 static void
3464 _smart_color_set(Evas_Object *obj,
3465                  int          r,
3466                  int          g,
3467                  int          b,
3468                  int          a)
3469 {
3470    Eina_List *list;
3471    Evas_Object *o;
3472    INTERNAL_ENTRY
3473    if ((list = evas_object_smart_members_get(obj)))
3474      {
3475         EINA_LIST_FREE(list, o)
3476           {
3477              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3478              evas_object_color_set(o, r, g, b, a);
3479           }
3480      }
3481 }
3482
3483 static void
3484 _smart_clip_set(Evas_Object *obj,
3485                 Evas_Object *clip)
3486 {
3487    Eina_List *list;
3488    Evas_Object *o;
3489    INTERNAL_ENTRY
3490    if ((list = evas_object_smart_members_get(obj)))
3491      {
3492         EINA_LIST_FREE(list, o)
3493           {
3494              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3495              evas_object_clip_set(o, clip);
3496           }
3497      }
3498 }
3499
3500 static void
3501 _smart_clip_unset(Evas_Object *obj)
3502 {
3503    Eina_List *list;
3504    Evas_Object *o;
3505    INTERNAL_ENTRY
3506    if ((list = evas_object_smart_members_get(obj)))
3507      {
3508         EINA_LIST_FREE(list, o)
3509           {
3510              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3511              evas_object_clip_unset(o);
3512           }
3513      }
3514 }
3515
3516 static void
3517 _smart_calculate(Evas_Object *obj)
3518 {
3519    INTERNAL_ENTRY
3520    if (sd->changed_func) sd->changed_func(obj);
3521 }
3522
3523 /* never need to touch this */
3524 static void
3525 _smart_init(void)
3526 {
3527    if (_e_smart) return;
3528      {
3529         static const Evas_Smart_Class sc =
3530           {
3531              SMART_NAME,
3532              EVAS_SMART_CLASS_VERSION,
3533              _smart_add,
3534              _smart_del,
3535              _smart_move,
3536              _smart_resize,
3537              _smart_show,
3538              _smart_hide,
3539              _smart_color_set,
3540              _smart_clip_set,
3541              _smart_clip_unset,
3542              _smart_calculate,
3543              NULL,
3544              NULL,
3545              NULL,
3546              NULL,
3547              NULL,
3548              NULL
3549           };
3550         _e_smart = evas_smart_class_new(&sc);
3551      }
3552 }
3553
3554 /* happy debug functions */
3555 #ifdef ELM_DEBUG
3556 static void
3557 _sub_obj_tree_dump(const Evas_Object *obj,
3558                    int                lvl)
3559 {
3560    int i;
3561
3562    for (i = 0; i < lvl * 3; i++)
3563      putchar(' ');
3564
3565    if (_elm_widget_is(obj))
3566      {
3567         Eina_List *l;
3568         INTERNAL_ENTRY
3569         printf("+ %s(%p)\n",
3570                sd->type,
3571                obj);
3572         if (sd->resize_obj)
3573           _sub_obj_tree_dump(sd->resize_obj, lvl + 1);
3574         EINA_LIST_FOREACH(sd->subobjs, l, obj)
3575           {
3576              if (obj != sd->resize_obj)
3577                _sub_obj_tree_dump(obj, lvl + 1);
3578           }
3579      }
3580    else
3581      printf("+ %s(%p)\n", evas_object_type_get(obj), obj);
3582 }
3583
3584 static void
3585 _sub_obj_tree_dot_dump(const Evas_Object *obj,
3586                        FILE              *output)
3587 {
3588    if (!_elm_widget_is(obj))
3589      return;
3590    INTERNAL_ENTRY
3591
3592    Eina_Bool visible = evas_object_visible_get(obj);
3593    Eina_Bool disabled = elm_widget_disabled_get(obj);
3594    Eina_Bool focused = elm_widget_focus_get(obj);
3595    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
3596
3597    if (sd->parent_obj)
3598      {
3599         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
3600
3601         if (focused)
3602           fprintf(output, ", style=bold");
3603
3604         if (!visible)
3605           fprintf(output, ", color=gray28");
3606
3607         fprintf(output, " ];\n");
3608      }
3609
3610    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
3611                    "disabled: %d|focused: %d/%d|focus order:%d}\"", obj, obj, sd->type,
3612            evas_object_name_get(obj), visible, disabled, focused, can_focus,
3613            sd->focus_order);
3614
3615    if (focused)
3616      fprintf(output, ", style=bold");
3617
3618    if (!visible)
3619      fprintf(output, ", fontcolor=gray28");
3620
3621    if ((disabled) || (!visible))
3622      fprintf(output, ", color=gray");
3623
3624    fprintf(output, " ];\n");
3625
3626    Eina_List *l;
3627    Evas_Object *o;
3628    EINA_LIST_FOREACH(sd->subobjs, l, o)
3629      _sub_obj_tree_dot_dump(o, output);
3630 }
3631 #endif
3632
3633 EAPI void
3634 elm_widget_tree_dump(const Evas_Object *top)
3635 {
3636 #ifdef ELM_DEBUG
3637    _sub_obj_tree_dump(top, 0);
3638 #else
3639    return;
3640    (void)top;
3641 #endif
3642 }
3643
3644 EAPI void
3645 elm_widget_tree_dot_dump(const Evas_Object *top,
3646                          FILE              *output)
3647 {
3648 #ifdef ELM_DEBUG
3649    if (!_elm_widget_is(top))
3650      return;
3651    fprintf(output, "graph " " { node [shape=record];\n");
3652    _sub_obj_tree_dot_dump(top, output);
3653    fprintf(output, "}\n");
3654 #else
3655    return;
3656    (void)top;
3657    (void)output;
3658 #endif
3659 }