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