efl_access_object: Support org.a11y.atspi.Value.Text property
[platform/upstream/efl.git] / src / lib / elementary / efl_access_object.c
1 #ifdef HAVE_CONFIG_H
2   #include "elementary_config.h"
3 #endif
4
5 #define EFL_ACCESS_OBJECT_PROTECTED
6
7 #include "elm_priv.h"
8
9 //TIZEN_ONLY(20181211): Fix for missing unregistration of atspi objects
10 void unregister_atspi_object_in_bridge(const Eo *obj);
11 //
12
13 const char* Access_Name[] = {
14     "invalid",
15     "accelerator label",
16     "alert",
17     "animation",
18     "arrow",
19     "calendar",
20     "canvas",
21     "check box",
22     "check menu item",
23     "color chooser",
24     "column header",
25     "combo box",
26     "dateeditor",
27     "desktop icon",
28     "desktop frame",
29     "dial",
30     "dialog",
31     "directory pane",
32     "drawing area",
33     "file chooser",
34     "filler",
35     "focus traversable",
36     "font chooser",
37     "frame",
38     "glass pane",
39     "html container",
40     "icon",
41     "image",
42     "internal frame",
43     "label",
44     "layered pane",
45     "list",
46     "list item",
47     "menu",
48     "menu bar",
49     "menu item",
50     "option pane",
51     "page tab",
52     "page tab list",
53     "panel",
54     "password text",
55     "popup menu",
56     "progress bar",
57     "push button",
58     "radio button",
59     "radio menu item",
60     "root pane",
61     "row header",
62     "scroll bar",
63     "scroll pane",
64     "separator",
65     "slider",
66     "spin button",
67     "split pane",
68     "status bar",
69     "table",
70     "table cell",
71     "table column header",
72     "table row header",
73     "tearoff menu item",
74     "terminal",
75     "text",
76     "toggle button",
77     "tool bar",
78     "tool tip",
79     "tree",
80     "tree table",
81     "unknown",
82     "viewport",
83     "window",
84     "extended",
85     "header",
86     "footer",
87     "paragraph",
88     "ruler",
89     "application",
90     "autocomplete",
91     "editbar",
92     "embedded",
93     "edit field",
94     "chart",
95     "caption",
96     "document frame",
97     "heading",
98     "page",
99     "section",
100     "redundant object",
101     "form",
102     "link",
103     "input method window",
104     "table row",
105     "tree item",
106     "document spreadsheet",
107     "document presentation",
108     "document text",
109     "document web",
110     "document email",
111     "comment",
112     "list box",
113     "grouping",
114     "image map",
115     "notification",
116     "info bar",
117     "last defined"
118 };
119
120 struct _Efl_Access_Event_Handler
121 {
122    Efl_Event_Cb cb;
123    void *data;
124 };
125
126 //TIZEN_ONLY(20190922): add name callback, description callback.
127 struct _Efl_Access_Reading_Info_Cb_Item
128 {
129    Efl_Access_Reading_Info_Cb cb;
130    const void *data;
131 };
132 typedef struct _Efl_Access_Reading_Info_Cb_Item Efl_Access_Reading_Info_Cb_Item;
133 //
134
135 //TIZEN_ONLY(20170405) Add gesture method to accessible interface
136 struct _Efl_Access_Gesture_Cb_Item
137 {
138    Efl_Access_Gesture_Cb cb;
139    const void *data;
140 };
141 typedef struct _Efl_Access_Gesture_Cb_Item Efl_Access_Gesture_Cb_Item;
142
143 struct _Elm_Atspi_Gesture_Cb_Item
144 {
145    Elm_Atspi_Gesture_Cb cb;
146    const void *data;
147 };
148 typedef struct _Elm_Atspi_Gesture_Cb_Item Elm_Atspi_Gesture_Cb_Item;
149 //
150
151 struct _Efl_Access_Object_Data
152 {
153    Efl_Access_Relation_Set relations;
154    //TIZEN_ONLY(20190922): add name callback, description callback.
155    Efl_Access_Reading_Info_Cb_Item name_cb_item;
156    Efl_Access_Reading_Info_Cb_Item description_cb_item;
157    //
158    //TIZEN_ONLY(20230414): Support org.a11y.atspi.Value.Text property.
159    Efl_Access_Reading_Info_Cb_Item value_text_cb_item;
160    //
161    //TIZEN_ONLY(20170405) Add gesture method to accessible interface
162    Efl_Access_Gesture_Cb_Item gesture_cb_item;
163    Elm_Atspi_Gesture_Cb_Item legacy_gesture_cb_item;
164    //
165    Eina_List     *attr_list;
166    const char    *name;
167    const char    *description;
168    //TIZEN_ONLY(20230414): Support org.a11y.atspi.Value.Text property.
169    const char    *value_text;
170    //
171    const char    *translation_domain;
172    Efl_Access_Role role;
173    Efl_Access_Reading_Info_Type_Mask reading_info;
174
175    //TIZEN_ONLY(20181024): Fix parent-children incosistencies in atspi tree
176    Eo *parent;
177    //
178 };
179
180 typedef struct _Efl_Access_Object_Data Efl_Access_Object_Data;
181
182
183 static Eina_List *global_callbacks;
184 static Eo *root;
185
186 EOLIAN static int
187 _efl_access_object_index_in_parent_get(const Eo *obj, Efl_Access_Object_Data *pd EINA_UNUSED)
188 {
189    Eina_List *l, *children = NULL;
190    Eo *chld;
191    int ret = 0;
192
193    //TIZEN_ONLY(20181024): Fix parent-children incosistencies in atspi tree
194    Eo *parent = efl_access_object_access_parent_get(obj);
195    //
196    if (!parent) return -1;
197
198    children = efl_access_object_access_children_get(parent);
199    if (!children) return -1;
200
201    EINA_LIST_FOREACH(children, l, chld)
202      {
203        if (obj == chld)
204          break;
205        ret++;
206      }
207    if (ret == (int)eina_list_count(children))
208      {
209         ERR("Object %s not present in its AT-SPI parents (%s) children list! This should never happen.", efl_class_name_get(efl_class_get(obj)), efl_class_name_get(efl_class_get(parent)));
210         ret = -1;
211      }
212    eina_list_free(children);
213    return ret;
214 }
215
216 //TIZEN_ONLY(20181024): Fix parent-children incosistencies in atspi tree
217 EOLIAN static Eo *
218 _efl_access_object_access_parent_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED)
219 {
220   return pd->parent;
221 }
222
223 EOLIAN static void
224 _efl_access_object_access_parent_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED, Eo *parent)
225 {
226   pd->parent = parent;
227 }
228 //
229
230 EOLIAN Eina_List*
231 _efl_access_object_attributes_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
232 {
233    Eina_List *attr_list = NULL;
234    if (pd->attr_list)
235      {
236         Eina_List *l = NULL;
237         Efl_Access_Attribute *t_attr = NULL;
238         EINA_LIST_FOREACH(pd->attr_list, l, t_attr)
239           {
240              Efl_Access_Attribute *attr = calloc(1, sizeof(Efl_Access_Attribute));
241              if (!attr)
242                return attr_list;
243
244              attr->key = eina_stringshare_add(t_attr->key);
245              attr->value = eina_stringshare_add(t_attr->value);
246              attr_list = eina_list_append(attr_list, attr);
247           }
248      }
249    return attr_list;
250 }
251
252 EOLIAN static void
253 _efl_access_object_attribute_append(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *key, const char *value)
254 {
255    Eina_List *l;
256    Efl_Access_Attribute *attr = NULL;
257
258    if (!key || !value) return;
259
260    /* Check existing attributes has this key */
261    EINA_LIST_FOREACH(pd->attr_list, l, attr)
262      {
263         if (!strcmp((const char *)attr->key, key))
264           {
265              eina_stringshare_replace(&attr->value, value);
266              return;
267           }
268      }
269
270    /* Add new attribute */
271    attr = calloc(1, sizeof(Efl_Access_Attribute));
272    if (!attr) return;
273
274    attr->key = eina_stringshare_add(key);
275    attr->value = eina_stringshare_add(value);
276    pd->attr_list = eina_list_append(pd->attr_list, attr);
277 }
278
279 EOLIAN static void
280 _efl_access_object_attribute_del(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *key)
281 {
282    Eina_List *l;
283    Efl_Access_Attribute *attr = NULL;
284
285    if (!key) return;
286    if (!pd->attr_list) return;
287
288    /* Check whether existing attribute list has this key and delete */
289    EINA_LIST_FOREACH(pd->attr_list, l, attr)
290      {
291         if (!strcmp((const char *)attr->key, key))
292           {
293              pd->attr_list = eina_list_remove_list(pd->attr_list, l);
294              eina_stringshare_del(attr->key);
295              eina_stringshare_del(attr->value);
296              free(attr);
297              return;
298           }
299      }
300 }
301
302 EOLIAN static void _efl_access_object_attributes_clear(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
303 {
304    if (!pd->attr_list) return;
305    Efl_Access_Attribute *attr;
306    EINA_LIST_FREE(pd->attr_list, attr)
307      {
308         eina_stringshare_del(attr->key);
309         eina_stringshare_del(attr->value);
310         free(attr);
311      }
312    pd->attr_list = NULL;
313 }
314
315 EOLIAN static void
316 _efl_access_object_reading_info_type_set(Eo *obj, Efl_Access_Object_Data *pd, Efl_Access_Reading_Info_Type reading_info)
317 {
318    Eina_Strbuf *buf = NULL;
319    if (reading_info == pd->reading_info)
320      return;
321    pd->reading_info = reading_info;
322    if (!pd->reading_info)
323      {
324         efl_access_object_attribute_del(obj, "reading_info_type");
325         return;
326      }
327    buf = eina_strbuf_new();
328    eina_strbuf_reset(buf);
329    if (reading_info & (EFL_ACCESS_READING_INFO_TYPE_NAME))
330      {
331         eina_strbuf_append(buf, "name");
332         eina_strbuf_append_char(buf, '|');
333      }
334    if (reading_info & (EFL_ACCESS_READING_INFO_TYPE_ROLE))
335      {
336         eina_strbuf_append(buf, "role");
337         eina_strbuf_append_char(buf, '|');
338      }
339    if (reading_info & (EFL_ACCESS_READING_INFO_TYPE_DESCRIPTION))
340      {
341         eina_strbuf_append(buf, "description");
342         eina_strbuf_append_char(buf, '|');
343      }
344    if (reading_info & (EFL_ACCESS_READING_INFO_TYPE_STATE))
345      {
346         eina_strbuf_append(buf, "state");
347      }
348    efl_access_object_attribute_append(obj, "reading_info_type", eina_strbuf_string_get(buf));
349    eina_strbuf_free(buf);
350 }
351
352 EOLIAN Efl_Access_Reading_Info_Type_Mask
353 _efl_access_object_reading_info_type_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
354 {
355    return pd->reading_info;
356 }
357
358 EOLIAN static Efl_Access_Role
359 _efl_access_object_role_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
360 {
361    return pd->role;
362 }
363
364 EOLIAN static void
365 //TIZEN_ONLY(20200220): add EINA_UNUSED for unused parameters
366 _efl_access_object_role_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Role role)
367 //_efl_access_object_role_set(Eo *obj, Efl_Access_Object_Data *pd, Efl_Access_Role role)
368 //
369 {
370    if (pd->role != role)
371      {
372         pd->role = role;
373         //TIZEN_ONLY(20160708) Do not send role changed signal - 10000 list items send 10000 IPC.
374         //efl_access_role_changed_signal_emit(obj);
375         //
376      }
377 }
378
379 EOLIAN const char *
380 _efl_access_object_role_name_get(const Eo *obj, Efl_Access_Object_Data *pd EINA_UNUSED)
381 {
382    Efl_Access_Role role;
383
384    role = efl_access_object_role_get(obj);
385
386    return role > EFL_ACCESS_ROLE_LAST_DEFINED ? "" : Access_Name[role];
387 }
388
389 EOLIAN const char *
390 _efl_access_object_i18n_name_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
391 {
392    //TIZEN_ONLY(20190922): add name callback, description callback.
393    char *ret = NULL;
394    if (pd->name_cb_item.cb)
395      ret = pd->name_cb_item.cb((void *)pd->name_cb_item.data, (Eo *)obj);
396    if (ret)
397      {
398         //TIZEN_ONLY(20220826): Remove markup from accessible name
399         char *text;
400
401         text = _elm_util_mkup_to_text(ret);
402         eina_stringshare_replace(&pd->translation_domain, NULL);
403         pd->translation_domain = NULL;
404         eina_stringshare_replace(&pd->name, text);
405         free(text);
406         free(ret);
407         //
408      }
409    //
410 #ifdef ENABLE_NLS
411    if (pd->translation_domain)
412      return dgettext(pd->translation_domain, pd->name);
413 #endif
414    return pd->name;
415 }
416
417 EOLIAN static void
418 _efl_access_object_i18n_name_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *val)
419 {
420    //TIZEN_ONLY(20220826): Remove markup from accessible name
421    char *text;
422
423    text = _elm_util_mkup_to_text(val); // NULL is OK
424    eina_stringshare_replace(&pd->name, text);
425    free(text);
426    //
427 }
428
429 //TIZEN_ONLY(20190922): add name callback, description callback.
430 EOLIAN static void
431 _efl_access_object_name_cb_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Reading_Info_Cb name_cb, const void *data)
432 {
433    pd->name_cb_item.cb = name_cb;
434    pd->name_cb_item.data = data;
435 }
436 //
437
438 const char * _efl_access_object_description_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
439 {
440    //TIZEN_ONLY(20190922): add name callback, description callback.
441    char *ret = NULL;
442    if (pd->description_cb_item.cb)
443      ret = pd->description_cb_item.cb((void *)pd->description_cb_item.data, (Eo *)obj);
444    if (ret)
445      {
446         eina_stringshare_replace(&pd->translation_domain, NULL);
447         pd->translation_domain = NULL;
448         eina_stringshare_replace(&pd->description, ret);
449         free(ret);
450      }
451    //
452 #ifdef ENABLE_NLS
453    if (pd->translation_domain)
454       return dgettext(pd->translation_domain, pd->description);
455 #endif
456    return pd->description;
457 }
458
459 EOLIAN static void
460 _efl_access_object_description_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *val)
461 {
462    eina_stringshare_replace(&pd->description, val);
463 }
464
465 //TIZEN_ONLY(20190922): add name callback, description callback.
466 EOLIAN static void
467 _efl_access_object_description_cb_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Reading_Info_Cb description_cb, const void *data)
468 {
469    pd->description_cb_item.cb = description_cb;
470    pd->description_cb_item.data = data;
471 }
472 //
473
474 //TIZEN_ONLY(20230414): Support org.a11y.atspi.Value.Text property.
475 EOLIAN static const char *
476 _efl_access_object_value_text_get(const Eo *obj, Efl_Access_Object_Data *pd)
477 {
478    char *ret = NULL;
479    if (pd->value_text_cb_item.cb)
480      ret = pd->value_text_cb_item.cb((void *)pd->value_text_cb_item.data, (Eo *)obj);
481    if (ret)
482      {
483         eina_stringshare_replace(&pd->value_text, ret);
484         free(ret);
485      }
486    return pd->value_text;
487 }
488
489 EOLIAN static void
490 _efl_access_object_value_text_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *val)
491 {
492    eina_stringshare_replace(&pd->value_text, val);
493 }
494
495 EOLIAN static void
496 _efl_access_object_value_text_cb_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Reading_Info_Cb value_text_cb, const void *data)
497 {
498    pd->value_text_cb_item.cb = value_text_cb;
499    pd->value_text_cb_item.data = data;
500 }
501 //
502
503 //TIZEN_ONLY(20170405) Add gesture method to accessible interface
504 EOLIAN static void
505 _efl_access_object_gesture_cb_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Gesture_Cb gesture_cb, const void *data)
506 {
507    pd->gesture_cb_item.cb = gesture_cb;
508    pd->gesture_cb_item.data = data;
509 }
510
511 EOLIAN static Eina_Bool
512 _efl_access_object_gesture_do(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, Efl_Access_Gesture_Info gesture_info)
513 {
514    Eina_Bool ret = EINA_FALSE;
515    if (pd->gesture_cb_item.cb)
516      ret = pd->gesture_cb_item.cb((void *)pd->gesture_cb_item.data, gesture_info, obj);
517
518    if (!ret && pd->legacy_gesture_cb_item.cb)
519      {
520         Elm_Atspi_Gesture_Info legacy_gesture_info;
521         legacy_gesture_info.type = (Elm_Atspi_Gesture_Type)gesture_info.type;
522         legacy_gesture_info.x_beg = gesture_info.x_beg;
523         legacy_gesture_info.y_beg = gesture_info.y_beg;
524         legacy_gesture_info.x_end = gesture_info.x_end;
525         legacy_gesture_info.y_end = gesture_info.y_end;
526         legacy_gesture_info.state = (Elm_Atspi_Gesture_State)gesture_info.state;
527         legacy_gesture_info.event_time = gesture_info.event_time;
528         ret = pd->legacy_gesture_cb_item.cb((void *)pd->legacy_gesture_cb_item.data, legacy_gesture_info, obj);
529      }
530
531    return ret;
532 }
533 //
534
535 EOLIAN static const char *
536 _efl_access_object_localized_role_name_get(const Eo *obj, Efl_Access_Object_Data *pd EINA_UNUSED)
537 {
538    const char *ret = NULL;
539    ret = efl_access_object_role_name_get(obj);
540 #ifdef ENABLE_NLS
541    ret = gettext(ret);
542 #endif
543    return ret;
544 }
545
546 EOLIAN static Eina_List *
547 _efl_access_object_access_children_get(const Eo *obj, Efl_Access_Object_Data *pd EINA_UNUSED)
548 {
549    Eina_List *children = NULL;
550    Eina_Iterator *iter = NULL;
551    Eo *chld;
552
553    // By default use Efl_Object object hierarchy
554    /* XXX const */
555    iter = efl_children_iterator_new((Eo *)obj);
556    if (!iter) return NULL;
557
558    EINA_ITERATOR_FOREACH(iter, chld)
559      {
560         if (efl_isa(chld, EFL_ACCESS_OBJECT_MIXIN))
561           {
562             children = eina_list_append(children, chld);
563             //TIZEN_ONLY(20181024): Fix parent-children incosistencies in atspi tree
564             efl_access_object_access_parent_set(chld, (Eo *)obj);
565             //
566           }
567      }
568    eina_iterator_free(iter);
569
570    return children;
571 }
572
573 EOLIAN static Efl_Access_State_Set
574 _efl_access_object_state_set_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED)
575 {
576    return 0;
577 }
578
579 //TIZEN_ONLY(20160726): add API elm_atspi_accessible_can_highlight_set/get
580 EOLIAN static void
581 _efl_access_object_can_highlight_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED, Eina_Bool can_highlight EINA_UNUSED)
582 {
583    WRN("The %s object does not implement the \"can_highlight_set\" function.",
584        efl_class_name_get(efl_class_get(obj)));
585 }
586
587 EOLIAN static Eina_Bool
588 _efl_access_object_can_highlight_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED)
589 {
590    WRN("The %s object does not implement the \"can_highlight_get\" function.",
591        efl_class_name_get(efl_class_get(obj)));
592    return EINA_TRUE;
593 }
594 //
595
596 //TIZEN_ONLY(20230220): Add SetListenPostRender to accessible object
597 EOLIAN static void
598 _efl_access_object_listen_render_post_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED, Eina_Bool enabled EINA_UNUSED)
599 {
600    WRN("The %s object does not implement the \"listen_render_post\" function.",
601        efl_class_name_get(efl_class_get(obj)));
602 }
603 //
604
605 EOLIAN Efl_Access_Relation_Set
606 _efl_access_object_relation_set_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd EINA_UNUSED)
607 {
608    //TIZEN_ONLY(20171115) Fixed the bugs and warnings in atspi relationship APIS
609    //return efl_access_relation_set_clone(pd->relations);
610    WRN("The %s object does not implement the \"accessible_relation_set\" function.",
611        efl_class_name_get(efl_class_get(obj)));
612    return NULL;
613    //
614 }
615
616 EAPI void
617 efl_access_attribute_free(Efl_Access_Attribute *attr)
618 {
619    eina_stringshare_del(attr->key);
620    eina_stringshare_del(attr->value);
621    free(attr);
622 }
623
624 EAPI void efl_access_attributes_list_free(Eina_List *list)
625 {
626    Efl_Access_Attribute *attr;
627    EINA_LIST_FREE(list, attr)
628      {
629         efl_access_attribute_free(attr);
630      }
631 }
632
633 EOLIAN void
634 _efl_access_object_event_emit(Eo *accessible, const Efl_Event_Description *event, void *event_info)
635
636 {
637    Eina_List *l;
638    Efl_Access_Event_Handler *hdl;
639
640    if (!accessible || !event || !efl_isa(accessible, EFL_ACCESS_OBJECT_MIXIN))
641      {
642         CRI("Invalid parameters, event: %s, obj: %s", event ? event->name : "NULL", accessible ? efl_class_name_get(accessible) : "NULL");
643         return;
644      }
645
646    Efl_Event ev;
647    ev.object = accessible;
648    ev.desc = event;
649    ev.info = event_info;
650    EINA_LIST_FOREACH(global_callbacks, l, hdl)
651      {
652         if (hdl->cb)
653           hdl->cb(hdl->data, &ev);
654      }
655 }
656
657 EOLIAN Efl_Access_Event_Handler *
658 _efl_access_object_event_handler_add(Efl_Event_Cb cb, void *data)
659 {
660    Efl_Access_Event_Handler *ret = calloc(1, sizeof(Efl_Access_Event_Handler));
661    if (!ret) return NULL;
662
663    ret->cb = cb;
664    ret->data = data;
665
666    global_callbacks = eina_list_append(global_callbacks, ret);
667
668    return ret;
669 }
670
671 EOLIAN void
672 _efl_access_object_event_handler_del(Efl_Access_Event_Handler *handler)
673 {
674    Eina_List *l, *l2;
675    Efl_Access_Event_Handler *hdl;
676    EINA_LIST_FOREACH_SAFE(global_callbacks, l, l2, hdl)
677      {
678         if (hdl == handler)
679           {
680              global_callbacks = eina_list_remove_list(global_callbacks, l);
681              free(hdl);
682              break;
683           }
684      }
685 }
686
687 EOLIAN void
688 _efl_access_object_translation_domain_set(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd, const char *domain)
689 {
690    eina_stringshare_replace(&pd->translation_domain, domain);
691 }
692
693
694 EOLIAN const char*
695 _efl_access_object_translation_domain_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
696 {
697    return pd->translation_domain;
698 }
699
700 EAPI void
701 efl_access_relation_free(Efl_Access_Relation *relation)
702 {
703    eina_list_free(relation->objects);
704    free(relation);
705 }
706
707 EAPI Efl_Access_Relation *
708 efl_access_relation_clone(const Efl_Access_Relation *relation)
709 {
710    Efl_Access_Relation *ret = calloc(1, sizeof(Efl_Access_Relation));
711    if (!ret) return NULL;
712
713    ret->type = relation->type;
714    ret->objects = eina_list_clone(relation->objects);
715    return ret;
716 }
717
718 static void
719 _on_rel_obj_del(void *data, const Efl_Event *event)
720 {
721    Efl_Access_Relation_Set *set = data;
722    Efl_Access_Relation *rel;
723    Eina_List *l, *l2, *p, *p2;
724    Eo *rel_obj;
725
726    EINA_LIST_FOREACH_SAFE(*set, l, l2, rel)
727      {
728         EINA_LIST_FOREACH_SAFE(rel->objects, p, p2, rel_obj)
729           {
730           if (rel_obj == event->object)
731                rel->objects = eina_list_remove_list(rel->objects, p);
732           }
733         if (!rel->objects)
734           {
735              *set = eina_list_remove_list(*set, l);
736              free(rel);
737           }
738      }
739 }
740
741 EAPI Eina_Bool
742 efl_access_relation_set_relation_append(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj)
743 {
744    Efl_Access_Relation *rel;
745    Eina_List *l, *ll;
746
747    if (!efl_isa(rel_obj, EFL_ACCESS_OBJECT_MIXIN))
748      return EINA_FALSE;
749
750    EINA_LIST_FOREACH(*set, l, rel)
751      {
752         if (rel->type == type)
753           {
754              ll = eina_list_data_find_list(rel->objects, rel_obj);
755              if (!ll)
756                {
757                   rel->objects = eina_list_append(rel->objects, rel_obj);
758                   efl_event_callback_add((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
759                }
760              else
761                {
762                   rel->objects = eina_list_demote_list(rel->objects, ll);
763                }
764              return EINA_TRUE;
765           }
766      }
767
768    rel = calloc(1, sizeof(Efl_Access_Relation));
769    if (!rel) return EINA_FALSE;
770
771    rel->type = type;
772    rel->objects = eina_list_append(rel->objects, rel_obj);
773    *set = eina_list_append(*set, rel);
774
775    efl_event_callback_add((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
776    return EINA_TRUE;
777 }
778
779 EAPI void
780 efl_access_relation_set_relation_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj)
781 {
782    Eina_List *l;
783    Efl_Access_Relation *rel;
784
785    EINA_LIST_FOREACH(*set, l, rel)
786      {
787         if (rel->type == type)
788           {
789              if (eina_list_data_find(rel->objects, rel_obj))
790                {
791                   efl_event_callback_del((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
792                   rel->objects = eina_list_remove(rel->objects, rel_obj);
793                }
794              if (!rel->objects)
795                {
796                   *set = eina_list_remove(*set, rel);
797                   efl_access_relation_free(rel);
798                }
799              return;
800           }
801      }
802 }
803
804 EAPI void
805 efl_access_relation_set_relation_type_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type)
806 {
807    Eina_List *l;
808    Efl_Access_Relation *rel;
809    Eo *obj;
810
811    EINA_LIST_FOREACH(*set, l, rel)
812      {
813         if (rel->type == type)
814           {
815              EINA_LIST_FOREACH(rel->objects, l, obj)
816                 efl_event_callback_del(obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
817              *set = eina_list_remove(*set, rel);
818              efl_access_relation_free(rel);
819              return;
820           }
821      }
822 }
823
824 //TIZEN_ONLY(20171115) Fixed the bugs and warnings in atspi relationship APIS
825 EAPI void
826 efl_access_relation_set_free(Efl_Access_Relation_Set *set)
827 {
828    Efl_Access_Relation *rel;
829    Eina_List *l;
830    Eo *obj;
831
832    EINA_LIST_FREE(*set, rel)
833      {
834         EINA_LIST_FOREACH(rel->objects, l, obj)
835            efl_event_callback_del(obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
836         efl_access_relation_free(rel);
837      }
838 }
839
840 EAPI Efl_Access_Relation_Set
841 efl_access_relation_set_clone(const Efl_Access_Relation_Set *set)
842 {
843    Efl_Access_Relation_Set ret = NULL;
844    Eina_List *l;
845    Efl_Access_Relation *rel;
846
847    EINA_LIST_FOREACH(*set, l, rel)
848      {
849         Efl_Access_Relation *cpy = efl_access_relation_clone(rel);
850         ret = eina_list_append(ret, cpy);
851      }
852
853    return ret;
854 }
855 //
856
857 EOLIAN static Eina_Bool
858 _efl_access_object_relationship_append(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation_obj)
859 {
860    return efl_access_relation_set_relation_append(&sd->relations, type, relation_obj);
861 }
862
863 EOLIAN static void
864 _efl_access_object_relationship_remove(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation_obj)
865 {
866    if (relation_obj)
867      efl_access_relation_set_relation_remove(&sd->relations, type, relation_obj);
868    else
869      efl_access_relation_set_relation_type_remove(&sd->relations, type);
870 }
871
872 EOLIAN static void
873 _efl_access_object_relationships_clear(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd)
874 {
875    //TIZEN_ONLY(20171115) Fixed the bugs and warnings in atspi relationship APIS
876    efl_access_relation_set_free(&sd->relations);
877    //
878    sd->relations = NULL;
879 }
880
881 //TIZEN_ONLY(20161122): add state_notify api
882 /**
883  * Notify accessibility clients about current state of object
884  *
885  * @param mask bitfield with accessibilty field type values that should be
886  * notified.
887  */
888 static void _elm_atspi_accessibility_state_notify(Eo *obj, Efl_Access_State_Set mask)
889 {
890    Efl_Access_State_Set ss;
891    Efl_Access_State_Type type;
892
893    ss = efl_access_object_state_set_get(obj);
894
895    for (type = EFL_ACCESS_STATE_TYPE_INVALID;
896         type < EFL_ACCESS_STATE_TYPE_LAST_DEFINED;
897         type++)
898      {
899         if (STATE_TYPE_GET(mask, type))
900           {
901              efl_access_state_changed_signal_emit(
902                 obj, type, STATE_TYPE_GET(ss, type) ? EINA_TRUE : EINA_FALSE);
903           }
904      }
905 }
906
907 EOLIAN void
908 _efl_access_object_state_notify(Eo *obj, Efl_Access_Object_Data *data EINA_UNUSED, Efl_Access_State_Set mask, Eina_Bool recursive)
909 {
910    _elm_atspi_accessibility_state_notify(obj, mask);
911
912    if (recursive)
913      {
914         Efl_Access_Object *child;
915         Eina_List *children;
916         children = efl_access_object_access_children_get(obj);
917         EINA_LIST_FREE(children, child)
918           {
919              efl_access_object_state_notify(child, mask, recursive);
920           }
921      }
922 }
923 //
924
925 EOLIAN Eo*
926 _efl_access_object_access_root_get(void)
927 {
928    if (!root)
929      root = efl_add(ELM_ATSPI_APP_OBJECT_CLASS, efl_main_loop_get());
930
931    return root;
932 }
933
934 EOLIAN void
935 _efl_access_object_efl_object_destructor(Eo *obj, Efl_Access_Object_Data *pd)
936 {
937    eina_stringshare_del(pd->name);
938    eina_stringshare_del(pd->description);
939    eina_stringshare_del(pd->translation_domain);
940    efl_access_relation_set_free(&pd->relations);
941    //TIZEN_ONLY(20181211): Fix for missing unregistration of atspi objects
942    unregister_atspi_object_in_bridge(obj);
943    //
944
945    efl_destructor(efl_super(obj, EFL_ACCESS_OBJECT_MIXIN));
946 }
947
948 void
949 _efl_access_shutdown(void)
950 {
951    Efl_Access_Event_Handler *hdl;
952
953    EINA_LIST_FREE(global_callbacks, hdl)
954      free(hdl);
955
956    ELM_SAFE_DEL(root);
957 }
958
959 //TIZEN_ONLY(20171211): Keep Tizen Legacy API
960 EAPI Eina_Bool
961 elm_atspi_accessible_relationship_append(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Relation_Type type, const Elm_Interface_Atspi_Accessible *relation_object)
962 {
963    return efl_access_object_relationship_append(obj, type, relation_object);
964 }
965
966 EAPI void
967 elm_atspi_accessible_relationship_remove(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Relation_Type type, const Elm_Interface_Atspi_Accessible *relation_object)
968 {
969    efl_access_object_relationship_remove(obj, type, relation_object);
970 }
971
972 EAPI const char *
973 elm_atspi_accessible_translation_domain_get(const Elm_Interface_Atspi_Accessible *obj)
974 {
975    return efl_access_object_translation_domain_get(obj);
976 }
977
978 EAPI void
979 elm_atspi_accessible_translation_domain_set(Elm_Interface_Atspi_Accessible *obj, const char *domain)
980 {
981    efl_access_object_translation_domain_set(obj, domain);
982 }
983
984 EAPI const char *
985 elm_atspi_accessible_localized_role_name_get(const Elm_Interface_Atspi_Accessible *obj)
986 {
987    return efl_access_object_localized_role_name_get(obj);
988 }
989
990 EAPI void elm_atspi_accessible_name_set(Elm_Interface_Atspi_Accessible *obj, const char *name)
991 {
992    efl_access_object_i18n_name_set(obj, name);
993 }
994
995 EAPI const char *
996 elm_atspi_accessible_name_get(const Elm_Interface_Atspi_Accessible *obj)
997 {
998    return efl_access_object_i18n_name_get(obj);
999 }
1000
1001 EAPI void
1002 elm_atspi_accessible_name_cb_set(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Reading_Info_Cb name_cb, const void *data)
1003 {
1004    efl_access_object_name_cb_set(obj, name_cb, data);
1005 }
1006
1007 EAPI Elm_Atspi_Relation_Set
1008 elm_atspi_accessible_relation_set_get(const Elm_Interface_Atspi_Accessible *obj)
1009 {
1010    return efl_access_object_relation_set_get(obj);
1011 }
1012
1013 EAPI void
1014 elm_atspi_accessible_role_set(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Role role)
1015 {
1016    efl_access_object_role_set(obj, role);
1017 }
1018
1019 EAPI Elm_Atspi_Role
1020 elm_atspi_accessible_role_get(const Elm_Interface_Atspi_Accessible *obj)
1021 {
1022    return efl_access_object_role_get(obj);
1023 }
1024
1025 EAPI Eina_List *elm_atspi_accessible_children_get(const Elm_Interface_Atspi_Accessible *obj)
1026 {
1027    return efl_access_object_access_children_get(obj);
1028 }
1029
1030 EAPI const char *
1031 elm_atspi_accessible_role_name_get(const Elm_Interface_Atspi_Accessible *obj)
1032 {
1033    return efl_access_object_role_name_get(obj);
1034 }
1035
1036 EAPI Eina_List *
1037 elm_atspi_accessible_attributes_get(const Elm_Interface_Atspi_Accessible *obj)
1038 {
1039    return efl_access_object_attributes_get(obj);
1040 }
1041
1042 EAPI void
1043 elm_atspi_accessible_reading_info_type_set(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Reading_Info_Type_Mask reading_info)
1044 {
1045    efl_access_object_reading_info_type_set(obj, (Efl_Access_Reading_Info_Type_Mask)reading_info);
1046 }
1047
1048 EAPI Elm_Atspi_Reading_Info_Type_Mask
1049 elm_atspi_accessible_reading_info_type_get(const Elm_Interface_Atspi_Accessible *obj)
1050 {
1051    return (Elm_Atspi_Reading_Info_Type_Mask)efl_access_object_reading_info_type_get(obj);
1052 }
1053
1054 EAPI int
1055 elm_atspi_accessible_index_in_parent_get(const Elm_Interface_Atspi_Accessible *obj)
1056 {
1057    return efl_access_object_index_in_parent_get(obj);
1058 }
1059
1060 EAPI void
1061 elm_atspi_accessible_description_set(Elm_Interface_Atspi_Accessible *obj, const char *description)
1062 {
1063    efl_access_object_description_set(obj, description);
1064 }
1065
1066 EAPI const char *
1067 elm_atspi_accessible_description_get(const Elm_Interface_Atspi_Accessible *obj)
1068 {
1069    return efl_access_object_description_get(obj);
1070 }
1071
1072 EAPI void
1073 elm_atspi_accessible_description_cb_set(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Reading_Info_Cb description_cb, const void *data)
1074 {
1075    efl_access_object_description_cb_set(obj, description_cb, data);
1076 }
1077
1078 EAPI void
1079 elm_atspi_accessible_gesture_cb_set(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_Gesture_Cb gesture_cb, const void *data)
1080 {
1081    efl_access_object_gesture_cb_set(obj, gesture_cb, data);
1082 }
1083
1084 EAPI void
1085 elm_atspi_accessible_parent_set(Elm_Interface_Atspi_Accessible *obj, Elm_Interface_Atspi_Accessible *parent)
1086 {
1087    efl_parent_set(obj, parent);
1088 }
1089
1090 EAPI Elm_Interface_Atspi_Accessible *
1091 elm_atspi_accessible_parent_get(const Elm_Interface_Atspi_Accessible *obj)
1092 {
1093    //TIZEN_ONLY(20181024): Fix parent-children incosistencies in atspi tree
1094    return efl_access_object_access_parent_get(obj);
1095    //
1096 }
1097
1098 EAPI Elm_Atspi_State_Set
1099 elm_atspi_accessible_state_set_get(const Elm_Interface_Atspi_Accessible *obj)
1100 {
1101    return efl_access_object_state_set_get(obj);
1102 }
1103
1104 EAPI void
1105 elm_atspi_accessible_can_highlight_set(Elm_Interface_Atspi_Accessible *obj, Eina_Bool can_highlight)
1106 {
1107    efl_access_object_can_highlight_set(obj, can_highlight);
1108 }
1109
1110 EAPI Eina_Bool
1111 elm_atspi_accessible_can_highlight_get(const Elm_Interface_Atspi_Accessible *obj)
1112 {
1113    return efl_access_object_can_highlight_get(obj);
1114 }
1115
1116 EAPI void
1117 elm_atspi_accessible_attribute_append(Elm_Interface_Atspi_Accessible *obj, const char *key, const char *value)
1118 {
1119    efl_access_object_attribute_append(obj, key, value);
1120 }
1121
1122 EAPI void
1123 elm_atspi_accessible_attributes_clear(Elm_Interface_Atspi_Accessible *obj)
1124 {
1125    efl_access_object_attributes_clear(obj);
1126 }
1127
1128 EAPI void
1129 elm_atspi_accessible_relationships_clear(Elm_Interface_Atspi_Accessible *obj)
1130 {
1131    efl_access_object_relationships_clear(obj);
1132 }
1133
1134 EAPI void
1135 elm_atspi_accessible_state_notify(Elm_Interface_Atspi_Accessible *obj, Elm_Atspi_State_Set state_types_mask, Eina_Bool recursive)
1136 {
1137    efl_access_object_state_notify(obj, state_types_mask, recursive);
1138 }
1139
1140 EAPI void elm_atspi_relation_set_free(Elm_Atspi_Relation_Set *set)
1141 {
1142    efl_access_relation_set_free(set);
1143 }
1144
1145 EAPI Elm_Atspi_Relation_Set elm_atspi_relation_set_clone(const Elm_Atspi_Relation_Set *set)
1146 {
1147    return efl_access_relation_set_clone(set);
1148 }
1149
1150 EAPI void elm_atspi_relation_free(Elm_Atspi_Relation *relation)
1151 {
1152    efl_access_relation_free(relation);
1153 }
1154
1155 EAPI Elm_Atspi_Relation * elm_atspi_relation_clone(const Elm_Atspi_Relation *relation)
1156 {
1157    return efl_access_relation_clone(relation);
1158 }
1159
1160 EAPI Eina_Bool elm_atspi_relation_set_relation_append(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj)
1161 {
1162    return efl_access_relation_set_relation_append(set, type, rel_obj);
1163 }
1164
1165 EAPI void elm_atspi_relation_set_relation_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj)
1166 {
1167    efl_access_relation_set_relation_remove(set, type, rel_obj);
1168 }
1169
1170 EAPI void elm_atspi_relation_set_relation_type_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type)
1171 {
1172    efl_access_relation_set_relation_type_remove(set, type);
1173 }
1174
1175 EAPI void elm_atspi_attributes_list_free(Eina_List *list)
1176 {
1177    efl_access_attributes_list_free(list);
1178 }
1179 //
1180
1181 #include "efl_access_object.eo.c"