[access] read at once - Tizen TTS engine performance issue
[framework/uifw/elementary.git] / src / lib / elm_access.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char ACCESS_SMART_NAME[] = "elm_access";
5
6 ELM_INTERNAL_SMART_SUBCLASS_NEW
7   (ACCESS_SMART_NAME, _elm_access, Elm_Widget_Smart_Class,
8   Elm_Widget_Smart_Class, elm_widget_smart_class_get, NULL);
9
10 static Eina_Bool mouse_event_enable = EINA_TRUE;
11 static Eina_Bool read_mode = EINA_FALSE;
12
13 static Evas_Object * _elm_access_add(Evas_Object *parent);
14
15 static void
16 _elm_access_smart_add(Evas_Object *obj)
17 {
18    EVAS_SMART_DATA_ALLOC(obj, Elm_Widget_Smart_Data);
19    ELM_WIDGET_CLASS(_elm_access_parent_sc)->base.add(obj);
20
21    elm_widget_can_focus_set(obj, EINA_TRUE);
22 }
23
24 static Eina_Bool
25 _elm_access_smart_on_focus(Evas_Object *obj)
26 {
27    evas_object_focus_set(obj, elm_widget_focus_get(obj));
28
29    return EINA_TRUE;
30 }
31
32 static Eina_Bool
33 _elm_access_smart_activate(Evas_Object *obj, Elm_Activate act)
34 {
35    if (act != ELM_ACTIVATE_DEFAULT) return EINA_FALSE;
36
37    Elm_Access_Info *ac = evas_object_data_get(obj, "_elm_access");
38    if (!ac) return EINA_FALSE;
39
40    if (ac->activate)
41      ac->activate(ac->activate_data, ac->part_object,
42                   (Elm_Object_Item *)ac->widget_item);
43
44    return EINA_TRUE;
45 }
46
47 static void
48 _elm_access_smart_set_user(Elm_Widget_Smart_Class *sc)
49 {
50    sc->base.add = _elm_access_smart_add;
51
52    /* not a 'focus chain manager' */
53    sc->focus_next = NULL;
54    sc->focus_direction = NULL;
55    sc->on_focus = _elm_access_smart_on_focus;
56    sc->activate = _elm_access_smart_activate;
57
58    return;
59 }
60
61 typedef struct _Mod_Api Mod_Api;
62
63 struct _Mod_Api
64 {
65    void (*out_read) (const char *txt);
66    void (*out_read_done) (void);
67    void (*out_cancel) (void);
68    void (*out_done_callback_set) (void (*func) (void *data), const void *data);
69 };
70
71 static int initted = 0;
72 static Mod_Api *mapi = NULL;
73
74 static void
75 _access_init(void)
76 {
77    Elm_Module *m;
78    initted++;
79    if (initted > 1) return;
80    if (!(m = _elm_module_find_as("access/api"))) return;
81    m->api = malloc(sizeof(Mod_Api));
82    if (!m->api) return;
83    m->init_func(m);
84    ((Mod_Api *)(m->api)      )->out_read = // called to read out some text
85       _elm_module_symbol_get(m, "out_read");
86    ((Mod_Api *)(m->api)      )->out_read_done = // called to set a done marker so when it is reached the done callback is called
87       _elm_module_symbol_get(m, "out_read_done");
88    ((Mod_Api *)(m->api)      )->out_cancel = // called to read out some text
89       _elm_module_symbol_get(m, "out_cancel");
90    ((Mod_Api *)(m->api)      )->out_done_callback_set = // called when last read done
91       _elm_module_symbol_get(m, "out_done_callback_set");
92    mapi = m->api;
93 }
94
95 static void
96 _access_shutdown(void)
97 {
98    Elm_Module *m;
99    if (initted == 0) return;
100    if (!(m = _elm_module_find_as("access/api"))) return;
101
102    m->shutdown_func(m);
103
104    initted = 0;
105
106    free(mapi);
107    mapi = NULL;
108 }
109
110 static Elm_Access_Item *
111 _access_add_set(Elm_Access_Info *ac, int type)
112 {
113    Elm_Access_Item *ai;
114    Eina_List *l;
115
116    if (!ac) return NULL;
117    EINA_LIST_FOREACH(ac->items, l, ai)
118      {
119         if (ai->type == type)
120           {
121              if (!ai->func)
122                {
123                   if (ai->data) eina_stringshare_del(ai->data);
124                }
125              ai->func = NULL;
126              ai->data = NULL;
127              return ai;
128           }
129      }
130    ai = calloc(1, sizeof(Elm_Access_Item));
131    ai->type = type;
132    ac->items = eina_list_prepend(ac->items, ai);
133    return ai;
134 }
135
136 static Evas_Object *
137 _access_highlight_object_get(Evas_Object *obj)
138 {
139    Evas_Object *o, *ho;
140
141    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
142    if (!o) return NULL;
143
144    ho = evas_object_data_get(o, "_elm_access_target");
145
146    return ho;
147 }
148
149 static void
150 _access_highlight_read(Elm_Access_Info *ac, Evas_Object *obj)
151 {
152    int type;
153    char *txt = NULL;
154    Eina_Strbuf *strbuf;
155
156    /*FIXME: TIZEN only - read at once because Tizen TTS engine performance is not good */
157    strbuf = eina_strbuf_new();
158
159    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
160      {
161
162         if (ac->on_highlight) ac->on_highlight(ac->on_highlight_data);
163         _elm_access_object_hilight(obj);
164
165         for (type = ELM_ACCESS_INFO_FIRST + 1; type < ELM_ACCESS_INFO_LAST; type++)
166           {
167              txt = _elm_access_text_get(ac, type, obj);
168              if (txt && (strlen(txt) > 0))
169                {
170                   if (eina_strbuf_length_get(strbuf) > 0)
171                     eina_strbuf_append_printf(strbuf, ", %s", txt);
172                   else
173                     eina_strbuf_append(strbuf, txt);
174
175                   free(txt);
176                }
177           }
178      }
179
180    txt = eina_strbuf_string_steal(strbuf);
181    eina_strbuf_free(strbuf);
182
183    _elm_access_say(txt);
184    free(txt);
185 }
186
187 static Eina_Bool
188 _access_obj_over_timeout_cb(void *data)
189 {
190    Elm_Access_Info *ac;
191    Evas_Object *ho;
192
193    if (!data) return EINA_FALSE;
194
195    ac = evas_object_data_get(data, "_elm_access");
196    if (!ac) return EINA_FALSE;
197
198    ho = _access_highlight_object_get(data);
199    if (ho != data) _access_highlight_read(ac, data);
200
201    ac->delay_timer = NULL;
202    return EINA_FALSE;
203 }
204
205 static void
206 _access_obj_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
207 {
208    Elm_Access_Info *ac;
209    if (!mouse_event_enable) return;
210
211    ac = evas_object_data_get(data, "_elm_access");
212    if (!ac) return;
213
214    if (ac->delay_timer)
215      {
216         ecore_timer_del(ac->delay_timer);
217         ac->delay_timer = NULL;
218      }
219    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
220       ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
221 }
222
223 static void
224 _access_obj_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
225 {
226    Elm_Access_Info *ac;
227    if (!mouse_event_enable) return;
228
229    ac = evas_object_data_get(data, "_elm_access");
230    if (!ac) return;
231
232    _elm_access_object_unhilight(data);
233    if (ac->delay_timer)
234      {
235         ecore_timer_del(ac->delay_timer);
236         ac->delay_timer = NULL;
237      }
238 }
239
240 static void
241 _access_obj_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
242 {
243    _elm_access_object_unregister(data, obj);
244
245    // _elm_access_edje_object_part_object_register(); set below object data
246    evas_object_data_del(obj, "_part_access_obj");
247 }
248
249 static void
250 _access_read_done(void *data __UNUSED__)
251 {
252    printf("read done\n");
253    // FIXME: produce event here
254 }
255
256 static void
257 _access_2nd_click_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
258 {
259    Ecore_Timer *t;
260
261    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
262                                        _access_2nd_click_del_cb, NULL);
263    t = evas_object_data_get(obj, "_elm_2nd_timeout");
264    if (t)
265      {
266         ecore_timer_del(t);
267         evas_object_data_del(obj, "_elm_2nd_timeout");
268      }
269 }
270
271 static Eina_Bool
272 _access_2nd_click_timeout_cb(void *data)
273 {
274    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
275                                        _access_2nd_click_del_cb, NULL);
276    evas_object_data_del(data, "_elm_2nd_timeout");
277    return EINA_FALSE;
278 }
279
280 static void
281 _access_obj_hilight_del_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
282 {
283    _elm_access_object_hilight_disable(e);
284 }
285
286 static void
287 _access_obj_hilight_hide_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
288 {
289    _elm_access_object_hilight_disable(e);
290 }
291
292 static void
293 _access_obj_hilight_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
294 {
295    Evas_Coord x, y;
296    Evas_Object *o;
297
298    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
299    if (!o) return;
300    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
301    evas_object_move(o, x, y);
302 }
303
304 static void
305 _access_obj_hilight_resize_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
306 {
307    Evas_Coord w, h;
308    Evas_Object *o;
309
310    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
311    if (!o) return;
312    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
313    evas_object_resize(o, w, h);
314 }
315
316 void
317 _elm_access_mouse_event_enabled_set(Eina_Bool enabled)
318 {
319    enabled = !!enabled;
320    if (mouse_event_enable == enabled) return;
321    mouse_event_enable = enabled;
322 }
323
324 void
325 _elm_access_read_mode_set(Eina_Bool enabled)
326 {
327    enabled = !!enabled;
328    if (read_mode == enabled) return;
329    read_mode = enabled;
330 }
331
332 Eina_Bool
333 _elm_access_read_mode_get()
334 {
335    return read_mode;
336 }
337
338 void
339 _elm_access_shutdown()
340 {
341    _access_shutdown();
342 }
343
344 static void
345 _access_order_del_cb(void *data,
346                      Evas *e __UNUSED__,
347                      Evas_Object *obj,
348                      void *event_info __UNUSED__)
349 {
350    Elm_Widget_Item *item = data;
351
352    item->access_order = eina_list_remove(item->access_order, obj);
353 }
354
355 void
356 _elm_access_widget_item_access_order_set(Elm_Widget_Item *item,
357                                               Eina_List *objs)
358 {
359    Eina_List *l;
360    Evas_Object *o;
361
362    if (!item) return;
363
364    _elm_access_widget_item_access_order_unset(item);
365
366    EINA_LIST_FOREACH(objs, l, o)
367      {
368         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
369                                        _access_order_del_cb, item);
370      }
371
372    item->access_order = objs;
373 }
374
375 const Eina_List *
376 _elm_access_widget_item_access_order_get(const Elm_Widget_Item *item)
377 {
378    if (!item) return NULL;
379    return item->access_order;
380 }
381
382 void
383 _elm_access_widget_item_access_order_unset(Elm_Widget_Item *item)
384 {
385    Eina_List *l, *l_next;
386    Evas_Object *o;
387
388    if (!item) return;
389
390    EINA_LIST_FOREACH_SAFE(item->access_order, l, l_next, o)
391      {
392         evas_object_event_callback_del_full
393           (o, EVAS_CALLBACK_DEL, _access_order_del_cb, item);
394         item->access_order = eina_list_remove_list(item->access_order, l);
395      }
396 }
397 //-------------------------------------------------------------------------//
398 EAPI void
399 _elm_access_highlight_set(Evas_Object* obj)
400 {
401    Elm_Access_Info *ac;
402    Evas_Object *ho;
403
404    if (!obj) return;
405
406    ho = _access_highlight_object_get(obj);
407    if (ho == obj) return;
408
409    ac = evas_object_data_get(obj, "_elm_access");
410    if (!ac) return;
411
412    _access_highlight_read(ac, obj);
413 }
414
415 EAPI void
416 _elm_access_clear(Elm_Access_Info *ac)
417 {
418    Elm_Access_Item *ai;
419
420    if (!ac) return;
421    if (ac->delay_timer)
422      {
423         ecore_timer_del(ac->delay_timer);
424         ac->delay_timer = NULL;
425      }
426    EINA_LIST_FREE(ac->items, ai)
427      {
428         if (!ai->func)
429           {
430              if (ai->data) eina_stringshare_del(ai->data);
431           }
432         free(ai);
433      }
434 }
435
436 EAPI void
437 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
438 {
439    Elm_Access_Item *ai = _access_add_set(ac, type);
440    if (!ai) return;
441    ai->data = eina_stringshare_add(text);
442 }
443
444 EAPI void
445 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Info_Cb func, const void *data)
446 {
447    Elm_Access_Item *ai = _access_add_set(ac, type);
448    if (!ai) return;
449    ai->func = func;
450    ai->data = data;
451 }
452
453 EAPI void
454 _elm_access_on_highlight_hook_set(Elm_Access_Info           *ac,
455                                   Elm_Access_On_Highlight_Cb func,
456                                   void                      *data)
457 {
458     if (!ac) return;
459     ac->on_highlight = func;
460     ac->on_highlight_data = data;
461 }
462
463 EAPI void
464 _elm_access_activate_callback_set(Elm_Access_Info           *ac,
465                                   Elm_Access_Activate_Cb     func,
466                                   void                      *data)
467 {
468    if (!ac) return;
469    ac->activate = func;
470    ac->activate_data = data;
471 }
472
473 EAPI void
474 _elm_access_highlight_object_activate(Evas_Object *obj, Elm_Activate act)
475 {
476    Evas_Object *highlight;
477
478    highlight = _access_highlight_object_get(obj);
479    if (!highlight) return;
480
481    _elm_access_read_mode_set(EINA_FALSE);
482
483    if (!elm_object_focus_get(highlight))
484      elm_object_focus_set(highlight, EINA_TRUE);
485
486    elm_widget_activate(highlight, act);
487    return;
488 }
489
490 EAPI void
491 _elm_access_highlight_cycle(Evas_Object *obj, Elm_Focus_Direction dir)
492 {
493    Evas_Object *ho;
494    ho = _access_highlight_object_get(obj);
495    if (!ho) return;
496
497    /* find highlight root */
498    do
499      {
500         ELM_WIDGET_DATA_GET(ho, sd);
501         if (sd->highlight_root)
502           {
503              /* change highlight root */
504              obj = ho;
505              break;
506           }
507         ho = elm_widget_parent_get(ho);
508      }
509    while (ho);
510
511    _elm_access_read_mode_set(EINA_TRUE);
512    elm_widget_focus_cycle(obj, dir);
513    _elm_access_read_mode_set(EINA_FALSE);
514 }
515
516 EAPI char *
517 _elm_access_text_get(const Elm_Access_Info *ac, int type, const Evas_Object *obj)
518 {
519    Elm_Access_Item *ai;
520    Eina_List *l;
521
522    if (!ac) return NULL;
523    EINA_LIST_FOREACH(ac->items, l, ai)
524      {
525         if (ai->type == type)
526           {
527              if (ai->func) return ai->func((void *)(ai->data), (Evas_Object *)obj);
528              else if (ai->data) return strdup(ai->data);
529              return NULL;
530           }
531      }
532    return NULL;
533 }
534
535 EAPI void
536 _elm_access_read(Elm_Access_Info *ac, int type, const Evas_Object *obj)
537 {
538    char *txt = _elm_access_text_get(ac, type, obj);
539
540    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
541
542    _access_init();
543    if (mapi)
544      {
545         if (mapi->out_done_callback_set)
546            mapi->out_done_callback_set(_access_read_done, NULL);
547         if (type == ELM_ACCESS_DONE)
548           {
549              if (mapi->out_read_done) mapi->out_read_done();
550           }
551         else if (type == ELM_ACCESS_CANCEL)
552           {
553              if (mapi->out_cancel) mapi->out_cancel();
554           }
555         else
556           {
557              if (txt && mapi->out_read) mapi->out_read(txt);
558           }
559      }
560    if (txt) free(txt);
561 }
562
563 EAPI void
564 _elm_access_say(const char *txt)
565 {
566    if (!_elm_config->access_mode) return;
567
568    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
569
570    _access_init();
571    if (mapi)
572      {
573         if (mapi->out_done_callback_set)
574            mapi->out_done_callback_set(_access_read_done, NULL);
575         if (mapi->out_cancel) mapi->out_cancel();
576         if (txt)
577           {
578              if (mapi->out_read) mapi->out_read(txt);
579              //if (mapi->out_read) mapi->out_read(".\n"); /* TIZEN only: Tizen TTS engine performance is not good */
580           }
581         if (mapi->out_read_done) mapi->out_read_done();
582      }
583 }
584
585 EAPI Elm_Access_Info *
586 _elm_access_object_get(const Evas_Object *obj)
587 {
588    return evas_object_data_get(obj, "_elm_access");
589 }
590
591 EAPI void
592 _elm_access_object_hilight(Evas_Object *obj)
593 {
594    Evas_Object *o;
595    Evas_Coord x, y, w, h;
596
597    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
598    if (!o)
599      {
600         o = edje_object_add(evas_object_evas_get(obj));
601         evas_object_name_set(o, "_elm_access_disp");
602         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
603      }
604    else
605      {
606         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
607         if (ptarget)
608           {
609              evas_object_data_del(o, "_elm_access_target");
610              elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
611
612              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
613                                                  _access_obj_hilight_del_cb, NULL);
614              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
615                                                  _access_obj_hilight_hide_cb, NULL);
616              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
617                                                  _access_obj_hilight_move_cb, NULL);
618              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
619                                                  _access_obj_hilight_resize_cb, NULL);
620           }
621      }
622    evas_object_data_set(o, "_elm_access_target", obj);
623    elm_widget_parent_highlight_set(obj, EINA_TRUE);
624
625    elm_widget_theme_object_set(obj, o, "access", "base", "default");
626
627    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
628                                   _access_obj_hilight_del_cb, NULL);
629    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
630                                   _access_obj_hilight_hide_cb, NULL);
631    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
632                                   _access_obj_hilight_move_cb, NULL);
633    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
634                                   _access_obj_hilight_resize_cb, NULL);
635    evas_object_raise(o);
636    evas_object_geometry_get(obj, &x, &y, &w, &h);
637    evas_object_move(o, x, y);
638    evas_object_resize(o, w, h);
639    evas_object_show(o);
640 }
641
642 EAPI void
643 _elm_access_object_unhilight(Evas_Object *obj)
644 {
645    Evas_Object *o, *ptarget;
646
647    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
648    if (!o) return;
649    ptarget = evas_object_data_get(o, "_elm_access_target");
650    if (ptarget == obj)
651      {
652         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
653                                             _access_obj_hilight_del_cb, NULL);
654         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
655                                             _access_obj_hilight_hide_cb, NULL);
656         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
657                                             _access_obj_hilight_move_cb, NULL);
658         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
659                                             _access_obj_hilight_resize_cb, NULL);
660         evas_object_del(o);
661         elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
662      }
663 }
664
665 static void
666 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
667                 void *event_info __UNUSED__)
668 {
669    Evas_Object *accessobj;
670    Evas_Coord w, h;
671
672    accessobj = data;
673    if (!accessobj) return;
674
675    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
676    evas_object_resize(accessobj, w, h);
677 }
678
679 static void
680 _content_move(void *data, Evas *e __UNUSED__, Evas_Object *obj,
681               void *event_info __UNUSED__)
682 {
683    Evas_Object *accessobj;
684    Evas_Coord x, y;
685
686    accessobj = data;
687    if (!accessobj) return;
688
689    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
690    evas_object_move(accessobj, x, y);
691 }
692
693 static Evas_Object *
694 _access_object_register(Evas_Object *obj, Evas_Object *parent)
695 {
696    Evas_Object *ao;
697    Elm_Access_Info *ac;
698    Evas_Coord x, y, w, h;
699
700    if (!obj) return NULL;
701
702    /* create access object */
703    ao = _elm_access_add(parent);
704    if (!ao) return NULL;
705
706    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
707                                   _content_resize, ao);
708    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
709                                   _content_move, ao);
710
711    evas_object_geometry_get(obj, &x, &y, &w, &h);
712    evas_object_move(ao, x, y);
713    evas_object_resize(ao, w, h);
714    evas_object_show(ao);
715
716    /* register access object */
717    _elm_access_object_register(ao, obj);
718
719    /* set access object */
720    evas_object_data_set(obj, "_part_access_obj", ao);
721
722    /* set owner part object */
723    ac = evas_object_data_get(ao, "_elm_access");
724    ac->part_object = obj;
725
726    return ao;
727 }
728
729 static void
730 _access_object_unregister(Evas_Object *obj)
731 {
732    Elm_Access_Info *ac;
733    Evas_Object *ao;
734
735    if (!obj) return;
736
737    ao = evas_object_data_get(obj, "_part_access_obj");
738
739    if (ao)
740      {
741         evas_object_data_del(obj, "_part_access_obj");
742
743         /* delete callbacks */
744         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE,
745                                             _content_resize, ao);
746         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
747                                             _content_move, ao);
748
749         /* unregister access object */
750         _elm_access_object_unregister(ao, obj);
751
752         evas_object_del(ao);
753      }
754    else
755      {
756         /* button, check, label etc. */
757         ac = evas_object_data_get(obj, "_elm_access");
758         if (ac && ac->hoverobj)
759           _elm_access_object_unregister(obj, ac->hoverobj);
760      }
761 }
762
763 EAPI Evas_Object *
764 _elm_access_edje_object_part_object_register(Evas_Object* obj,
765                                              const Evas_Object *eobj,
766                                              const char* part)
767 {
768    Evas_Object *ao, *po;
769
770    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
771    if (!obj || !po) return NULL;
772
773    /* check previous access object */
774    ao = evas_object_data_get(po, "_part_access_obj");
775    if (ao)
776      _elm_access_edje_object_part_object_unregister(obj, eobj, part);
777
778    ao = _access_object_register(po, obj);
779
780    return ao;
781 }
782
783 //FIXME: unused obj should be removed from here and each widget.
784 EAPI void
785 _elm_access_edje_object_part_object_unregister(Evas_Object* obj __UNUSED__,
786                                                const Evas_Object *eobj,
787                                                const char* part)
788 {
789    Evas_Object *po;
790
791    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
792    if (!po) return;
793
794    _access_object_unregister(po);
795 }
796
797 EAPI void
798 _elm_access_object_hilight_disable(Evas *e)
799 {
800    Evas_Object *o, *ptarget;
801
802    o = evas_object_name_find(e, "_elm_access_disp");
803    if (!o) return;
804    ptarget = evas_object_data_get(o, "_elm_access_target");
805    if (ptarget)
806      {
807         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
808                                             _access_obj_hilight_del_cb, NULL);
809         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
810                                             _access_obj_hilight_hide_cb, NULL);
811         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
812                                             _access_obj_hilight_move_cb, NULL);
813         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
814                                             _access_obj_hilight_resize_cb, NULL);
815      }
816    evas_object_del(o);
817    elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
818 }
819
820 EAPI void
821 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
822 {
823    Elm_Access_Info *ac;
824
825    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
826                                   _access_obj_mouse_in_cb, obj);
827    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
828                                   _access_obj_mouse_out_cb, obj);
829    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
830                                   _access_obj_del_cb, obj);
831    ac = calloc(1, sizeof(Elm_Access_Info));
832    evas_object_data_set(obj, "_elm_access", ac);
833
834    ac->hoverobj = hoverobj;
835 }
836
837 EAPI void
838 _elm_access_object_unregister(Evas_Object *obj, Evas_Object *hoverobj)
839 {
840    Elm_Access_Info *ac;
841
842    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_IN,
843                                        _access_obj_mouse_in_cb, obj);
844    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
845                                        _access_obj_mouse_out_cb, obj);
846    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_DEL,
847                                        _access_obj_del_cb, obj);
848
849    ac = evas_object_data_get(obj, "_elm_access");
850    evas_object_data_del(obj, "_elm_access");
851    if (ac)
852      {
853         _elm_access_clear(ac);
854         free(ac);
855      }
856 }
857
858 EAPI void
859 _elm_access_widget_item_register(Elm_Widget_Item *item)
860 {
861    Evas_Object *ao, *ho;
862    Evas_Coord x, y, w, h;
863    Elm_Access_Info *ac;
864
865    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
866
867    /* check previous access object */
868    if (item->access_obj)
869      _elm_access_widget_item_unregister(item);
870
871    // create access object
872    ho = item->view;
873    ao = _elm_access_add(item->widget);
874    if (!ao) return;
875
876    evas_object_event_callback_add(ho, EVAS_CALLBACK_RESIZE,
877                                   _content_resize, ao);
878    evas_object_event_callback_add(ho, EVAS_CALLBACK_MOVE,
879                                   _content_move, ao);
880
881    evas_object_geometry_get(ho, &x, &y, &w, &h);
882    evas_object_move(ao, x, y);
883    evas_object_resize(ao, w, h);
884    evas_object_show(ao);
885
886    // register access object
887    _elm_access_object_register(ao, ho);
888
889    item->access_obj = ao;
890
891    /* set owner widget item */
892    ac = evas_object_data_get(ao, "_elm_access");
893    ac->widget_item = item;
894 }
895
896 EAPI void
897 _elm_access_widget_item_unregister(Elm_Widget_Item *item)
898 {
899    Evas_Object *ho;
900
901    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
902
903    if (!item->access_obj) return;
904
905    ho = item->view;
906    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_RESIZE,
907                                   _content_resize, item->access_obj);
908    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_MOVE,
909                                   _content_move, item->access_obj);
910
911    _elm_access_object_unregister(item->access_obj, ho);
912
913    evas_object_del(item->access_obj);
914    item->access_obj = NULL;
915 }
916
917 EAPI Eina_Bool
918 _elm_access_2nd_click_timeout(Evas_Object *obj)
919 {
920    Ecore_Timer *t;
921
922    t = evas_object_data_get(obj, "_elm_2nd_timeout");
923    if (t)
924      {
925         ecore_timer_del(t);
926         evas_object_data_del(obj, "_elm_2nd_timeout");
927         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
928                                             _access_2nd_click_del_cb, NULL);
929         return EINA_TRUE;
930      }
931    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
932    evas_object_data_set(obj, "_elm_2nd_timeout", t);
933    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
934                                   _access_2nd_click_del_cb, NULL);
935    return EINA_FALSE;
936 }
937
938 static Evas_Object *
939 _elm_access_add(Evas_Object *parent)
940 {
941    Evas_Object *obj;
942
943    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
944
945    obj = elm_widget_add(_elm_access_smart_class_new(), parent);
946    if (!obj) return NULL;
947
948    if (!elm_widget_sub_object_add(parent, obj))
949      ERR("could not add %p as sub object of %p", obj, parent);
950
951    return obj;
952 }
953
954 EAPI Evas_Object *
955 elm_access_object_register(Evas_Object *obj, Evas_Object *parent)
956 {
957    return _access_object_register(obj, parent);
958 }
959
960 EAPI void
961 elm_access_object_unregister(Evas_Object *obj)
962 {
963    _access_object_unregister(obj);
964 }
965
966 EAPI Evas_Object *
967 elm_access_object_get(const Evas_Object *obj)
968 {
969    return evas_object_data_get(obj, "_part_access_obj");
970 }
971
972 EAPI void
973 elm_access_info_set(Evas_Object *obj, int type, const char *text)
974 {
975    _elm_access_text_set(_elm_access_object_get(obj), type, text);
976 }
977
978 EAPI char *
979 elm_access_info_get(const Evas_Object *obj, int type)
980 {
981    return _elm_access_text_get(_elm_access_object_get(obj), type, obj);
982 }
983
984 EAPI void
985 elm_access_info_cb_set(Evas_Object *obj, int type,
986                           Elm_Access_Info_Cb func, const void *data)
987 {
988    _elm_access_callback_set(_elm_access_object_get(obj), type, func, data);
989 }
990
991 EAPI void
992 elm_access_activate_cb_set(Evas_Object *obj,
993                            Elm_Access_Activate_Cb  func, void *data)
994 {
995    Elm_Access_Info *ac;
996
997    ac = _elm_access_object_get(obj);
998    if (!ac) return;
999
1000    ac->activate = func;
1001    ac->activate_data = data;
1002 }
1003
1004 EAPI void
1005 elm_access_say(const char *text)
1006 {
1007    if (!text) return;
1008
1009    _elm_access_say(text);
1010 }
1011
1012 EAPI void
1013 elm_access_highlight_set(Evas_Object* obj)
1014 {
1015    _elm_access_highlight_set(obj);
1016 }
1017
1018 EAPI void
1019 elm_access_external_info_set(Evas_Object *obj, const char *text)
1020 {
1021    _elm_access_text_set
1022      (_elm_access_object_get(obj), ELM_ACCESS_CONTEXT_INFO, text);
1023 }
1024
1025 EAPI char *
1026 elm_access_external_info_get(const Evas_Object *obj)
1027 {
1028    Elm_Access_Info *ac;
1029
1030    ac = _elm_access_object_get(obj);
1031    return _elm_access_text_get(ac, ELM_ACCESS_CONTEXT_INFO, obj);
1032 }