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