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