1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 
8 #include <Elementary.h>
9 #include "elm_priv.h"
10 
11 #define MY_CLASS ELM_ACCESS_CLASS
12 
13 #define MY_CLASS_NAME "Elm_Access"
14 #define MY_CLASS_NAME_LEGACY "elm_access"
15 
16 struct _Func_Data
17 {
18    void                *user_data; /* Holds user data to CB */
19    Elm_Access_Action_Cb cb;
20 };
21 
22 typedef struct _Func_Data Func_Data;
23 
24 struct _Action_Info
25 {
26    Evas_Object      *obj;
27    Func_Data         fn[ELM_ACCESS_ACTION_LAST + 1]; /* Callback for specific action */
28 };
29 
30 typedef struct _Action_Info Action_Info;
31 
32 static Eina_Bool mouse_event_enable = EINA_TRUE;
33 static Eina_Bool auto_highlight = EINA_FALSE;
34 static Elm_Access_Action_Type action_by = ELM_ACCESS_ACTION_FIRST;
35 
36 static Evas_Object * _elm_access_add(Evas_Object *parent);
37 
38 static void _access_object_unregister(Evas_Object *obj);
39 
40 static const char SIG_ACTIVATED[] = "access,activated";
41 static const Evas_Smart_Cb_Description _smart_callbacks[] =
42 {
43    {SIG_ACTIVATED, ""},
44    {NULL, NULL}
45 };
46 
47 EOLIAN static void
_elm_access_efl_canvas_group_group_add(Eo * obj,void * _pd EINA_UNUSED)48 _elm_access_efl_canvas_group_group_add(Eo *obj, void *_pd EINA_UNUSED)
49 {
50    efl_canvas_group_add(efl_super(obj, MY_CLASS));
51 }
52 
53 static Eina_Bool
_access_action_callback_call(Evas_Object * obj,Elm_Access_Action_Type type,Elm_Access_Action_Info * action_info)54 _access_action_callback_call(Evas_Object *obj,
55                              Elm_Access_Action_Type type,
56                              Elm_Access_Action_Info *action_info)
57 {
58    Elm_Access_Action_Info *ai = NULL;
59    Action_Info *a;
60    Eina_Bool ret;
61 
62    ret = EINA_FALSE;
63    a = evas_object_data_get(obj, "_elm_access_action_info");
64 
65    if (!action_info)
66      {
67         ai = calloc(1, sizeof(Elm_Access_Action_Info));
68         action_info = ai;
69      }
70 
71    action_info->action_type = type;
72 
73    if ((type == ELM_ACCESS_ACTION_HIGHLIGHT) &&
74        (action_by != ELM_ACCESS_ACTION_FIRST))
75      action_info->action_by = action_by;
76 
77    if (a && (a->fn[type].cb))
78      ret = a->fn[type].cb(a->fn[type].user_data, obj, action_info);
79 
80    free(ai);
81 
82    return ret;
83 }
84 
85 EOLIAN static Eina_Bool
_elm_access_efl_ui_widget_on_access_activate(Eo * obj,void * _pd EINA_UNUSED,Efl_Ui_Activate act)86 _elm_access_efl_ui_widget_on_access_activate(Eo *obj, void *_pd EINA_UNUSED, Efl_Ui_Activate act)
87 {
88    int type = ELM_ACCESS_ACTION_FIRST;
89 
90    Action_Info *a;
91    a = evas_object_data_get(obj, "_elm_access_action_info");
92 
93    switch (act)
94      {
95       case EFL_UI_ACTIVATE_DEFAULT:
96         type = ELM_ACCESS_ACTION_ACTIVATE;
97         break;
98 
99       case EFL_UI_ACTIVATE_UP:
100         type = ELM_ACCESS_ACTION_UP;
101         break;
102 
103       case EFL_UI_ACTIVATE_DOWN:
104         type = ELM_ACCESS_ACTION_DOWN;
105         break;
106 
107       case EFL_UI_ACTIVATE_RIGHT:
108         break;
109 
110       case EFL_UI_ACTIVATE_LEFT:
111         break;
112 
113       case EFL_UI_ACTIVATE_BACK:
114         type = ELM_ACCESS_ACTION_BACK;
115         break;
116 
117       default:
118         break;
119      }
120 
121    if (type == ELM_ACCESS_ACTION_FIRST) return EINA_FALSE;
122 
123    /* if an access object has a callback, it would have the intention to do
124       something. so, check here and return EINA_TRUE. */
125    if ((a) && (type > ELM_ACCESS_ACTION_FIRST) &&
126               (type < ELM_ACCESS_ACTION_LAST) &&
127               (a->fn[type].cb))
128      {
129         _access_action_callback_call(obj, type, NULL);
130         return EINA_TRUE;
131      }
132 
133    /* TODO: deprecate below? */
134    if (act != EFL_UI_ACTIVATE_DEFAULT) return EINA_FALSE;
135 
136    Elm_Access_Info *ac = evas_object_data_get(obj, "_elm_access");
137    if (!ac) return EINA_FALSE;
138 
139    if (ac->activate)
140      ac->activate(ac->activate_data, ac->part_object,
141                   ac->widget_item->eo_obj);
142 
143    return EINA_TRUE;
144 }
145 
146 EOLIAN static Eina_Bool
_elm_access_efl_ui_focus_object_on_focus_update(Eo * obj,void * _pd EINA_UNUSED)147 _elm_access_efl_ui_focus_object_on_focus_update(Eo *obj, void *_pd EINA_UNUSED)
148 {
149    evas_object_focus_set(obj, efl_ui_focus_object_focus_get(obj));
150 
151    return EINA_TRUE;
152 }
153 
154 typedef struct _Mod_Api Mod_Api;
155 
156 struct _Mod_Api
157 {
158    void (*out_read) (const char *txt);
159    void (*out_read_done) (void);
160    void (*out_cancel) (void);
161    void (*out_done_callback_set) (void (*func) (void *data), const void *data);
162 };
163 
164 static int initted = 0;
165 static Mod_Api *mapi = NULL;
166 
167 static void
_access_init(void)168 _access_init(void)
169 {
170    Elm_Module *m;
171 
172    if (initted > 0) return;
173    if (!(m = _elm_module_find_as("access/api"))) return;
174    if (m->init_func(m) < 0) return;
175    initted++;
176 
177    m->api = malloc(sizeof(Mod_Api));
178    if (!m->api) return;
179    ((Mod_Api *)(m->api)      )->out_read = // called to read out some text
180       _elm_module_symbol_get(m, "out_read");
181    ((Mod_Api *)(m->api)      )->out_read_done = // called to set a done marker so when it is reached the done callback is called
182       _elm_module_symbol_get(m, "out_read_done");
183    ((Mod_Api *)(m->api)      )->out_cancel = // called to read out some text
184       _elm_module_symbol_get(m, "out_cancel");
185    ((Mod_Api *)(m->api)      )->out_done_callback_set = // called when last read done
186       _elm_module_symbol_get(m, "out_done_callback_set");
187    mapi = m->api;
188 }
189 
190 static void
_access_shutdown(void)191 _access_shutdown(void)
192 {
193    Elm_Module *m;
194    if (initted == 0) return;
195    if (!(m = _elm_module_find_as("access/api"))) return;
196 
197    m->shutdown_func(m);
198 
199    initted = 0;
200 
201    /* _elm_module_unload(); could access m->api and try to free(); */
202    ELM_SAFE_FREE(m->api, free);
203    mapi = NULL;
204 }
205 
206 static Elm_Access_Item *
_access_add_set(Elm_Access_Info * ac,int type)207 _access_add_set(Elm_Access_Info *ac, int type)
208 {
209    Elm_Access_Item *ai;
210    Eina_List *l;
211 
212    if (!ac) return NULL;
213    EINA_LIST_FOREACH(ac->items, l, ai)
214      {
215         if (ai->type == type)
216           {
217              if (!ai->func)
218                {
219                   eina_stringshare_del(ai->data);
220                }
221              ai->func = NULL;
222              ai->data = NULL;
223              return ai;
224           }
225      }
226    ai = calloc(1, sizeof(Elm_Access_Item));
227    ai->type = type;
228    ac->items = eina_list_prepend(ac->items, ai);
229    return ai;
230 }
231 
232 static Evas_Object *
_access_highlight_object_get(Evas_Object * obj)233 _access_highlight_object_get(Evas_Object *obj)
234 {
235    Evas_Object *o, *ho;
236 
237    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
238    if (!o) return NULL;
239 
240    ho = evas_object_data_get(o, "_elm_access_target");
241 
242    return ho;
243 }
244 
245 static void
_access_highlight_read(Elm_Access_Info * ac,Evas_Object * obj)246 _access_highlight_read(Elm_Access_Info *ac, Evas_Object *obj)
247 {
248    int type;
249    char *txt = NULL;
250    Eina_Strbuf *strbuf;
251 
252    strbuf = eina_strbuf_new();
253 
254    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
255      {
256         if (ac->on_highlight) ac->on_highlight(ac->on_highlight_data);
257         _elm_access_object_highlight(obj);
258 
259         for (type = ELM_ACCESS_INFO_FIRST + 1; type < ELM_ACCESS_INFO_LAST; type++)
260           {
261              txt = _elm_access_text_get(ac, type, obj);
262              if (txt && (strlen(txt) > 0))
263                {
264                   if (eina_strbuf_length_get(strbuf) > 0)
265                     eina_strbuf_append_printf(strbuf, ", %s", txt);
266                   else
267                     eina_strbuf_append(strbuf, txt);
268                }
269              free(txt);
270           }
271      }
272 
273    txt = eina_strbuf_string_steal(strbuf);
274    eina_strbuf_free(strbuf);
275 
276    _elm_access_say(txt);
277    free(txt);
278 }
279 
280 static Eina_Bool
_access_obj_over_timeout_cb(void * data)281 _access_obj_over_timeout_cb(void *data)
282 {
283    Elm_Access_Info *ac;
284    Evas_Object *ho;
285 
286    if (!data) return EINA_FALSE;
287 
288    ac = evas_object_data_get(data, "_elm_access");
289    if (!ac) return EINA_FALSE;
290 
291    ho = _access_highlight_object_get(data);
292    if (ho != data) _access_highlight_read(ac, data);
293 
294    ac->delay_timer = NULL;
295    return EINA_FALSE;
296 }
297 
298 static void
_access_hover_mouse_in_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)299 _access_hover_mouse_in_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info  EINA_UNUSED)
300 {
301    Elm_Access_Info *ac;
302    if (!mouse_event_enable) return;
303 
304     ac = evas_object_data_get(data, "_elm_access");
305    if (!ac) return;
306 
307    ELM_SAFE_FREE(ac->delay_timer, ecore_timer_del);
308 
309    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
310       ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
311 }
312 
313 static void
_access_hover_mouse_out_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)314 _access_hover_mouse_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
315 {
316    Elm_Access_Info *ac;
317    if (!mouse_event_enable) return;
318 
319    ac = evas_object_data_get(data, "_elm_access");
320    if (!ac) return;
321 
322    _elm_access_object_unhighlight(data);
323 
324    ELM_SAFE_FREE(ac->delay_timer, ecore_timer_del);
325 }
326 
327 static void
_access_read_done(void * data EINA_UNUSED)328 _access_read_done(void *data EINA_UNUSED)
329 {
330    DBG("read done");
331    // FIXME: produce event here
332 }
333 
334 static void
_access_2nd_click_del_cb(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)335 _access_2nd_click_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
336 {
337    Ecore_Timer *t;
338 
339    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
340                                        _access_2nd_click_del_cb, NULL);
341    t = evas_object_data_get(obj, "_elm_2nd_timeout");
342    if (t)
343      {
344         ecore_timer_del(t);
345         evas_object_data_del(obj, "_elm_2nd_timeout");
346      }
347 }
348 
349 static Eina_Bool
_access_2nd_click_timeout_cb(void * data)350 _access_2nd_click_timeout_cb(void *data)
351 {
352    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
353                                        _access_2nd_click_del_cb, NULL);
354    evas_object_data_del(data, "_elm_2nd_timeout");
355    return EINA_FALSE;
356 }
357 
358 static void
_access_obj_hilight_del_cb(void * data EINA_UNUSED,Evas * e,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)359 _access_obj_hilight_del_cb(void *data EINA_UNUSED, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
360 {
361    _elm_access_object_highlight_disable(e);
362 }
363 
364 static void
_access_obj_hilight_hide_cb(void * data EINA_UNUSED,Evas * e,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)365 _access_obj_hilight_hide_cb(void *data EINA_UNUSED, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
366 {
367    _elm_access_object_highlight_disable(e);
368 }
369 
370 static void
_access_obj_hilight_move_cb(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)371 _access_obj_hilight_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
372 {
373    Evas_Coord x, y;
374    Evas_Object *o;
375 
376    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
377    if (!o) return;
378    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
379    evas_object_move(o, x, y);
380 }
381 
382 static void
_access_obj_hilight_resize_cb(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)383 _access_obj_hilight_resize_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
384 {
385    Evas_Coord w, h;
386    Evas_Object *o;
387 
388    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
389    if (!o) return;
390    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
391    evas_object_resize(o, w, h);
392 }
393 
394 void
_elm_access_mouse_event_enabled_set(Eina_Bool enabled)395 _elm_access_mouse_event_enabled_set(Eina_Bool enabled)
396 {
397    enabled = !!enabled;
398    if (mouse_event_enable == enabled) return;
399    mouse_event_enable = enabled;
400 }
401 
402 void
_elm_access_auto_highlight_set(Eina_Bool enabled)403 _elm_access_auto_highlight_set(Eina_Bool enabled)
404 {
405    enabled = !!enabled;
406    if (auto_highlight == enabled) return;
407    auto_highlight = enabled;
408 }
409 
410 Eina_Bool
_elm_access_auto_highlight_get(void)411 _elm_access_auto_highlight_get(void)
412 {
413    return auto_highlight;
414 }
415 
416 void
_elm_access_shutdown()417 _elm_access_shutdown()
418 {
419    _access_shutdown();
420 }
421 
422 static void
_access_order_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)423 _access_order_del_cb(void *data,
424                      Evas *e EINA_UNUSED,
425                      Evas_Object *obj,
426                      void *event_info EINA_UNUSED)
427 {
428    Elm_Widget_Item_Data *item = data;
429 
430    item->access_order = eina_list_remove(item->access_order, obj);
431 }
432 
433 void
_elm_access_widget_item_access_order_set(Elm_Widget_Item_Data * item,Eina_List * objs)434 _elm_access_widget_item_access_order_set(Elm_Widget_Item_Data *item,
435                                          Eina_List *objs)
436 {
437    Eina_List *l;
438    Evas_Object *o;
439 
440    if (!item) return;
441 
442    _elm_access_widget_item_access_order_unset(item);
443 
444    EINA_LIST_FOREACH(objs, l, o)
445      {
446         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
447                                        _access_order_del_cb, item);
448      }
449 
450    item->access_order = objs;
451 }
452 
453 const Eina_List *
_elm_access_widget_item_access_order_get(const Elm_Widget_Item_Data * item)454 _elm_access_widget_item_access_order_get(const Elm_Widget_Item_Data *item)
455 {
456    if (!item) return NULL;
457    return item->access_order;
458 }
459 
460 void
_elm_access_widget_item_access_order_unset(Elm_Widget_Item_Data * item)461 _elm_access_widget_item_access_order_unset(Elm_Widget_Item_Data *item)
462 {
463    Eina_List *l, *l_next;
464    Evas_Object *o;
465 
466    if (!item) return;
467 
468    EINA_LIST_FOREACH_SAFE(item->access_order, l, l_next, o)
469      {
470         evas_object_event_callback_del_full
471           (o, EVAS_CALLBACK_DEL, _access_order_del_cb, item);
472         item->access_order = eina_list_remove_list(item->access_order, l);
473      }
474 }
475 
476 static Eina_Bool
_access_highlight_next_get(Evas_Object * obj,Elm_Focus_Direction dir)477 _access_highlight_next_get(Evas_Object *obj, Elm_Focus_Direction dir)
478 {
479    int type;
480    Evas_Object *ho, *parent, *target;
481    Eina_Bool ret;
482 
483    target = NULL;
484    ret = EINA_FALSE;
485 
486    if (!elm_widget_is(obj)) return ret;
487 
488    ho = _access_highlight_object_get(obj);
489    if (!ho) ho = obj;
490 
491    parent = ho;
492 
493    /* find highlight root */
494    do
495      {
496         ELM_WIDGET_DATA_GET_OR_RETURN(parent, wd, ret);
497         if (wd->highlight_root)
498           {
499              /* change highlight root */
500              obj = parent;
501              break;
502           }
503         parent = elm_widget_parent_get(parent);
504      }
505    while (parent);
506 
507    _elm_access_auto_highlight_set(EINA_TRUE);
508 
509    if (dir == ELM_FOCUS_NEXT)
510      type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
511    else
512      type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
513 
514    /* this value is used in _elm_access_object_highlight();
515       to inform the target object of how to get highlight */
516    action_by = type;
517 
518    if (!_access_action_callback_call(ho, type, NULL))
519      {
520         if (ho)
521           {
522              Elm_Access_Info *info = _elm_access_info_get(ho);
523              EINA_SAFETY_ON_NULL_RETURN_VAL(info, ret);
524              if (type == ELM_ACCESS_ACTION_HIGHLIGHT_NEXT && info->next)
525                target = info->next;
526              else if (type == ELM_ACCESS_ACTION_HIGHLIGHT_PREV && info->prev)
527                target = info->prev;
528           }
529 
530         if (target)
531           {
532              _elm_access_highlight_set(target);
533              elm_widget_focus_region_show(target);
534              ret = EINA_TRUE;
535           }
536         else
537           {
538              Efl_Ui_Focus_Relations *rel;
539 
540              rel = efl_ui_focus_manager_fetch(efl_ui_focus_object_focus_manager_get(obj), obj);
541 
542              if (rel)
543                {
544                   if (dir == ELM_FOCUS_NEXT)
545                     _elm_access_highlight_set(rel->next);
546                   else
547                     _elm_access_highlight_set(rel->prev);
548 
549                   free(rel);
550                }
551           }
552      }
553 
554    action_by = ELM_ACCESS_ACTION_FIRST;
555 
556    _elm_access_auto_highlight_set(EINA_FALSE);
557 
558    return ret;
559 }
560 
561 //-------------------------------------------------------------------------//
562 EAPI void
_elm_access_highlight_set(Evas_Object * obj)563 _elm_access_highlight_set(Evas_Object* obj)
564 {
565    Elm_Access_Info *ac;
566    Evas_Object *ho;
567 
568    if (!obj) return;
569 
570    ho = _access_highlight_object_get(obj);
571    if (ho == obj) return;
572 
573    ac = evas_object_data_get(obj, "_elm_access");
574    if (!ac) return;
575 
576    _access_highlight_read(ac, obj);
577 }
578 
579 EAPI void
_elm_access_clear(Elm_Access_Info * ac)580 _elm_access_clear(Elm_Access_Info *ac)
581 {
582    Elm_Access_Item *ai;
583 
584    if (!ac) return;
585    ELM_SAFE_FREE(ac->delay_timer, ecore_timer_del);
586    EINA_LIST_FREE(ac->items, ai)
587      {
588         if (!ai->func)
589           {
590              eina_stringshare_del(ai->data);
591           }
592         free(ai);
593      }
594 }
595 
596 EAPI void
_elm_access_text_set(Elm_Access_Info * ac,int type,const char * text)597 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
598 {
599    Elm_Access_Item *ai = _access_add_set(ac, type);
600    if (!ai) return;
601    ai->func = NULL;
602    ai->data = eina_stringshare_add(text);
603 }
604 
605 EAPI void
_elm_access_callback_set(Elm_Access_Info * ac,int type,Elm_Access_Info_Cb func,const void * data)606 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Info_Cb func, const void *data)
607 {
608    Elm_Access_Item *ai = _access_add_set(ac, type);
609    if (!ai) return;
610    ai->func = func;
611    ai->data = data;
612 }
613 
614 EAPI void
_elm_access_on_highlight_hook_set(Elm_Access_Info * ac,Elm_Access_On_Highlight_Cb func,void * data)615 _elm_access_on_highlight_hook_set(Elm_Access_Info           *ac,
616                                   Elm_Access_On_Highlight_Cb func,
617                                   void                      *data)
618 {
619     if (!ac) return;
620     ac->on_highlight = func;
621     ac->on_highlight_data = data;
622 }
623 
624 EAPI void
_elm_access_activate_callback_set(Elm_Access_Info * ac,Elm_Access_Activate_Cb func,void * data)625 _elm_access_activate_callback_set(Elm_Access_Info           *ac,
626                                   Elm_Access_Activate_Cb     func,
627                                   void                      *data)
628 {
629    if (!ac) return;
630    ac->activate = func;
631    ac->activate_data = data;
632 }
633 
634 EAPI void
_elm_access_highlight_object_activate(Evas_Object * obj,Efl_Ui_Activate act)635 _elm_access_highlight_object_activate(Evas_Object *obj, Efl_Ui_Activate act)
636 {
637    Evas_Object *highlight;
638 
639    highlight = _access_highlight_object_get(obj);
640    if (!highlight) return;
641 
642    _elm_access_auto_highlight_set(EINA_FALSE);
643 
644    if (!elm_object_focus_get(highlight))
645      elm_object_focus_set(highlight, EINA_TRUE);
646 
647    elm_widget_activate(highlight, act);
648    return;
649 }
650 
651 EAPI void
_elm_access_highlight_cycle(Evas_Object * obj,Elm_Focus_Direction dir)652 _elm_access_highlight_cycle(Evas_Object *obj, Elm_Focus_Direction dir)
653 {
654    int type;
655    Evas_Object *ho, *parent;
656 
657    ho = _access_highlight_object_get(obj);
658    if (!ho) return;
659 
660    parent = ho;
661 
662    /* find highlight root */
663    do
664      {
665         ELM_WIDGET_DATA_GET_OR_RETURN(parent, wd);
666         if (wd->highlight_root)
667           {
668              /* change highlight root */
669              obj = parent;
670              break;
671           }
672         parent = elm_widget_parent_get(parent);
673      }
674    while (parent);
675 
676    _elm_access_auto_highlight_set(EINA_TRUE);
677 
678    if (dir == ELM_FOCUS_NEXT)
679      type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
680    else
681      type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
682 
683    action_by = type;
684 
685    if (!_access_action_callback_call(ho, type, NULL))
686      {
687         Elm_Access_Info *info = _elm_access_info_get(ho);
688         Evas_Object *comming = NULL;
689         if (type == ELM_ACCESS_ACTION_HIGHLIGHT_NEXT)
690           {
691              if ((info) && (info->next)) comming = info->next;
692           }
693         else
694           {
695              if ((info) && (info->prev)) comming = info->prev;
696           }
697         if (comming)
698           {
699              _elm_access_highlight_set(comming);
700              elm_widget_focus_region_show(comming);
701           }
702         else
703           {
704              efl_ui_focus_util_focus(obj);
705              efl_ui_focus_manager_move(elm_widget_top_get(obj),
706                                        (Efl_Ui_Focus_Direction)dir);
707           }
708      }
709 
710    action_by = ELM_ACCESS_ACTION_FIRST;
711 
712    _elm_access_auto_highlight_set(EINA_FALSE);
713 }
714 
715 EAPI char *
_elm_access_text_get(const Elm_Access_Info * ac,int type,const Evas_Object * obj)716 _elm_access_text_get(const Elm_Access_Info *ac, int type, const Evas_Object *obj)
717 {
718    Elm_Access_Item *ai;
719    Eina_List *l;
720 
721    if (!ac) return NULL;
722    EINA_LIST_FOREACH(ac->items, l, ai)
723      {
724         if (ai->type == type)
725           {
726              if (ai->func) return ai->func((void *)(ai->data), (Evas_Object *)obj);
727              else if (ai->data) return strdup(ai->data);
728              return NULL;
729           }
730      }
731    return NULL;
732 }
733 
734 EAPI void
_elm_access_read(Elm_Access_Info * ac,int type,const Evas_Object * obj)735 _elm_access_read(Elm_Access_Info *ac, int type, const Evas_Object *obj)
736 {
737    char *txt = _elm_access_text_get(ac, type, obj);
738 
739    _access_init();
740    if (mapi)
741      {
742         if (mapi->out_done_callback_set)
743            mapi->out_done_callback_set(_access_read_done, NULL);
744         if (type == ELM_ACCESS_DONE)
745           {
746              if (mapi->out_read_done) mapi->out_read_done();
747           }
748         else if (type == ELM_ACCESS_CANCEL)
749           {
750              if (mapi->out_cancel) mapi->out_cancel();
751           }
752         else
753           {
754              if (txt)
755                {
756                   if (mapi->out_read) mapi->out_read(txt);
757                   if (mapi->out_read) mapi->out_read(".\n");
758                }
759           }
760      }
761    free(txt);
762 }
763 
764 EAPI void
_elm_access_say(const char * txt)765 _elm_access_say(const char *txt)
766 {
767    if (!_elm_config->access_mode) return;
768 
769    _access_init();
770    if (mapi)
771      {
772         if (mapi->out_done_callback_set)
773            mapi->out_done_callback_set(_access_read_done, NULL);
774         if (mapi->out_cancel) mapi->out_cancel();
775         if (txt)
776           {
777              if (mapi->out_read) mapi->out_read(txt);
778              if (mapi->out_read) mapi->out_read(".\n");
779           }
780         if (mapi->out_read_done) mapi->out_read_done();
781      }
782 }
783 
784 EAPI Elm_Access_Info *
_elm_access_info_get(const Evas_Object * obj)785 _elm_access_info_get(const Evas_Object *obj)
786 {
787    return evas_object_data_get(obj, "_elm_access");
788 }
789 
790 EAPI Elm_Access_Info *
_elm_access_object_get(const Evas_Object * obj)791 _elm_access_object_get(const Evas_Object *obj)
792 {
793    return _elm_access_info_get(obj);
794 }
795 
796 static Evas_Object *
_elm_access_widget_target_get(Evas_Object * obj)797 _elm_access_widget_target_get(Evas_Object *obj)
798 {
799    Evas_Object *o = obj;
800 
801    do
802      {
803         if (elm_widget_is(o))
804           break;
805         else
806           {
807              o = elm_widget_parent_widget_get(o);
808              if (!o)
809                o = evas_object_smart_parent_get(o);
810           }
811      }
812    while (o);
813 
814    return o;
815 }
816 
817 EAPI void
_elm_access_object_highlight(Evas_Object * obj)818 _elm_access_object_highlight(Evas_Object *obj)
819 {
820    Evas_Object *o, *widget;
821    Evas_Coord x, y, w, h;
822    Eina_Bool in_theme = EINA_FALSE;
823 
824    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
825    if (!o)
826      {
827         o = edje_object_add(evas_object_evas_get(obj));
828         evas_object_name_set(o, "_elm_access_disp");
829         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
830      }
831    else
832      {
833         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
834         if (ptarget)
835           {
836              evas_object_data_del(o, "_elm_access_target");
837              elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
838 
839              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
840                                                  _access_obj_hilight_del_cb, NULL);
841              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
842                                                  _access_obj_hilight_hide_cb, NULL);
843              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
844                                                  _access_obj_hilight_move_cb, NULL);
845              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
846                                                  _access_obj_hilight_resize_cb, NULL);
847 
848              widget = _elm_access_widget_target_get(ptarget);
849              if (widget)
850                {
851                   if (elm_widget_access_highlight_in_theme_get(widget))
852                     {
853                        elm_widget_signal_emit(widget, "elm,action,access_highlight,hide", "elm");
854                     }
855                }
856           }
857      }
858    evas_object_data_set(o, "_elm_access_target", obj);
859    elm_widget_parent_highlight_set(obj, EINA_TRUE);
860 
861    elm_widget_theme_object_set(obj, o, "access", "base", "default");
862 
863    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
864                                   _access_obj_hilight_del_cb, NULL);
865    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
866                                   _access_obj_hilight_hide_cb, NULL);
867    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
868                                   _access_obj_hilight_move_cb, NULL);
869    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
870                                   _access_obj_hilight_resize_cb, NULL);
871    evas_object_raise(o);
872    evas_object_geometry_get(obj, &x, &y, &w, &h);
873    evas_object_geometry_set(o, x, y, w, h);
874 
875    widget = _elm_access_widget_target_get(obj);
876    if (widget)
877      {
878         if (elm_widget_access_highlight_in_theme_get(widget))
879           {
880              in_theme = EINA_TRUE;
881              elm_widget_signal_emit(widget, "elm,action,access_highlight,show", "elm");
882           }
883      }
884    /* use callback, should an access object do below every time when
885     * a window gets a client message ECORE_X_ATOM_E_ILLMUE_ACTION_READ? */
886    if (!in_theme &&
887        !_access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT, NULL))
888      evas_object_show(o);
889    else
890      evas_object_hide(o);
891 }
892 
893 EAPI void
_elm_access_object_unhighlight(Evas_Object * obj)894 _elm_access_object_unhighlight(Evas_Object *obj)
895 {
896    Evas_Object *o, *ptarget;
897 
898    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
899    if (!o) return;
900    ptarget = evas_object_data_get(o, "_elm_access_target");
901    if (ptarget == obj)
902      {
903         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
904                                             _access_obj_hilight_del_cb, NULL);
905         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
906                                             _access_obj_hilight_hide_cb, NULL);
907         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
908                                             _access_obj_hilight_move_cb, NULL);
909         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
910                                             _access_obj_hilight_resize_cb, NULL);
911         evas_object_del(o);
912         elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
913      }
914 }
915 
916 static void
_content_resize(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)917 _content_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj,
918                 void *event_info EINA_UNUSED)
919 {
920    Evas_Object *accessobj;
921    Evas_Coord w, h;
922 
923    accessobj = data;
924    if (!accessobj) return;
925 
926    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
927    evas_object_resize(accessobj, w, h);
928 }
929 
930 static void
_content_move(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)931 _content_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj,
932               void *event_info EINA_UNUSED)
933 {
934    Evas_Object *accessobj;
935    Evas_Coord x, y;
936 
937    accessobj = data;
938    if (!accessobj) return;
939 
940    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
941    evas_object_move(accessobj, x, y);
942 }
943 
944 static Evas_Object *
_access_object_register(Evas_Object * obj,Evas_Object * parent)945 _access_object_register(Evas_Object *obj, Evas_Object *parent)
946 {
947    Evas_Object *ao;
948    Elm_Access_Info *ac;
949    Evas_Coord x, y, w, h;
950 
951    if (!obj) return NULL;
952 
953    /* check previous access object */
954    ao = evas_object_data_get(obj, "_part_access_obj");
955    if (ao)
956      _access_object_unregister(obj);
957 
958    /* create access object */
959    ao = _elm_access_add(parent);
960    if (!ao) return NULL;
961 
962    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
963                                   _content_resize, ao);
964    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
965                                   _content_move, ao);
966 
967    evas_object_geometry_get(obj, &x, &y, &w, &h);
968    evas_object_geometry_set(ao, x, y, w, h);
969    evas_object_show(ao);
970 
971    /* register access object */
972    _elm_access_object_register(ao, obj);
973 
974    /* set access object */
975    evas_object_data_set(obj, "_part_access_obj", ao);
976 
977    /* set owner part object */
978    ac = evas_object_data_get(ao, "_elm_access");
979    ac->part_object = obj;
980 
981    return ao;
982 }
983 
984 static void
_access_object_unregister(Evas_Object * obj)985 _access_object_unregister(Evas_Object *obj)
986 {
987    Elm_Access_Info *ac;
988    Evas_Object *ao;
989 
990    if (!obj) return;
991 
992    ao = evas_object_data_get(obj, "_part_access_obj");
993 
994    if (ao)
995      {
996         /* delete callbacks and unregister access object in _access_obj_del_cb*/
997         evas_object_del(ao);
998      }
999    else
1000      {
1001         /* button, check, label etc. */
1002         ac = evas_object_data_get(obj, "_elm_access");
1003         if (ac && ac->hoverobj)
1004           _elm_access_object_unregister(obj, ac->hoverobj);
1005      }
1006 }
1007 
1008 EAPI Evas_Object *
_elm_access_edje_object_part_object_register(Evas_Object * obj,const Evas_Object * eobj,const char * part)1009 _elm_access_edje_object_part_object_register(Evas_Object* obj,
1010                                              const Evas_Object *eobj,
1011                                              const char* part)
1012 {
1013    Evas_Object *ao, *po;
1014 
1015    edje_object_freeze((Evas_Object *)eobj);
1016    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1017    edje_object_thaw((Evas_Object *)eobj);
1018    if (!obj || !po) return NULL;
1019 
1020    /* check previous access object */
1021    ao = evas_object_data_get(po, "_part_access_obj");
1022    if (ao)
1023      _elm_access_edje_object_part_object_unregister(obj, eobj, part);
1024 
1025    ao = _access_object_register(po, obj);
1026 
1027    return ao;
1028 }
1029 
1030 //FIXME: unused obj should be removed from here and each widget.
1031 EAPI void
_elm_access_edje_object_part_object_unregister(Evas_Object * obj EINA_UNUSED,const Evas_Object * eobj,const char * part)1032 _elm_access_edje_object_part_object_unregister(Evas_Object* obj EINA_UNUSED,
1033                                                const Evas_Object *eobj,
1034                                                const char* part)
1035 {
1036    Evas_Object *po;
1037 
1038    edje_object_freeze((Evas_Object *)eobj);
1039    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1040    edje_object_thaw((Evas_Object *)eobj);
1041    if (!po) return;
1042 
1043    _access_object_unregister(po);
1044 }
1045 
1046 EAPI void
_elm_access_object_highlight_disable(Evas * e)1047 _elm_access_object_highlight_disable(Evas *e)
1048 {
1049    Evas_Object *o, *ptarget;
1050 
1051    o = evas_object_name_find(e, "_elm_access_disp");
1052    if (!o) return;
1053    ptarget = evas_object_data_get(o, "_elm_access_target");
1054    if (ptarget)
1055      {
1056         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
1057                                             _access_obj_hilight_del_cb, NULL);
1058         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
1059                                             _access_obj_hilight_hide_cb, NULL);
1060         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
1061                                             _access_obj_hilight_move_cb, NULL);
1062         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
1063                                             _access_obj_hilight_resize_cb, NULL);
1064      }
1065    evas_object_del(o);
1066    elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
1067 }
1068 
1069 static void
_access_obj_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)1070 _access_obj_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1071 {
1072 
1073    Ecore_Job *ao_del_job = NULL;
1074 
1075    evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _access_obj_del_cb);
1076 
1077    if (data) /* hover object */
1078      {
1079         evas_object_event_callback_del_full(data, EVAS_CALLBACK_RESIZE,
1080                                             _content_resize, obj);
1081         evas_object_event_callback_del_full(data, EVAS_CALLBACK_MOVE,
1082                                             _content_move, obj);
1083 
1084         _elm_access_object_unregister(obj, data);
1085      }
1086 
1087    ao_del_job = evas_object_data_get(obj, "_access_obj_del_job");
1088 
1089    if (ao_del_job)
1090      {
1091         ecore_job_del(ao_del_job);
1092         evas_object_data_del(obj, "_access_obj_del_job");
1093      }
1094 }
1095 
1096 static void
_access_obj_del_job(void * data)1097 _access_obj_del_job(void *data)
1098 {
1099    if (!data) return;
1100 
1101    evas_object_data_del(data, "_access_obj_del_job");
1102 
1103    evas_object_event_callback_del(data, EVAS_CALLBACK_DEL, _access_obj_del_cb);
1104    evas_object_del(data);
1105 }
1106 
1107 static void
_access_hover_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)1108 _access_hover_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1109 {
1110    Ecore_Job *ao_del_job = NULL;
1111 
1112    /* data - access object - could be NULL */
1113    if (!data) return;
1114 
1115    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE,
1116                                        _content_resize, data);
1117    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
1118                                        _content_move, data);
1119 
1120    _elm_access_object_unregister(data, obj);
1121 
1122    /* delete access object in job */
1123    ao_del_job = evas_object_data_get(data, "_access_obj_del_job");
1124    if (ao_del_job)
1125      {
1126         ecore_job_del(ao_del_job);
1127         evas_object_data_del(data, "_access_obj_del_job");
1128      }
1129 
1130    ao_del_job = ecore_job_add(_access_obj_del_job, data);
1131    evas_object_data_set(data, "_access_obj_del_job", ao_del_job);
1132 }
1133 
1134 EAPI void
_elm_access_object_register(Evas_Object * obj,Evas_Object * hoverobj)1135 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
1136 {
1137    Elm_Access_Info *ac;
1138 
1139    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1140                                   _access_hover_mouse_in_cb, obj);
1141    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
1142                                   _access_hover_mouse_out_cb, obj);
1143    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
1144                                   _access_hover_del_cb, obj);
1145 
1146    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1147                                   _access_obj_del_cb, hoverobj);
1148 
1149    ac = calloc(1, sizeof(Elm_Access_Info));
1150    evas_object_data_set(obj, "_elm_access", ac);
1151 
1152    ac->hoverobj = hoverobj;
1153 }
1154 
1155 EAPI void
_elm_access_object_unregister(Evas_Object * obj,Evas_Object * hoverobj)1156 _elm_access_object_unregister(Evas_Object *obj, Evas_Object *hoverobj)
1157 {
1158    Elm_Access_Info *ac;
1159    Evas_Object *ao;
1160 
1161    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1162                                        _access_hover_mouse_in_cb, obj);
1163    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
1164                                        _access_hover_mouse_out_cb, obj);
1165    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_DEL,
1166                                        _access_hover_del_cb, obj);
1167 
1168    /* _access_obj_del_cb and _access_hover_del_cb calls this function,
1169       both do not need _part_access_obj data, so delete the data here. */
1170    ao = evas_object_data_get(hoverobj, "_part_access_obj");
1171    if (ao) evas_object_data_del(hoverobj, "_part_access_obj");
1172 
1173    ac = evas_object_data_get(obj, "_elm_access");
1174    evas_object_data_del(obj, "_elm_access");
1175    if (ac)
1176      {
1177         _elm_access_clear(ac);
1178         free(ac);
1179      }
1180 
1181    Action_Info *a;
1182    a = evas_object_data_get(obj, "_elm_access_action_info");
1183    evas_object_data_del(obj,  "_elm_access_action_info");
1184    free(a);
1185 }
1186 
1187 EAPI void
_elm_access_widget_item_register(Elm_Widget_Item_Data * item)1188 _elm_access_widget_item_register(Elm_Widget_Item_Data *item)
1189 {
1190    Evas_Object *ao, *ho;
1191    Evas_Coord x, y, w, h;
1192    Elm_Access_Info *ac;
1193 
1194    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1195 
1196    /* check previous access object */
1197    if (item->access_obj)
1198      _elm_access_widget_item_unregister(item);
1199 
1200    // create access object
1201    ho = item->view;
1202    ao = _elm_access_add(item->widget);
1203    if (!ao) return;
1204 
1205    evas_object_event_callback_add(ho, EVAS_CALLBACK_RESIZE,
1206                                   _content_resize, ao);
1207    evas_object_event_callback_add(ho, EVAS_CALLBACK_MOVE,
1208                                   _content_move, ao);
1209 
1210    evas_object_geometry_get(ho, &x, &y, &w, &h);
1211    evas_object_geometry_set(ao, x, y, w, h);
1212    evas_object_show(ao);
1213 
1214    // register access object
1215    _elm_access_object_register(ao, ho);
1216 
1217    item->access_obj = ao;
1218 
1219    /* set owner widget item */
1220    ac = evas_object_data_get(ao, "_elm_access");
1221    ac->widget_item = item;
1222 }
1223 
1224 EAPI void
_elm_access_widget_item_unregister(Elm_Widget_Item_Data * item)1225 _elm_access_widget_item_unregister(Elm_Widget_Item_Data *item)
1226 {
1227    Evas_Object *ao;
1228 
1229    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1230 
1231    if (!item->access_obj) return;
1232 
1233    /* delete callbacks and unregister access object in _access_obj_del_cb*/
1234    ao = item->access_obj;
1235    item->access_obj = NULL;
1236 
1237    evas_object_del(ao);
1238 }
1239 
1240 EAPI Eina_Bool
_elm_access_2nd_click_timeout(Evas_Object * obj)1241 _elm_access_2nd_click_timeout(Evas_Object *obj)
1242 {
1243    Ecore_Timer *t;
1244 
1245    t = evas_object_data_get(obj, "_elm_2nd_timeout");
1246    if (t)
1247      {
1248         ecore_timer_del(t);
1249         evas_object_data_del(obj, "_elm_2nd_timeout");
1250         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
1251                                             _access_2nd_click_del_cb, NULL);
1252         return EINA_TRUE;
1253      }
1254    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
1255    evas_object_data_set(obj, "_elm_2nd_timeout", t);
1256    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1257                                   _access_2nd_click_del_cb, NULL);
1258    return EINA_FALSE;
1259 }
1260 
1261 static Evas_Object *
_elm_access_add(Evas_Object * parent)1262 _elm_access_add(Evas_Object *parent)
1263 {
1264    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1265    return elm_legacy_add(MY_CLASS, parent);
1266 }
1267 
1268 EOLIAN static Eo *
_elm_access_efl_object_constructor(Eo * obj,void * _pd EINA_UNUSED)1269 _elm_access_efl_object_constructor(Eo *obj, void *_pd EINA_UNUSED)
1270 {
1271    obj = efl_constructor(efl_super(obj, MY_CLASS));
1272    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
1273    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
1274 
1275    return obj;
1276 }
1277 
1278 EAPI Evas_Object *
elm_access_object_register(Evas_Object * obj,Evas_Object * parent)1279 elm_access_object_register(Evas_Object *obj, Evas_Object *parent)
1280 {
1281    return _access_object_register(obj, parent);
1282 }
1283 
1284 EAPI void
elm_access_object_unregister(Evas_Object * obj)1285 elm_access_object_unregister(Evas_Object *obj)
1286 {
1287    _access_object_unregister(obj);
1288 }
1289 
1290 EAPI Evas_Object *
elm_access_object_get(const Evas_Object * obj)1291 elm_access_object_get(const Evas_Object *obj)
1292 {
1293    return evas_object_data_get(obj, "_part_access_obj");
1294 }
1295 
1296 EAPI void
elm_access_info_set(Evas_Object * obj,int type,const char * text)1297 elm_access_info_set(Evas_Object *obj, int type, const char *text)
1298 {
1299    _elm_access_text_set(_elm_access_info_get(obj), type, text);
1300 }
1301 
1302 EAPI char *
elm_access_info_get(const Evas_Object * obj,int type)1303 elm_access_info_get(const Evas_Object *obj, int type)
1304 {
1305    return _elm_access_text_get(_elm_access_info_get(obj), type, obj);
1306 }
1307 
1308 EAPI void
elm_access_info_cb_set(Evas_Object * obj,int type,Elm_Access_Info_Cb func,const void * data)1309 elm_access_info_cb_set(Evas_Object *obj, int type,
1310                           Elm_Access_Info_Cb func, const void *data)
1311 {
1312    _elm_access_callback_set(_elm_access_info_get(obj), type, func, data);
1313 }
1314 
1315 EAPI void
elm_access_activate_cb_set(Evas_Object * obj,Elm_Access_Activate_Cb func,void * data)1316 elm_access_activate_cb_set(Evas_Object *obj,
1317                            Elm_Access_Activate_Cb  func, void *data)
1318 {
1319    Elm_Access_Info *ac;
1320 
1321    ac = _elm_access_info_get(obj);
1322    if (!ac) return;
1323 
1324    ac->activate = func;
1325    ac->activate_data = data;
1326 }
1327 
1328 EAPI void
elm_access_say(const char * text)1329 elm_access_say(const char *text)
1330 {
1331    if (!text) return;
1332 
1333    _elm_access_say(text);
1334 }
1335 
1336 EAPI void
elm_access_highlight_set(Evas_Object * obj)1337 elm_access_highlight_set(Evas_Object* obj)
1338 {
1339    _elm_access_highlight_set(obj);
1340 }
1341 
1342 EAPI Eina_Bool
elm_access_action(Evas_Object * obj,const Elm_Access_Action_Type type,Elm_Access_Action_Info * action_info)1343 elm_access_action(Evas_Object *obj, const Elm_Access_Action_Type type, Elm_Access_Action_Info *action_info)
1344 {
1345    Evas *evas;
1346    Evas_Object *ho;
1347    Elm_Access_Action_Info *a = action_info;
1348 
1349    switch (type)
1350      {
1351       case ELM_ACCESS_ACTION_READ:
1352       case ELM_ACCESS_ACTION_HIGHLIGHT:
1353         evas = evas_object_evas_get(obj);
1354         if (!evas) return EINA_FALSE;
1355 
1356         evas_event_feed_mouse_in(evas, 0, NULL);
1357 
1358         _elm_access_mouse_event_enabled_set(EINA_TRUE);
1359         evas_event_feed_mouse_move(evas, a->x, a->y, 0, NULL);
1360         _elm_access_mouse_event_enabled_set(EINA_FALSE);
1361 
1362         ho = _access_highlight_object_get(obj);
1363         if (ho)
1364           _access_action_callback_call(ho, ELM_ACCESS_ACTION_READ, a);
1365         break;
1366 
1367       case ELM_ACCESS_ACTION_UNHIGHLIGHT:
1368         evas = evas_object_evas_get(obj);
1369         if (!evas) return EINA_FALSE;
1370         _elm_access_object_highlight_disable(evas);
1371         break;
1372 
1373       case ELM_ACCESS_ACTION_HIGHLIGHT_NEXT:
1374         if (a->highlight_cycle)
1375           _elm_access_highlight_cycle(obj, ELM_FOCUS_NEXT);
1376         else
1377           return _access_highlight_next_get(obj, ELM_FOCUS_NEXT);
1378         break;
1379 
1380       case ELM_ACCESS_ACTION_HIGHLIGHT_PREV:
1381         if (a->highlight_cycle)
1382           _elm_access_highlight_cycle(obj, ELM_FOCUS_PREVIOUS);
1383         else
1384           return _access_highlight_next_get(obj, ELM_FOCUS_PREVIOUS);
1385         break;
1386 
1387       case ELM_ACCESS_ACTION_ACTIVATE:
1388         _elm_access_highlight_object_activate(obj, EFL_UI_ACTIVATE_DEFAULT);
1389         break;
1390 
1391       case ELM_ACCESS_ACTION_UP:
1392         _elm_access_highlight_object_activate(obj, EFL_UI_ACTIVATE_UP);
1393         break;
1394 
1395       case ELM_ACCESS_ACTION_DOWN:
1396         _elm_access_highlight_object_activate(obj, EFL_UI_ACTIVATE_DOWN);
1397         break;
1398 
1399       case ELM_ACCESS_ACTION_SCROLL:
1400         //TODO: SCROLL HIGHLIGHT OBJECT
1401         break;
1402 
1403       case ELM_ACCESS_ACTION_BACK:
1404         break;
1405 
1406       default:
1407         break;
1408      }
1409 
1410    return EINA_TRUE;
1411 }
1412 
1413 EAPI void
elm_access_action_cb_set(Evas_Object * obj,const Elm_Access_Action_Type type,const Elm_Access_Action_Cb cb,const void * data)1414 elm_access_action_cb_set(Evas_Object *obj, const Elm_Access_Action_Type type, const Elm_Access_Action_Cb cb, const void *data)
1415 {
1416    Action_Info *a;
1417    a =  evas_object_data_get(obj, "_elm_access_action_info");
1418 
1419    if (!a)
1420      {
1421         a = calloc(1, sizeof(Action_Info));
1422         evas_object_data_set(obj, "_elm_access_action_info", a);
1423      }
1424 
1425    a->obj = obj;
1426    a->fn[type].cb = cb;
1427    a->fn[type].user_data = (void *)data;
1428 }
1429 EAPI void
elm_access_external_info_set(Evas_Object * obj,const char * text)1430 elm_access_external_info_set(Evas_Object *obj, const char *text)
1431 {
1432    _elm_access_text_set
1433      (_elm_access_info_get(obj), ELM_ACCESS_CONTEXT_INFO, text);
1434 }
1435 
1436 EAPI char *
elm_access_external_info_get(const Evas_Object * obj)1437 elm_access_external_info_get(const Evas_Object *obj)
1438 {
1439    Elm_Access_Info *ac;
1440 
1441    ac = _elm_access_info_get(obj);
1442    return _elm_access_text_get(ac, ELM_ACCESS_CONTEXT_INFO, obj);
1443 }
1444 
1445 EAPI void
elm_access_highlight_next_set(Evas_Object * obj,Elm_Highlight_Direction dir,Evas_Object * next)1446 elm_access_highlight_next_set(Evas_Object *obj, Elm_Highlight_Direction dir, Evas_Object *next)
1447 {
1448    EINA_SAFETY_ON_FALSE_RETURN(obj);
1449    EINA_SAFETY_ON_FALSE_RETURN(next);
1450 
1451    Elm_Access_Info *info = _elm_access_info_get(obj);
1452    Elm_Access_Info *info_next = _elm_access_info_get(next);
1453 
1454    if (!info || !info_next)
1455      {
1456         ERR("There is no access information");
1457         return;
1458      }
1459 
1460    if (dir == ELM_HIGHLIGHT_DIR_NEXT)
1461      {
1462         info_next->prev = obj;
1463         info->next = next;
1464      }
1465    else if (dir == ELM_HIGHLIGHT_DIR_PREVIOUS)
1466      {
1467         info_next->next = obj;
1468         info->prev = next;
1469      }
1470    else
1471       ERR("Not supported focus direction for access highlight [%d]", dir);
1472 }
1473 
1474 EOLIAN static void
_elm_access_class_constructor(Efl_Class * klass)1475 _elm_access_class_constructor(Efl_Class *klass)
1476 {
1477    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1478 }
1479 
1480 static Eina_Bool
_access_atspi_action_do(Evas_Object * obj,const char * params)1481 _access_atspi_action_do(Evas_Object *obj, const char *params)
1482 {
1483    Eina_Bool ret;
1484 
1485    ret = EINA_FALSE;
1486    if (!strcmp(params, "highlight"))
1487       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT, NULL);
1488    else if (!strcmp(params, "unhighlight"))
1489       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
1490    else if (!strcmp(params, "highlight,next"))
1491       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT_NEXT, NULL);
1492    else if (!strcmp(params, "highlight,prev"))
1493       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT_PREV, NULL);
1494    else if (!strcmp(params, "activate"))
1495      {
1496         evas_object_smart_callback_call(obj, SIG_ACTIVATED, NULL);
1497         ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_ACTIVATE, NULL);
1498      }
1499    else if (!strcmp(params, "value,up"))
1500       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_UP, NULL);
1501    else if (!strcmp(params, "value,down"))
1502       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_DOWN, NULL);
1503    else if (!strcmp(params, "read"))
1504       ret = _access_action_callback_call(obj, ELM_ACCESS_ACTION_READ, NULL);
1505 
1506    return ret;
1507 }
1508 
1509 EOLIAN const Efl_Access_Action_Data *
_elm_access_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,void * pd EINA_UNUSED)1510 _elm_access_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
1511 {
1512    static Efl_Access_Action_Data atspi_actions[] = {
1513           { "highlight", NULL, "highlight", _access_atspi_action_do},
1514           { "unhighlight", NULL, "unhighlight", _access_atspi_action_do},
1515           { "highlight,next", NULL, "highlight,next", _access_atspi_action_do},
1516           { "highlight,prev", NULL, "highlight,prev", _access_atspi_action_do},
1517           { "activate", NULL, "activate", _access_atspi_action_do},
1518           { "value,up", NULL, "value,up", _access_atspi_action_do},
1519           { "value,down", NULL, "value,down", _access_atspi_action_do},
1520           { "read", NULL, "read", _access_atspi_action_do},
1521           { NULL, NULL, NULL, NULL }
1522    };
1523    return &atspi_actions[0];
1524 }
1525 
1526 EOLIAN static Efl_Access_State_Set
_elm_access_efl_access_object_state_set_get(const Eo * obj,void * pd EINA_UNUSED)1527 _elm_access_efl_access_object_state_set_get(const Eo *obj, void *pd EINA_UNUSED)
1528 {
1529    Efl_Access_State_Set ret;
1530    ret = efl_access_object_state_set_get(efl_super(obj, ELM_ACCESS_CLASS));
1531 
1532    Elm_Access_Info *info = _elm_access_info_get(obj);
1533    if (info && !evas_object_visible_get(info->part_object))
1534      {
1535         STATE_TYPE_UNSET(ret, EFL_ACCESS_STATE_TYPE_VISIBLE);
1536         STATE_TYPE_UNSET(ret, EFL_ACCESS_STATE_TYPE_SHOWING);
1537      }
1538 
1539    return ret;
1540 }
1541 
1542 /* Internal EO APIs and hidden overrides */
1543 
1544 #define ELM_ACCESS_EXTRA_OPS \
1545    EFL_CANVAS_GROUP_ADD_OPS(elm_access)
1546 
1547 #include "elm_access_eo.c"
1548