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