[atspi] try bottom-up search first for getting accessible object at x,y point
[platform/upstream/elementary.git] / src / lib / elm_widget.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
7 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #include <Elementary.h>
10
11 #include "elm_priv.h"
12 #include "elm_widget_container.h"
13 #include "elm_interface_scrollable.h"
14
15 #define MY_CLASS ELM_WIDGET_CLASS
16
17 #define MY_CLASS_NAME "Elm_Widget"
18 #define MY_CLASS_NAME_LEGACY "elm_widget"
19
20 #define ELM_WIDGET_DATA_GET(o, wd)                             \
21   Elm_Widget_Smart_Data *wd = eo_data_scope_get(o, MY_CLASS)
22
23 #define API_ENTRY                                    \
24   ELM_WIDGET_DATA_GET(obj, sd);                      \
25   if ((!sd) || (!_elm_widget_is(obj)))
26 #define INTERNAL_ENTRY                               \
27   ELM_WIDGET_DATA_GET(obj, sd);                      \
28   if (!sd) return
29
30 #define ELM_WIDGET_FOCUS_GET(obj)                                          \
31   (eo_isa(obj, ELM_WIDGET_CLASS) &&                                    \
32    ((_elm_access_auto_highlight_get()) ? (elm_widget_highlight_get(obj)) : \
33                                          (elm_widget_focus_get(obj))))
34
35 const char SIG_WIDGET_FOCUSED[] = "focused";
36 const char SIG_WIDGET_UNFOCUSED[] = "unfocused";
37 const char SIG_WIDGET_LANG_CHANGED[] = "language,changed";
38 const char SIG_WIDGET_ACCESS_CHANGED[] = "access,changed";
39
40 // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
41 const char SIG_WIDGET_ATSPI_HIGHLIGHTED[] = "atspi,highlighted";
42 const char SIG_WIDGET_ATSPI_UNHIGHLIGHTED[] = "atspi,unhighlighted";
43 //
44
45 typedef struct _Elm_Event_Cb_Data         Elm_Event_Cb_Data;
46 typedef struct _Elm_Label_Data            Elm_Label_Data;
47 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
48
49 struct _Elm_Event_Cb_Data
50 {
51    Elm_Event_Cb func;
52    const void  *data;
53 };
54
55 struct _Elm_Label_Data
56 {
57    const char *part;
58    const char *text;
59 };
60
61 struct _Elm_Translate_String_Data
62 {
63    EINA_INLIST;
64    Eina_Stringshare *id;
65    Eina_Stringshare *domain;
66    Eina_Stringshare *string;
67    Eina_Bool   preset : 1;
68 };
69
70 /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
71 static void
72 _elm_widget_evas_object_paragraph_direction_set_internal(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir);
73 /* END */
74
75 /* local subsystem globals */
76 static unsigned int focus_order = 0;
77
78 static inline Eina_Bool
79 _elm_widget_is(const Evas_Object *obj)
80 {
81    return eo_isa(obj, MY_CLASS);
82 }
83
84 static inline Eina_Bool
85 _is_focusable(Evas_Object *obj)
86 {
87    API_ENTRY return EINA_FALSE;
88    return sd->can_focus || (sd->child_can_focus);
89 }
90
91 static inline Eina_Bool
92 _is_focused(Evas_Object *obj)
93 {
94    API_ENTRY return EINA_FALSE;
95    return sd->focused;
96 }
97
98 static inline Eina_Bool
99 _elm_scrollable_is(const Evas_Object *obj)
100 {
101    INTERNAL_ENTRY EINA_FALSE;
102    return
103       eo_isa(obj, ELM_INTERFACE_SCROLLABLE_MIXIN);
104 }
105
106 static void
107 elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled);
108 static Eina_Bool
109 _on_sub_obj_del(void *data,
110                 Eo *obj,
111                 const Eo_Event_Description *desc,
112                 void *event_info);
113 static Eina_Bool
114 _on_sub_obj_hide(void *data,
115                  Eo *obj,
116                  const Eo_Event_Description *desc,
117                  void *event_info);
118 static Eina_Bool
119 _propagate_event(void *data,
120                  Eo *obj,
121                  const Eo_Event_Description *desc,
122                  void *event_info);
123
124 EO_CALLBACKS_ARRAY_DEFINE(elm_widget_subitems_callbacks,
125                           { EVAS_OBJECT_EVENT_DEL, _on_sub_obj_del },
126                           { EVAS_OBJECT_EVENT_HIDE, _on_sub_obj_hide });
127 EO_CALLBACKS_ARRAY_DEFINE(efl_subitems_callbacks,
128                           { EVAS_OBJECT_EVENT_DEL, _on_sub_obj_del });
129 EO_CALLBACKS_ARRAY_DEFINE(focus_callbacks,
130                           { EVAS_OBJECT_EVENT_KEY_DOWN, _propagate_event },
131                           { EVAS_OBJECT_EVENT_KEY_UP, _propagate_event },
132                           { EVAS_OBJECT_EVENT_MOUSE_WHEEL, _propagate_event });
133
134 static inline void
135 _callbacks_add(Eo *widget, void *data)
136 {
137    if (_elm_widget_is(widget))
138      {
139         eo_do(widget,
140               eo_event_callback_array_add(elm_widget_subitems_callbacks(), data));
141      }
142    else
143      {
144         eo_do(widget,
145               eo_event_callback_array_add(efl_subitems_callbacks(), data));
146      }
147 }
148
149 static inline void
150 _callbacks_del(Eo *widget, void *data)
151 {
152    if (_elm_widget_is(widget))
153      {
154         eo_do(widget,
155               eo_event_callback_array_del(elm_widget_subitems_callbacks(), data));
156      }
157    else
158      {
159         eo_do(widget,
160               eo_event_callback_array_del(efl_subitems_callbacks(), data));
161      }
162 }
163
164 void
165 _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *eo_it)
166 {
167    const char *str;
168
169    if (!eo_it) return;
170    if (eo_isa(eo_it, ELM_WIDGET_ITEM_CLASS))
171      {
172         Elm_Widget_Item_Data *it = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS);
173
174         if (eo_isa(it->view, ELM_LAYOUT_CLASS))
175           str = edje_object_data_get(elm_layout_edje_get(it->view), "focus_highlight");
176         else
177           str = edje_object_data_get(it->view, "focus_highlight");
178      }
179    else
180       str = edje_object_data_get(((Elm_Widget_Item_Data *)eo_it)->view, "focus_highlight");
181    if ((str) && (!strcmp(str, "on")))
182      elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
183    else
184      elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
185 }
186
187 void
188 _elm_widget_focus_highlight_start(const Evas_Object *obj)
189 {
190    Evas_Object *top = elm_widget_top_get(obj);
191
192    if (top && eo_isa(top, ELM_WIN_CLASS))
193      _elm_win_focus_highlight_start(top);
194 }
195
196 Evas_Object *
197 _elm_widget_focus_highlight_object_get(const Evas_Object *obj)
198 {
199    Evas_Object *top = elm_widget_top_get(obj);
200
201    if (top && eo_isa(top, ELM_WIN_CLASS))
202      return _elm_win_focus_highlight_object_get(top);
203    return NULL;
204 }
205
206 EAPI Eina_Bool
207 elm_widget_focus_highlight_enabled_get(const Evas_Object *obj)
208 {
209    const Evas_Object *win = elm_widget_top_get(obj);
210
211    if (win && eo_isa(win, ELM_WIN_CLASS))
212      return elm_win_focus_highlight_enabled_get(win);
213    return EINA_FALSE;
214 }
215
216 /**
217  * @internal
218  *
219  * Resets the mirrored mode from the system mirror mode for widgets that are in
220  * automatic mirroring mode. This function does not call elm_widget_theme.
221  *
222  * @param obj The widget.
223  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
224  */
225 static void
226 _elm_widget_mirrored_reload(Evas_Object *obj)
227 {
228    API_ENTRY return;
229    Eina_Bool mirrored = elm_config_mirrored_get();
230
231    if (elm_widget_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
232      {
233         sd->is_mirrored = mirrored;
234      }
235 }
236
237 EOLIAN static Eina_Bool
238 _elm_widget_on_focus_region(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x EINA_UNUSED, Evas_Coord *y EINA_UNUSED, Evas_Coord *w EINA_UNUSED, Evas_Coord *h EINA_UNUSED)
239 {
240    WRN("The %s widget does not implement the \"on_focus_region\" function.",
241        eo_class_name_get(eo_class_get(obj)));
242
243    return EINA_FALSE;
244 }
245
246 static void
247 _parents_focus(Evas_Object *obj)
248 {
249    for (; obj; obj = elm_widget_parent_get(obj))
250      {
251         INTERNAL_ENTRY;
252         if (sd->focused) return;
253         sd->focused = 1;
254      }
255 }
256
257 static void
258 _parents_unfocus(Evas_Object *obj)
259 {
260    for (; obj; obj = elm_widget_parent_get(obj))
261      {
262         INTERNAL_ENTRY;
263         if (!sd->focused) return;
264         sd->focused = 0;
265      }
266 }
267
268 static Eina_Bool
269 _on_sub_obj_hide(void *data EINA_UNUSED,
270                  Eo *obj,
271                  const Eo_Event_Description *desc EINA_UNUSED,
272                  void *event_info EINA_UNUSED)
273 {
274    elm_widget_focus_hide_handle(obj);
275    return EO_CALLBACK_CONTINUE;
276 }
277
278 static Eina_Bool
279 _on_sub_obj_del(void *data,
280                 Eo *obj,
281                 const Eo_Event_Description *desc EINA_UNUSED,
282                 void *event_info EINA_UNUSED)
283 {
284    ELM_WIDGET_DATA_GET(data, sd);
285
286    if (_elm_widget_is(obj))
287      {
288         if (_is_focused((Eo *)obj)) _parents_unfocus(sd->obj);
289      }
290    if (obj == sd->resize_obj)
291      {
292         /* already dels sub object */
293         elm_widget_resize_object_set(sd->obj, NULL, EINA_TRUE);
294      }
295    else if (obj == sd->hover_obj)
296      {
297         sd->hover_obj = NULL;
298      }
299    else
300      {
301         if (!elm_widget_sub_object_del(sd->obj, obj))
302           ERR("failed to remove sub object %p from %p\n", obj, sd->obj);
303      }
304
305    return EO_CALLBACK_CONTINUE;
306 }
307
308 static const Evas_Smart_Cb_Description _smart_callbacks[] =
309 {
310    {SIG_WIDGET_FOCUSED, ""},
311    {SIG_WIDGET_UNFOCUSED, ""},
312    {SIG_WIDGET_LANG_CHANGED, ""},
313    {SIG_WIDGET_ACCESS_CHANGED, ""},
314    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
315    {SIG_WIDGET_ATSPI_HIGHLIGHTED, ""},
316    {SIG_WIDGET_ATSPI_UNHIGHLIGHTED, ""},
317    //
318    {NULL, NULL}
319 };
320
321 static void
322 _obj_mouse_down(void *data,
323                 Evas *e EINA_UNUSED,
324                 Evas_Object *obj EINA_UNUSED,
325                 void *event_info)
326 {
327    Evas_Object *top;
328
329    ELM_WIDGET_DATA_GET(data, sd);
330    Evas_Event_Mouse_Down *ev = event_info;
331    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
332
333    top = elm_widget_top_get(data);
334    if (top && eo_isa(top, ELM_WIN_CLASS)) _elm_win_focus_auto_hide(top);
335    sd->still_in = EINA_TRUE;
336 }
337
338 static void
339 _obj_mouse_move(void *data,
340                 Evas *e EINA_UNUSED,
341                 Evas_Object *obj,
342                 void *event_info)
343 {
344    ELM_WIDGET_DATA_GET(data, sd);
345    Evas_Event_Mouse_Move *ev = event_info;
346    if (!sd->still_in) return;
347
348    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
349      sd->still_in = EINA_FALSE;
350    else
351      {
352         Evas_Coord x, y, w, h;
353         evas_object_geometry_get(obj, &x, &y, &w, &h);
354         if (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y))
355           sd->still_in = EINA_FALSE;
356      }
357 }
358
359 static void
360 _obj_mouse_up(void *data,
361               Evas *e EINA_UNUSED,
362               Evas_Object *obj,
363               void *event_info EINA_UNUSED)
364 {
365    ELM_WIDGET_DATA_GET(data, sd);
366    if (sd->still_in &&
367        (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_CLICK))
368      elm_widget_focus_mouse_up_handle(obj);
369
370    sd->still_in = EINA_FALSE;
371 }
372
373 static void
374 _obj_mouse_in(void *data,
375               Evas *e EINA_UNUSED,
376               Evas_Object *obj,
377               void *event_info EINA_UNUSED)
378 {
379    ELM_WIDGET_DATA_GET(data, sd);
380    if (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_IN)
381      elm_widget_focus_mouse_up_handle(obj);
382 }
383
384 EOLIAN static void
385 _elm_widget_evas_object_smart_add(Eo *obj, Elm_Widget_Smart_Data *priv)
386 {
387
388    priv->obj = obj;
389    priv->mirrored_auto_mode = EINA_TRUE; /* will follow system locale
390                                           * settings */
391    priv->focus_move_policy_auto_mode = EINA_TRUE;
392    priv->focus_region_show_mode = ELM_FOCUS_REGION_SHOW_WIDGET;
393    elm_widget_can_focus_set(obj, EINA_TRUE);
394    priv->is_mirrored = elm_config_mirrored_get();
395    priv->focus_move_policy = _elm_config->focus_move_policy;
396
397    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
398                                   _obj_mouse_down, obj);
399    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
400                                   _obj_mouse_move, obj);
401    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
402                                   _obj_mouse_up, obj);
403    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_IN,
404                                   _obj_mouse_in, obj);
405    /* just a helper for inheriting classes */
406    if (priv->resize_obj)
407      {
408         Evas_Object *r_obj = priv->resize_obj;
409         priv->resize_obj = NULL;
410
411         elm_widget_resize_object_set(obj, r_obj, EINA_TRUE);
412      }
413 }
414
415 static void
416 _if_focused_revert(Evas_Object *obj,
417                    Eina_Bool can_focus_only)
418 {
419    Evas_Object *top;
420    Evas_Object *newest = NULL;
421    unsigned int newest_focus_order = 0;
422
423    INTERNAL_ENTRY;
424
425    if (!sd->focused) return;
426    if (!sd->parent_obj) return;
427
428    top = elm_widget_top_get(sd->parent_obj);
429    if (top)
430      {
431         newest = elm_widget_newest_focus_order_get
432            (top, &newest_focus_order, can_focus_only);
433         if (newest)
434           {
435              if (newest == top)
436                {
437                   ELM_WIDGET_DATA_GET(newest, sd2);
438                   if (!sd2) return;
439
440                   if (!_is_focused(newest))
441                     elm_widget_focus_steal(newest, NULL);
442                   else
443                     {
444                        if (sd2->resize_obj && _is_focused(sd2->resize_obj))
445                          elm_widget_focused_object_clear(sd2->resize_obj);
446                        else
447                          {
448                             const Eina_List *l;
449                             Evas_Object *child;
450                             EINA_LIST_FOREACH(sd2->subobjs, l, child)
451                               {
452                                  if (_is_focused(child))
453                                    {
454                                       elm_widget_focused_object_clear(child);
455                                       break;
456                                    }
457                               }
458                          }
459                     }
460                   evas_object_focus_set(newest, EINA_TRUE);
461                }
462              else
463                {
464                   elm_object_focus_set(newest, EINA_FALSE);
465                   elm_object_focus_set(newest, EINA_TRUE);
466                }
467           }
468      }
469 }
470
471 EOLIAN static void
472 _elm_widget_evas_object_smart_del(Eo *obj, Elm_Widget_Smart_Data *sd)
473 {
474    Evas_Object *sobj;
475    Elm_Translate_String_Data *ts;
476    Elm_Event_Cb_Data *ecb;
477
478    if (sd->hover_obj)
479      {
480         /* detach it from us */
481         _callbacks_del(sd->hover_obj, obj);
482         sd->hover_obj = NULL;
483      }
484
485    while (sd->subobjs)
486      {
487         sobj = eina_list_data_get(sd->subobjs);
488
489         /* let the objects clean-up themselves and get rid of this list */
490         if (!elm_widget_sub_object_del(obj, sobj))
491           {
492              ERR("failed to remove sub object %p from %p\n", sobj, obj);
493              sd->subobjs = eina_list_remove_list
494                  (sd->subobjs, sd->subobjs);
495           }
496         evas_object_del(sobj);
497      }
498    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
499    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
500    while (sd->translate_strings)
501      {
502         ts = EINA_INLIST_CONTAINER_GET(sd->translate_strings,
503                                        Elm_Translate_String_Data);
504         eina_stringshare_del(ts->id);
505         eina_stringshare_del(ts->domain);
506         eina_stringshare_del(ts->string);
507         sd->translate_strings = eina_inlist_remove(sd->translate_strings,
508                                                    sd->translate_strings);
509         free(ts);
510      }
511
512    EINA_LIST_FREE(sd->event_cb, ecb)
513       free(ecb);
514
515    eina_stringshare_del(sd->style);
516    if (sd->theme) elm_theme_free(sd->theme);
517    _if_focused_revert(obj, EINA_TRUE);
518    elm_widget_focus_custom_chain_unset(obj);
519    eina_stringshare_del(sd->access_info);
520    eina_stringshare_del(sd->accessible_name);
521    evas_object_smart_data_set(obj, NULL);
522 }
523
524 static void
525 _smart_reconfigure(Elm_Widget_Smart_Data *sd)
526 {
527    if (sd->resize_obj)
528      {
529         evas_object_move(sd->resize_obj, sd->x, sd->y);
530         evas_object_resize(sd->resize_obj, sd->w, sd->h);
531      }
532    if (sd->hover_obj)
533      {
534         evas_object_move(sd->hover_obj, sd->x, sd->y);
535         evas_object_resize(sd->hover_obj, sd->w, sd->h);
536      }
537 }
538
539 EOLIAN static void
540 _elm_widget_evas_object_smart_move(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y)
541 {
542    sd->x = x;
543    sd->y = y;
544
545    _smart_reconfigure(sd);
546 }
547
548 EOLIAN static void
549 _elm_widget_evas_object_smart_resize(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord w, Evas_Coord h)
550 {
551    sd->w = w;
552    sd->h = h;
553
554    _smart_reconfigure(sd);
555 }
556
557 EOLIAN static void
558 _elm_widget_evas_object_smart_show(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
559 {
560    Eina_Iterator *it;
561    Evas_Object *o;
562
563    if (_elm_atspi_enabled())
564      {
565         Eo *parent;
566         eo_do(obj, parent = elm_interface_atspi_accessible_parent_get());
567         if (parent) elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, obj);
568      }
569
570    it = evas_object_smart_iterator_new(obj);
571    EINA_ITERATOR_FOREACH(it, o)
572      {
573        if (evas_object_data_get(o, "_elm_leaveme")) continue;
574        evas_object_show(o);
575      }
576    eina_iterator_free(it);
577
578    if (_elm_atspi_enabled())
579      {
580         elm_interface_atspi_accessible_added(obj);
581         if (_elm_widget_onscreen_is(obj))
582            elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_TRUE);
583      }
584 }
585
586 EOLIAN static void
587 _elm_widget_evas_object_smart_hide(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
588 {
589    Eina_Iterator *it;
590    Evas_Object *o;
591
592    it = evas_object_smart_iterator_new(obj);
593    EINA_ITERATOR_FOREACH(it, o)
594      {
595         if (evas_object_data_get(o, "_elm_leaveme")) continue;
596         evas_object_hide(o);
597      }
598    eina_iterator_free(it);
599
600    if (_elm_atspi_enabled())
601      elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_FALSE);
602 }
603
604 EOLIAN static void
605 _elm_widget_evas_object_smart_color_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, int r, int g, int b, int a)
606 {
607    Eina_Iterator *it;
608    Evas_Object *o;
609
610    it = evas_object_smart_iterator_new(obj);
611    EINA_ITERATOR_FOREACH(it, o)
612      {
613        if (evas_object_data_get(o, "_elm_leaveme")) continue;
614        evas_object_color_set(o, r, g, b, a);
615      }
616    eina_iterator_free(it);
617 }
618
619 EOLIAN static void
620 _elm_widget_evas_object_smart_clip_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *clip)
621 {
622    Eina_Iterator *it;
623    Evas_Object *o;
624
625    it = evas_object_smart_iterator_new(obj);
626    EINA_ITERATOR_FOREACH(it, o)
627      {
628        if (evas_object_data_get(o, "_elm_leaveme")) continue;
629        evas_object_clip_set(o, clip);
630      }
631    eina_iterator_free(it);
632 }
633
634 EOLIAN static void
635 _elm_widget_evas_object_smart_clip_unset(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
636 {
637    Eina_Iterator *it;
638    Evas_Object *o;
639
640    it = evas_object_smart_iterator_new(obj);
641    EINA_ITERATOR_FOREACH(it, o)
642      {
643        if (evas_object_data_get(o, "_elm_leaveme")) continue;
644        evas_object_clip_unset(o);
645      }
646    eina_iterator_free(it);
647 }
648
649 EOLIAN static void
650 _elm_widget_evas_object_smart_calculate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
651 {
652    /* a NO-OP, on the base */
653 }
654
655 EOLIAN static void
656 _elm_widget_evas_object_smart_member_add(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child)
657 {
658    int r, g, b, a;
659    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(child));
660
661    if (evas_object_data_get(child, "_elm_leaveme")) return;
662
663    evas_object_color_get(obj, &r, &g, &b, &a);
664    evas_object_color_set(child, r, g, b, a);
665
666    evas_object_clip_set(child, evas_object_clip_get(obj));
667
668    if (evas_object_visible_get(obj))
669      evas_object_show(child);
670    else
671      evas_object_hide(child);
672 }
673
674 EOLIAN static void
675 _elm_widget_evas_object_smart_member_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child)
676 {
677    if (!evas_object_data_get(child, "_elm_leaveme"))
678       evas_object_clip_unset(child);
679    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_del(child));
680 }
681
682 // internal funcs
683 /**
684  * @internal
685  *
686  * Check if the widget has its own focus next function.
687  *
688  * @param obj The widget.
689  * @return focus next function is implemented/unimplemented.
690  * (@c EINA_TRUE = implemented/@c EINA_FALSE = unimplemented.)
691  */
692 static inline Eina_Bool
693 _elm_widget_focus_chain_manager_is(const Evas_Object *obj)
694 {
695    ELM_WIDGET_CHECK(obj) EINA_FALSE;
696
697    Eina_Bool manager_is = EINA_FALSE;
698    eo_do((Eo *)obj, manager_is = elm_obj_widget_focus_next_manager_is());
699    return manager_is;
700 }
701
702 static inline Eina_Bool
703 _internal_elm_widget_focus_direction_manager_is(const Evas_Object *obj)
704 {
705    ELM_WIDGET_CHECK(obj) EINA_FALSE;
706
707    Eina_Bool manager_is = EINA_FALSE;
708    eo_do((Eo *)obj, manager_is = elm_obj_widget_focus_direction_manager_is());
709    return manager_is;
710 }
711
712 static void
713 _propagate_x_drag_lock(Evas_Object *obj,
714                        int dir)
715 {
716    INTERNAL_ENTRY;
717    if (sd->parent_obj)
718      {
719         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
720         if (sd2)
721           {
722              sd2->child_drag_x_locked += dir;
723              _propagate_x_drag_lock(sd->parent_obj, dir);
724           }
725      }
726 }
727
728 static void
729 _propagate_y_drag_lock(Evas_Object *obj,
730                        int dir)
731 {
732    INTERNAL_ENTRY;
733    if (sd->parent_obj)
734      {
735         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
736         if (sd2)
737           {
738              sd2->child_drag_y_locked += dir;
739              _propagate_y_drag_lock(sd->parent_obj, dir);
740           }
741      }
742 }
743
744 static Eina_Bool
745 _propagate_event(void *data EINA_UNUSED,
746                  Eo *obj,
747                  const Eo_Event_Description *desc,
748                  void *event_info)
749 {
750    INTERNAL_ENTRY EO_CALLBACK_CONTINUE;
751    Evas_Callback_Type type;
752    Evas_Event_Flags *event_flags = NULL;
753
754    if (desc == EVAS_OBJECT_EVENT_KEY_DOWN)
755      {
756         Evas_Event_Key_Down *ev = event_info;
757         event_flags = &(ev->event_flags);
758         type = EVAS_CALLBACK_KEY_DOWN;
759      }
760    else if (desc == EVAS_OBJECT_EVENT_KEY_UP)
761      {
762         Evas_Event_Key_Up *ev = event_info;
763         event_flags = &(ev->event_flags);
764         type = EVAS_CALLBACK_KEY_UP;
765      }
766    else if (desc == EVAS_OBJECT_EVENT_MOUSE_WHEEL)
767      {
768         Evas_Event_Mouse_Wheel *ev = event_info;
769         event_flags = &(ev->event_flags);
770         type = EVAS_CALLBACK_MOUSE_WHEEL;
771      }
772    else
773      return EO_CALLBACK_CONTINUE;
774
775    elm_widget_event_propagate(obj, type, event_info, event_flags);
776
777    return EO_CALLBACK_CONTINUE;
778 }
779
780 /**
781  * @internal
782  *
783  * If elm_widget_focus_region_get() returns EINA_FALSE, this function will
784  * ignore region show action.
785  */
786 EOLIAN static void
787 _elm_widget_focus_region_show(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
788 {
789    Evas_Coord x, y, w, h, ox, oy;
790    Evas_Object *o;
791
792    o = elm_widget_parent_get(obj);
793    if (!o) return;
794
795    if (!elm_widget_focus_region_get(obj, &x, &y, &w, &h))
796      return;
797
798    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
799
800    while (o)
801      {
802         Evas_Coord px, py;
803         evas_object_geometry_get(o, &px, &py, NULL, NULL);
804
805         if (_elm_scrollable_is(o) && !elm_widget_disabled_get(o))
806           {
807              Evas_Coord sx, sy;
808              eo_do(o, elm_interface_scrollable_content_region_get(&sx, &sy, NULL, NULL));
809
810              // Get the object's on_focus_region position relative to the scroller.
811              Evas_Coord rx, ry;
812              rx = ox + x - px + sx;
813              ry = oy + y - py + sy;
814
815              switch (_elm_config->focus_autoscroll_mode)
816                {
817                 case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
818                    eo_do(o, elm_interface_scrollable_content_region_show(rx, ry, w, h));
819                    break;
820                 case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
821                    eo_do(o, elm_interface_scrollable_region_bring_in(rx, ry, w, h));
822                    break;
823                 default:
824                    break;
825                }
826
827              if (!elm_widget_focus_region_get(o, &x, &y, &w, &h))
828                {
829                   o = elm_widget_parent_get(o);
830                   continue;
831                }
832           }
833         else
834           {
835              x += ox - px;
836              y += oy - py;
837              ox = px;
838              oy = py;
839           }
840         o = elm_widget_parent_get(o);
841      }
842 }
843
844 EOLIAN static Eina_Bool
845 _elm_widget_focus_highlight_style_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *style)
846 {
847    if (eina_stringshare_replace(&sd->focus_highlight_style, style)) return EINA_TRUE;
848    return EINA_FALSE;
849 }
850
851 EOLIAN static const char*
852 _elm_widget_focus_highlight_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
853 {
854    return sd->focus_highlight_style;
855 }
856
857 static void
858 _parent_focus(Evas_Object *obj, Elm_Object_Item *item)
859 {
860    API_ENTRY return;
861
862    if (sd->focused) return;
863
864    Evas_Object *o = elm_widget_parent_get(obj);
865    sd->focus_order_on_calc = EINA_TRUE;
866
867    if (o) _parent_focus(o, item);
868
869    if (!sd->focus_order_on_calc)
870      return;  /* we don't want to override it if by means of any of the
871                  callbacks below one gets to calculate our order
872                  first. */
873
874    focus_order++;
875    sd->focus_order = focus_order;
876    sd->focused = EINA_TRUE;
877
878    if (sd->top_win_focused)
879      eo_do(obj, elm_obj_widget_on_focus(item));
880    sd->focus_order_on_calc = EINA_FALSE;
881
882    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
883      _elm_access_highlight_set(obj);
884 }
885
886 static void
887 _elm_object_focus_chain_del_cb(void *data,
888                                Evas *e EINA_UNUSED,
889                                Evas_Object *obj,
890                                void *event_info EINA_UNUSED)
891 {
892    ELM_WIDGET_DATA_GET(data, sd);
893
894    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
895 }
896
897 EOLIAN static void
898 _elm_widget_parent_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *parent EINA_UNUSED)
899 {
900 }
901
902 EAPI Eina_Bool
903 elm_widget_api_check(int ver)
904 {
905    if (ver != ELM_INTERNAL_API_VERSION)
906      {
907         CRI("Elementary widget api versions do not match");
908         return EINA_FALSE;
909      }
910    return EINA_TRUE;
911 }
912
913 EAPI Eina_Bool
914 elm_widget_access(Evas_Object *obj,
915                   Eina_Bool is_access)
916 {
917    const Eina_List *l;
918    Evas_Object *child;
919    Eina_Bool ret = EINA_TRUE;
920
921    API_ENTRY return EINA_FALSE;
922    EINA_LIST_FOREACH(sd->subobjs, l, child)
923      {
924         if (elm_widget_is(child))
925           ret &= elm_widget_access(child, is_access);
926      }
927
928    eo_do(obj, elm_obj_widget_access(is_access));
929    eo_do(obj, eo_event_callback_call(ELM_WIDGET_EVENT_ACCESS_CHANGED, NULL));
930
931    return ret;
932 }
933
934 //TIZEN_ONLY(20160822): When atspi mode is dynamically switched on/off,
935 //register/unregister access objects accordingly.
936 EAPI Eina_Bool
937 elm_widget_atspi(Evas_Object *obj,
938                   Eina_Bool is_atspi)
939 {
940    const Eina_List *l;
941    Evas_Object *child;
942    Eina_Bool ret = EINA_TRUE;
943
944    API_ENTRY return EINA_FALSE;
945    EINA_LIST_FOREACH(sd->subobjs, l, child)
946      {
947         if (elm_widget_is(child))
948           ret &= elm_widget_atspi(child, is_atspi);
949      }
950    eo_do(obj, elm_obj_widget_atspi(is_atspi));
951
952    return ret;
953 }
954
955 EOLIAN static void
956 _elm_widget_atspi(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_atspi EINA_UNUSED)
957 {
958 }
959 //
960
961 EOLIAN static void
962 _elm_widget_access(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_access EINA_UNUSED)
963 {
964 }
965
966 EAPI Elm_Theme_Apply
967 elm_widget_theme(Evas_Object *obj)
968 {
969    const Eina_List *l;
970    Evas_Object *child;
971    Elm_Tooltip *tt;
972    Elm_Cursor *cur;
973    Elm_Theme_Apply ret = ELM_THEME_APPLY_SUCCESS;
974
975    API_ENTRY return ELM_THEME_APPLY_FAILED;
976
977    EINA_LIST_FOREACH(sd->subobjs, l, child)
978      if (_elm_widget_is(child))
979        ret &= elm_widget_theme(child);
980
981    if (sd->hover_obj) ret &= elm_widget_theme(sd->hover_obj);
982
983    EINA_LIST_FOREACH(sd->tooltips, l, tt)
984      elm_tooltip_theme(tt);
985    EINA_LIST_FOREACH(sd->cursors, l, cur)
986      elm_cursor_theme(cur);
987
988    Elm_Theme_Apply ret2 = ELM_THEME_APPLY_FAILED;
989    eo_do(obj, ret2 = elm_obj_widget_theme_apply());
990    ret &= ret2;
991
992    return ret;
993 }
994
995 EAPI void
996 elm_widget_theme_specific(Evas_Object *obj,
997                           Elm_Theme *th,
998                           Eina_Bool force)
999 {
1000    const Eina_List *l;
1001    Evas_Object *child;
1002    Elm_Tooltip *tt;
1003    Elm_Cursor *cur;
1004    Elm_Theme *th2, *thdef;
1005
1006    API_ENTRY return;
1007
1008    thdef = elm_theme_default_get();
1009    if (!th) th = thdef;
1010    if (!force)
1011      {
1012         th2 = sd->theme;
1013         if (!th2) th2 = thdef;
1014         while (th2)
1015           {
1016              if (th2 == th)
1017                {
1018                   force = EINA_TRUE;
1019                   break;
1020                }
1021              if (th2 == thdef) break;
1022              th2 = th2->ref_theme;
1023              if (!th2) th2 = thdef;
1024           }
1025      }
1026    if (!force) return;
1027    EINA_LIST_FOREACH(sd->subobjs, l, child)
1028      {
1029         if (elm_widget_is(child))
1030           elm_widget_theme_specific(child, th, force);
1031      }
1032    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
1033    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1034      elm_tooltip_theme(tt);
1035    EINA_LIST_FOREACH(sd->cursors, l, cur)
1036      elm_cursor_theme(cur);
1037    eo_do(obj, elm_obj_widget_theme_apply());
1038 }
1039
1040 EOLIAN static Elm_Theme_Apply
1041 _elm_widget_theme_apply(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
1042 {
1043    _elm_widget_mirrored_reload(obj);
1044    if (elm_widget_disabled_get(obj))
1045      elm_widget_disabled_internal(obj, elm_widget_disabled_get(obj));
1046
1047    return ELM_THEME_APPLY_SUCCESS;
1048 }
1049
1050 /**
1051  * @internal
1052  *
1053  * Returns the widget's mirrored mode.
1054  *
1055  * @param obj The widget.
1056  * @return mirrored mode of the object.
1057  *
1058  **/
1059 EOLIAN static Eina_Bool
1060 _elm_widget_mirrored_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1061 {
1062    return sd->is_mirrored;
1063 }
1064
1065 /**
1066  * @internal
1067  *
1068  * Sets the widget's mirrored mode.
1069  *
1070  * @param obj The widget.
1071  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
1072  */
1073 EOLIAN static void
1074 _elm_widget_mirrored_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool mirrored)
1075 {
1076    mirrored = !!mirrored;
1077
1078    if (sd->is_mirrored == mirrored) return;
1079
1080    sd->is_mirrored = mirrored;
1081    elm_widget_theme(obj);
1082 }
1083
1084 /**
1085  * Returns the widget's mirrored mode setting.
1086  *
1087  * @param obj The widget.
1088  * @return mirrored mode setting of the object.
1089  *
1090  **/
1091 EOLIAN static Eina_Bool
1092 _elm_widget_mirrored_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1093 {
1094    return sd->mirrored_auto_mode;
1095 }
1096
1097 /**
1098  * @internal
1099  *
1100  * Sets the widget's mirrored mode setting.
1101  * When widget in automatic mode, it follows the system mirrored mode set by
1102  * elm_mirrored_set().
1103  * @param obj The widget.
1104  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
1105  */
1106 EOLIAN static void
1107 _elm_widget_mirrored_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
1108 {
1109    if (sd->mirrored_auto_mode != automatic)
1110      {
1111         sd->mirrored_auto_mode = automatic;
1112
1113         if (automatic)
1114           {
1115              elm_widget_mirrored_set(obj, elm_config_mirrored_get());
1116           }
1117      }
1118 }
1119
1120 EOLIAN static void
1121 _elm_widget_on_show_region_hook_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, region_hook_func_type func, void *data)
1122 {
1123    sd->on_show_region = func;
1124    sd->on_show_region_data = data;
1125 }
1126
1127 /*
1128  * @internal
1129  *
1130  * Add myself as a sub object of parent object
1131  *
1132  * @see elm_widget_sub_object_add()
1133  */
1134 EAPI Eina_Bool
1135 elm_widget_sub_object_parent_add(Evas_Object *sobj)
1136 {
1137    Eina_Bool ret = EINA_FALSE;
1138    Eo *parent = NULL;
1139
1140    eo_do(sobj, parent = eo_parent_get());
1141    if (!eo_isa(parent, ELM_WIDGET_CLASS))
1142      {
1143         ERR("You passed a wrong parent parameter (%p %s). "
1144             "Elementary widget's parent should be an elementary widget.", parent, evas_object_type_get(parent));
1145         return ret;
1146      }
1147
1148    eo_do(parent, ret = elm_obj_widget_sub_object_add(sobj));
1149
1150    return ret;
1151 }
1152
1153 /*
1154  * @internal
1155  *
1156  * Add sobj to obj's sub object.
1157  *
1158  * What does elementary sub object mean? This is unique in elementary, it
1159  * handles overall elementary policies between parent and sub objects.
1160  *   focus, access, deletion, theme, scale, mirror, scrollable child get,
1161  *   translate, name find, display mode set, orientation set, tree dump
1162  *   AUTOMATICALLY.
1163  *
1164  * @see elm_widget_sub_object_parent_add()
1165  */
1166 EOLIAN static Eina_Bool
1167 _elm_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1168 {
1169    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
1170
1171    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1172
1173    if (sobj == sd->parent_obj)
1174      {
1175         /* in this case, sobj must be an elm widget, or something
1176          * very wrong is happening */
1177         if (!_elm_widget_is(sobj)) return EINA_FALSE;
1178
1179         if (!elm_widget_sub_object_del(sobj, obj)) return EINA_FALSE;
1180         WRN("You passed a parent object of obj = %p as the sub object = %p!",
1181             obj, sobj);
1182      }
1183
1184    if (_elm_widget_is(sobj))
1185      {
1186         ELM_WIDGET_DATA_GET(sobj, sdc);
1187
1188         if (sdc->parent_obj == obj) goto end;
1189         if (sdc->parent_obj)
1190           {
1191              if (!elm_widget_sub_object_del(sdc->parent_obj, sobj))
1192                return EINA_FALSE;
1193           }
1194         sdc->parent_obj = obj;
1195
1196         if (!sdc->on_create)
1197           eo_do(sobj, elm_obj_widget_orientation_set(sd->orient_mode));
1198         else
1199           sdc->orient_mode = sd->orient_mode;
1200
1201         if (!sdc->on_create)
1202           {
1203              if (!sdc->disabled && (elm_widget_disabled_get(obj)))
1204                {
1205                   elm_widget_focus_disabled_handle(sobj);
1206                   eo_do(sobj, elm_obj_widget_disable());
1207                }
1208           }
1209
1210         _elm_widget_top_win_focused_set(sobj, sd->top_win_focused);
1211
1212         /* update child focusable-ness on self and parents, now that a
1213          * focusable child got in */
1214         if (!sd->child_can_focus && (_is_focusable(sobj)))
1215           {
1216              Elm_Widget_Smart_Data *sdp = sd;
1217
1218              sdp->child_can_focus = EINA_TRUE;
1219              while (sdp->parent_obj)
1220                {
1221                   sdp = eo_data_scope_get(sdp->parent_obj, MY_CLASS);
1222
1223                   if (sdp->child_can_focus) break;
1224
1225                   sdp->child_can_focus = EINA_TRUE;
1226                }
1227           }
1228      }
1229    else
1230      {
1231         void *data = evas_object_data_get(sobj, "elm-parent");
1232
1233         if (data)
1234           {
1235              if (data == obj) goto end;
1236              if (!elm_widget_sub_object_del(data, sobj)) return EINA_FALSE;
1237           }
1238      }
1239    sd->subobjs = eina_list_append(sd->subobjs, sobj);
1240    evas_object_data_set(sobj, "elm-parent", obj);
1241
1242    _callbacks_add(sobj, obj);
1243    if (_elm_widget_is(sobj))
1244      {
1245         ELM_WIDGET_DATA_GET(sobj, sdc);
1246
1247         /* NOTE: In the following two lines, 'sobj' is correct. Do not change it.
1248          * Due to elementary's scale policy, scale and pscale can be different in
1249          * some cases. This happens when sobj's previous parent and new parent have
1250          * different scale value.
1251          * For example, if sobj's previous parent's scale is 5 and new parent's scale
1252          * is 2 while sobj's scale is 0. Then 'pscale' is 5 and 'scale' is 2. So we
1253          * need to reset sobj's scale to 5.
1254          * Note that each widget's scale is 0 by default.
1255          */
1256         double scale, pscale = elm_widget_scale_get(sobj);
1257         Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
1258
1259         scale = elm_widget_scale_get(sobj);
1260         th = elm_widget_theme_get(sobj);
1261         mirrored = elm_widget_mirrored_get(sobj);
1262
1263         if (!sdc->on_create)
1264           {
1265              if ((scale != pscale) || (th != pth) || (pmirrored != mirrored))
1266                elm_widget_theme(sobj);
1267           }
1268
1269         if (_is_focused(sobj)) _parents_focus(obj);
1270
1271         elm_widget_display_mode_set(sobj,
1272               evas_object_size_hint_display_mode_get(obj));
1273         if (_elm_atspi_enabled() && !sdc->on_create)
1274           {
1275              Elm_Interface_Atspi_Accessible *aparent;
1276              eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
1277              if (obj == aparent)
1278                 elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, sobj);
1279           }
1280
1281         /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
1282         if (sdc->inherit_paragraph_direction &&
1283             (sdc->paragraph_direction != evas_object_paragraph_direction_get(obj)))
1284           {
1285              sdc->paragraph_direction = evas_object_paragraph_direction_get(obj);
1286              _elm_widget_evas_object_paragraph_direction_set_internal(sobj, sdc, sdc->paragraph_direction);
1287              eo_do_super(sobj, MY_CLASS, evas_obj_paragraph_direction_set(sdc->paragraph_direction));
1288           }
1289         /* END */
1290      }
1291
1292 end:
1293    return EINA_TRUE;
1294 }
1295
1296 EOLIAN static Eina_Bool
1297 _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1298 {
1299    Evas_Object *sobj_parent;
1300
1301    if (!sobj) return EINA_FALSE;
1302
1303    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1304
1305    sobj_parent = evas_object_data_del(sobj, "elm-parent");
1306    if (sobj_parent && sobj_parent != obj)
1307      {
1308         static int abort_on_warn = -1;
1309
1310         ERR("removing sub object %p (%s) from parent %p (%s), "
1311             "but elm-parent is different %p (%s)!",
1312             sobj, elm_widget_type_get(sobj), obj, elm_widget_type_get(obj),
1313             sobj_parent, elm_widget_type_get(sobj_parent));
1314
1315         if (EINA_UNLIKELY(abort_on_warn == -1))
1316           {
1317              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1318              else abort_on_warn = 0;
1319           }
1320         if (abort_on_warn == 1) abort();
1321
1322         return EINA_FALSE;
1323      }
1324
1325    if (_elm_widget_is(sobj))
1326      {
1327         if (_is_focused(sobj))
1328           {
1329              elm_widget_tree_unfocusable_set(sobj, EINA_TRUE);
1330              elm_widget_tree_unfocusable_set(sobj, EINA_FALSE);
1331           }
1332         if ((sd->child_can_focus) && (_is_focusable(sobj)))
1333           {
1334              Evas_Object *parent = obj;
1335
1336              /* update child focusable-ness on self and parents, now that a
1337               * focusable child is gone */
1338              while (parent)
1339                {
1340                   const Eina_List *l;
1341                   Evas_Object *subobj;
1342
1343                   ELM_WIDGET_DATA_GET(parent, sdp);
1344
1345                   sdp->child_can_focus = EINA_FALSE;
1346                   EINA_LIST_FOREACH(sdp->subobjs, l, subobj)
1347                     {
1348                        if ((subobj != sobj) && (_is_focusable(subobj)))
1349                          {
1350                             sdp->child_can_focus = EINA_TRUE;
1351                             break;
1352                          }
1353                     }
1354
1355                   /* break again, child_can_focus went back to
1356                    * original value */
1357                   if (sdp->child_can_focus) break;
1358                   parent = sdp->parent_obj;
1359                }
1360           }
1361         if (_elm_atspi_enabled() && !sd->on_destroy)
1362           {
1363              Elm_Interface_Atspi_Accessible *aparent;
1364              eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
1365              if (obj == aparent)
1366                 elm_interface_atspi_accessible_children_changed_del_signal_emit(obj, sobj);
1367           }
1368
1369         ELM_WIDGET_DATA_GET(sobj, sdc);
1370         sdc->parent_obj = NULL;
1371
1372         /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
1373         if (sdc->inherit_paragraph_direction &&
1374             (sdc->paragraph_direction != EVAS_BIDI_DIRECTION_NEUTRAL))
1375           {
1376              sdc->paragraph_direction = EVAS_BIDI_DIRECTION_NEUTRAL;
1377              _elm_widget_evas_object_paragraph_direction_set_internal(sobj, sdc, sdc->paragraph_direction);
1378              eo_do_super(sobj, MY_CLASS, evas_obj_paragraph_direction_set(EVAS_BIDI_DIRECTION_NEUTRAL));
1379           }
1380         /* END */
1381      }
1382
1383    if (sd->resize_obj == sobj) sd->resize_obj = NULL;
1384
1385    sd->subobjs = eina_list_remove(sd->subobjs, sobj);
1386
1387    _callbacks_del(sobj, obj);
1388
1389    return EINA_TRUE;
1390 }
1391
1392 /*
1393  * @internal
1394  *
1395  * a resize object is added to and deleted from the smart member and the sub object
1396  * of the parent if the third argument, Eina_Bool sub_obj, is set as EINA_TRUE.
1397  */
1398 EOLIAN static void
1399 _elm_widget_resize_object_set(Eo *obj, Elm_Widget_Smart_Data *sd,
1400                              Evas_Object *sobj,
1401                              Eina_Bool sub_obj)
1402 {
1403    Evas_Object *parent;
1404
1405    if (sd->resize_obj == sobj) return;
1406
1407    // orphan previous resize obj
1408    if (sd->resize_obj && sub_obj)
1409      {
1410         evas_object_clip_unset(sd->resize_obj);
1411         evas_object_smart_member_del(sd->resize_obj);
1412
1413         if (_elm_widget_is(sd->resize_obj))
1414           {
1415              if (_is_focused(sd->resize_obj)) _parents_unfocus(obj);
1416           }
1417         elm_widget_sub_object_del(obj, sd->resize_obj);
1418      }
1419
1420    sd->resize_obj = sobj;
1421    if (!sobj) return;
1422
1423    // orphan new resize obj
1424    parent = evas_object_data_get(sobj, "elm-parent");
1425    if (parent && parent != obj)
1426      {
1427         ELM_WIDGET_DATA_GET(parent, sdp);
1428
1429         /* should be there, just being paranoid */
1430         if (sdp)
1431           {
1432              if (sdp->resize_obj == sobj)
1433                elm_widget_resize_object_set(parent, NULL, sub_obj);
1434              else if (sub_obj)
1435                elm_widget_sub_object_del(parent, sobj);
1436           }
1437      }
1438    if (sub_obj)
1439      {
1440         elm_widget_sub_object_add(obj, sobj);
1441         evas_object_smart_member_add(sobj, obj);
1442      }
1443
1444    _smart_reconfigure(sd);
1445 }
1446
1447 /*
1448  * @internal
1449  *
1450  * WARNING: the programmer is responsible, in the scenario of
1451  * exchanging a hover object, of cleaning the old hover "target"
1452  * before
1453  */
1454 EOLIAN static void
1455 _elm_widget_hover_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1456 {
1457    if (sd->hover_obj)
1458      {
1459         _callbacks_del(sd->hover_obj, obj);
1460      }
1461    sd->hover_obj = sobj;
1462    if (sd->hover_obj)
1463      {
1464         _callbacks_add(sobj, obj);
1465         _smart_reconfigure(sd);
1466      }
1467 }
1468
1469 EOLIAN static void
1470 _elm_widget_can_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool can_focus)
1471 {
1472    can_focus = !!can_focus;
1473
1474    if (sd->can_focus == can_focus) return;
1475    sd->can_focus = can_focus;
1476    if (sd->can_focus)
1477      {
1478         /* update child_can_focus of parents */
1479         Evas_Object *o = obj;
1480
1481         for (;;)
1482           {
1483              o = elm_widget_parent_get(o);
1484              if (!o) break;
1485              sd = eo_data_scope_get(o, MY_CLASS);
1486              if (!sd || sd->child_can_focus) break;
1487              sd->child_can_focus = EINA_TRUE;
1488           }
1489
1490         eo_do(obj, eo_event_callback_array_add(focus_callbacks(), NULL));
1491      }
1492    else
1493      {
1494         // update child_can_focus of parents */
1495         Evas_Object *parent = elm_widget_parent_get(obj);
1496         while (parent)
1497           {
1498              const Eina_List *l;
1499              Evas_Object *subobj;
1500
1501              ELM_WIDGET_DATA_GET(parent, sdp);
1502
1503              sdp->child_can_focus = EINA_FALSE;
1504              EINA_LIST_FOREACH(sdp->subobjs, l, subobj)
1505                {
1506                   if (_is_focusable(subobj))
1507                     {
1508                        sdp->child_can_focus = EINA_TRUE;
1509                        break;
1510                     }
1511                }
1512              /* break again, child_can_focus went back to
1513               * original value */
1514              if (sdp->child_can_focus) break;
1515              parent = sdp->parent_obj;
1516           }
1517         eo_do(obj, eo_event_callback_array_del(focus_callbacks(), NULL));
1518      }
1519 }
1520
1521 EOLIAN static Eina_Bool
1522 _elm_widget_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1523 {
1524    return sd->can_focus;
1525 }
1526
1527 EOLIAN static Eina_Bool
1528 _elm_widget_child_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1529 {
1530    return sd->child_can_focus;
1531 }
1532
1533 /**
1534  * @internal
1535  *
1536  * This API makes the widget object and its children to be unfocusable.
1537  *
1538  * This API can be helpful for an object to be deleted.
1539  * When an object will be deleted soon, it and its children may not
1540  * want to get focus (by focus reverting or by other focus controls).
1541  * Then, just use this API before deleting.
1542  *
1543  * @param obj The widget root of sub-tree
1544  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1545  *
1546  * @ingroup Widget
1547  */
1548 EOLIAN static void
1549 _elm_widget_tree_unfocusable_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool tree_unfocusable)
1550 {
1551    tree_unfocusable = !!tree_unfocusable;
1552    if (sd->tree_unfocusable == tree_unfocusable) return;
1553    sd->tree_unfocusable = tree_unfocusable;
1554    elm_widget_focus_tree_unfocusable_handle(obj);
1555 }
1556
1557 /**
1558  * @internal
1559  *
1560  * This returns true, if the object sub-tree is unfocusable.
1561  *
1562  * @param obj The widget root of sub-tree
1563  * @return EINA_TRUE if the object sub-tree is unfocusable
1564  *
1565  * @ingroup Widget
1566  */
1567 EOLIAN static Eina_Bool
1568 _elm_widget_tree_unfocusable_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1569 {
1570    return sd->tree_unfocusable;
1571 }
1572
1573 /**
1574  * @internal
1575  *
1576  * Get the list of focusable child objects.
1577  *
1578  * This function retruns list of child objects which can get focus.
1579  *
1580  * @param obj The parent widget
1581  * @retrun list of focusable child objects.
1582  *
1583  * @ingroup Widget
1584  */
1585 EOLIAN static Eina_List*
1586 _elm_widget_can_focus_child_list_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1587 {
1588    const Eina_List *l;
1589    Eina_List *child_list = NULL;
1590    Evas_Object *child;
1591
1592    EINA_LIST_FOREACH(sd->subobjs, l, child)
1593      {
1594         if (!_elm_widget_is(child)) continue;
1595         if ((elm_widget_can_focus_get(child)) &&
1596             (evas_object_visible_get(child)) &&
1597             (!elm_widget_disabled_get(child)))
1598           child_list = eina_list_append(child_list, child);
1599         else
1600           {
1601              Eina_List *can_focus_list;
1602              can_focus_list = elm_widget_can_focus_child_list_get(child);
1603              if (can_focus_list)
1604                child_list = eina_list_merge(child_list, can_focus_list);
1605           }
1606      }
1607
1608    return child_list;
1609 }
1610
1611 EOLIAN static void
1612 _elm_widget_highlight_ignore_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool ignore)
1613 {
1614    sd->highlight_ignore = !!ignore;
1615 }
1616
1617 EOLIAN static Eina_Bool
1618 _elm_widget_highlight_ignore_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1619 {
1620    return sd->highlight_ignore;
1621 }
1622
1623 EOLIAN static void
1624 _elm_widget_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight)
1625 {
1626    sd->highlight_in_theme = !!highlight;
1627    /* FIXME: if focused, it should switch from one mode to the other */
1628 }
1629
1630 void
1631 _elm_widget_highlight_in_theme_update(Eo *obj)
1632 {
1633    Evas_Object *top = elm_widget_top_get(obj);
1634
1635    if (top && eo_isa(top, ELM_WIN_CLASS))
1636      {
1637         _elm_win_focus_highlight_in_theme_update(
1638            top, elm_widget_highlight_in_theme_get(obj));
1639      }
1640 }
1641
1642 EOLIAN static Eina_Bool
1643 _elm_widget_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1644 {
1645    return sd->highlight_in_theme;
1646 }
1647
1648 EOLIAN static void
1649 _elm_widget_access_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight)
1650 {
1651    sd->access_highlight_in_theme = !!highlight;
1652 }
1653
1654 EOLIAN static Eina_Bool
1655 _elm_widget_access_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1656 {
1657    return sd->access_highlight_in_theme;
1658 }
1659
1660 EOLIAN static Eina_Bool
1661 _elm_widget_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1662 {
1663    return (sd->focused && sd->top_win_focused);
1664 }
1665
1666 EOLIAN static Eina_Bool
1667 _elm_widget_highlight_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1668 {
1669    return sd->highlighted;
1670 }
1671
1672 EOLIAN static Evas_Object*
1673 _elm_widget_focused_object_get(Eo *obj, Elm_Widget_Smart_Data *sd)
1674 {
1675    const Evas_Object *subobj;
1676    const Eina_List *l;
1677
1678    if (!sd->focused || !sd->top_win_focused) return NULL;
1679    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1680      {
1681         Evas_Object *fobj;
1682         if (!_elm_widget_is(subobj)) continue;
1683         fobj = elm_widget_focused_object_get(subobj);
1684         if (fobj) return fobj;
1685      }
1686    return (Evas_Object *)obj;
1687 }
1688
1689 EOLIAN static Evas_Object*
1690 _elm_widget_top_get(Eo *obj, Elm_Widget_Smart_Data *sd)
1691 {
1692    if (sd->parent_obj)
1693      {
1694         Evas_Object *ret = NULL;
1695         if (!eo_isa(sd->parent_obj, ELM_WIDGET_CLASS)) return NULL;
1696         eo_do((Eo *) sd->parent_obj, ret = elm_obj_widget_top_get());
1697         return ret;
1698      }
1699    return (Evas_Object *)obj;
1700 }
1701
1702 EAPI Eina_Bool
1703 elm_widget_is(const Evas_Object *obj)
1704 {
1705    return _elm_widget_is(obj);
1706 }
1707
1708 EAPI Evas_Object *
1709 elm_widget_parent_widget_get(const Evas_Object *obj)
1710 {
1711    Evas_Object *parent;
1712
1713    if (_elm_widget_is(obj))
1714      {
1715         ELM_WIDGET_DATA_GET(obj, sd);
1716         if (!sd) return NULL;
1717         parent = sd->parent_obj;
1718      }
1719    else
1720      {
1721         parent = evas_object_data_get(obj, "elm-parent");
1722         if (!parent) parent = evas_object_smart_parent_get(obj);
1723      }
1724
1725    while (parent)
1726      {
1727         Evas_Object *elm_parent;
1728         if (_elm_widget_is(parent)) break;
1729         elm_parent = evas_object_data_get(parent, "elm-parent");
1730         if (elm_parent) parent = elm_parent;
1731         else parent = evas_object_smart_parent_get(parent);
1732      }
1733    return parent;
1734 }
1735
1736 EOLIAN static Evas_Object *
1737 _elm_widget_parent2_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1738 {
1739    return sd->parent2;
1740 }
1741
1742 EOLIAN static void
1743 _elm_widget_parent2_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *parent)
1744 {
1745    sd->parent2 = parent;
1746 }
1747
1748 EOLIAN static void
1749 _elm_widget_event_callback_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Event_Cb func, const void *data)
1750 {
1751    EINA_SAFETY_ON_NULL_RETURN(func);
1752
1753    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1754    if (!ecb)
1755      {
1756         ERR("Failed to allocate memory");
1757         return;
1758      }
1759    ecb->func = func;
1760    ecb->data = data;
1761    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1762 }
1763
1764 EOLIAN static void*
1765 _elm_widget_event_callback_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Event_Cb func, const void *data)
1766 {
1767    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1768    Eina_List *l;
1769    Elm_Event_Cb_Data *ecd;
1770    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1771      if ((ecd->func == func) && (ecd->data == data))
1772        {
1773           free(ecd);
1774           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1775           return (void *)data;
1776        }
1777
1778    return NULL;
1779 }
1780
1781 EOLIAN static Eina_Bool
1782 _elm_widget_event_propagate(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Callback_Type type, void *event_info, Evas_Event_Flags *event_flags)
1783 {
1784    Evas_Object *parent = obj;
1785    Elm_Event_Cb_Data *ecd;
1786    Eina_List *l, *l_prev;
1787
1788    while (parent &&
1789           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1790      {
1791         ELM_WIDGET_CHECK(parent) EINA_FALSE;
1792         Elm_Widget_Smart_Data *sd = eo_data_scope_get(parent, MY_CLASS);
1793
1794         Eina_Bool int_ret = EINA_FALSE;
1795
1796         if (elm_widget_disabled_get(obj))
1797           {
1798              parent = sd->parent_obj;
1799              continue;
1800           }
1801
1802         eo_do(parent, int_ret = elm_obj_widget_event(obj, type, event_info));
1803         if (int_ret) return EINA_TRUE;
1804
1805         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1806           {
1807              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1808                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1809                 return EINA_TRUE;
1810           }
1811         parent = sd->parent_obj;
1812      }
1813
1814    return EINA_FALSE;
1815 }
1816
1817 /**
1818  * @internal
1819  *
1820  * Set custom focus chain.
1821  *
1822  * This function i set one new and overwrite any previous custom focus chain
1823  * with the list of objects. The previous list will be deleted and this list
1824  * will be managed. After setted, don't modity it.
1825  *
1826  * @note On focus cycle, only will be evaluated children of this container.
1827  *
1828  * @param obj The container widget
1829  * @param objs Chain of objects to pass focus
1830  * @ingroup Widget
1831  */
1832 EOLIAN static void
1833 _elm_widget_focus_custom_chain_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_List *objs)
1834 {
1835    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1836
1837    elm_widget_focus_custom_chain_unset(obj);
1838
1839    Eina_List *l;
1840    Evas_Object *o;
1841
1842    EINA_LIST_FOREACH(objs, l, o)
1843      {
1844         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1845                                        _elm_object_focus_chain_del_cb, obj);
1846      }
1847
1848    sd->focus_chain = objs;
1849 }
1850
1851 /**
1852  * @internal
1853  *
1854  * Get custom focus chain
1855  *
1856  * @param obj The container widget
1857  * @ingroup Widget
1858  */
1859 EOLIAN static const Eina_List*
1860 _elm_widget_focus_custom_chain_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1861 {
1862    return (const Eina_List *)sd->focus_chain;
1863 }
1864
1865 /**
1866  * @internal
1867  *
1868  * Unset custom focus chain
1869  *
1870  * @param obj The container widget
1871  * @ingroup Widget
1872  */
1873 EOLIAN static void
1874 _elm_widget_focus_custom_chain_unset(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1875 {
1876    Eina_List *l, *l_next;
1877    Evas_Object *o;
1878
1879    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1880      {
1881         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1882                                             _elm_object_focus_chain_del_cb, obj);
1883         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1884      }
1885 }
1886
1887 /**
1888  * @internal
1889  *
1890  * Append object to custom focus chain.
1891  *
1892  * @note If relative_child equal to NULL or not in custom chain, the object
1893  * will be added in end.
1894  *
1895  * @note On focus cycle, only will be evaluated children of this container.
1896  *
1897  * @param obj The container widget
1898  * @param child The child to be added in custom chain
1899  * @param relative_child The relative object to position the child
1900  * @ingroup Widget
1901  */
1902 EOLIAN static void
1903 _elm_widget_focus_custom_chain_append(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child)
1904 {
1905    EINA_SAFETY_ON_NULL_RETURN(child);
1906
1907    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1908
1909    evas_object_event_callback_add(child, EVAS_CALLBACK_DEL,
1910                                   _elm_object_focus_chain_del_cb, obj);
1911
1912    if (!relative_child)
1913      sd->focus_chain = eina_list_append(sd->focus_chain, child);
1914    else
1915      sd->focus_chain = eina_list_append_relative(sd->focus_chain,
1916                                                  child, relative_child);
1917 }
1918
1919 /**
1920  * @internal
1921  *
1922  * Prepend object to custom focus chain.
1923  *
1924  * @note If relative_child equal to NULL or not in custom chain, the object
1925  * will be added in begin.
1926  *
1927  * @note On focus cycle, only will be evaluated children of this container.
1928  *
1929  * @param obj The container widget
1930  * @param child The child to be added in custom chain
1931  * @param relative_child The relative object to position the child
1932  * @ingroup Widget
1933  */
1934 EOLIAN static void
1935 _elm_widget_focus_custom_chain_prepend(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child)
1936 {
1937    EINA_SAFETY_ON_NULL_RETURN(child);
1938
1939    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1940
1941    evas_object_event_callback_add(child, EVAS_CALLBACK_DEL,
1942                                   _elm_object_focus_chain_del_cb, obj);
1943
1944    if (!relative_child)
1945      sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1946    else
1947      sd->focus_chain = eina_list_prepend_relative(sd->focus_chain,
1948                                                   child, relative_child);
1949 }
1950
1951 /**
1952  * @internal
1953  *
1954  * Give focus to next object in object tree.
1955  *
1956  * Give focus to next object in focus chain of one object sub-tree.
1957  * If the last object of chain already have focus, the focus will go to the
1958  * first object of chain.
1959  *
1960  * @param obj The widget root of sub-tree
1961  * @param dir Direction to cycle the focus
1962  *
1963  * @ingroup Widget
1964  */
1965 EOLIAN static void
1966 _elm_widget_focus_cycle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Focus_Direction dir)
1967 {
1968    Evas_Object *target = NULL;
1969    Elm_Object_Item *target_item = NULL;
1970    if (!_elm_widget_is(obj))
1971      return;
1972    elm_widget_focus_next_get(obj, dir, &target, &target_item);
1973    if (target)
1974      {
1975         /* access */
1976         if (_elm_config->access_mode)
1977           {
1978              /* highlight cycle does not steal a focus, only after window gets
1979                 the ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE message,
1980                 target will steal focus, or focus its own job. */
1981              if (!_elm_access_auto_highlight_get())
1982                elm_widget_focus_steal(target, target_item);
1983
1984              _elm_access_highlight_set(target);
1985              elm_widget_focus_region_show(target);
1986           }
1987         else elm_widget_focus_steal(target, target_item);
1988      }
1989 }
1990
1991 /**
1992  * @internal
1993  *
1994  * Give focus to near object(in object tree) in one direction.
1995  *
1996  * Give focus to near object(in object tree) in direction of current
1997  * focused object.  If none focusable object in given direction or
1998  * none focused object in object tree, the focus will not change.
1999  *
2000  * @param obj The reference widget
2001  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2002  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2003  * @return EINA_TRUE if focus is moved.
2004  *
2005  * @ingroup Widget
2006  */
2007 EOLIAN static Eina_Bool
2008 _elm_widget_focus_direction_go(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, double degree)
2009 {
2010    Evas_Object *target = NULL;
2011    Elm_Object_Item *target_item = NULL;
2012    Evas_Object *current_focused = NULL;
2013    double weight = 0.0;
2014
2015    if (!_elm_widget_is(obj)) return EINA_FALSE;
2016    if (!_is_focused(obj)) return EINA_FALSE;
2017
2018    current_focused = elm_widget_focused_object_get(obj);
2019
2020    if (elm_widget_focus_direction_get
2021          (obj, current_focused, degree, &target, &target_item, &weight))
2022      {
2023         elm_widget_focus_steal(target, NULL);
2024         return EINA_TRUE;
2025      }
2026
2027    return EINA_FALSE;
2028 }
2029
2030 double
2031 _elm_widget_focus_direction_weight_get(const Evas_Object *obj1,
2032                       const Evas_Object *obj2,
2033                       double degree)
2034 {
2035    Evas_Coord obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2;
2036    double x1, yy1, x2, yy2, xx1, yyy1, xx2, yyy2;
2037    double ax, ay, cx, cy;
2038    double weight = -1.0, g = 0.0;
2039
2040    if (obj1 == obj2) return 0.0;
2041
2042    degree -= 90.0;
2043    while (degree >= 360.0)
2044      degree -= 360.0;
2045    while (degree < 0.0)
2046      degree += 360.0;
2047
2048    evas_object_geometry_get(obj1, &obj_x1, &obj_y1, &w1, &h1);
2049    cx = obj_x1 + (w1 / 2.0);
2050    cy = obj_y1 + (h1 / 2.0);
2051    evas_object_geometry_get(obj2, &obj_x2, &obj_y2, &w2, &h2);
2052
2053    /* For overlapping cases. */
2054    if (ELM_RECTS_INTERSECT(obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2))
2055      return 0.0;
2056
2057    /* Change all points to relative one. */
2058    x1 = obj_x1 - cx;
2059    xx1 = x1 + w1;
2060    yy1 = obj_y1 - cy;
2061    yyy1 = yy1 + h1;
2062    x2 = obj_x2 - cx;
2063    xx2 = x2 + w2;
2064    yy2 = obj_y2 - cy;
2065    yyy2 = yy2 + h2;
2066
2067    /* Get crossing points (ax, ay) between obj1 and a line extending
2068     * to the direction of current degree. */
2069    if (degree == 0.0)
2070      {
2071         ax = xx1;
2072         ay = 0.0;
2073      }
2074    else if (degree == 90.0)
2075      {
2076         ax = 0.0;
2077         ay = yyy1;
2078      }
2079    else if (degree == 180.0)
2080      {
2081         ax = x1;
2082         ay = 0.0;
2083      }
2084    else if (degree == 270.0)
2085      {
2086         ax = 0.0;
2087         ay = yy1;
2088      }
2089    else
2090      {
2091         g = tan(degree * (M_PI / 180.0));
2092         if ((degree > 0.0) && (degree < 90.0))
2093           {
2094              ay = g * xx1;
2095              if (ay <= yyy1) ax = xx1;
2096              else
2097                {
2098                   ax = yyy1 / g;
2099                   ay = yyy1;
2100                }
2101           }
2102         else if ((degree > 90.0) && (degree < 180.0))
2103           {
2104              ay = g * x1;
2105              if (ay <= yyy1) ax = x1;
2106              else
2107                {
2108                   ax = yyy1 / g;
2109                   ay = yyy1;
2110                }
2111           }
2112         else if ((degree > 180.0) && (degree < 270.0))
2113           {
2114              ay = g * x1;
2115              if (ay >= yy1) ax = x1;
2116              else
2117                {
2118                   ax = yy1 / g;
2119                   ay = yy1;
2120                }
2121           }
2122         else
2123           {
2124              ay = g * xx1;
2125              if (ay >= yy1) ax = xx1;
2126              else
2127                {
2128                   ax = yy1 / g;
2129                   ay = yy1;
2130                }
2131           }
2132      }
2133
2134    /* Filter obj2, if it is not in the specific derection. */
2135    int i = 0;
2136    double rx[4] = {0.0, 0.0, 0.0, 0.0}, ry[4] = {0.0, 0.0, 0.0, 0.0};
2137    double t1, t2, u1, v1, u2, v2;
2138
2139    if ((degree == 45.0) || (degree == 225.0) || (degree == 135.0) ||
2140        (degree == 315.0))
2141      {
2142         u1 = 1.0;
2143         v1 = 0.0;
2144         u2 = 0.0;
2145         v2 = 1.0;
2146      }
2147    else
2148      {
2149         double g2 = tan((degree + 45.0) * (M_PI / 180.0));
2150         u1 = (-1.0 * g2);
2151         u2 = (1.0 / g2);
2152         v1 = v2 = 1.0;
2153      }
2154    t1 = (u1 * ax) + (v1 * ay);
2155    t2 = (u2 * ax) + (v2 * ay);
2156
2157 #define _R(x) (int)((x + 0.05) * 10.0)
2158
2159    if ((_R(t1 * ((u1 * x2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * x2) +
2160                                                             (v2 * yy2))) > 0))
2161      {
2162         rx[i] = x2;
2163         ry[i++] = yy2;
2164      }
2165    if ((_R(t1 * ((u1 * x2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * x2) +
2166                                                              (v2 * yyy2))) > 0))
2167      {
2168         rx[i] = x2;
2169         ry[i++] = yyy2;
2170      }
2171    if ((_R(t1 * ((u1 * xx2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * xx2) +
2172                                                              (v2 * yy2))) > 0))
2173      {
2174         rx[i] = xx2;
2175         ry[i++] = yy2;
2176      }
2177    if ((_R(t1 * ((u1 * xx2) + (v1 * yyy2))) > 0) &&
2178        (_R(t2 * ((u2 * xx2) + (v2 * yyy2))) > 0))
2179      {
2180         rx[i] = xx2;
2181         ry[i++] = yyy2;
2182      }
2183    if (i == 0)
2184      {
2185         if (degree == 0.0)
2186           {
2187              if ((_R(xx2) < 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2188           }
2189         else if (degree == 90.0)
2190           {
2191              if ((_R(yyy2) < 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2192           }
2193         else if (degree == 180.0)
2194           {
2195              if ((_R(x2) > 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2196           }
2197         else if (degree == 270.0)
2198           {
2199              if ((_R(yy2) > 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2200           }
2201         else
2202           {
2203              if ((_R(g * x2) >= _R(yy2)) && (_R((g * x2)) <= _R(yyy2)))
2204                {
2205                   if (!((_R(ax * x2) > 0) && (_R(ay * (g * x2)) > 0)))
2206                     return 0.0;
2207                }
2208              else if ((_R(g * xx2) >= _R(yy2)) && (_R((g * xx2)) <= _R(yyy2)))
2209                {
2210                   if (!((_R(ax * xx2) > 0) && (_R(ay * (g * xx2)) > 0)))
2211                     return 0.0;
2212                }
2213              else if ((_R((1.0 / g) * yy2) >= _R(xx2)) && (_R((1.0 / g) * yy2)
2214                                                            <= _R(xx2)))
2215                {
2216                   if (!((_R(ax * ((1.0 / g) * yy2)) > 0)
2217                         && (_R(ay * yy2) > 0)))
2218                     return 0.0;
2219                }
2220              else if ((_R((1.0 / g) * yyy2) >= _R(xx2)) &&
2221                       (_R((1.0 / g) * yyy2) <= _R(xx2)))
2222                {
2223                   if (!((_R(ax * ((1.0 / g) * yyy2)) > 0)
2224                         && (_R(ay * yyy2) > 0))) return 0.0;
2225                }
2226              else return 0.0;
2227           }
2228      }
2229
2230    /* Calculate the weight for obj2. */
2231    if (degree == 0.0)
2232      {
2233         if (_R(xx1) > _R(x2)) weight = -1.0;
2234         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2235           weight = (x2 - xx1) * (x2 - xx1);
2236         else if (_R(yy2) > 0)
2237           weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2);
2238         else if (_R(yyy2) < 0)
2239           weight = ((x2 - xx1) * (x2 - xx1)) + (yyy2 * yyy2);
2240         else weight = (x2 - xx1) * (x2 - xx1);
2241      }
2242    else if (degree == 90.0)
2243      {
2244         if (_R(yyy1) > _R(yy2)) weight = -1.0;
2245         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2246           weight = (yy2 - yyy1) * (yy2 - yyy1);
2247         else if (_R(x2) > 0)
2248           weight = (x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1));
2249         else if (_R(xx2) < 0)
2250           weight = (xx2 * xx2) + ((yy2 - yyy1) * (yy2 - yyy1));
2251         else weight = (yy2 - yyy1) * (yy2 - yyy1);
2252      }
2253    else if (degree == 180.0)
2254      {
2255         if (_R(x1) < _R(xx2)) weight = -1.0;
2256         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2257           weight = (x1 - xx2) * (x1 - xx2);
2258         else if (_R(yy2) > 0)
2259           weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2);
2260         else if (_R(yyy2) < 0)
2261           weight = ((x1 - xx2) * (x1 - xx2)) + (yyy2 * yyy2);
2262         else weight = (x1 - xx2) * (x1 - xx2);
2263      }
2264    else if (degree == 270.0)
2265      {
2266         if (_R(yy1) < _R(yyy2)) weight = -1.0;
2267         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2268           weight = (yy1 - yyy2) * (yy1 - yyy2);
2269         else if (_R(x2) > 0)
2270           weight = (x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2));
2271         else if (_R(xx2) < 0)
2272           weight = (xx2 * xx2) + ((yy1 - yyy2) * (yy1 - yyy2));
2273         else weight = (yy1 - yyy2) * (yy1 - yyy2);
2274      }
2275    else
2276      {
2277         int j = 0, k = 0;
2278         double sx[4] = {0.0, 0.0, 0.0, 0.0}, sy[4] = {0.0, 0.0, 0.0, 0.0};
2279         double t_weight[4] = {-1.0, -1.0, -1.0, -1.0};
2280         if ((_R(g * x2) >= _R(yy2)) && (_R(g * x2) <= _R(yyy2)))
2281           {
2282              sx[j] = x2;
2283              sy[j] = g * x2;
2284              t_weight[j++] = ((ax - x2) * (ax - x2)) +
2285                ((ay - (g * x2)) * (ay - (g * x2)));
2286           }
2287         if ((_R(g * xx2) >= _R(yy2)) && (_R(g * xx2) <= _R(yyy2)))
2288           {
2289              sx[j] = xx2;
2290              sy[j] = g * xx2;
2291              t_weight[j++] = ((ax - xx2) * (ax - xx2)) +
2292                ((ay - (g * xx2)) * (ay - (g * xx2)));
2293           }
2294         if ((_R((1.0 / g) * yy2) >= _R(x2)) && (_R((1.0 / g) * yy2) <= _R(xx2)))
2295           {
2296              sx[j] = (1.0 / g) * yy2;
2297              sy[j] = yy2;
2298              t_weight[j++] =
2299                ((ax - ((1.0 / g) * yy2)) * (ax - ((1.0 / g) * yy2))) +
2300                ((ay - yy2) * (ay - yy2));
2301           }
2302         if ((_R((1.0 / g) * yyy2) >= _R(x2)) && (_R((1.0 / g) * yyy2)
2303                                                  <= _R(xx2)))
2304           {
2305              sx[j] = (1.0 / g) * yyy2;
2306              sy[j] = yyy2;
2307              t_weight[j++] =
2308                ((ax - ((1.0 / g) * yyy2)) * (ax - ((1.0 / g) * yyy2))) +
2309                ((ay - yyy2) * (ay - yyy2));
2310           }
2311
2312         if ((j > 2) || ((j == 2) && ((_R(sx[0]) != _R(sx[1])) ||
2313                                      (_R(sy[0]) != _R(sy[1])))))
2314           {
2315              for (; k < j; k++)
2316                {
2317                   if (_R(t_weight[k]) == 0) return -1.0;
2318                   if ((1 / weight) < (1 / t_weight[k])) weight = t_weight[k];
2319                }
2320           }
2321         else
2322           {
2323              for (; k < i; k++)
2324                {
2325                   double ccx, ccy, t1_weight, x_diff, y_diff;
2326                   ccx = ((1.0 / g) * rx[k] + ry[k]) / (g + (1.0 / g));
2327                   ccy = g * ccx;
2328                   x_diff = rx[k] - ccx;
2329                   if (x_diff < 0) x_diff *= -1.0;
2330                   y_diff = ry[k] - ccy;
2331                   if (y_diff < 0) y_diff *= -1.0;
2332                   t1_weight =
2333                     (((ax - ccx) * (ax - ccx)) + ((ay - ccy) * (ay - ccy))) +
2334                     ((x_diff * x_diff * x_diff) + (y_diff * y_diff * y_diff));
2335                   if ((_R(t1_weight) != 0) && ((1 / weight) < (1 / t1_weight)))
2336                     weight = t1_weight;
2337                }
2338           }
2339      }
2340    /* Return the current object's weight. */
2341    if (weight == -1.0) return 0.0;
2342    if (_R(weight) == 0) return -1.0;
2343
2344 #undef _R
2345
2346    return 1.0 / weight;
2347 }
2348
2349 /**
2350  * @internal
2351  *
2352  * Get near object in one direction of base object.
2353  *
2354  * Get near object(in the object sub-tree) in one direction of
2355  * base object. Return the near object by reference.
2356  * By initializing weight, you can filter objects locating far
2357  * from base object. If object is in the specific direction,
2358  * weight is (1/(distance^2)). If object is not exactly in one
2359  * direction, some penalty will be added.
2360  *
2361  * @param obj The widget root of sub-tree
2362  * @param base The base object of the direction
2363  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2364  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2365  * @param direction The near object in one direction
2366  * @param weight The weight is bigger when the object is located near
2367  * @return EINA_TRUE if near object is updated.
2368  *
2369  * @ingroup Widget
2370  */
2371
2372 EOLIAN static Eina_Bool
2373 _elm_widget_focus_direction_get(const Eo *obj, Elm_Widget_Smart_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
2374 {
2375    double c_weight;
2376
2377    /* -1 means the best was already decided. Don't need any more searching. */
2378    if (!direction || !weight || !base || (obj == base))
2379      return EINA_FALSE;
2380
2381    /* Ignore if disabled */
2382    if ((!evas_object_visible_get(obj))
2383        || (elm_widget_disabled_get(obj))
2384        || (elm_widget_tree_unfocusable_get(obj)))
2385      return EINA_FALSE;
2386
2387    /* Try use hook */
2388    if (_internal_elm_widget_focus_direction_manager_is(obj))
2389      {
2390         Eina_Bool int_ret = EINA_FALSE;
2391         eo_do((Eo *)obj, int_ret = elm_obj_widget_focus_direction(base, degree, direction, direction_item, weight));
2392         return int_ret;
2393      }
2394
2395    if (!elm_widget_can_focus_get(obj) || _is_focused((Eo *)obj))
2396      return EINA_FALSE;
2397
2398    c_weight = _elm_widget_focus_direction_weight_get(base, obj, degree);
2399    if ((c_weight == -1.0) ||
2400        ((c_weight != 0.0) && (*weight != -1.0) &&
2401         ((int)(*weight * 1000000) <= (int)(c_weight * 1000000))))
2402      {
2403         if (*direction &&
2404             ((int)(*weight * 1000000) == (int)(c_weight * 1000000)))
2405           {
2406              ELM_WIDGET_DATA_GET(*direction, sd1);
2407              if (sd1)
2408                {
2409                   if (sd->focus_order <= sd1->focus_order)
2410                     return EINA_FALSE;
2411                }
2412           }
2413         *direction = (Evas_Object *)obj;
2414         *weight = c_weight;
2415         return EINA_TRUE;
2416      }
2417
2418    return EINA_FALSE;
2419 }
2420
2421 /**
2422  * @internal
2423  *
2424  * Get near object in one direction of base object in list.
2425  *
2426  * Get near object in one direction of base object in the specific
2427  * object list. Return the near object by reference.
2428  * By initializing weight, you can filter objects locating far
2429  * from base object. If object is in the specific direction,
2430  * weight is (1/(distance^2)). If object is not exactly in one
2431  * direction, some penalty will be added.
2432  *
2433  * @param obj The widget root of sub-tree
2434  * @param base The base object of the direction
2435  * @param items list with ordered objects
2436  * @param list_data_get function to get the object from one item of list
2437  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2438  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2439  * @param direction The near object in one direction
2440  * @param weight The weight is bigger when the object is located near
2441  * @return EINA_TRUE if near object is updated.
2442  *
2443  * @ingroup Widget
2444  */
2445 EOLIAN static Eina_Bool
2446 _elm_widget_focus_list_direction_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Evas_Object *base, const Eina_List *items, list_data_get_func_type list_data_get, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
2447 {
2448    if (!direction || !weight || !base || !items)
2449      return EINA_FALSE;
2450
2451    const Eina_List *l = items;
2452    Evas_Object *current_best = *direction;
2453
2454    for (; l; l = eina_list_next(l))
2455      {
2456         Evas_Object *cur = list_data_get(l);
2457         if (cur && _elm_widget_is(cur))
2458           elm_widget_focus_direction_get(cur, base, degree, direction, direction_item, weight);
2459      }
2460    if (current_best != *direction) return EINA_TRUE;
2461
2462    return EINA_FALSE;
2463 }
2464
2465 /**
2466  * @internal
2467  *
2468  * Get next object in focus chain of object tree.
2469  *
2470  * Get next object in focus chain of one object sub-tree.
2471  * Return the next object by reference. If don't have any candidate to receive
2472  * focus before chain end, the first candidate will be returned.
2473  *
2474  * @param obj The widget root of sub-tree
2475  * @param dir Direction of focus chain
2476  * @param next The next object in focus chain
2477  * @return EINA_TRUE if don't need focus chain restart/loop back
2478  *         to use 'next' obj.
2479  *
2480  * @ingroup Widget
2481  */
2482 EOLIAN static Eina_Bool
2483 _elm_widget_focus_next_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
2484 {
2485    Elm_Access_Info *ac;
2486
2487    if (!next)
2488      return EINA_FALSE;
2489    *next = NULL;
2490
2491    /* Ignore if disabled */
2492    if (_elm_config->access_mode && _elm_access_auto_highlight_get())
2493      {
2494         if (!evas_object_visible_get(obj)
2495             || (elm_widget_tree_unfocusable_get(obj)))
2496           return EINA_FALSE;
2497      }
2498    else
2499      {
2500         if ((!evas_object_visible_get(obj))
2501             || (elm_widget_disabled_get(obj))
2502             || (elm_widget_tree_unfocusable_get(obj)))
2503           return EINA_FALSE;
2504      }
2505
2506    /* Try use hook */
2507    if (_elm_widget_focus_chain_manager_is(obj))
2508      {
2509         Eina_Bool int_ret = EINA_FALSE;
2510         eo_do((Eo *)obj, int_ret = elm_obj_widget_focus_next(dir, next, next_item));
2511         if (!int_ret && _is_focused((Eo *)obj))
2512           {
2513              Evas_Object *o = NULL;
2514              if (dir == ELM_FOCUS_PREVIOUS)
2515                *next_item = sd->item_focus_previous;
2516              else if (dir == ELM_FOCUS_NEXT)
2517                *next_item = sd->item_focus_next;
2518              else if (dir == ELM_FOCUS_UP)
2519                *next_item = sd->item_focus_up;
2520              else if (dir == ELM_FOCUS_DOWN)
2521                *next_item = sd->item_focus_down;
2522              else if (dir == ELM_FOCUS_RIGHT)
2523                *next_item = sd->item_focus_right;
2524              else if (dir == ELM_FOCUS_LEFT)
2525                *next_item = sd->item_focus_left;
2526              o = elm_object_item_widget_get(*next_item);
2527
2528              if (!o)
2529                {
2530                   if (dir == ELM_FOCUS_PREVIOUS)
2531                     o = sd->focus_previous;
2532                   else if (dir == ELM_FOCUS_NEXT)
2533                     o = sd->focus_next;
2534                   else if (dir == ELM_FOCUS_UP)
2535                     o = sd->focus_up;
2536                   else if (dir == ELM_FOCUS_DOWN)
2537                     o = sd->focus_down;
2538                   else if (dir == ELM_FOCUS_RIGHT)
2539                     o = sd->focus_right;
2540                   else if (dir == ELM_FOCUS_LEFT)
2541                     o = sd->focus_left;
2542                }
2543
2544              if (o)
2545                {
2546                   *next = o;
2547                   return EINA_TRUE;
2548                }
2549           }
2550         return int_ret;
2551      }
2552
2553    /* access object does not check sd->can_focus, because an object could
2554       have highlight even though the object is not focusable. */
2555    if (_elm_config->access_mode && _elm_access_auto_highlight_get())
2556      {
2557         ac = _elm_access_info_get(obj);
2558         if (!ac) return EINA_FALSE;
2559
2560         /* check whether the hover object is visible or not */
2561         if (!evas_object_visible_get(ac->hoverobj))
2562           return EINA_FALSE;
2563      }
2564    else if (!elm_widget_can_focus_get(obj))
2565      return EINA_FALSE;
2566
2567    if (_is_focused((Eo *)obj))
2568      {
2569         if (dir == ELM_FOCUS_PREVIOUS)
2570           *next_item = sd->item_focus_previous;
2571         else if (dir == ELM_FOCUS_NEXT)
2572           *next_item = sd->item_focus_next;
2573         else if (dir == ELM_FOCUS_UP)
2574           *next_item = sd->item_focus_up;
2575         else if (dir == ELM_FOCUS_DOWN)
2576           *next_item = sd->item_focus_down;
2577         else if (dir == ELM_FOCUS_RIGHT)
2578           *next_item = sd->item_focus_right;
2579         else if (dir == ELM_FOCUS_LEFT)
2580           *next_item = sd->item_focus_left;
2581         *next = elm_object_item_widget_get(*next_item);
2582
2583         if (!(*next))
2584           {
2585              if (dir == ELM_FOCUS_PREVIOUS)
2586                *next = sd->focus_previous;
2587              else if (dir == ELM_FOCUS_NEXT)
2588                *next = sd->focus_next;
2589              else if (dir == ELM_FOCUS_UP)
2590                *next = sd->focus_up;
2591              else if (dir == ELM_FOCUS_DOWN)
2592                *next = sd->focus_down;
2593              else if (dir == ELM_FOCUS_RIGHT)
2594                *next = sd->focus_right;
2595              else if (dir == ELM_FOCUS_LEFT)
2596                *next = sd->focus_left;
2597           }
2598
2599         if (*next) return EINA_TRUE;
2600      }
2601
2602    /* Return */
2603    *next = (Evas_Object *)obj;
2604    return !ELM_WIDGET_FOCUS_GET(obj);
2605 }
2606
2607 /**
2608  * @internal
2609  *
2610  * Get next object in focus chain of object tree in list.
2611  *
2612  * Get next object in focus chain of one object sub-tree ordered by one list.
2613  * Return the next object by reference. If don't have any candidate to receive
2614  * focus before list end, the first candidate will be returned.
2615  *
2616  * @param obj The widget root of sub-tree
2617  * @param items list with ordered objects
2618  * @param list_data_get function to get the object from one item of list
2619  * @param dir Direction of focus chain
2620  * @param next The next object in focus chain
2621  * @return EINA_TRUE if don't need focus chain restart/loop back
2622  *         to use 'next' obj.
2623  *
2624  * @ingroup Widget
2625  */
2626 EOLIAN static Eina_Bool
2627 _elm_widget_focus_list_next_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Eina_List *items, list_data_get_func_type list_data_get, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
2628 {
2629    Eina_List *(*list_next)(const Eina_List *list) = NULL;
2630    Evas_Object *focused_object = NULL;
2631
2632    if (!next)
2633      return EINA_FALSE;
2634    *next = NULL;
2635
2636    if (!_elm_widget_is(obj))
2637      return EINA_FALSE;
2638
2639    if (!items)
2640      return EINA_FALSE;
2641
2642    /* When Up, Down, Right, or Left, try direction_get first. */
2643    focused_object = elm_widget_focused_object_get(obj);
2644    if (focused_object)
2645      {
2646         if ((dir == ELM_FOCUS_UP)
2647            || (dir == ELM_FOCUS_DOWN)
2648            || (dir == ELM_FOCUS_RIGHT)
2649            || (dir == ELM_FOCUS_LEFT))
2650           {
2651              *next_item = elm_widget_focus_next_item_get(focused_object, dir);
2652              if (*next_item)
2653                *next = elm_object_item_widget_get(*next_item);
2654              else
2655                *next = elm_widget_focus_next_object_get(focused_object, dir);
2656              if (*next) return EINA_TRUE;
2657              else
2658                {
2659                   Evas_Object *n = NULL;
2660                   Elm_Object_Item *n_item = NULL;
2661                   double degree = 0;
2662                   double weight = 0.0;
2663
2664                   if (dir == ELM_FOCUS_UP) degree = 0.0;
2665                   else if (dir == ELM_FOCUS_DOWN) degree = 180.0;
2666                   else if (dir == ELM_FOCUS_RIGHT) degree = 90.0;
2667                   else if (dir == ELM_FOCUS_LEFT) degree = 270.0;
2668
2669                   if (elm_widget_focus_list_direction_get(obj, focused_object,
2670                                                           items, list_data_get,
2671                                                           degree, &n, &n_item,
2672                                                           &weight))
2673                     {
2674                        *next_item = n_item;
2675                        *next = n;
2676                        return EINA_TRUE;
2677                     }
2678                }
2679           }
2680      }
2681
2682    /* Direction */
2683    if (dir == ELM_FOCUS_PREVIOUS)
2684      {
2685         items = eina_list_last(items);
2686         list_next = eina_list_prev;
2687      }
2688    else if ((dir == ELM_FOCUS_NEXT)
2689             || (dir == ELM_FOCUS_UP)
2690             || (dir == ELM_FOCUS_DOWN)
2691             || (dir == ELM_FOCUS_RIGHT)
2692             || (dir == ELM_FOCUS_LEFT))
2693      list_next = eina_list_next;
2694    else
2695      return EINA_FALSE;
2696
2697    const Eina_List *l = items;
2698
2699    /* Recovery last focused sub item */
2700    if (ELM_WIDGET_FOCUS_GET(obj))
2701      {
2702         for (; l; l = list_next(l))
2703           {
2704              Evas_Object *cur = list_data_get(l);
2705              if (ELM_WIDGET_FOCUS_GET(cur)) break;
2706           }
2707
2708          /* Focused object, but no focused sub item */
2709          if (!l) l = items;
2710      }
2711
2712    const Eina_List *start = l;
2713    Evas_Object *to_focus = NULL;
2714    Elm_Object_Item *to_focus_item = NULL;
2715
2716    /* Iterate sub items */
2717    /* Go to the end of list */
2718    for (; l; l = list_next(l))
2719      {
2720         Evas_Object *tmp = NULL;
2721         Elm_Object_Item *tmp_item = NULL;
2722         Evas_Object *cur = list_data_get(l);
2723
2724         if (!cur) continue;
2725         if (!_elm_widget_is(cur)) continue;
2726         if (elm_widget_parent_get(cur) != obj)
2727           continue;
2728
2729         /* Try Focus cycle in subitem */
2730         if (elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item))
2731           {
2732              *next = tmp;
2733              *next_item = tmp_item;
2734              return EINA_TRUE;
2735           }
2736         else if ((dir == ELM_FOCUS_UP)
2737                  || (dir == ELM_FOCUS_DOWN)
2738                  || (dir == ELM_FOCUS_RIGHT)
2739                  || (dir == ELM_FOCUS_LEFT))
2740           {
2741              if (tmp && _is_focused(cur))
2742                {
2743                   *next = tmp;
2744                   *next_item = tmp_item;
2745                   return EINA_FALSE;
2746                }
2747           }
2748         else if ((tmp) && (!to_focus))
2749           {
2750              to_focus = tmp;
2751              to_focus_item = tmp_item;
2752           }
2753      }
2754
2755    l = items;
2756
2757    /* Get First possible */
2758    for (; l != start; l = list_next(l))
2759      {
2760         Evas_Object *tmp = NULL;
2761         Elm_Object_Item *tmp_item = NULL;
2762         Evas_Object *cur = list_data_get(l);
2763
2764         if (elm_widget_parent_get(cur) != obj)
2765           continue;
2766
2767         /* Try Focus cycle in subitem */
2768         elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item);
2769         if (tmp)
2770           {
2771              *next = tmp;
2772              *next_item = tmp_item;
2773              return EINA_FALSE;
2774           }
2775      }
2776
2777    *next = to_focus;
2778    *next_item = to_focus_item;
2779    return EINA_FALSE;
2780 }
2781
2782 /**
2783  * @internal
2784  *
2785  * Get next object which was set with specific focus direction.
2786  *
2787  * Get next object which was set by elm_widget_focus_next_object_set
2788  * with specific focus directioin.
2789  *
2790  * @param obj The widget
2791  * @param dir Direction of focus
2792  * @return Widget which was registered with sepecific focus direction.
2793  *
2794  * @ingroup Widget
2795  */
2796 EOLIAN static Evas_Object*
2797 _elm_widget_focus_next_object_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir)
2798 {
2799    Evas_Object *ret = NULL;
2800
2801    if (dir == ELM_FOCUS_PREVIOUS)
2802      ret = sd->focus_previous;
2803    else if (dir == ELM_FOCUS_NEXT)
2804      ret = sd->focus_next;
2805    else if (dir == ELM_FOCUS_UP)
2806      ret = sd->focus_up;
2807    else if (dir == ELM_FOCUS_DOWN)
2808      ret = sd->focus_down;
2809    else if (dir == ELM_FOCUS_RIGHT)
2810      ret = sd->focus_right;
2811    else if (dir == ELM_FOCUS_LEFT)
2812      ret = sd->focus_left;
2813
2814    return ret;
2815 }
2816
2817 /**
2818  * @internal
2819  *
2820  * Set next object with specific focus direction.
2821  *
2822  * When a widget is set with specific focus direction, this widget will be
2823  * the first candidate when finding the next focus object.
2824  * Focus next object can be registered with six directions that are previous,
2825  * next, up, down, right, and left.
2826  *
2827  * @param obj The widget
2828  * @param next Next focus object
2829  * @param dir Direction of focus
2830  *
2831  * @ingroup Widget
2832  */
2833 EOLIAN static void
2834 _elm_widget_focus_next_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *next, Elm_Focus_Direction dir)
2835 {
2836
2837    if (dir == ELM_FOCUS_PREVIOUS)
2838      sd->focus_previous = next;
2839    else if (dir == ELM_FOCUS_NEXT)
2840      sd->focus_next = next;
2841    else if (dir == ELM_FOCUS_UP)
2842      sd->focus_up = next;
2843    else if (dir == ELM_FOCUS_DOWN)
2844      sd->focus_down = next;
2845    else if (dir == ELM_FOCUS_RIGHT)
2846      sd->focus_right = next;
2847    else if (dir == ELM_FOCUS_LEFT)
2848      sd->focus_left = next;
2849 }
2850
2851 EOLIAN static Elm_Object_Item*
2852 _elm_widget_focus_next_item_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir)
2853 {
2854    Elm_Object_Item *ret = NULL;
2855
2856    if (dir == ELM_FOCUS_PREVIOUS)
2857      ret = sd->item_focus_previous;
2858    else if (dir == ELM_FOCUS_NEXT)
2859      ret = sd->item_focus_next;
2860    else if (dir == ELM_FOCUS_UP)
2861      ret = sd->item_focus_up;
2862    else if (dir == ELM_FOCUS_DOWN)
2863      ret = sd->item_focus_down;
2864    else if (dir == ELM_FOCUS_RIGHT)
2865      ret = sd->item_focus_right;
2866    else if (dir == ELM_FOCUS_LEFT)
2867      ret = sd->item_focus_left;
2868
2869    return ret;
2870 }
2871
2872 EOLIAN static void
2873 _elm_widget_focus_next_item_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Object_Item *next_item, Elm_Focus_Direction dir)
2874 {
2875    if (dir == ELM_FOCUS_PREVIOUS)
2876      sd->item_focus_previous = next_item;
2877    else if (dir == ELM_FOCUS_NEXT)
2878      sd->item_focus_next = next_item;
2879    else if (dir == ELM_FOCUS_UP)
2880      sd->item_focus_up = next_item;
2881    else if (dir == ELM_FOCUS_DOWN)
2882      sd->item_focus_down = next_item;
2883    else if (dir == ELM_FOCUS_RIGHT)
2884      sd->item_focus_right = next_item;
2885    else if (dir == ELM_FOCUS_LEFT)
2886      sd->item_focus_left = next_item;
2887 }
2888
2889 EOLIAN static void
2890 _elm_widget_parent_highlight_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool highlighted)
2891 {
2892    highlighted = !!highlighted;
2893
2894    Evas_Object *o = elm_widget_parent_get(obj);
2895
2896    if (o) elm_widget_parent_highlight_set(o, highlighted);
2897
2898    sd->highlighted = highlighted;
2899 }
2900
2901 EOLIAN static void
2902 _elm_widget_signal_emit(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source)
2903 {
2904    if (evas_object_smart_type_check(obj, "elm_layout"))
2905      elm_layout_signal_emit(obj, emission, source);
2906    else if (evas_object_smart_type_check(obj, "elm_icon"))
2907      {
2908         WRN("Deprecated function. This functionality on icon objects"
2909             " will be dropped on a next release.");
2910         _elm_icon_signal_emit(obj, emission, source);
2911      }
2912 }
2913
2914 EOLIAN static void
2915 _elm_widget_signal_callback_add(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func, void *data)
2916 {
2917    EINA_SAFETY_ON_NULL_RETURN(func);
2918
2919    if (evas_object_smart_type_check(obj, "elm_layout"))
2920      elm_layout_signal_callback_add(obj, emission, source, func, data);
2921    else if (evas_object_smart_type_check(obj, "elm_icon"))
2922      {
2923         WRN("Deprecated function. This functionality on icon objects"
2924             " will be dropped on a next release.");
2925
2926         _elm_icon_signal_callback_add(obj, emission, source, func, data);
2927      }
2928 }
2929
2930 EOLIAN static void*
2931 _elm_widget_signal_callback_del(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func)
2932 {
2933    void *data = NULL;
2934
2935    if (evas_object_smart_type_check(obj, "elm_layout"))
2936      data = elm_layout_signal_callback_del(obj, emission, source, func);
2937    else if (evas_object_smart_type_check(obj, "elm_icon"))
2938      {
2939         WRN("Deprecated function. This functionality on icon objects"
2940             " will be dropped on a next release.");
2941
2942         data = _elm_icon_signal_callback_del(obj, emission, source, func);
2943      }
2944
2945    return data;
2946 }
2947
2948 EOLIAN static void
2949 _elm_widget_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool focus)
2950 {
2951    if (!sd->focused)
2952      {
2953         focus_order++;
2954         sd->focus_order = focus_order;
2955         sd->focused = EINA_TRUE;
2956         eo_do(obj, elm_obj_widget_on_focus(NULL));
2957      }
2958
2959    if (focus)
2960      {
2961         if ((_is_focusable(sd->resize_obj)) &&
2962             (!elm_widget_disabled_get(sd->resize_obj)))
2963           {
2964              elm_widget_focus_set(sd->resize_obj, focus);
2965           }
2966         else
2967           {
2968              const Eina_List *l;
2969              Evas_Object *child;
2970
2971              EINA_LIST_FOREACH(sd->subobjs, l, child)
2972                {
2973                   if (!_elm_widget_is(child)) continue;
2974                   if ((_is_focusable(child)) &&
2975                       (!elm_widget_disabled_get(child)))
2976                     {
2977                        elm_widget_focus_set(child, focus);
2978                        break;
2979                     }
2980                }
2981           }
2982      }
2983    else
2984      {
2985         const Eina_List *l;
2986         Evas_Object *child;
2987
2988         EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
2989           {
2990              if (!_elm_widget_is(child)) continue;
2991              if ((_is_focusable(child)) &&
2992                  (!elm_widget_disabled_get(child)))
2993                {
2994                   elm_widget_focus_set(child, focus);
2995                   break;
2996                }
2997           }
2998      }
2999 }
3000
3001 EOLIAN static Evas_Object*
3002 _elm_widget_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3003 {
3004    return sd->parent_obj;
3005 }
3006
3007 EOLIAN static void
3008 _elm_widget_focused_object_clear(Eo *obj, Elm_Widget_Smart_Data *sd)
3009 {
3010    if (!sd->focused) return;
3011    if (sd->resize_obj && elm_widget_is(sd->resize_obj) &&
3012        _is_focused(sd->resize_obj))
3013      {
3014         eo_do(sd->resize_obj, elm_obj_widget_focused_object_clear());
3015      }
3016    else
3017      {
3018         const Eina_List *l;
3019         Evas_Object *child;
3020         EINA_LIST_FOREACH(sd->subobjs, l, child)
3021           {
3022              if (_elm_widget_is(child) && _is_focused(child))
3023                {
3024                   eo_do(child, elm_obj_widget_focused_object_clear());
3025                   break;
3026                }
3027           }
3028      }
3029    sd->focused = EINA_FALSE;
3030    if (sd->top_win_focused)
3031      eo_do(obj, elm_obj_widget_on_focus(NULL));
3032 }
3033
3034 EOLIAN static void
3035 _elm_widget_focus_steal(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item)
3036 {
3037    Evas_Object *parent, *parent2, *o;
3038
3039    if (sd->focused) return;
3040    if (sd->disabled) return;
3041    if (!sd->can_focus) return;
3042    if (sd->tree_unfocusable) return;
3043    parent = obj;
3044    for (;; )
3045      {
3046         o = elm_widget_parent_get(parent);
3047         if (!o) break;
3048         sd = eo_data_scope_get(o, MY_CLASS);
3049         if (sd->disabled || sd->tree_unfocusable) return;
3050         if (sd->focused) break;
3051         parent = o;
3052      }
3053    if ((!elm_widget_parent_get(parent)) &&
3054        (!elm_widget_parent2_get(parent)))
3055      eo_do(parent, elm_obj_widget_focused_object_clear());
3056    else
3057      {
3058         parent2 = elm_widget_parent_get(parent);
3059         if (!parent2) parent2 = elm_widget_parent2_get(parent);
3060         parent = parent2;
3061         sd = eo_data_scope_get(parent, MY_CLASS);
3062         if (sd)
3063           {
3064              if (sd->resize_obj && elm_widget_is(sd->resize_obj) &&
3065                    _is_focused(sd->resize_obj))
3066                {
3067                   eo_do(sd->resize_obj, elm_obj_widget_focused_object_clear());
3068                }
3069              else
3070                {
3071                   const Eina_List *l;
3072                   Evas_Object *child;
3073                   EINA_LIST_FOREACH(sd->subobjs, l, child)
3074                     {
3075                        if (_elm_widget_is(child) && _is_focused(child))
3076                          {
3077                             eo_do(child, elm_obj_widget_focused_object_clear());
3078                             break;
3079                          }
3080                     }
3081                }
3082           }
3083      }
3084    _parent_focus(obj, item);
3085    elm_widget_focus_region_show(obj);
3086    return;
3087 }
3088
3089 static void
3090 _parents_on_focus(Evas_Object *obj)
3091 {
3092    API_ENTRY return;
3093    if (!sd->focused || !sd->top_win_focused) return;
3094
3095    Evas_Object *o = elm_widget_parent_get(obj);
3096    if (o) _parents_on_focus(o);
3097    eo_do(obj, elm_obj_widget_on_focus(NULL));
3098 }
3099
3100 EOLIAN static void
3101 _elm_widget_focus_restore(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3102 {
3103    Evas_Object *newest = NULL;
3104    unsigned int newest_focus_order = 0;
3105
3106    newest = elm_widget_newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
3107    if (newest)
3108      _parents_on_focus(newest);
3109 }
3110
3111 void
3112 _elm_widget_focus_auto_show(Evas_Object *obj)
3113 {
3114    Evas_Object *top = elm_widget_top_get(obj);
3115    if (top && eo_isa(top, ELM_WIN_CLASS)) _elm_win_focus_auto_show(top);
3116 }
3117
3118 void
3119 _elm_widget_top_win_focused_set(Evas_Object *obj,
3120                                 Eina_Bool top_win_focused)
3121 {
3122    const Eina_List *l;
3123    Evas_Object *child;
3124    API_ENTRY return;
3125
3126    if (sd->top_win_focused == top_win_focused) return;
3127    EINA_LIST_FOREACH(sd->subobjs, l, child)
3128      {
3129         if (elm_widget_is(child))
3130           _elm_widget_top_win_focused_set(child, top_win_focused);
3131      }
3132    sd->top_win_focused = top_win_focused;
3133
3134    if (sd->focused && !sd->top_win_focused)
3135      eo_do(obj, elm_obj_widget_on_focus(NULL));
3136 }
3137
3138 Eina_Bool
3139 _elm_widget_top_win_focused_get(const Evas_Object *obj)
3140 {
3141    API_ENTRY return EINA_FALSE;
3142    return sd->top_win_focused;
3143 }
3144
3145 static void
3146 _elm_widget_disabled_eval(const Evas_Object *obj, Eina_Bool disabled)
3147 {
3148    const Eina_List *l;
3149    Evas_Object *child;
3150    ELM_WIDGET_DATA_GET(obj, sd);
3151
3152    if (disabled)
3153      {
3154         EINA_LIST_FOREACH(sd->subobjs, l, child)
3155           {
3156               if (elm_widget_is(child))
3157                 {
3158                    elm_widget_focus_disabled_handle(child);
3159                    eo_do(child, elm_obj_widget_disable());
3160                    _elm_widget_disabled_eval(child, EINA_TRUE);
3161                 }
3162           }
3163      }
3164    else
3165      {
3166         EINA_LIST_FOREACH(sd->subobjs, l, child)
3167           {
3168              ELM_WIDGET_DATA_GET(child, sdc);
3169              if (elm_widget_is(child) && !sdc->disabled)
3170                {
3171                   elm_widget_focus_disabled_handle(child);
3172                   eo_do(child, elm_obj_widget_disable());
3173                   _elm_widget_disabled_eval(child, EINA_FALSE);
3174                }
3175           }
3176      }
3177 }
3178
3179 static void
3180 elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled)
3181 {
3182    Eina_Bool parent_state = EINA_FALSE;
3183
3184    if (disabled)
3185      {
3186         elm_widget_focus_disabled_handle(obj);
3187         eo_do(obj, elm_obj_widget_disable());
3188         _elm_widget_disabled_eval(obj, EINA_TRUE);
3189      }
3190    else
3191      {
3192         parent_state = elm_widget_disabled_get(elm_widget_parent_get(obj));
3193         if (parent_state) return;
3194         elm_widget_focus_disabled_handle(obj);
3195         eo_do(obj, elm_obj_widget_disable());
3196         _elm_widget_disabled_eval(obj, EINA_FALSE);
3197      }
3198 }
3199
3200 EOLIAN static void
3201 _elm_widget_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled)
3202 {
3203    if (sd->disabled == disabled) return;
3204    sd->disabled = !!disabled;
3205
3206    elm_widget_disabled_internal(obj, disabled);
3207 }
3208
3209 EOLIAN static Eina_Bool
3210 _elm_widget_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3211 {
3212    Eina_Bool disabled = EINA_FALSE;
3213
3214    if (sd->disabled) disabled = EINA_TRUE;
3215    else disabled = elm_widget_disabled_get(elm_widget_parent_get(obj));
3216    return disabled;
3217 }
3218
3219 EOLIAN static void
3220 _elm_widget_show_region_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool forceshow)
3221 {
3222
3223    Evas_Object *parent_obj, *child_obj;
3224    Evas_Coord px, py, cx, cy, nx = 0, ny = 0;
3225
3226
3227    evas_smart_objects_calculate(evas_object_evas_get(obj));
3228
3229    if (!forceshow && (x == sd->rx) && (y == sd->ry) &&
3230        (w == sd->rw) && (h == sd->rh)) return;
3231
3232    sd->rx = x;
3233    sd->ry = y;
3234    sd->rw = w;
3235    sd->rh = h;
3236    if (sd->on_show_region)
3237      {
3238         sd->on_show_region
3239            (sd->on_show_region_data, obj);
3240
3241         if (_elm_scrollable_is(obj))
3242           {
3243              eo_do(obj, elm_interface_scrollable_content_pos_get(&nx, &ny));
3244              x -= nx;
3245              y -= ny;
3246           }
3247      }
3248
3249    do
3250      {
3251         parent_obj = sd->parent_obj;
3252         child_obj = sd->obj;
3253         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
3254         sd = eo_data_scope_get(parent_obj, MY_CLASS);
3255         if (!sd) break;
3256
3257         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
3258         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
3259
3260         x += (cx - px);
3261         y += (cy - py);
3262         sd->rx = x;
3263         sd->ry = y;
3264         sd->rw = w;
3265         sd->rh = h;
3266
3267         if (sd->on_show_region)
3268           {
3269              sd->on_show_region
3270                (sd->on_show_region_data, parent_obj);
3271           }
3272      }
3273    while (parent_obj);
3274 }
3275
3276 EOLIAN static void
3277 _elm_widget_show_region_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3278 {
3279    if (x) *x = sd->rx;
3280    if (y) *y = sd->ry;
3281    if (w) *w = sd->rw;
3282    if (h) *h = sd->rh;
3283 }
3284
3285 /**
3286  * @internal
3287  *
3288  * Get the focus region of the given widget.
3289  *
3290  * @return show region or not
3291  * (@c EINA_TRUE = show region/@c EINA_FALSE = do not show region). Default is @c EINA_FALSE.
3292  *
3293  * The focus region is the area of a widget that should brought into the
3294  * visible area when the widget is focused. Mostly used to show the part of
3295  * an entry where the cursor is, for example. The area returned is relative
3296  * to the object @p obj.
3297  *
3298  * @param obj The widget object
3299  * @param x Where to store the x coordinate of the area
3300  * @param y Where to store the y coordinate of the area
3301  * @param w Where to store the width of the area
3302  * @param h Where to store the height of the area
3303  *
3304  * @ingroup Widget
3305  */
3306 EOLIAN static Eina_Bool
3307 _elm_widget_focus_region_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3308 {
3309    Eina_Bool int_ret = EINA_FALSE;
3310    eo_do((Eo *)obj, int_ret = elm_obj_widget_on_focus_region(x, y, w, h));
3311    if (!int_ret)
3312      {
3313         evas_object_geometry_get(obj, NULL, NULL, w, h);
3314         if (x) *x = 0;
3315         if (y) *y = 0;
3316      }
3317    if ((*w <= 0) || (*h <= 0)) return EINA_FALSE;
3318    return EINA_TRUE;
3319 }
3320
3321 EOLIAN static void
3322 _elm_widget_parents_bounce_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool *horiz, Eina_Bool *vert)
3323 {
3324    Evas_Object *parent_obj = obj;
3325    Eina_Bool h = EINA_FALSE, v = EINA_FALSE;
3326
3327    *horiz = EINA_FALSE;
3328    *vert = EINA_FALSE;
3329
3330    do
3331      {
3332         parent_obj = elm_widget_parent_get(parent_obj);
3333         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
3334
3335         if (_elm_scrollable_is(parent_obj))
3336           {
3337              eo_do(parent_obj, elm_interface_scrollable_bounce_allow_get(&h, &v));
3338              if (h) *horiz = EINA_TRUE;
3339              if (v) *vert = EINA_TRUE;
3340           }
3341      }
3342    while (parent_obj);
3343 }
3344
3345 EOLIAN static Eina_List*
3346 _elm_widget_scrollable_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3347 {
3348    Eina_List *ret;
3349    ret = NULL;
3350
3351    Eina_List *l;
3352    Evas_Object *child;
3353
3354
3355    EINA_LIST_FOREACH(sd->subobjs, l, child)
3356      {
3357         if (elm_widget_is(child) && _elm_scrollable_is(child))
3358           ret = eina_list_append(ret, child);
3359      }
3360
3361    return ret;
3362 }
3363
3364 EOLIAN static void
3365 _elm_widget_scroll_hold_push(Eo *obj, Elm_Widget_Smart_Data *sd)
3366 {
3367    sd->scroll_hold++;
3368    if (sd->scroll_hold == 1)
3369      {
3370         if (_elm_scrollable_is(obj))
3371            eo_do(obj, elm_interface_scrollable_hold_set(EINA_TRUE));
3372         else
3373           {
3374              Eina_List *scr_children, *l;
3375              Evas_Object *child;
3376
3377              scr_children = elm_widget_scrollable_children_get(obj);
3378              EINA_LIST_FOREACH(scr_children, l, child)
3379                {
3380                   eo_do(child, elm_interface_scrollable_hold_set(EINA_TRUE));
3381                }
3382              eina_list_free(scr_children);
3383           }
3384      }
3385    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_hold_push());
3386    // FIXME: on delete/reparent hold pop
3387 }
3388
3389 EOLIAN static void
3390 _elm_widget_scroll_hold_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
3391 {
3392    sd->scroll_hold--;
3393    if (!sd->scroll_hold)
3394      {
3395         if (_elm_scrollable_is(obj))
3396            eo_do(obj, elm_interface_scrollable_hold_set(EINA_FALSE));
3397         else
3398           {
3399              Eina_List *scr_children, *l;
3400              Evas_Object *child;
3401
3402              scr_children = elm_widget_scrollable_children_get(obj);
3403              EINA_LIST_FOREACH(scr_children, l, child)
3404                {
3405                   eo_do(child, elm_interface_scrollable_hold_set(EINA_FALSE));
3406                }
3407              eina_list_free(scr_children);
3408           }
3409      }
3410    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_hold_pop());
3411    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
3412 }
3413
3414 EOLIAN static int
3415 _elm_widget_scroll_hold_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3416 {
3417    return sd->scroll_hold;
3418 }
3419
3420 EOLIAN static void
3421 _elm_widget_scroll_freeze_push(Eo *obj, Elm_Widget_Smart_Data *sd)
3422 {
3423    sd->scroll_freeze++;
3424    if (sd->scroll_freeze == 1)
3425      {
3426         if (_elm_scrollable_is(obj))
3427            eo_do(obj, elm_interface_scrollable_freeze_set(EINA_TRUE));
3428         else
3429           {
3430              Eina_List *scr_children, *l;
3431              Evas_Object *child;
3432
3433              scr_children = elm_widget_scrollable_children_get(obj);
3434              EINA_LIST_FOREACH(scr_children, l, child)
3435                {
3436                   eo_do(child, elm_interface_scrollable_freeze_set(EINA_TRUE));
3437                }
3438              eina_list_free(scr_children);
3439           }
3440      }
3441    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_freeze_push());
3442    // FIXME: on delete/reparent freeze pop
3443 }
3444
3445 EOLIAN static void
3446 _elm_widget_scroll_freeze_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
3447 {
3448    sd->scroll_freeze--;
3449    if (!sd->scroll_freeze)
3450      {
3451         if (_elm_scrollable_is(obj))
3452            eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
3453         else
3454           {
3455              Eina_List *scr_children, *l;
3456              Evas_Object *child;
3457
3458              scr_children = elm_widget_scrollable_children_get(obj);
3459              EINA_LIST_FOREACH(scr_children, l, child)
3460                {
3461                   eo_do(child, elm_interface_scrollable_freeze_set(EINA_FALSE));
3462                }
3463              eina_list_free(scr_children);
3464           }
3465      }
3466    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_freeze_pop());
3467    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
3468 }
3469
3470 EOLIAN static int
3471 _elm_widget_scroll_freeze_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3472 {
3473    return sd->scroll_freeze;
3474 }
3475
3476 // TIZEN_ONLY(20150705): Genlist item align feature
3477 EAPI void
3478 elm_widget_scroll_item_align_enabled_set(Evas_Object *obj,
3479                                         Eina_Bool scroll_item_align_enable)
3480 {
3481    API_ENTRY return;
3482    if (sd->scroll_item_align_enable == scroll_item_align_enable) return;
3483    sd->scroll_item_align_enable = scroll_item_align_enable;
3484 }
3485
3486 EAPI Eina_Bool
3487 elm_widget_scroll_item_align_enabled_get(const Evas_Object *obj)
3488 {
3489    API_ENTRY return EINA_FALSE;
3490    return sd->scroll_item_align_enable;
3491 }
3492
3493 EAPI void
3494 elm_widget_scroll_item_valign_set(Evas_Object *obj,
3495                                   const char *scroll_item_valign)
3496 {
3497    API_ENTRY return;
3498    if (sd->scroll_item_valign) eina_stringshare_del(sd->scroll_item_valign);
3499    if (!scroll_item_valign) sd->scroll_item_valign = NULL;
3500    else sd->scroll_item_valign = eina_stringshare_add(scroll_item_valign);
3501 }
3502
3503 EAPI const char*
3504 elm_widget_scroll_item_valign_get(const Evas_Object *obj)
3505 {
3506    API_ENTRY return NULL;
3507    return sd->scroll_item_valign;
3508 }
3509 //
3510
3511 EOLIAN static void
3512 _elm_widget_scale_set(Eo *obj, Elm_Widget_Smart_Data *sd, double scale)
3513 {
3514    if (scale < 0.0) scale = 0.0;
3515    if (sd->scale != scale)
3516      {
3517         sd->scale = scale;
3518         elm_widget_theme(obj);
3519      }
3520 }
3521
3522 EOLIAN static double
3523 _elm_widget_scale_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3524 {
3525    // FIXME: save walking up the tree by storing/caching parent scale
3526    if (sd->scale == 0.0)
3527      {
3528         if (sd->parent_obj && elm_widget_is(sd->parent_obj))
3529           {
3530              return elm_widget_scale_get(sd->parent_obj);
3531           }
3532         else
3533           {
3534              return 1.0;
3535           }
3536      }
3537    return sd->scale;
3538 }
3539
3540 EOLIAN static void
3541 _elm_widget_theme_set(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Theme *th)
3542 {
3543    Eina_Bool apply = EINA_FALSE;
3544    if (sd->theme != th)
3545      {
3546         if (elm_widget_theme_get(obj) != th) apply = EINA_TRUE;
3547         if (sd->theme) elm_theme_free(sd->theme);
3548         sd->theme = th;
3549         if (th) th->ref++;
3550         if (apply) elm_widget_theme(obj);
3551      }
3552 }
3553
3554 EOLIAN static void
3555 _elm_widget_part_text_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part, const char *label)
3556 {
3557    if (evas_object_smart_type_check(obj, "elm_layout"))
3558      elm_layout_text_set(obj, part, label);
3559 }
3560
3561 EOLIAN static const char*
3562 _elm_widget_part_text_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part)
3563 {
3564    if (evas_object_smart_type_check(obj, "elm_layout"))
3565      return elm_layout_text_get(obj, part);
3566
3567    return NULL;
3568 }
3569
3570 static Elm_Translate_String_Data *
3571 _translate_string_data_get(Eina_Inlist *translate_strings, const char *part)
3572 {
3573    Elm_Translate_String_Data *ts;
3574    Eina_Stringshare *str;
3575
3576    if (!translate_strings) return NULL;
3577
3578    str = eina_stringshare_add(part);
3579    EINA_INLIST_FOREACH(translate_strings, ts)
3580      {
3581         if (ts->id == str) break;
3582      }
3583
3584    eina_stringshare_del(str);
3585
3586    return ts;
3587 }
3588
3589 static Elm_Translate_String_Data *
3590 _part_text_translatable_set(Eina_Inlist **translate_strings, const char *part, Eina_Bool translatable, Eina_Bool preset)
3591 {
3592    Eina_Inlist *t;
3593    Elm_Translate_String_Data *ts;
3594    t = *translate_strings;
3595    ts = _translate_string_data_get(t, part);
3596
3597    if (translatable)
3598      {
3599         if (!ts)
3600           {
3601              ts = ELM_NEW(Elm_Translate_String_Data);
3602              if (!ts) return NULL;
3603
3604              ts->id = eina_stringshare_add(part);
3605              t = eina_inlist_append(t, (Eina_Inlist*) ts);
3606           }
3607         if (preset) ts->preset = EINA_TRUE;
3608      }
3609    //Delete this exist one if this part has been not preset.
3610    //see elm_widget_part_text_translatable_set()
3611    else if (ts && ((preset) || (!ts->preset)))
3612      {
3613         t = eina_inlist_remove(t, EINA_INLIST_GET(ts));
3614         eina_stringshare_del(ts->id);
3615         eina_stringshare_del(ts->domain);
3616         eina_stringshare_del(ts->string);
3617         ELM_SAFE_FREE(ts, free);
3618      }
3619
3620    *translate_strings = t;
3621
3622    return ts;
3623 }
3624
3625 EOLIAN static void
3626 _elm_widget_domain_translatable_part_text_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, const char *label)
3627 {
3628
3629    Elm_Translate_String_Data *ts;
3630
3631    if (!label)
3632      {
3633         _part_text_translatable_set(&sd->translate_strings, part, EINA_FALSE,
3634                                     EINA_FALSE);
3635      }
3636    else
3637      {
3638         ts = _part_text_translatable_set(&sd->translate_strings, part,
3639                                          EINA_TRUE, EINA_FALSE);
3640         if (!ts) return;
3641         if (!ts->string) ts->string = eina_stringshare_add(label);
3642         else eina_stringshare_replace(&ts->string, label);
3643         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3644         else eina_stringshare_replace(&ts->domain, domain);
3645 #ifdef HAVE_GETTEXT
3646         if (label[0]) label = dgettext(domain, label);
3647 #endif
3648      }
3649
3650    sd->on_translate = EINA_TRUE;
3651    eo_do(obj, elm_obj_widget_part_text_set(part, label));
3652    sd->on_translate = EINA_FALSE;
3653 }
3654
3655 EOLIAN static const char*
3656 _elm_widget_translatable_part_text_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part)
3657 {
3658    Elm_Translate_String_Data *ts;
3659
3660    ts = _translate_string_data_get(sd->translate_strings, part);
3661    if (ts) return ts->string;
3662    else return NULL;
3663 }
3664
3665 EOLIAN static void
3666 _elm_widget_domain_part_text_translatable_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, Eina_Bool translatable)
3667 {
3668    Elm_Translate_String_Data *ts;
3669    const char *text = NULL;
3670
3671    ts = _part_text_translatable_set(&sd->translate_strings, part,
3672                                     translatable, EINA_TRUE);
3673    if (!ts) return;
3674    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3675    else eina_stringshare_replace(&ts->domain, domain);
3676
3677    eo_do(obj, text = elm_obj_widget_part_text_get(part));
3678    if (!text || !text[0]) return;
3679
3680    if (!ts->string) ts->string = eina_stringshare_add(text);
3681
3682 //Try to translate text since we don't know the text is already translated.
3683 #ifdef HAVE_GETTEXT
3684    text = dgettext(domain, text);
3685 #endif
3686    sd->on_translate = EINA_TRUE;
3687    eo_do(obj, elm_obj_widget_part_text_set(part, text));
3688    sd->on_translate = EINA_FALSE;
3689 }
3690
3691 EAPI void
3692 elm_widget_translate(Evas_Object *obj)
3693 {
3694    ELM_WIDGET_CHECK(obj);
3695    eo_do(obj, elm_obj_widget_translate());
3696 }
3697
3698 static const char*
3699 _part_text_translate(Eina_Inlist *translate_strings,
3700                      const char *part,
3701                      const char *text)
3702 {
3703    Elm_Translate_String_Data *ts;
3704    ts = _translate_string_data_get(translate_strings, part);
3705    if (!ts) return text;
3706
3707    if (!ts->string) ts->string = eina_stringshare_add(text);
3708    else eina_stringshare_replace(&ts->string, text);
3709 #ifdef HAVE_GETTEXT
3710    if (text && text[0])
3711      text = dgettext(ts->domain, text);
3712 #endif
3713    return text;
3714 }
3715
3716 EOLIAN static const char*
3717 _elm_widget_part_text_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part, const char *text)
3718 {
3719
3720
3721    if (!sd->translate_strings || sd->on_translate) return text;
3722    return _part_text_translate(sd->translate_strings, part, text);
3723 }
3724
3725 EOLIAN static Eina_Bool
3726 _elm_widget_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3727 {
3728    const Eina_List *l;
3729    Evas_Object *child;
3730    API_ENTRY return EINA_FALSE;
3731
3732    EINA_LIST_FOREACH(sd->subobjs, l, child)
3733      {
3734         if (elm_widget_is(child))
3735           elm_widget_translate(child);
3736      }
3737
3738    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
3739
3740 #ifdef HAVE_GETTEXT
3741    Elm_Translate_String_Data *ts;
3742    EINA_INLIST_FOREACH(sd->translate_strings, ts)
3743      {
3744         if (!ts->string) continue;
3745         const char *s = dgettext(ts->domain, ts->string);
3746         sd->on_translate = EINA_TRUE;
3747         eo_do(obj, elm_obj_widget_part_text_set(ts->id, s));
3748         sd->on_translate = EINA_FALSE;
3749      }
3750 #endif
3751    eo_do(obj, eo_event_callback_call(ELM_WIDGET_EVENT_LANGUAGE_CHANGED, NULL));
3752    return EINA_TRUE;
3753 }
3754
3755 /**
3756  * @internal
3757  *
3758  * Resets the focus_move_policy mode from the system one
3759  * for widgets that are in automatic mode.
3760  *
3761  * @param obj The widget.
3762  *
3763  */
3764 static void
3765 _elm_widget_focus_move_policy_reload(Evas_Object *obj)
3766 {
3767    API_ENTRY return;
3768    Elm_Focus_Move_Policy focus_move_policy = elm_config_focus_move_policy_get();
3769
3770    if (elm_widget_focus_move_policy_automatic_get(obj) &&
3771        (sd->focus_move_policy != focus_move_policy))
3772      {
3773         sd->focus_move_policy = focus_move_policy;
3774      }
3775 }
3776
3777 EOLIAN static void
3778 _elm_widget_focus_reconfigure(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3779 {
3780    const Eina_List *l;
3781    Evas_Object *child;
3782    API_ENTRY return;
3783
3784    EINA_LIST_FOREACH(sd->subobjs, l, child)
3785      {
3786         if (elm_widget_is(child))
3787           elm_widget_focus_reconfigure(child);
3788      }
3789
3790    if (sd->hover_obj) elm_widget_focus_reconfigure(sd->hover_obj);
3791
3792    _elm_widget_focus_move_policy_reload(obj);
3793 }
3794
3795 //TIZEN_ONLY(20160726): add API elm_object_part_access_object_get
3796 EOLIAN static Evas_Object*
3797 _elm_widget_part_access_object_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part EINA_UNUSED)
3798 {
3799    WRN("The %s widget does not implement the \"part_access_object_get\" functions.",
3800        eo_class_name_get(eo_class_get(obj)));
3801    return NULL;
3802 }
3803 //
3804
3805 EAPI void
3806 elm_widget_content_part_set(Evas_Object *obj,
3807                             const char *part,
3808                             Evas_Object *content)
3809 {
3810    ELM_WIDGET_CHECK(obj);
3811    eo_do(obj, elm_obj_container_content_set(part, content));
3812 }
3813
3814 /**
3815  * Returns the widget's focus_move_policy mode setting.
3816  *
3817  * @param obj The widget.
3818  * @return focus_move_policy mode setting of the object.
3819  *
3820  **/
3821 EOLIAN static Eina_Bool
3822 _elm_widget_focus_move_policy_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3823 {
3824    return sd->focus_move_policy_auto_mode;
3825 }
3826
3827 /**
3828  * @internal
3829  *
3830  * Sets the widget's focus_move_policy mode setting.
3831  * When widget in automatic mode, it follows the system focus_move_policy mode set by
3832  * elm_config_focus_move_policy_set().
3833  * @param obj The widget.
3834  * @param automatic EINA_TRUE for auto focus_move_policy mode. EINA_FALSE for manual.
3835  */
3836 EOLIAN static void
3837 _elm_widget_focus_move_policy_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
3838 {
3839    if (sd->focus_move_policy_auto_mode != automatic)
3840      {
3841         sd->focus_move_policy_auto_mode = automatic;
3842
3843         if (automatic)
3844           {
3845              elm_widget_focus_move_policy_set(obj, elm_config_focus_move_policy_get());
3846           }
3847      }
3848 }
3849
3850 EAPI Evas_Object *
3851 elm_widget_content_part_get(const Evas_Object *obj,
3852                             const char *part)
3853 {
3854    ELM_WIDGET_CHECK(obj) NULL;
3855    Evas_Object *ret = NULL;
3856    eo_do((Eo *) obj, ret = elm_obj_container_content_get(part));
3857    return ret;
3858 }
3859
3860 EAPI Evas_Object *
3861 elm_widget_content_part_unset(Evas_Object *obj,
3862                               const char *part)
3863 {
3864    ELM_WIDGET_CHECK(obj) NULL;
3865    Evas_Object *ret = NULL;
3866    eo_do(obj, ret = elm_obj_container_content_unset(part));
3867    return ret;
3868 }
3869
3870 EOLIAN static void
3871 _elm_widget_access_info_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *txt)
3872 {
3873    eina_stringshare_del(sd->access_info);
3874    if (!txt) sd->access_info = NULL;
3875    else sd->access_info = eina_stringshare_add(txt);
3876 }
3877
3878 EOLIAN static const char*
3879 _elm_widget_access_info_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3880 {
3881    return sd->access_info;
3882 }
3883
3884 EOLIAN static Elm_Theme*
3885 _elm_widget_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3886 {
3887    if (!sd->theme)
3888      {
3889         if (sd->parent_obj && elm_widget_is(sd->parent_obj))
3890            return elm_widget_theme_get(sd->parent_obj);
3891         else return NULL;
3892      }
3893    return sd->theme;
3894 }
3895
3896 EOLIAN static Elm_Theme_Apply
3897 _elm_widget_style_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *style)
3898 {
3899    if (eina_stringshare_replace(&sd->style, style))
3900       return elm_widget_theme(obj);
3901
3902    return ELM_THEME_APPLY_SUCCESS;
3903 }
3904
3905 EOLIAN static const char*
3906 _elm_widget_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3907 {
3908    const char *ret;
3909    ret = "default";
3910    if (sd->style) ret = sd->style;
3911
3912    return ret;
3913 }
3914
3915 EOLIAN static void
3916 _elm_widget_tooltip_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt)
3917 {
3918    sd->tooltips = eina_list_append(sd->tooltips, tt);
3919 }
3920
3921 EOLIAN static void
3922 _elm_widget_tooltip_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt)
3923 {
3924    sd->tooltips = eina_list_remove(sd->tooltips, tt);
3925 }
3926
3927 EOLIAN static void
3928 _elm_widget_cursor_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Cursor *cur)
3929 {
3930    sd->cursors = eina_list_append(sd->cursors, cur);
3931 }
3932
3933 EOLIAN static void
3934 _elm_widget_cursor_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Cursor *cur)
3935 {
3936    sd->cursors = eina_list_remove(sd->cursors, cur);
3937 }
3938
3939 EOLIAN static void
3940 _elm_widget_drag_lock_x_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock)
3941 {
3942    if (sd->drag_x_locked == lock) return;
3943    sd->drag_x_locked = lock;
3944    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
3945    else _propagate_x_drag_lock(obj, -1);
3946 }
3947
3948 EOLIAN static void
3949 _elm_widget_drag_lock_y_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock)
3950 {
3951    if (sd->drag_y_locked == lock) return;
3952    sd->drag_y_locked = lock;
3953    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
3954    else _propagate_y_drag_lock(obj, -1);
3955 }
3956
3957 EOLIAN static Eina_Bool
3958 _elm_widget_drag_lock_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3959 {
3960    return sd->drag_x_locked;
3961 }
3962
3963 EOLIAN static Eina_Bool
3964 _elm_widget_drag_lock_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3965 {
3966    return sd->drag_y_locked;
3967 }
3968
3969 EOLIAN static int
3970 _elm_widget_drag_child_locked_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3971 {
3972    return sd->child_drag_x_locked;
3973 }
3974
3975 EOLIAN static int
3976 _elm_widget_drag_child_locked_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3977 {
3978    return sd->child_drag_y_locked;
3979 }
3980
3981 EOLIAN static void
3982 _elm_widget_item_loop_enabled_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Bool enable EINA_UNUSED)
3983 {
3984         return;
3985 }
3986
3987 EOLIAN static Eina_Bool
3988 _elm_widget_item_loop_enabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED)
3989 {
3990         return EINA_FALSE;
3991 }
3992
3993 EOLIAN static Elm_Theme_Apply
3994 _elm_widget_theme_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle)
3995 {
3996    Elm_Theme_Apply ret = _elm_theme_object_set(obj, edj, wname, welement, wstyle);
3997    if (!ret)
3998      {
3999         return ELM_THEME_APPLY_FAILED;
4000      }
4001
4002    if (sd->orient_mode != -1)
4003      {
4004         char buf[128];
4005         snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
4006         eo_do(obj, elm_obj_widget_signal_emit(buf, "elm"));
4007      }
4008
4009    return ret;
4010 }
4011
4012 EOLIAN static void
4013 _elm_widget_eo_base_dbg_info_get(Eo *eo_obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eo_Dbg_Info *root)
4014 {
4015    eo_do_super(eo_obj, MY_CLASS, eo_dbg_info_get(root));
4016    Eo_Dbg_Info *group = EO_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
4017
4018    EO_DBG_INFO_APPEND(group, "Wid-Type", EINA_VALUE_TYPE_STRING, elm_widget_type_get(eo_obj));
4019    EO_DBG_INFO_APPEND(group, "Style", EINA_VALUE_TYPE_STRING, elm_widget_style_get(eo_obj));
4020    EO_DBG_INFO_APPEND(group, "Layer", EINA_VALUE_TYPE_INT,
4021          (int) evas_object_layer_get(eo_obj));
4022    EO_DBG_INFO_APPEND(group, "Scale", EINA_VALUE_TYPE_DOUBLE,
4023          evas_object_scale_get(eo_obj));
4024    EO_DBG_INFO_APPEND(group, "Has focus", EINA_VALUE_TYPE_CHAR,
4025          elm_object_focus_get(eo_obj));
4026    EO_DBG_INFO_APPEND(group, "Disabled", EINA_VALUE_TYPE_CHAR,
4027          elm_widget_disabled_get(eo_obj));
4028    EO_DBG_INFO_APPEND(group, "Mirrored", EINA_VALUE_TYPE_CHAR,
4029          elm_widget_mirrored_get(eo_obj));
4030    EO_DBG_INFO_APPEND(group, "Automatic mirroring", EINA_VALUE_TYPE_CHAR,
4031          elm_widget_mirrored_automatic_get(eo_obj));
4032 }
4033
4034 EAPI Eina_Bool
4035 elm_widget_is_check(const Evas_Object *obj)
4036 {
4037    static int abort_on_warn = -1;
4038    if (elm_widget_is(obj))
4039      return EINA_TRUE;
4040
4041    ERR("Passing Object: %p.", obj);
4042    if (abort_on_warn == -1)
4043      {
4044         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
4045         else abort_on_warn = 0;
4046      }
4047    if (abort_on_warn == 1) abort();
4048    return EINA_FALSE;
4049 }
4050
4051 EAPI const char *
4052 elm_widget_type_get(const Evas_Object *obj)
4053 {
4054    API_ENTRY return NULL;
4055
4056    return eo_class_name_get(eo_class_get(obj));
4057 }
4058
4059 EAPI Eina_Bool
4060 elm_widget_type_check(const Evas_Object *obj,
4061                       const char *type,
4062                       const char *func)
4063 {
4064    const char *provided, *expected = "(unknown)";
4065    static int abort_on_warn = -1;
4066
4067    provided = elm_widget_type_get(obj);
4068    /* TODO: eventually migrate to check_ptr version */
4069    if (evas_object_smart_type_check(obj, type)) return EINA_TRUE;
4070    if (type) expected = type;
4071    if ((!provided) || (!provided[0]))
4072      {
4073         provided = evas_object_type_get(obj);
4074         if ((!provided) || (!provided[0]))
4075           provided = "(unknown)";
4076      }
4077    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting"
4078        " type: '%s'", obj, func, provided, expected);
4079    if (abort_on_warn == -1)
4080      {
4081         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
4082         else abort_on_warn = 0;
4083      }
4084    if (abort_on_warn == 1) abort();
4085    return EINA_FALSE;
4086 }
4087
4088 static Evas_Object *
4089 _widget_name_find(const Evas_Object *obj,
4090                   const char *name,
4091                   int recurse)
4092 {
4093    Eina_List *l;
4094    Evas_Object *child;
4095    const char *s;
4096    INTERNAL_ENTRY NULL;
4097
4098    if (!_elm_widget_is(obj)) return NULL;
4099    EINA_LIST_FOREACH(sd->subobjs, l, child)
4100      {
4101         s = evas_object_name_get(child);
4102         if ((s) && (!strcmp(s, name))) return child;
4103         if ((recurse != 0) &&
4104             ((child = _widget_name_find(child, name, recurse - 1))))
4105           return child;
4106      }
4107    if (sd->hover_obj)
4108      {
4109         s = evas_object_name_get(sd->hover_obj);
4110         if ((s) && (!strcmp(s, name))) return sd->hover_obj;
4111         if ((recurse != 0) &&
4112             ((child = _widget_name_find(sd->hover_obj, name, recurse - 1))))
4113           return child;
4114      }
4115    return NULL;
4116 }
4117
4118 EOLIAN static Evas_Object*
4119 _elm_widget_name_find(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *name, int recurse)
4120 {
4121    if (!name) return NULL;
4122    return _widget_name_find(obj, name, recurse);
4123 }
4124
4125 /**
4126  * @internal
4127  *
4128  * Split string in words
4129  *
4130  * @param str Source string
4131  * @return List of const words
4132  *
4133  * @see elm_widget_stringlist_free()
4134  * @ingroup Widget
4135  */
4136 EAPI Eina_List *
4137 elm_widget_stringlist_get(const char *str)
4138 {
4139    Eina_List *list = NULL;
4140    const char *s, *b;
4141    if (!str) return NULL;
4142    for (b = s = str; 1; s++)
4143      {
4144         if ((*s == ' ') || (!*s))
4145           {
4146              char *t = malloc(s - b + 1);
4147              if (t)
4148                {
4149                   strncpy(t, b, s - b);
4150                   t[s - b] = 0;
4151                   list = eina_list_append(list, eina_stringshare_add(t));
4152                   free(t);
4153                }
4154              b = s + 1;
4155           }
4156         if (!*s) break;
4157      }
4158    return list;
4159 }
4160
4161 EAPI void
4162 elm_widget_stringlist_free(Eina_List *list)
4163 {
4164    const char *s;
4165    EINA_LIST_FREE(list, s)
4166      eina_stringshare_del(s);
4167 }
4168
4169 EOLIAN static void
4170 _elm_widget_focus_hide_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4171 {
4172    if (!_elm_widget_is(obj))
4173      return;
4174    _if_focused_revert(obj, EINA_TRUE);
4175 }
4176
4177 EAPI void
4178 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
4179 {
4180    Evas_Object *o = obj;
4181    do
4182      {
4183         if (_elm_widget_is(o)) break;
4184         o = evas_object_smart_parent_get(o);
4185      }
4186    while (o);
4187
4188    eo_do(o, elm_obj_widget_focus_mouse_up_handle());
4189 }
4190
4191 EOLIAN static void
4192 _elm_widget_focus_mouse_up_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4193 {
4194    if (!obj) return;
4195    if (!_is_focusable(obj)) return;
4196
4197    elm_widget_focus_steal(obj, NULL);
4198 }
4199
4200 EOLIAN static void
4201 _elm_widget_focus_tree_unfocusable_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4202 {
4203    if (!elm_widget_parent_get(obj))
4204      elm_widget_focused_object_clear(obj);
4205    else
4206      _if_focused_revert(obj, EINA_TRUE);
4207 }
4208
4209 EOLIAN static void
4210 _elm_widget_focus_disabled_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4211 {
4212    elm_widget_focus_tree_unfocusable_handle(obj);
4213 }
4214
4215 EOLIAN static unsigned int
4216 _elm_widget_focus_order_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4217 {
4218    return sd->focus_order;
4219 }
4220
4221 EOLIAN static Evas_Object*
4222 _elm_widget_newest_focus_order_get(const Eo *obj, Elm_Widget_Smart_Data *sd, unsigned int *newest_focus_order, Eina_Bool can_focus_only)
4223 {
4224    const Eina_List *l;
4225    Evas_Object *child, *cur, *best;
4226
4227    if (!evas_object_visible_get(obj)
4228        || (elm_widget_disabled_get(obj))
4229        || (elm_widget_tree_unfocusable_get(obj)))
4230      return NULL;
4231
4232    best = NULL;
4233    if (*newest_focus_order < sd->focus_order)
4234      {
4235         if (!can_focus_only || elm_widget_can_focus_get(obj))
4236           {
4237              *newest_focus_order = sd->focus_order;
4238              best = (Evas_Object *)obj;
4239           }
4240      }
4241    EINA_LIST_FOREACH(sd->subobjs, l, child)
4242      {
4243         if (!_elm_widget_is(child)) continue;
4244
4245         cur = elm_widget_newest_focus_order_get
4246            (child, newest_focus_order, can_focus_only);
4247         if (!cur) continue;
4248         best = cur;
4249      }
4250    return best;
4251 }
4252
4253 /*
4254  * @internal
4255  *
4256  * Get the focus highlight geometry of an widget.
4257  *
4258  * @param obj Widget object for the focus highlight
4259  * @param x Focus highlight x coordinate
4260  * @param y Focus highlight y coordinate
4261  * @param w Focus highlight object width
4262  * @param h Focus highlight object height
4263  * @param is_next @c EINA_TRUE if this request is for the new focused object,
4264  * @c EINA_FALSE if this request is for the previously focused object. This
4265  * information becomes important when the focus highlight is changed inside one
4266  * widget.
4267  *
4268  * @ingroup Widget
4269  */
4270 /*
4271  * @internal
4272  *
4273  * Get the 'focus_part' geometry if there is any
4274  *
4275  * This queries if there is a 'focus_part' request from the edc style. If edc
4276  * style offers 'focus_part' edje data item, this function requests for the
4277  * geometry of a specific part which is described in 'focus_part' edje data.
4278  *
4279  * @param obj Widget object for the focus highlight
4280  * @param x Focus highlight x coordinate
4281  * @param y Focus highlight y coordinate
4282  * @param w Focus highlight object width
4283  * @param h Focus highlight object height
4284  *
4285  * x, y, w, h already contain the object's geometry. If there is a 'focus_part'
4286  * support, these values will be updated accordingly or the values will be
4287  * remained as they were.
4288  *
4289  * @ingroup Widget
4290  */
4291 EAPI void
4292 elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object *obj,
4293                                                    Evas_Coord *x,
4294                                                    Evas_Coord *y,
4295                                                    Evas_Coord *w,
4296                                                    Evas_Coord *h)
4297 {
4298    Evas_Coord tx = 0, ty = 0, tw = 0, th = 0;
4299    const char *target_hl_part = NULL;
4300    const Evas_Object *edje_obj = NULL;
4301
4302    if (obj && eo_isa(obj, EDJE_OBJECT_CLASS))
4303      {
4304         edje_obj = obj;
4305         if (!(target_hl_part = edje_object_data_get(edje_obj, "focus_part")))
4306           return;
4307      }
4308    else if (obj && eo_isa(obj, ELM_LAYOUT_CLASS))
4309      {
4310         edje_obj = elm_layout_edje_get(obj);
4311         if (!(target_hl_part = elm_layout_data_get(obj, "focus_part")))
4312           return;
4313      }
4314    else
4315      return;
4316
4317   edje_object_part_geometry_get(edje_obj, target_hl_part,
4318                                 &tx, &ty, &tw, &th);
4319   *x += tx;
4320   *y += ty;
4321   if (tw != *w) *w = tw;
4322   if (th != *h) *h = th;
4323 }
4324
4325 EOLIAN static void
4326 _elm_widget_focus_highlight_geometry_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
4327 {
4328    Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
4329    Evas_Object *scroller = (Evas_Object *)obj;
4330
4331    evas_object_geometry_get(obj, x, y, w, h);
4332    elm_widget_focus_highlight_focus_part_geometry_get(sd->resize_obj, x, y, w, h);
4333
4334    if (_elm_config->focus_autoscroll_mode != ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN)
4335      return;
4336
4337    while (scroller)
4338      {
4339         if (_elm_scrollable_is(scroller))
4340           {
4341              eo_do(scroller,
4342                    elm_interface_scrollable_content_viewport_geometry_get(&ox, &oy, &ow, &oh));
4343
4344              if (*y < oy)
4345                *y = oy;
4346              else if ((oy + oh) < (*y + *h))
4347                *y = (oy + oh - *h);
4348              else if (*x < ox)
4349                *x = ox;
4350              else if ((ox + ow) < (*x + *w))
4351                *x = (ox + ow - *w);
4352
4353              break;
4354           }
4355         scroller = elm_widget_parent_get(scroller);
4356      }
4357 }
4358
4359 EOLIAN static Elm_Object_Item*
4360 _elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4361 {
4362    return NULL;
4363 }
4364
4365 EOLIAN static void
4366 _elm_widget_focus_region_show_mode_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, Elm_Focus_Region_Show_Mode mode)
4367 {
4368    _pd->focus_region_show_mode = mode;
4369 }
4370
4371 EOLIAN static Elm_Focus_Region_Show_Mode
4372 _elm_widget_focus_region_show_mode_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
4373 {
4374    return _pd->focus_region_show_mode;
4375 }
4376
4377 EAPI void
4378 elm_widget_activate(Evas_Object *obj, Elm_Activate act)
4379 {
4380    Evas_Object *parent;
4381    Eina_Bool ret;
4382
4383    ELM_WIDGET_CHECK(obj);
4384
4385    ret = EINA_FALSE;
4386
4387    eo_do(obj, ret = elm_obj_widget_activate(act));
4388
4389    if (ret) return;
4390
4391    parent = elm_widget_parent_get(obj);
4392    if (parent)
4393      elm_widget_activate(parent, act);
4394
4395    return;
4396 }
4397
4398 /**
4399  * @internal
4400  *
4401  * Sets the widget and child widget's Evas_Display_Mode.
4402  *
4403  * @param obj The widget.
4404  * @param dispmode Evas_Display_Mode to set widget's mode.
4405  *
4406  * Widgets are resized by several reasons.
4407  * Evas_Display_Mode can help for widgets to get one more reason of resize.
4408  * For example, elm conform widget resizes it's contents when keypad state changed.
4409  * After keypad showing, conform widget can change child's Evas_Display_Mode.
4410  * @ingroup Widget
4411  */
4412 EOLIAN static void
4413 _elm_widget_display_mode_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Display_Mode dispmode)
4414 {
4415    Evas_Display_Mode prev_dispmode;
4416    Evas_Object *child;
4417    Eina_List *l;
4418
4419    prev_dispmode = evas_object_size_hint_display_mode_get(obj);
4420
4421    if ((prev_dispmode == dispmode) ||
4422        (prev_dispmode == EVAS_DISPLAY_MODE_DONT_CHANGE)) return;
4423
4424    evas_object_size_hint_display_mode_set(obj, dispmode);
4425
4426    EINA_LIST_FOREACH (sd->subobjs, l, child)
4427      {
4428         if (elm_widget_is(child))
4429           elm_widget_display_mode_set(child, dispmode);
4430      }
4431 }
4432
4433 EOLIAN static void
4434 _elm_widget_orientation_mode_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled)
4435 {
4436    int orient_mode = -1;
4437
4438    if (!disabled)
4439      {
4440         //Get current orient mode from it's parent otherwise, 0.
4441         sd->orient_mode = 0;
4442         ELM_WIDGET_DATA_GET(sd->parent_obj, sd_parent);
4443         if (!sd_parent) orient_mode = 0;
4444         else orient_mode = sd_parent->orient_mode;
4445      }
4446    eo_do(obj, elm_obj_widget_orientation_set(orient_mode));
4447 }
4448
4449 EOLIAN static Eina_Bool
4450 _elm_widget_orientation_mode_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4451 {
4452    if (sd->orient_mode == -1) return EINA_TRUE;
4453    else return EINA_FALSE;
4454 }
4455
4456 EOLIAN static void
4457 _elm_widget_orientation_set(Eo *obj, Elm_Widget_Smart_Data *sd, int orient_mode)
4458 {
4459    Evas_Object *child;
4460    Eina_List *l;
4461
4462    sd->orient_mode = orient_mode;
4463
4464    EINA_LIST_FOREACH (sd->subobjs, l, child)
4465      {
4466         if (elm_widget_is(child))
4467           eo_do(child, elm_obj_widget_orientation_set(orient_mode));
4468      }
4469
4470    if (orient_mode != -1)
4471      {
4472         char buf[128];
4473         snprintf(buf, sizeof(buf), "elm,state,orient,%d", orient_mode);
4474         eo_do(obj, elm_obj_widget_signal_emit(buf, "elm"));
4475      }
4476 }
4477
4478 /**
4479  * @internal
4480  *
4481  * Returns the widget's focus move policy.
4482  *
4483  * @param obj The widget.
4484  * @return focus move policy of the object.
4485  *
4486  **/
4487 EOLIAN static Elm_Focus_Move_Policy
4488 _elm_widget_focus_move_policy_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4489 {
4490    return sd->focus_move_policy;
4491 }
4492
4493 /**
4494  * @internal
4495  *
4496  * Sets the widget's focus move policy.
4497  *
4498  * @param obj The widget.
4499  * @param policy Elm_Focus_Move_Policy to set object's focus move policy.
4500  */
4501
4502 EOLIAN static void
4503 _elm_widget_focus_move_policy_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Move_Policy policy)
4504 {
4505    if (sd->focus_move_policy == policy) return;
4506    sd->focus_move_policy = policy;
4507 }
4508 static void
4509 _track_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
4510
4511 static void
4512 _track_obj_update(Evas_Object *track, Evas_Object *obj)
4513 {
4514    //Geometry
4515    Evas_Coord x, y, w, h;
4516    evas_object_geometry_get(obj, &x, &y, &w, &h);
4517    evas_object_move(track, x, y);
4518    evas_object_resize(track, w, h);
4519
4520    //Visibility
4521    if (evas_object_visible_get(obj)) evas_object_show(track);
4522    else evas_object_hide(track);
4523 }
4524
4525 static Eina_Bool
4526 _track_obj_view_update(void *data, Eo *obj,
4527                        const Eo_Event_Description *desc EINA_UNUSED,
4528                        void *event_info EINA_UNUSED)
4529 {
4530    Elm_Widget_Item_Data *item = data;
4531    _track_obj_update(item->track_obj, obj);
4532    return EO_CALLBACK_CONTINUE;
4533 }
4534
4535 static Eina_Bool
4536 _track_obj_view_del(void *data, Eo *obj EINA_UNUSED,
4537                     const Eo_Event_Description *desc EINA_UNUSED,
4538                     void *event_info EINA_UNUSED);
4539
4540 EO_CALLBACKS_ARRAY_DEFINE(tracker_callbacks,
4541                           { EVAS_OBJECT_EVENT_RESIZE, _track_obj_view_update },
4542                           { EVAS_OBJECT_EVENT_MOVE, _track_obj_view_update },
4543                           { EVAS_OBJECT_EVENT_SHOW, _track_obj_view_update },
4544                           { EVAS_OBJECT_EVENT_HIDE, _track_obj_view_update },
4545                           { EVAS_OBJECT_EVENT_DEL, _track_obj_view_del });
4546
4547 static Eina_Bool
4548 _track_obj_view_del(void *data, Eo *obj EINA_UNUSED,
4549                     const Eo_Event_Description *desc EINA_UNUSED,
4550                     void *event_info EINA_UNUSED)
4551 {
4552    Elm_Widget_Item_Data *item = data;
4553
4554    while (evas_object_ref_get(item->track_obj) > 0)
4555      evas_object_unref(item->track_obj);
4556
4557    evas_object_event_callback_del(item->track_obj, EVAS_CALLBACK_DEL,
4558                                   _track_obj_del);
4559    evas_object_del(item->track_obj);
4560    item->track_obj = NULL;
4561
4562    return EO_CALLBACK_CONTINUE;
4563 }
4564
4565 static void
4566 _track_obj_del(void *data, Evas *e EINA_UNUSED,
4567                     Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
4568 {
4569    Elm_Widget_Item_Data *item = data;
4570    item->track_obj = NULL;
4571
4572    if (!item->view) return;
4573
4574    eo_do(item->view, eo_event_callback_array_del(tracker_callbacks(), item));
4575 }
4576
4577 static void
4578 _elm_widget_item_signal_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission,
4579                            const char *source)
4580 {
4581    Elm_Widget_Item_Signal_Data *wisd = data;
4582    wisd->func(wisd->data, wisd->item, emission, source);
4583 }
4584
4585 static void *
4586 _elm_widget_item_signal_callback_list_get(Elm_Widget_Item_Data *item, Eina_List *position)
4587 {
4588    Elm_Widget_Item_Signal_Data *wisd = eina_list_data_get(position);
4589    void *data;
4590
4591    item->signals = eina_list_remove_list(item->signals, position);
4592    data = wisd->data;
4593
4594    if (_elm_widget_is(item->view))
4595      elm_object_signal_callback_del(item->view,
4596                                     wisd->emission, wisd->source,
4597                                     _elm_widget_item_signal_cb);
4598    else if (eo_isa(item->view, EDJE_OBJECT_CLASS))
4599      edje_object_signal_callback_del_full(item->view,
4600                                           wisd->emission, wisd->source,
4601                                           _elm_widget_item_signal_cb, wisd);
4602
4603    eina_stringshare_del(wisd->emission);
4604    eina_stringshare_del(wisd->source);
4605    free(wisd);
4606
4607    return data;
4608 }
4609
4610 #define ERR_NOT_SUPPORTED(item, method)  ERR("%s does not support %s API.", elm_widget_type_get(item->widget), method);
4611
4612 static Eina_Bool
4613 _eo_del_cb(void *data EINA_UNUSED, Eo *eo_item, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
4614 {
4615    Elm_Widget_Item_Data *item = eo_data_scope_get(eo_item, ELM_WIDGET_ITEM_CLASS);
4616    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_TRUE);
4617    if (item->del_func)
4618       item->del_func((void *) WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj);
4619    return EINA_TRUE;
4620 }
4621
4622 /**
4623  * @internal
4624  *
4625  * Allocate a new Elm_Widget_Item-derived structure.
4626  *
4627  * The goal of this structure is to provide common ground for actions
4628  * that a widget item have, such as the owner widget, callback to
4629  * notify deletion, data pointer and maybe more.
4630  *
4631  * @param widget the owner widget that holds this item, must be an elm_widget!
4632  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
4633  *        be used to allocate memory.
4634  *
4635  * @return allocated memory that is already zeroed out, or NULL on errors.
4636  *
4637  * @see elm_widget_item_new() convenience macro.
4638  * @see elm_widget_item_del() to release memory.
4639  * @ingroup Widget
4640  */
4641 EOLIAN static Eo *
4642 _elm_widget_item_eo_base_constructor(Eo *eo_item, Elm_Widget_Item_Data *item)
4643 {
4644    Evas_Object *widget;
4645    eo_do (eo_item, widget = eo_parent_get());
4646
4647    if (!_elm_widget_is(widget))
4648      {
4649         ERR("Failed");
4650         return NULL;
4651      }
4652
4653    eo_item = eo_do_super_ret(eo_item, ELM_WIDGET_ITEM_CLASS, eo_item, eo_constructor());
4654
4655    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
4656
4657    item->widget = widget;
4658    item->eo_obj = eo_item;
4659    //TIZEN_ONLY(20170717) : expose highlight information on atspi
4660    item->can_highlight = EINA_TRUE;
4661    //
4662
4663    eo_do(eo_item, eo_event_callback_add(EO_BASE_EVENT_DEL, _eo_del_cb, NULL));
4664
4665    return eo_item;
4666 }
4667
4668 EOLIAN static void
4669 _elm_widget_item_eo_base_destructor(Eo *eo_item, Elm_Widget_Item_Data *item)
4670 {
4671    Elm_Translate_String_Data *ts;
4672
4673    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4674
4675    evas_object_del(item->view);
4676
4677    eina_stringshare_del(item->access_info);
4678    eina_stringshare_del(item->accessible_name);
4679
4680    while (item->signals)
4681      _elm_widget_item_signal_callback_list_get(item, item->signals);
4682
4683    while (item->translate_strings)
4684      {
4685         ts = EINA_INLIST_CONTAINER_GET(item->translate_strings,
4686                                        Elm_Translate_String_Data);
4687         eina_stringshare_del(ts->id);
4688         eina_stringshare_del(ts->domain);
4689         eina_stringshare_del(ts->string);
4690         item->translate_strings = eina_inlist_remove(item->translate_strings,
4691                                                      item->translate_strings);
4692         free(ts);
4693      }
4694    eina_hash_free(item->labels);
4695
4696    eo_do(eo_item,
4697          elm_interface_atspi_accessible_description_set(NULL),
4698          elm_interface_atspi_accessible_name_set(NULL),
4699          //TIZEN_ONLY(20190922): add name callback, description callback.
4700          elm_interface_atspi_accessible_description_cb_set(NULL, NULL),
4701          elm_interface_atspi_accessible_name_cb_set(NULL, NULL),
4702          //
4703          elm_interface_atspi_accessible_translation_domain_set(NULL),
4704          elm_interface_atspi_accessible_relationships_clear(),
4705                  // TIZEN_ONLY(20160930) : endless recursion fix
4706          elm_interface_atspi_accessible_attributes_clear()
4707                  //
4708          );
4709
4710    if (item->name)
4711      eina_stringshare_del(item->name);
4712
4713    if (item->atspi_custom_relations)
4714      elm_atspi_relation_set_free(&item->atspi_custom_relations);
4715
4716    //TIZEN_ONLY(20150731) : add i18n support for name and description
4717    if (item->atspi_translation_domain)
4718      eina_stringshare_del(item->atspi_translation_domain);
4719    //
4720    //Tizen Only(20160728) free attribute list
4721    if (item->attr_list)
4722    {
4723       Elm_Atspi_Attribute *attr;
4724       EINA_LIST_FREE(item->attr_list, attr)
4725        {
4726           eina_stringshare_del(attr->key);
4727           eina_stringshare_del(attr->value);
4728           free(attr);
4729        }
4730    }
4731    //
4732
4733 //TIZEN_ONLY(20161013): clean up elm color class feature
4734    if (item->color_classes)
4735      ELM_SAFE_FREE(item->color_classes, eina_hash_free);
4736 //
4737
4738    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
4739
4740    eo_do_super(eo_item, ELM_WIDGET_ITEM_CLASS, eo_destructor());
4741 }
4742
4743 /**
4744  * @internal
4745  *
4746  * Releases widget item memory, calling back item_del_pre_hook() and
4747  * item_del_cb() if they exist.
4748  *
4749  * @param item a valid #Elm_Widget_Item to be deleted.
4750  *
4751  * If there is an Elm_Widget_Item::del_cb, then it will be called prior
4752  * to memory release. Note that elm_widget_item_pre_notify_del() calls
4753  * this function and then unset it, thus being useful for 2 step
4754  * cleanup whenever the del_cb may use any of the data that must be
4755  * deleted from item.
4756  *
4757  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
4758  * is presented!
4759  *
4760  * Note that if item_del_pre_hook() returns @c EINA_TRUE, item free will be
4761  * deferred, or item will be freed here if it returns @c EINA_FALSE.
4762  *
4763  * @see elm_widget_item_del() convenience macro.
4764  * @ingroup Widget
4765  */
4766 EOLIAN static void
4767 _elm_widget_item_del(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4768 {
4769    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4770    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4771    item->on_deletion = EINA_TRUE;
4772
4773    //Widget item delete callback
4774    Eina_Bool del_ok;
4775    eo_do(item->eo_obj, del_ok = elm_wdg_item_del_pre());
4776    if (del_ok)
4777       eo_del(item->eo_obj);
4778    return;
4779 }
4780
4781 EOLIAN static Eina_Bool
4782 _elm_widget_item_del_pre(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
4783 {
4784    return EINA_TRUE;
4785 }
4786
4787 /**
4788  * @internal
4789  *
4790  * Notify object will be deleted without actually deleting it.
4791  *
4792  * This function will callback Elm_Widget_Item::del_cb if it is set
4793  * and then unset it so it is not called twice (ie: from
4794  * elm_widget_item_del()).
4795  *
4796  * @param item a valid #Elm_Widget_Item to be notified
4797  * @see elm_widget_item_pre_notify_del() convenience macro.
4798  * @ingroup Widget
4799  */
4800 EOLIAN static void
4801 _elm_widget_item_pre_notify_del(Eo *eo_item, Elm_Widget_Item_Data *item)
4802 {
4803    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4804    if (!item->del_func) return;
4805    item->del_func((void *)WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj);
4806    item->del_func = NULL;
4807 }
4808
4809 /**
4810  * @internal
4811  *
4812  * Set the function to notify when item is being deleted.
4813  *
4814  * This function will complain if there was a callback set already,
4815  * however it will set the new one.
4816  *
4817  * The callback will be called from elm_widget_item_pre_notify_del()
4818  * or elm_widget_item_del() will be called with:
4819  *   - data: the Elm_Widget_Item::data value.
4820  *   - obj: the Elm_Widget_Item::widget evas object.
4821  *   - event_info: the item being deleted.
4822  *
4823  * @param item a valid #Elm_Widget_Item to be notified
4824  * @see elm_widget_item_del_cb_set() convenience macro.
4825  * @ingroup Widget
4826  */
4827 EOLIAN static void
4828 _elm_widget_item_del_cb_set(Eo *eo_item EINA_UNUSED,
4829                             Elm_Widget_Item_Data *item,
4830                             Evas_Smart_Cb func)
4831 {
4832    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4833    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4834
4835    if ((item->del_func) && (item->del_func != func))
4836      WRN("You're replacing a previously set del_cb %p of item %p with %p",
4837          item->del_func, item->eo_obj, func);
4838
4839    item->del_func = func;
4840 }
4841
4842 /**
4843  * @internal
4844  *
4845  * Get owner widget of this item.
4846  *
4847  * @param item a valid #Elm_Widget_Item to get data from.
4848  * @return owner widget of this item.
4849  * @ingroup Widget
4850  */
4851 EOLIAN static Evas_Object *
4852 _elm_widget_item_widget_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4853 {
4854    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4855    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4856
4857    return item->widget;
4858 }
4859
4860 EAPI Eina_Bool
4861 _elm_widget_onscreen_is(Evas_Object *widget)
4862 {
4863    Evas_Object *parent = widget;
4864    Evas_Coord x, y, w, h, wx, wy, ww, wh;
4865
4866    Evas *evas = evas_object_evas_get(widget);
4867    if (!evas) return EINA_FALSE;
4868
4869    // check if on canvas
4870    evas_output_viewport_get(evas, &x, &y, &w, &h);
4871    evas_object_geometry_get(widget, &wx, &wy, &ww, &wh);
4872    if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4873        ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4874      return EINA_FALSE;
4875
4876    // check if inside scrollable parent viewport
4877    do {
4878       parent = elm_widget_parent_get(parent);
4879       if (parent && !evas_object_visible_get(parent))
4880         return EINA_FALSE;
4881       if (parent && eo_isa(parent, ELM_INTERFACE_SCROLLABLE_MIXIN))
4882         {
4883            evas_object_geometry_get(parent, &x, &y, &w, &h);
4884            if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4885                ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4886              return EINA_FALSE;
4887         }
4888    } while (parent && (parent != elm_widget_top_get(widget)));
4889
4890    return EINA_TRUE;
4891 }
4892
4893 EAPI Eina_Bool
4894 _elm_widget_item_onscreen_is(Elm_Object_Item *item)
4895 {
4896    Evas_Coord x, y, w, h, wx, wy, ww, wh;
4897    Elm_Widget_Item_Data *id = eo_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
4898    if (!id || !id->view) return EINA_FALSE;
4899
4900    if (!evas_object_visible_get(id->view))
4901      return EINA_FALSE;
4902
4903    if (!_elm_widget_onscreen_is(id->widget))
4904      return EINA_FALSE;
4905
4906    evas_object_geometry_get(id->view, &x, &y, &w, &h);
4907    evas_object_geometry_get(id->widget, &wx, &wy, &ww, &wh);
4908    if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4909        ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4910      return EINA_FALSE;
4911
4912    return EINA_TRUE;
4913 }
4914
4915 //TIZEN_ONLY(20161107): enhance elm_atspi_accessible_can_highlight_set to set can_hihglight property to its children
4916 EAPI Eina_Bool
4917 _elm_widget_item_highlightable(Elm_Object_Item *item)
4918 {
4919    Elm_Widget_Item_Data *id = eo_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
4920    if (!id) return EINA_FALSE;
4921    if (!id->can_highlight) return EINA_FALSE;
4922    Evas_Object *widget = id->widget;
4923    Evas_Object *parent = widget;
4924    Elm_Widget_Smart_Data *wd;
4925    if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
4926      {
4927         wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
4928         if (!wd->can_highlight) return EINA_FALSE;
4929      }
4930    do
4931      {
4932         parent = elm_widget_parent_get(parent);
4933         if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
4934           {
4935              wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
4936              if (!wd->can_highlight) return EINA_FALSE;
4937           }
4938      }
4939    while (parent && (parent != elm_widget_top_get(widget)));
4940    return EINA_TRUE;
4941 }
4942 //
4943
4944 EOLIAN static Elm_Atspi_State_Set
4945 _elm_widget_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_item,
4946                                                               Elm_Widget_Item_Data *item)
4947 {
4948    Elm_Atspi_State_Set states = 0;
4949
4950    STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE);
4951
4952    if (elm_object_item_focus_get(eo_item))
4953      STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED);
4954    if (!elm_object_item_disabled_get(eo_item))
4955      {
4956         STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED);
4957         STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE);
4958         STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE);
4959      }
4960    if (_elm_widget_item_onscreen_is(eo_item))
4961      STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING);
4962
4963    //TIZEN_ONLY(20170717) : expose highlight information on atspi
4964    if (_elm_widget_item_highlightable(eo_item))
4965      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
4966    else
4967      STATE_TYPE_UNSET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
4968
4969    if (_elm_object_accessibility_currently_highlighted_get() == (void*)item->eo_obj)
4970      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTED);
4971    //
4972    return states;
4973 }
4974
4975 EOLIAN static Eo*
4976 _elm_widget_item_elm_interface_atspi_accessible_parent_get(Eo *eo_item, Elm_Widget_Item_Data *item EINA_UNUSED)
4977 {
4978    Eo *parent;
4979    eo_do(eo_item, parent = eo_parent_get());
4980    return parent;
4981 }
4982
4983 EAPI void
4984 elm_object_item_data_set(Elm_Object_Item *it, void *data)
4985 {
4986    WIDGET_ITEM_DATA_SET(it, data);
4987 }
4988
4989 EAPI void *
4990 elm_object_item_data_get(const Elm_Object_Item *it)
4991 {
4992    return (void *) WIDGET_ITEM_DATA_GET(it);
4993 }
4994
4995 EOLIAN static void
4996 _elm_widget_item_disabled_set(Eo *eo_item EINA_UNUSED,
4997                               Elm_Widget_Item_Data *item,
4998                               Eina_Bool disabled)
4999 {
5000    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5001    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5002
5003    if (item->disabled == disabled) return;
5004    item->disabled = !!disabled;
5005    eo_do(item->eo_obj, elm_wdg_item_disable());
5006 }
5007
5008 EOLIAN static Eina_Bool
5009 _elm_widget_item_disabled_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5010 {
5011    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5012    return item->disabled;
5013 }
5014
5015 EOLIAN static void
5016 _elm_widget_item_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style EINA_UNUSED)
5017 {
5018    ERR_NOT_SUPPORTED(item, "elm_object_style_set()");
5019 }
5020
5021 EOLIAN static const char *
5022 _elm_widget_item_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5023 {
5024    ERR_NOT_SUPPORTED(item, "elm_object_style_get()");
5025    return NULL;
5026 }
5027
5028 EOLIAN static void
5029 _elm_widget_item_disable(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
5030 {
5031 }
5032
5033 EOLIAN static void
5034 _elm_widget_item_focus_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool focused EINA_UNUSED)
5035 {
5036    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_set");
5037 }
5038
5039 EOLIAN static Eina_Bool
5040 _elm_widget_item_focus_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5041 {
5042    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_get");
5043    return EINA_FALSE;
5044 }
5045
5046 EOLIAN static void
5047 _elm_widget_item_domain_translatable_part_text_set(Eo *eo_item EINA_UNUSED,
5048                                                    Elm_Widget_Item_Data *item,
5049                                                    const char *part,
5050                                                    const char *domain,
5051                                                    const char *label)
5052 {
5053    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5054    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5055    Elm_Translate_String_Data *ts;
5056
5057    if (!label)
5058      {
5059         _part_text_translatable_set(&item->translate_strings, part, EINA_FALSE,
5060                                     EINA_FALSE);
5061      }
5062    else
5063      {
5064         ts = _part_text_translatable_set(&item->translate_strings, part,
5065                                          EINA_TRUE, EINA_FALSE);
5066         if (!ts) return;
5067         if (!ts->string) ts->string = eina_stringshare_add(label);
5068         else eina_stringshare_replace(&ts->string, label);
5069         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
5070         else eina_stringshare_replace(&ts->domain, domain);
5071 #ifdef HAVE_GETTEXT
5072         if (label[0]) label = dgettext(domain, label);
5073 #endif
5074      }
5075    item->on_translate = EINA_TRUE;
5076    eo_do(item->eo_obj, elm_wdg_item_part_text_set(part, label));
5077    item->on_translate = EINA_FALSE;
5078 }
5079
5080 EOLIAN static const char *
5081 _elm_widget_item_translatable_part_text_get(const Eo *eo_item EINA_UNUSED,
5082                                             Elm_Widget_Item_Data *item,
5083                                             const char *part)
5084 {
5085    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5086    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5087
5088    Elm_Translate_String_Data *ts;
5089    ts = _translate_string_data_get(item->translate_strings, part);
5090    if (ts) return ts->string;
5091    return NULL;
5092 }
5093
5094 EOLIAN static void
5095 _elm_widget_item_domain_part_text_translatable_set(Eo *eo_item EINA_UNUSED,
5096                                                    Elm_Widget_Item_Data *item,
5097                                                    const char *part,
5098                                                    const char *domain,
5099                                                    Eina_Bool translatable)
5100 {
5101    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5102    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5103    Elm_Translate_String_Data *ts;
5104    const char *text;
5105
5106    ts = _part_text_translatable_set(&item->translate_strings, part,
5107                                     translatable, EINA_TRUE);
5108    if (!ts) return;
5109    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
5110    else eina_stringshare_replace(&ts->domain, domain);
5111
5112    eo_do(item->eo_obj, text = elm_wdg_item_part_text_get(part));
5113
5114    if (!text || !text[0]) return;
5115
5116    if (!ts->string) ts->string = eina_stringshare_add(text);
5117
5118 //Try to translate text since we don't know the text is already translated.
5119 #ifdef HAVE_GETTEXT
5120    text = dgettext(domain, text);
5121 #endif
5122    item->on_translate = EINA_TRUE;
5123    eo_do (item->eo_obj, elm_wdg_item_part_text_set(part, text));
5124    item->on_translate = EINA_FALSE;
5125 }
5126
5127 EOLIAN static void
5128 _elm_widget_item_track_cancel(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5129 {
5130    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5131    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5132
5133    if (!item->track_obj) return;
5134
5135    while (evas_object_ref_get(item->track_obj) > 0)
5136      evas_object_unref(item->track_obj);
5137
5138    evas_object_del(item->track_obj);
5139 }
5140
5141 EOLIAN static Evas_Object *
5142 _elm_widget_item_track(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5143 {
5144    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5145    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5146
5147    if (item->track_obj)
5148      {
5149         evas_object_ref(item->track_obj);
5150         return item->track_obj;
5151      }
5152
5153    if (!item->view)
5154      {
5155         WRN("view obj of the item(%p) is invalid. Please make sure the view obj is created!", item);
5156         return NULL;
5157      }
5158
5159    Evas_Object *track =
5160       evas_object_rectangle_add(evas_object_evas_get(item->widget));
5161    evas_object_color_set(track, 0, 0, 0, 0);
5162    evas_object_pass_events_set(track, EINA_TRUE);
5163    _track_obj_update(track, item->view);
5164    evas_object_event_callback_add(track, EVAS_CALLBACK_DEL, _track_obj_del,
5165                                   item);
5166
5167    eo_do(item->view,
5168          eo_event_callback_array_add(tracker_callbacks(), item));
5169
5170    evas_object_ref(track);
5171
5172    item->track_obj = track;
5173
5174    return track;
5175 }
5176
5177 EOLIAN static void
5178 _elm_widget_item_untrack(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5179 {
5180    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5181    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5182
5183    if (!item->track_obj) return;
5184    evas_object_unref(item->track_obj);
5185
5186    if (evas_object_ref_get(item->track_obj) == 0)
5187      evas_object_del(item->track_obj);
5188 }
5189
5190 EOLIAN static int
5191 _elm_widget_item_track_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5192 {
5193    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, 0);
5194    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, 0);
5195
5196    if (!item->track_obj) return 0;
5197    return evas_object_ref_get(item->track_obj);
5198 }
5199
5200 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
5201
5202 struct _Elm_Widget_Item_Tooltip
5203 {
5204    Elm_Widget_Item_Data       *item;
5205    Elm_Tooltip_Item_Content_Cb func;
5206    Evas_Smart_Cb               del_cb;
5207    const void                 *data;
5208 };
5209
5210 static Evas_Object *
5211 _elm_widget_item_tooltip_label_create(void *data,
5212                                       Evas_Object *obj EINA_UNUSED,
5213                                       Evas_Object *tooltip,
5214                                       void *item EINA_UNUSED)
5215 {
5216    Evas_Object *label = elm_label_add(tooltip);
5217    if (!label)
5218      return NULL;
5219    elm_object_style_set(label, "tooltip");
5220    elm_object_text_set(label, data);
5221    return label;
5222 }
5223
5224 static Evas_Object *
5225 _elm_widget_item_tooltip_trans_label_create(void *data,
5226                                             Evas_Object *obj EINA_UNUSED,
5227                                             Evas_Object *tooltip,
5228                                             void *item EINA_UNUSED)
5229 {
5230    Evas_Object *label = elm_label_add(tooltip);
5231    if (!label)
5232      return NULL;
5233    elm_object_style_set(label, "tooltip");
5234    elm_object_translatable_text_set(label, data);
5235    return label;
5236 }
5237
5238 static void
5239 _elm_widget_item_tooltip_label_del_cb(void *data,
5240                                       Evas_Object *obj EINA_UNUSED,
5241                                       void *event_info EINA_UNUSED)
5242 {
5243    eina_stringshare_del(data);
5244 }
5245
5246 /**
5247  * @internal
5248  *
5249  * Set the text to be shown in the widget item.
5250  *
5251  * @param item Target item
5252  * @param text The text to set in the content
5253  *
5254  * Setup the text as tooltip to object. The item can have only one tooltip,
5255  * so any previous tooltip data is removed.
5256  *
5257  * @ingroup Widget
5258  */
5259 EOLIAN static void
5260 _elm_widget_item_tooltip_text_set(Eo *eo_item EINA_UNUSED,
5261                                   Elm_Widget_Item_Data *item EINA_UNUSED,
5262                                   const char *text)
5263 {
5264    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5265    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5266    EINA_SAFETY_ON_NULL_RETURN(text);
5267
5268    text = eina_stringshare_add(text);
5269    eo_do(item->eo_obj, elm_wdg_item_tooltip_content_cb_set(
5270             _elm_widget_item_tooltip_label_create,
5271             text,
5272             _elm_widget_item_tooltip_label_del_cb));
5273 }
5274
5275 EOLIAN static void
5276 _elm_widget_item_tooltip_translatable_text_set(Eo *eo_item EINA_UNUSED,
5277                                                Elm_Widget_Item_Data *item EINA_UNUSED,
5278                                                const char *text)
5279 {
5280    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5281    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5282    EINA_SAFETY_ON_NULL_RETURN(text);
5283
5284    text = eina_stringshare_add(text);
5285    eo_do(item->eo_obj, elm_wdg_item_tooltip_content_cb_set(
5286             _elm_widget_item_tooltip_trans_label_create,
5287             text,
5288             _elm_widget_item_tooltip_label_del_cb));
5289 }
5290
5291 static Evas_Object *
5292 _elm_widget_item_tooltip_create(void *data,
5293                                 Evas_Object *obj,
5294                                 Evas_Object *tooltip)
5295 {
5296    Elm_Widget_Item_Tooltip *wit = data;
5297    return wit->func((void *)wit->data, obj, tooltip, wit->item->eo_obj);
5298 }
5299
5300 static void
5301 _elm_widget_item_tooltip_del_cb(void *data,
5302                                 Evas_Object *obj,
5303                                 void *event_info EINA_UNUSED)
5304 {
5305    Elm_Widget_Item_Tooltip *wit = data;
5306    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item->eo_obj);
5307    free(wit);
5308 }
5309
5310 /**
5311  * @internal
5312  *
5313  * Set the content to be shown in the tooltip item
5314  *
5315  * Setup the tooltip to item. The item can have only one tooltip,
5316  * so any previous tooltip data is removed. @p func(with @p data) will
5317  * be called every time that need show the tooltip and it should
5318  * return a valid Evas_Object. This object is then managed fully by
5319  * tooltip system and is deleted when the tooltip is gone.
5320  *
5321  * @param item the widget item being attached a tooltip.
5322  * @param func the function used to create the tooltip contents.
5323  * @param data what to provide to @a func as callback data/context.
5324  * @param del_cb called when data is not needed anymore, either when
5325  *        another callback replaces @func, the tooltip is unset with
5326  *        elm_widget_item_tooltip_unset() or the owner @a item
5327  *        dies. This callback receives as the first parameter the
5328  *        given @a data, and @c event_info is the item.
5329  *
5330  * @ingroup Widget
5331  */
5332 EOLIAN static void
5333 _elm_widget_item_tooltip_content_cb_set(Eo *eo_item EINA_UNUSED,
5334                                         Elm_Widget_Item_Data *item,
5335                                         Elm_Tooltip_Item_Content_Cb func,
5336                                         const void *data,
5337                                         Evas_Smart_Cb del_cb)
5338 {
5339    Elm_Widget_Item_Tooltip *wit;
5340
5341    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
5342    //ELM_WIDGET_ITEM_RETURN_IF_GOTO(item, error_noitem);
5343
5344    if (!func)
5345      {
5346         eo_do(item->eo_obj, elm_wdg_item_tooltip_unset());
5347         return;
5348      }
5349
5350    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
5351    if (!wit) goto error;
5352    wit->item = item;
5353    wit->func = func;
5354    wit->data = data;
5355    wit->del_cb = del_cb;
5356
5357    elm_object_sub_tooltip_content_cb_set
5358      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
5359      _elm_widget_item_tooltip_del_cb);
5360
5361    return;
5362
5363 error_noitem:
5364    if (del_cb) del_cb((void *)data, NULL, item);
5365    return;
5366 error:
5367    if (del_cb) del_cb((void *)data, item->widget, item);
5368 }
5369
5370 /**
5371  * @internal
5372  *
5373  * Unset tooltip from item
5374  *
5375  * @param item widget item to remove previously set tooltip.
5376  *
5377  * Remove tooltip from item. The callback provided as del_cb to
5378  * elm_widget_item_tooltip_content_cb_set() will be called to notify
5379  * it is not used anymore.
5380  *
5381  * @see elm_widget_item_tooltip_content_cb_set()
5382  *
5383  * @ingroup Widget
5384  */
5385 EOLIAN static void
5386 _elm_widget_item_tooltip_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5387 {
5388    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5389    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5390
5391    elm_object_tooltip_unset(item->view);
5392 }
5393
5394 /**
5395  * @internal
5396  *
5397  * Sets a different style for this item tooltip.
5398  *
5399  * @note before you set a style you should define a tooltip with
5400  *       elm_widget_item_tooltip_content_cb_set() or
5401  *       elm_widget_item_tooltip_text_set()
5402  *
5403  * @param item widget item with tooltip already set.
5404  * @param style the theme style to use (default, transparent, ...)
5405  *
5406  * @ingroup Widget
5407  */
5408 EOLIAN static void
5409 _elm_widget_item_tooltip_style_set(Eo *eo_item EINA_UNUSED,
5410                                    Elm_Widget_Item_Data *item,
5411                                    const char *style)
5412 {
5413    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5414    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5415
5416    elm_object_tooltip_style_set(item->view, style);
5417 }
5418
5419 EOLIAN static Eina_Bool
5420 _elm_widget_item_tooltip_window_mode_set(Eo *eo_item EINA_UNUSED,
5421                                          Elm_Widget_Item_Data *item,
5422                                          Eina_Bool disable)
5423 {
5424    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5425    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
5426
5427    return elm_object_tooltip_window_mode_set(item->view, disable);
5428 }
5429
5430 EOLIAN static Eina_Bool
5431 _elm_widget_item_tooltip_window_mode_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5432 {
5433    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5434    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
5435
5436    return elm_object_tooltip_window_mode_get(item->view);
5437 }
5438
5439 /**
5440  * @internal
5441  *
5442  * Get the style for this item tooltip.
5443  *
5444  * @param item widget item with tooltip already set.
5445  * @return style the theme style in use, defaults to "default". If the
5446  *         object does not have a tooltip set, then NULL is returned.
5447  *
5448  * @ingroup Widget
5449  */
5450 EOLIAN static const char *
5451 _elm_widget_item_tooltip_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5452 {
5453    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5454
5455    return elm_object_tooltip_style_get(item->view);
5456 }
5457
5458 EOLIAN static void
5459 _elm_widget_item_cursor_set(Eo *eo_item EINA_UNUSED,
5460                             Elm_Widget_Item_Data *item,
5461                             const char *cursor)
5462 {
5463    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5464    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5465
5466    elm_object_sub_cursor_set(item->view, item->widget, cursor);
5467 }
5468
5469 EOLIAN static const char *
5470 _elm_widget_item_cursor_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5471 {
5472    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5473    return elm_object_cursor_get(item->view);
5474 }
5475
5476 EOLIAN static void
5477 _elm_widget_item_cursor_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5478 {
5479    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5480    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5481
5482    elm_object_cursor_unset(item->view);
5483 }
5484
5485 /**
5486  * @internal
5487  *
5488  * Sets a different style for this item cursor.
5489  *
5490  * @note before you set a style you should define a cursor with
5491  *       elm_widget_item_cursor_set()
5492  *
5493  * @param item widget item with cursor already set.
5494  * @param style the theme style to use (default, transparent, ...)
5495  *
5496  * @ingroup Widget
5497  */
5498 EOLIAN static void
5499 _elm_widget_item_cursor_style_set(Eo *eo_item EINA_UNUSED,
5500                                   Elm_Widget_Item_Data *item,
5501                                   const char *style)
5502 {
5503    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5504    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5505
5506    elm_object_cursor_style_set(item->view, style);
5507 }
5508
5509 /**
5510  * @internal
5511  *
5512  * Get the style for this item cursor.
5513  *
5514  * @param item widget item with cursor already set.
5515  * @return style the theme style in use, defaults to "default". If the
5516  *         object does not have a cursor set, then NULL is returned.
5517  *
5518  * @ingroup Widget
5519  */
5520 EOLIAN static const char *
5521 _elm_widget_item_cursor_style_get(Eo *eo_item EINA_UNUSED,
5522                                   Elm_Widget_Item_Data *item)
5523 {
5524    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5525    return elm_object_cursor_style_get(item->view);
5526 }
5527
5528 /**
5529  * @internal
5530  *
5531  * Set if the cursor set should be searched on the theme or should use
5532  * the provided by the engine, only.
5533  *
5534  * @note before you set if should look on theme you should define a cursor
5535  * with elm_object_cursor_set(). By default it will only look for cursors
5536  * provided by the engine.
5537  *
5538  * @param item widget item with cursor already set.
5539  * @param engine_only boolean to define it cursors should be looked only
5540  * between the provided by the engine or searched on widget's theme as well.
5541  *
5542  * @ingroup Widget
5543  */
5544 EOLIAN static void
5545 _elm_widget_item_cursor_engine_only_set(Eo *eo_item EINA_UNUSED,
5546                                         Elm_Widget_Item_Data *item,
5547                                         Eina_Bool engine_only)
5548 {
5549    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5550    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5551
5552    elm_object_cursor_theme_search_enabled_set(item->view, !engine_only);
5553 }
5554
5555 /**
5556  * @internal
5557  *
5558  * Get the cursor engine only usage for this item cursor.
5559  *
5560  * @param item widget item with cursor already set.
5561  * @return engine_only boolean to define it cursors should be looked only
5562  * between the provided by the engine or searched on widget's theme as well. If
5563  *         the object does not have a cursor set, then EINA_FALSE is returned.
5564  *
5565  * @ingroup Widget
5566  */
5567 EOLIAN static Eina_Bool
5568 _elm_widget_item_cursor_engine_only_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5569 {
5570    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5571    return !elm_object_cursor_theme_search_enabled_get(item->view);
5572 }
5573
5574 EOLIAN static void
5575 _elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED,
5576                                   Elm_Widget_Item_Data *item,
5577                                   const char *part EINA_UNUSED,
5578                                   Evas_Object *content EINA_UNUSED)
5579 {
5580    ERR_NOT_SUPPORTED(item, "elm_object_part_content_set()");
5581 }
5582
5583 EOLIAN static Evas_Object *
5584 _elm_widget_item_part_content_get(Eo *eo_item EINA_UNUSED,
5585                                   Elm_Widget_Item_Data *item,
5586                                   const char *part EINA_UNUSED)
5587 {
5588    ERR_NOT_SUPPORTED(item, "elm_object_part_content_get()");
5589    return NULL;
5590 }
5591
5592 EOLIAN static Evas_Object *
5593 _elm_widget_item_part_content_unset(Eo *eo_item EINA_UNUSED,
5594                                     Elm_Widget_Item_Data *item,
5595                                     const char *part EINA_UNUSED)
5596 {
5597    ERR_NOT_SUPPORTED(item, "elm_object_part_content_unset()");
5598    return NULL;
5599 }
5600
5601 EOLIAN static void
5602 _elm_widget_item_part_text_set(Eo *eo_item EINA_UNUSED,
5603                                Elm_Widget_Item_Data *item,
5604                                const char *part EINA_UNUSED,
5605                                const char *label EINA_UNUSED)
5606 {
5607    ERR_NOT_SUPPORTED(item, "elm_object_part_text_set()");
5608 }
5609
5610 EOLIAN static const char *
5611 _elm_widget_item_part_text_get(Eo *eo_item EINA_UNUSED,
5612                                Elm_Widget_Item_Data *item,
5613                                const char *part EINA_UNUSED)
5614 {
5615    ERR_NOT_SUPPORTED(item, "elm_object_part_text_get()");
5616    return NULL;
5617 }
5618
5619 static void
5620 _elm_widget_item_part_text_custom_free(void *data)
5621 {
5622    Elm_Label_Data *label;
5623    label = data;
5624    eina_stringshare_del(label->part);
5625    eina_stringshare_del(label->text);
5626    free(label);
5627 }
5628
5629 EOLIAN static void
5630 _elm_widget_item_part_text_custom_set(Eo *eo_item EINA_UNUSED,
5631                                       Elm_Widget_Item_Data *item,
5632                                       const char *part,
5633                                       const char *text)
5634 {
5635    Elm_Label_Data *label;
5636    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5637    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5638
5639    if (!item->labels)
5640      item->labels =
5641         eina_hash_stringshared_new(_elm_widget_item_part_text_custom_free);
5642    label = eina_hash_find(item->labels, part);
5643    if (!label)
5644      {
5645         label = malloc(sizeof(Elm_Label_Data));
5646         if (!label)
5647           {
5648              ERR("Failed to allocate memory");
5649              return;
5650           }
5651         label->part = eina_stringshare_add(part);
5652         label->text = eina_stringshare_add(text);
5653         eina_hash_add(item->labels, part, label);
5654      }
5655    else
5656      eina_stringshare_replace(&label->text, text);
5657 }
5658
5659 EOLIAN static const char *
5660 _elm_widget_item_part_text_custom_get(Eo *eo_item EINA_UNUSED,
5661                                       Elm_Widget_Item_Data *item,
5662                                       const char *part)
5663 {
5664    Elm_Label_Data *label;
5665    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5666    label = eina_hash_find(item->labels, part);
5667    return label ? label->text : NULL;
5668 }
5669
5670 static Eina_Bool
5671 _elm_widget_item_part_text_custom_foreach(const Eina_Hash *labels EINA_UNUSED,
5672                                           const void *key EINA_UNUSED,
5673                                           void *data,
5674                                           void *func_data)
5675 {
5676    Elm_Label_Data *label;
5677    Elm_Widget_Item_Data *item;
5678    label = data;
5679    item = func_data;
5680
5681    eo_do(item->eo_obj, elm_wdg_item_part_text_set(label->part, label->text));
5682
5683    return EINA_TRUE;
5684 }
5685
5686 EOLIAN static void
5687 _elm_widget_item_part_text_custom_update(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5688 {
5689    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5690    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5691    if (item->labels)
5692      eina_hash_foreach(item->labels,
5693                        _elm_widget_item_part_text_custom_foreach, item);
5694 }
5695
5696 EOLIAN static void
5697 _elm_widget_item_signal_emit(Eo *eo_item EINA_UNUSED,
5698                              Elm_Widget_Item_Data *item EINA_UNUSED,
5699                              const char *emission EINA_UNUSED,
5700                              const char *source EINA_UNUSED)
5701 {
5702
5703 }
5704
5705 EOLIAN static void
5706 _elm_widget_item_signal_callback_add(Eo *eo_item,
5707                                      Elm_Widget_Item_Data *item,
5708                                      const char *emission,
5709                                      const char *source,
5710                                      Elm_Object_Item_Signal_Cb func,
5711                                      void *data)
5712 {
5713    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5714    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5715    EINA_SAFETY_ON_NULL_RETURN(func);
5716
5717    Elm_Widget_Item_Signal_Data *wisd;
5718
5719    wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data));
5720    if (!wisd) return;
5721
5722    wisd->item = eo_item;
5723    wisd->func = (Elm_Widget_Item_Signal_Cb)func;
5724    wisd->data = data;
5725    wisd->emission = eina_stringshare_add(emission);
5726    wisd->source = eina_stringshare_add(source);
5727
5728    if (_elm_widget_is(item->view))
5729      elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
5730    else if (eo_isa(item->view, EDJE_OBJECT_CLASS))
5731      edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
5732    else
5733      {
5734         WRN("The %s widget item doesn't support signal callback add!",
5735             eo_class_name_get(eo_class_get(item->widget)));
5736         free(wisd);
5737         return;
5738      }
5739
5740    item->signals = eina_list_append(item->signals, wisd);
5741 }
5742
5743 EOLIAN static void *
5744 _elm_widget_item_signal_callback_del(Eo *eo_item EINA_UNUSED,
5745                                      Elm_Widget_Item_Data *item,
5746                                      const char *emission,
5747                                      const char *source,
5748                                      Elm_Object_Item_Signal_Cb func)
5749 {
5750    Elm_Widget_Item_Signal_Data *wisd;
5751    Eina_List *l;
5752
5753    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5754    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5755    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
5756
5757    EINA_LIST_FOREACH(item->signals, l, wisd)
5758      {
5759         if ((wisd->func == (Elm_Widget_Item_Signal_Cb)func) &&
5760             !strcmp(wisd->emission, emission) &&
5761             !strcmp(wisd->source, source))
5762           return _elm_widget_item_signal_callback_list_get(item, l);
5763      }
5764
5765    return NULL;
5766 }
5767
5768 EOLIAN static void
5769 _elm_widget_item_access_info_set(Eo *eo_item EINA_UNUSED,
5770                                  Elm_Widget_Item_Data *item,
5771                                  const char *txt)
5772 {
5773    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5774    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5775
5776    eina_stringshare_del(item->access_info);
5777    if (!txt) item->access_info = NULL;
5778    else item->access_info = eina_stringshare_add(txt);
5779 }
5780
5781 EOLIAN static void
5782 _elm_widget_item_translate(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5783 {
5784    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5785    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5786
5787 #ifdef HAVE_GETTEXT
5788    Elm_Translate_String_Data *ts;
5789    EINA_INLIST_FOREACH(item->translate_strings, ts)
5790      {
5791         if (!ts->string) continue;
5792         const char *s = dgettext(ts->domain, ts->string);
5793         item->on_translate = EINA_TRUE;
5794         eo_do(item->eo_obj, elm_wdg_item_part_text_set(ts->id, s));
5795         item->on_translate = EINA_FALSE;
5796      }
5797 #endif
5798 }
5799
5800 EOLIAN static void
5801 _elm_widget_item_access_order_set(Eo *eo_item EINA_UNUSED,
5802                                   Elm_Widget_Item_Data *item,
5803                                   Eina_List *objs)
5804 {
5805    _elm_access_widget_item_access_order_set(item, objs);
5806 }
5807
5808 EOLIAN static const Eina_List *
5809 _elm_widget_item_access_order_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5810 {
5811    return _elm_access_widget_item_access_order_get(item);
5812 }
5813
5814 EOLIAN static void
5815 _elm_widget_item_access_order_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5816 {
5817    _elm_access_widget_item_access_order_unset(item);
5818 }
5819
5820 EOLIAN static Evas_Object*
5821 _elm_widget_item_access_register(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5822 {
5823    _elm_access_widget_item_register(item);
5824    return item->access_obj;
5825 }
5826
5827 EOLIAN static void
5828 _elm_widget_item_access_unregister(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5829 {
5830    _elm_access_widget_item_unregister(item);
5831 }
5832
5833 EOLIAN static Evas_Object*
5834 _elm_widget_item_access_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5835 {
5836    return item->access_obj;
5837 }
5838
5839 EOLIAN static Evas_Object *
5840 _elm_widget_item_focus_next_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
5841 {
5842    Evas_Object *ret = NULL;
5843
5844    if (dir == ELM_FOCUS_PREVIOUS)
5845      ret = item->focus_previous;
5846    else if (dir == ELM_FOCUS_NEXT)
5847      ret = item->focus_next;
5848    else if (dir == ELM_FOCUS_UP)
5849      ret = item->focus_up;
5850    else if (dir == ELM_FOCUS_DOWN)
5851      ret = item->focus_down;
5852    else if (dir == ELM_FOCUS_RIGHT)
5853      ret = item->focus_right;
5854    else if (dir == ELM_FOCUS_LEFT)
5855      ret = item->focus_left;
5856
5857    return ret;
5858 }
5859
5860 EOLIAN static void
5861 _elm_widget_item_focus_next_object_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Evas_Object *next, Elm_Focus_Direction dir)
5862 {
5863    if (dir == ELM_FOCUS_PREVIOUS)
5864      item->focus_previous = next;
5865    else if (dir == ELM_FOCUS_NEXT)
5866      item->focus_next = next;
5867    else if (dir == ELM_FOCUS_UP)
5868      item->focus_up = next;
5869    else if (dir == ELM_FOCUS_DOWN)
5870      item->focus_down = next;
5871    else if (dir == ELM_FOCUS_RIGHT)
5872      item->focus_right = next;
5873    else if (dir == ELM_FOCUS_LEFT)
5874      item->focus_left = next;
5875 }
5876
5877 EOLIAN static Elm_Object_Item*
5878 _elm_widget_item_focus_next_item_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
5879 {
5880    Elm_Object_Item *ret = NULL;
5881
5882    if (dir == ELM_FOCUS_PREVIOUS)
5883      ret = item->item_focus_previous;
5884    else if (dir == ELM_FOCUS_NEXT)
5885      ret = item->item_focus_next;
5886    else if (dir == ELM_FOCUS_UP)
5887      ret = item->item_focus_up;
5888    else if (dir == ELM_FOCUS_DOWN)
5889      ret = item->item_focus_down;
5890    else if (dir == ELM_FOCUS_RIGHT)
5891      ret = item->item_focus_right;
5892    else if (dir == ELM_FOCUS_LEFT)
5893      ret = item->item_focus_left;
5894
5895    return ret;
5896 }
5897
5898 EOLIAN static void
5899 _elm_widget_item_focus_next_item_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Object_Item *next_item, Elm_Focus_Direction dir)
5900 {
5901    if (dir == ELM_FOCUS_PREVIOUS)
5902      item->item_focus_previous = next_item;
5903    else if (dir == ELM_FOCUS_NEXT)
5904      item->item_focus_next = next_item;
5905    else if (dir == ELM_FOCUS_UP)
5906      item->item_focus_up = next_item;
5907    else if (dir == ELM_FOCUS_DOWN)
5908      item->item_focus_down = next_item;
5909    else if (dir == ELM_FOCUS_RIGHT)
5910      item->item_focus_right = next_item;
5911    else if (dir == ELM_FOCUS_LEFT)
5912      item->item_focus_left = next_item;
5913 }
5914
5915 /* happy debug functions */
5916 #ifdef ELM_DEBUG
5917 static void
5918 _sub_obj_tree_dump(const Evas_Object *obj,
5919                    int lvl)
5920 {
5921    int i;
5922
5923    for (i = 0; i < lvl * 3; i++)
5924      putchar(' ');
5925
5926    if (_elm_widget_is(obj))
5927      {
5928         Eina_List *l;
5929         INTERNAL_ENTRY;
5930         DBG("+ %s(%p)\n",
5931             elm_widget_type_get(obj),
5932             obj);
5933         EINA_LIST_FOREACH(sd->subobjs, l, obj)
5934           _sub_obj_tree_dump(obj, lvl + 1);
5935      }
5936    else
5937      DBG("+ %s(%p)\n", evas_object_type_get(obj), obj);
5938 }
5939
5940 static void
5941 _sub_obj_tree_dot_dump(const Evas_Object *obj,
5942                        FILE *output)
5943 {
5944    if (!_elm_widget_is(obj))
5945      return;
5946    INTERNAL_ENTRY;
5947
5948    Eina_Bool visible = evas_object_visible_get(obj);
5949    Eina_Bool disabled = elm_widget_disabled_get(obj);
5950    Eina_Bool focused = elm_widget_focus_get(obj);
5951    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
5952
5953    if (sd->parent_obj)
5954      {
5955         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
5956
5957         if (focused)
5958           fprintf(output, ", style=bold");
5959
5960         if (!visible)
5961           fprintf(output, ", color=gray28");
5962
5963         fprintf(output, " ];\n");
5964      }
5965
5966    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
5967                    "disabled: %d|focused: %d/%d|focus order:%d}\"",
5968            obj, obj, elm_widget_type_get(obj),
5969            evas_object_name_get(obj), visible, disabled, focused, can_focus,
5970            sd->focus_order);
5971
5972    if (focused)
5973      fprintf(output, ", style=bold");
5974
5975    if (!visible)
5976      fprintf(output, ", fontcolor=gray28");
5977
5978    if ((disabled) || (!visible))
5979      fprintf(output, ", color=gray");
5980
5981    fprintf(output, " ];\n");
5982
5983    Eina_List *l;
5984    Evas_Object *o;
5985    EINA_LIST_FOREACH(sd->subobjs, l, o)
5986      _sub_obj_tree_dot_dump(o, output);
5987 }
5988
5989 #endif
5990
5991 EAPI void
5992 elm_widget_tree_dump(const Evas_Object *top)
5993 {
5994 #ifdef ELM_DEBUG
5995    if (!_elm_widget_is(top))
5996      return;
5997    _sub_obj_tree_dump(top, 0);
5998 #else
5999    (void)top;
6000    return;
6001 #endif
6002 }
6003
6004 EAPI void
6005 elm_widget_tree_dot_dump(const Evas_Object *top,
6006                          FILE *output)
6007 {
6008 #ifdef ELM_DEBUG
6009    if (!_elm_widget_is(top))
6010      return;
6011    fprintf(output, "graph " " { node [shape=record];\n");
6012    _sub_obj_tree_dot_dump(top, output);
6013    fprintf(output, "}\n");
6014 #else
6015    (void)top;
6016    (void)output;
6017    return;
6018 #endif
6019 }
6020
6021 EOLIAN static Eo *
6022 _elm_widget_eo_base_constructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED)
6023 {
6024    Eo *parent = NULL;
6025
6026    sd->on_create = EINA_TRUE;
6027    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
6028    eo_do(obj,
6029          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
6030          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
6031          parent = eo_parent_get());
6032    eo_do(obj, elm_obj_widget_parent_set(parent));
6033    sd->on_create = EINA_FALSE;
6034    //TIZEN_ONLY(20170717) : expose highlight information on atspi
6035    sd->can_highlight = EINA_TRUE;
6036    //
6037    /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
6038    sd->inherit_paragraph_direction = EINA_TRUE;
6039    /* END */
6040
6041    eo_do(obj, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_UNKNOWN));
6042
6043    /* TIZEN_ONLY(20161117): Inherit paragraph direction from widget parent */
6044    if (sd->paragraph_direction != evas_object_paragraph_direction_get(parent))
6045      {
6046         sd->paragraph_direction = evas_object_paragraph_direction_get(parent);
6047         _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, sd->paragraph_direction);
6048         eo_do_super(obj, MY_CLASS, evas_obj_paragraph_direction_set(sd->paragraph_direction));
6049      }
6050    /* END */
6051
6052    return obj;
6053 }
6054
6055 EOLIAN static void
6056 _elm_widget_eo_base_destructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED)
6057 {
6058    sd->on_destroy = EINA_TRUE;
6059    eo_do(obj,
6060          elm_interface_atspi_accessible_description_set(NULL),
6061          elm_interface_atspi_accessible_name_set(NULL),
6062          //TIZEN_ONLY(20190922): add name callback, description callback.
6063          elm_interface_atspi_accessible_description_cb_set(NULL, NULL),
6064          elm_interface_atspi_accessible_name_cb_set(NULL, NULL),
6065          //
6066          elm_interface_atspi_accessible_translation_domain_set(NULL),
6067          elm_interface_atspi_accessible_relationships_clear(),
6068          // TIZEN_ONLY(20160930) : endless recursion fix
6069          elm_interface_atspi_accessible_attributes_clear()
6070          //
6071          );
6072    // TIZEN_ONLY(20150709) : atspi relations api
6073    if (sd->atspi_custom_relations)
6074      elm_atspi_relation_set_free(&sd->atspi_custom_relations);
6075    //
6076    //TIZEN_ONLY(20150717) add widget name setter
6077    if (sd->name)
6078      eina_stringshare_del(sd->name);
6079    //
6080
6081    //TIZEN_ONLY(20150731) : add i18n support for name and description
6082    if (sd->atspi_translation_domain)
6083      eina_stringshare_del(sd->atspi_translation_domain);
6084    //
6085    //Tizen Only(20160728) free attribute list
6086    if (sd->attr_list)
6087    {
6088       Elm_Atspi_Attribute *attr;
6089       EINA_LIST_FREE(sd->attr_list, attr)
6090        {
6091           eina_stringshare_del(attr->key);
6092           eina_stringshare_del(attr->value);
6093           free(attr);
6094        }
6095    }
6096    //
6097
6098    eo_do_super(obj, ELM_WIDGET_CLASS, eo_destructor());
6099    sd->on_destroy = EINA_FALSE;
6100
6101    elm_interface_atspi_accessible_removed(obj);
6102 }
6103
6104 EOLIAN static Eina_Bool
6105 _elm_widget_on_focus(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item EINA_UNUSED)
6106 {
6107    if (elm_widget_can_focus_get(obj))
6108      {
6109         if (elm_widget_focus_get(obj))
6110           {
6111              if (!sd->resize_obj)
6112                evas_object_focus_set(obj, EINA_TRUE);
6113               eo_do(obj, eo_event_callback_call
6114                (ELM_WIDGET_EVENT_FOCUSED, NULL));
6115              if (_elm_atspi_enabled() && !elm_widget_child_can_focus_get(obj))
6116                elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE);
6117           }
6118         else
6119           {
6120              if (!sd->resize_obj)
6121                evas_object_focus_set(obj, EINA_FALSE);
6122              eo_do(obj, eo_event_callback_call
6123                (ELM_WIDGET_EVENT_UNFOCUSED, NULL));
6124              if (_elm_atspi_enabled() && !elm_widget_child_can_focus_get(obj))
6125                elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE);
6126     }
6127      }
6128    else
6129      return EINA_FALSE;
6130
6131    return EINA_TRUE;
6132 }
6133
6134 EOLIAN static Eina_Bool
6135 _elm_widget_disable(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6136 {
6137    return EINA_FALSE;
6138 }
6139
6140 EOLIAN static Eina_Bool
6141 _elm_widget_event(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *source EINA_UNUSED, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
6142 {
6143    return EINA_FALSE;
6144 }
6145
6146 EOLIAN static Eina_Bool
6147 _elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6148 {
6149    WRN("The %s widget does not implement the \"focus_next/focus_next_manager_is\" functions.",
6150        eo_class_name_get(eo_class_get(obj)));
6151    return EINA_FALSE;
6152 }
6153
6154 static Eina_Bool
6155 _elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6156 {
6157    WRN("The %s widget does not implement the \"focus_direction/focus_direction_manager_is\" functions.",
6158        eo_class_name_get(eo_class_get(obj)));
6159    return EINA_FALSE;
6160 }
6161
6162 EOLIAN static Eina_Bool
6163 _elm_widget_activate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Activate act EINA_UNUSED)
6164 {
6165    WRN("The %s widget does not implement the \"activate\" functions.",
6166        eo_class_name_get(eo_class_get(obj)));
6167    return EINA_TRUE;
6168 }
6169
6170 EOLIAN static void
6171 _elm_widget_class_constructor(Eo_Class *klass)
6172 {
6173    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
6174 }
6175
6176 EOLIAN static Eina_Bool
6177 _elm_widget_elm_interface_atspi_component_focus_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6178 {
6179    if (elm_object_focus_allow_get(obj))
6180      {
6181        Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
6182        if (!ee) return EINA_FALSE;
6183        ecore_evas_activate(ee);
6184        elm_object_focus_set(obj, EINA_TRUE);
6185        return EINA_TRUE;
6186      }
6187    return EINA_FALSE;
6188 }
6189
6190 //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods (29e253e2f7ef3c632ac3a64c489bf569df407f30)
6191 EOLIAN static Eina_Bool
6192 _elm_widget_elm_interface_atspi_component_highlight_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6193 {
6194    if(!_elm_atspi_enabled())
6195       return EINA_FALSE;
6196
6197    elm_widget_focus_region_show(obj);
6198
6199    elm_object_accessibility_highlight_set(obj, EINA_TRUE);
6200    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_TRUE);
6201
6202    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
6203    evas_object_smart_callback_call(obj, SIG_WIDGET_ATSPI_HIGHLIGHTED, NULL);
6204    //
6205    return EINA_TRUE;
6206 }
6207
6208 EOLIAN static Eina_Bool
6209 _elm_widget_elm_interface_atspi_component_highlight_clear(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6210 {
6211    if(!_elm_atspi_enabled())
6212       return EINA_FALSE;
6213    elm_object_accessibility_highlight_set(obj, EINA_FALSE);
6214    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_FALSE);
6215
6216    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
6217    evas_object_smart_callback_call(obj, SIG_WIDGET_ATSPI_UNHIGHLIGHTED, NULL);
6218    //
6219    return EINA_TRUE;
6220 }
6221 //
6222
6223 EOLIAN static const char*
6224 _elm_widget_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
6225 {
6226    char *accessible_name;
6227    //TIZEN_ONLY(20190922): add name callback, description callback.
6228    const char *ret = NULL;
6229    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_name_get());
6230    if (ret) return ret;
6231    //
6232
6233    //TIZEN_ONLY(20150717) add widget name setter
6234    if (_pd->name)
6235      {
6236 #ifdef HAVE_GETTEXT
6237         if (_pd->atspi_translation_domain)
6238           return dgettext(_pd->atspi_translation_domain, _pd->name);
6239 #endif
6240         return _pd->name;
6241      }
6242    //
6243
6244    ret = elm_object_text_get(obj);
6245    if (!ret) return NULL;
6246
6247    accessible_name = _elm_util_mkup_to_text(ret);
6248    eina_stringshare_del(_pd->accessible_name);
6249    _pd->accessible_name =  eina_stringshare_add(accessible_name);
6250    free(accessible_name);
6251    return _pd->accessible_name;
6252 }
6253 //TIZEN_ONLY(20161111) add widget/widget_item description get/set
6254 EOLIAN void
6255 _elm_widget_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data* _pd EINA_UNUSED, const char *description)
6256 {
6257    if (_pd->description)
6258      eina_stringshare_del(_pd->description);
6259
6260    _pd->description = eina_stringshare_add(description);
6261 }
6262
6263 EOLIAN static const char*
6264 _elm_widget_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6265 {
6266    char *ret = NULL;
6267    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_description_get());
6268    if (ret) return ret;
6269
6270 #ifdef HAVE_GETTEXT
6271    if (_pd->atspi_translation_domain)
6272      return dgettext(_pd->atspi_translation_domain, _pd->description);
6273 #endif
6274    return _pd->description;
6275 }
6276 //
6277
6278 //TIZEN_ONLY(20150713) : add atspi name setter to widget_item
6279 EOLIAN void
6280 _elm_widget_item_elm_interface_atspi_accessible_name_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data* _pd EINA_UNUSED, const char *name)
6281 {
6282    if (_pd->name)
6283      eina_stringshare_del(_pd->name);
6284
6285    _pd->name = eina_stringshare_add(name);
6286 }
6287
6288 EOLIAN const char*
6289 _elm_widget_item_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6290 {
6291    //TIZEN_ONLY(20190922): add name callback, description callback.
6292    const char *ret = NULL;
6293    eo_do_super(obj, ELM_WIDGET_ITEM_CLASS, ret = elm_interface_atspi_accessible_name_get());
6294    if (ret) return ret;
6295    //
6296
6297    if (_pd->name)
6298      {
6299 #ifdef HAVE_GETTEXT
6300         if (_pd->atspi_translation_domain)
6301           return dgettext(_pd->atspi_translation_domain, _pd->name);
6302 #endif
6303         return _pd->name;
6304      }
6305
6306    return NULL;
6307 }
6308 //
6309 //TIZEN_ONLY(20161111) add widget/widget_item description get/set
6310 EOLIAN void
6311 _elm_widget_item_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data* _pd EINA_UNUSED, const char *description)
6312 {
6313    if (_pd->description)
6314      eina_stringshare_del(_pd->description);
6315
6316    _pd->description = eina_stringshare_add(description);
6317 }
6318
6319 EOLIAN const char*
6320 _elm_widget_item_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6321 {
6322    char *ret = NULL;
6323    eo_do_super(obj, ELM_WIDGET_ITEM_CLASS, ret = elm_interface_atspi_accessible_description_get());
6324    if (ret) return ret;
6325
6326 #ifdef HAVE_GETTEXT
6327    if (_pd->atspi_translation_domain)
6328      return dgettext(_pd->atspi_translation_domain, _pd->description);
6329 #endif
6330    return _pd->description;
6331 }
6332 //
6333 //TIZEN_ONLY(20150709) : spatially sort atspi children
6334 static int _sort_vertically(const void *data1, const void *data2)
6335 {
6336    Evas_Coord y1, y2;
6337    evas_object_geometry_get(data1, NULL, &y1, NULL, NULL);
6338    evas_object_geometry_get(data2, NULL, &y2, NULL, NULL);
6339
6340    return y1 < y2 ? -1 : 1;
6341 }
6342
6343 static int _sort_horizontally(const void *data1, const void *data2)
6344 {
6345    Evas_Coord x1, x2;
6346    evas_object_geometry_get(data1, &x1, NULL, NULL, NULL);
6347    evas_object_geometry_get(data2, &x2, NULL, NULL, NULL);
6348
6349    return x1 < x2 ? -1 : 1;
6350 }
6351
6352 static Eina_List *_lines_split(Eina_List *children)
6353 {
6354    Eo *c;
6355    Eina_List *lines, *line, *l;
6356    Evas_Coord yl, y, hl, h;
6357    lines = line = NULL;
6358
6359    if (!children) return NULL;
6360
6361    EINA_LIST_FOREACH(children, l, c)
6362      {
6363         evas_object_geometry_get(c, NULL, &yl, NULL, &hl);
6364
6365         /* remove child if its height == 0 */
6366         if (hl != 0) break;
6367      }
6368
6369    EINA_LIST_FREE(children, c)
6370      {
6371         evas_object_geometry_get(c, NULL, &y, NULL, &h);
6372
6373         /* remove child if its height == 0 */
6374         if (h == 0) continue;
6375
6376         if ((yl + (int)(0.25 * hl)) >= y)
6377           {
6378              //same line
6379              line = eina_list_append(line,c);
6380           }
6381         else
6382           {
6383              // finish current line & start new
6384              lines = eina_list_append(lines, line);
6385              yl = y, hl = h;
6386              line = eina_list_append(NULL, c);
6387           }
6388      }
6389
6390    return eina_list_append(lines, line);
6391 }
6392 //
6393
6394 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6395 static void
6396 _proxy_widget_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
6397 {
6398    Evas_Coord x, y;
6399    Eo *proxy = data;
6400
6401    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
6402    elm_atspi_bridge_utils_proxy_offset_set(proxy, x, y);
6403 }
6404 //
6405
6406 static Eina_Bool
6407 _on_widget_del(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
6408 {
6409    Eo *plug = data;
6410    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6411    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
6412                                        _proxy_widget_move_cb, plug);
6413    //
6414    eo_del(plug);
6415    return EINA_TRUE;
6416 }
6417
6418 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6419 static Eina_Bool
6420 _on_proxy_connected_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
6421 {
6422    Evas_Coord x, y;
6423    Evas_Object *widget = data;
6424
6425    evas_object_geometry_get(widget, &x, &y, NULL, NULL);
6426    elm_atspi_bridge_utils_proxy_offset_set(obj, x, y);
6427
6428    evas_object_event_callback_add(widget, EVAS_CALLBACK_MOVE, _proxy_widget_move_cb, obj);
6429    return EINA_TRUE;
6430 }
6431 //
6432 // TIZEN ONLY - END
6433
6434 EOLIAN static Eina_List*
6435 _elm_widget_elm_interface_atspi_accessible_children_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6436 {
6437    Eina_List *l, *accs = NULL;
6438    Elm_Widget_Smart_Data *wd;
6439    Evas_Object *widget;
6440    // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
6441    Eo *parent;
6442    //
6443
6444    wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS);
6445    if (!wd) return NULL;
6446
6447    EINA_LIST_FOREACH(wd->subobjs, l, widget)
6448      {
6449         const char *type = evas_object_type_get(widget);
6450         // TIZEN ONLY
6451         // Ugly Tizen hack to integrate AT-SPI2 accessibility provided by WebKit/Chromium with elementary one.
6452         // This wrapper class should be implemented in Webkit/Chromium EFL ports
6453         if (type && (!strcmp(type, "EWebView") || !strcmp(type, "WebView"))) {
6454            elm_atspi_ewk_wrapper_a11y_init(obj, widget);
6455         }
6456      }
6457
6458    EINA_LIST_FOREACH(wd->subobjs, l, widget)
6459      {
6460         // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
6461         if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) {
6462            eo_do(widget, parent = elm_interface_atspi_accessible_parent_get());
6463            if (parent && (parent != obj)) continue;
6464         }
6465
6466         // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6467         const char *plug_id_2;
6468         if ((plug_id_2 = evas_object_data_get(widget, "___PLUGID")) != NULL)
6469           {
6470             // TIZEN_ONLY(20160930) : endless recursion fix
6471             eo_do_super(obj, MY_CLASS, elm_interface_atspi_accessible_attribute_append("___PlugID", plug_id_2));
6472
6473              Eo *proxy;
6474              char *svcname, *svcnum;
6475
6476              proxy = evas_object_data_get(widget, "__widget_proxy");
6477              if (proxy)
6478                {
6479                   accs = eina_list_append(accs, proxy);
6480                   continue;
6481                }
6482
6483              if (_elm_atspi_bridge_plug_id_split(plug_id_2, &svcname, &svcnum))
6484                {
6485                   proxy = _elm_atspi_bridge_utils_proxy_create(obj, svcname, atoi(svcnum), ELM_ATSPI_PROXY_TYPE_PLUG);
6486                   evas_object_data_set(widget, "__widget_proxy", proxy);
6487                   eo_do(widget, eo_event_callback_add(EO_EV_DEL, _on_widget_del, proxy));
6488                   eo_do(proxy, eo_event_callback_add(ELM_ATSPI_PROXY_EVENT_CONNECTED,  _on_proxy_connected_cb, widget));
6489                   elm_atspi_bridge_utils_proxy_connect(proxy);
6490                   accs = eina_list_append(accs, proxy);
6491                   free(svcname);
6492                   free(svcnum);
6493                }
6494              continue;
6495           }
6496         //
6497         // TIZEN ONLY - END
6498         if (!elm_object_widget_check(widget)) continue;
6499         if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6500           accs = eina_list_append(accs, widget);
6501      }
6502    //TIZEN_ONLY(20150709) : spatially sort atspi children
6503    // sort children using its top-left coordinate
6504    accs = eina_list_sort(accs, -1, _sort_vertically);
6505    Eina_List *line, *lines = _lines_split(accs);
6506    accs = NULL;
6507    EINA_LIST_FREE(lines, line)
6508      accs = eina_list_merge(accs, eina_list_sort(line, -1, _sort_horizontally));
6509    //
6510    return accs;
6511 }
6512
6513 EOLIAN static Eo*
6514 _elm_widget_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd)
6515 {
6516    Eo *ret;
6517    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_parent_get());
6518
6519    return ret ? ret : pd->parent_obj;
6520 }
6521
6522 //TIZEN_ONLY(20161107): enhance elm_atspi_accessible_can_highlight_set to set can_hihglight property to its children
6523 EAPI Eina_Bool
6524 _elm_widget_highlightable(Evas_Object *obj)
6525 {
6526    Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS);
6527    if (!wd) return EINA_FALSE;
6528    if (!wd->can_highlight) return EINA_FALSE;
6529    Evas_Object *parent = elm_widget_parent_get(obj);
6530    if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6531      {
6532         wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
6533         if (!wd->can_highlight) return EINA_FALSE;
6534      }
6535    do
6536      {
6537         parent = elm_widget_parent_get(parent);
6538         if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6539           {
6540              wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
6541              if (!wd->can_highlight) return EINA_FALSE;
6542           }
6543      }
6544    while (parent && (parent != elm_widget_top_get(obj)));
6545    return EINA_TRUE;
6546 }
6547 //
6548
6549 EOLIAN static Elm_Atspi_State_Set
6550 _elm_widget_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Widget_Smart_Data *pd)
6551 {
6552    Elm_Atspi_State_Set states = 0;
6553
6554    eo_do_super(obj, ELM_WIDGET_CLASS, states = elm_interface_atspi_accessible_state_set_get());
6555
6556    if (evas_object_visible_get(obj))
6557      {
6558         STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE);
6559         if (_elm_widget_onscreen_is(obj))
6560           STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING);
6561      }
6562    if (!elm_widget_child_can_focus_get(obj))
6563      {
6564         if (elm_object_focus_allow_get(obj))
6565           STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE);
6566         if (elm_object_focus_get(obj))
6567           STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED);
6568      }
6569    if (!elm_object_disabled_get(obj))
6570      {
6571         STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED);
6572         STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE);
6573      }
6574
6575    //TIZEN_ONLY(20170717) : expose highlight information on atspi
6576    if (_elm_widget_highlightable(obj))
6577      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
6578    else
6579      STATE_TYPE_UNSET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
6580
6581    if (_elm_object_accessibility_currently_highlighted_get() == (void*)pd->obj)
6582      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTED);
6583    //
6584
6585    return states;
6586 }
6587
6588 //TIZEN_ONLY(20160729): attributes_get, append APIs added/updated.
6589 EOLIAN static Eina_List*
6590 _elm_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6591 {
6592    Eina_List *attr_list = NULL;
6593    // TIZEN_ONLY(20160930) : endless recursion fix
6594    eo_do_super(obj, MY_CLASS, attr_list = elm_interface_atspi_accessible_attributes_get());
6595    //
6596    //Add type and style information in addition.
6597    Elm_Atspi_Attribute *attr = NULL;
6598    attr = calloc(1, sizeof(Elm_Atspi_Attribute));
6599    if (attr)
6600      {
6601         attr->key = eina_stringshare_add("type");
6602         attr->value = eina_stringshare_add(elm_widget_type_get(obj));
6603         attr_list = eina_list_append(attr_list, attr);
6604      }
6605
6606    attr = calloc(1, sizeof(Elm_Atspi_Attribute));
6607    if (attr)
6608      {
6609         attr->key = eina_stringshare_add("style");
6610         attr->value = eina_stringshare_add(elm_widget_style_get(obj));
6611         attr_list = eina_list_append(attr_list, attr);
6612      }
6613
6614    return attr_list;
6615 }
6616
6617 //TIZEN_ONLY(20150709) : atspi relations api
6618 EOLIAN static Elm_Atspi_Relation_Set
6619 _elm_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
6620 {
6621    return elm_atspi_relation_set_clone(&sd->atspi_custom_relations);
6622 }
6623
6624 EOLIAN static Elm_Atspi_Relation_Set
6625 _elm_widget_item_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd)
6626 {
6627    return elm_atspi_relation_set_clone(&sd->atspi_custom_relations);
6628 }
6629 //
6630
6631 EOLIAN static void
6632 _elm_widget_item_elm_interface_atspi_component_extents_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords, int *x, int *y, int *w, int *h)
6633 {
6634    int ee_x, ee_y;
6635
6636    if (!sd->view)
6637      {
6638         if (x) *x = -1;
6639         if (y) *y = -1;
6640         if (w) *w = -1;
6641         if (h) *h = -1;
6642         return;
6643      }
6644
6645    evas_object_geometry_get(sd->view, x, y, w, h);
6646    if (screen_coords)
6647      {
6648         Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(sd->view));
6649         if (!ee) return;
6650         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
6651         if (x) *x += ee_x;
6652         if (y) *y += ee_y;
6653      }
6654 }
6655
6656 EOLIAN static Eina_Bool
6657 _elm_widget_item_elm_interface_atspi_component_extents_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
6658 {
6659    return EINA_FALSE;
6660 }
6661
6662 EOLIAN static int
6663 _elm_widget_item_elm_interface_atspi_component_layer_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED)
6664 {
6665    if (!sd->view)
6666      return -1;
6667    return evas_object_layer_get(sd->view);
6668 }
6669
6670 EOLIAN static Eina_Bool
6671 _elm_widget_item_elm_interface_atspi_component_focus_grab(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6672 {
6673    elm_object_item_focus_set(obj, EINA_TRUE);
6674    return elm_object_item_focus_get(obj);
6675 }
6676
6677 //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods
6678 EOLIAN static Eina_Bool
6679 _elm_widget_item_elm_interface_atspi_component_highlight_grab(Eo *obj, Elm_Widget_Item_Data *sd)
6680 {
6681
6682    if (!obj) return EINA_FALSE;
6683
6684    Evas_Object *o = elm_object_parent_widget_get(sd->view);
6685    if (_elm_scrollable_is(o))
6686      {
6687         Evas_Coord bx, by, bw, bh;
6688         Evas_Coord x, y, w, h;
6689         Evas_Object *w1 = elm_object_parent_widget_get(o);
6690         evas_object_geometry_get(sd->view, &x, &y, &w, &h);
6691         evas_object_geometry_get(o, &bx, &by, &bw, &bh);
6692         x -= bx;
6693         y -= by;
6694         switch (_elm_config->focus_autoscroll_mode)
6695           {
6696            case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
6697               eo_do(w1, elm_interface_scrollable_content_region_show(x, y, w, h));
6698               break;
6699            case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
6700               eo_do(w1, elm_interface_scrollable_region_bring_in(x, y, w, h));
6701               break;
6702            default:
6703               break;
6704           }
6705      }
6706
6707    elm_object_accessibility_highlight_set(sd->eo_obj, EINA_TRUE);
6708    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_TRUE);
6709
6710    return EINA_TRUE;
6711
6712 }
6713
6714 EOLIAN static Eina_Bool
6715 _elm_widget_item_elm_interface_atspi_component_highlight_clear(Eo *obj, Elm_Widget_Item_Data *sd)
6716 {
6717    if (!obj) return EINA_FALSE;
6718    elm_object_accessibility_highlight_set(sd->eo_obj, EINA_FALSE);
6719    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_FALSE);
6720    return EINA_TRUE;
6721 }
6722 //
6723
6724 EOLIAN static double
6725 _elm_widget_item_elm_interface_atspi_component_alpha_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED)
6726 {
6727    int alpha;
6728
6729    if (!sd->view) return -1.0;
6730    evas_object_color_get(sd->view, NULL, NULL, NULL, &alpha);
6731    return (double)alpha / 255.0;
6732 }
6733
6734 //TIZEN_ONLY(20150717) add widget name setter
6735 EOLIAN void
6736 _elm_widget_elm_interface_atspi_accessible_name_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data* _pd EINA_UNUSED, const char *name)
6737 {
6738    if (_pd->name)
6739      eina_stringshare_del(_pd->name);
6740
6741    _pd->name = eina_stringshare_add(name);
6742 }
6743 //
6744
6745 //TIZEN_ONLY(20160329): widget: improve accessibile_at_point getter (a8aff0423202b9a55dbb3843205875226678fbd6)
6746 static void
6747 _coordinate_system_based_point_translate(Eo *obj, Eina_Bool screen_coords, int *x, int *y)
6748 {
6749    Ecore_Evas *ee;
6750    int ee_x = 0;
6751    int ee_y = 0;
6752
6753    if (screen_coords)
6754      {
6755         ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
6756         if (!ee) return;
6757
6758         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
6759         *x -= ee_x;
6760         *y -= ee_y;
6761      }
6762 }
6763
6764 static Evas_Object *
6765 _parent_get(Evas_Object *obj)
6766 {
6767    Evas_Object *parent;
6768
6769    parent = evas_object_smart_parent_get(obj);
6770    if (!parent)
6771      {
6772         if (strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
6773           parent = elm_widget_parent_get(obj);
6774      }
6775
6776    return parent;
6777 }
6778
6779 static Eina_Bool
6780 _is_inside(Evas_Object *obj, int x, int y)
6781 {
6782    Eina_Bool ret = EINA_TRUE;
6783    Evas_Coord cx = 0;
6784    Evas_Coord cy = 0;
6785    Evas_Coord cw = 0;
6786    Evas_Coord ch = 0;
6787    if (eo_isa(obj, ELM_WIDGET_ITEM_CLASS))
6788      {
6789         Elm_Widget_Item_Data *id = eo_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
6790         evas_object_geometry_get(id->view, &cx, &cy, &cw, &ch);
6791      }
6792    else
6793      evas_object_geometry_get(obj, &cx, &cy, &cw, &ch);
6794
6795    /* check the point is out of bound */
6796    if (x < cx || x > cx + cw || y < cy || y > cy + ch)
6797      {
6798         ret = EINA_FALSE;
6799      }
6800    return ret;
6801 }
6802
6803 static Eina_Bool
6804 _is_ancestor_of(Evas_Object *smart_parent, Evas_Object *obj)
6805 {
6806    Eina_Bool ret = EINA_FALSE;
6807    Evas_Object *parent = elm_widget_parent_get(obj);
6808    while (parent)
6809      {
6810         /* No need to check more, the smart_parent is parent of obj */
6811         if (smart_parent == parent)
6812           {
6813              ret = EINA_TRUE;
6814              break;
6815           }
6816         parent = elm_widget_parent_get(parent);
6817      }
6818
6819    return ret;
6820 }
6821
6822 static Eo *
6823 _accessible_at_point_top_down_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
6824 {
6825    Eina_List *l, *l2, *children, *valid_children = NULL;
6826    Eo *child;
6827    Evas_Object *stack_item;
6828    Eo *compare_obj;
6829    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6830    Eo *proxy;
6831    Evas_Coord px, py, pw, ph;
6832    //
6833
6834    _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
6835
6836    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
6837
6838    EINA_LIST_FOREACH(children, l2, child)
6839      {
6840         if (_is_inside(child, x, y))
6841           valid_children = eina_list_append(valid_children, child);
6842      }
6843    /* Get evas_object stacked at given x,y coordinates starting from top */
6844    Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
6845    /* Foreach stacked object starting from top */
6846    EINA_LIST_FOREACH(stack, l, stack_item)
6847      {
6848         /* Foreach at-spi valid children traverse stack_item evas_objects hierarchy */
6849         EINA_LIST_FOREACH(valid_children, l2, child)
6850           {
6851              Elm_Atspi_Role role;
6852              eo_do(child, role = elm_interface_atspi_accessible_role_get());
6853              if (role == ELM_ATSPI_ROLE_REDUNDANT_OBJECT)
6854                {
6855                   /* The redundant object ignores */
6856                   continue;
6857                }
6858              /* Compare object used to compare with stacked evas objects */
6859              compare_obj = child;
6860              /* In case of widget_items compare should be different then elm_widget_ item  object */
6861              if (eo_isa(child, ELM_WIDGET_ITEM_CLASS))
6862                {
6863                   Elm_Widget_Item_Data *id = eo_data_scope_get(child, ELM_WIDGET_ITEM_CLASS);
6864                   compare_obj = id->view;
6865                }
6866              /* In case of access object compare should be 'wrapped' evas_object */
6867              if (eo_isa(child, ELM_ACCESS_CLASS))
6868                {
6869                    Elm_Access_Info *info = _elm_access_info_get(child);
6870                    compare_obj = info->part_object;
6871                 }
6872              /* In case of widget is registerd by elm_access_object_register */
6873              Elm_Access_Info *info = _elm_access_info_get(child);
6874              if (info && info->part_object)
6875                {
6876                   compare_obj = info->part_object;
6877                }
6878
6879              /* In case of ewk wrapper object compare with internal ewk_view evas_object */
6880              if (eo_isa(child, ELM_ATSPI_EWK_WRAPPER_CLASS))
6881                {
6882                   compare_obj = elm_atspi_ewk_wrapper_ewk_view_get(child);
6883                }
6884
6885              /* If spacial eo children do not have backing evas_object continue with search */
6886              if (!compare_obj)
6887                continue;
6888
6889              Evas_Object *smart_parent = stack_item;
6890              while (smart_parent)
6891                {
6892                    if (smart_parent == compare_obj)
6893                      {
6894                         eina_list_free(children);
6895                         eina_list_free(stack);
6896                         return child;
6897                      }
6898
6899                    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6900                    proxy = evas_object_data_get(smart_parent, "__widget_proxy");
6901                    if (proxy)
6902                      {
6903                         evas_object_geometry_get(smart_parent, &px, &py, &pw, &ph);
6904                         if (x >= px && x <= px + pw && y >= py && y <= py +ph)
6905                           {
6906                              eina_list_free(children);
6907                              eina_list_free(stack);
6908                              return proxy;
6909                           }
6910                      }
6911                    //
6912
6913                    smart_parent = _parent_get(smart_parent);
6914                    if (_is_ancestor_of(smart_parent, obj)) break;
6915                }
6916           }
6917      }
6918
6919    eina_list_free(children);
6920    eina_list_free(stack);
6921    return NULL;
6922 }
6923
6924 static int _sort_by_repeat_events(const void *data1, const void *data2)
6925 {
6926    Eina_Bool repeat1, repeat2;
6927
6928    repeat1 = evas_object_repeat_events_get(data1);
6929    repeat2 = evas_object_repeat_events_get(data2);
6930
6931    if (repeat1 != repeat2 && repeat1 == EINA_TRUE) return 1;
6932    return -1;
6933 }
6934
6935 EOLIAN static Eo *
6936 _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
6937 {
6938    Eina_List *l;
6939    Evas_Object *stack_item;
6940
6941    if(strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
6942      return _accessible_at_point_top_down_get(obj, _pd, screen_coords, x, y);
6943
6944    _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
6945
6946    Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
6947    stack = eina_list_sort(stack, -1, _sort_by_repeat_events);
6948
6949    EINA_LIST_FOREACH(stack, l, stack_item)
6950      {
6951         Evas_Object *smart_parent = stack_item;
6952         while (smart_parent)
6953           {
6954              Evas_Object *ao = elm_access_object_get(smart_parent);
6955              if (ao) return ao;
6956
6957              if (eo_isa(smart_parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6958                {
6959                   Eina_Bool acceptable = EINA_FALSE;
6960
6961                   Elm_Atspi_Role role;
6962                   eo_do(smart_parent, role = elm_interface_atspi_accessible_role_get());
6963                   switch (role)
6964                     {
6965                      case ELM_ATSPI_ROLE_FILLER: /* ex: View of colorselector item is layout */
6966                      case ELM_ATSPI_ROLE_ICON:
6967                      case ELM_ATSPI_ROLE_IMAGE:
6968                      case ELM_ATSPI_ROLE_REDUNDANT_OBJECT:
6969                      case ELM_ATSPI_ROLE_WINDOW:
6970                        DBG("Go for parent: %s (%p)\n", evas_object_type_get(smart_parent), smart_parent);
6971                        break;
6972
6973                      default:
6974                        acceptable = EINA_TRUE;
6975                        break;
6976                     }
6977
6978                     if (acceptable) return smart_parent;
6979                }
6980
6981              smart_parent = _parent_get(smart_parent);
6982           }
6983      }
6984    return NULL;
6985 }
6986 //
6987
6988 //TIZEN_ONLY(20150709) add relations atpi
6989 EOLIAN static Eina_Bool
6990 _elm_widget_elm_interface_atspi_accessible_relationship_append(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
6991 {
6992    return elm_atspi_relation_set_relation_append(&sd->atspi_custom_relations, type, relation_obj);
6993 }
6994
6995 EOLIAN static void
6996 _elm_widget_elm_interface_atspi_accessible_relationship_remove(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
6997 {
6998    elm_atspi_relation_set_relation_remove(&sd->atspi_custom_relations, type, relation_obj);
6999 }
7000
7001 EOLIAN static Eina_Bool
7002 _elm_widget_item_elm_interface_atspi_accessible_relationship_append(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7003 {
7004    return elm_atspi_relation_set_relation_append(&sd->atspi_custom_relations, type, relation_obj);
7005 }
7006
7007 EOLIAN static void
7008 _elm_widget_item_elm_interface_atspi_accessible_relationship_remove(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7009 {
7010    elm_atspi_relation_set_relation_remove(&sd->atspi_custom_relations, type, relation_obj);
7011 }
7012 //
7013
7014 //TIZEN_ONLY(20150731) : add i18n support for name and description
7015 EOLIAN static void
7016 _elm_widget_elm_interface_atspi_accessible_translation_domain_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, const char *domain)
7017 {
7018    eina_stringshare_replace(&_pd->atspi_translation_domain, domain);
7019 }
7020
7021 EOLIAN static const char*
7022 _elm_widget_elm_interface_atspi_accessible_translation_domain_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
7023 {
7024    return _pd->atspi_translation_domain;
7025 }
7026
7027 EOLIAN static void
7028 _elm_widget_item_elm_interface_atspi_accessible_translation_domain_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd, const char *domain)
7029 {
7030    eina_stringshare_replace(&_pd->atspi_translation_domain, domain);
7031 }
7032
7033 EOLIAN static const char*
7034 _elm_widget_item_elm_interface_atspi_accessible_translation_domain_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd)
7035 {
7036    return _pd->atspi_translation_domain;
7037 }
7038
7039 //TIZEN_ONLY(20160726): add API elm_atspi_accessible_can_highlight_set/get
7040 static Eina_Bool
7041 _children_highlight_check(Eo *obj)
7042 {
7043    Eina_List *children, *l;
7044    Eo *child;
7045
7046    if (_elm_object_accessibility_currently_highlighted_get() == (void *)obj)
7047      {
7048         eo_do(obj, elm_interface_atspi_component_highlight_clear());
7049         return EINA_TRUE;
7050      }
7051
7052    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
7053    EINA_LIST_FOREACH(children, l, child)
7054      {
7055         if (_children_highlight_check(child)) return EINA_TRUE;
7056      }
7057
7058    return EINA_FALSE;
7059 }
7060
7061 EOLIAN static void
7062 _elm_widget_elm_interface_atspi_accessible_can_highlight_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, Eina_Bool can_highlight)
7063 {
7064    if (!can_highlight) _children_highlight_check(obj);
7065    _pd->can_highlight = !!can_highlight;
7066 }
7067
7068 EOLIAN static Eina_Bool
7069 _elm_widget_elm_interface_atspi_accessible_can_highlight_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
7070 {
7071    return _elm_widget_highlightable(obj);
7072 }
7073
7074 EOLIAN static void
7075 _elm_widget_item_elm_interface_atspi_accessible_can_highlight_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd, Eina_Bool can_highlight)
7076 {
7077    if (!can_highlight) _children_highlight_check(obj);
7078    _pd->can_highlight = !!can_highlight;
7079 }
7080
7081 EOLIAN static Eina_Bool
7082 _elm_widget_item_elm_interface_atspi_accessible_can_highlight_get(Eo *obj, Elm_Widget_Item_Data *_pd EINA_UNUSED)
7083 {
7084    return _elm_widget_item_highlightable(obj);
7085 }
7086 //
7087
7088 //TIZEN_ONLY(20160622): Override Paragraph Direction APIs
7089 static void
7090 _elm_widget_evas_object_paragraph_direction_set_internal(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir)
7091 {
7092    Evas_Object *child;
7093    Eina_List *l;
7094
7095    if (sd->on_destroy) return;
7096
7097    EINA_LIST_FOREACH(sd->subobjs, l, child)
7098      {
7099         if (_elm_widget_is(child))
7100           {
7101              Elm_Widget_Smart_Data *sdc = eo_data_scope_get(child, MY_CLASS);
7102
7103              if (sdc->inherit_paragraph_direction &&
7104                  (sdc->paragraph_direction != dir))
7105                {
7106                   sdc->paragraph_direction = dir;
7107                   _elm_widget_evas_object_paragraph_direction_set_internal(child, sdc, dir);
7108                   eo_do_super(child, MY_CLASS, evas_obj_paragraph_direction_set(dir));
7109                }
7110           }
7111
7112         /* FIXME: There is no way to handle non-widget child object.
7113          * If a non-widget child object has smart parent, it will get the direction
7114          * from the smart parent. */
7115      }
7116 }
7117
7118 EOLIAN static void
7119 _elm_widget_evas_object_paragraph_direction_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir)
7120 {
7121    if ((!(sd->inherit_paragraph_direction) && (sd->paragraph_direction == dir)) ||
7122        (sd->inherit_paragraph_direction && (dir == EVAS_BIDI_DIRECTION_INHERIT)))
7123      return;
7124
7125    if (dir == EVAS_BIDI_DIRECTION_INHERIT)
7126      {
7127         sd->inherit_paragraph_direction = EINA_TRUE;
7128         Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
7129
7130         if (sd->parent_obj)
7131           parent_dir = evas_object_paragraph_direction_get(sd->parent_obj);
7132
7133         if (parent_dir != sd->paragraph_direction)
7134           {
7135              sd->paragraph_direction = parent_dir;
7136              _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, parent_dir);
7137           }
7138      }
7139    else
7140      {
7141         sd->inherit_paragraph_direction = EINA_FALSE;
7142         sd->paragraph_direction = dir;
7143         _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, dir);
7144      }
7145
7146    eo_do_super(obj, MY_CLASS, evas_obj_paragraph_direction_set(dir));
7147 }
7148 //
7149
7150
7151 //TIZEN_ONLY(20161013): clean up elm color class feature
7152 void
7153 _edje_color_class_free(void *data)
7154 {
7155    Edje_Color_Class *cc = data;
7156
7157    if (cc->name) eina_stringshare_del(cc->name);
7158    free(cc);
7159 }
7160
7161 Eina_Stringshare *
7162 _elm_widget_edje_class_get(const Eo_Class *klass, const char *style, const char *part)
7163 {
7164    Eina_Strbuf *buf;
7165    Eina_Stringshare *str;
7166
7167    buf = eina_strbuf_new();
7168
7169    eina_strbuf_append(buf, strchr(eo_class_name_get(klass), '_') + 1);
7170    eina_strbuf_tolower(buf);
7171
7172    if (style)
7173      {
7174         eina_strbuf_append_printf(buf, "/%s/%s", style, part);
7175      }
7176    else
7177      {
7178         eina_strbuf_append_printf(buf, "/%s", part);
7179      }
7180
7181    str = eina_stringshare_add(eina_strbuf_string_get(buf));
7182
7183    eina_strbuf_free(buf);
7184    return str;
7185 }
7186
7187 /* TIZEN_ONLY(20161025): Apply color_class parent-child relationship */
7188 Eina_Bool
7189 _elm_widget_color_class_set_internal(Evas_Object *obj, Evas_Object *edje, const char *color_class,
7190                                      int r, int g, int b, int a,
7191                                      int r2, int g2, int b2, int a2,
7192                                      int r3, int g3, int b3, int a3)
7193 {
7194    Eina_Bool int_ret = EINA_TRUE;
7195    Eina_Stringshare *buf;
7196    int temp_color[3][4] = { { r,  g,  b,  a },
7197                             { r2, g2, b2, a2 },
7198                             { r3, g3, b3, a3 } };
7199
7200    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);
7201
7202 #define TEMP_COLOR(x, y) \
7203    ((temp_color[x][y] == -1) ? &temp_color[x][y] : NULL)
7204
7205    edje_object_color_class_get(edje, buf,
7206                                TEMP_COLOR(0, 0), TEMP_COLOR(0, 1), TEMP_COLOR(0, 2), TEMP_COLOR(0, 3),
7207                                TEMP_COLOR(1, 0), TEMP_COLOR(1, 1), TEMP_COLOR(1, 2), TEMP_COLOR(1, 3),
7208                                TEMP_COLOR(2, 0), TEMP_COLOR(2, 1), TEMP_COLOR(2, 2), TEMP_COLOR(2, 3));
7209
7210 #undef TEMP_COLOR
7211
7212 #define TEMP_COLOR(x, y) \
7213    ((temp_color[x][y] == -1) ? 0 : temp_color[x][y])
7214
7215    int_ret &= edje_object_color_class_set(edje, buf,
7216                                           TEMP_COLOR(0, 0), TEMP_COLOR(0, 1), TEMP_COLOR(0, 2), TEMP_COLOR(0, 3),
7217                                           TEMP_COLOR(1, 0), TEMP_COLOR(1, 1), TEMP_COLOR(1, 2), TEMP_COLOR(1, 3),
7218                                           TEMP_COLOR(2, 0), TEMP_COLOR(2, 1), TEMP_COLOR(2, 2), TEMP_COLOR(2, 3));
7219
7220 #undef TEMP_COLOR
7221
7222    eina_stringshare_del(buf);
7223
7224    return int_ret;
7225 }
7226
7227 Eina_Bool
7228 _elm_widget_color_class_get_internal(Evas_Object *obj, Evas_Object *edje, const char *color_class,
7229                                      int *r, int *g, int *b, int *a,
7230                                      int *r2, int *g2, int *b2, int *a2,
7231                                      int *r3, int *g3, int *b3, int *a3)
7232 {
7233    Eina_Bool int_ret = EINA_TRUE;
7234    Eina_Stringshare *buf;
7235
7236    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);
7237
7238    int_ret &= edje_object_color_class_get(edje, buf,
7239                                           r,  g,  b,  a,
7240                                           r2, g2, b2, a2,
7241                                           r3, g3, b3, a3);
7242
7243    eina_stringshare_del(buf);
7244
7245    return int_ret;
7246 }
7247 /* END */
7248
7249 EOLIAN Eina_Bool
7250 _elm_widget_class_color_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7251 {
7252    Evas_Object *edje;
7253    Eina_Bool int_ret = EINA_TRUE;
7254
7255    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7256
7257    edje = elm_layout_edje_get(obj);
7258    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7259                                                    r, g, b, a,
7260                                                    -1, -1, -1, -1,
7261                                                    -1, -1, -1, -1);
7262
7263    return int_ret;
7264 }
7265
7266 EOLIAN Eina_Bool
7267 _elm_widget_class_color_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7268 {
7269    Evas_Object *edje;
7270    Eina_Bool int_ret = EINA_TRUE;
7271
7272    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7273
7274    edje = elm_layout_edje_get(obj);
7275    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7276                                                    r, g, b, a,
7277                                                    NULL, NULL, NULL, NULL,
7278                                                    NULL, NULL, NULL, NULL);
7279
7280    return int_ret;
7281 }
7282
7283 EOLIAN Eina_Bool
7284 _elm_widget_class_color2_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7285 {
7286    Evas_Object *edje;
7287    Eina_Bool int_ret = EINA_TRUE;
7288
7289    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7290
7291    edje = elm_layout_edje_get(obj);
7292    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7293                                                    -1, -1, -1, -1,
7294                                                    r, g, b, a,
7295                                                    -1, -1, -1, -1);
7296
7297    return int_ret;
7298 }
7299
7300 EOLIAN Eina_Bool
7301 _elm_widget_class_color2_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7302 {
7303    Evas_Object *edje;
7304    Eina_Bool int_ret = EINA_TRUE;
7305
7306    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7307
7308    edje = elm_layout_edje_get(obj);
7309    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7310                                                    NULL, NULL, NULL, NULL,
7311                                                    r, g, b, a,
7312                                                    NULL, NULL, NULL, NULL);
7313
7314    return int_ret;
7315 }
7316
7317 EOLIAN Eina_Bool
7318 _elm_widget_class_color3_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7319 {
7320    Evas_Object *edje;
7321    Eina_Bool int_ret = EINA_TRUE;
7322
7323    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7324
7325    edje = elm_layout_edje_get(obj);
7326    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7327                                                    -1, -1, -1, -1,
7328                                                    -1, -1, -1, -1,
7329                                                    r, g, b, a);
7330
7331    return int_ret;
7332 }
7333
7334 EOLIAN Eina_Bool
7335 _elm_widget_class_color3_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7336 {
7337    Evas_Object *edje;
7338    Eina_Bool int_ret = EINA_TRUE;
7339
7340    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7341
7342    edje = elm_layout_edje_get(obj);
7343    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7344                                                    NULL, NULL, NULL, NULL,
7345                                                    NULL, NULL, NULL, NULL,
7346                                                    r, g, b, a);
7347
7348    return int_ret;
7349 }
7350
7351 #define ELM_COLOR_CLASS_UPDATE(obj, hash, cond)                                  \
7352    Evas_Object *edje = NULL;                                                     \
7353    Eina_Iterator *itr;                                                           \
7354    Edje_Color_Class *cc;                                                         \
7355    Eina_Bool int_ret = EINA_TRUE;                                                \
7356    if (cond) return EINA_FALSE;                                                  \
7357    if (eo_isa(obj, ELM_LAYOUT_CLASS))                                            \
7358      edje =  elm_layout_edje_get(obj);                                           \
7359    else if (eo_isa(obj, EDJE_OBJECT_CLASS))                                      \
7360      edje = obj;                                                                 \
7361    if (!edje) return EINA_FALSE;                                                 \
7362    itr = eina_hash_iterator_data_new(hash);                                      \
7363    EINA_ITERATOR_FOREACH(itr, cc)                                                \
7364      {                                                                           \
7365         int_ret &= edje_object_color_class_set(edje, cc->name,                   \
7366                                                cc->r, cc->g, cc->b, cc->a,       \
7367                                                cc->r2, cc->g2, cc->b2, cc->a2,   \
7368                                                cc->r3, cc->g3, cc->b3, cc->a3);  \
7369      }                                                                           \
7370    eina_iterator_free(itr);                                                      \
7371    return int_ret
7372
7373
7374 #define CHECK_BOUND(x)                                                           \
7375    if (x > 0xff) x = 0xff;                                                       \
7376    else if (x < 0) x = 0
7377
7378 #define ELM_COLOR_CLASS_SET_START(obj, cr, cg, cb, ca)                           \
7379    Eina_Bool int_ret = EINA_FALSE;                                               \
7380    Edje_Color_Class *cc = NULL;                                                  \
7381    Eina_Stringshare *buf;                                                        \
7382    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);       \
7383    CHECK_BOUND(r);                                                               \
7384    CHECK_BOUND(g);                                                               \
7385    CHECK_BOUND(b);                                                               \
7386    CHECK_BOUND(a);                                                               \
7387    _elm_color_unpremul(a, &r, &g, &b);                                           \
7388    if (!sd->color_classes)                                                       \
7389      sd->color_classes = eina_hash_string_small_new(_edje_color_class_free);     \
7390    else                                                                          \
7391      cc = eina_hash_find(sd->color_classes, buf);                                \
7392    if (!cc)                                                                      \
7393      {                                                                           \
7394         cc = calloc(1, sizeof(Edje_Color_Class));                                \
7395         cc->name = eina_stringshare_add(buf);                                    \
7396         if (!cc->name)                                                           \
7397           {                                                                      \
7398              free(cc);                                                           \
7399              eina_stringshare_del(buf);                                          \
7400              return EINA_FALSE;                                                  \
7401           }                                                                      \
7402         eina_hash_direct_add(sd->color_classes, cc->name, cc);                   \
7403      }                                                                           \
7404    else if ((cc->cr == r) && (cc->cg == g) &&                                    \
7405             (cc->cb == b) && (cc->ca == a))                                      \
7406      {                                                                           \
7407         eina_stringshare_del(buf);                                               \
7408         return EINA_TRUE;                                                        \
7409      }                                                                           \
7410    cc->cr = r;                                                                   \
7411    cc->cg = g;                                                                   \
7412    cc->cb = b;                                                                   \
7413    cc->ca = a;                                                                   \
7414    int_ret = EINA_TRUE
7415
7416 #define ELM_COLOR_CLASS_SET_END()                                                \
7417    eina_stringshare_del(buf);                                                    \
7418    return int_ret
7419
7420 #define ELM_COLOR_CLASS_GET(obj, cr, cg, cb, ca)                                 \
7421    Eina_Bool int_ret = EINA_FALSE;                                               \
7422    Edje_Color_Class *cc;                                                         \
7423    Eina_Stringshare *buf;                                                        \
7424    int alpha = 0;                                                                \
7425    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);       \
7426    if ((!sd->color_classes) || !(cc = eina_hash_find(sd->color_classes, buf)))   \
7427      {                                                                           \
7428         if (r) *r = 0;                                                           \
7429         if (g) *g = 0;                                                           \
7430         if (b) *b = 0;                                                           \
7431         if (a) *a = 0;                                                           \
7432         int_ret = EINA_FALSE;                                                    \
7433      }                                                                           \
7434    else                                                                          \
7435      {                                                                           \
7436         if (r) *r = cc->cr;                                                      \
7437         if (g) *g = cc->cg;                                                      \
7438         if (b) *b = cc->cb;                                                      \
7439         if (a) *a = cc->ca;                                                      \
7440         alpha = cc->ca;                                                          \
7441         int_ret = EINA_TRUE;                                                     \
7442      }                                                                           \
7443    _elm_color_premul(alpha, r, g, b);                                            \
7444    eina_stringshare_del(buf);                                                    \
7445    return int_ret
7446
7447 Eina_Bool
7448 _elm_widget_item_color_class_update(Elm_Widget_Item_Data *sd)
7449 {
7450    ELM_COLOR_CLASS_UPDATE(sd->view, sd->color_classes, (!sd) || (!sd->color_classes) || (!sd->view));
7451 }
7452
7453 EOLIAN Eina_Bool
7454 _elm_widget_item_class_color_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7455 {
7456    ELM_COLOR_CLASS_SET_START(obj, r, g, b, a);
7457
7458    int_ret &= _elm_widget_item_color_class_update(sd);
7459
7460    ELM_COLOR_CLASS_SET_END();
7461 }
7462
7463 EOLIAN Eina_Bool
7464 _elm_widget_item_class_color_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7465 {
7466    ELM_COLOR_CLASS_GET(obj, r, g, b, a);
7467 }
7468
7469 EOLIAN Eina_Bool
7470 _elm_widget_item_class_color2_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7471 {
7472    ELM_COLOR_CLASS_SET_START(obj, r2, g2, b2, a2);
7473
7474    int_ret &= _elm_widget_item_color_class_update(sd);
7475
7476    ELM_COLOR_CLASS_SET_END();
7477 }
7478
7479 EOLIAN Eina_Bool
7480 _elm_widget_item_class_color2_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7481 {
7482    ELM_COLOR_CLASS_GET(obj, r2, g2, b2, a2);
7483 }
7484
7485 EOLIAN Eina_Bool
7486 _elm_widget_item_class_color3_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7487 {
7488    ELM_COLOR_CLASS_SET_START(obj, r3, g3, b3, a3);
7489
7490    int_ret &= _elm_widget_item_color_class_update(sd);
7491
7492    ELM_COLOR_CLASS_SET_END();
7493 }
7494
7495 EOLIAN Eina_Bool
7496 _elm_widget_item_class_color3_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7497 {
7498    ELM_COLOR_CLASS_GET(obj, r3, g3, b3, a3);
7499 }
7500 //
7501
7502 /* TIZEN_ONLY(20161025): Apply color_class parent-child relationship */
7503 void
7504 _elm_widget_color_class_parent_set(Evas_Object *obj, Evas_Object *parent)
7505 {
7506    Evas_Object *edje = NULL, *parent_edje = NULL;
7507
7508    if (!obj || !parent) return;
7509
7510    if (eo_isa(obj, ELM_LAYOUT_CLASS))
7511      edje =  elm_layout_edje_get(obj);
7512    else if (eo_isa(obj, EDJE_OBJECT_CLASS))
7513      edje = obj;
7514
7515    if (eo_isa(parent, ELM_LAYOUT_CLASS))
7516      parent_edje =  elm_layout_edje_get(parent);
7517    else if (eo_isa(parent, EDJE_OBJECT_CLASS))
7518      parent_edje = parent;
7519
7520    if (!edje || !parent_edje) return;
7521
7522    edje_object_color_class_parent_set(edje, parent_edje);
7523 }
7524
7525 void
7526 _elm_widget_color_class_parent_unset(Evas_Object *obj)
7527 {
7528    Evas_Object *edje = NULL;
7529
7530    if (!obj) return;
7531
7532    if (eo_isa(obj, ELM_LAYOUT_CLASS))
7533      edje =  elm_layout_edje_get(obj);
7534    else if (eo_isa(obj, EDJE_OBJECT_CLASS))
7535      edje = obj;
7536
7537    if (!edje) return;
7538
7539    edje_object_color_class_parent_unset(edje);
7540 }
7541 /* END */
7542
7543 //TIZEN_ONLY(20160527): widget: add AtspiAction interface to all widgets and widget_items, add handlers for reading stopped/cancelled
7544 EOLIAN const Elm_Atspi_Action *
7545 _elm_widget_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED)
7546 {
7547    return NULL;
7548 }
7549
7550 EOLIAN const Elm_Atspi_Action *
7551 _elm_widget_item_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *pd EINA_UNUSED)
7552 {
7553    return NULL;
7554 }
7555 //
7556
7557 #include "elm_widget_item.eo.c"
7558 #include "elm_widget.eo.c"