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