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