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