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