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