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