[access] reset access info callback function, if access info data is set only
[framework/uifw/elementary.git] / src / lib / elm_access.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_interface_scrollable.h"
4
5 static const char ACCESS_SMART_NAME[] = "elm_access";
6
7 ELM_INTERNAL_SMART_SUBCLASS_NEW
8   (ACCESS_SMART_NAME, _elm_access, Elm_Widget_Smart_Class,
9   Elm_Widget_Smart_Class, elm_widget_smart_class_get, NULL);
10
11 struct _Func_Data
12 {
13    void                *user_data; /* Holds user data to CB */
14    Elm_Access_Action_Cb cb;
15 };
16
17 typedef struct _Func_Data Func_Data;
18
19 struct _Action_Info
20 {
21    Evas_Object      *obj;
22    Func_Data         fn[ELM_ACCESS_ACTION_LAST + 1]; /* Callback for specific action */
23 };
24
25 typedef struct _Action_Info Action_Info;
26
27 static Eina_Bool mouse_event_enable = EINA_TRUE;
28 static Eina_Bool read_mode = EINA_FALSE;
29 static Evas_Coord_Point offset;
30 static Evas_Object *s_parent; /* scrollable parent */
31 static Elm_Access_Action_Type action_type = ELM_ACCESS_ACTION_FIRST;
32
33 static Evas_Object * _elm_access_add(Evas_Object *parent);
34
35 static void
36 _elm_access_smart_add(Evas_Object *obj)
37 {
38    EVAS_SMART_DATA_ALLOC(obj, Elm_Widget_Smart_Data);
39    ELM_WIDGET_CLASS(_elm_access_parent_sc)->base.add(obj);
40
41    elm_widget_can_focus_set(obj, EINA_TRUE);
42 }
43
44 static Eina_Bool
45 _elm_access_smart_on_focus(Evas_Object *obj)
46 {
47    evas_object_focus_set(obj, elm_widget_focus_get(obj));
48
49    return EINA_TRUE;
50 }
51
52 static Eina_Bool
53 _elm_access_smart_activate(Evas_Object *obj, Elm_Activate act)
54 {
55    int type = ELM_ACCESS_ACTION_FIRST;
56
57    Action_Info *a;
58    a = evas_object_data_get(obj, "_elm_access_action_info");
59
60    switch (act)
61      {
62       case ELM_ACTIVATE_DEFAULT:
63         type = ELM_ACCESS_ACTION_ACTIVATE;
64         break;
65
66       case ELM_ACTIVATE_UP:
67         type = ELM_ACCESS_ACTION_VALUE_CHANGE;
68         break;
69
70       case ELM_ACTIVATE_DOWN:
71         type = ELM_ACCESS_ACTION_VALUE_CHANGE;
72         break;
73
74       case ELM_ACTIVATE_RIGHT:
75         break;
76
77       case ELM_ACTIVATE_LEFT:
78         break;
79
80       default:
81         break;
82      }
83
84    if ((a) && (type > ELM_ACCESS_ACTION_FIRST) &&
85               (type < ELM_ACCESS_ACTION_LAST) &&
86               (a->fn[type].cb))
87      {
88         a->fn[type].cb(a->fn[type].user_data, obj, NULL);
89         return EINA_TRUE;
90      }
91
92    /* TODO: deprecate below? and change above with _access_action_callback_call(); */
93    if (act != ELM_ACTIVATE_DEFAULT) return EINA_FALSE;
94
95    Elm_Access_Info *ac = evas_object_data_get(obj, "_elm_access");
96    if (!ac) return EINA_FALSE;
97
98    if (ac->activate)
99      ac->activate(ac->activate_data, ac->part_object,
100                   (Elm_Object_Item *)ac->widget_item);
101
102    return EINA_TRUE;
103 }
104
105 static void
106 _elm_access_smart_set_user(Elm_Widget_Smart_Class *sc)
107 {
108    sc->base.add = _elm_access_smart_add;
109
110    /* not a 'focus chain manager' */
111    sc->focus_next = NULL;
112    sc->focus_direction = NULL;
113    sc->on_focus = _elm_access_smart_on_focus;
114    sc->activate = _elm_access_smart_activate;
115
116    return;
117 }
118
119 typedef struct _Mod_Api Mod_Api;
120
121 struct _Mod_Api
122 {
123    void (*out_read) (const char *txt);
124    void (*out_read_done) (void);
125    void (*out_cancel) (void);
126    void (*out_done_callback_set) (void (*func) (void *data), const void *data);
127 };
128
129 static int initted = 0;
130 static Mod_Api *mapi = NULL;
131
132 static void
133 _access_init(void)
134 {
135    Elm_Module *m;
136    initted++;
137    if (initted > 1) return;
138    if (!(m = _elm_module_find_as("access/api"))) return;
139    m->api = malloc(sizeof(Mod_Api));
140    if (!m->api) return;
141    m->init_func(m);
142    ((Mod_Api *)(m->api)      )->out_read = // called to read out some text
143       _elm_module_symbol_get(m, "out_read");
144    ((Mod_Api *)(m->api)      )->out_read_done = // called to set a done marker so when it is reached the done callback is called
145       _elm_module_symbol_get(m, "out_read_done");
146    ((Mod_Api *)(m->api)      )->out_cancel = // called to read out some text
147       _elm_module_symbol_get(m, "out_cancel");
148    ((Mod_Api *)(m->api)      )->out_done_callback_set = // called when last read done
149       _elm_module_symbol_get(m, "out_done_callback_set");
150    mapi = m->api;
151 }
152
153 static void
154 _access_shutdown(void)
155 {
156    Elm_Module *m;
157    if (initted == 0) return;
158    if (!(m = _elm_module_find_as("access/api"))) return;
159
160    m->shutdown_func(m);
161
162    initted = 0;
163
164    free(mapi);
165    mapi = NULL;
166 }
167
168 static Elm_Access_Item *
169 _access_add_set(Elm_Access_Info *ac, int type)
170 {
171    Elm_Access_Item *ai;
172    Eina_List *l;
173
174    if (!ac) return NULL;
175    EINA_LIST_FOREACH(ac->items, l, ai)
176      {
177         if (ai->type == type)
178           {
179              if (!ai->func)
180                {
181                   if (ai->data) eina_stringshare_del(ai->data);
182                }
183              ai->func = NULL;
184              ai->data = NULL;
185              return ai;
186           }
187      }
188    ai = calloc(1, sizeof(Elm_Access_Item));
189    ai->type = type;
190    ac->items = eina_list_prepend(ac->items, ai);
191    return ai;
192 }
193
194 static Evas_Object *
195 _access_highlight_object_get(Evas_Object *obj)
196 {
197    Evas_Object *o, *ho;
198
199    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
200    if (!o) return NULL;
201
202    ho = evas_object_data_get(o, "_elm_access_target");
203
204    return ho;
205 }
206
207 static void
208 _access_highlight_read(Elm_Access_Info *ac, Evas_Object *obj)
209 {
210    int type;
211    char *txt = NULL;
212    Eina_Strbuf *strbuf;
213
214    /*FIXME: TIZEN only - read at once because Tizen TTS engine performance is not good */
215    strbuf = eina_strbuf_new();
216
217    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
218      {
219
220         if (ac->on_highlight) ac->on_highlight(ac->on_highlight_data);
221         _elm_access_object_hilight(obj);
222
223         for (type = ELM_ACCESS_INFO_FIRST + 1; type < ELM_ACCESS_INFO_LAST; type++)
224           {
225              txt = _elm_access_text_get(ac, type, obj);
226              if (txt && (strlen(txt) > 0))
227                {
228                   if (eina_strbuf_length_get(strbuf) > 0)
229                     eina_strbuf_append_printf(strbuf, ", %s", txt);
230                   else
231                     eina_strbuf_append(strbuf, txt);
232
233                   free(txt);
234                }
235           }
236      }
237
238    txt = eina_strbuf_string_steal(strbuf);
239    eina_strbuf_free(strbuf);
240
241    _elm_access_say(txt);
242    free(txt);
243 }
244
245 static Eina_Bool
246 _access_obj_over_timeout_cb(void *data)
247 {
248    Elm_Access_Info *ac;
249    Evas_Object *ho;
250
251    if (!data) return EINA_FALSE;
252
253    ac = evas_object_data_get(data, "_elm_access");
254    if (!ac) return EINA_FALSE;
255
256    ho = _access_highlight_object_get(data);
257    if (ho != data) _access_highlight_read(ac, data);
258
259    ac->delay_timer = NULL;
260    return EINA_FALSE;
261 }
262
263 static void
264 _access_obj_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
265 {
266    Elm_Access_Info *ac;
267    if (!mouse_event_enable) return;
268
269    ac = evas_object_data_get(data, "_elm_access");
270    if (!ac) return;
271
272    if (ac->delay_timer)
273      {
274         ecore_timer_del(ac->delay_timer);
275         ac->delay_timer = NULL;
276      }
277    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
278       ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
279 }
280
281 static void
282 _access_obj_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
283 {
284    Elm_Access_Info *ac;
285    if (!mouse_event_enable) return;
286
287    ac = evas_object_data_get(data, "_elm_access");
288    if (!ac) return;
289
290    _elm_access_object_unhilight(data);
291    if (ac->delay_timer)
292      {
293         ecore_timer_del(ac->delay_timer);
294         ac->delay_timer = NULL;
295      }
296 }
297
298 static void
299 _access_obj_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
300 {
301    _elm_access_object_unregister(data, obj);
302
303    // _elm_access_edje_object_part_object_register(); set below object data
304    evas_object_data_del(obj, "_part_access_obj");
305 }
306
307 static void
308 _access_read_done(void *data __UNUSED__)
309 {
310    printf("read done\n");
311    // FIXME: produce event here
312 }
313
314 static void
315 _access_2nd_click_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
316 {
317    Ecore_Timer *t;
318
319    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
320                                        _access_2nd_click_del_cb, NULL);
321    t = evas_object_data_get(obj, "_elm_2nd_timeout");
322    if (t)
323      {
324         ecore_timer_del(t);
325         evas_object_data_del(obj, "_elm_2nd_timeout");
326      }
327 }
328
329 static Eina_Bool
330 _access_2nd_click_timeout_cb(void *data)
331 {
332    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
333                                        _access_2nd_click_del_cb, NULL);
334    evas_object_data_del(data, "_elm_2nd_timeout");
335    return EINA_FALSE;
336 }
337
338 static void
339 _access_obj_hilight_del_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
340 {
341    _elm_access_object_hilight_disable(e);
342 }
343
344 static void
345 _access_obj_hilight_hide_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
346 {
347    _elm_access_object_hilight_disable(e);
348 }
349
350 static void
351 _access_obj_hilight_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
352 {
353    Evas_Coord x, y;
354    Evas_Object *o;
355
356    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
357    if (!o) return;
358    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
359    evas_object_move(o, x, y);
360 }
361
362 static void
363 _access_obj_hilight_resize_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
364 {
365    Evas_Coord w, h;
366    Evas_Object *o;
367
368    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
369    if (!o) return;
370    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
371    evas_object_resize(o, w, h);
372 }
373
374 void
375 _elm_access_mouse_event_enabled_set(Eina_Bool enabled)
376 {
377    enabled = !!enabled;
378    if (mouse_event_enable == enabled) return;
379    mouse_event_enable = enabled;
380 }
381
382 void
383 _elm_access_read_mode_set(Eina_Bool enabled)
384 {
385    enabled = !!enabled;
386    if (read_mode == enabled) return;
387    read_mode = enabled;
388 }
389
390 Eina_Bool
391 _elm_access_read_mode_get()
392 {
393    return read_mode;
394 }
395
396 void
397 _elm_access_shutdown()
398 {
399    _access_shutdown();
400 }
401
402 static void
403 _access_order_del_cb(void *data,
404                      Evas *e __UNUSED__,
405                      Evas_Object *obj,
406                      void *event_info __UNUSED__)
407 {
408    Elm_Widget_Item *item = data;
409
410    item->access_order = eina_list_remove(item->access_order, obj);
411 }
412
413 void
414 _elm_access_widget_item_access_order_set(Elm_Widget_Item *item,
415                                               Eina_List *objs)
416 {
417    Eina_List *l;
418    Evas_Object *o;
419
420    if (!item) return;
421
422    _elm_access_widget_item_access_order_unset(item);
423
424    EINA_LIST_FOREACH(objs, l, o)
425      {
426         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
427                                        _access_order_del_cb, item);
428      }
429
430    item->access_order = objs;
431 }
432
433 const Eina_List *
434 _elm_access_widget_item_access_order_get(const Elm_Widget_Item *item)
435 {
436    if (!item) return NULL;
437    return item->access_order;
438 }
439
440 void
441 _elm_access_widget_item_access_order_unset(Elm_Widget_Item *item)
442 {
443    Eina_List *l, *l_next;
444    Evas_Object *o;
445
446    if (!item) return;
447
448    EINA_LIST_FOREACH_SAFE(item->access_order, l, l_next, o)
449      {
450         evas_object_event_callback_del_full
451           (o, EVAS_CALLBACK_DEL, _access_order_del_cb, item);
452         item->access_order = eina_list_remove_list(item->access_order, l);
453      }
454 }
455
456 void
457 _elm_access_highlight_object_scroll(Evas_Object *obj, int type, int x, int y)
458 {
459    Evas *evas;
460    Evas_Object *ho;
461    Evas_Coord_Rectangle ho_area;
462
463    if (!obj) return;
464
465    evas = evas_object_evas_get(obj);
466    if (!evas) return;
467
468    switch (type)
469      {
470       case 0:
471         ho = _access_highlight_object_get(obj);
472         if (!ho)
473           {
474              s_parent = NULL;
475              return;
476           }
477         else
478           {
479              /* find scrollable parent */
480              s_parent = elm_widget_parent_get(ho);
481              while (s_parent)
482                {
483                   if(!!evas_object_smart_interface_get(s_parent, ELM_SCROLLABLE_IFACE_NAME))
484                     break;
485                   s_parent = elm_widget_parent_get(s_parent);
486                }
487
488               if (!s_parent) return;
489
490               ELM_SCROLLABLE_IFACE_GET(s_parent, s_iface);
491               s_iface->repeat_events_set(s_parent, EINA_FALSE);
492
493               evas_object_geometry_get
494                 (ho, &ho_area.x, &ho_area.y, &ho_area.w, &ho_area.h);
495
496               offset.x = x - (ho_area.x + (ho_area.w / 2));
497               offset.y = y - (ho_area.y + (ho_area.h / 2));
498           }
499
500         evas_event_feed_mouse_in(evas, 0, NULL);
501         evas_event_feed_mouse_move(evas, x - offset.x, y - offset.y, 0, NULL);
502         evas_event_feed_mouse_down(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
503         break;
504
505       case 1:
506         if (!s_parent) return;
507         evas_event_feed_mouse_move(evas, x - offset.x, y - offset.y, 0, NULL);
508         break;
509
510       case 2:
511         if (!s_parent) return;
512         evas_event_feed_mouse_up(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
513
514         ELM_SCROLLABLE_IFACE_GET(s_parent, s_iface);
515         s_iface->repeat_events_set(s_parent, EINA_TRUE);
516         break;
517
518       default:
519         break;
520      }
521 }
522
523 static Eina_Bool
524 _access_action_callback_call(Evas_Object *obj,
525                              Elm_Access_Action_Type type,
526                              void *data)
527 {
528    Action_Info *a;
529    Eina_Bool ret;
530
531    ret = EINA_FALSE;
532    a = evas_object_data_get(obj, "_elm_access_action_info");
533
534    if (a && (a->fn[type].cb))
535      ret = a->fn[type].cb(a->fn[type].user_data, obj, data);
536
537    return ret;
538 }
539
540 static Eina_Bool
541 _access_highlight_next_get(Evas_Object *obj, Elm_Focus_Direction dir)
542 {
543    int type;
544    Evas_Object *ho, *parent, *target;
545    Eina_Bool ret;
546
547    target = NULL;
548    ret = EINA_FALSE;
549
550    if (!elm_widget_is(obj)) return ret;
551
552    ho = _access_highlight_object_get(obj);
553    if (!ho) return ret;
554
555    parent = ho;
556
557    /* find highlight root */
558    do
559      {
560         ELM_WIDGET_DATA_GET(parent, sd);
561         if (sd->highlight_root)
562           {
563              /* change highlight root */
564              obj = parent;
565              break;
566           }
567         parent = elm_widget_parent_get(parent);
568      }
569    while (parent);
570
571    _elm_access_read_mode_set(EINA_TRUE);
572
573    ret = elm_widget_focus_next_get(obj, dir, &target);
574    if (ret && target)
575      {
576         if (dir == ELM_FOCUS_NEXT)
577           type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
578         else
579           type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
580
581         if (!_access_action_callback_call(ho, type, NULL))
582           {
583              /* change highlight object */
584              action_type = type;
585
586              _elm_access_highlight_set(target);
587              ret = EINA_FALSE;
588
589              action_type = ELM_ACCESS_ACTION_FIRST;
590           }
591      }
592
593    _elm_access_read_mode_set(EINA_FALSE);
594
595    return ret;
596 }
597
598 //-------------------------------------------------------------------------//
599 EAPI void
600 _elm_access_highlight_set(Evas_Object* obj)
601 {
602    Evas *evas;
603    Elm_Access_Info *ac;
604    Evas_Object *ho;
605    Evas_Coord_Point ho_point = { 0, 0 };
606
607    if (!obj) return;
608
609    ho = _access_highlight_object_get(obj);
610    if (ho == obj) return;
611
612    ac = evas_object_data_get(obj, "_elm_access");
613    if (!ac) return;
614
615    _access_highlight_read(ac, obj);
616
617    /* move mouse position to inside of highlight object. if an object has a
618       highlight by highlight_cycle();, the mouse still positions at previous
619       position which would be made by MOUSE_IN event. */
620    evas = evas_object_evas_get(obj);
621    if (!evas) return;
622
623    evas_object_geometry_get(obj, &ho_point.x, &ho_point.y, 0, 0);
624    evas_event_feed_mouse_move(evas, ho_point.x, ho_point.y, 0, NULL);
625 }
626
627 EAPI void
628 _elm_access_clear(Elm_Access_Info *ac)
629 {
630    Elm_Access_Item *ai;
631
632    if (!ac) return;
633    if (ac->delay_timer)
634      {
635         ecore_timer_del(ac->delay_timer);
636         ac->delay_timer = NULL;
637      }
638    EINA_LIST_FREE(ac->items, ai)
639      {
640         if (!ai->func)
641           {
642              if (ai->data) eina_stringshare_del(ai->data);
643           }
644         free(ai);
645      }
646 }
647
648 EAPI void
649 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
650 {
651    Elm_Access_Item *ai = _access_add_set(ac, type);
652    if (!ai) return;
653    ai->func = NULL;
654    ai->data = eina_stringshare_add(text);
655 }
656
657 EAPI void
658 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Info_Cb func, const void *data)
659 {
660    Elm_Access_Item *ai = _access_add_set(ac, type);
661    if (!ai) return;
662    ai->func = func;
663    ai->data = data;
664 }
665
666 EAPI void
667 _elm_access_on_highlight_hook_set(Elm_Access_Info           *ac,
668                                   Elm_Access_On_Highlight_Cb func,
669                                   void                      *data)
670 {
671     if (!ac) return;
672     ac->on_highlight = func;
673     ac->on_highlight_data = data;
674 }
675
676 EAPI void
677 _elm_access_activate_callback_set(Elm_Access_Info           *ac,
678                                   Elm_Access_Activate_Cb     func,
679                                   void                      *data)
680 {
681    if (!ac) return;
682    ac->activate = func;
683    ac->activate_data = data;
684 }
685
686 EAPI void
687 _elm_access_highlight_object_activate(Evas_Object *obj, Elm_Activate act)
688 {
689    Evas_Object *highlight;
690
691    highlight = _access_highlight_object_get(obj);
692    if (!highlight) return;
693
694    _elm_access_read_mode_set(EINA_FALSE);
695
696    if (!elm_object_focus_get(highlight))
697      elm_object_focus_set(highlight, EINA_TRUE);
698
699    elm_widget_activate(highlight, act);
700    return;
701 }
702
703 EAPI void
704 _elm_access_highlight_cycle(Evas_Object *obj, Elm_Focus_Direction dir)
705 {
706    int type;
707    Evas_Object *ho, *parent;
708
709    ho = _access_highlight_object_get(obj);
710    if (!ho) return;
711
712    parent = ho;
713
714    /* find highlight root */
715    do
716      {
717         ELM_WIDGET_DATA_GET(parent, sd);
718         if (sd->highlight_root)
719           {
720              /* change highlight root */
721              obj = parent;
722              break;
723           }
724         parent = elm_widget_parent_get(parent);
725      }
726    while (parent);
727
728    _elm_access_read_mode_set(EINA_TRUE);
729
730    if (dir == ELM_FOCUS_NEXT)
731      type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
732    else
733      type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
734
735    action_type = type;
736
737    if (!_access_action_callback_call(ho, type, NULL))
738      elm_widget_focus_cycle(obj, dir);
739
740    action_type = ELM_ACCESS_ACTION_FIRST;
741
742    _elm_access_read_mode_set(EINA_FALSE);
743 }
744
745 EAPI char *
746 _elm_access_text_get(const Elm_Access_Info *ac, int type, const Evas_Object *obj)
747 {
748    Elm_Access_Item *ai;
749    Eina_List *l;
750
751    if (!ac) return NULL;
752    EINA_LIST_FOREACH(ac->items, l, ai)
753      {
754         if (ai->type == type)
755           {
756              if (ai->func) return ai->func((void *)(ai->data), (Evas_Object *)obj);
757              else if (ai->data) return strdup(ai->data);
758              return NULL;
759           }
760      }
761    return NULL;
762 }
763
764 EAPI void
765 _elm_access_read(Elm_Access_Info *ac, int type, const Evas_Object *obj)
766 {
767    char *txt = _elm_access_text_get(ac, type, obj);
768
769    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
770
771    _access_init();
772    if (mapi)
773      {
774         if (mapi->out_done_callback_set)
775            mapi->out_done_callback_set(_access_read_done, NULL);
776         if (type == ELM_ACCESS_DONE)
777           {
778              if (mapi->out_read_done) mapi->out_read_done();
779           }
780         else if (type == ELM_ACCESS_CANCEL)
781           {
782              if (mapi->out_cancel) mapi->out_cancel();
783           }
784         else
785           {
786              if (txt && mapi->out_read) mapi->out_read(txt);
787           }
788      }
789    if (txt) free(txt);
790 }
791
792 EAPI void
793 _elm_access_say(const char *txt)
794 {
795    if (!_elm_config->access_mode) return;
796
797    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
798
799    _access_init();
800    if (mapi)
801      {
802         if (mapi->out_done_callback_set)
803            mapi->out_done_callback_set(_access_read_done, NULL);
804         if (mapi->out_cancel) mapi->out_cancel();
805         if (txt)
806           {
807              if (mapi->out_read) mapi->out_read(txt);
808              //if (mapi->out_read) mapi->out_read(".\n"); /* TIZEN only: Tizen TTS engine performance is not good */
809           }
810         if (mapi->out_read_done) mapi->out_read_done();
811      }
812 }
813
814 EAPI Elm_Access_Info *
815 _elm_access_object_get(const Evas_Object *obj)
816 {
817    return evas_object_data_get(obj, "_elm_access");
818 }
819
820 EAPI void
821 _elm_access_object_hilight(Evas_Object *obj)
822 {
823    Evas_Object *o;
824    Evas_Coord x, y, w, h;
825    Elm_Access_Action_Info *a;
826
827    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
828    if (!o)
829      {
830         o = edje_object_add(evas_object_evas_get(obj));
831         evas_object_name_set(o, "_elm_access_disp");
832         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
833      }
834    else
835      {
836         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
837         if (ptarget)
838           {
839              evas_object_data_del(o, "_elm_access_target");
840              elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
841
842              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
843                                                  _access_obj_hilight_del_cb, NULL);
844              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
845                                                  _access_obj_hilight_hide_cb, NULL);
846              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
847                                                  _access_obj_hilight_move_cb, NULL);
848              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
849                                                  _access_obj_hilight_resize_cb, NULL);
850              _access_action_callback_call(ptarget, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
851           }
852      }
853    evas_object_data_set(o, "_elm_access_target", obj);
854    elm_widget_parent_highlight_set(obj, EINA_TRUE);
855
856    elm_widget_theme_object_set(obj, o, "access", "base", "default");
857
858    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
859                                   _access_obj_hilight_del_cb, NULL);
860    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
861                                   _access_obj_hilight_hide_cb, NULL);
862    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
863                                   _access_obj_hilight_move_cb, NULL);
864    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
865                                   _access_obj_hilight_resize_cb, NULL);
866    evas_object_raise(o);
867    evas_object_geometry_get(obj, &x, &y, &w, &h);
868    evas_object_move(o, x, y);
869    evas_object_resize(o, w, h);
870
871    /* use callback, should an access object do below every time when
872         * a window gets a client message ECORE_X_ATOM_E_ILLMUE_ACTION_READ? */
873    a = calloc(1, sizeof(Elm_Access_Action_Info));
874    a->action_type = action_type;
875    if (!_access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT, a))
876      evas_object_show(o);
877    else
878      evas_object_hide(o);
879    free(a);
880 }
881
882 EAPI void
883 _elm_access_object_unhilight(Evas_Object *obj)
884 {
885    Evas_Object *o, *ptarget;
886
887    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
888    if (!o) return;
889    ptarget = evas_object_data_get(o, "_elm_access_target");
890    if (ptarget == obj)
891      {
892         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
893                                             _access_obj_hilight_del_cb, NULL);
894         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
895                                             _access_obj_hilight_hide_cb, NULL);
896         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
897                                             _access_obj_hilight_move_cb, NULL);
898         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
899                                             _access_obj_hilight_resize_cb, NULL);
900         evas_object_del(o);
901         elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
902         _access_action_callback_call(ptarget, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
903      }
904 }
905
906 static void
907 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
908                 void *event_info __UNUSED__)
909 {
910    Evas_Object *accessobj;
911    Evas_Coord w, h;
912
913    accessobj = data;
914    if (!accessobj) return;
915
916    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
917    evas_object_resize(accessobj, w, h);
918 }
919
920 static void
921 _content_move(void *data, Evas *e __UNUSED__, Evas_Object *obj,
922               void *event_info __UNUSED__)
923 {
924    Evas_Object *accessobj;
925    Evas_Coord x, y;
926
927    accessobj = data;
928    if (!accessobj) return;
929
930    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
931    evas_object_move(accessobj, x, y);
932 }
933
934 static Evas_Object *
935 _access_object_register(Evas_Object *obj, Evas_Object *parent)
936 {
937    Evas_Object *ao;
938    Elm_Access_Info *ac;
939    Evas_Coord x, y, w, h;
940
941    if (!obj) return NULL;
942
943    /* create access object */
944    ao = _elm_access_add(parent);
945    if (!ao) return NULL;
946
947    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
948                                   _content_resize, ao);
949    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
950                                   _content_move, ao);
951
952    evas_object_geometry_get(obj, &x, &y, &w, &h);
953    evas_object_move(ao, x, y);
954    evas_object_resize(ao, w, h);
955    evas_object_show(ao);
956
957    /* register access object */
958    _elm_access_object_register(ao, obj);
959
960    /* set access object */
961    evas_object_data_set(obj, "_part_access_obj", ao);
962
963    /* set owner part object */
964    ac = evas_object_data_get(ao, "_elm_access");
965    ac->part_object = obj;
966
967    return ao;
968 }
969
970 static void
971 _access_object_unregister(Evas_Object *obj)
972 {
973    Elm_Access_Info *ac;
974    Evas_Object *ao;
975
976    if (!obj) return;
977
978    ao = evas_object_data_get(obj, "_part_access_obj");
979
980    if (ao)
981      {
982         evas_object_data_del(obj, "_part_access_obj");
983
984         /* delete callbacks */
985         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE,
986                                             _content_resize, ao);
987         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
988                                             _content_move, ao);
989
990         /* unregister access object */
991         _elm_access_object_unregister(ao, obj);
992
993         evas_object_del(ao);
994      }
995    else
996      {
997         /* button, check, label etc. */
998         ac = evas_object_data_get(obj, "_elm_access");
999         if (ac && ac->hoverobj)
1000           _elm_access_object_unregister(obj, ac->hoverobj);
1001      }
1002 }
1003
1004 EAPI Evas_Object *
1005 _elm_access_edje_object_part_object_register(Evas_Object* obj,
1006                                              const Evas_Object *eobj,
1007                                              const char* part)
1008 {
1009    Evas_Object *ao, *po;
1010
1011    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1012    if (!obj || !po) return NULL;
1013
1014    /* check previous access object */
1015    ao = evas_object_data_get(po, "_part_access_obj");
1016    if (ao)
1017      _elm_access_edje_object_part_object_unregister(obj, eobj, part);
1018
1019    ao = _access_object_register(po, obj);
1020
1021    return ao;
1022 }
1023
1024 //FIXME: unused obj should be removed from here and each widget.
1025 EAPI void
1026 _elm_access_edje_object_part_object_unregister(Evas_Object* obj __UNUSED__,
1027                                                const Evas_Object *eobj,
1028                                                const char* part)
1029 {
1030    Evas_Object *po;
1031
1032    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1033    if (!po) return;
1034
1035    _access_object_unregister(po);
1036 }
1037
1038 EAPI void
1039 _elm_access_object_hilight_disable(Evas *e)
1040 {
1041    Evas_Object *o, *ptarget;
1042
1043    o = evas_object_name_find(e, "_elm_access_disp");
1044    if (!o) return;
1045    ptarget = evas_object_data_get(o, "_elm_access_target");
1046    if (ptarget)
1047      {
1048         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
1049                                             _access_obj_hilight_del_cb, NULL);
1050         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
1051                                             _access_obj_hilight_hide_cb, NULL);
1052         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
1053                                             _access_obj_hilight_move_cb, NULL);
1054         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
1055                                             _access_obj_hilight_resize_cb, NULL);
1056      }
1057    evas_object_del(o);
1058    elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
1059 }
1060
1061 EAPI void
1062 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
1063 {
1064    Elm_Access_Info *ac;
1065
1066    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1067                                   _access_obj_mouse_in_cb, obj);
1068    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
1069                                   _access_obj_mouse_out_cb, obj);
1070    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
1071                                   _access_obj_del_cb, obj);
1072    ac = calloc(1, sizeof(Elm_Access_Info));
1073    evas_object_data_set(obj, "_elm_access", ac);
1074
1075    ac->hoverobj = hoverobj;
1076 }
1077
1078 EAPI void
1079 _elm_access_object_unregister(Evas_Object *obj, Evas_Object *hoverobj)
1080 {
1081    Elm_Access_Info *ac;
1082
1083    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1084                                        _access_obj_mouse_in_cb, obj);
1085    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
1086                                        _access_obj_mouse_out_cb, obj);
1087    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_DEL,
1088                                        _access_obj_del_cb, obj);
1089
1090    ac = evas_object_data_get(obj, "_elm_access");
1091    evas_object_data_del(obj, "_elm_access");
1092    if (ac)
1093      {
1094         _elm_access_clear(ac);
1095         free(ac);
1096      }
1097
1098    Action_Info *a;
1099    a = evas_object_data_get(obj, "_elm_access_action_info");
1100    if (a) free(a);
1101 }
1102
1103 EAPI void
1104 _elm_access_widget_item_register(Elm_Widget_Item *item)
1105 {
1106    Evas_Object *ao, *ho;
1107    Evas_Coord x, y, w, h;
1108    Elm_Access_Info *ac;
1109
1110    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1111
1112    /* check previous access object */
1113    if (item->access_obj)
1114      _elm_access_widget_item_unregister(item);
1115
1116    // create access object
1117    ho = item->view;
1118    ao = _elm_access_add(item->widget);
1119    if (!ao) return;
1120
1121    evas_object_event_callback_add(ho, EVAS_CALLBACK_RESIZE,
1122                                   _content_resize, ao);
1123    evas_object_event_callback_add(ho, EVAS_CALLBACK_MOVE,
1124                                   _content_move, ao);
1125
1126    evas_object_geometry_get(ho, &x, &y, &w, &h);
1127    evas_object_move(ao, x, y);
1128    evas_object_resize(ao, w, h);
1129    evas_object_show(ao);
1130
1131    // register access object
1132    _elm_access_object_register(ao, ho);
1133
1134    item->access_obj = ao;
1135
1136    /* set owner widget item */
1137    ac = evas_object_data_get(ao, "_elm_access");
1138    ac->widget_item = item;
1139 }
1140
1141 EAPI void
1142 _elm_access_widget_item_unregister(Elm_Widget_Item *item)
1143 {
1144    Evas_Object *ho;
1145
1146    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1147
1148    if (!item->access_obj) return;
1149
1150    ho = item->view;
1151    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_RESIZE,
1152                                   _content_resize, item->access_obj);
1153    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_MOVE,
1154                                   _content_move, item->access_obj);
1155
1156    _elm_access_object_unregister(item->access_obj, ho);
1157
1158    evas_object_del(item->access_obj);
1159    item->access_obj = NULL;
1160 }
1161
1162 EAPI Eina_Bool
1163 _elm_access_2nd_click_timeout(Evas_Object *obj)
1164 {
1165    Ecore_Timer *t;
1166
1167    t = evas_object_data_get(obj, "_elm_2nd_timeout");
1168    if (t)
1169      {
1170         ecore_timer_del(t);
1171         evas_object_data_del(obj, "_elm_2nd_timeout");
1172         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
1173                                             _access_2nd_click_del_cb, NULL);
1174         return EINA_TRUE;
1175      }
1176    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
1177    evas_object_data_set(obj, "_elm_2nd_timeout", t);
1178    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1179                                   _access_2nd_click_del_cb, NULL);
1180    return EINA_FALSE;
1181 }
1182
1183 static Evas_Object *
1184 _elm_access_add(Evas_Object *parent)
1185 {
1186    Evas_Object *obj;
1187
1188    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1189
1190    obj = elm_widget_add(_elm_access_smart_class_new(), parent);
1191    if (!obj) return NULL;
1192
1193    if (!elm_widget_sub_object_add(parent, obj))
1194      ERR("could not add %p as sub object of %p", obj, parent);
1195
1196    return obj;
1197 }
1198
1199 EAPI Evas_Object *
1200 elm_access_object_register(Evas_Object *obj, Evas_Object *parent)
1201 {
1202    return _access_object_register(obj, parent);
1203 }
1204
1205 EAPI void
1206 elm_access_object_unregister(Evas_Object *obj)
1207 {
1208    _access_object_unregister(obj);
1209 }
1210
1211 EAPI Evas_Object *
1212 elm_access_object_get(const Evas_Object *obj)
1213 {
1214    return evas_object_data_get(obj, "_part_access_obj");
1215 }
1216
1217 EAPI void
1218 elm_access_info_set(Evas_Object *obj, int type, const char *text)
1219 {
1220    _elm_access_text_set(_elm_access_object_get(obj), type, text);
1221 }
1222
1223 EAPI char *
1224 elm_access_info_get(const Evas_Object *obj, int type)
1225 {
1226    return _elm_access_text_get(_elm_access_object_get(obj), type, obj);
1227 }
1228
1229 EAPI void
1230 elm_access_info_cb_set(Evas_Object *obj, int type,
1231                           Elm_Access_Info_Cb func, const void *data)
1232 {
1233    _elm_access_callback_set(_elm_access_object_get(obj), type, func, data);
1234 }
1235
1236 EAPI void
1237 elm_access_activate_cb_set(Evas_Object *obj,
1238                            Elm_Access_Activate_Cb  func, void *data)
1239 {
1240    Elm_Access_Info *ac;
1241
1242    ac = _elm_access_object_get(obj);
1243    if (!ac) return;
1244
1245    ac->activate = func;
1246    ac->activate_data = data;
1247 }
1248
1249 EAPI void
1250 elm_access_say(const char *text)
1251 {
1252    if (!text) return;
1253
1254    _elm_access_say(text);
1255 }
1256
1257 EAPI void
1258 elm_access_highlight_set(Evas_Object* obj)
1259 {
1260    _elm_access_highlight_set(obj);
1261 }
1262
1263 EAPI Eina_Bool
1264 elm_access_action(Evas_Object *obj, const Elm_Access_Action_Type type, void *action_info)
1265 {
1266    Evas *evas;
1267    Evas_Object *ho;
1268    Elm_Access_Action_Info *a;
1269
1270    a = (Elm_Access_Action_Info *) action_info;
1271
1272    switch (type)
1273      {
1274       case ELM_ACCESS_ACTION_READ:
1275       case ELM_ACCESS_ACTION_HIGHLIGHT:
1276         evas = evas_object_evas_get(obj);
1277         if (!evas) return EINA_FALSE;
1278
1279         _elm_access_mouse_event_enabled_set(EINA_TRUE);
1280
1281         evas_event_feed_mouse_in(evas, 0, NULL);
1282         evas_event_feed_mouse_move(evas, a->x, a->y, 0, NULL);
1283         _elm_access_mouse_event_enabled_set(EINA_FALSE);
1284
1285         ho = _access_highlight_object_get(obj);
1286         if (ho)
1287           _access_action_callback_call(ho, ELM_ACCESS_ACTION_READ, a);
1288         break;
1289
1290       case ELM_ACCESS_ACTION_UNHIGHLIGHT:
1291         break;
1292
1293       case ELM_ACCESS_ACTION_HIGHLIGHT_NEXT:
1294         if (a->highlight_cycle)
1295           _elm_access_highlight_cycle(obj, ELM_FOCUS_NEXT);
1296         else
1297           return _access_highlight_next_get(obj, ELM_FOCUS_NEXT);
1298         break;
1299
1300       case ELM_ACCESS_ACTION_HIGHLIGHT_PREV:
1301         if (a->highlight_cycle)
1302           _elm_access_highlight_cycle(obj, ELM_FOCUS_PREVIOUS);
1303         else
1304           return _access_highlight_next_get(obj, ELM_FOCUS_PREVIOUS);
1305         break;
1306
1307       case ELM_ACCESS_ACTION_ACTIVATE:
1308         _elm_access_highlight_object_activate(obj, ELM_ACTIVATE_DEFAULT);
1309         break;
1310
1311       case ELM_ACCESS_ACTION_VALUE_CHANGE:
1312         _elm_access_highlight_object_activate(obj, ELM_ACTIVATE_UP);
1313         break;
1314
1315       case ELM_ACCESS_ACTION_SCROLL:
1316         break;
1317
1318       case ELM_ACCESS_ACTION_BACK:
1319         break;
1320
1321       default:
1322         break;
1323      }
1324
1325    return EINA_TRUE;
1326 }
1327
1328 EAPI void
1329 elm_access_action_cb_set(Evas_Object *obj, const Elm_Access_Action_Type type, const Elm_Access_Action_Cb cb, const void *data)
1330 {
1331    Action_Info *a;
1332    a =  evas_object_data_get(obj, "_elm_access_action_info");
1333
1334    if (!a)
1335      {
1336         a = calloc(1, sizeof(Action_Info));
1337         evas_object_data_set(obj, "_elm_access_action_info", a);
1338      }
1339
1340    a->obj = obj;
1341    a->fn[type].cb = cb;
1342    a->fn[type].user_data = (void *)data;
1343 }
1344
1345 EAPI void
1346 elm_access_external_info_set(Evas_Object *obj, const char *text)
1347 {
1348    _elm_access_text_set
1349      (_elm_access_object_get(obj), ELM_ACCESS_CONTEXT_INFO, text);
1350 }
1351
1352 EAPI char *
1353 elm_access_external_info_get(const Evas_Object *obj)
1354 {
1355    Elm_Access_Info *ac;
1356
1357    ac = _elm_access_object_get(obj);
1358    return _elm_access_text_get(ac, ELM_ACCESS_CONTEXT_INFO, obj);
1359 }