atspi: fix infinite loop issue
[platform/upstream/elementary.git] / src / lib / elm_atspi_bridge.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
6 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
7 #define ELM_INTERFACE_ATSPI_ACTION_PROTECTED
8 #define ELM_INTERFACE_ATSPI_VALUE_PROTECTED
9 #define ELM_INTERFACE_ATSPI_IMAGE_PROTECTED
10 #define ELM_INTERFACE_ATSPI_SELECTION_PROTECTED
11 #define ELM_INTERFACE_ATSPI_TEXT_PROTECTED
12 #define ELM_INTERFACE_ATSPI_EDITABLE_TEXT_PROTECTED
13
14 #include "atspi/atspi-constants.h"
15
16 #include <stdint.h>
17 #include <Elementary.h>
18 #include "elm_priv.h"
19
20 /*
21  * Accessibility Bus info not defined in atspi-constants.h
22  */
23 #define A11Y_DBUS_NAME "org.a11y.Bus"
24 #define A11Y_DBUS_PATH "/org/a11y/bus"
25 #define A11Y_DBUS_INTERFACE "org.a11y.Bus"
26 #define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
27 // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
28 #define A11Y_DBUS_ENABLED_PROPERTY "IsEnabled"
29 //
30 #define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
31
32 #define CACHE_ITEM_SIGNATURE "((so)(so)(so)a(so)assusau)"
33 #define CACHE_INTERFACE_PATH "/org/a11y/atspi/cache"
34
35 #define ELM_ACCESS_OBJECT_PATH_ROOT "root"
36 #define ELM_ACCESS_OBJECT_PATH_PREFIX  "/org/a11y/atspi/accessible/"
37 #define ELM_ACCESS_OBJECT_PATH_PREFIX2  "/org/a11y/atspi/accessible"
38 #define ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE ELM_ACCESS_OBJECT_PATH_PREFIX "%llu"
39
40 #define ELM_ATSPI_DBUS_INTERFACE_PROXY "elm.atspi.bridge.proxy.Socket"
41 //TIZEN_ONLY(20160527) - Add direct reading feature
42 #define ELM_ATSPI_DIRECT_READ_BUS "org.tizen.ScreenReader"
43 #define ELM_ATSPI_DIRECT_READ_PATH "/org/tizen/DirectReading"
44 #define ELM_ATSPI_DIRECT_READ_INTERFACE "org.tizen.DirectReading"
45 struct _Elm_Atspi_Say_Info
46 {
47    void                    *data;
48    Elm_Atspi_Say_Signal_Cb  func; //this function will be called when state of related reading is changed
49 };
50 typedef struct _Elm_Atspi_Say_Info Elm_Atspi_Say_Info;
51 static Eina_Hash *read_command_id = NULL;
52 //
53 #define SIZE(x) sizeof(x)/sizeof(x[0])
54 #define ELM_ATSPI_BRIDGE_CLASS_NAME "__Elm_Atspi_Bridge"
55
56 #define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, sd) \
57    Elm_Atspi_Bridge_Data *sd = eo_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
58    if (!sd) return;
59
60 #define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(obj, sd, val) \
61    Elm_Atspi_Bridge_Data *sd = eo_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
62    if (!sd) return val;
63
64 #define ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg, error) \
65    if (!(obj) || !eo_isa(obj, class)) \
66      { \
67         *(error) = _dbus_invalid_ref_error_new(msg); \
68         return EINA_FALSE; \
69      }
70
71 #define ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg) \
72    if (!(obj) || !eo_isa(obj, class)) \
73      return _dbus_invalid_ref_error_new(msg);
74
75 typedef struct Key_Event_Info {
76      Ecore_Event_Key event;
77      int type;
78      Eo *bridge;
79 } Key_Event_Info;
80
81 typedef struct _Elm_Atspi_Bridge_Data
82 {
83    Eldbus_Connection *session_bus;
84    Eldbus_Connection *a11y_bus;
85    Eina_List *reemited_events;
86    Eo *root;
87    Eina_Hash *cache;
88    Eldbus_Service_Interface *cache_interface;
89    Eldbus_Signal_Handler *register_hdl;
90    Eldbus_Signal_Handler *unregister_hdl;
91 //TIZEN_ONLY(20160614):apply callbacks on direct reading stop/cancel/skipp
92    Eldbus_Signal_Handler *reading_state_changed_hdl;
93 //
94    unsigned long object_broadcast_mask;
95    unsigned long object_property_broadcast_mask;
96    unsigned long object_children_broadcast_mask;
97    unsigned long long object_state_broadcast_mask;
98    unsigned long long window_signal_broadcast_mask;
99    Ecore_Event_Filter *key_flr;
100    Eldbus_Object *bus_obj;
101    Eina_List *pending_requests;
102    int id;
103    Eina_Hash *state_hash;
104    struct {
105         Eldbus_Service_Interface *accessible;
106         Eldbus_Service_Interface *application;
107         Eldbus_Service_Interface *action;
108         Eldbus_Service_Interface *component;
109         Eldbus_Service_Interface *collection;
110         Eldbus_Service_Interface *editable_text;
111         Eldbus_Service_Interface *image;
112         Eldbus_Service_Interface *selection;
113         Eldbus_Service_Interface *text;
114         Eldbus_Service_Interface *value;
115         // TIZEN_ONLY(20160705) - enable atspi_proxy to work
116         Eldbus_Service_Interface *socket;
117         //
118    } interfaces;
119    Elm_Atspi_Event_Handler *event_hdlr;
120    Eina_Hash *event_hash;
121    Eina_List *socket_queue;
122    Eina_List *plug_queue;
123    Eina_Bool connected : 1;
124    // TIZEN_ONLY(20160802): do not handle events if the window is not activated
125    Eina_Bool window_activated : 1;
126    // TIZEN_ONLY(20170512): send window activated event to at_spi2 only once per session
127    Eina_Bool window_activated_broadcast_needed : 1;
128    //TIZEN_ONLY(20161027) - Export elm_atspi_bridge_utils_is_screen_reader_enabled
129    Eina_Bool screen_reader_enabled : 1;
130    //
131 } Elm_Atspi_Bridge_Data;
132
133
134 struct collection_match_rule {
135      Elm_Atspi_State_Set states;
136      AtspiCollectionMatchType statematchtype;
137      Eina_List *attributes;
138      AtspiCollectionMatchType attributematchtype;
139      uint64_t roles[2];
140      AtspiCollectionMatchType rolematchtype;
141      Eina_List *ifaces;
142      AtspiCollectionMatchType interfacematchtype;
143      Eina_Bool reverse : 1;
144 };
145
146 static Eo *_instance;
147 static int _init_count = 0;
148 static const char *_a11y_socket_address;
149
150 // Object Event handlers
151 static Eina_Bool _state_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
152 static Eina_Bool _property_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info);
153 static Eina_Bool _bounds_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info);
154 static Eina_Bool _children_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info);
155 static Eina_Bool _window_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
156 static Eina_Bool _visible_data_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
157 static Eina_Bool _active_descendant_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
158 static Eina_Bool _selection_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
159 static Eina_Bool _text_text_inserted_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
160 static Eina_Bool _text_text_removed_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
161 static Eina_Bool _text_caret_moved_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
162 static Eina_Bool _text_selection_changed_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info EINA_UNUSED);
163 //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
164 static Eina_Bool _move_outed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info);
165 //
166
167 // bridge private methods
168 static void _bridge_cache_build(Eo *bridge, void *obj);
169 static void _bridge_object_register(Eo *bridge, Eo *obj);
170 static void _bridge_object_unregister(Eo *bridge, Eo *obj);
171 static const char * _bridge_path_from_object(Eo *bridge, const Eo *eo);
172 static void _bridge_signal_send(Eo *bridge, Eo *obj, const char *ifc, const Eldbus_Signal *signal, const char *minor, unsigned int det1, unsigned int det2, const char *variant_sig, ...);
173 static Eo * _bridge_object_from_path(Eo *bridge, const char *path);
174 static void _bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj);
175
176 // utility functions
177 static void _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj);
178 static Eina_Bool _elm_atspi_bridge_key_filter(void *data, void *loop, int type, void *event);
179 static void _object_desktop_reference_append(Eldbus_Message_Iter *iter);
180 static Eina_Bool _on_object_add(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED);
181 static Eina_Bool _on_object_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED);
182 static void _plug_connect(Eldbus_Connection *conn, Eo *proxy);
183 static void _socket_ifc_create(Eldbus_Connection *conn, Eo *proxy);
184 static void _object_get_bus_name_and_path(Eo *bridge, const Eo *obj, const char **bus_name, const char **path);
185 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
186 static Eo *_calculate_navigable_accessible_at_point(Eo *bridge, Eo *root, Eina_Bool coord_type, int x, int y);
187 static Eo *_calculate_neighbor(Eo *bridge, Eo *root, Eo *current, Eina_Bool forward, int search_mode);
188 //
189
190 typedef struct {
191      const Eo_Event_Description *desc;
192      const Eo_Event_Cb callback;
193 } Elm_Atspi_Bridge_Event_Handler;
194
195 static const Elm_Atspi_Bridge_Event_Handler event_handlers[] = {
196    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, _children_changed_signal_send},
197    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_PROPERTY_CHANGED, _property_changed_signal_send},
198    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_BOUNDS_CHANGED, _bounds_changed_signal_send},
199    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_STATE_CHANGED, _state_changed_signal_send},
200    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_VISIBLE_DATA_CHANGED, _visible_data_changed_signal_send},
201    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_ACTIVE_DESCENDANT_CHANGED, _active_descendant_changed_signal_send},
202    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_ADDED, _on_object_add},
203    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_REMOVED, _on_object_del},
204    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_CREATED, _window_signal_send},
205    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DESTROYED, _window_signal_send},
206    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_ACTIVATED, _window_signal_send},
207    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DEACTIVATED, _window_signal_send},
208    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_MAXIMIZED, _window_signal_send},
209    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_MINIMIZED, _window_signal_send},
210    { ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_RESTORED, _window_signal_send},
211    { ELM_INTERFACE_ATSPI_SELECTION_EVENT_SELECTION_CHANGED, _selection_signal_send},
212    { ELM_INTERFACE_ATSPI_TEXT_EVENT_ACCESS_TEXT_CARET_MOVED, _text_caret_moved_send },
213    { ELM_INTERFACE_ATSPI_TEXT_EVENT_ACCESS_TEXT_INSERTED, _text_text_inserted_send },
214    { ELM_INTERFACE_ATSPI_TEXT_EVENT_ACCESS_TEXT_REMOVED, _text_text_removed_send },
215    { ELM_INTERFACE_ATSPI_TEXT_EVENT_ACCESS_TEXT_SELECTION_CHANGED, _text_selection_changed_send },
216    //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
217    { ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_MOVE_OUTED, _move_outed_signal_send}
218    //
219 };
220
221 enum
222 {
223   ELM_ACCESSIBLE_DEFAULT_LABEL_ENABLED = 0,
224   ELM_ACCESSIBLE_DEFAULT_LABEL_DISABLED = 1 << 0,
225 };
226
227 enum _Atspi_Object_Child_Event_Type
228 {
229    ATSPI_OBJECT_CHILD_ADDED = 0,
230    ATSPI_OBJECT_CHILD_REMOVED
231 };
232
233 enum _Atspi_Object_Property
234 {
235    ATSPI_OBJECT_PROPERTY_NAME = 0,
236    ATSPI_OBJECT_PROPERTY_DESCRIPTION,
237    ATSPI_OBJECT_PROPERTY_VALUE,
238    ATSPI_OBJECT_PROPERTY_ROLE,
239    ATSPI_OBJECT_PROPERTY_PARENT,
240    ATSPI_OBJECT_PROPERTY_LAST
241 };
242
243 enum _Atspi_Object_Signals {
244    ATSPI_OBJECT_EVENT_PROPERTY_CHANGED = 0,
245    ATSPI_OBJECT_EVENT_BOUNDS_CHANGED,
246    ATSPI_OBJECT_EVENT_LINK_SELECTED,
247    ATSPI_OBJECT_EVENT_STATE_CHANGED,
248    ATSPI_OBJECT_EVENT_CHILDREN_CHANGED,
249    ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED,
250    ATSPI_OBJECT_EVENT_SELECTION_CHANGED,
251    ATSPI_OBJECT_EVENT_MODEL_CHANGED,
252    ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED,
253    ATSPI_OBJECT_EVENT_ROW_INSERTED,
254    ATSPI_OBJECT_EVENT_ROW_REORDERED,
255    ATSPI_OBJECT_EVENT_ROW_DELETED,
256    ATSPI_OBJECT_EVENT_COLUMN_INSERTED,
257    ATSPI_OBJECT_EVENT_COLUMN_REORDERED,
258    ATSPI_OBJECT_EVENT_COLUMN_DELETED,
259    ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED,
260    ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED,
261    ATSPI_OBJECT_EVENT_TEXT_CHANGED,
262    ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED,
263    ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED,
264    ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED,
265    //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
266    ATSPI_OBJECT_EVENT_MOVE_OUTED
267    //
268 };
269
270 enum _Atspi_Window_Signals
271 {
272    ATSPI_WINDOW_EVENT_PROPERTY_CHANGE = 0,
273    ATSPI_WINDOW_EVENT_MINIMIZE,
274    ATSPI_WINDOW_EVENT_MAXIMIZE,
275    ATSPI_WINDOW_EVENT_RESTORE,
276    ATSPI_WINDOW_EVENT_CLOSE,
277    ATSPI_WINDOW_EVENT_CREATE,
278    ATSPI_WINDOW_EVENT_REPARENT,
279    ATSPI_WINDOW_EVENT_DESKTOPCREATE,
280    ATSPI_WINDOW_EVENT_DESKTOPDESTROY,
281    ATSPI_WINDOW_EVENT_DESTROY,
282    ATSPI_WINDOW_EVENT_ACTIVATE,
283    ATSPI_WINDOW_EVENT_DEACTIVATE,
284    ATSPI_WINDOW_EVENT_RAISE,
285    ATSPI_WINDOW_EVENT_LOWER,
286    ATSPI_WINDOW_EVENT_MOVE,
287    ATSPI_WINDOW_EVENT_RESIZE,
288    ATSPI_WINDOW_EVENT_SHADE,
289    ATSPI_WINDOW_EVENT_UUSHADE,
290    ATSPI_WINDOW_EVENT_RESTYLE,
291 };
292
293 static const Eldbus_Signal _event_obj_signals[] = {
294    [ATSPI_OBJECT_EVENT_PROPERTY_CHANGED] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
295    [ATSPI_OBJECT_EVENT_BOUNDS_CHANGED] = {"BoundsChanged", ELDBUS_ARGS({"siiv(iiii)", NULL}), 0},
296    [ATSPI_OBJECT_EVENT_LINK_SELECTED] = {"LinkSelected", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
297    [ATSPI_OBJECT_EVENT_STATE_CHANGED] = {"StateChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
298    [ATSPI_OBJECT_EVENT_CHILDREN_CHANGED] = {"ChildrenChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
299    [ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED] = {"VisibleDataChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
300    [ATSPI_OBJECT_EVENT_SELECTION_CHANGED] = {"SelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
301    [ATSPI_OBJECT_EVENT_MODEL_CHANGED] = {"ModelChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
302    [ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED] = {"ActiveDescendantChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
303    [ATSPI_OBJECT_EVENT_ROW_INSERTED] = {"RowInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
304    [ATSPI_OBJECT_EVENT_ROW_REORDERED] = {"RowReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
305    [ATSPI_OBJECT_EVENT_ROW_DELETED] = {"RowDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
306    [ATSPI_OBJECT_EVENT_COLUMN_INSERTED] = {"ColumnInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
307    [ATSPI_OBJECT_EVENT_COLUMN_REORDERED] = {"ColumnReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
308    [ATSPI_OBJECT_EVENT_COLUMN_DELETED] = {"ColumnDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
309    [ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED] = {"TextBoundsChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
310    [ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED] = {"TextSelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
311    [ATSPI_OBJECT_EVENT_TEXT_CHANGED] = {"TextChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
312    [ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED] = {"TextAttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
313    [ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED] = {"TextCaretMoved", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
314    [ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED] = {"AttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
315    //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
316    [ATSPI_OBJECT_EVENT_MOVE_OUTED] = {"MoveOuted", ELDBUS_ARGS({"siiv(i)", NULL}), 0},
317    //
318    {NULL, ELDBUS_ARGS({NULL, NULL}), 0}
319 };
320
321 static const Eldbus_Signal _window_obj_signals[] = {
322    [ATSPI_WINDOW_EVENT_PROPERTY_CHANGE] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
323    [ATSPI_WINDOW_EVENT_MINIMIZE] = {"Minimize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
324    [ATSPI_WINDOW_EVENT_MAXIMIZE] = {"Maximize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
325    [ATSPI_WINDOW_EVENT_RESTORE] = {"Restore", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
326    [ATSPI_WINDOW_EVENT_CLOSE] = {"Close", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
327    [ATSPI_WINDOW_EVENT_CREATE] = {"Create", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
328    [ATSPI_WINDOW_EVENT_REPARENT] = {"Reparent", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
329    [ATSPI_WINDOW_EVENT_DESKTOPCREATE] = {"DesktopCreate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
330    [ATSPI_WINDOW_EVENT_DESKTOPDESTROY] = {"DesktopDestroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
331    [ATSPI_WINDOW_EVENT_DESTROY] = {"Destroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
332    [ATSPI_WINDOW_EVENT_ACTIVATE] = {"Activate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
333    [ATSPI_WINDOW_EVENT_DEACTIVATE] = {"Deactivate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
334    [ATSPI_WINDOW_EVENT_RAISE] = {"Raise", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
335    [ATSPI_WINDOW_EVENT_LOWER] = {"Lower", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
336    [ATSPI_WINDOW_EVENT_MOVE] = {"Move", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
337    [ATSPI_WINDOW_EVENT_RESIZE] = {"Resize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
338    [ATSPI_WINDOW_EVENT_SHADE] = {"Shade", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
339    [ATSPI_WINDOW_EVENT_UUSHADE] = {"uUshade", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
340    [ATSPI_WINDOW_EVENT_RESTYLE] = {"Restyle", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
341    {NULL, ELDBUS_ARGS({NULL, NULL}), 0}
342 };
343
344 const int elm_roles_to_atspi_roles[][2] = {
345    { ELM_ATSPI_ROLE_INVALID, ATSPI_ROLE_INVALID },
346    { ELM_ATSPI_ROLE_ACCELERATOR_LABEL, ATSPI_ROLE_ACCELERATOR_LABEL },
347    { ELM_ATSPI_ROLE_ALERT, ATSPI_ROLE_ALERT },
348    { ELM_ATSPI_ROLE_ANIMATION, ATSPI_ROLE_ANIMATION },
349    { ELM_ATSPI_ROLE_ARROW, ATSPI_ROLE_ARROW },
350    { ELM_ATSPI_ROLE_CALENDAR, ATSPI_ROLE_CALENDAR },
351    { ELM_ATSPI_ROLE_CANVAS, ATSPI_ROLE_CANVAS },
352    { ELM_ATSPI_ROLE_CHECK_BOX, ATSPI_ROLE_CHECK_BOX },
353    { ELM_ATSPI_ROLE_CHECK_MENU_ITEM, ATSPI_ROLE_CHECK_MENU_ITEM },
354    { ELM_ATSPI_ROLE_COLOR_CHOOSER, ATSPI_ROLE_COLOR_CHOOSER },
355    { ELM_ATSPI_ROLE_COLUMN_HEADER, ATSPI_ROLE_COLUMN_HEADER },
356    { ELM_ATSPI_ROLE_COMBO_BOX, ATSPI_ROLE_COMBO_BOX },
357    { ELM_ATSPI_ROLE_DATE_EDITOR, ATSPI_ROLE_DATE_EDITOR },
358    { ELM_ATSPI_ROLE_DESKTOP_ICON, ATSPI_ROLE_DESKTOP_ICON },
359    { ELM_ATSPI_ROLE_DESKTOP_FRAME, ATSPI_ROLE_DESKTOP_FRAME },
360    { ELM_ATSPI_ROLE_DIAL, ATSPI_ROLE_DIAL },
361    { ELM_ATSPI_ROLE_DIALOG, ATSPI_ROLE_DIALOG },
362    { ELM_ATSPI_ROLE_DIRECTORY_PANE, ATSPI_ROLE_DIRECTORY_PANE },
363    { ELM_ATSPI_ROLE_DRAWING_AREA, ATSPI_ROLE_DRAWING_AREA },
364    { ELM_ATSPI_ROLE_FILE_CHOOSER, ATSPI_ROLE_FILE_CHOOSER },
365    { ELM_ATSPI_ROLE_FILLER, ATSPI_ROLE_FILLER },
366    { ELM_ATSPI_ROLE_FOCUS_TRAVERSABLE, ATSPI_ROLE_FOCUS_TRAVERSABLE },
367    { ELM_ATSPI_ROLE_FONT_CHOOSER, ATSPI_ROLE_FONT_CHOOSER },
368    { ELM_ATSPI_ROLE_FRAME, ATSPI_ROLE_FRAME },
369    { ELM_ATSPI_ROLE_GLASS_PANE, ATSPI_ROLE_GLASS_PANE },
370    { ELM_ATSPI_ROLE_HTML_CONTAINER, ATSPI_ROLE_HTML_CONTAINER },
371    { ELM_ATSPI_ROLE_ICON, ATSPI_ROLE_ICON },
372    { ELM_ATSPI_ROLE_IMAGE, ATSPI_ROLE_IMAGE },
373    { ELM_ATSPI_ROLE_INTERNAL_FRAME, ATSPI_ROLE_INTERNAL_FRAME },
374    { ELM_ATSPI_ROLE_LABEL, ATSPI_ROLE_LABEL },
375    { ELM_ATSPI_ROLE_LAYERED_PANE, ATSPI_ROLE_LAYERED_PANE },
376    { ELM_ATSPI_ROLE_LIST, ATSPI_ROLE_LIST },
377    { ELM_ATSPI_ROLE_LIST_ITEM, ATSPI_ROLE_LIST_ITEM },
378    { ELM_ATSPI_ROLE_MENU, ATSPI_ROLE_MENU },
379    { ELM_ATSPI_ROLE_MENU_BAR, ATSPI_ROLE_MENU_BAR },
380    { ELM_ATSPI_ROLE_MENU_ITEM, ATSPI_ROLE_MENU_ITEM },
381    { ELM_ATSPI_ROLE_OPTION_PANE, ATSPI_ROLE_OPTION_PANE },
382    { ELM_ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_PAGE_TAB },
383    { ELM_ATSPI_ROLE_PAGE_TAB_LIST, ATSPI_ROLE_PAGE_TAB_LIST },
384    { ELM_ATSPI_ROLE_PANEL, ATSPI_ROLE_PANEL },
385    { ELM_ATSPI_ROLE_PASSWORD_TEXT, ATSPI_ROLE_PASSWORD_TEXT },
386    { ELM_ATSPI_ROLE_POPUP_MENU, ATSPI_ROLE_POPUP_MENU },
387    { ELM_ATSPI_ROLE_PROGRESS_BAR, ATSPI_ROLE_PROGRESS_BAR },
388    { ELM_ATSPI_ROLE_PUSH_BUTTON, ATSPI_ROLE_PUSH_BUTTON },
389    { ELM_ATSPI_ROLE_RADIO_BUTTON, ATSPI_ROLE_RADIO_BUTTON },
390    { ELM_ATSPI_ROLE_RADIO_MENU_ITEM, ATSPI_ROLE_RADIO_MENU_ITEM },
391    { ELM_ATSPI_ROLE_ROOT_PANE, ATSPI_ROLE_ROOT_PANE },
392    { ELM_ATSPI_ROLE_ROW_HEADER, ATSPI_ROLE_ROW_HEADER },
393    { ELM_ATSPI_ROLE_SCROLL_BAR, ATSPI_ROLE_SCROLL_BAR },
394    { ELM_ATSPI_ROLE_SCROLL_PANE, ATSPI_ROLE_SCROLL_PANE },
395    { ELM_ATSPI_ROLE_SEPARATOR, ATSPI_ROLE_SEPARATOR },
396    { ELM_ATSPI_ROLE_SLIDER, ATSPI_ROLE_SLIDER },
397    { ELM_ATSPI_ROLE_SPIN_BUTTON, ATSPI_ROLE_SPIN_BUTTON },
398    { ELM_ATSPI_ROLE_SPLIT_PANE, ATSPI_ROLE_SPLIT_PANE },
399    { ELM_ATSPI_ROLE_STATUS_BAR, ATSPI_ROLE_STATUS_BAR },
400    { ELM_ATSPI_ROLE_TABLE, ATSPI_ROLE_TABLE },
401    { ELM_ATSPI_ROLE_TABLE_CELL, ATSPI_ROLE_TABLE_CELL },
402    { ELM_ATSPI_ROLE_TABLE_COLUMN_HEADER, ATSPI_ROLE_TABLE_COLUMN_HEADER },
403    { ELM_ATSPI_ROLE_TABLE_ROW_HEADER, ATSPI_ROLE_TABLE_ROW_HEADER },
404    { ELM_ATSPI_ROLE_TEAROFF_MENU_ITEM, ATSPI_ROLE_TEAROFF_MENU_ITEM },
405    { ELM_ATSPI_ROLE_TERMINAL, ATSPI_ROLE_TERMINAL },
406    { ELM_ATSPI_ROLE_TEXT, ATSPI_ROLE_TEXT },
407    { ELM_ATSPI_ROLE_TOGGLE_BUTTON, ATSPI_ROLE_TOGGLE_BUTTON },
408    { ELM_ATSPI_ROLE_TOOL_BAR, ATSPI_ROLE_TOOL_BAR },
409    { ELM_ATSPI_ROLE_TOOL_TIP, ATSPI_ROLE_TOOL_TIP },
410    { ELM_ATSPI_ROLE_TREE, ATSPI_ROLE_TREE },
411    { ELM_ATSPI_ROLE_TREE_TABLE, ATSPI_ROLE_TREE_TABLE },
412    { ELM_ATSPI_ROLE_UNKNOWN, ATSPI_ROLE_UNKNOWN },
413    { ELM_ATSPI_ROLE_VIEWPORT, ATSPI_ROLE_VIEWPORT },
414    { ELM_ATSPI_ROLE_WINDOW, ATSPI_ROLE_WINDOW },
415    { ELM_ATSPI_ROLE_EXTENDED, ATSPI_ROLE_EXTENDED },
416    { ELM_ATSPI_ROLE_HEADER, ATSPI_ROLE_HEADER },
417    { ELM_ATSPI_ROLE_FOOTER, ATSPI_ROLE_FOOTER },
418    { ELM_ATSPI_ROLE_PARAGRAPH, ATSPI_ROLE_PARAGRAPH },
419    { ELM_ATSPI_ROLE_RULER, ATSPI_ROLE_RULER },
420    { ELM_ATSPI_ROLE_APPLICATION, ATSPI_ROLE_APPLICATION },
421    { ELM_ATSPI_ROLE_AUTOCOMPLETE, ATSPI_ROLE_AUTOCOMPLETE },
422    { ELM_ATSPI_ROLE_EDITBAR, ATSPI_ROLE_EDITBAR },
423    { ELM_ATSPI_ROLE_EMBEDDED, ATSPI_ROLE_EMBEDDED },
424    { ELM_ATSPI_ROLE_ENTRY, ATSPI_ROLE_ENTRY },
425    { ELM_ATSPI_ROLE_CHART, ATSPI_ROLE_CHART },
426    { ELM_ATSPI_ROLE_CAPTION, ATSPI_ROLE_CAPTION },
427    { ELM_ATSPI_ROLE_DOCUMENT_FRAME, ATSPI_ROLE_DOCUMENT_FRAME },
428    { ELM_ATSPI_ROLE_HEADING, ATSPI_ROLE_HEADING },
429    { ELM_ATSPI_ROLE_PAGE, ATSPI_ROLE_PAGE },
430    { ELM_ATSPI_ROLE_SECTION, ATSPI_ROLE_SECTION },
431    { ELM_ATSPI_ROLE_REDUNDANT_OBJECT, ATSPI_ROLE_REDUNDANT_OBJECT },
432    { ELM_ATSPI_ROLE_FORM, ATSPI_ROLE_FORM },
433    { ELM_ATSPI_ROLE_LINK, ATSPI_ROLE_LINK },
434    { ELM_ATSPI_ROLE_INPUT_METHOD_WINDOW, ATSPI_ROLE_INPUT_METHOD_WINDOW },
435    { ELM_ATSPI_ROLE_TABLE_ROW, ATSPI_ROLE_TABLE_ROW },
436    { ELM_ATSPI_ROLE_TREE_ITEM, ATSPI_ROLE_TREE_ITEM },
437    { ELM_ATSPI_ROLE_DOCUMENT_SPREADSHEET, ATSPI_ROLE_DOCUMENT_SPREADSHEET },
438    { ELM_ATSPI_ROLE_DOCUMENT_PRESENTATION, ATSPI_ROLE_DOCUMENT_PRESENTATION },
439    { ELM_ATSPI_ROLE_DOCUMENT_TEXT, ATSPI_ROLE_DOCUMENT_TEXT },
440    { ELM_ATSPI_ROLE_DOCUMENT_WEB, ATSPI_ROLE_DOCUMENT_WEB },
441    { ELM_ATSPI_ROLE_DOCUMENT_EMAIL, ATSPI_ROLE_DOCUMENT_EMAIL },
442    { ELM_ATSPI_ROLE_COMMENT, ATSPI_ROLE_COMMENT },
443    { ELM_ATSPI_ROLE_LIST_BOX, ATSPI_ROLE_LIST_BOX },
444    { ELM_ATSPI_ROLE_GROUPING, ATSPI_ROLE_GROUPING },
445    { ELM_ATSPI_ROLE_IMAGE_MAP, ATSPI_ROLE_IMAGE_MAP },
446    { ELM_ATSPI_ROLE_NOTIFICATION, ATSPI_ROLE_NOTIFICATION },
447    { ELM_ATSPI_ROLE_INFO_BAR, ATSPI_ROLE_INFO_BAR },
448    { ELM_ATSPI_ROLE_LAST_DEFINED, ATSPI_ROLE_LAST_DEFINED },
449 };
450
451 struct atspi_state_desc
452 {
453    Elm_Atspi_State_Type elm_state;
454    AtspiStateType atspi_state;
455    const char *name;
456 };
457
458 const struct atspi_state_desc elm_states_to_atspi_state[] = {
459    { ELM_ATSPI_STATE_INVALID, ATSPI_STATE_INVALID, "invalid" },
460    { ELM_ATSPI_STATE_ACTIVE, ATSPI_STATE_ACTIVE, "active" },
461    { ELM_ATSPI_STATE_ARMED, ATSPI_STATE_ARMED, "armed" },
462    { ELM_ATSPI_STATE_BUSY, ATSPI_STATE_BUSY, "busy" },
463    { ELM_ATSPI_STATE_CHECKED, ATSPI_STATE_CHECKED, "checked" },
464    { ELM_ATSPI_STATE_COLLAPSED, ATSPI_STATE_COLLAPSED, "collapsed" },
465    { ELM_ATSPI_STATE_DEFUNCT, ATSPI_STATE_DEFUNCT, "defunct" },
466    { ELM_ATSPI_STATE_EDITABLE, ATSPI_STATE_EDITABLE, "editable" },
467    { ELM_ATSPI_STATE_ENABLED, ATSPI_STATE_ENABLED, "enabled" },
468    { ELM_ATSPI_STATE_EXPANDABLE, ATSPI_STATE_EXPANDABLE, "expandable" },
469    { ELM_ATSPI_STATE_EXPANDED, ATSPI_STATE_EXPANDED, "expanded" },
470    { ELM_ATSPI_STATE_FOCUSABLE, ATSPI_STATE_FOCUSABLE, "focusable" },
471    { ELM_ATSPI_STATE_FOCUSED, ATSPI_STATE_FOCUSED, "focused" },
472    { ELM_ATSPI_STATE_HAS_TOOLTIP, ATSPI_STATE_HAS_TOOLTIP, "has-tooltip" },
473    { ELM_ATSPI_STATE_HORIZONTAL, ATSPI_STATE_HORIZONTAL, "horizontal" },
474    { ELM_ATSPI_STATE_ICONIFIED, ATSPI_STATE_ICONIFIED, "iconified" },
475    { ELM_ATSPI_STATE_MODAL, ATSPI_STATE_MODAL, "modal" },
476    { ELM_ATSPI_STATE_MULTI_LINE, ATSPI_STATE_MULTI_LINE, "multi-line" },
477    { ELM_ATSPI_STATE_MULTISELECTABLE, ATSPI_STATE_MULTISELECTABLE, "multiselectable" },
478    { ELM_ATSPI_STATE_OPAQUE, ATSPI_STATE_OPAQUE, "opaque" },
479    { ELM_ATSPI_STATE_PRESSED, ATSPI_STATE_PRESSED, "pressed" },
480    { ELM_ATSPI_STATE_RESIZABLE, ATSPI_STATE_RESIZABLE, "resizable" },
481    { ELM_ATSPI_STATE_SELECTABLE, ATSPI_STATE_SELECTABLE, "selectable" },
482    { ELM_ATSPI_STATE_SELECTED, ATSPI_STATE_SELECTED, "selected" },
483    { ELM_ATSPI_STATE_SENSITIVE, ATSPI_STATE_SENSITIVE, "sensitive" },
484    { ELM_ATSPI_STATE_SHOWING, ATSPI_STATE_SHOWING, "showing" },
485    { ELM_ATSPI_STATE_SINGLE_LINE, ATSPI_STATE_SINGLE_LINE, "single-line" },
486    { ELM_ATSPI_STATE_STALE, ATSPI_STATE_STALE, "stale" },
487    { ELM_ATSPI_STATE_TRANSIENT, ATSPI_STATE_TRANSIENT, "transient" },
488    { ELM_ATSPI_STATE_VERTICAL, ATSPI_STATE_VERTICAL, "vertical" },
489    { ELM_ATSPI_STATE_VISIBLE, ATSPI_STATE_VISIBLE, "visible" },
490    { ELM_ATSPI_STATE_MANAGES_DESCENDANTS, ATSPI_STATE_MANAGES_DESCENDANTS, "manages-descendants" },
491    { ELM_ATSPI_STATE_INDETERMINATE, ATSPI_STATE_INDETERMINATE, "indeterminate" },
492    { ELM_ATSPI_STATE_REQUIRED, ATSPI_STATE_REQUIRED, "required" },
493    { ELM_ATSPI_STATE_TRUNCATED, ATSPI_STATE_TRUNCATED, "truncated" },
494    { ELM_ATSPI_STATE_ANIMATED, ATSPI_STATE_ANIMATED, "animated" },
495    { ELM_ATSPI_STATE_INVALID_ENTRY, ATSPI_STATE_INVALID_ENTRY, "invalid-entry" },
496    { ELM_ATSPI_STATE_SUPPORTS_AUTOCOMPLETION, ATSPI_STATE_SUPPORTS_AUTOCOMPLETION, "supports-autocompletion" },
497    { ELM_ATSPI_STATE_SELECTABLE_TEXT, ATSPI_STATE_SELECTABLE_TEXT, "selectable-text" },
498    { ELM_ATSPI_STATE_IS_DEFAULT, ATSPI_STATE_IS_DEFAULT, "is-default" },
499    { ELM_ATSPI_STATE_VISITED, ATSPI_STATE_VISITED, "visited" },
500     //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods (29e253e2f7ef3c632ac3a64c489bf569df407f30)
501    { ELM_ATSPI_STATE_CHECKABLE, ATSPI_STATE_CHECKABLE, "checkable" },
502    { ELM_ATSPI_STATE_HAS_POPUP, ATSPI_STATE_HAS_POPUP, "has-popup" },
503    { ELM_ATSPI_STATE_READ_ONLY, ATSPI_STATE_READ_ONLY, "read-only" },
504    { ELM_ATSPI_STATE_HIGHLIGHTED, ATSPI_STATE_HIGHLIGHTED, "highlighted" },
505    { ELM_ATSPI_STATE_HIGHLIGHTABLE, ATSPI_STATE_HIGHLIGHTABLE, "highlightable" },
506    //
507    { ELM_ATSPI_STATE_LAST_DEFINED, ATSPI_STATE_LAST_DEFINED, "last-defined" }
508 };
509
510 const int elm_relation_to_atspi_relation_mapping[] = {
511    [ELM_ATSPI_RELATION_NULL] =  ATSPI_RELATION_NULL,
512    [ELM_ATSPI_RELATION_LABEL_FOR] =  ATSPI_RELATION_LABEL_FOR,
513    [ELM_ATSPI_RELATION_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY,
514    [ELM_ATSPI_RELATION_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR,
515    [ELM_ATSPI_RELATION_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY,
516    [ELM_ATSPI_RELATION_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF,
517    [ELM_ATSPI_RELATION_TOOLTIP_FOR] = ATSPI_RELATION_TOOLTIP_FOR,
518    [ELM_ATSPI_RELATION_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF,
519    [ELM_ATSPI_RELATION_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF,
520    [ELM_ATSPI_RELATION_EXTENDED] = ATSPI_RELATION_EXTENDED,
521    [ELM_ATSPI_RELATION_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO,
522    [ELM_ATSPI_RELATION_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM,
523    [ELM_ATSPI_RELATION_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF,
524    [ELM_ATSPI_RELATION_EMBEDS] = ATSPI_RELATION_EMBEDS,
525    [ELM_ATSPI_RELATION_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY,
526    [ELM_ATSPI_RELATION_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR,
527    [ELM_ATSPI_RELATION_PARENT_WINDOW_OF] = ATSPI_RELATION_PARENT_WINDOW_OF,
528    [ELM_ATSPI_RELATION_DESCRIPTION_FOR] = ATSPI_RELATION_DESCRIPTION_FOR,
529    [ELM_ATSPI_RELATION_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY,
530    [ELM_ATSPI_RELATION_LAST_DEFINED] = ATSPI_RELATION_LAST_DEFINED,
531 };
532
533 static inline Eldbus_Message *_dbus_invalid_ref_error_new(const Eldbus_Message *msg)
534 {
535   return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.UnknownObject", "Path is not valid accessible object reference.");
536 }
537
538 static AtspiRelationType _elm_relation_to_atspi_relation(Elm_Atspi_Relation_Type type)
539 {
540    if ((type < ELM_ATSPI_RELATION_LAST_DEFINED) && (type > ELM_ATSPI_RELATION_NULL))
541      return elm_relation_to_atspi_relation_mapping[type];
542    return ATSPI_RELATION_NULL;
543 }
544
545 static Elm_Atspi_Relation_Type _atspi_relation_to_elm_relation(AtspiRelationType type)
546 {
547    unsigned int i;
548    for(i = 0; i < sizeof(elm_relation_to_atspi_relation_mapping) / sizeof(elm_relation_to_atspi_relation_mapping[0]); ++i)
549      {
550        if (elm_relation_to_atspi_relation_mapping[i] == (int)type) return (Elm_Atspi_Relation_Type)i;
551      }
552    return ELM_ATSPI_RELATION_NULL;
553 }
554
555 static AtspiRole _elm_role_to_atspi_role(Elm_Atspi_Role role)
556 {
557    return role > ELM_ATSPI_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
558 }
559
560 static Eldbus_Message *
561 _accessible_get_role(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
562 {
563    const char *obj_path = eldbus_message_path_get(msg);
564    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
565    Eo *obj = _bridge_object_from_path(bridge, obj_path);
566    Elm_Atspi_Role role;
567
568    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
569
570    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
571
572    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
573    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
574
575    AtspiRole atspi_role = _elm_role_to_atspi_role(role);
576    eldbus_message_arguments_append(ret, "u", atspi_role);
577    return ret;
578 }
579
580 static Eldbus_Message *
581 _accessible_get_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
582 {
583    const char *role_name = NULL, *obj_path = eldbus_message_path_get(msg);
584    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
585    Eo *obj = _bridge_object_from_path(bridge, obj_path);
586
587    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
588
589    eo_do(obj, role_name = elm_interface_atspi_accessible_role_name_get());
590
591    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
592    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
593    eldbus_message_arguments_append(ret, "s", role_name);
594
595    return ret;
596 }
597
598 static Eldbus_Message *
599 _accessible_get_localized_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
600 {
601    const char *l_role_name = NULL, *obj_path = eldbus_message_path_get(msg);
602    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
603    Eo *obj = _bridge_object_from_path(bridge, obj_path);
604
605    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
606
607    eo_do(obj, l_role_name = elm_interface_atspi_accessible_localized_role_name_get());
608    EINA_SAFETY_ON_NULL_RETURN_VAL(l_role_name, NULL);
609
610    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
611    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
612    eldbus_message_arguments_append(ret, "s", l_role_name);
613
614    return ret;
615 }
616
617 static Eldbus_Message *
618 _accessible_get_children(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
619 {
620    const char *obj_path = eldbus_message_path_get(msg);
621    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
622    Eo *obj = _bridge_object_from_path(bridge, obj_path);
623    Eina_List *children_list = NULL, *l;
624    Eldbus_Message *ret;
625    Eldbus_Message_Iter *iter, *iter_array;
626    Eo *children;
627
628    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
629
630    eo_do(obj, children_list = elm_interface_atspi_accessible_children_get());
631
632    ret = eldbus_message_method_return_new(msg);
633    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
634
635    iter = eldbus_message_iter_get(ret);
636    iter_array = eldbus_message_iter_container_new(iter, 'a', "(so)");
637    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
638
639    EINA_LIST_FOREACH(children_list, l, children)
640      {
641         _bridge_iter_object_reference_append(bridge, iter_array, children);
642         _bridge_object_register(bridge, children);
643      }
644
645    eldbus_message_iter_container_close(iter, iter_array);
646    eina_list_free(children_list);
647
648    return ret;
649
650 fail:
651    if (ret) eldbus_message_unref(ret);
652    return NULL;
653 }
654
655 static Eldbus_Message *
656 _accessible_get_application(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
657 {
658    Eldbus_Message *ret;
659    const char *obj_path = eldbus_message_path_get(msg);
660    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
661    Eo *obj = _bridge_object_from_path(bridge, obj_path);
662
663    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
664
665    ret = eldbus_message_method_return_new(msg);
666    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
667
668    Eldbus_Message_Iter *iter = eldbus_message_iter_get(ret);
669    _bridge_iter_object_reference_append(bridge, iter, elm_atspi_bridge_root_get(bridge));
670
671    return ret;
672 }
673
674 static Eldbus_Message *
675 _accessible_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
676 {
677    Eina_List *attrs, *l;
678    Elm_Atspi_Attribute *attr;
679    Eldbus_Message_Iter *iter, *iter_dict, *iter_entry;
680    Eldbus_Message *ret;
681
682    const char *obj_path = eldbus_message_path_get(msg);
683    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
684    Eo *obj = _bridge_object_from_path(bridge, obj_path);
685
686    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
687
688    ret = eldbus_message_method_return_new(msg);
689    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
690
691    eo_do(obj, attrs = elm_interface_atspi_accessible_attributes_get());
692
693    iter = eldbus_message_iter_get(ret);
694    iter_dict = eldbus_message_iter_container_new(iter, 'a', "{ss}");
695    EINA_SAFETY_ON_NULL_RETURN_VAL(iter_dict, NULL);
696
697    EINA_LIST_FOREACH(attrs, l, attr)
698      {
699         iter_entry = eldbus_message_iter_container_new(iter_dict, 'e', NULL);
700         EINA_SAFETY_ON_NULL_RETURN_VAL(iter_entry, NULL);
701         eldbus_message_iter_arguments_append(iter_entry, "ss", attr->key, attr->value);
702         eldbus_message_iter_container_close(iter_dict, iter_entry);
703      }
704
705    eldbus_message_iter_container_close(iter, iter_dict);
706    elm_atspi_attributes_list_free(attrs);
707
708    return ret;
709 }
710
711 static Eldbus_Message *
712 _accessible_interfaces_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
713 {
714    Eldbus_Message *ret;
715    Eldbus_Message_Iter *iter;
716    const char *obj_path = eldbus_message_path_get(msg);
717    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
718    Eo *obj = _bridge_object_from_path(bridge, obj_path);
719
720    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
721
722    ret = eldbus_message_method_return_new(msg);
723    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
724
725    iter = eldbus_message_iter_get(ret);
726    _iter_interfaces_append(iter, obj);
727
728    return ret;
729 }
730
731 static uint64_t
732 _elm_atspi_state_set_to_atspi_state_set(Elm_Atspi_State_Set states)
733 {
734    uint64_t ret = 0;
735    unsigned int i = 0;
736
737    for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
738      {
739         if (STATE_TYPE_GET(states, elm_states_to_atspi_state[i].elm_state))
740           STATE_TYPE_SET(ret, elm_states_to_atspi_state[i].atspi_state);
741      }
742    return ret;
743 }
744
745 static Elm_Atspi_State_Set
746 _atspi_state_set_to_elm_atspi_state_set(uint64_t states)
747 {
748    //Currently Elm_Atspi_State and Atspi_State_Set are binary compatible,
749    //implement proper coversion when it will be needed.
750    Elm_Atspi_State_Set ret = states;
751    return ret;
752 }
753
754 static Eina_Hash*
755 _elm_atspi_state_hash_build(void)
756 {
757    Eina_Hash *ret = eina_hash_string_superfast_new(NULL);
758    unsigned int i = 0;
759
760    for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
761      eina_hash_add(ret, elm_states_to_atspi_state[i].name, &elm_states_to_atspi_state[i]);
762
763    return ret;
764 }
765
766 static Eina_Hash*
767 _elm_atspi_event_hash_build(void)
768 {
769    Eina_Hash *ret = eina_hash_pointer_new(NULL);
770    unsigned int i = 0;
771
772    for (i = 0; i < SIZE(event_handlers); i++)
773      eina_hash_add(ret, &(event_handlers[i].desc), event_handlers[i].callback);
774
775    return ret;
776 }
777
778 static Eldbus_Message *
779 _accessible_get_state(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
780 {
781    Eldbus_Message *ret;
782    Eldbus_Message_Iter *iter, *iter_array;
783    Elm_Atspi_State_Set states;
784    uint64_t atspi_states = 0;
785
786    const char *obj_path = eldbus_message_path_get(msg);
787    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
788    Eo *obj = _bridge_object_from_path(bridge, obj_path);
789
790    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
791
792    ret = eldbus_message_method_return_new(msg);
793    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
794
795    iter = eldbus_message_iter_get(ret);
796    iter_array = eldbus_message_iter_container_new(iter, 'a', "u");
797    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
798
799    eo_do(obj, states = elm_interface_atspi_accessible_state_set_get());
800
801    atspi_states = _elm_atspi_state_set_to_atspi_state_set(states);
802
803    unsigned int s1 = atspi_states & 0xFFFFFFFF;
804    unsigned int s2 = (atspi_states >> 32) & 0xFFFFFFFF;
805
806    eldbus_message_iter_basic_append(iter_array, 'u', s1);
807    eldbus_message_iter_basic_append(iter_array, 'u', s2);
808    eldbus_message_iter_container_close(iter, iter_array);
809
810    return ret;
811
812 fail:
813    if (ret) eldbus_message_unref(ret);
814    return NULL;
815 }
816
817 static Eldbus_Message *
818 _accessible_get_index_in_parent(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
819 {
820    const char *obj_path = eldbus_message_path_get(msg);
821    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
822    Eo *obj = _bridge_object_from_path(bridge, obj_path);
823    Eldbus_Message *ret;
824    int idx = -1;
825
826    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
827
828    ret = eldbus_message_method_return_new(msg);
829    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
830
831    eo_do(obj, idx = elm_interface_atspi_accessible_index_in_parent_get());
832
833    eldbus_message_arguments_append(ret, "i", idx);
834
835    return ret;
836 }
837
838 static Eldbus_Message *
839 _accessible_child_at_index(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
840 {
841    const char *obj_path = eldbus_message_path_get(msg);
842    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
843    Eo *obj = _bridge_object_from_path(bridge, obj_path);
844    Eo *child = NULL;
845    Eina_List *children = NULL;
846    int idx;
847    Eldbus_Message *ret;
848    Eldbus_Message_Iter *iter;
849
850    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
851
852    if (!eldbus_message_arguments_get(msg, "i", &idx))
853      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
854
855    ret = eldbus_message_method_return_new(msg);
856    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
857
858    iter = eldbus_message_iter_get(ret);
859    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
860
861    child = eina_list_nth(children, idx);
862    _bridge_iter_object_reference_append(bridge, iter, child);
863    _bridge_object_register(bridge, child);
864    eina_list_free(children);
865
866    return ret;
867 }
868
869 static Eldbus_Message *
870 _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
871 {
872    const char *obj_path = eldbus_message_path_get(msg);
873    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
874    Eo *rel_obj, *obj = _bridge_object_from_path(bridge, obj_path);
875    Eldbus_Message *ret = NULL;
876    Eldbus_Message_Iter *iter = NULL, *iter_array = NULL, *iter_array2 = NULL, *iter_struct;
877    Elm_Atspi_Relation *rel;
878    Eina_List *l, *l2;
879    Elm_Atspi_Relation_Set rels;
880
881    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
882
883    ret = eldbus_message_method_return_new(msg);
884    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
885
886    iter = eldbus_message_iter_get(ret);
887    iter_array = eldbus_message_iter_container_new(iter, 'a', "(ua(so))");
888    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
889
890    eo_do(obj, rels = elm_interface_atspi_accessible_relation_set_get());
891
892    EINA_LIST_FOREACH(rels, l, rel)
893      {
894         iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
895         eldbus_message_iter_basic_append(iter_struct, 'u', _elm_relation_to_atspi_relation(rel->type));
896         iter_array2 = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
897         EINA_SAFETY_ON_NULL_GOTO(iter_array2, fail);
898         EINA_LIST_FOREACH(rel->objects, l2, rel_obj)
899           {
900              _bridge_iter_object_reference_append(bridge, iter_array2, rel_obj);
901              _bridge_object_register(bridge, rel_obj);
902           }
903         eldbus_message_iter_container_close(iter_struct, iter_array2);
904         eldbus_message_iter_container_close(iter_array, iter_struct);
905      }
906    elm_atspi_relation_set_free(&rels);
907    eldbus_message_iter_container_close(iter, iter_array);
908
909    return ret;
910
911 fail:
912    return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get relation set.");
913 }
914
915 //TIZEN_ONLY(20170405) Add gesture method to accessible interface
916 static Eldbus_Message *
917 _accessible_gesture_do(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
918 {
919    const char *obj_path = eldbus_message_path_get(msg);
920    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
921    Eo *obj = _bridge_object_from_path(bridge, obj_path);
922    int type, x_beg, y_beg, x_end, y_end, state;
923    unsigned int event_time;
924    Eldbus_Message *ret;
925    Eina_Bool result = EINA_FALSE;
926
927    if (!eldbus_message_arguments_get(msg, "iiiiiiu", &type, &x_beg, &y_beg,
928                                      &x_end, &y_end, &state, &event_time))
929      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
930
931    ret = eldbus_message_method_return_new(msg);
932    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
933
934    Elm_Atspi_Gesture_Info gesture_info;
935    gesture_info.type = (Elm_Atspi_Gesture_Type)type;
936    gesture_info.x_beg = x_beg;
937    gesture_info.y_beg = y_beg;
938    gesture_info.x_end = x_end;
939    gesture_info.y_end = y_end;
940    gesture_info.state = (Elm_Atspi_Gesture_State)state;
941    gesture_info.event_time = event_time;
942    eo_do(obj, result = elm_interface_atspi_accessible_gesture_do(gesture_info));
943    eldbus_message_arguments_append(ret, "b", result);
944    return ret;
945 }
946 //
947
948 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
949 static Eldbus_Message *
950 _accessible_get_neighbor(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
951 {
952    const char *start_path = eldbus_message_path_get(msg);
953    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
954    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
955    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
956    //
957    Eo *start = _bridge_object_from_path(bridge, start_path);
958    Eldbus_Message *ret;
959    Eldbus_Message_Iter *iter;
960    int direction, search_mode;
961
962    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(start, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
963
964    char *root_path = "";
965    if (!eldbus_message_arguments_get(msg, "sii", &root_path, &direction, &search_mode))
966      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
967
968    Eo *root = _bridge_object_from_path(bridge, root_path);
969
970    // TIZEN_ONLY(20161213) - do not response if ecore evas is obscured
971    if (root)
972      {
973         const Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(root));
974         if (ecore_evas_obscured_get(ee))
975           return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "ecore evas is obscured.");
976      }
977    //
978
979    ret = eldbus_message_method_return_new(msg);
980    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
981
982    iter = eldbus_message_iter_get(ret);
983
984    Eo *accessible = _calculate_neighbor(bridge, root, start, direction == 1, search_mode);
985    _bridge_iter_object_reference_append(bridge, iter, accessible);
986    _bridge_object_register(bridge, accessible);
987
988    const char *obj_bus_name = NULL, *ret_bus_name = NULL;
989    _object_get_bus_name_and_path(bridge, start, &obj_bus_name, NULL);
990    if (accessible) _object_get_bus_name_and_path(bridge, accessible, &ret_bus_name, NULL);
991
992    unsigned char recurse = obj_bus_name && ret_bus_name && strcmp(obj_bus_name, ret_bus_name) != 0;
993    eldbus_message_iter_basic_append(iter, 'y', recurse);
994    return ret;
995 }
996
997 static Eldbus_Message *
998 _accessible_get_navigable_at_point(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
999 {
1000    const char *obj_path = eldbus_message_path_get(msg);
1001    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1002    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
1003    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
1004    //
1005    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1006    int x, y;
1007    Eldbus_Message *ret;
1008    AtspiCoordType coord_type;
1009    Eldbus_Message_Iter *iter;
1010
1011    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
1012
1013    // TIZEN_ONLY(20161213) - do not response if ecore evas is obscured
1014    const Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1015    if (ecore_evas_obscured_get(ee))
1016      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "ecore evas is obscured.");
1017    //
1018
1019    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
1020      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1021
1022    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
1023    Evas_Object *top = elm_object_top_widget_get(obj);
1024    int sx = 0;
1025    int sy = 0;
1026    eo_do(top, elm_interface_atspi_component_socket_offset_get(&sx, &sy));
1027    x = x - sx;
1028    y = y - sy;
1029    //
1030
1031    ret = eldbus_message_method_return_new(msg);
1032    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1033
1034    iter = eldbus_message_iter_get(ret);
1035
1036    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1037    Eo *accessible = _calculate_navigable_accessible_at_point(bridge, obj, type, x, y);
1038
1039    /* Check deputy */
1040    Eo *deputy = NULL;
1041    if (accessible && eo_isa(accessible, ELM_ACCESS_CLASS))
1042      {
1043         Evas_Object *parent = elm_widget_parent_get(accessible);
1044
1045         Elm_Widget_Smart_Data *wd;
1046         wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
1047         if (wd)
1048           {
1049              Eina_List *l;
1050              Evas_Object *widget;
1051
1052              EINA_LIST_FOREACH(wd->subobjs, l, widget)
1053                {
1054                   Eo *proxy;
1055
1056                   proxy = evas_object_data_get(widget, "__widget_proxy");
1057                   if (proxy)
1058                     {
1059                        int px, py, pw, ph;
1060                        evas_object_geometry_get(widget, &px, &py, &pw, &ph);
1061                        if (x >= px && x <= px + pw && y >= py && y <= py +ph)
1062                          {
1063                             /* proxy is also selectable */
1064                             deputy = accessible;
1065                             accessible = proxy;
1066                             break;
1067                          }
1068                     }
1069                }
1070           }
1071      }
1072
1073    _bridge_iter_object_reference_append(bridge, iter, accessible);
1074    _bridge_object_register(bridge, accessible);
1075
1076    const char *obj_bus_name = NULL, *ret_bus_name = NULL;
1077    _object_get_bus_name_and_path(bridge, obj, &obj_bus_name, NULL);
1078    if (accessible) _object_get_bus_name_and_path(bridge, accessible, &ret_bus_name, NULL);
1079    unsigned char recurse = obj_bus_name && ret_bus_name && strcmp(obj_bus_name, ret_bus_name) != 0;
1080    eldbus_message_iter_basic_append(iter, 'y', recurse);
1081
1082    /* Send deputy */
1083    _bridge_iter_object_reference_append(bridge, iter, deputy);
1084    if (deputy) _bridge_object_register(bridge, deputy);
1085
1086    return ret;
1087 }
1088 //
1089
1090 //TIZEN_ONLY(20170531): add "GetReadingMaterial" interface method
1091 static int
1092 _list_children_count_check(Eo *obj)
1093 {
1094    int i;
1095    int list_count = 0;
1096    Eina_List *children;
1097    Eo *child = NULL;
1098    Elm_Atspi_Role role;
1099
1100    if (!obj)
1101      return 0;
1102
1103    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
1104    if (role == ELM_ATSPI_ROLE_LIST)
1105      {
1106         int children_count = 0;
1107         eo_do(obj, children = elm_interface_atspi_accessible_children_get());
1108         children_count = eina_list_count(children);
1109
1110         for (i = 0; i < children_count; i++)
1111           {
1112              child = eina_list_nth(children, i);
1113              eo_do(child, role = elm_interface_atspi_accessible_role_get());
1114              if (role == ELM_ATSPI_ROLE_LIST_ITEM)
1115                list_count++;
1116           }
1117         eina_list_free(children);
1118      }
1119
1120    return list_count;
1121 }
1122
1123 static int
1124 _list_children_count(Eo *obj)
1125 {
1126    Eina_List *children;
1127    int list_items_count = 0;
1128    int children_count = 0;
1129
1130    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
1131    children_count = eina_list_count(children);
1132
1133    int i;
1134    Eo *child = NULL;
1135
1136    list_items_count = _list_children_count_check(obj);
1137    if (list_items_count > 0)
1138      {
1139         eina_list_free(children);
1140         return list_items_count;
1141      }
1142
1143    for (i = 0; i < children_count; i++)
1144      {
1145         child = eina_list_nth(children, i);
1146         list_items_count = _list_children_count(child);
1147         if (list_items_count > 0)
1148           {
1149              eina_list_free(children);
1150              return list_items_count;
1151           }
1152      }
1153
1154    return 0;
1155 }
1156
1157 static Eldbus_Message *
1158 _accessible_reading_material_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1159 {
1160    Eldbus_Message *ret;
1161    Eldbus_Message_Iter *iter, *iter_array, *iter_dict, *iter_entry;
1162    Eina_List *attrs, *l, *children;
1163    const char *name = NULL;
1164    unsigned int s1, s2;
1165    double value = 0;
1166    double increment = 0;
1167    double max_value = 0;
1168    double min_value = 0;
1169    int idx = 0;
1170    int child_count = 0;
1171    int selected_child_count = 0;
1172    uint64_t atspi_states = 0;
1173    Elm_Atspi_Role role;
1174    Elm_Atspi_Attribute *attr;
1175    Elm_Atspi_State_Set states;
1176    Elm_Atspi_Relation_Set rels = NULL;
1177    Elm_Atspi_Relation *rel;
1178    Eo *relation_obj = NULL;
1179    Eo *parent = NULL;
1180    Eo *child = NULL;
1181    Eina_Bool is_selected = EINA_FALSE;
1182    AtspiRole atspi_role = ATSPI_ROLE_INVALID;
1183
1184    const char *obj_path = eldbus_message_path_get(msg);
1185    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1186    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1187
1188    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
1189
1190    ret = eldbus_message_method_return_new(msg);
1191    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1192
1193    iter = eldbus_message_iter_get(ret);
1194    /* attributes */
1195    eo_do(obj, attrs = elm_interface_atspi_accessible_attributes_get());
1196    iter_dict = eldbus_message_iter_container_new(iter, 'a', "{ss}");
1197    EINA_SAFETY_ON_NULL_RETURN_VAL(iter_dict, NULL);
1198    EINA_LIST_FOREACH(attrs, l, attr)
1199      {
1200         iter_entry = eldbus_message_iter_container_new(iter_dict, 'e', NULL);
1201         EINA_SAFETY_ON_NULL_RETURN_VAL(iter_entry, NULL);
1202         eldbus_message_iter_arguments_append(iter_entry, "ss", attr->key, attr->value);
1203         eldbus_message_iter_container_close(iter_dict, iter_entry);
1204      }
1205
1206    eldbus_message_iter_container_close(iter, iter_dict);
1207    elm_atspi_attributes_list_free(attrs);
1208
1209    /* name */
1210    eo_do(obj, name = elm_interface_atspi_accessible_name_get());
1211    if (!name)
1212      name = "";
1213    eldbus_message_iter_basic_append(iter, 's', name);
1214
1215    /* name - LABELED_BY relation */
1216    eo_do(obj, rels = elm_interface_atspi_accessible_relation_set_get());
1217    EINA_LIST_FOREACH(rels, l, rel)
1218      {
1219         if (rel->type == ELM_ATSPI_RELATION_LABELLED_BY)
1220           {
1221              int last_index = eina_list_count(rel->objects) - 1;
1222              relation_obj = eina_list_nth(rel->objects, last_index);
1223              break;
1224           }
1225      }
1226    eo_do(relation_obj, name = elm_interface_atspi_accessible_name_get());
1227    if (!name)
1228      name = "";
1229    eldbus_message_iter_basic_append(iter, 's', name);
1230
1231    /* name - text interface */
1232    name = NULL;
1233    if (eo_isa(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE))
1234      {
1235         int val;
1236         eo_do(obj, val = elm_interface_atspi_text_character_count_get());
1237         eo_do(obj, name = elm_interface_atspi_text_get(0, val));
1238      }
1239    if (!name)
1240      name = "";
1241    eldbus_message_iter_basic_append(iter, 's', name);
1242
1243    /* role */
1244    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
1245    atspi_role = role > ELM_ATSPI_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
1246    eldbus_message_iter_basic_append(iter, 'u', atspi_role);
1247
1248    /* states */
1249    iter_array = eldbus_message_iter_container_new(iter, 'a', "u");
1250    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
1251    eo_do(obj, states = elm_interface_atspi_accessible_state_set_get());
1252    atspi_states = _elm_atspi_state_set_to_atspi_state_set(states);
1253    s1 = atspi_states & 0xFFFFFFFF;
1254    s2 = (atspi_states >> 32) & 0xFFFFFFFF;
1255    eldbus_message_iter_basic_append(iter_array, 'u', s1);
1256    eldbus_message_iter_basic_append(iter_array, 'u', s2);
1257    eldbus_message_iter_container_close(iter, iter_array);
1258
1259    /* localized role name */
1260    eo_do(obj, name = elm_interface_atspi_accessible_localized_role_name_get());
1261    if (!name)
1262      name = "";
1263    eldbus_message_iter_basic_append(iter, 's', name);
1264
1265    /* child count */
1266    eo_do(obj, l = elm_interface_atspi_accessible_children_get());
1267    eldbus_message_iter_basic_append(iter, 'i', eina_list_count(l));
1268    eina_list_free(l);
1269
1270    /* current value, increment, max, min */
1271    value = 0;
1272    increment = 0;
1273    max_value = 0;
1274    min_value = 0;
1275    if (eo_isa(obj, ELM_INTERFACE_ATSPI_VALUE_INTERFACE))
1276      {
1277         eo_do(obj, elm_interface_atspi_value_and_text_get(&value, NULL));
1278         eo_do(obj, increment = elm_interface_atspi_value_increment_get());
1279         eo_do(obj, elm_interface_atspi_value_range_get(&min_value, &max_value, NULL));
1280      }
1281    eldbus_message_iter_basic_append(iter, 'd', value);
1282    eldbus_message_iter_basic_append(iter, 'd', increment);
1283    eldbus_message_iter_basic_append(iter, 'd', max_value);
1284    eldbus_message_iter_basic_append(iter, 'd', min_value);
1285
1286    /* description */
1287    eo_do(obj, name = elm_interface_atspi_accessible_description_get());
1288    if (!name)
1289      name = "";
1290    eldbus_message_iter_basic_append(iter, 's', name);
1291
1292    /* index in parent */
1293    eo_do(obj, idx = elm_interface_atspi_accessible_index_in_parent_get());
1294    eldbus_message_iter_basic_append(iter, 'i', idx);
1295
1296    /* is selected in parent */
1297    eo_do(obj, parent = elm_interface_atspi_accessible_parent_get());
1298    if (eo_isa(parent, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE))
1299      {
1300         eo_do(parent, is_selected = elm_interface_atspi_selection_is_child_selected(idx));
1301      }
1302    eldbus_message_arguments_append(ret, "b", is_selected);
1303
1304    /* has checkbox child */
1305    is_selected = EINA_FALSE;
1306    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
1307    EINA_LIST_FOREACH(children, l, child)
1308      {
1309         if (eo_isa(child, ELM_CHECK_CLASS))
1310           {
1311              is_selected = EINA_TRUE;
1312              break;
1313           }
1314      }
1315    eldbus_message_iter_basic_append(iter, 'b', is_selected);
1316    eina_list_free(children);
1317
1318    /* list children count */
1319    child_count = 0;
1320    if (role == ELM_ATSPI_ROLE_DIALOG)
1321      {
1322         child_count = _list_children_count(obj);
1323      }
1324    eldbus_message_iter_basic_append(iter, 'i', child_count);
1325
1326    /* first selected child index */
1327    idx = 0;
1328    if (eo_isa(obj, ELM_INDEX_CLASS))
1329      {
1330         eo_do(obj, children = elm_interface_atspi_accessible_children_get());
1331         EINA_LIST_FOREACH(children, l, child)
1332           {
1333              eo_do(child, states = elm_interface_atspi_accessible_state_set_get());
1334              if (STATE_TYPE_GET(states, ELM_ATSPI_STATE_SELECTED))
1335                break;
1336              idx++;
1337           }
1338         eina_list_free(children);
1339      }
1340    eldbus_message_iter_basic_append(iter, 'i', idx);
1341
1342    /* parent */
1343    role = ELM_ATSPI_ROLE_INVALID;
1344    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
1345    if ((!parent) && (ELM_ATSPI_ROLE_APPLICATION == role))
1346      _object_desktop_reference_append(iter);
1347    else
1348      _bridge_iter_object_reference_append(bridge, iter, parent);
1349
1350    /* parent - states */
1351    iter_array = eldbus_message_iter_container_new(iter, 'a', "u");
1352    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
1353    eo_do(parent, states = elm_interface_atspi_accessible_state_set_get());
1354    atspi_states = _elm_atspi_state_set_to_atspi_state_set(states);
1355    s1 = atspi_states & 0xFFFFFFFF;
1356    s2 = (atspi_states >> 32) & 0xFFFFFFFF;
1357    eldbus_message_iter_basic_append(iter_array, 'u', s1);
1358    eldbus_message_iter_basic_append(iter_array, 'u', s2);
1359    eldbus_message_iter_container_close(iter, iter_array);
1360
1361    /* parent - child count */
1362    eo_do(parent, l = elm_interface_atspi_accessible_children_get());
1363    eldbus_message_iter_basic_append(iter, 'i', eina_list_count(l));
1364    eina_list_free(l);
1365
1366    /* parent - role */
1367    eo_do(parent, role = elm_interface_atspi_accessible_role_get());
1368    atspi_role = role > ELM_ATSPI_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
1369    eldbus_message_iter_basic_append(iter, 'u', atspi_role);
1370
1371    /* parent - child count */
1372    if (eo_isa(parent, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE))
1373      {
1374         eo_do(parent, selected_child_count = elm_interface_atspi_selection_selected_children_count_get());
1375      }
1376    eldbus_message_iter_basic_append(iter, 'i', selected_child_count);
1377
1378    /* relation object - DESCRIBED_BY */
1379    relation_obj = NULL;
1380    EINA_LIST_FOREACH(rels, l, rel)
1381      {
1382         if (rel->type == ELM_ATSPI_RELATION_DESCRIBED_BY)
1383           {
1384              int last_index = eina_list_count(rel->objects) - 1;
1385              relation_obj = eina_list_nth(rel->objects, last_index);
1386              break;
1387           }
1388      }
1389    _bridge_iter_object_reference_append(bridge, iter, relation_obj);
1390    elm_atspi_relation_set_free(&rels);
1391
1392    return ret;
1393
1394 fail:
1395    if (rels) elm_atspi_relation_set_free(&rels);
1396    if (ret) eldbus_message_unref(ret);
1397    return NULL;
1398 }
1399 //
1400 //TIZEN_ONLY(20170919): Handle default label object
1401 static Eldbus_Message *
1402 _accessible_default_label_info_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1403 {
1404    Eldbus_Message *ret;
1405    Eldbus_Message_Iter *iter;
1406    const char *obj_path = eldbus_message_path_get(msg);
1407    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1408    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1409    Eo *default_label_obj;
1410    Elm_Atspi_Role role;
1411    AtspiRole atspi_role = ATSPI_ROLE_INVALID;
1412
1413    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
1414
1415    ret = eldbus_message_method_return_new(msg);
1416    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1417
1418    iter = eldbus_message_iter_get(ret);
1419
1420     default_label_obj = _elm_win_default_label_obj_get(obj);
1421     if (!default_label_obj) default_label_obj = obj;
1422    _bridge_iter_object_reference_append(bridge, iter, default_label_obj);
1423    _bridge_object_register(bridge, default_label_obj);
1424
1425    eo_do(default_label_obj, role = elm_interface_atspi_accessible_role_get());
1426    atspi_role = role > ELM_ATSPI_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
1427    eldbus_message_iter_basic_append(iter, 'u', atspi_role);
1428
1429    return ret;
1430 }
1431 //
1432
1433 static const Eldbus_Method accessible_methods[] = {
1434 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
1435    { "GetNavigableAtPoint", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"(so)y", "accessible"}, {"(so)", "deputy"}), _accessible_get_navigable_at_point, 0 },
1436    { "GetNeighbor", ELDBUS_ARGS({"s", "current"}, {"i", "direction"}, {"i", "force_next"}), ELDBUS_ARGS({"(so)y", "accessible"}), _accessible_get_neighbor, 0 },
1437 //
1438    { "GetChildAtIndex", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"(so)", "Accessible"}), _accessible_child_at_index, 0 },
1439    { "GetChildren", NULL, ELDBUS_ARGS({"a(so)", "children"}), _accessible_get_children, 0 },
1440    { "GetIndexInParent", NULL, ELDBUS_ARGS({"i", "index"}), _accessible_get_index_in_parent, 0 },
1441    { "GetRelationSet", NULL, ELDBUS_ARGS({"a(ua(so))", NULL}), _accessible_get_relation_set, 0 },
1442    { "GetRole", NULL, ELDBUS_ARGS({"u", "Role"}), _accessible_get_role, 0 },
1443    { "GetRoleName", NULL, ELDBUS_ARGS({"s", "Name"}), _accessible_get_role_name, 0 },
1444    { "GetLocalizedRoleName", NULL, ELDBUS_ARGS({"s", "LocalizedName"}), _accessible_get_localized_role_name, 0},
1445    { "GetState", NULL, ELDBUS_ARGS({"au", NULL}), _accessible_get_state, 0},
1446    { "GetApplication", NULL, ELDBUS_ARGS({"(so)", NULL}), _accessible_get_application, 0},
1447    { "GetAttributes", NULL, ELDBUS_ARGS({"a{ss}", NULL}), _accessible_attributes_get, 0},
1448    { "GetInterfaces", NULL, ELDBUS_ARGS({"as", NULL}), _accessible_interfaces_get, 0},
1449    //TIZEN_ONLY(20170405) Add gesture method to accessible interface
1450    { "DoGesture",
1451      ELDBUS_ARGS({"i", "type"}, {"i", "x_beg"}, {"i", "y_beg"},
1452                  {"i", "x_end"}, {"i", "y_end"}, {"i", "state"},
1453                  {"u", "event_time"}),
1454      ELDBUS_ARGS({"b", "result"}), _accessible_gesture_do, 0},
1455    //
1456    //TIZEN_ONLY(20170531): add "GetReadingMaterial" interface method
1457    { "GetReadingMaterial",
1458      NULL,
1459      ELDBUS_ARGS({"a{ss}", "attributes"}, {"s", "name"},
1460                  {"s", "labledByName"},{"s", "textIfceName"},
1461                  {"u", "role"}, {"au", "stateSet"},
1462                  {"s", "localizedName"}, {"i", "childCount"},
1463                  {"d", "currentValue"},{"d", "minimumIncrement"},
1464                  {"d", "maximumValue"},{"d", "minimumValue"},
1465                  {"s", "description"}, {"i", "indexInParent"},
1466                  {"b", "isSelectedInParent"}, {"b", "hasCheckboxChild"},
1467                  {"i", "listChildrenCount"},
1468                  {"i", "firstSelectedChildIndex"},
1469                  {"(so)", "parent"}, {"au", "parentStateSet"},
1470                  {"i", "parentChildCount"}, {"u", "parentRole"},
1471                  {"i", "selectedChildCount"},
1472                  {"(so)", "describecByObject"}),
1473      _accessible_reading_material_get, 0},
1474    //
1475    //TIZEN_ONLY(20170919): Handle default label object
1476    { "GetDefaultLabelInfo",
1477      NULL, ELDBUS_ARGS({"(so)", "defaultLabelObject"}, {"u", "defaultLabelRole"}),
1478      _accessible_default_label_info_get, 0},
1479    //
1480    { NULL, NULL, NULL, NULL, 0 }
1481 };
1482
1483 static Eina_Bool
1484 _is_operation_permitted(Eo *obj)
1485 {
1486    Elm_Atspi_State_Set states;
1487    eo_do(obj, states = elm_interface_atspi_accessible_state_set_get());
1488
1489    if (!STATE_TYPE_GET(states, ELM_ATSPI_STATE_SHOWING)) return EINA_FALSE;
1490
1491    Eo *parent = obj;
1492    while (parent)
1493      {
1494         if (evas_object_freeze_events_get(parent)) return EINA_FALSE;
1495         parent = evas_object_smart_parent_get(parent);
1496      }
1497    return EINA_TRUE;
1498 }
1499
1500 static Eldbus_Message *
1501 _selection_selected_child_get(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
1502 {
1503    const char *obj_path = eldbus_message_path_get(msg);
1504    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1505    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1506    Eo *child = NULL;
1507
1508    int idx;
1509    Eldbus_Message *ret;
1510    Eldbus_Message_Iter *iter;
1511
1512    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1513
1514    if (!eldbus_message_arguments_get(msg, "i", &idx))
1515      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1516
1517    ret = eldbus_message_method_return_new(msg);
1518    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1519
1520    iter = eldbus_message_iter_get(ret);
1521    eo_do(obj, child = elm_interface_atspi_selection_selected_child_get(idx));
1522
1523    _bridge_iter_object_reference_append(bridge, iter, child);
1524    _bridge_object_register(bridge, child);
1525
1526    return ret;
1527 }
1528
1529 static Eldbus_Message *
1530 _selection_child_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1531 {
1532    const char *obj_path = eldbus_message_path_get(msg);
1533    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1534    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1535    int idx;
1536    Eldbus_Message *ret;
1537    Eina_Bool result = EINA_FALSE;
1538
1539    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1540
1541    if (!eldbus_message_arguments_get(msg, "i", &idx))
1542      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1543
1544    ret = eldbus_message_method_return_new(msg);
1545    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1546
1547    if (_is_operation_permitted(obj))
1548      eo_do(obj, result = elm_interface_atspi_selection_child_select(idx));
1549    eldbus_message_arguments_append(ret, "b", result);
1550
1551    return ret;
1552 }
1553
1554 static Eldbus_Message *
1555 _selection_selected_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1556 {
1557    const char *obj_path = eldbus_message_path_get(msg);
1558    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1559    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1560    int idx;
1561    Eldbus_Message *ret;
1562    Eina_Bool result = EINA_FALSE;
1563
1564    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1565
1566    if (!eldbus_message_arguments_get(msg, "i", &idx))
1567      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1568
1569    ret = eldbus_message_method_return_new(msg);
1570    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1571
1572    if (_is_operation_permitted(obj))
1573      eo_do(obj, result = elm_interface_atspi_selection_selected_child_deselect(idx));
1574    eldbus_message_arguments_append(ret, "b", result);
1575
1576    return ret;
1577 }
1578
1579 static Eldbus_Message *
1580 _selection_is_child_selected(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1581 {
1582    const char *obj_path = eldbus_message_path_get(msg);
1583    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1584    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1585    int idx;
1586    Eldbus_Message *ret;
1587    Eina_Bool result;
1588
1589    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1590
1591    if (!eldbus_message_arguments_get(msg, "i", &idx))
1592      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1593
1594    ret = eldbus_message_method_return_new(msg);
1595    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1596
1597    eo_do(obj, result = elm_interface_atspi_selection_is_child_selected(idx));
1598    eldbus_message_arguments_append(ret, "b", result);
1599
1600    return ret;
1601 }
1602
1603 static Eldbus_Message *
1604 _selection_all_children_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1605 {
1606    const char *obj_path = eldbus_message_path_get(msg);
1607    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1608    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1609    Eldbus_Message *ret;
1610    Eina_Bool result = EINA_FALSE;
1611
1612    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1613
1614    ret = eldbus_message_method_return_new(msg);
1615    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1616
1617    if (_is_operation_permitted(obj))
1618      eo_do(obj, result = elm_interface_atspi_selection_all_children_select());
1619    eldbus_message_arguments_append(ret, "b", result);
1620
1621    return ret;
1622 }
1623
1624 static Eldbus_Message *
1625 _selection_clear(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1626 {
1627    const char *obj_path = eldbus_message_path_get(msg);
1628    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1629    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1630    Eldbus_Message *ret;
1631    Eina_Bool result = EINA_FALSE;
1632
1633    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1634
1635    ret = eldbus_message_method_return_new(msg);
1636    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1637
1638    if (_is_operation_permitted(obj))
1639      eo_do(obj, result = elm_interface_atspi_selection_clear());
1640    eldbus_message_arguments_append(ret, "b", result);
1641
1642    return ret;
1643 }
1644
1645 static Eldbus_Message *
1646 _selection_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1647 {
1648    const char *obj_path = eldbus_message_path_get(msg);
1649    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1650    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1651    int idx;
1652    Eldbus_Message *ret;
1653    Eina_Bool result = EINA_FALSE;
1654
1655    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, msg);
1656
1657    if (!eldbus_message_arguments_get(msg, "i", &idx))
1658      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1659
1660    ret = eldbus_message_method_return_new(msg);
1661    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1662
1663    if (_is_operation_permitted(obj))
1664      eo_do(obj, result = elm_interface_atspi_selection_child_deselect(idx));
1665    eldbus_message_arguments_append(ret, "b", result);
1666
1667    return ret;
1668 }
1669
1670 static const Eldbus_Method selection_methods[] = {
1671    { "GetSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"(so)", "Accessible"}), _selection_selected_child_get, 0 },
1672    { "SelectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_select, 0 },
1673    { "DeselectSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_selected_child_deselect, 0 },
1674    { "IsChildSelected", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_is_child_selected, 0 },
1675    { "SelectAll", NULL, ELDBUS_ARGS({"b", "result"}), _selection_all_children_select, 0},
1676    { "ClearSelection", NULL, ELDBUS_ARGS({"b", "result"}), _selection_clear, 0},
1677    { "DeselectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_deselect, 0 },
1678    { NULL, NULL, NULL, NULL, 0 }
1679 };
1680
1681 static Eldbus_Message *
1682 _action_description_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1683 {
1684    const char *description, *obj_path = eldbus_message_path_get(msg);
1685    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1686    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1687    int idx;
1688    Eldbus_Message *ret;
1689
1690    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1691
1692    if (!eldbus_message_arguments_get(msg, "i", &idx))
1693      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1694
1695    ret = eldbus_message_method_return_new(msg);
1696    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1697
1698    eo_do(obj, description = elm_interface_atspi_action_description_get(idx));
1699    description = description ? description : "";
1700    eldbus_message_arguments_append(ret, "s", description);
1701
1702    return ret;
1703 }
1704
1705 static Eldbus_Message *
1706 _action_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1707 {
1708    const char *name, *obj_path = eldbus_message_path_get(msg);
1709    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1710    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1711    int idx;
1712    Eldbus_Message *ret;
1713
1714    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1715
1716    if (!eldbus_message_arguments_get(msg, "i", &idx))
1717      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1718
1719    ret = eldbus_message_method_return_new(msg);
1720    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1721
1722    eo_do(obj, name = elm_interface_atspi_action_name_get(idx));
1723    name = name ? name : "";
1724    eldbus_message_arguments_append(ret, "s", name);
1725
1726    return ret;
1727 }
1728
1729 static Eldbus_Message *
1730 _action_localized_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1731 {
1732    const char *name, *obj_path = eldbus_message_path_get(msg);
1733    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1734    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1735    int idx;
1736    Eldbus_Message *ret;
1737
1738    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1739
1740    if (!eldbus_message_arguments_get(msg, "i", &idx))
1741      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1742
1743    ret = eldbus_message_method_return_new(msg);
1744    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1745
1746    eo_do(obj, name = elm_interface_atspi_action_localized_name_get(idx));
1747    name = name ? name : "";
1748    eldbus_message_arguments_append(ret, "s", name);
1749
1750    return ret;
1751 }
1752
1753 static Eldbus_Message *
1754 _action_key_binding_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1755 {
1756    const char *obj_path = eldbus_message_path_get(msg);
1757    char *key;
1758    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1759    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1760    int idx;
1761    Eldbus_Message *ret;
1762
1763    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1764
1765    if (!eldbus_message_arguments_get(msg, "i", &idx))
1766      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1767
1768    ret = eldbus_message_method_return_new(msg);
1769    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1770
1771    eo_do(obj, key = elm_interface_atspi_action_keybinding_get(idx));
1772    eldbus_message_arguments_append(ret, "s", key ? key : "");
1773    if (key) free(key);
1774
1775    return ret;
1776 }
1777
1778 static Eldbus_Message *
1779 _action_actions_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1780 {
1781    const char *action, *obj_path = eldbus_message_path_get(msg);
1782    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1783    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1784    Eina_List *actions;
1785    Eldbus_Message *ret;
1786    Eldbus_Message_Iter *iter, *iter_array;
1787
1788    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1789
1790    ret = eldbus_message_method_return_new(msg);
1791    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1792
1793    iter = eldbus_message_iter_get(ret);
1794    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
1795
1796    iter_array = eldbus_message_iter_container_new(iter, 'a', "sss");
1797    EINA_SAFETY_ON_NULL_RETURN_VAL(iter_array, NULL);
1798
1799    eo_do(obj, actions = elm_interface_atspi_action_actions_get());
1800
1801    int id = 0;
1802    EINA_LIST_FREE(actions, action)
1803      {
1804         const char *descr;
1805         char *key;
1806         eo_do(obj, key = elm_interface_atspi_action_keybinding_get(id));
1807         eo_do(obj, descr = elm_interface_atspi_action_description_get(id));
1808         descr = descr ? descr : "";
1809         eldbus_message_iter_arguments_append(iter_array, "sss", action, descr, key ? key : "");
1810         if (key) free(key);
1811         id++;
1812      }
1813
1814   eldbus_message_iter_container_close(iter, iter_array);
1815
1816    return ret;
1817 }
1818
1819 static Eldbus_Message *
1820 _action_action_do(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1821 {
1822    const char *obj_path = eldbus_message_path_get(msg);
1823    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1824    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1825    int idx;
1826    Eldbus_Message *ret;
1827    Eina_Bool result = EINA_FALSE;
1828
1829    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1830
1831    if (!eldbus_message_arguments_get(msg, "i", &idx))
1832      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1833
1834    ret = eldbus_message_method_return_new(msg);
1835    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1836
1837    if (_is_operation_permitted(obj))
1838      eo_do(obj, result = elm_interface_atspi_action_do(idx));
1839
1840    eldbus_message_arguments_append(ret, "b", result);
1841
1842    return ret;
1843 }
1844
1845 static Eldbus_Message *
1846 _action_action_name_do(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1847 {
1848    const char *obj_path = eldbus_message_path_get(msg);
1849    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1850    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1851    char *action_name;
1852    int idx = 0;
1853    Eina_List *actions;
1854    const char *action;
1855    Eldbus_Message *ret;
1856    Eina_Bool result = EINA_FALSE;
1857
1858    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, msg);
1859
1860    if (!eldbus_message_arguments_get(msg, "s", &action_name))
1861      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1862
1863    ret = eldbus_message_method_return_new(msg);
1864    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1865
1866    eo_do(obj, actions = elm_interface_atspi_action_actions_get());
1867    EINA_LIST_FREE(actions, action)
1868      {
1869         if (!result && action && !strcmp(action, action_name))
1870           result = EINA_TRUE;
1871
1872         if (!result)
1873           idx++;
1874      }
1875
1876    if (result)
1877      eo_do(obj, result = elm_interface_atspi_action_do(idx));
1878
1879    eldbus_message_arguments_append(ret, "b", result);
1880
1881    return ret;
1882 }
1883
1884 static const Eldbus_Method action_methods[] = {
1885    { "GetDescription", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "description"}), _action_description_get, 0 },
1886    { "GetName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_name_get, 0 },
1887    { "GetLocalizedName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_localized_name_get, 0 },
1888    { "GetKeyBinding", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "key"}), _action_key_binding_get, 0 },
1889    { "GetActions", NULL, ELDBUS_ARGS({"a(sss)", "actions"}), _action_actions_get, 0 },
1890    { "DoAction", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"b", "result"}), _action_action_do, 0 },
1891    { "DoActionName", ELDBUS_ARGS({"s", "name"}), ELDBUS_ARGS({"b", "result"}), _action_action_name_do, 0 },
1892    { NULL, NULL, NULL, NULL, 0 }
1893 };
1894
1895 static Eldbus_Message *
1896 _image_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1897 {
1898    AtspiCoordType type;
1899    Eldbus_Message *ret;
1900    const char *obj_path = eldbus_message_path_get(msg);
1901    int x, y, w, h;
1902    Eina_Bool screen_coords;
1903    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1904    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1905
1906    x = y = w = h = -1;
1907
1908    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_IMAGE_MIXIN, msg);
1909
1910    if (!eldbus_message_arguments_get(msg, "u", &type))
1911      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1912
1913    ret = eldbus_message_method_return_new(msg);
1914    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1915
1916    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1917    eo_do(obj, elm_interface_atspi_image_extents_get(screen_coords, &x, &y, &w, &h));
1918    eldbus_message_arguments_append(ret, "iiii", x, y, w, h);
1919
1920    return ret;
1921 }
1922
1923 static Eldbus_Message *
1924 _image_position_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1925 {
1926    AtspiCoordType type;
1927    Eldbus_Message *ret;
1928    const char *obj_path = eldbus_message_path_get(msg);
1929    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1930    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1931    int x = -1, y = -1;
1932    Eina_Bool screen_coords;
1933
1934    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_IMAGE_MIXIN, msg);
1935
1936    if (!eldbus_message_arguments_get(msg, "u", &type))
1937      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1938
1939    ret = eldbus_message_method_return_new(msg);
1940    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1941
1942    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1943    eo_do(obj, elm_interface_atspi_image_extents_get(screen_coords, &x, &y, NULL, NULL));
1944    eldbus_message_arguments_append(ret, "i", x);
1945    eldbus_message_arguments_append(ret, "i", y);
1946
1947    return ret;
1948 }
1949
1950 static Eldbus_Message *
1951 _image_size_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1952 {
1953    Eldbus_Message *ret;
1954    const char *obj_path = eldbus_message_path_get(msg);
1955    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1956    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1957    int w = -1, h = -1;
1958
1959    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_IMAGE_MIXIN, msg);
1960
1961    ret = eldbus_message_method_return_new(msg);
1962    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1963
1964    eo_do(obj, elm_interface_atspi_image_extents_get(EINA_FALSE, NULL, NULL, &w, &h));
1965    eldbus_message_arguments_append(ret, "i", w);
1966    eldbus_message_arguments_append(ret, "i", h);
1967
1968    return ret;
1969 }
1970
1971 static const Eldbus_Method image_methods[] = {
1972    { "GetImageExtents", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"iiii", "extents"}), _image_extents_get, 0 },
1973    { "GetImagePosition", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}), _image_position_get, 0 },
1974    { "GetImageSize", NULL, ELDBUS_ARGS({"i", "width"}, {"i", "height"}), _image_size_get, 0 },
1975    { NULL, NULL, NULL, NULL, 0 }
1976 };
1977
1978 static Eldbus_Message *
1979 _text_string_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1980 {
1981    const char *obj_path = eldbus_message_path_get(msg);
1982    char *str;
1983    Elm_Atspi_Text_Granularity gran;
1984    int start, end;
1985    Eldbus_Message *ret;
1986    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1987    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1988
1989    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
1990
1991    if (!eldbus_message_arguments_get(msg, "iu", &start, &gran))
1992      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and granularity expected.");
1993
1994    ret = eldbus_message_method_return_new(msg);
1995    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1996
1997    eo_do(obj, str = elm_interface_atspi_text_string_get(gran, &start, &end));
1998    str = str ? str : strdup("");
1999
2000    eldbus_message_arguments_append(ret, "sii", str, start, end);
2001    free(str);
2002
2003    return ret;
2004 }
2005
2006 static Eldbus_Message *
2007 _text_text_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2008 {
2009    const char *obj_path = eldbus_message_path_get(msg);
2010    char *str;
2011    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2012    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2013    int start, end;
2014
2015    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2016
2017    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2018      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and granularity expected.");
2019
2020    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
2021    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2022
2023    eo_do(obj, str = elm_interface_atspi_text_get(start, end));
2024    str = str ? str : strdup("");
2025
2026    eldbus_message_arguments_append(ret, "s", str);
2027    free(str);
2028
2029    return ret;
2030 }
2031
2032 static Eldbus_Message *
2033 _text_caret_offset_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2034 {
2035    const char *obj_path = eldbus_message_path_get(msg);
2036    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2037    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2038    int offset;
2039    Eldbus_Message *ret;
2040    Eina_Bool res;
2041
2042    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2043
2044    if (!eldbus_message_arguments_get(msg, "i", &offset))
2045      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
2046
2047    ret = eldbus_message_method_return_new(msg);
2048    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2049
2050    eo_do(obj, res = elm_interface_atspi_text_caret_offset_set(offset));
2051
2052    eldbus_message_arguments_append(ret, "b", res);
2053
2054    return ret;
2055 }
2056
2057 static Eldbus_Message *
2058 _text_character_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2059 {
2060    const char *obj_path = eldbus_message_path_get(msg);
2061    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2062    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2063    int offset;
2064    Eldbus_Message *ret;
2065    Eina_Unicode res;
2066
2067    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2068
2069    if (!eldbus_message_arguments_get(msg, "i", &offset))
2070      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
2071
2072    ret = eldbus_message_method_return_new(msg);
2073    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2074
2075    eo_do(obj, res = elm_interface_atspi_text_character_get(offset));
2076
2077    eldbus_message_arguments_append(ret, "i", res);
2078
2079    return ret;
2080 }
2081
2082 static Eldbus_Message *
2083 _text_attribute_value_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2084 {
2085    const char *name, *obj_path = eldbus_message_path_get(msg);
2086    char *value = NULL;
2087    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2088    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2089    int start, end;
2090    Eldbus_Message *ret;
2091    Eina_Bool res;
2092
2093    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2094
2095    if (!eldbus_message_arguments_get(msg, "is", &start, &name))
2096      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and attribute name expected.");
2097
2098    ret = eldbus_message_method_return_new(msg);
2099    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2100
2101    eo_do(obj, res = elm_interface_atspi_text_attribute_get(name, &start, &end, &value));
2102    eldbus_message_arguments_append(ret, "siib", value ? value : "", start, end, res);
2103
2104    if (value) free(value);
2105    return ret;
2106 }
2107
2108 static Eldbus_Message *
2109 _text_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2110 {
2111    const char *obj_path = eldbus_message_path_get(msg);
2112    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2113    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2114    int start, end;
2115    Eldbus_Message *ret;
2116    Eldbus_Message_Iter *iter, *iter_array;
2117    Eina_List *attrs;
2118    Elm_Atspi_Text_Attribute *attr;
2119
2120    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2121
2122    if (!eldbus_message_arguments_get(msg, "i", &start))
2123      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
2124
2125    ret = eldbus_message_method_return_new(msg);
2126    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2127
2128    iter = eldbus_message_iter_get(ret);
2129    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
2130    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2131
2132    eo_do(obj, attrs = elm_interface_atspi_text_attributes_get(&start, &end));
2133
2134    EINA_LIST_FREE(attrs, attr)
2135     {
2136        eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
2137        elm_atspi_text_text_attribute_free(attr);
2138     }
2139
2140    eldbus_message_iter_container_close(iter, iter_array);
2141    eldbus_message_iter_arguments_append(iter, "ii", start, end);
2142
2143    return ret;
2144
2145 fail:
2146    if (ret) eldbus_message_unref(ret);
2147    return NULL;
2148 }
2149
2150 static Eldbus_Message *
2151 _text_default_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2152 {
2153    const char *obj_path = eldbus_message_path_get(msg);
2154    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2155    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2156    int start = -1, end;
2157    Eldbus_Message *ret;
2158    Eldbus_Message_Iter *iter, *iter_array;
2159    Eina_List *attrs;
2160    Elm_Atspi_Text_Attribute *attr;
2161
2162    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2163
2164    ret = eldbus_message_method_return_new(msg);
2165    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2166
2167    iter = eldbus_message_iter_get(ret);
2168    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
2169    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2170
2171    eo_do(obj, attrs = elm_interface_atspi_text_attributes_get(&start, &end));
2172
2173    EINA_LIST_FREE(attrs, attr)
2174     {
2175       eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
2176       elm_atspi_text_text_attribute_free(attr);
2177     }
2178
2179    eldbus_message_iter_container_close(iter, iter_array);
2180    eldbus_message_iter_arguments_append(iter, "ii", start, end);
2181
2182    return ret;
2183
2184 fail:
2185    if (ret) eldbus_message_unref(ret);
2186    return NULL;
2187 }
2188
2189 static Eldbus_Message *
2190 _text_character_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2191 {
2192    const char *obj_path = eldbus_message_path_get(msg);
2193    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2194    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2195    int offset;
2196    Eina_Rectangle rect;
2197    AtspiCoordType type;
2198    Eina_Bool screen_coords, res;
2199    Eldbus_Message *ret;
2200
2201    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2202
2203    if (!eldbus_message_arguments_get(msg, "iu", &offset, &type))
2204      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
2205
2206    ret = eldbus_message_method_return_new(msg);
2207    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2208
2209    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2210
2211    eo_do(obj, res = elm_interface_atspi_text_character_extents_get(offset, screen_coords, &rect));
2212
2213    if (!res)
2214      {
2215         eldbus_message_unref(ret);
2216         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get character extents.");
2217      }
2218    eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
2219
2220    return ret;
2221 }
2222
2223 static Eldbus_Message *
2224 _text_offset_at_point_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2225 {
2226    const char *obj_path = eldbus_message_path_get(msg);
2227    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2228    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2229    int offset, x, y;
2230    AtspiCoordType type;
2231    Eina_Bool screen_coords;
2232    Eldbus_Message *ret;
2233
2234    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2235
2236    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &type))
2237      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
2238
2239    ret = eldbus_message_method_return_new(msg);
2240    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2241
2242    x = y = -1;
2243    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2244
2245    eo_do(obj, offset = elm_interface_atspi_text_offset_at_point_get(screen_coords, x, y));
2246
2247    eldbus_message_arguments_append(ret, "i", offset);
2248
2249    return ret;
2250 }
2251
2252 static Eldbus_Message *
2253 _text_n_selections_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2254 {
2255    const char *obj_path = eldbus_message_path_get(msg);
2256    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2257    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2258    int n;
2259    Eldbus_Message *ret;
2260
2261    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2262
2263    ret = eldbus_message_method_return_new(msg);
2264    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2265
2266    eo_do(obj, n = elm_interface_atspi_text_selections_count_get());
2267
2268    eldbus_message_arguments_append(ret, "i", n);
2269
2270    return ret;
2271 }
2272
2273 static Eldbus_Message *
2274 _text_selection_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2275 {
2276    const char *obj_path = eldbus_message_path_get(msg);
2277    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2278    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2279    int sel_num, start, end;
2280    Eldbus_Message *ret;
2281
2282    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2283
2284    if (!eldbus_message_arguments_get(msg, "i", &sel_num))
2285      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2286
2287    ret = eldbus_message_method_return_new(msg);
2288    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2289
2290    eo_do(obj, elm_interface_atspi_text_selection_get(sel_num, &start, &end));
2291
2292    eldbus_message_arguments_append(ret, "ii", start, end);
2293
2294    return ret;
2295 }
2296
2297 static Eldbus_Message *
2298 _text_selection_add(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2299 {
2300    const char *obj_path = eldbus_message_path_get(msg);
2301    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2302    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2303    int start, end;
2304    Eina_Bool res;
2305    Eldbus_Message *ret;
2306
2307    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2308
2309    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2310      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end text offset expected.");
2311
2312    ret = eldbus_message_method_return_new(msg);
2313    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2314
2315    eo_do(obj, res = elm_interface_atspi_text_selection_add(start, end));
2316
2317    eldbus_message_arguments_append(ret, "b", res);
2318
2319    return ret;
2320 }
2321
2322 static Eldbus_Message *
2323 _text_selection_remove(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2324 {
2325    const char *obj_path = eldbus_message_path_get(msg);
2326    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2327    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2328    int sel_num;
2329    Eina_Bool res;
2330    Eldbus_Message *ret;
2331
2332    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2333
2334    if (!eldbus_message_arguments_get(msg, "i", &sel_num))
2335      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2336
2337    ret = eldbus_message_method_return_new(msg);
2338    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2339
2340    eo_do(obj, res = elm_interface_atspi_text_selection_remove(sel_num));
2341
2342    eldbus_message_arguments_append(ret, "b", res);
2343
2344    return ret;
2345 }
2346
2347 static Eldbus_Message *
2348 _text_selection_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2349 {
2350    const char *obj_path = eldbus_message_path_get(msg);
2351    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2352    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2353    int sel_num, start, end;
2354    Eina_Bool res;
2355    Eldbus_Message *ret;
2356
2357    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2358
2359    if (!eldbus_message_arguments_get(msg, "iii", &sel_num, &start, &end))
2360      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2361
2362    ret = eldbus_message_method_return_new(msg);
2363    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2364
2365    eo_do(obj, res = elm_interface_atspi_text_selection_set(sel_num, start, end));
2366
2367    eldbus_message_arguments_append(ret, "b", res);
2368
2369    return ret;
2370 }
2371
2372 static Eldbus_Message *
2373 _text_range_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2374 {
2375    const char *obj_path = eldbus_message_path_get(msg);
2376    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2377    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2378    int start, end;
2379    Eina_Rectangle rect;
2380    Eina_Bool screen_coords, res;
2381    AtspiCoordType type;
2382    Eldbus_Message *ret;
2383
2384    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2385
2386    if (!eldbus_message_arguments_get(msg, "iiu", &start, &end, &type))
2387      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2388
2389    ret = eldbus_message_method_return_new(msg);
2390    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2391
2392    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2393    eo_do(obj, res = elm_interface_atspi_text_range_extents_get(screen_coords, start, end, &rect));
2394    if (!res)
2395      {
2396         eldbus_message_unref(ret);
2397         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Can't get range extents.");
2398      }
2399
2400    eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
2401
2402    return ret;
2403 }
2404
2405 static Eldbus_Message *
2406 _text_bounded_ranges_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2407 {
2408    const char *obj_path = eldbus_message_path_get(msg);
2409    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2410    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2411    Eina_Rectangle rect;
2412    Eina_Bool screen_coords;
2413    AtspiCoordType type;
2414    Elm_Atspi_Text_Clip_Type xclip, yclip;
2415    Eina_List *ranges;
2416    Eldbus_Message *ret;
2417    Elm_Atspi_Text_Range *range;
2418    Eldbus_Message_Iter *iter, *iter_array, *iter_struct, *iter_var;
2419
2420    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2421
2422    if (!eldbus_message_arguments_get(msg, "iiiiuuu", &rect.x, &rect.y, &rect.w, &rect.h, &type, &xclip, &yclip))
2423      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected (x,y,w,h) of bounding box, screen coord type and x, y text clip types.");
2424
2425    ret = eldbus_message_method_return_new(msg);
2426    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2427
2428    iter = eldbus_message_iter_get(ret);
2429    iter_array = eldbus_message_iter_container_new(iter, 'a', "(iisv)");
2430    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2431
2432    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2433    eo_do(obj, ranges = elm_interface_atspi_text_bounded_ranges_get(screen_coords, rect, xclip, yclip));
2434
2435    EINA_LIST_FREE(ranges, range)
2436      {
2437         iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
2438         if (iter_struct)
2439           {
2440              eldbus_message_iter_basic_append(iter_struct, 'i', range->start_offset);
2441              eldbus_message_iter_basic_append(iter_struct, 'i', range->end_offset);
2442              range->content = range->content ? range->content : strdup("");
2443              eldbus_message_iter_basic_append(iter_struct, 's', range->content);
2444              /* AT-SPI specification requires variant type in return, however
2445               * ATK or other implementations as well as AT Clients don't use it .
2446               * To cover spec a dummy value will be returned */
2447              iter_var = eldbus_message_iter_container_new(iter_struct, 'v', "i");
2448              if (iter_var)
2449                {
2450                   eldbus_message_iter_basic_append(iter_var, 'i', 0);
2451                   eldbus_message_iter_container_close(iter_struct, iter_var);
2452                }
2453              eldbus_message_iter_container_close(iter_array, iter_struct);
2454           }
2455         if (range->content) free(range->content);
2456         free(range);
2457      }
2458
2459    eldbus_message_iter_container_close(iter, iter_array);
2460
2461    return ret;
2462
2463 fail:
2464    if (ret) eldbus_message_unref(ret);
2465    return NULL;
2466 }
2467
2468 static Eldbus_Message *
2469 _text_run_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2470 {
2471    const char *obj_path = eldbus_message_path_get(msg);
2472    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2473    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2474    int start, end;
2475    Eldbus_Message *ret;
2476    Eldbus_Message_Iter *iter, *iter_array;
2477    Eina_List *attrs, *defaults;
2478    Elm_Atspi_Text_Attribute *attr;
2479    Eina_Bool incl_def;
2480
2481    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, msg);
2482
2483    if (!eldbus_message_arguments_get(msg, "ib", &start, &incl_def))
2484      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and include defaults flag expected.");
2485
2486    ret = eldbus_message_method_return_new(msg);
2487    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2488
2489    iter = eldbus_message_iter_get(ret);
2490    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
2491    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2492
2493    eo_do(obj, attrs = elm_interface_atspi_text_attributes_get(&start, &end));
2494
2495    if (incl_def)
2496      {
2497         eo_do(obj, defaults = elm_interface_atspi_text_default_attributes_get());
2498         attrs = eina_list_merge(attrs, defaults);
2499      }
2500
2501    EINA_LIST_FREE(attrs, attr)
2502      {
2503         eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
2504         elm_atspi_text_text_attribute_free(attr);
2505      }
2506
2507    eldbus_message_iter_container_close(iter, iter_array);
2508    eldbus_message_iter_arguments_append(iter, "ii", start, end);
2509
2510    return ret;
2511
2512 fail:
2513    if (ret) eldbus_message_unref(ret);
2514    return NULL;
2515 }
2516
2517 static const Eldbus_Method text_methods[] = {
2518    { "GetTextAtOffset", ELDBUS_ARGS({"i", "offset"}, {"u", "granularity"}), ELDBUS_ARGS({"s", "string"}, {"i", "startOffset"}, {"i", "endOffset"}), _text_string_at_offset_get, 0 },
2519    { "GetText", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"s", "string"}), _text_text_get, 0 },
2520    { "SetCaretOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"b", NULL}), _text_caret_offset_set, 0 },
2521    { "GetCharacterAtOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"i", NULL}), _text_character_at_offset_get, 0 },
2522    { "GetAttributeValue", ELDBUS_ARGS({"i", "offset"}, {"s", "attributeName"}), ELDBUS_ARGS({"s", NULL}, {"i", "startOffset"}, {"i", "endOffset"}, {"b", "defined"}), _text_attribute_value_get, 0 },
2523    { "GetAttributes", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_attributes_get, 0 },
2524    { "GetDefaultAttributes", NULL, ELDBUS_ARGS({"a(ss)", NULL}), _text_default_attributes_get, 0 },
2525    { "GetCharacterExtents", ELDBUS_ARGS({"i", "offset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_character_extents_get, 0 },
2526    { "GetOffsetAtPoint", ELDBUS_ARGS({"i", "x"}, {"i","y"}, {"u", "coordType"}), ELDBUS_ARGS({"i", NULL}), _text_offset_at_point_get, 0 },
2527    { "GetNSelections", NULL, ELDBUS_ARGS({"i", NULL}), _text_n_selections_get, 0 },
2528    { "GetSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), _text_selection_get, 0 },
2529    { "AddSelection", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_add, 0 },
2530    { "RemoveSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"b", NULL}), _text_selection_remove, 0 },
2531    { "SetSelection", ELDBUS_ARGS({"i", "selectionNum"}, {"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_set, 0 },
2532    { "GetRangeExtents", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_range_extents_get, 0 },
2533    { "GetBoundedRanges", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}, {"u", "coordType"}, {"u", "xClipType"}, {"u", "yClipType"}), ELDBUS_ARGS({"a(issv)", NULL}), _text_bounded_ranges_get, 0 },
2534    { "GetAttributeRun", ELDBUS_ARGS({"i", "offset"}, {"b", "includeDefaults"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_run_attributes_get, 0 },
2535    { "GetDefaultAttributeSet", NULL, ELDBUS_ARGS({"a(ss)", NULL}), _text_default_attributes_get, 0 },
2536    { NULL, NULL, NULL, NULL, 0 }
2537 };
2538
2539 static Eldbus_Message *
2540 _editable_text_text_content_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2541 {
2542    const char *obj_path = eldbus_message_path_get(msg);
2543    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2544    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2545    const char *content;
2546    Eldbus_Message *ret;
2547    Eina_Bool res;
2548
2549    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2550
2551    if (!eldbus_message_arguments_get(msg, "s", &content))
2552      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "String expected.");
2553
2554    ret = eldbus_message_method_return_new(msg);
2555    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2556
2557    eo_do(obj, res = elm_interface_atspi_editable_text_content_set(content));
2558
2559    eldbus_message_arguments_append(ret, "b", res);
2560
2561    return ret;
2562 }
2563
2564 static Eldbus_Message *
2565 _editable_text_text_insert(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2566 {
2567    const char *obj_path = eldbus_message_path_get(msg);
2568    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2569    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2570    const char *text;
2571    Eldbus_Message *ret;
2572    int pos, len;
2573    Eina_Bool res;
2574
2575    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2576
2577    if (!eldbus_message_arguments_get(msg, "isi", &pos, &text, &len))
2578      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Postion, string, length expected.");
2579
2580    ret = eldbus_message_method_return_new(msg);
2581    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2582
2583    eo_do(obj, res = elm_interface_atspi_editable_text_insert(text, pos));
2584
2585    eldbus_message_arguments_append(ret, "b", res);
2586
2587    return ret;
2588 }
2589
2590 static Eldbus_Message *
2591 _editable_text_text_copy(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2592 {
2593    const char *obj_path = eldbus_message_path_get(msg);
2594    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2595    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2596    Eldbus_Message *ret;
2597    int start, end;
2598    Eina_Bool res;
2599
2600    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2601
2602    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2603      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2604
2605    ret = eldbus_message_method_return_new(msg);
2606    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2607
2608    eo_do(obj, res = elm_interface_atspi_editable_text_copy(start, end));
2609
2610    eldbus_message_arguments_append(ret, "b", res);
2611
2612    return ret;
2613 }
2614
2615 static Eldbus_Message *
2616 _editable_text_text_cut(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2617 {
2618    const char *obj_path = eldbus_message_path_get(msg);
2619    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2620    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2621    Eldbus_Message *ret;
2622    int start, end;
2623    Eina_Bool res;
2624
2625    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2626
2627    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2628      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2629
2630    ret = eldbus_message_method_return_new(msg);
2631    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2632
2633    eo_do(obj, res = elm_interface_atspi_editable_text_cut(start, end));
2634
2635    eldbus_message_arguments_append(ret, "b", res);
2636
2637    return ret;
2638 }
2639
2640 static Eldbus_Message *
2641 _editable_text_text_delete(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2642 {
2643    const char *obj_path = eldbus_message_path_get(msg);
2644    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2645    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2646    Eldbus_Message *ret;
2647    int start, end;
2648    Eina_Bool res;
2649
2650    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2651
2652    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2653      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2654
2655    ret = eldbus_message_method_return_new(msg);
2656    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2657
2658    eo_do(obj, res = elm_interface_atspi_editable_text_delete(start, end));
2659
2660    eldbus_message_arguments_append(ret, "b", res);
2661
2662    return ret;
2663 }
2664
2665 static Eldbus_Message *
2666 _editable_text_text_paste(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2667 {
2668    const char *obj_path = eldbus_message_path_get(msg);
2669    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2670    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2671    Eldbus_Message *ret;
2672    int pos;
2673    Eina_Bool res;
2674
2675    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE, msg);
2676
2677    if (!eldbus_message_arguments_get(msg, "i", &pos))
2678      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2679
2680    ret = eldbus_message_method_return_new(msg);
2681    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2682
2683    eo_do(obj, res = elm_interface_atspi_editable_text_paste(pos));
2684
2685    eldbus_message_arguments_append(ret, "b", res);
2686
2687    return ret;
2688 }
2689
2690 Eina_Bool
2691 _elm_atspi_bridge_plug_id_split(const char *plug_id, char **bus, char **path)
2692 {
2693    if (!plug_id || !strcmp(plug_id, "")) return EINA_FALSE;
2694    unsigned int tokens = 0;
2695    char **split = eina_str_split_full(plug_id, ":", 0, &tokens);
2696    Eina_Bool ret = EINA_FALSE;
2697    if (tokens == 2)
2698      {
2699         if (!split[0] || !split[1])
2700           ret = EINA_FALSE;
2701         else
2702           {
2703              if (bus) *bus = strdup(split[0]);
2704              if (path) *path = strdup(split[1]);
2705              ret = EINA_TRUE;
2706           }
2707      }
2708    else if (tokens == 3)
2709      {
2710         if (!split[0] || !split[1] || !split[2])
2711           ret = EINA_FALSE;
2712         else
2713           {
2714              char buf[128];
2715              snprintf(buf, sizeof(buf), "%s:%s",split[0], split[1]);
2716              if (bus) *bus = strdup(buf);
2717              if (path) *path = strdup(split[2]);
2718              ret = EINA_TRUE;
2719           }
2720      }
2721
2722    free(split[0]);
2723    free(split);
2724    return ret;
2725 }
2726
2727 static Eldbus_Message *
2728 _socket_embedded(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
2729 {
2730    Eo *proxy;
2731    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
2732    const char *obj_path = eldbus_message_path_get(msg);
2733    //
2734    const char *bus, *path;
2735    Eo *bridge = _elm_atspi_bridge_get();
2736    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2737    eo_do(obj, proxy = elm_interface_atspi_accessible_parent_get());
2738
2739    if (!eo_isa(proxy, ELM_ATSPI_PROXY_CLASS))
2740      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to embed object.");
2741
2742    if (!eldbus_message_arguments_get(msg, "s", &path))
2743      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Plug id expected.");
2744
2745    bus = eldbus_message_sender_get(msg);
2746
2747    eo_do(proxy, elm_obj_atspi_proxy_address_set(bus, path));
2748
2749    _bridge_cache_build(bridge, proxy);
2750
2751    return eldbus_message_method_return_new(msg);
2752 }
2753
2754 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
2755 static Eldbus_Message *
2756 _socket_offset_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2757 {
2758    int x, y;
2759    Eo *parent;
2760    Eo *obj = eldbus_service_object_data_get(iface, "_atspi_obj");
2761    eo_do(obj, parent = eo_parent_get());
2762    Evas_Object *top = elm_object_top_widget_get(parent);
2763
2764    if (!eldbus_message_arguments_get(msg, "ii", &x, &y))
2765      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
2766
2767    eo_do(top, elm_interface_atspi_component_socket_offset_set(x, y));
2768
2769    return eldbus_message_method_return_new(msg);
2770 }
2771 //
2772
2773 static const Eldbus_Method editable_text_methods[] = {
2774    { "SetTextContents", ELDBUS_ARGS({"s", "newcontents"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_content_set, 0 },
2775    { "InsertText", ELDBUS_ARGS({"i", "position"}, {"s", "text"}, {"i", "length"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_insert, 0 },
2776    { "CopyText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), NULL, _editable_text_text_copy, 0 },
2777    { "CutText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_cut, 0 },
2778    { "DeleteText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_delete, 0 },
2779    { "PasteText", ELDBUS_ARGS({"i", "position"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_paste, 0 },
2780    { NULL, NULL, NULL, NULL, 0 }
2781 };
2782
2783 static const Eldbus_Method socket_methods[] = {
2784    { "Embedded", ELDBUS_ARGS({"s", "id"}), ELDBUS_ARGS({NULL, NULL}), _socket_embedded, 0 },
2785    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
2786    { "SetOffset", ELDBUS_ARGS({"i", "x"}, {"i", "y"}), ELDBUS_ARGS({NULL, NULL}), _socket_offset_set, 0 },
2787    //
2788    { NULL, NULL, NULL, NULL, 0 }
2789 };
2790
2791 static const Eldbus_Service_Interface_Desc socket_iface_desc = {
2792    ATSPI_DBUS_INTERFACE_SOCKET, socket_methods, NULL, NULL, NULL, NULL
2793 };
2794
2795 static Eo *
2796 _bridge_object_from_path(Eo *bridge, const char *path)
2797 {
2798    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2799    unsigned long long eo_ptr = 0;
2800    Eo *eo = NULL;
2801    const char *tmp = path;
2802    Eo *ret;
2803
2804    int len = strlen(ELM_ACCESS_OBJECT_PATH_PREFIX);
2805    if (strncmp(path, ELM_ACCESS_OBJECT_PATH_PREFIX, len))
2806      return NULL;
2807
2808    tmp = path + len; /* Skip over the prefix */
2809    if (!strcmp(ELM_ACCESS_OBJECT_PATH_ROOT, tmp))
2810      return elm_atspi_bridge_root_get(bridge);
2811
2812    sscanf(tmp, "%llu", &eo_ptr);
2813    eo = (Eo *) (uintptr_t) eo_ptr;
2814
2815    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
2816    if (!eina_hash_find(pd->cache, &eo))
2817      {
2818         WRN("Request for non-registered object: %s", path);
2819         return NULL;
2820      }
2821
2822    ret = eo_isa(eo, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN) ? eo : NULL;
2823
2824    return ret;
2825 }
2826
2827 static const char *
2828 _bridge_path_from_object(Eo *bridge, const Eo *eo)
2829 {
2830    static char path[64];
2831
2832    if (!eo)
2833      return ATSPI_DBUS_PATH_NULL;
2834
2835    if (eo == elm_atspi_bridge_root_get(bridge))
2836      snprintf(path, sizeof(path), "%s%s", ELM_ACCESS_OBJECT_PATH_PREFIX, ELM_ACCESS_OBJECT_PATH_ROOT);
2837    else
2838      snprintf(path, sizeof(path), ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE, (unsigned long long)(uintptr_t)eo);
2839    return path;
2840 }
2841
2842 static Eina_Bool
2843 _accessible_property_get(const Eldbus_Service_Interface *interface, const char *property,
2844                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2845                          Eldbus_Message **error)
2846 {
2847    const char *ret = NULL, *obj_path = eldbus_message_path_get(request_msg);
2848    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2849    Eo *ret_obj = NULL, *obj = _bridge_object_from_path(bridge, obj_path);
2850
2851    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, request_msg, error);
2852
2853    if (!strcmp(property, "Name"))
2854      {
2855         eo_do(obj, ret = elm_interface_atspi_accessible_name_get());
2856         if (!ret)
2857           ret = "";
2858         eldbus_message_iter_basic_append(iter, 's', ret);
2859         return EINA_TRUE;
2860      }
2861    else if (!strcmp(property, "Description"))
2862      {
2863         eo_do(obj, ret = elm_interface_atspi_accessible_description_get());
2864         if (!ret)
2865           ret = "";
2866         eldbus_message_iter_basic_append(iter, 's', ret);
2867         return EINA_TRUE;
2868      }
2869    else if (!strcmp(property, "Parent"))
2870      {
2871        eo_do(obj, ret_obj = elm_interface_atspi_accessible_parent_get());
2872        Elm_Atspi_Role role = ELM_ATSPI_ROLE_INVALID;
2873        eo_do(obj, role = elm_interface_atspi_accessible_role_get());
2874        if ((!ret_obj) && (ELM_ATSPI_ROLE_APPLICATION == role))
2875          _object_desktop_reference_append(iter);
2876        else
2877          _bridge_iter_object_reference_append(bridge, iter, ret_obj);
2878        return EINA_TRUE;
2879      }
2880    else if (!strcmp(property, "ChildCount"))
2881      {
2882         Eina_List *l = NULL;
2883         eo_do(obj, l = elm_interface_atspi_accessible_children_get());
2884         eldbus_message_iter_basic_append(iter, 'i', eina_list_count(l));
2885         eina_list_free(l);
2886         return EINA_TRUE;
2887      }
2888    return EINA_FALSE;
2889 }
2890
2891 static Eina_Bool
2892 _selection_property_get(const Eldbus_Service_Interface *interface, const char *property,
2893                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2894                          Eldbus_Message **error)
2895 {
2896    int n;
2897    const char *obj_path = eldbus_message_path_get(request_msg);
2898    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2899    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2900
2901    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE, request_msg, error);
2902
2903    if (!strcmp(property, "NSelectedChildren"))
2904      {
2905         eo_do(obj, n = elm_interface_atspi_selection_selected_children_count_get());
2906         eldbus_message_iter_basic_append(iter, 'i', n);
2907         return EINA_TRUE;
2908      }
2909    return EINA_FALSE;
2910 }
2911
2912 static Eina_Bool
2913 _action_property_get(const Eldbus_Service_Interface *interface, const char *property,
2914                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2915                          Eldbus_Message **error)
2916 {
2917    Eina_List *actions;
2918    const char *obj_path = eldbus_message_path_get(request_msg);
2919    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2920    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2921
2922    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN, request_msg, error);
2923
2924    if (!strcmp(property, "NActions"))
2925      {
2926         eo_do(obj, actions = elm_interface_atspi_action_actions_get());
2927         eldbus_message_iter_basic_append(iter, 'i', eina_list_count(actions));
2928         eina_list_free(actions);
2929         return EINA_TRUE;
2930      }
2931    return EINA_FALSE;
2932 }
2933
2934 static Eldbus_Message*
2935 _value_properties_set(const Eldbus_Service_Interface *interface, const char *property,
2936                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg)
2937 {
2938    double value;
2939    Eina_Bool ret;
2940    const char *obj_path = eldbus_message_path_get(request_msg);
2941    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2942    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2943
2944    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_VALUE_INTERFACE, request_msg);
2945
2946    if (!eldbus_message_iter_arguments_get(iter, "d", &value))
2947      {
2948        return eldbus_message_error_new(request_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: double.");
2949      }
2950
2951    if (!strcmp(property, "CurrentValue"))
2952      {
2953         eo_do(obj, ret = elm_interface_atspi_value_and_text_set(value, NULL));
2954         Eldbus_Message *answer = eldbus_message_method_return_new(request_msg);
2955         eldbus_message_arguments_append(answer, "b", ret);
2956         return answer;
2957      }
2958
2959    return NULL;
2960 }
2961
2962 static Eina_Bool
2963 _value_properties_get(const Eldbus_Service_Interface *interface, const char *property,
2964                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2965                          Eldbus_Message **error)
2966 {
2967    double value;
2968    const char *obj_path = eldbus_message_path_get(request_msg);
2969    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2970    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2971
2972    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_VALUE_INTERFACE, request_msg, error);
2973
2974    if (!strcmp(property, "CurrentValue"))
2975      {
2976         eo_do(obj, elm_interface_atspi_value_and_text_get(&value, NULL));
2977         eldbus_message_iter_basic_append(iter, 'd', value);
2978         return EINA_TRUE;
2979      }
2980    if (!strcmp(property, "MinimumValue"))
2981      {
2982         eo_do(obj, elm_interface_atspi_value_range_get(&value, NULL, NULL));
2983         eldbus_message_iter_basic_append(iter, 'd', value);
2984         return EINA_TRUE;
2985      }
2986    if (!strcmp(property, "MaximumValue"))
2987      {
2988         eo_do(obj, elm_interface_atspi_value_range_get(NULL, &value, NULL));
2989         eldbus_message_iter_basic_append(iter, 'd', value);
2990         return EINA_TRUE;
2991      }
2992    if (!strcmp(property, "MinimumIncrement"))
2993      {
2994         eo_do(obj, value = elm_interface_atspi_value_increment_get());
2995         eldbus_message_iter_basic_append(iter, 'd', value);
2996         return EINA_TRUE;
2997      }
2998    return EINA_FALSE;
2999 }
3000
3001 static Eina_Bool
3002 _image_properties_get(const Eldbus_Service_Interface *interface, const char *property,
3003                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
3004                          Eldbus_Message **error)
3005 {
3006    const char *value;
3007    const char *obj_path = eldbus_message_path_get(request_msg);
3008    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3009    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3010
3011    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_IMAGE_MIXIN, request_msg, error);
3012
3013    if (!strcmp(property, "ImageDescription"))
3014      {
3015         eo_do(obj, value = elm_interface_atspi_image_description_get());
3016         value = value ? value : "";
3017         eldbus_message_iter_basic_append(iter, 's', value);
3018         return EINA_TRUE;
3019      }
3020    if (!strcmp(property, "ImageLocale"))
3021      {
3022         eo_do(obj, value = elm_interface_atspi_image_locale_get());
3023         value = value ? value : "";
3024         eldbus_message_iter_basic_append(iter, 's', value);
3025         return EINA_TRUE;
3026      }
3027    return EINA_FALSE;
3028 }
3029
3030 static Eina_Bool
3031 _text_properties_get(const Eldbus_Service_Interface *interface, const char *property,
3032                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
3033                          Eldbus_Message **error)
3034 {
3035    const char *obj_path = eldbus_message_path_get(request_msg);
3036    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3037    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3038    int val;
3039
3040    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE, request_msg, error);
3041
3042    if (!strcmp(property, "CharacterCount"))
3043      {
3044         eo_do(obj, val = elm_interface_atspi_text_character_count_get());
3045         eldbus_message_iter_basic_append(iter, 'i', val);
3046         return EINA_TRUE;
3047      }
3048    if (!strcmp(property, "CaretOffset"))
3049      {
3050         eo_do(obj, val = elm_interface_atspi_text_caret_offset_get());
3051         eldbus_message_iter_basic_append(iter, 'i', val);
3052         return EINA_TRUE;
3053      }
3054    return EINA_FALSE;
3055 }
3056
3057 static Eldbus_Message*
3058 _application_properties_set(const Eldbus_Service_Interface *iface, const char *property, Eldbus_Message_Iter *iter, const Eldbus_Message *input_msg)
3059 {
3060    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3061    const char *obj_path = eldbus_message_path_get(input_msg);
3062    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3063    int value;
3064
3065    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
3066    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, input_msg);
3067
3068    if (!eldbus_message_iter_arguments_get(iter, "i", &value))
3069      {
3070        return eldbus_message_error_new(input_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: int.");
3071      }
3072
3073    if (!strcmp(property, "Id"))
3074      {
3075         pd->id = value;
3076         Eldbus_Message *answer = eldbus_message_method_return_new(input_msg);
3077         eldbus_message_arguments_append(answer, "b", EINA_TRUE);
3078         return answer;
3079      }
3080
3081    return NULL;
3082 }
3083
3084 static Eina_Bool
3085 _application_properties_get(const Eldbus_Service_Interface *interface, const char *property,
3086                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
3087                          Eldbus_Message **error)
3088 {
3089    const char *obj_path = eldbus_message_path_get(request_msg);
3090    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3091    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3092
3093    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
3094    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, request_msg, error);
3095
3096    if (!strcmp(property, "ToolkitName"))
3097      {
3098         eldbus_message_iter_basic_append(iter, 's', "elementary");
3099         return EINA_TRUE;
3100      }
3101    if (!strcmp(property, "Version"))
3102      {
3103         char buf[64];
3104         snprintf(buf, sizeof(buf), "%d.%d", ELM_VERSION_MAJOR, ELM_VERSION_MINOR);
3105         eldbus_message_iter_basic_append(iter, 's', buf);
3106         return EINA_TRUE;
3107      }
3108    if (!strcmp(property, "Id"))
3109      {
3110         eldbus_message_iter_basic_append(iter, 'i', pd->id);
3111         return EINA_TRUE;
3112      }
3113    return EINA_FALSE;
3114 }
3115
3116 static const Eldbus_Property accessible_properties[] = {
3117    { "Name", "s", NULL, NULL, 0 },
3118    { "Description", "s", NULL, NULL, 0 },
3119    { "Parent", "(so)", NULL, NULL, 0 },
3120    { "ChildCount", "i", NULL, NULL, 0 },
3121    { NULL, NULL, NULL, NULL, 0 }
3122 };
3123
3124 static const Eldbus_Property action_properties[] = {
3125    { "NActions", "i", _action_property_get, NULL, 0 },
3126    { NULL, NULL, NULL, NULL, 0 }
3127 };
3128
3129 static const Eldbus_Property value_properties[] = {
3130    { "MinimumValue", "d", NULL, NULL, 0 },
3131    { "MaximumValue", "d", NULL, NULL, 0 },
3132    { "MinimumIncrement", "d", NULL, NULL, 0 },
3133    { "CurrentValue", "d", NULL, NULL, 0 },
3134    { NULL, NULL, NULL, NULL, 0 }
3135 };
3136
3137 static const Eldbus_Property image_properties[] = {
3138    { "ImageDescription", "s", NULL, NULL, 0 },
3139    { "ImageLocale", "s", NULL, NULL, 0 },
3140    { NULL, NULL, NULL, NULL, 0 }
3141 };
3142
3143 static const Eldbus_Property selection_properties[] = {
3144    { "NSelectedChildren", "i", _selection_property_get, NULL, 0 },
3145    { NULL, NULL, NULL, NULL, 0 }
3146 };
3147
3148 static const Eldbus_Property text_properties[] = {
3149    { "CharacterCount", "i", NULL, NULL, 0 },
3150    { "CaretOffset", "i", NULL, NULL, 0 },
3151    { NULL, NULL, NULL, NULL, 0 }
3152 };
3153
3154 static const Eldbus_Property application_properties[] = {
3155    { "ToolkitName", "s", NULL, NULL, 0 },
3156    { "Version", "s", NULL, NULL, 0 },
3157    { "Id", "i", NULL, NULL, 0 },
3158    { NULL, NULL, NULL, NULL, 0 }
3159 };
3160
3161 static const Eldbus_Service_Interface_Desc accessible_iface_desc = {
3162    ATSPI_DBUS_INTERFACE_ACCESSIBLE, accessible_methods, NULL, accessible_properties, _accessible_property_get, NULL
3163 };
3164
3165 static const Eldbus_Service_Interface_Desc action_iface_desc = {
3166    ATSPI_DBUS_INTERFACE_ACTION, action_methods, NULL, action_properties, NULL, NULL
3167 };
3168
3169 static const Eldbus_Service_Interface_Desc value_iface_desc = {
3170    ATSPI_DBUS_INTERFACE_VALUE, NULL, NULL, value_properties, _value_properties_get, _value_properties_set
3171 };
3172
3173 static const Eldbus_Service_Interface_Desc image_iface_desc = {
3174    ATSPI_DBUS_INTERFACE_IMAGE, image_methods, NULL, image_properties, _image_properties_get, NULL
3175 };
3176
3177 static const Eldbus_Service_Interface_Desc selection_iface_desc = {
3178    ATSPI_DBUS_INTERFACE_SELECTION, selection_methods, NULL, selection_properties, NULL, NULL
3179 };
3180
3181 static const Eldbus_Service_Interface_Desc text_iface_desc = {
3182    ATSPI_DBUS_INTERFACE_TEXT, text_methods, NULL, text_properties, _text_properties_get, NULL
3183 };
3184
3185 static const Eldbus_Service_Interface_Desc editable_text_iface_desc = {
3186    ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, editable_text_methods, NULL, NULL, NULL, NULL
3187 };
3188
3189 static const Eldbus_Service_Interface_Desc application_iface_desc = {
3190    ATSPI_DBUS_INTERFACE_APPLICATION, NULL, NULL, application_properties, _application_properties_get, _application_properties_set
3191 };
3192
3193 void
3194 _collection_match_rule_free(struct collection_match_rule *rule)
3195 {
3196    Elm_Atspi_Attribute *attr;
3197    eina_list_free(rule->ifaces);
3198    EINA_LIST_FREE(rule->attributes, attr)
3199      {
3200         eina_stringshare_del(attr->key);
3201         eina_stringshare_del(attr->value);
3202      }
3203 }
3204
3205 static void
3206 _collection_roles_convert(uint64_t roles[2])
3207 {
3208    // Currently elm roles and atspi roles are binary compatible.
3209    // Implement this function when it will be needed.
3210    (void)roles;
3211 }
3212
3213 static Eina_Bool
3214 _collection_iter_match_rule_get(Eldbus_Message_Iter *iter, struct collection_match_rule *rule)
3215 {
3216    Eldbus_Message_Iter *states_iter, *attrib_iter, *iter_arg, *role_iter, *ifc_iter;
3217    unsigned int *array;
3218    int array_count, state_match, attrib_match, role_match, ifc_match, reverse;
3219    const char *ifc_name;
3220
3221    if (!eldbus_message_iter_arguments_get(iter, "aiia{ss}iaiiasib", &states_iter, &state_match, &attrib_iter, &attrib_match, &role_iter, &role_match, &ifc_iter, &ifc_match, &reverse))
3222      {
3223         ERR("Unable to get message arguments");
3224         return EINA_FALSE;
3225      }
3226
3227    memset(rule, 0x0, sizeof(struct collection_match_rule));
3228    rule->statematchtype = state_match;
3229    rule->attributematchtype = attrib_match;
3230    rule->rolematchtype = role_match;
3231    rule->interfacematchtype = ifc_match;
3232    rule->reverse = reverse;
3233
3234    if (!eldbus_message_iter_fixed_array_get(states_iter, 'i', &array, &array_count))
3235      return EINA_FALSE;
3236
3237    //Roles according to libatspi impementation are transferred in 2-int element fixed bit array
3238    if (array_count != 2)
3239      {
3240         ERR("Unexpected states array size");
3241         return EINA_FALSE;
3242      }
3243    uint64_t states = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
3244    rule->states = _atspi_state_set_to_elm_atspi_state_set(states);
3245
3246    //Roles according to libatspi impementation are transferred in 4-int element fixed bit array
3247    if (!eldbus_message_iter_fixed_array_get(role_iter, 'i', &array, &array_count))
3248      return EINA_FALSE;
3249
3250    if (array_count != 4)
3251      {
3252         ERR("Unexpected roles array size");
3253         return EINA_FALSE;
3254      }
3255
3256    //convert atspi roles to elm_roles
3257    rule->roles[0] = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
3258    rule->roles[1] = ((uint64_t)array[2] | ((uint64_t)array[3] << 32));
3259
3260    _collection_roles_convert(rule->roles);
3261
3262    //Get matching properties
3263    while (eldbus_message_iter_get_and_next(attrib_iter, '{', &iter_arg))
3264      {
3265         const char *key, *value;
3266         if (eldbus_message_iter_arguments_get(iter_arg, "ss", &key, &value))
3267           {
3268              Elm_Atspi_Attribute *attrib = calloc(sizeof(Elm_Atspi_Attribute), 1);
3269              attrib->key = eina_stringshare_add(key);
3270              attrib->value = eina_stringshare_add(value);
3271              rule->attributes = eina_list_append(rule->attributes, attrib);
3272           }
3273      }
3274
3275    //Get interfaces to match
3276    while (eldbus_message_iter_get_and_next(ifc_iter, 's', &ifc_name))
3277      {
3278         const Eo_Class *class = NULL;
3279         if (!strcmp(ifc_name, "action"))
3280           class = ELM_INTERFACE_ATSPI_ACTION_MIXIN;
3281         else if (!strcmp(ifc_name, "component"))
3282           class = ELM_INTERFACE_ATSPI_COMPONENT_MIXIN;
3283         else if (!strcmp(ifc_name, "editabletext"))
3284           class = ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE;
3285         else if (!strcmp(ifc_name, "text"))
3286           class = ELM_INTERFACE_ATSPI_TEXT_INTERFACE;
3287         else if (!strcmp(ifc_name, "image"))
3288           class = ELM_INTERFACE_ATSPI_SELECTION_INTERFACE;
3289         else if (!strcmp(ifc_name, "value"))
3290           class = ELM_INTERFACE_ATSPI_VALUE_INTERFACE;
3291
3292         if (class)
3293           rule->ifaces = eina_list_append(rule->ifaces, class);
3294         else
3295           {
3296              _collection_match_rule_free(rule);
3297              return EINA_FALSE;
3298           }
3299      }
3300
3301    return EINA_TRUE;
3302 }
3303
3304 static Eina_Bool
3305 _collection_match_interfaces_helper(Eo *obj, Eina_List *ifcs, Eina_Bool condition, Eina_Bool ret_if_true, Eina_Bool ret_if_false)
3306 {
3307    Eo_Class *class;
3308    Eina_List *l;
3309
3310    EINA_LIST_FOREACH(ifcs, l, class)
3311      {
3312         if (eo_isa(obj, class) == condition)
3313           return ret_if_true;
3314      }
3315    return ret_if_false;
3316 }
3317
3318 static Eina_Bool
3319 _collection_match_interfaces_lookup(Eo *obj, struct collection_match_rule *rule)
3320 {
3321    Eina_Bool ret = EINA_FALSE;
3322
3323    switch (rule->interfacematchtype)
3324      {
3325         case ATSPI_Collection_MATCH_INVALID:
3326            ret = EINA_TRUE;
3327            break;
3328         case ATSPI_Collection_MATCH_ALL:
3329            ret = _collection_match_interfaces_helper(
3330               obj, rule->ifaces, EINA_FALSE, EINA_FALSE, EINA_TRUE);
3331            break;
3332         case ATSPI_Collection_MATCH_ANY:
3333            ret = _collection_match_interfaces_helper(
3334               obj, rule->ifaces, EINA_TRUE, EINA_TRUE, EINA_FALSE);
3335            break;
3336         case ATSPI_Collection_MATCH_NONE:
3337            ret = _collection_match_interfaces_helper(
3338               obj, rule->ifaces, EINA_TRUE, EINA_FALSE, EINA_TRUE);
3339            break;
3340         default:
3341            break;
3342      }
3343    return ret;
3344 }
3345
3346 static Eina_Bool
3347 _collection_match_states_lookup(Eo *obj, struct collection_match_rule *rule)
3348 {
3349    Eina_Bool ret = EINA_FALSE;
3350    Elm_Atspi_State_Set ss;
3351
3352    eo_do(obj, ss = elm_interface_atspi_accessible_state_set_get());
3353
3354    switch (rule->statematchtype)
3355      {
3356         case ATSPI_Collection_MATCH_INVALID:
3357            ret = EINA_TRUE;
3358            break;
3359         case ATSPI_Collection_MATCH_ALL:
3360            ret = (ss & rule->states) == rule->states;
3361            break;
3362         case ATSPI_Collection_MATCH_ANY:
3363            ret = (ss & rule->states) > 0;
3364            break;
3365         case ATSPI_Collection_MATCH_NONE:
3366            ret = (ss & rule->states) == 0;
3367            break;
3368         default:
3369            break;
3370      }
3371
3372    return ret;
3373 }
3374
3375 static Eina_Bool
3376 _collection_match_roles_lookup(Eo *obj, struct collection_match_rule *rule)
3377 {
3378    Eina_Bool ret = EINA_FALSE;
3379    Elm_Atspi_Role role;
3380    int64_t role_set;
3381
3382    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
3383
3384    if (role >= 64)
3385      {
3386         role -= 64;
3387         role_set = rule->roles[1];
3388      }
3389    else
3390      role_set = rule->roles[0];
3391
3392    if (role >= 64)
3393      {
3394         ERR("Elm_Atspi_Role enum value exceeds 127. Unable to compare with roles bit field.");
3395         return EINA_FALSE;
3396      }
3397
3398    switch (rule->rolematchtype)
3399      {
3400         case ATSPI_Collection_MATCH_INVALID:
3401            ret = EINA_TRUE;
3402            break;
3403         case ATSPI_Collection_MATCH_ALL:
3404         case ATSPI_Collection_MATCH_ANY:
3405            ret = (role_set & (1ULL << role)) > 0;
3406            break;
3407         case ATSPI_Collection_MATCH_NONE:
3408            ret = (role_set & (1ULL << role)) == 0;
3409            break;
3410         default:
3411            break;
3412      }
3413
3414    return ret;
3415 }
3416
3417 static Eina_Bool
3418 _collection_match_attributes_helper(Eina_List *obj_attribs, Eina_List *attribs, Eina_Bool compare, Eina_Bool ret_if_compare, Eina_Bool ret_default)
3419 {
3420    Eina_List *l, *l2;
3421    Elm_Atspi_Attribute *attr, *attr2;
3422
3423    EINA_LIST_FOREACH(attribs, l, attr)
3424      {
3425         EINA_LIST_FOREACH(obj_attribs, l2, attr2)
3426           {
3427              if ((attr->key && attr2->key &&
3428                   attr->value && attr2->value &&
3429                   !strcmp(attr->key, attr2->key) &&
3430                   !strcmp(attr->value, attr2->value)) == compare)
3431                {
3432                   return ret_if_compare;
3433                }
3434           }
3435      }
3436
3437    return ret_default;
3438 }
3439
3440 static Eina_Bool
3441 _collection_match_attributes_lookup(Eo *obj, struct collection_match_rule *rule)
3442 {
3443    Eina_Bool ret = EINA_FALSE;
3444    Eina_List *obj_attribs;
3445
3446    eo_do(obj, obj_attribs = elm_interface_atspi_accessible_attributes_get());
3447
3448    switch (rule->attributematchtype)
3449      {
3450         case ATSPI_Collection_MATCH_INVALID:
3451            ret = EINA_TRUE;
3452            break;
3453         case ATSPI_Collection_MATCH_ALL:
3454            ret = _collection_match_attributes_helper(
3455               obj_attribs, rule->attributes, EINA_FALSE, EINA_FALSE, EINA_TRUE);
3456            break;
3457         case ATSPI_Collection_MATCH_ANY:
3458            ret = _collection_match_attributes_helper(
3459               obj_attribs, rule->attributes, EINA_TRUE, EINA_TRUE, EINA_FALSE);
3460            break;
3461         case ATSPI_Collection_MATCH_NONE:
3462            ret = _collection_match_attributes_helper(
3463               obj_attribs, rule->attributes, EINA_TRUE, EINA_FALSE, EINA_TRUE);
3464            break;
3465         default:
3466            break;
3467      }
3468
3469    elm_atspi_attributes_list_free(obj_attribs);
3470
3471    return ret;
3472 }
3473
3474 static int
3475 _collection_sort_order_canonical(struct collection_match_rule *rule, Eina_List **ls,
3476                       int count, int max,
3477                       Eo *obj, long index, Eina_Bool flag,
3478                       Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
3479 {
3480    int i = index;
3481    Eina_List *children;
3482    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
3483    long acount = eina_list_count(children);
3484    Eina_Bool prev = pobj ? EINA_TRUE : EINA_FALSE;
3485
3486    for (; i < acount && (max == 0 || count < max); i++)
3487      {
3488         Eo *child = eina_list_nth(children, i);
3489
3490         if (prev && child == pobj)
3491           {
3492              eina_list_free(children);
3493              return count;
3494           }
3495
3496         if (flag && _collection_match_interfaces_lookup(child, rule)
3497             && _collection_match_states_lookup(child, rule)
3498             && _collection_match_roles_lookup(child, rule)
3499             && _collection_match_attributes_lookup(child, rule))
3500           {
3501              *ls = eina_list_append(*ls, child);
3502              count++;
3503           }
3504
3505        if (!flag)
3506          flag = EINA_TRUE;
3507
3508        if (recurse && traverse)
3509          count = _collection_sort_order_canonical(rule, ls, count,
3510                                                   max, child, 0, EINA_TRUE,
3511                                                   pobj, recurse, traverse);
3512      }
3513    eina_list_free(children);
3514    return count;
3515 }
3516
3517 static int
3518 _collection_sort_order_reverse_canonical(struct collection_match_rule *rule, Eina_List **ls,
3519                       int count, int max, Eo *obj, Eina_Bool flag, Eo *pobj)
3520 {
3521   Eo *nextobj, *parent;
3522   long indexinparent;
3523   Eina_List *children;
3524
3525   /* This breaks us out of the recursion. */
3526   if (!obj || obj == pobj)
3527     {
3528       return count;
3529     }
3530
3531   /* Add to the list if it matches */
3532   if (flag && _collection_match_interfaces_lookup(obj, rule)
3533       && _collection_match_states_lookup(obj, rule)
3534       && _collection_match_roles_lookup(obj, rule)
3535       && _collection_match_attributes_lookup(obj, rule)
3536       && (max == 0 || count < max))
3537     {
3538        *ls = eina_list_append(*ls, obj);
3539        count++;
3540     }
3541
3542   if (!flag)
3543     flag = EINA_TRUE;
3544
3545   /* Get the current nodes index in it's parent and the parent object. */
3546   eo_do(obj,
3547         indexinparent = elm_interface_atspi_accessible_index_in_parent_get(),
3548         parent = elm_interface_atspi_accessible_parent_get());
3549
3550   if ((indexinparent > 0) && ((max == 0) || (count < max)))
3551     {
3552        /* there are still some siblings to visit so get the previous sibling
3553           and get it's last descendant.
3554           First, get the previous sibling */
3555        eo_do(parent, children = elm_interface_atspi_accessible_children_get());
3556        nextobj = eina_list_nth(children, indexinparent - 1);
3557        eina_list_free(children);
3558
3559        /* Now, drill down the right side to the last descendant */
3560        do {
3561             eo_do(nextobj, children = elm_interface_atspi_accessible_children_get());
3562             if (children) nextobj = eina_list_last_data_get(children);
3563             eina_list_free(children);
3564        } while (children);
3565
3566        /* recurse with the last descendant */
3567        count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
3568                                        nextobj, EINA_TRUE, pobj);
3569     }
3570   else if (max == 0 || count < max)
3571     {
3572       /* no more siblings so next node must be the parent */
3573       count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
3574                                         parent, EINA_TRUE, pobj);
3575
3576     }
3577   return count;
3578 }
3579
3580 static int
3581 _collection_inbackorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
3582                         int max, Eo *obj)
3583 {
3584    *list = eina_list_append(*list, obj);
3585
3586    _collection_sort_order_reverse_canonical(rule, list, 0, max, obj, EINA_TRUE, collection);
3587
3588    *list = eina_list_remove_list(*list, *list);
3589
3590    return 0;
3591 }
3592
3593 static int
3594 _collection_inorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
3595                     int count, int max, Eo *obj, Eina_Bool traverse)
3596 {
3597    int idx = 0;
3598
3599    count = _collection_sort_order_canonical(rule, list, count, max, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
3600
3601   while ((max == 0 || count < max) && obj && obj != collection)
3602     {
3603        Eo *parent;
3604        eo_do(obj,
3605              parent = elm_interface_atspi_accessible_parent_get(),
3606              idx = elm_interface_atspi_accessible_index_in_parent_get());
3607        count = _collection_sort_order_canonical(rule, list, count, max, parent,
3608                                      idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
3609        obj = parent;
3610     }
3611
3612   if (max == 0 || count < max)
3613     count = _collection_sort_order_canonical(rule, list, count, max,
3614                                     obj, idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
3615
3616   return count;
3617 }
3618
3619 static int
3620 _collection_query(struct collection_match_rule *rule, AtspiCollectionSortOrder sortby,
3621                          Eina_List **list, int count, int max, Eo *obj, long index,
3622                          Eina_Bool flag, Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
3623 {
3624    switch (sortby)
3625      {
3626         case ATSPI_Collection_SORT_ORDER_CANONICAL:
3627            count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
3628                                                     pobj, recurse, traverse);
3629            break;
3630         case ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL:
3631            count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
3632                                                     pobj, recurse, traverse);
3633            *list = eina_list_reverse(*list);
3634            break;
3635         default:
3636           count = 0;
3637           WRN("Unhandled sort method");
3638           break;
3639      }
3640    return count;
3641 }
3642
3643 static Eldbus_Message*
3644 _collection_return_msg_from_list(Elm_Atspi_Bridge *bridge, const Eldbus_Message *msg, const Eina_List *objs)
3645 {
3646    Eldbus_Message *ret;
3647    const Eina_List *l;
3648    Eldbus_Message_Iter *iter, *array_iter;
3649    Eo *obj;
3650
3651    ret = eldbus_message_method_return_new(msg);
3652    if (!ret) return NULL;
3653
3654    iter = eldbus_message_iter_get(ret);
3655    array_iter = eldbus_message_iter_container_new(iter, 'a', "(so)");
3656
3657    EINA_LIST_FOREACH(objs, l, obj)
3658      {
3659         _bridge_object_register(bridge, obj);
3660         _bridge_iter_object_reference_append(bridge, array_iter, obj);
3661      }
3662
3663    eldbus_message_iter_container_close(iter, array_iter);
3664    return ret;
3665 }
3666
3667 static Eina_List*
3668 _collection_get_matches_from_handle(Eo *collection, Eo *current, struct collection_match_rule *rule, AtspiCollectionSortOrder sortby, AtspiCollectionTreeTraversalType tree, int max, Eina_Bool traverse)
3669 {
3670    Eina_List *result = NULL;
3671    Eo *parent;
3672    int idx;
3673
3674    switch (tree)
3675      {
3676       case ATSPI_Collection_TREE_INORDER:
3677            _collection_inorder(collection, rule, &result, 0, max, current, traverse);
3678          if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
3679            result = eina_list_reverse(result);
3680          break;
3681       case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
3682          eo_do(current,
3683                idx = elm_interface_atspi_accessible_index_in_parent_get(),
3684                parent = elm_interface_atspi_accessible_parent_get());
3685          _collection_query(rule, sortby, &result, 0, max, parent, idx, EINA_FALSE, NULL, EINA_TRUE, traverse);
3686          break;
3687       case ATSPI_Collection_TREE_RESTRICT_SIBLING:
3688          _collection_query(rule, sortby, &result, 0, max, current, 0, EINA_FALSE, NULL, EINA_TRUE, traverse);
3689          break;
3690       default:
3691          ERR("Tree parameter value not handled");
3692          break;
3693      }
3694    return result;
3695 }
3696
3697 static Eldbus_Message*
3698 _collection_get_matches_from(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
3699 {
3700    const char *obj_path = eldbus_message_path_get(msg);
3701    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3702    Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
3703    Eldbus_Message *ret;
3704    Eldbus_Message_Iter *iter, *rule_iter;
3705    struct collection_match_rule rule;
3706    int count;
3707    AtspiCollectionTreeTraversalType tree;
3708    Eina_Bool traverse;
3709    AtspiCollectionSortOrder sortby;
3710    Eina_List *result = NULL;
3711
3712    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
3713
3714    iter = eldbus_message_iter_get(msg);
3715    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3716
3717    if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uuib", &obj_path, &rule_iter, &sortby, &tree, &count, &traverse))
3718      {
3719         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
3720      }
3721
3722    current = _bridge_object_from_path(bridge, obj_path);
3723
3724    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
3725
3726    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3727      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3728
3729    result = _collection_get_matches_from_handle(obj, current, &rule, sortby, tree, count, traverse);
3730    ret = _collection_return_msg_from_list(bridge, msg, result);
3731
3732    eina_list_free(result);
3733    _collection_match_rule_free(&rule);
3734
3735    return ret;
3736 }
3737
3738 static Eina_List*
3739 _collection_get_matches_to_handle(Eo *obj, Eo *current, struct collection_match_rule *rule, AtspiCollectionSortOrder sortby, AtspiCollectionTreeTraversalType tree, Eina_Bool limit, int max, Eina_Bool traverse)
3740 {
3741    Eina_List *result = NULL;
3742    Eo *collection = obj;
3743
3744    if (limit)
3745      eo_do(obj, collection = elm_interface_atspi_accessible_parent_get());
3746
3747    switch (tree)
3748      {
3749       case ATSPI_Collection_TREE_INORDER:
3750          _collection_inbackorder(obj, rule, &result, max, current);
3751          if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
3752            result = eina_list_reverse(result);
3753          break;
3754       case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
3755          _collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
3756          break;
3757       case ATSPI_Collection_TREE_RESTRICT_SIBLING:
3758          _collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
3759          break;
3760       default:
3761          ERR("Tree parameter value not handled");
3762          break;
3763      }
3764
3765    return result;
3766 }
3767
3768 static Eldbus_Message*
3769 _collection_get_matches_to(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
3770 {
3771    const char *obj_path = eldbus_message_path_get(msg);
3772    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3773    Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
3774    Eldbus_Message *ret;
3775    Eldbus_Message_Iter *iter, *rule_iter;
3776    struct collection_match_rule rule;
3777    int count;
3778    AtspiCollectionTreeTraversalType tree;
3779    Eina_Bool traverse;
3780    AtspiCollectionSortOrder sortby;
3781    Eina_List *result = NULL;
3782    Eina_Bool limit;
3783
3784    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
3785
3786    iter = eldbus_message_iter_get(msg);
3787    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3788
3789    if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uubib", &obj_path, &rule_iter, &sortby, &tree, &limit, &count, &traverse))
3790      {
3791         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, tree, limit count or traverse values.");
3792      }
3793
3794    current = _bridge_object_from_path(bridge, obj_path);
3795
3796    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
3797
3798    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3799      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3800
3801    result = _collection_get_matches_to_handle(obj, current, &rule, sortby, tree, limit, count, traverse);
3802    ret = _collection_return_msg_from_list(bridge, msg, result);
3803
3804    eina_list_free(result);
3805    _collection_match_rule_free(&rule);
3806
3807    return ret;
3808 }
3809
3810 static Eldbus_Message*
3811 _collection_get_matches(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
3812 {
3813    const char *obj_path = eldbus_message_path_get(msg);
3814    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3815    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3816    Eldbus_Message *ret;
3817    Eldbus_Message_Iter *iter, *rule_iter;
3818    struct collection_match_rule rule;
3819    int count;
3820    Eina_Bool traverse;
3821    AtspiCollectionSortOrder sortby;
3822    Eina_List *result = NULL;
3823
3824    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, msg);
3825
3826    iter = eldbus_message_iter_get(msg);
3827    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3828
3829    if (!eldbus_message_iter_arguments_get(iter, "(aiia{ss}iaiiasib)uib", &rule_iter, &sortby, &count, &traverse))
3830      {
3831         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
3832      }
3833
3834    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3835      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3836
3837    _collection_query(&rule, sortby, &result, 0, count, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
3838
3839    ret = _collection_return_msg_from_list(bridge, msg, result);
3840
3841    eina_list_free(result);
3842    _collection_match_rule_free(&rule);
3843
3844    return ret;
3845 }
3846
3847 static const Eldbus_Method collection_methods[] = {
3848    { "GetMatchesFrom",
3849       ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
3850                   {"u", "sortby"}, {"u", "tree"}, {"i", "count"}, {"b", "traverse"}),
3851       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_from, 0 },
3852    { "GetMatchesTo",
3853       ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
3854                   {"u", "sortby"}, {"u", "tree"}, {"b", "limit_scope"},
3855                   {"i", "count"}, {"b", "traverse"}),
3856       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_to, 0 },
3857    { "GetMatches",
3858       ELDBUS_ARGS({"(aiia{ss}iaiiasib)", "match_rule"},
3859                   {"u", "sortby"}, {"i", "count"}, {"b", "traverse"}),
3860       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches, 0 },
3861    { NULL, NULL, NULL, NULL, 0 }
3862 };
3863
3864 static const Eldbus_Service_Interface_Desc collection_iface_desc = {
3865    ATSPI_DBUS_INTERFACE_COLLECTION, collection_methods, NULL, NULL, NULL, NULL
3866 };
3867
3868 static void
3869 _object_get_bus_name_and_path(Eo *bridge, const Eo *obj, const char **bus_name, const char **path)
3870 {
3871    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
3872
3873    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
3874    if (eo_isa(obj, ELM_ATSPI_PROXY_CLASS))
3875      {
3876         const char *pbus = "", *ppath = ATSPI_DBUS_PATH_NULL;
3877         eo_do(obj, elm_obj_atspi_proxy_address_get(&pbus, &ppath));
3878         if (pbus && ppath)
3879           {
3880             if (bus_name) *bus_name = pbus;
3881             if (path) *path = ppath;
3882              return;
3883           }
3884        DBG("Invalid proxy address! Address not set before connecting/listening. Or after proxy is removed.");
3885      }
3886    if (bus_name) *bus_name = eldbus_connection_unique_name_get(pd->a11y_bus);
3887    if (path) *path = _bridge_path_from_object(bridge, obj);
3888    //
3889 }
3890
3891 static void
3892 _bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj)
3893 {
3894    EINA_SAFETY_ON_NULL_RETURN(iter);
3895
3896    const char *pbus = NULL, *ppath = NULL;
3897    _object_get_bus_name_and_path(bridge, obj, &pbus, &ppath);
3898    Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
3899    eldbus_message_iter_basic_append(iter_struct, 's', pbus);
3900    eldbus_message_iter_basic_append(iter_struct, 'o', ppath);
3901    eldbus_message_iter_container_close(iter, iter_struct);
3902 }
3903
3904 static void
3905 _object_desktop_reference_append(Eldbus_Message_Iter *iter)
3906 {
3907   Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
3908   EINA_SAFETY_ON_NULL_RETURN(iter);
3909
3910   eldbus_message_iter_basic_append(iter_struct, 's', ATSPI_DBUS_NAME_REGISTRY);
3911   eldbus_message_iter_basic_append(iter_struct, 'o', ATSPI_DBUS_PATH_ROOT);
3912   eldbus_message_iter_container_close(iter, iter_struct);
3913 }
3914
3915 static void
3916 _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj)
3917 {
3918   Eldbus_Message_Iter *iter_array;
3919   iter_array = eldbus_message_iter_container_new(iter, 'a', "s");
3920   if (!iter_array) return;
3921
3922   if (eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
3923     {
3924        eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACCESSIBLE);
3925        eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COLLECTION);
3926     }
3927   if (eo_isa(obj, ELM_INTERFACE_ATSPI_ACTION_MIXIN))
3928     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACTION);
3929   if (eo_isa(obj, ELM_ATSPI_APP_OBJECT_CLASS))
3930     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_APPLICATION);
3931   if (eo_isa(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN))
3932     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COMPONENT);
3933   if (eo_isa(obj, ELM_INTERFACE_ATSPI_EDITABLE_TEXT_INTERFACE))
3934     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_EDITABLE_TEXT);
3935   if (eo_isa(obj, ELM_INTERFACE_ATSPI_IMAGE_MIXIN))
3936     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_IMAGE);
3937   if (eo_isa(obj, ELM_INTERFACE_ATSPI_SELECTION_INTERFACE))
3938     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_SELECTION);
3939   if (eo_isa(obj, ELM_INTERFACE_ATSPI_TEXT_INTERFACE))
3940     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_TEXT);
3941   if (eo_isa(obj, ELM_INTERFACE_ATSPI_VALUE_INTERFACE))
3942     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_VALUE);
3943
3944   eldbus_message_iter_container_close(iter, iter_array);
3945 }
3946
3947 static Eina_Bool
3948 _cache_item_reference_append_cb(Eo *bridge, Eo *data, Eldbus_Message_Iter *iter_array)
3949 {
3950   if (!eo_ref_get(data) || eo_destructed_is(data))
3951     return EINA_TRUE;
3952
3953   Eldbus_Message_Iter *iter_struct, *iter_sub_array;
3954   Elm_Atspi_State_Set states;
3955   Elm_Atspi_Role role;
3956   Eo *root = elm_atspi_bridge_root_get(bridge);
3957
3958   eo_do(data, role = elm_interface_atspi_accessible_role_get());
3959
3960   iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
3961   EINA_SAFETY_ON_NULL_RETURN_VAL(iter_struct, EINA_TRUE);
3962
3963   /* Marshall object path */
3964   _bridge_iter_object_reference_append(bridge, iter_struct, data);
3965
3966   /* Marshall application */
3967   _bridge_iter_object_reference_append(bridge, iter_struct, root);
3968
3969   Eo *parent = NULL;
3970   eo_do(data, parent = elm_interface_atspi_accessible_parent_get());
3971   /* Marshall parent */
3972   if ((!parent) && (ELM_ATSPI_ROLE_APPLICATION == role))
3973     _object_desktop_reference_append(iter_struct);
3974   else
3975     _bridge_iter_object_reference_append(bridge, iter_struct, parent);
3976
3977   /* Marshall children  */
3978   Eina_List *children_list = NULL, *l;
3979   Eo *child;
3980
3981   //TIZEN_ONLY(20150709) Do not register children of MANAGES_DESCENDATS objects
3982   Elm_Atspi_State_Set ss;
3983   eo_do(data, ss = elm_interface_atspi_accessible_state_set_get());
3984   //
3985   iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
3986   EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail);
3987
3988   //TIZEN_ONLY(20150709) Do not register children of MANAGES_DESCENDATS objects
3989   if (!STATE_TYPE_GET(ss, ELM_ATSPI_STATE_MANAGES_DESCENDANTS))
3990     {
3991        eo_do(data, children_list = elm_interface_atspi_accessible_children_get());
3992   //
3993        EINA_LIST_FOREACH(children_list, l, child)
3994           _bridge_iter_object_reference_append(bridge, iter_sub_array, child);
3995
3996   //TIZEN_ONLY(20150709) Do not register children of MANAGES_DESCENDATS objects
3997        eina_list_free(children_list);
3998     }
3999   //
4000
4001   eldbus_message_iter_container_close(iter_struct, iter_sub_array);
4002
4003   /* Marshall interfaces */
4004   _iter_interfaces_append(iter_struct, data);
4005
4006   /* Marshall name */
4007   const char *name = NULL;
4008   eo_do(data, name = elm_interface_atspi_accessible_name_get());
4009   if (!name)
4010     name = "";
4011
4012   eldbus_message_iter_basic_append(iter_struct, 's', name);
4013
4014   /* Marshall role */
4015   eldbus_message_iter_basic_append(iter_struct, 'u', role);
4016
4017   /* Marshall description */
4018   const char* descritpion = NULL;
4019   eo_do(data, descritpion = elm_interface_atspi_accessible_description_get());
4020   if (!descritpion)
4021     descritpion = "";
4022   eldbus_message_iter_basic_append(iter_struct, 's', descritpion);
4023
4024   /* Marshall state set */
4025   iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "u");
4026   EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail);
4027
4028   eo_do(data, states = elm_interface_atspi_accessible_state_set_get());
4029
4030   unsigned int s1 = states & 0xFFFFFFFF;
4031   unsigned int s2 = (states >> 32) & 0xFFFFFFFF;
4032   eldbus_message_iter_basic_append(iter_sub_array, 'u', s1);
4033   eldbus_message_iter_basic_append(iter_sub_array, 'u', s2);
4034
4035   eldbus_message_iter_container_close(iter_struct, iter_sub_array);
4036   eldbus_message_iter_container_close(iter_array, iter_struct);
4037
4038   return EINA_TRUE;
4039
4040 fail:
4041   if (iter_struct) eldbus_message_iter_del(iter_struct);
4042   return EINA_TRUE;
4043 }
4044
4045 static Eldbus_Message *
4046 _cache_get_items(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
4047 {
4048    Eldbus_Message_Iter *iter, *iter_array;
4049    Eldbus_Message *ret;
4050    Eina_List *to_process;
4051    Eo *root;
4052
4053    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4054    if (!bridge) return NULL;
4055
4056    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
4057
4058    ret = eldbus_message_method_return_new(msg);
4059    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4060
4061    iter = eldbus_message_iter_get(ret);
4062    iter_array = eldbus_message_iter_container_new(iter, 'a', CACHE_ITEM_SIGNATURE);
4063    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
4064
4065    eo_do(bridge, root = elm_obj_atspi_bridge_root_get());
4066    to_process = eina_list_append(NULL, root);
4067
4068    while (to_process)
4069      {
4070         Eo *obj = eina_list_data_get(to_process);
4071         to_process = eina_list_remove_list(to_process, to_process);
4072         _cache_item_reference_append_cb(bridge, obj, iter_array);
4073         _bridge_object_register(bridge, obj);
4074
4075         Eina_List *children;
4076         eo_do(obj, children = elm_interface_atspi_accessible_children_get());
4077         to_process = eina_list_merge(to_process, children);
4078      }
4079
4080    eldbus_message_iter_container_close(iter, iter_array);
4081
4082    return ret;
4083 fail:
4084    if (ret) eldbus_message_unref(ret);
4085    return NULL;
4086 }
4087
4088 static const Eldbus_Method cache_methods[] = {
4089    { "GetItems", NULL, ELDBUS_ARGS({CACHE_ITEM_SIGNATURE, "items"}), _cache_get_items, 0 },
4090    { NULL, NULL, NULL, NULL, 0 }
4091 };
4092
4093 static const Eldbus_Signal cache_signals[] = {
4094   [ATSPI_OBJECT_CHILD_ADDED] = { "AddAccessible", ELDBUS_ARGS({"((so)(so)a(so)assusau)", "added"}), 0},
4095   [ATSPI_OBJECT_CHILD_REMOVED] = { "RemoveAccessible", ELDBUS_ARGS({ "(so)", "removed" }), 0},
4096   {NULL, NULL, 0}
4097 };
4098
4099 static const Eldbus_Service_Interface_Desc cache_iface_desc = {
4100    ATSPI_DBUS_INTERFACE_CACHE, cache_methods, cache_signals, NULL, NULL, NULL
4101 };
4102
4103 // Component interface
4104 static Eldbus_Message *
4105 _component_contains(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4106 {
4107    const char *obj_path = eldbus_message_path_get(msg);
4108    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4109    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4110    int x, y;
4111    Eina_Bool contains = EINA_FALSE;
4112    AtspiCoordType coord_type;
4113    Eldbus_Message *ret;
4114
4115    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
4116
4117    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
4118      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4119
4120    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4121    eo_do(obj, contains = elm_interface_atspi_component_contains(type, x, y));
4122
4123    ret = eldbus_message_method_return_new(msg);
4124    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4125
4126    eldbus_message_arguments_append(ret, "b", contains);
4127
4128    return ret;
4129 }
4130
4131 static Eldbus_Message *
4132 _component_get_accessible_at_point(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4133 {
4134    const char *obj_path = eldbus_message_path_get(msg);
4135    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4136    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
4137    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
4138    //
4139    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4140    int x, y;
4141    Eo *accessible = NULL;
4142    AtspiCoordType coord_type;
4143    Eldbus_Message *ret;
4144    Eldbus_Message_Iter *iter;
4145
4146    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
4147
4148    // TIZEN_ONLY(20161213) - do not response if ecore evas is obscured
4149    const Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
4150    if (ecore_evas_obscured_get(ee))
4151      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "ecore evas is obscured.");
4152    //
4153
4154    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
4155      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4156
4157    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
4158    Evas_Object *top = elm_object_top_widget_get(obj);
4159    int sx = 0;
4160    int sy = 0;
4161    eo_do(top, elm_interface_atspi_component_socket_offset_get(&sx, &sy));
4162
4163    x = x - sx;
4164    y = y - sy;
4165    //
4166
4167    ret = eldbus_message_method_return_new(msg);
4168    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4169
4170    iter = eldbus_message_iter_get(ret);
4171    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4172    eo_do(obj, accessible = elm_interface_atspi_component_accessible_at_point_get(type, x, y));
4173    _bridge_iter_object_reference_append(bridge, iter, accessible);
4174    _bridge_object_register(bridge, accessible);
4175
4176    return ret;
4177 }
4178
4179 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
4180 typedef enum {
4181   NEIGHBOR_SEARCH_MODE_NORMAL = 0,
4182   NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
4183   NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
4184   NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3,
4185 } GetNeighborSearchMode;
4186
4187 typedef struct accessibility_navigation_pointer_table {
4188    AtspiRole (*object_get_role)(struct accessibility_navigation_pointer_table *t, void *ptr);
4189    uint64_t (*object_get_state_set)(struct accessibility_navigation_pointer_table *t, void *ptr);
4190    void *(*get_object_in_relation_by_type)(struct accessibility_navigation_pointer_table *t, void *ptr, AtspiRelationType type);
4191    unsigned char (*object_is_zero_size)(struct accessibility_navigation_pointer_table *t, void *ptr);
4192    void *(*get_parent)(struct accessibility_navigation_pointer_table *t, void *ptr);
4193    unsigned char (*object_is_scrollable)(struct accessibility_navigation_pointer_table *t, void *ptr);
4194    void *(*get_object_at_point)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
4195    unsigned char (*object_contains)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
4196    unsigned char (*object_is_proxy)(struct accessibility_navigation_pointer_table *t, void *ptr);
4197 } accessibility_navigation_pointer_table;
4198
4199 #define CALL(fncname, ...) table->fncname(table, __VA_ARGS__)
4200 static unsigned char _accept_object_check_role(accessibility_navigation_pointer_table *table EINA_UNUSED, void *obj)
4201 {
4202    return _elm_widget_atspi_role_acceptable_check(obj);
4203 }
4204
4205 static unsigned char _state_set_is_set(uint64_t state_set, AtspiStateType state)
4206 {
4207    return (state_set & ((uint64_t)1 << (unsigned int)state)) != 0;
4208 }
4209
4210 static unsigned char _object_is_defunct(accessibility_navigation_pointer_table *table, void *ptr)
4211 {
4212    uint64_t states = CALL(object_get_state_set, ptr);
4213    return _state_set_is_set(states, ATSPI_STATE_DEFUNCT);
4214 }
4215
4216 static unsigned char _object_role_is_acceptable_when_navigating_next_prev(accessibility_navigation_pointer_table *table, void *obj)
4217 {
4218    AtspiRole role = CALL(object_get_role, obj);
4219    return role != ATSPI_ROLE_POPUP_MENU && role != ATSPI_ROLE_DIALOG;
4220 }
4221
4222 static void *_get_object_in_relation_flow(accessibility_navigation_pointer_table *table, void *source, unsigned char forward)
4223 {
4224     return CALL(get_object_in_relation_by_type, source, forward ? ATSPI_RELATION_FLOWS_TO : ATSPI_RELATION_FLOWS_FROM);
4225 }
4226
4227 static unsigned char _object_is_item(accessibility_navigation_pointer_table *table, void *obj)
4228 {
4229    AtspiRole role = CALL(object_get_role, obj);
4230    return role == ATSPI_ROLE_LIST_ITEM || role == ATSPI_ROLE_MENU_ITEM;
4231 }
4232
4233 static unsigned char _object_is_highlightable(accessibility_navigation_pointer_table *table, void *obj)
4234 {
4235    uint64_t state_set = CALL(object_get_state_set, obj);
4236    return _state_set_is_set(state_set, ATSPI_STATE_HIGHLIGHTABLE);
4237 }
4238
4239 static unsigned char _object_is_visible(accessibility_navigation_pointer_table *table, void *obj)
4240 {
4241    uint64_t state_set = CALL(object_get_state_set, obj);
4242    return _state_set_is_set(state_set, ATSPI_STATE_VISIBLE);
4243 }
4244
4245 static unsigned char _object_is_showing(accessibility_navigation_pointer_table *table, void *obj)
4246 {
4247    uint64_t state_set = CALL(object_get_state_set, obj);
4248    return _state_set_is_set(state_set, ATSPI_STATE_SHOWING);
4249 }
4250
4251 static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table *table, void *obj)
4252 {
4253    uint64_t state_set = CALL(object_get_state_set, obj);
4254    return
4255       _state_set_is_set(state_set, ATSPI_STATE_EXPANDABLE) &&
4256       !_state_set_is_set(state_set, ATSPI_STATE_EXPANDED);
4257 }
4258
4259 static unsigned char _object_has_modal_state(accessibility_navigation_pointer_table *table, void *obj)
4260 {
4261    uint64_t state_set = CALL(object_get_state_set, obj);
4262    return _state_set_is_set(state_set, ATSPI_STATE_MODAL);
4263 }
4264
4265 static unsigned char _object_is_zero_size(accessibility_navigation_pointer_table *table, void *obj)
4266 {
4267    return CALL(object_is_zero_size, obj);
4268 }
4269
4270 static void *_get_scrollable_parent(accessibility_navigation_pointer_table *table, void *obj)
4271 {
4272    while(obj)
4273      {
4274        obj = CALL(get_parent, obj);
4275        if (obj && CALL(object_is_scrollable, obj)) return obj;
4276      }
4277    return NULL;
4278 }
4279 static unsigned char _accept_object(accessibility_navigation_pointer_table *table, void *obj)
4280 {
4281    if (!obj) return 0;
4282    if (!_object_is_visible(table, obj)) return 0;
4283    if (!_accept_object_check_role(table, obj)) return 0;
4284    if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
4285    if (!_object_is_highlightable(table, obj)) return 0;
4286
4287    if (_get_scrollable_parent(table, obj) != NULL)
4288      {
4289        void *parent = CALL(get_parent, obj);
4290
4291        if (parent)
4292          {
4293            return !_object_is_item(table, obj) || !_object_is_collapsed(table, parent);
4294          }
4295      }
4296    else
4297      {
4298        if (_object_is_zero_size(table, obj)) return 0;
4299        if (!_object_is_showing(table, obj)) return 0;
4300      }
4301    return 1;
4302 }
4303
4304 /* The target cannot be a parent of root */
4305 static Eina_Bool _target_validation_check(Eo *target, Eo *root)
4306 {
4307    Eo *parent;
4308    eo_do(root, parent = elm_interface_atspi_accessible_parent_get());
4309
4310    while (parent)
4311      {
4312         if (parent == target) return EINA_FALSE;
4313         eo_do(parent, parent = elm_interface_atspi_accessible_parent_get());
4314      }
4315
4316    return EINA_TRUE;
4317 }
4318
4319 static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigation_pointer_table *table,
4320           void *root, int x, int y, unsigned char coordinates_are_screen_based)
4321 {
4322    if (!root) return NULL;
4323    void *prev_root = root;
4324
4325    void *return_value = NULL;
4326    while (1)
4327      {
4328        void *target = CALL(get_object_at_point, root, x, y, coordinates_are_screen_based);
4329        if (!target) break;
4330        if (target == root || target == prev_root) break;
4331        if (!_target_validation_check(target, root)) break;
4332
4333        // always return proxy, so atspi lib can call on it again
4334        if (CALL(object_is_proxy, target)) return target;
4335
4336        root = target;
4337        void *relation_obj = CALL(get_object_in_relation_by_type, root, ATSPI_RELATION_CONTROLLED_BY);
4338        unsigned char contains = 0;
4339        if (relation_obj)
4340          {
4341            contains = CALL(object_contains, relation_obj, x, y, coordinates_are_screen_based);
4342            if (contains) root = relation_obj;
4343          }
4344
4345        if (_accept_object(table, root))
4346          {
4347            return_value = root;
4348            if (contains) break;
4349          }
4350      }
4351
4352    if (return_value && _object_has_modal_state(table, return_value)) return_value = NULL;
4353    return return_value;
4354 }
4355
4356 static void *_find_non_defunct_child(accessibility_navigation_pointer_table *table,
4357             Eina_List *children, unsigned int current_index, unsigned char forward)
4358 {
4359    unsigned int children_count = eina_list_count(children);
4360    for(; current_index < children_count; forward ? ++current_index : --current_index)
4361      {
4362        void *n = eina_list_nth(children, current_index);
4363        if (n && !_object_is_defunct(table, n)) return n;
4364      }
4365    return NULL;
4366 }
4367
4368 static void *_directional_depth_first_search_try_non_defunct_child(accessibility_navigation_pointer_table *table,
4369             void *node, Eina_List *children, unsigned char forward)
4370 {
4371    unsigned int children_count = eina_list_count(children);
4372    if (children_count > 0)
4373      {
4374        unsigned char is_showing = _get_scrollable_parent(table, node) == NULL ? _object_is_showing(table, node) : 1;
4375        if (is_showing)
4376          {
4377            return _find_non_defunct_child(table, children, forward ? 0 : children_count - 1, forward);
4378          }
4379      }
4380    return NULL;
4381 }
4382
4383 static Eina_List *_scrollable_parent_list_get(Eo *obj)
4384 {
4385    Eina_List *ret = NULL;
4386    Eo *parent;
4387
4388    if (obj)
4389      {
4390         eo_do(obj, parent = elm_interface_atspi_accessible_parent_get());
4391         while (parent)
4392           {
4393              if (eo_isa(parent, ELM_INTERFACE_SCROLLABLE_MIXIN))
4394                {
4395                   ret = eina_list_append(ret, parent);
4396                }
4397              eo_do(parent, parent = elm_interface_atspi_accessible_parent_get());
4398           }
4399      }
4400
4401    return ret;
4402 }
4403
4404 static void _viewport_geometry_get(Eo *obj, int *x, int *y, int *w, int *h)
4405 {
4406    eo_do(obj, elm_interface_scrollable_content_viewport_geometry_get(x, y, w, h));
4407    /* widget implements scrollable interface but does not use scoller
4408       in this case, use widget geometry */
4409    if (*w == 0 || *h == 0)
4410      {
4411         INF("%s is zero sized content viewport", eo_class_name_get(eo_class_get(obj)));
4412         eo_do(obj, elm_interface_atspi_component_extents_get(EINA_FALSE, x, y, w, h));
4413      }
4414 }
4415
4416 static Eina_Bool
4417 _new_scrollable_parent_viewport_geometry_get(Eo *node, Eo *start,
4418                                              int *x, int *y, int *w, int *h)
4419 {
4420    Eina_Bool ret = EINA_FALSE;
4421    Eina_List *n_spl;
4422    Eina_List *s_spl;
4423
4424    n_spl = _scrollable_parent_list_get(node);
4425    s_spl = _scrollable_parent_list_get(start);
4426
4427    Eo *sp;
4428    Eina_List *l;
4429    EINA_LIST_FOREACH(s_spl, l, sp)
4430      {
4431         n_spl = eina_list_remove(n_spl, sp);
4432      }
4433
4434    Evas_Coord sx = 0, sy = 0, sw = 0, sh = 0;
4435
4436    unsigned int count = eina_list_count(n_spl);
4437    if (count > 0)
4438      {
4439         sp = eina_list_nth(n_spl, count - 1);
4440         _viewport_geometry_get(sp, &sx, &sy, &sw, &sh);
4441         ret = EINA_TRUE;
4442      }
4443
4444    *x = sx;
4445    *y = sy;
4446    *w = sw;
4447    *h = sh;
4448
4449    return ret;
4450 }
4451
4452 static Eina_List *_valid_children_get(Eina_List *children, Eo *start, Eo *root)
4453 {
4454    /* condition to find first(last) object regardless of scrollable parent.
4455       looping navigation does not care scrollable parent.
4456       1. currently highlighted object exists
4457       2. both start and root are same */
4458    Eo *current = _elm_object_accessibility_currently_highlighted_get();
4459    if (current && start == root) return children;
4460
4461    Eo *child = NULL;
4462    child = eina_list_nth(children, 0);
4463
4464    if (child)
4465      {
4466         Evas_Coord x = 0, y = 0, w = 0, h = 0;
4467         Evas_Coord sx = 0, sy = 0, sw = 0, sh = 0;
4468
4469         if (_new_scrollable_parent_viewport_geometry_get(child, start,
4470                                                    &sx, &sy, &sw, &sh))
4471           {
4472              Eina_List *l, *l_next;
4473              EINA_LIST_FOREACH_SAFE(children, l, l_next, child)
4474                {
4475                   eo_do(child,
4476                         elm_interface_atspi_component_extents_get(EINA_FALSE,
4477                                                              &x, &y, &w, &h));
4478                   if (w == 0 || h == 0 ||
4479                       !ELM_RECTS_INTERSECT(x, y, w, h, sx, sy, sw, sh))
4480                      children = eina_list_remove_list(children, l);
4481                }
4482           }
4483      }
4484    return children;
4485 }
4486
4487 static void *_get_next_non_defunct_sibling(accessibility_navigation_pointer_table *table,
4488             void *obj, void *start, void *root, unsigned char forward)
4489 {
4490    if (!obj) return NULL;
4491    void *parent = CALL(get_parent, obj);
4492    if (!parent) return NULL;
4493
4494    Eina_List *children;
4495    eo_do(parent, children = elm_interface_atspi_accessible_children_get());
4496    children = _valid_children_get(children, start, root);
4497
4498    unsigned int children_count = eina_list_count(children);
4499    if (children_count == 0)
4500      {
4501         eina_list_free(children);
4502         return NULL;
4503      }
4504    unsigned int current = 0;
4505    for(; current < children_count && eina_list_nth(children, current) != obj; ++current) ;
4506    if (current >= children_count)
4507      {
4508         eina_list_free(children);
4509         return NULL;
4510      }
4511    forward ? ++current : --current;
4512    void *ret = _find_non_defunct_child(table, children, current, forward);
4513    eina_list_free(children);
4514    return ret;
4515 }
4516
4517 static void *
4518 _directional_depth_first_search_try_non_defunct_sibling(accessibility_navigation_pointer_table *table,
4519                                                               unsigned char *all_children_visited_ptr,
4520                                                                   void *node, void *start, void *root,
4521                                                                                 unsigned char forward)
4522 {
4523    while(1)
4524      {
4525        void *sibling = _get_next_non_defunct_sibling(table, node, start, root, forward);
4526        if (sibling != NULL)
4527          {
4528            node = sibling;
4529            *all_children_visited_ptr = 0;
4530            break;
4531          }
4532
4533        // walk up...
4534        node = CALL(get_parent, node);
4535        if (node == NULL || node == root) return NULL;
4536
4537        // in backward traversing stop the walk up on parent
4538        if (!forward) break;
4539      }
4540    return node;
4541 }
4542
4543 typedef struct {
4544     const void *key;
4545     unsigned int current_search_size;
4546     unsigned int counter;
4547 } cycle_detection_data;
4548
4549 void cycle_detection_initialize(cycle_detection_data *data, const void *key)
4550 {
4551    if (!data) return;
4552    data->key = key;
4553    data->current_search_size = 1;
4554    data->counter = 1;
4555 }
4556
4557 unsigned char cycle_detection_check_if_in_cycle(cycle_detection_data *data, const void *key)
4558 {
4559    if (!data) return 1;
4560    if (data->key == key) return 1;
4561    if (--data->counter == 0)
4562      {
4563        data->current_search_size <<= 1;
4564        if (data->current_search_size == 0) return 1;
4565        data->counter = data->current_search_size;
4566        data->key = key;
4567      }
4568    return 0;
4569 }
4570
4571 static Eina_Bool
4572 _deputy_is(Eo *obj)
4573 {
4574    if (eo_isa(obj, ELM_ACCESS_CLASS))
4575      {
4576         Elm_Access_Info *info;
4577
4578         info = _elm_access_info_get(obj);
4579         if (info && eo_isa(info->part_object, ELM_LAYOUT_CLASS))
4580           {
4581              Eina_List *attrs, *l;
4582              Elm_Atspi_Attribute *attr;
4583
4584              eo_do(info->part_object,
4585                attrs = elm_interface_atspi_accessible_attributes_get());
4586              EINA_LIST_FOREACH(attrs, l, attr)
4587                {
4588                   if (!strcmp(attr->key, "___PlugID"))
4589                     {
4590                        elm_atspi_attributes_list_free(attrs);
4591                        return EINA_TRUE;
4592                     }
4593                }
4594              elm_atspi_attributes_list_free(attrs);
4595           }
4596      }
4597    return EINA_FALSE;
4598 }
4599
4600 static Eo *
4601 _proxy_in_parent_get(Eo *obj)
4602 {
4603    Eina_List *l;
4604    Eo *proxy = NULL;
4605    Eina_List *children_list = NULL;
4606    eo_do(obj, children_list = elm_interface_atspi_accessible_children_get());
4607
4608    Evas_Object *child;
4609    EINA_LIST_FOREACH(children_list, l, child)
4610      {
4611         if (eo_isa(child, ELM_ATSPI_PROXY_CLASS))
4612           {
4613              proxy = child;
4614              break;
4615           }
4616      }
4617    eina_list_free(children_list);
4618
4619    return proxy;
4620 }
4621
4622 static Eo *
4623 _deputy_of_proxy_in_parent_get(Eo *obj)
4624 {
4625    Eina_List *l;
4626    Eo *deputy = NULL;
4627    Eina_List *children_list = NULL;
4628    eo_do(obj, children_list = elm_interface_atspi_accessible_children_get());
4629
4630    unsigned int index = 0;
4631    Evas_Object *child;
4632    EINA_LIST_FOREACH(children_list, l, child)
4633      {
4634         if (eo_isa(child, ELM_ATSPI_PROXY_CLASS))
4635           {
4636              if (index == 0)
4637                {
4638                   WRN("Proxy does not have deputy object");
4639                   break;
4640                }
4641
4642              deputy = eina_list_nth(children_list, index - 1);
4643              break;
4644           }
4645         index++;
4646      }
4647    eina_list_free(children_list);
4648
4649    return deputy;
4650 }
4651
4652 static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *table, void *root, void *start, unsigned char forward, GetNeighborSearchMode search_mode)
4653 {
4654    if (root && _object_is_defunct(table, root)) return NULL;
4655    if (start && _object_is_defunct(table, start))
4656      {
4657        start = NULL;
4658        forward = 1;
4659      }
4660
4661    if (search_mode == NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE)
4662      {
4663         /* This only works if we navigate backward, and it is not possible to
4664            find in embedded process. In this case the deputy should be used */
4665         return _deputy_of_proxy_in_parent_get(start);
4666      }
4667
4668    void *node = start ? start : root;
4669    if (!node) return NULL;
4670
4671    // initialization of all-children-visited flag for start node - we assume
4672    // that when we begin at start node and we navigate backward, then all children
4673    // are visited, so navigation will ignore start's children and go to
4674    // previous sibling available.
4675    /* Regarding condtion (start != root):
4676       The last object can be found only if all_children_visited is false.
4677       The start is same with root, when looking for the last object. */
4678    unsigned char all_children_visited = (start != root) && (search_mode != NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT && !forward);
4679
4680    // true, if starting element should be ignored. this is only used in rare case of
4681    // recursive search failing to find an object.
4682    // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
4683    // element A algorithm has to descend into BUS_B and search element B and its children. this is done
4684    // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
4685    // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
4686    // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
4687    // this flag means, that object A was already checked previously and we should skip it and its children.
4688    unsigned char force_next = (search_mode == NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING);
4689
4690    cycle_detection_data cycle_detection;
4691    cycle_detection_initialize(&cycle_detection, node);
4692    while (node)
4693      {
4694        if (_object_is_defunct(table, node)) return NULL;
4695
4696        // always accept proxy object from different world
4697        if (!force_next && CALL(object_is_proxy, node)) return node;
4698
4699        Eina_List *children;
4700        eo_do(node, children = elm_interface_atspi_accessible_children_get());
4701        children = _valid_children_get(children, start, root);
4702
4703        // do accept:
4704        // 1. not start node
4705        // 2. parent after all children in backward traversing
4706        // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
4707        //    Objects with those roles shouldnt be reachable, when navigating next / prev.
4708        unsigned char all_children_visited_or_moving_forward = (eina_list_count(children) == 0 || forward || all_children_visited);
4709        if (!force_next && node != start && all_children_visited_or_moving_forward && _accept_object(table, node))
4710          {
4711            if (start == NULL || _object_role_is_acceptable_when_navigating_next_prev(table, node))
4712              {
4713                eina_list_free(children);
4714                return node;
4715              }
4716          }
4717
4718        void *next_related_in_direction = !force_next ? _get_object_in_relation_flow(table, node, forward) : NULL;
4719
4720        /* force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING
4721           in this case the node is elm_layout which is parent of proxy object.
4722           There is an access object working for the proxy object, and the access
4723           object could have relation information. This relation information should
4724           be checked first before using the elm_layout as a node. */
4725        if (force_next && forward)
4726          {
4727             Eo *deputy;
4728             deputy = _deputy_of_proxy_in_parent_get(node);
4729             next_related_in_direction =
4730               _get_object_in_relation_flow(table, deputy, forward);
4731          }
4732
4733        if (next_related_in_direction && _object_is_defunct(table, next_related_in_direction))
4734            next_related_in_direction = NULL;
4735        unsigned char want_cycle_detection = 0;
4736        if (next_related_in_direction)
4737          {
4738            /* Check next_related_in_direction is deputy object */
4739            Eo *parent;
4740            if (!forward)
4741              {
4742                 /* If the prev object is deputy, then go to inside of its proxy first */
4743                 if (_deputy_is(next_related_in_direction))
4744                   {
4745                      parent = elm_widget_parent_get(next_related_in_direction);
4746                      next_related_in_direction =
4747                        _proxy_in_parent_get(parent);
4748                   }
4749              }
4750            else
4751              {
4752                 /* If current object is deputy, and it has relation next object,
4753                    then do not use the relation next object, and use proxy first */
4754                 if (_deputy_is(node))
4755                   {
4756                      parent = elm_widget_parent_get(node);
4757                      next_related_in_direction =
4758                        _proxy_in_parent_get(parent);
4759                   }
4760              }
4761
4762            node = next_related_in_direction;
4763            want_cycle_detection = 1;
4764          }
4765        else {
4766            void *child = !force_next && !all_children_visited ?
4767                           _directional_depth_first_search_try_non_defunct_child(table, node, children, forward) : NULL;
4768            if (child != NULL) want_cycle_detection = 1;
4769            else
4770              {
4771                if (!force_next && node == root)
4772                  {
4773                    eina_list_free(children);
4774                    return NULL;
4775                  }
4776                all_children_visited = 1;
4777                child = _directional_depth_first_search_try_non_defunct_sibling(table, &all_children_visited, node, start, root, forward);
4778              }
4779            node = child;
4780        }
4781
4782        force_next = 0;
4783        if (want_cycle_detection && cycle_detection_check_if_in_cycle(&cycle_detection, node))
4784          {
4785            eina_list_free(children);
4786            return NULL;
4787          }
4788        eina_list_free(children);
4789      }
4790    return NULL;
4791 }
4792
4793 typedef struct accessibility_navigation_pointer_table_impl {
4794   accessibility_navigation_pointer_table ptrs;
4795   Eo *bridge;
4796 } accessibility_navigation_pointer_table_impl;
4797
4798 static AtspiRole _object_get_role_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr)
4799 {
4800    Elm_Atspi_Role role;
4801    Eo *obj = (Eo*)ptr;
4802    eo_do(obj, role = elm_interface_atspi_accessible_role_get());
4803    return _elm_role_to_atspi_role(role);
4804 }
4805
4806 static uint64_t _object_get_state_set_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr)
4807 {
4808    Elm_Atspi_State_Set states;
4809    Eo *obj = (Eo*)ptr;
4810    eo_do(obj, states = elm_interface_atspi_accessible_state_set_get());
4811    return _elm_atspi_state_set_to_atspi_state_set(states);
4812 }
4813
4814 static void *_get_object_in_relation_by_type_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr, AtspiRelationType type)
4815 {
4816    if (ptr)
4817      {
4818        const Eo *source = ptr;
4819        Elm_Atspi_Relation_Set relations;
4820        Elm_Atspi_Relation_Type expected_relation_type = _atspi_relation_to_elm_relation(type);
4821        eo_do(source, relations = elm_interface_atspi_accessible_relation_set_get());
4822        Elm_Atspi_Relation *rel;
4823        Eina_List *l;
4824        EINA_LIST_FOREACH(relations, l, rel)
4825          {
4826            if (rel->type == expected_relation_type)
4827              {
4828                 Eina_List *last = eina_list_last(rel->objects);
4829                 return eina_list_data_get(last);
4830              }
4831          }
4832      }
4833    return NULL;
4834 }
4835
4836 static unsigned char _object_is_zero_size_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr)
4837 {
4838    int x, y, w, h;
4839    Eo *obj = (Eo*)ptr;
4840    eo_do(obj, elm_interface_atspi_component_extents_get(EINA_TRUE, &x, &y, &w, &h));
4841    return w == 0 || h == 0;
4842 }
4843
4844 unsigned char _object_is_scrollable_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr)
4845 {
4846    Eo *obj = (Eo*)ptr;
4847    return eo_isa(obj, ELM_INTERFACE_SCROLLABLE_MIXIN);
4848 }
4849
4850 void *_get_parent_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr)
4851 {
4852    Eo *obj = (Eo*)ptr, *ret_obj;
4853    eo_do(obj, ret_obj = elm_interface_atspi_accessible_parent_get());
4854    return ret_obj;
4855 }
4856
4857 void *_get_object_at_point_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
4858 {
4859    Eo *obj = (Eo*)ptr, *target;
4860    eo_do(obj, target = elm_interface_atspi_component_accessible_at_point_get(coordinates_are_screen_based, x, y));
4861    return target;
4862 }
4863
4864 unsigned char _object_contains_impl(struct accessibility_navigation_pointer_table *table EINA_UNUSED, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
4865 {
4866    Eo *obj = (Eo*)ptr;
4867    Eina_Bool return_value;
4868    eo_do(obj, return_value = elm_interface_atspi_component_contains(coordinates_are_screen_based, x, y));
4869    return return_value ? 1 : 0;
4870 }
4871
4872 unsigned char _object_is_proxy_impl(struct accessibility_navigation_pointer_table *table_, void *obj)
4873 {
4874    accessibility_navigation_pointer_table_impl *table = (accessibility_navigation_pointer_table_impl*)table_;
4875    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(table->bridge, pd, 0);
4876    const char *our_bus_name = eldbus_connection_unique_name_get(pd->a11y_bus);
4877    const char *obj_bus_name;
4878    _object_get_bus_name_and_path(table->bridge, (Eo*)obj, &obj_bus_name, NULL);
4879    return our_bus_name && obj_bus_name && strcmp(our_bus_name, obj_bus_name) != 0;
4880 }
4881
4882 accessibility_navigation_pointer_table_impl construct_accessibility_navigation_pointer_table(Eo *bridge)
4883 {
4884    accessibility_navigation_pointer_table_impl table;
4885 #define INIT(n) table.ptrs.n = _## n ## _impl
4886    INIT(object_get_role);
4887    INIT(object_get_state_set);
4888    INIT(get_object_in_relation_by_type);
4889    INIT(object_is_zero_size);
4890    INIT(get_parent);
4891    INIT(object_is_scrollable);
4892    INIT(get_object_at_point);
4893    INIT(object_contains);
4894    INIT(object_is_proxy);
4895 #undef INIT
4896    table.bridge = bridge;
4897    return table;
4898 }
4899
4900
4901 static Eo *_calculate_navigable_accessible_at_point(Eo *bridge, Eo *root, Eina_Bool coord_type, int x, int y)
4902 {
4903    accessibility_navigation_pointer_table_impl table = construct_accessibility_navigation_pointer_table(bridge);
4904    Eo *result = (Eo*)_calculate_navigable_accessible_at_point_impl(&table.ptrs, root, x, y, coord_type ? 1 : 0);
4905    return result;
4906 }
4907
4908 static Eo *_calculate_neighbor(Eo *bridge, Eo *root, Eo *start, Eina_Bool forward, int search_mode)
4909 {
4910    accessibility_navigation_pointer_table_impl table = construct_accessibility_navigation_pointer_table(bridge);
4911    Eo *result = (Eo*)_calculate_neighbor_impl(&table.ptrs, root, start, forward ? 1 : 0, (GetNeighborSearchMode)search_mode);
4912
4913    return result;
4914 }
4915 //
4916
4917 static Eldbus_Message *
4918 _component_get_extents(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4919 {
4920    const char *obj_path = eldbus_message_path_get(msg);
4921    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4922    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4923    int x, y, w, h;
4924    AtspiCoordType coord_type;
4925    Eldbus_Message *ret;
4926    Eldbus_Message_Iter *iter, *iter_struct;
4927
4928    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
4929
4930    if (!eldbus_message_arguments_get(msg, "u", &coord_type))
4931      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4932
4933    ret = eldbus_message_method_return_new(msg);
4934    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4935
4936    iter = eldbus_message_iter_get(ret);
4937
4938    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4939    eo_do(obj, elm_interface_atspi_component_extents_get(type, &x, &y, &w, &h));
4940    iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
4941    EINA_SAFETY_ON_NULL_GOTO(iter_struct, fail);
4942
4943    eldbus_message_iter_basic_append(iter_struct, 'i', x);
4944    eldbus_message_iter_basic_append(iter_struct, 'i', y);
4945    eldbus_message_iter_basic_append(iter_struct, 'i', w);
4946    eldbus_message_iter_basic_append(iter_struct, 'i', h);
4947
4948    eldbus_message_iter_container_close(iter, iter_struct);
4949
4950    return ret;
4951 fail:
4952    if (ret) eldbus_message_unref(ret);
4953    return NULL;
4954 }
4955
4956 static Eldbus_Message *
4957 _component_get_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4958 {
4959    const char *obj_path = eldbus_message_path_get(msg);
4960    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4961    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4962    int x, y;
4963    AtspiCoordType coord_type;
4964    Eldbus_Message *ret;
4965
4966    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
4967
4968    if (!eldbus_message_arguments_get(msg, "u", &coord_type))
4969      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4970
4971    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4972    eo_do(obj, elm_interface_atspi_component_position_get(type, &x, &y));
4973
4974    ret = eldbus_message_method_return_new(msg);
4975    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4976
4977    eldbus_message_arguments_append(ret, "i", x);
4978    eldbus_message_arguments_append(ret, "i", y);
4979
4980    return ret;
4981 }
4982
4983 static Eldbus_Message *
4984 _component_get_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4985 {
4986    const char *obj_path = eldbus_message_path_get(msg);
4987    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4988    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4989    int x, y;
4990    Eldbus_Message *ret;
4991
4992    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
4993
4994    eo_do(obj, elm_interface_atspi_component_size_get(&x, &y));
4995
4996    ret = eldbus_message_method_return_new(msg);
4997    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4998
4999    eldbus_message_arguments_append(ret, "i", x);
5000    eldbus_message_arguments_append(ret, "i", y);
5001
5002    return ret;
5003 }
5004
5005 static AtspiComponentLayer
5006 _elm_layer_2_atspi_layer(int layer)
5007 {
5008    if (layer <= ELM_OBJECT_LAYER_BACKGROUND) return ATSPI_LAYER_CANVAS;
5009    if (layer < ELM_OBJECT_LAYER_FOCUS) return ATSPI_LAYER_WIDGET;
5010    if (layer <= ELM_OBJECT_LAYER_TOOLTIP) return ATSPI_LAYER_POPUP;
5011
5012    return ATSPI_LAYER_OVERLAY;
5013 }
5014
5015 static Eldbus_Message *
5016 _component_get_layer(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5017 {
5018    const char *obj_path = eldbus_message_path_get(msg);
5019    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5020    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5021    int layer = 0;
5022    Eldbus_Message *ret;
5023    AtspiComponentLayer atspi_layer;
5024
5025    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5026
5027    eo_do(obj, layer = elm_interface_atspi_component_layer_get());
5028
5029    ret = eldbus_message_method_return_new(msg);
5030    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5031
5032    atspi_layer = _elm_layer_2_atspi_layer(layer);
5033    eldbus_message_arguments_append(ret, "u", atspi_layer);
5034
5035    return ret;
5036 }
5037
5038 static Eldbus_Message *
5039 _component_grab_focus(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5040 {
5041    const char *obj_path = eldbus_message_path_get(msg);
5042    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5043    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5044    Eldbus_Message *ret;
5045    Eina_Bool focus = EINA_FALSE;
5046
5047    if (!obj)
5048      return _dbus_invalid_ref_error_new(msg);
5049
5050    eo_do(obj, focus = elm_interface_atspi_component_focus_grab());
5051
5052    ret = eldbus_message_method_return_new(msg);
5053    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5054
5055    eldbus_message_arguments_append(ret, "b", focus);
5056
5057    return ret;
5058 }
5059
5060 //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods (29e253e2f7ef3c632ac3a64c489bf569df407f30)
5061 static Eldbus_Message *
5062 _component_grab_highlight(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5063 {
5064    const char *obj_path = eldbus_message_path_get(msg);
5065    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5066    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5067    Eldbus_Message *ret;
5068    Eina_Bool highlight = EINA_FALSE;
5069
5070    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5071
5072    eo_do(obj, highlight = elm_interface_atspi_component_highlight_grab());
5073
5074    ret = eldbus_message_method_return_new(msg);
5075    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5076
5077    eldbus_message_arguments_append(ret, "b", highlight);
5078
5079    return ret;
5080 }
5081
5082 static Eldbus_Message *
5083 _component_clear_highlight(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5084 {
5085    const char *obj_path = eldbus_message_path_get(msg);
5086    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5087    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5088    Eldbus_Message *ret;
5089    Eina_Bool highlight = EINA_FALSE;
5090
5091    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5092
5093    eo_do(obj, highlight = elm_interface_atspi_component_highlight_clear());
5094
5095    ret = eldbus_message_method_return_new(msg);
5096    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5097
5098    eldbus_message_arguments_append(ret, "b", highlight);
5099
5100    return ret;
5101 }
5102 //
5103
5104 static Eldbus_Message *
5105 _component_get_alpha(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5106 {
5107    const char *obj_path = eldbus_message_path_get(msg);
5108    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5109    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5110    Eldbus_Message *ret;
5111    double alpha = 0;
5112
5113    if (!obj)
5114      return _dbus_invalid_ref_error_new(msg);
5115
5116    eo_do(obj, alpha = elm_interface_atspi_component_alpha_get());
5117
5118    ret = eldbus_message_method_return_new(msg);
5119    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5120
5121    eldbus_message_arguments_append(ret, "d", alpha);
5122
5123    return ret;
5124 }
5125
5126 static Eldbus_Message *
5127 _component_set_extends(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5128 {
5129    const char *obj_path = eldbus_message_path_get(msg);
5130    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5131    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5132    int x, y, w, h;
5133    AtspiCoordType coord_type;
5134    Eldbus_Message *ret;
5135    Eina_Bool result = EINA_FALSE;
5136
5137    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5138
5139    if (!eldbus_message_arguments_get(msg, "iiiiu", &x, &y, &w, &h, &coord_type))
5140      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
5141
5142    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
5143    eo_do(obj, result = elm_interface_atspi_component_extents_set(type, x, y, w, h));
5144
5145    ret = eldbus_message_method_return_new(msg);
5146    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5147
5148    eldbus_message_arguments_append(ret, "b", result);
5149
5150    return ret;
5151 }
5152
5153 static Eldbus_Message *
5154 _component_set_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5155 {
5156    const char *obj_path = eldbus_message_path_get(msg);
5157    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5158    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5159    int x, y;
5160    Eina_Bool result = EINA_FALSE;
5161    AtspiCoordType coord_type;
5162    Eldbus_Message *ret;
5163
5164    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5165
5166    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
5167      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
5168
5169    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
5170    eo_do(obj, result = elm_interface_atspi_component_position_set(type, x, y));
5171
5172    ret = eldbus_message_method_return_new(msg);
5173    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5174
5175    eldbus_message_arguments_append(ret, "b", result);
5176
5177    return ret;
5178 }
5179
5180 static Eldbus_Message *
5181 _component_set_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
5182 {
5183    const char *obj_path = eldbus_message_path_get(msg);
5184    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
5185    Eo *obj = _bridge_object_from_path(bridge, obj_path);
5186    int w, h;
5187    Eina_Bool result;
5188    Eldbus_Message *ret;
5189
5190    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_INTERFACE_ATSPI_COMPONENT_MIXIN, msg);
5191
5192    if (!eldbus_message_arguments_get(msg, "ii", &w, &h))
5193      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
5194
5195    eo_do(obj, result = elm_interface_atspi_component_size_set(w, h));
5196
5197    ret = eldbus_message_method_return_new(msg);
5198    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
5199
5200    eldbus_message_arguments_append(ret, "b", result);
5201
5202    return ret;
5203 }
5204
5205 static const Eldbus_Method component_methods[] = {
5206    { "Contains", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "contains"}), _component_contains, 0 },
5207    { "GetAccessibleAtPoint", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"(so)", "accessible"}), _component_get_accessible_at_point, 0 },
5208    { "GetExtents", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"(iiii)", "extents"}), _component_get_extents, 0 },
5209    { "GetPosition", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"i", "x"}, {"i","y"}), _component_get_position, 0 },
5210    { "GetSize", NULL, ELDBUS_ARGS({"i", "w"}, {"i", "h"}), _component_get_size, 0 },
5211    { "GetLayer", NULL, ELDBUS_ARGS({"u", "layer"}), _component_get_layer, 0 },
5212 //   { "GetMDIZOrder", NULL, ELDBUS_ARGS({"n", "MDIZOrder"}), _component_get_mdizorder, 0 },
5213    { "GrabFocus", NULL, ELDBUS_ARGS({"b", "focus"}), _component_grab_focus, 0 },
5214    { "GetAlpha", NULL, ELDBUS_ARGS({"d", "alpha"}), _component_get_alpha, 0 },
5215    { "SetExtents", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "width"}, {"i", "height"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_extends, 0 },
5216    { "SetPosition", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_position, 0 },
5217    { "SetSize", ELDBUS_ARGS({"i", "width"}, {"i", "height"}), ELDBUS_ARGS({"b", "result"}), _component_set_size, 0 },
5218
5219    //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods (29e253e2f7ef3c632ac3a64c489bf569df407f30)
5220    { "GrabHighlight", NULL, ELDBUS_ARGS({"b", "result"}), _component_grab_highlight, 0 },
5221    { "ClearHighlight", NULL, ELDBUS_ARGS({"b", "result"}), _component_clear_highlight, 0 },
5222    //
5223    { NULL, NULL, NULL, NULL, 0 }
5224 };
5225
5226 static const Eldbus_Service_Interface_Desc component_iface_desc = {
5227    ATSPI_DBUS_INTERFACE_COMPONENT, component_methods, NULL, NULL, NULL, NULL
5228 };
5229
5230 static void
5231 _on_elm_atspi_bridge_app_register(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
5232 {
5233    const char *errname, *errmsg;
5234
5235    if (eldbus_message_error_get(msg, &errname, &errmsg))
5236      {
5237         ERR("%s %s", errname, errmsg);
5238         return;
5239      }
5240    DBG("Application successfuly registered at ATSPI2 bus.");
5241 }
5242
5243 EAPI Eina_Bool
5244 _elm_atspi_bridge_app_register(Eo *bridge)
5245 {
5246    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
5247
5248    Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
5249                                     ATSPI_DBUS_PATH_ROOT,
5250                                     ATSPI_DBUS_INTERFACE_SOCKET,
5251                                     "Embed");
5252    Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
5253
5254    _bridge_iter_object_reference_append(bridge, iter, elm_atspi_bridge_root_get(bridge));
5255    eldbus_connection_send(pd->a11y_bus, message, _on_elm_atspi_bridge_app_register, NULL, -1);
5256
5257    return EINA_TRUE;
5258 }
5259
5260 EAPI Eina_Bool
5261 _elm_atspi_bridge_app_unregister(Eo *bridge)
5262 {
5263    Eo *root;
5264    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
5265
5266    root = elm_atspi_bridge_root_get(bridge);
5267
5268    Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
5269                                     ATSPI_DBUS_PATH_ROOT,
5270                                     ATSPI_DBUS_INTERFACE_SOCKET,
5271                                     "Unembed");
5272    Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
5273
5274    _bridge_iter_object_reference_append(bridge, iter, root);
5275    eldbus_connection_send(pd->a11y_bus, message, NULL, NULL, -1);
5276
5277    return EINA_TRUE;
5278 }
5279
5280 static void
5281 _cache_register(Eo *obj)
5282 {
5283    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
5284    pd->cache_interface = eldbus_service_interface_register(pd->a11y_bus, CACHE_INTERFACE_PATH, &cache_iface_desc);
5285    eldbus_service_object_data_set(pd->cache_interface, ELM_ATSPI_BRIDGE_CLASS_NAME, obj);
5286 }
5287
5288 static void
5289 _set_broadcast_flag(const char *event, Eo *bridge)
5290 {
5291    char **tokens;
5292    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5293
5294    tokens = eina_str_split(event, ":", 3);
5295
5296    if (!tokens) return;
5297
5298    if (!strcmp(tokens[0], "Object"))
5299      {
5300         if (!tokens[1] || *tokens[1] == '\0') return; // do not handle "Object:*"
5301         else if (!strcmp(tokens[1], "StateChanged"))
5302           {
5303              if (!tokens[2] || *tokens[2] == '\0')
5304                pd->object_state_broadcast_mask = -1; // broadcast all
5305              eina_str_tolower(&tokens[2]);
5306              struct atspi_state_desc *sd = eina_hash_find(pd->state_hash, tokens[2]);
5307              if (sd)
5308                STATE_TYPE_SET(pd->object_state_broadcast_mask, sd->elm_state);
5309           }
5310         else if (!strcmp(tokens[1], "PropertyChange"))
5311           {
5312              if (!tokens[2] || *tokens[2] == '\0')
5313                pd->object_property_broadcast_mask = -1; //broadcast all
5314              else if (!strcmp(tokens[2], "AccessibleValue"))
5315                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_VALUE);
5316              else if (!strcmp(tokens[2], "AccessibleName"))
5317                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_NAME);
5318              else if (!strcmp(tokens[2], "AccessibleDescription"))
5319                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_DESCRIPTION);
5320              else if (!strcmp(tokens[2], "AccessibleParent"))
5321                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_PARENT);
5322              else if (!strcmp(tokens[2], "AccessibleRole"))
5323                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_ROLE);
5324           }
5325         else if (!strcmp(tokens[1], "ChildrenChanged"))
5326           {
5327              if (!tokens[2] || *tokens[2] == '\0')
5328                pd->object_children_broadcast_mask = -1; // broadcast all
5329              else if (!strcmp(tokens[2], "add"))
5330                STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_ADDED);
5331              else if (!strcmp(tokens[2], "remove"))
5332                STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_REMOVED);
5333           }
5334         else if (!strcmp(tokens[1], "TextChanged"))
5335           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED);
5336         else if (!strcmp(tokens[1], "TextCaretMoved"))
5337           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED);
5338         else if (!strcmp(tokens[1], "TextBoundsChanged"))
5339           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED);
5340         else if (!strcmp(tokens[1], "TextSelectionChanged"))
5341           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED);
5342         else if (!strcmp(tokens[1], "TextAttributesChanged"))
5343           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED);
5344         else if (!strcmp(tokens[1], "VisibleDataChanged"))
5345           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED);
5346         else if (!strcmp(tokens[1], "ActiveDescendantChanged"))
5347           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED);
5348         else if (!strcmp(tokens[1], "BoundsChanged"))
5349           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_BOUNDS_CHANGED);
5350         //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
5351         else if (!strcmp(tokens[1], "MoveOuted"))
5352           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_MOVE_OUTED);
5353         //
5354      }
5355    else if (!strcmp(tokens[0], "Window"))
5356      {
5357         if (!tokens[1] || *tokens[1] == '\0')
5358           pd->window_signal_broadcast_mask = -1; // broadcast all
5359         else if (!strcmp(tokens[1], "Create"))
5360           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_CREATE);
5361         else if (!strcmp(tokens[1], "Destroy"))
5362           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DESTROY);
5363         else if (!strcmp(tokens[1], "Activate"))
5364           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_ACTIVATE);
5365         else if (!strcmp(tokens[1], "Deactivate"))
5366           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DEACTIVATE);
5367         else if (!strcmp(tokens[1], "Maximize"))
5368           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MAXIMIZE);
5369         else if (!strcmp(tokens[1], "Minimize"))
5370           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MINIMIZE);
5371         else if (!strcmp(tokens[1], "Resize"))
5372           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESIZE);
5373         else if (!strcmp(tokens[1], "Restore"))
5374           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESTORE);
5375      }
5376
5377    free(tokens[0]);
5378    free(tokens);
5379 }
5380
5381 static void
5382 _registered_listeners_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
5383 {
5384    const char *event, *bus;
5385    Eo *root, *pr;
5386    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
5387    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
5388
5389    DBG("Updating registered ATSPI signals list.");
5390    pd->object_broadcast_mask = 0;
5391    pd->object_children_broadcast_mask = 0;
5392    pd->object_property_broadcast_mask = 0;
5393    pd->object_state_broadcast_mask = 0;
5394    pd->window_signal_broadcast_mask = 0;
5395
5396    if (eldbus_message_error_get(msg, &event, &bus))
5397      {
5398         WRN("%s %s", event, bus);
5399         return;
5400      }
5401    Eldbus_Message_Iter *iter, *siter;
5402    if (!eldbus_message_arguments_get(msg, "a(ss)", &iter))
5403      {
5404         ERR("Invalid answer type from GetRegisteredEvents method call!");
5405         return;
5406      }
5407    while (eldbus_message_iter_get_and_next(iter, 'r', &siter))
5408      {
5409         eldbus_message_iter_arguments_get(siter, "ss", &bus, &event);
5410         _set_broadcast_flag(event, data);
5411      }
5412
5413    if (!pd->connected)
5414      {
5415         //TIZEN_ONLY(20170910) atspi: emit signal after atspi bridge is connected
5416         pd->connected = EINA_TRUE;
5417         eo_do(data, eo_event_callback_call(ELM_ATSPI_BRIDGE_EVENT_CONNECTED, NULL));
5418         _elm_win_atspi(EINA_TRUE);
5419         //
5420
5421         // buid cache
5422         eo_do(data, root = elm_obj_atspi_bridge_root_get());
5423         _bridge_cache_build(data, root);
5424
5425         // initialize pending proxy
5426         EINA_LIST_FREE(pd->socket_queue, pr)
5427            _socket_ifc_create(pd->a11y_bus, pr);
5428         EINA_LIST_FREE(pd->plug_queue, pr)
5429            _plug_connect(pd->a11y_bus, pr);
5430
5431         pd->socket_queue = pd->plug_queue = NULL;
5432      }
5433 }
5434
5435 static void
5436 _registered_events_list_update(Eo *bridge)
5437 {
5438    Eldbus_Message *msg;
5439    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5440    Eldbus_Pending *p;
5441
5442    msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "GetRegisteredEvents");
5443    p = eldbus_connection_send(pd->a11y_bus, msg, _registered_listeners_get, bridge, -1);
5444    pd->pending_requests = eina_list_append(pd->pending_requests, p);
5445 }
5446
5447 static void
5448 _handle_listener_change(void *data, const Eldbus_Message *msg EINA_UNUSED)
5449 {
5450    _registered_events_list_update(data);
5451 }
5452
5453 //TIZEN_ONLY(20170802): handle "gesture_required" attribute
5454 static Eina_Bool
5455 _scroll_gesture_required_is(Eo *obj)
5456 {
5457    Eina_Bool ret = EINA_FALSE;
5458    Eina_List *l, *attr_list = NULL;
5459    Elm_Atspi_Attribute *attr = NULL;
5460
5461    eo_do(obj, attr_list = elm_interface_atspi_accessible_attributes_get());
5462    EINA_LIST_FOREACH(attr_list, l, attr)
5463      {
5464         if (!strcmp(attr->key, "gesture_required") && !strcmp(attr->value, "scroll"))
5465           {
5466              ret = EINA_TRUE;
5467              break;
5468           }
5469      }
5470    if (attr_list)
5471      elm_atspi_attributes_list_free(attr_list);
5472
5473    return ret;
5474 }
5475 //
5476
5477 static Eina_Bool
5478 _state_changed_signal_send(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5479 {
5480    Elm_Atspi_Event_State_Changed_Data *state_data = event_info;
5481    const char *type_desc;
5482    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5483
5484    // TIZEN_ONLY(20160802): do not handle events if the window is not activated
5485    if ((state_data->type == ELM_ATSPI_STATE_ACTIVE) && eo_isa(obj, ELM_WIN_CLASS))
5486      {
5487         pd->window_activated = state_data->new_value;
5488      }
5489    //
5490    // TIZEN_ONLY(20161209): reduce IPC of object:state-changed:showing
5491    if ((state_data->type == ELM_ATSPI_STATE_SHOWING) ||
5492        (state_data->type == ELM_ATSPI_STATE_VISIBLE))
5493      {
5494         Elm_Atspi_Role role = ELM_ATSPI_ROLE_INVALID;
5495         Elm_Atspi_State_Set ss;
5496
5497         eo_do(obj, role = elm_interface_atspi_accessible_role_get());
5498         eo_do(obj, ss = elm_interface_atspi_accessible_state_set_get());
5499         if (state_data->new_value) /* Showing */
5500           {
5501              if ((role != ELM_ATSPI_ROLE_WINDOW) &&
5502                  (role != ELM_ATSPI_ROLE_PAGE_TAB) &&
5503                  (!STATE_TYPE_GET(ss, ELM_ATSPI_STATE_MODAL)))
5504                return EINA_FALSE;
5505           }
5506         else /* Not Showing */
5507           {
5508              if ((role != ELM_ATSPI_ROLE_WINDOW) &&
5509                  (!STATE_TYPE_GET(ss, ELM_ATSPI_STATE_MODAL)) &&
5510                  (_elm_object_accessibility_currently_highlighted_get() != (void *)obj))
5511                return EINA_FALSE;
5512           }
5513      }
5514    //
5515
5516    if (!STATE_TYPE_GET(pd->object_state_broadcast_mask, state_data->type))
5517      return EINA_FALSE;
5518
5519    if ((state_data->type > ELM_ATSPI_STATE_LAST_DEFINED) ||
5520         (int)state_data->type < 0)
5521      return EINA_FALSE;
5522
5523    type_desc = elm_states_to_atspi_state[state_data->type].name;
5524
5525    //TIZEN_ONLY(20170802): handle "gesture_required" attribute
5526    unsigned int det2 = 0;
5527    if ((state_data->type == ELM_ATSPI_STATE_HIGHLIGHTED) &&
5528        (_scroll_gesture_required_is(obj)))
5529      det2++;
5530
5531    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5532                        &_event_obj_signals[ATSPI_OBJECT_EVENT_STATE_CHANGED], type_desc, state_data->new_value, det2, NULL);
5533    //
5534    return EINA_TRUE;
5535 }
5536
5537 static Eina_Bool
5538 _bounds_changed_signal_send(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5539 {
5540    Elm_Atspi_Event_Geometry_Changed_Data *geo_data = event_info;
5541
5542    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5543                        &_event_obj_signals[ATSPI_OBJECT_EVENT_BOUNDS_CHANGED], "", 0, 0, "(iiii)",
5544                        geo_data->x, geo_data->y, geo_data->width, geo_data->height);
5545    return EINA_TRUE;
5546 }
5547
5548 static Eina_Bool
5549 _property_changed_signal_send(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5550 {
5551    const char *property = event_info;
5552    char *atspi_desc;
5553    enum _Atspi_Object_Property prop = ATSPI_OBJECT_PROPERTY_LAST;
5554
5555    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5556
5557    if (!strcmp(property, "parent"))
5558      {
5559         prop = ATSPI_OBJECT_PROPERTY_PARENT;
5560         atspi_desc = "accessible-parent";
5561      }
5562    else if (!strcmp(property, "name"))
5563      {
5564         prop = ATSPI_OBJECT_PROPERTY_NAME;
5565         atspi_desc = "accessible-name";
5566      }
5567    else if (!strcmp(property, "description"))
5568      {
5569         prop = ATSPI_OBJECT_PROPERTY_DESCRIPTION;
5570         atspi_desc = "accessible-description";
5571      }
5572    else if (!strcmp(property, "role"))
5573      {
5574         prop = ATSPI_OBJECT_PROPERTY_ROLE;
5575         atspi_desc = "accessible-role";
5576      }
5577    else if (!strcmp(property, "value"))
5578      {
5579         prop = ATSPI_OBJECT_PROPERTY_VALUE;
5580         atspi_desc = "accessible-value";
5581      }
5582    if (prop == ATSPI_OBJECT_PROPERTY_LAST)
5583      {
5584         ERR("Unrecognized property name!");
5585         return EINA_FALSE;
5586      }
5587    if (!STATE_TYPE_GET(pd->object_property_broadcast_mask, prop))
5588      {
5589         DBG("Masking property %s changed event.", property);
5590         return EINA_FALSE;
5591      }
5592
5593    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5594                        &_event_obj_signals[ATSPI_OBJECT_EVENT_PROPERTY_CHANGED], atspi_desc, 0, 0, NULL, NULL);
5595    return EINA_TRUE;
5596 }
5597
5598 static Eina_Bool
5599 _visible_data_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
5600 {
5601    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5602
5603    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED))
5604      return EINA_FALSE;
5605
5606    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5607                        &_event_obj_signals[ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED], "",
5608                        0, 0, NULL, NULL);
5609
5610    return EINA_TRUE;
5611 }
5612
5613 static Eina_Bool
5614 _active_descendant_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5615 {
5616    Eo *child = event_info;
5617    int idx;
5618
5619    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5620
5621    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED))
5622      return EINA_FALSE;
5623
5624    eo_do(child, idx = elm_interface_atspi_accessible_index_in_parent_get());
5625
5626    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5627                        &_event_obj_signals[ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED], "",
5628                        idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), child);
5629    return EINA_TRUE;
5630 }
5631
5632 static Eina_Bool
5633 _children_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5634 {
5635    const char *atspi_desc = NULL;
5636    Elm_Atspi_Event_Children_Changed_Data *ev_data = event_info;
5637    int idx;
5638    enum _Atspi_Object_Child_Event_Type type;
5639
5640    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5641
5642    type = ev_data->is_added ? ATSPI_OBJECT_CHILD_ADDED : ATSPI_OBJECT_CHILD_REMOVED;
5643
5644    // update cached objects
5645    if (ev_data->is_added)
5646      _bridge_cache_build(data, ev_data->child);
5647
5648    if (!STATE_TYPE_GET(pd->object_children_broadcast_mask, type))
5649      return EINA_FALSE;
5650
5651    switch (type)
5652     {
5653      case ATSPI_OBJECT_CHILD_ADDED:
5654         atspi_desc = "add";
5655         eo_do(ev_data->child, idx = elm_interface_atspi_accessible_index_in_parent_get());
5656         break;
5657      case ATSPI_OBJECT_CHILD_REMOVED:
5658         atspi_desc = "remove";
5659         eo_do(ev_data->child, idx = elm_interface_atspi_accessible_index_in_parent_get());
5660         break;
5661     }
5662
5663    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5664                        &_event_obj_signals[ATSPI_OBJECT_EVENT_CHILDREN_CHANGED], atspi_desc,
5665                        idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), ev_data->child);
5666
5667    return EINA_TRUE;
5668 }
5669
5670 //TIZEN_ONLY(20160623): atspi: moved highlight when object is out of screen
5671 static Eina_Bool
5672 _move_outed_signal_send(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5673 {
5674    const Elm_Atspi_Move_Outed_Type *type = event_info;
5675
5676    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5677
5678    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_MOVE_OUTED))
5679      return EINA_FALSE;
5680    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5681                        &_event_obj_signals[ATSPI_OBJECT_EVENT_MOVE_OUTED], "", *type, 0, NULL, NULL);
5682    return EINA_TRUE;
5683 }
5684 //
5685
5686 static unsigned int
5687 _window_activated_detail_value_add(Eo *obj)
5688 {
5689    unsigned int ret = ELM_ACCESSIBLE_DEFAULT_LABEL_ENABLED;
5690    Eina_List *l, *attr_list = NULL;
5691    Elm_Atspi_Attribute *attr = NULL;
5692
5693    eo_do(obj, attr_list = elm_interface_atspi_accessible_attributes_get());
5694    EINA_LIST_FOREACH(attr_list, l, attr)
5695      {
5696         if (!strcmp(attr->key, "default_label") && !strcmp(attr->value, "disabled"))
5697           {
5698              ret |= ELM_ACCESSIBLE_DEFAULT_LABEL_DISABLED;
5699              break;
5700           }
5701      }
5702    if (attr_list)
5703      elm_atspi_attributes_list_free(attr_list);
5704
5705    return ret;
5706 }
5707
5708 static Eina_Bool
5709 _window_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info EINA_UNUSED)
5710 {
5711    enum _Atspi_Window_Signals type;
5712
5713    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5714
5715    if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_CREATED)
5716      type = ATSPI_WINDOW_EVENT_CREATE;
5717    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DESTROYED)
5718      type = ATSPI_WINDOW_EVENT_DESTROY;
5719    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DEACTIVATED)
5720      type = ATSPI_WINDOW_EVENT_DEACTIVATE;
5721    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_ACTIVATED)
5722      type = ATSPI_WINDOW_EVENT_ACTIVATE;
5723    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_MAXIMIZED)
5724      type = ATSPI_WINDOW_EVENT_MAXIMIZE;
5725    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_MINIMIZED)
5726      type = ATSPI_WINDOW_EVENT_MINIMIZE;
5727    else if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_RESTORED)
5728      type = ATSPI_WINDOW_EVENT_RESTORE;
5729    else
5730      return EINA_FALSE;
5731
5732    if (!STATE_TYPE_GET(pd->window_signal_broadcast_mask, type))
5733      return EINA_FALSE;
5734
5735    if (!pd->a11y_bus)
5736      {
5737         ERR("A11Y connection closed. Unable to send ATSPI event.");
5738         return EINA_FALSE;
5739      }
5740
5741    unsigned int det1 = 0;
5742    if (desc == ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_ACTIVATED)
5743      det1 = _window_activated_detail_value_add(obj);
5744
5745    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_WINDOW,
5746                        &_window_obj_signals[type], "", det1, 0, "i", 0);
5747    return EINA_TRUE;
5748 }
5749
5750 static Eina_Bool
5751 _selection_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
5752 {
5753    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5754
5755    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_SELECTION_CHANGED))
5756      return EINA_FALSE;
5757
5758    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5759                        &_event_obj_signals[ATSPI_OBJECT_EVENT_SELECTION_CHANGED], "", 0, 0, "i", 0);
5760    return EINA_TRUE;
5761 }
5762
5763 static void _bridge_signal_send(Eo *bridge, Eo *obj, const char *infc, const Eldbus_Signal *signal, const char *minor, unsigned int det1, unsigned int det2, const char *variant_sig, ...)
5764 {
5765    Eldbus_Message *msg;
5766    Eldbus_Message_Iter *iter , *iter_stack[64], *iter_struct;
5767    va_list va;
5768    Eo *atspi_obj;
5769    const char *path;
5770    int top = 0;
5771
5772    EINA_SAFETY_ON_NULL_RETURN(infc);
5773    EINA_SAFETY_ON_NULL_RETURN(signal);
5774    EINA_SAFETY_ON_NULL_RETURN(minor);
5775    EINA_SAFETY_ON_NULL_RETURN(obj);
5776    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5777
5778    path = _bridge_path_from_object(bridge, obj);
5779
5780    msg = eldbus_message_signal_new(path, infc, signal->name);
5781    if (!msg) return;
5782
5783    va_start(va, variant_sig);
5784
5785    iter = eldbus_message_iter_get(msg);
5786    eldbus_message_iter_arguments_append(iter, "sii", minor, det1, det2);
5787
5788    if (variant_sig)
5789      {
5790         iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', variant_sig);
5791
5792         const char *tmp = variant_sig;
5793         while (*tmp)
5794           {
5795              switch (*tmp)
5796                {
5797                 case '(':
5798                    iter_stack[top + 1] = eldbus_message_iter_container_new(iter_stack[top], 'r', NULL);
5799                    top++;
5800                    break;
5801                 case 's':
5802                    eldbus_message_iter_basic_append(iter_stack[top], 's', va_arg(va, char*));
5803                    break;
5804                 case 'i':
5805                    eldbus_message_iter_basic_append(iter_stack[top], 'i', va_arg(va, int));
5806                    break;
5807                 case 'o':
5808                    atspi_obj = va_arg(va, Eo*);
5809                    path = _bridge_path_from_object(bridge, atspi_obj);
5810                    eldbus_message_iter_basic_append(iter_stack[top], 'o', path);
5811                    break;
5812                 case ')':
5813                    eldbus_message_iter_container_close(iter_stack[top - 1], iter_stack[top]);
5814                    top--;
5815                    break;
5816                 default:
5817                    ERR("Not supported d-bus type: %c.", *tmp);
5818                    break;
5819                }
5820              tmp++;
5821           }
5822      }
5823    else // AT-SPI implementation forces checks on variant in signature even if not used.
5824      {
5825         iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', "i");
5826         eldbus_message_iter_basic_append(iter_stack[top], 'i', 0);
5827      }
5828
5829    va_end(va);
5830    if (top != 0)
5831      ERR("Invalid d-bus signature: () do not match.");
5832
5833    eldbus_message_iter_container_close(iter, iter_stack[0]);
5834
5835    iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
5836    path = _bridge_path_from_object(bridge, elm_atspi_bridge_root_get(bridge));
5837    eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(pd->a11y_bus));
5838    eldbus_message_iter_basic_append(iter_struct, 'o', path);
5839    eldbus_message_iter_container_close(iter, iter_struct);
5840
5841    eldbus_connection_send(pd->a11y_bus, msg, NULL, NULL, -1);
5842    DBG("Send %s.%s[%s,%d,%d]", infc, signal->name, minor, det1, det2);
5843 }
5844
5845 static Eina_Bool
5846 _text_caret_moved_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
5847 {
5848    int cursor_pos = 0;
5849
5850    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_FALSE);
5851
5852    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED))
5853      return EINA_TRUE;
5854
5855    eo_do(obj, cursor_pos = elm_interface_atspi_text_caret_offset_get());
5856
5857    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5858                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED], "", cursor_pos, 0, NULL, NULL);
5859
5860    return EINA_TRUE;
5861 }
5862
5863 static Eina_Bool
5864 _text_text_inserted_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5865 {
5866    Elm_Atspi_Text_Change_Info *info = event_info;
5867
5868    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5869
5870    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
5871      return EINA_TRUE;
5872
5873    if (!info->content)
5874      {
5875         WRN("Try to send signal with NULL value");
5876         return EINA_TRUE;
5877      }
5878
5879    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5880                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "insert", info->pos, info->len, "s", info->content);
5881
5882    return EINA_TRUE;
5883 }
5884
5885 static Eina_Bool
5886 _text_text_removed_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
5887 {
5888    Elm_Atspi_Text_Change_Info *info = event_info;
5889
5890    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5891
5892    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
5893      return EINA_TRUE;
5894
5895    if (!info->content)
5896      {
5897         WRN("Try to send signal with NULL value");
5898         return EINA_TRUE;
5899      }
5900
5901    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5902                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "delete", info->pos, info->len, "s", info->content);
5903
5904    return EINA_TRUE;
5905 }
5906
5907 static Eina_Bool
5908 _text_selection_changed_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
5909 {
5910    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5911
5912    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED))
5913      return EINA_TRUE;
5914
5915    _bridge_signal_send(data, obj, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
5916                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED], "", 0, 0, NULL, NULL);
5917
5918    return EINA_TRUE;
5919 }
5920
5921 //TIZEN_ONLY(20160527) - Add direct reading feature
5922 static void
5923 _on_reading_state_changed(void *data EINA_UNUSED, const Eldbus_Message *msg)
5924 {
5925    const int32_t i;
5926    const char *say_signal_name = "";
5927    Elm_Atspi_Say_Info *say_info;
5928
5929    if (eldbus_message_arguments_get(msg, "is", &i, &say_signal_name))
5930      {  if (read_command_id)
5931           {
5932              say_info = eina_hash_find(read_command_id, &i);
5933              if (say_info)
5934                {
5935                   if (say_info->func && say_signal_name)
5936                      say_info->func(say_info->data, say_signal_name);
5937                   eina_hash_del(read_command_id, &i, NULL);
5938                   free(say_info);
5939                }
5940           }
5941      }
5942 }
5943 //
5944
5945 static void
5946 _event_handlers_register(Eo *bridge)
5947 {
5948    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5949
5950    _registered_events_list_update(bridge);
5951
5952    // register signal handlers in order to update list of registered listeners of ATSPI-Clients
5953    pd->register_hdl = eldbus_signal_handler_add(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerRegistered", _handle_listener_change, bridge);
5954    pd->unregister_hdl = eldbus_signal_handler_add(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerDeregistered", _handle_listener_change, bridge);
5955    //TIZEN_ONLY(20160527) - Add direct reading feature
5956    pd->reading_state_changed_hdl = eldbus_signal_handler_add(pd->a11y_bus, ELM_ATSPI_DIRECT_READ_BUS, ELM_ATSPI_DIRECT_READ_PATH, ELM_ATSPI_DIRECT_READ_INTERFACE, "ReadingStateChanged", _on_reading_state_changed, bridge);
5957    //
5958    pd->key_flr = ecore_event_filter_add(NULL, _elm_atspi_bridge_key_filter, NULL, bridge);
5959 }
5960
5961 static void
5962 _bridge_object_unregister(Eo *bridge, Eo *obj)
5963 {
5964    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5965
5966    eina_hash_del(pd->cache, &obj, obj);
5967 }
5968
5969 static Eina_Bool
5970 _on_object_add(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED)
5971 {
5972    Eldbus_Message *sig;
5973    Eldbus_Message_Iter *iter;
5974
5975    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5976
5977    sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_ADDED);
5978    iter = eldbus_message_iter_get(sig);
5979    _cache_item_reference_append_cb(data, obj, iter);
5980
5981    eldbus_service_signal_send(pd->cache_interface, sig);
5982
5983    return EINA_TRUE;
5984 }
5985
5986 static Eina_Bool
5987 _on_object_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED)
5988 {
5989    Eldbus_Message *sig;
5990
5991    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
5992
5993    _bridge_object_unregister(data, obj);
5994
5995    sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_REMOVED);
5996    Eldbus_Message_Iter *iter = eldbus_message_iter_get(sig);
5997    _bridge_iter_object_reference_append(data, iter, obj);
5998    eldbus_service_signal_send(pd->cache_interface, sig);
5999
6000    return EINA_TRUE;
6001 }
6002
6003 static void
6004 _bridge_cache_build(Eo *bridge, void *obj)
6005 {
6006    Eina_List *children;
6007    Elm_Atspi_State_Set ss;
6008    Eo *child;
6009
6010    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6011
6012    if (!eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6013      return;
6014
6015    if (!eo_isa(obj, ELM_ATSPI_PROXY_CLASS))
6016       _bridge_object_register(bridge, obj);
6017
6018    eo_do(obj, ss = elm_interface_atspi_accessible_state_set_get());
6019    if (STATE_TYPE_GET(ss, ELM_ATSPI_STATE_MANAGES_DESCENDANTS))
6020      return;
6021    if (eo_isa(obj, ELM_INTERFACE_ATSPI_WINDOW_INTERFACE))
6022      {
6023         if (STATE_TYPE_GET(ss, ELM_ATSPI_STATE_ACTIVE))
6024           {
6025              // TIZEN_ONLY(20160802): do not handle events if the window is not activated
6026              pd->window_activated = EINA_TRUE;
6027              //
6028           }
6029         else
6030           {
6031              // TIZEN_ONLY(20160802): do not handle events if the window is not activated
6032              pd->window_activated = EINA_FALSE;
6033              //
6034           }
6035      }
6036    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
6037    EINA_LIST_FREE(children, child)
6038       _bridge_cache_build(bridge, child);
6039 }
6040
6041 static void
6042 _interfaces_unregister(Eo *bridge)
6043 {
6044     ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6045
6046 #define INTERFACE_SAFE_FREE(ifc) \
6047    if (ifc) \
6048       eldbus_service_interface_unregister(ifc); \
6049    ifc = NULL;
6050
6051    INTERFACE_SAFE_FREE(pd->interfaces.accessible);
6052    INTERFACE_SAFE_FREE(pd->interfaces.application);
6053    INTERFACE_SAFE_FREE(pd->interfaces.action);
6054    INTERFACE_SAFE_FREE(pd->interfaces.component);
6055    INTERFACE_SAFE_FREE(pd->interfaces.collection);
6056    INTERFACE_SAFE_FREE(pd->interfaces.editable_text);
6057    INTERFACE_SAFE_FREE(pd->interfaces.image);
6058    INTERFACE_SAFE_FREE(pd->interfaces.selection);
6059    INTERFACE_SAFE_FREE(pd->interfaces.text);
6060    INTERFACE_SAFE_FREE(pd->interfaces.value);
6061 }
6062
6063 static void
6064 _a11y_connection_shutdown(Eo *bridge)
6065 {
6066    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6067    Eldbus_Pending *pending;
6068
6069    if (pd->connected)
6070       _elm_atspi_bridge_app_unregister(bridge);
6071
6072    if (pd->cache)
6073      eina_hash_free(pd->cache);
6074    pd->cache = NULL;
6075
6076    if (pd->cache_interface)
6077      eldbus_service_object_unregister(pd->cache_interface);
6078    pd->cache_interface = NULL;
6079
6080    _interfaces_unregister(bridge);
6081
6082    if (pd->key_flr) ecore_event_filter_del(pd->key_flr);
6083    pd->key_flr = NULL;
6084
6085    if (pd->register_hdl) eldbus_signal_handler_del(pd->register_hdl);
6086    pd->register_hdl = NULL;
6087
6088    if (pd->unregister_hdl) eldbus_signal_handler_del(pd->unregister_hdl);
6089    pd->unregister_hdl = NULL;
6090
6091    //TIZEN_ONLY(20160527) - Add direct reading feature
6092    if (pd->reading_state_changed_hdl) eldbus_signal_handler_del(pd->reading_state_changed_hdl);
6093    pd->reading_state_changed_hdl = NULL;
6094    //
6095
6096    EINA_LIST_FREE(pd->pending_requests, pending)
6097       eldbus_pending_cancel(pending);
6098    pd->pending_requests = NULL;
6099
6100    if (pd->a11y_bus) eldbus_connection_unref(pd->a11y_bus);
6101    pd->a11y_bus = NULL;
6102
6103    if (pd->state_hash) eina_hash_free(pd->state_hash);
6104    pd->state_hash = NULL;
6105
6106    if (pd->event_hash) eina_hash_free(pd->event_hash);
6107    pd->event_hash = NULL;
6108
6109    eo_do(ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, elm_interface_atspi_accessible_event_handler_del(pd->event_hdlr));
6110    pd->event_hdlr = NULL;
6111
6112    eo_do(bridge, eo_event_callback_call(ELM_ATSPI_BRIDGE_EVENT_DISCONNECTED, NULL));
6113    pd->connected = EINA_FALSE;
6114 }
6115
6116 static void _disconnect_cb(void *data, Eldbus_Connection *conn EINA_UNUSED, void *event_info EINA_UNUSED)
6117 {
6118    _a11y_connection_shutdown(data);
6119 }
6120
6121 static void
6122 _interfaces_register(Eo *bridge)
6123 {
6124    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6125
6126    pd->interfaces.accessible =
6127       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &accessible_iface_desc);
6128    eldbus_service_object_data_set(pd->interfaces.accessible, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6129
6130    pd->interfaces.application =
6131       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &application_iface_desc);
6132    eldbus_service_object_data_set(pd->interfaces.application, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6133
6134    pd->interfaces.action =
6135       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &action_iface_desc);
6136    eldbus_service_object_data_set(pd->interfaces.action, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6137
6138    pd->interfaces.component =
6139       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &component_iface_desc);
6140    eldbus_service_object_data_set(pd->interfaces.component, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6141
6142    pd->interfaces.collection =
6143       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &collection_iface_desc);
6144    eldbus_service_object_data_set(pd->interfaces.collection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6145
6146    pd->interfaces.editable_text =
6147       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &editable_text_iface_desc);
6148    eldbus_service_object_data_set(pd->interfaces.editable_text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6149
6150    pd->interfaces.image =
6151       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &image_iface_desc);
6152    eldbus_service_object_data_set(pd->interfaces.image, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6153
6154    pd->interfaces.selection =
6155       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &selection_iface_desc);
6156    eldbus_service_object_data_set(pd->interfaces.selection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6157
6158    pd->interfaces.text =
6159       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &text_iface_desc);
6160    eldbus_service_object_data_set(pd->interfaces.text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6161
6162    pd->interfaces.value =
6163       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &value_iface_desc);
6164    eldbus_service_object_data_set(pd->interfaces.value, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
6165 }
6166
6167 static Eina_Bool
6168 _bridge_accessible_event_dispatch(void *data, Eo *accessible, const Eo_Event_Description *desc, void *event_info)
6169 {
6170    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(data, pd, EINA_TRUE);
6171
6172    _bridge_object_register(data, accessible);
6173
6174    Eo_Event_Cb cb = eina_hash_find(pd->event_hash, &desc);
6175    return cb ? cb(data, accessible, desc, event_info) : EINA_TRUE;
6176 }
6177
6178 static void
6179 _a11y_bus_initialize(Eo *obj, const char *socket_addr)
6180 {
6181    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
6182    pd->a11y_bus = eldbus_private_address_connection_get(socket_addr);
6183    if (!pd->a11y_bus)
6184      return;
6185
6186    eldbus_connection_event_callback_add(pd->a11y_bus, ELDBUS_CONNECTION_EVENT_DISCONNECTED, _disconnect_cb, obj);
6187
6188    // init data structures
6189    pd->cache = eina_hash_pointer_new(NULL);
6190    pd->state_hash = _elm_atspi_state_hash_build();
6191    pd->event_hash = _elm_atspi_event_hash_build();
6192
6193    // dbus init
6194    _cache_register(obj);
6195    _interfaces_register(obj);
6196    _event_handlers_register(obj);
6197    if (!getenv("ELM_ATSPI_NO_EMBED"))
6198      _elm_atspi_bridge_app_register(obj);
6199
6200    // register accesible object event listener
6201    eo_do(ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, pd->event_hdlr = elm_interface_atspi_accessible_event_handler_add(_bridge_accessible_event_dispatch, obj));
6202
6203 }
6204
6205 static void
6206 _a11y_bus_address_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
6207 {
6208    const char *errname, *errmsg, *sock_addr = NULL;
6209    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
6210
6211    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
6212
6213    if (eldbus_message_error_get(msg, &errname, &errmsg))
6214      {
6215         ERR("%s %s", errname, errmsg);
6216         return;
6217      }
6218
6219    if (!eldbus_message_arguments_get(msg, "s", &sock_addr) || !sock_addr)
6220      {
6221         ERR("Could not get A11Y Bus socket address.");
6222         return;
6223      }
6224
6225    _a11y_socket_address = eina_stringshare_add(sock_addr);
6226    _a11y_bus_initialize((Eo*)data, sock_addr);
6227 }
6228
6229 static void _a11y_connection_init(Eo *bridge)
6230 {
6231    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6232    Eina_Bool is_connected;
6233
6234    eo_do(bridge, is_connected = elm_obj_atspi_bridge_connected_get());
6235
6236    if (is_connected) return;
6237
6238    // TIZEN_ONLY(20170512): send window activated event to at_spi2 only once per session
6239    pd->window_activated_broadcast_needed = EINA_TRUE;
6240
6241    Eldbus_Message *m = eldbus_object_method_call_new(pd->bus_obj, A11Y_DBUS_INTERFACE, "GetAddress");
6242    Eldbus_Pending *p = eldbus_object_send(pd->bus_obj, m, _a11y_bus_address_get, bridge, 100);
6243
6244    if (p)
6245       pd->pending_requests = eina_list_append(pd->pending_requests, p);
6246 }
6247
6248 static void
6249 _screen_reader_enabled_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
6250 {
6251    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
6252    const char *errname, *errmsg;
6253    Eina_Bool is_enabled;
6254    Eldbus_Message_Iter *variant;
6255
6256    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
6257
6258    if (eldbus_message_error_get(msg, &errname, &errmsg))
6259      {
6260         WRN("%s %s", errname, errmsg);
6261         return;
6262      }
6263    if (!eldbus_message_arguments_get(msg, "v", &variant))
6264      {
6265         ERR("'ScreenReaderEnabled' not packed into variant.");
6266         return;
6267      }
6268    if (!eldbus_message_iter_arguments_get(variant, "b", &is_enabled))
6269      {
6270         ERR("Could not get 'ScreenReaderEnabled' boolean property");
6271         return;
6272      }
6273    //TIZEN_ONLY(20161027) - Export elm_atspi_bridge_utils_is_screen_reader_enabled
6274    pd->screen_reader_enabled = !!is_enabled;
6275    //
6276    //TIZEN_ONLY(20160822): When atspi mode is dynamically switched on/off,
6277    //register/unregister access objects accordingly.
6278    // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6279    _elm_win_screen_reader(is_enabled);
6280    //
6281    //
6282 }
6283
6284 // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6285 static void
6286 _at_spi_client_enabled_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
6287 {
6288    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
6289    const char *errname, *errmsg;
6290    Eina_Bool is_enabled;
6291    Eldbus_Message_Iter *variant;
6292
6293    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
6294
6295    if (eldbus_message_error_get(msg, &errname, &errmsg))
6296      {
6297         WRN("%s %s", errname, errmsg);
6298         return;
6299      }
6300    if (!eldbus_message_arguments_get(msg, "v", &variant))
6301      {
6302         ERR("'" A11Y_DBUS_ENABLED_PROPERTY "' not packed into variant.");
6303         return;
6304      }
6305    if (!eldbus_message_iter_arguments_get(variant, "b", &is_enabled))
6306      {
6307         ERR("Could not get '" A11Y_DBUS_ENABLED_PROPERTY "' boolean property");
6308         return;
6309      }
6310    if (is_enabled)
6311      _a11y_connection_init(data);
6312    else
6313      {
6314         _elm_win_atspi(EINA_FALSE);
6315         DBG("AT-SPI2 stack not enabled.");
6316      }
6317
6318 }
6319 //
6320
6321 static void _bridge_object_register(Eo *bridge, Eo *obj)
6322 {
6323    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6324
6325    if (!eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6326      {
6327         WRN("Unable to register class w/o Elm_Interface_Atspi_Accessible!");
6328         return;
6329      }
6330
6331    if (eina_hash_find(pd->cache, &obj))
6332         return;
6333
6334    eina_hash_add(pd->cache, &obj, obj);
6335 }
6336
6337 void
6338 _elm_atspi_bridge_init(void)
6339 {
6340    if (!_init_count)
6341      {
6342         _instance = eo_add(ELM_ATSPI_BRIDGE_CLASS, NULL);
6343         _init_count = 1;
6344      }
6345 }
6346
6347 EAPI Eo*
6348 _elm_atspi_bridge_get(void)
6349 {
6350    return _instance;
6351 }
6352
6353 void
6354 _elm_atspi_bridge_shutdown(void)
6355 {
6356    if (_init_count)
6357      {
6358         eo_del(_instance);
6359         _init_count = 0;
6360      }
6361    if (_a11y_socket_address)
6362      eina_stringshare_del(_a11y_socket_address);
6363    _a11y_socket_address = NULL;
6364 }
6365
6366 static Key_Event_Info*
6367 _key_event_info_new(int event_type, const Ecore_Event_Key *data, Eo *bridge)
6368 {
6369    Key_Event_Info *ret;
6370    EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
6371
6372    ret = calloc(sizeof(Key_Event_Info), 1);
6373
6374    ret->type = event_type;
6375    ret->event = *data;
6376    ret->bridge = bridge;
6377
6378    ret->event.keyname = eina_stringshare_add(data->keyname);
6379    ret->event.key = eina_stringshare_add(data->key);
6380    ret->event.string = eina_stringshare_add(data->string);
6381    ret->event.compose = eina_stringshare_add(data->compose);
6382
6383    // not sure why it is here, but explicite keep it NULLed.
6384    ret->event.data = NULL;
6385
6386    return ret;
6387 }
6388
6389 static void
6390 _key_event_info_free(Key_Event_Info *data)
6391 {
6392    EINA_SAFETY_ON_NULL_RETURN(data);
6393
6394    eina_stringshare_del(data->event.keyname);
6395    eina_stringshare_del(data->event.key);
6396    eina_stringshare_del(data->event.string);
6397    eina_stringshare_del(data->event.compose);
6398
6399    free(data);
6400 }
6401
6402 static void
6403 _iter_marshall_key_event(Eldbus_Message_Iter *iter, Key_Event_Info *data)
6404 {
6405    Eldbus_Message_Iter *struct_iter;
6406    EINA_SAFETY_ON_NULL_RETURN(data);
6407
6408    struct_iter = eldbus_message_iter_container_new(iter, 'r', NULL);
6409
6410    const char *str = data->event.keyname ? data->event.keyname : "";
6411    int is_text = data->event.keyname ? 1 : 0;
6412    int type;
6413    if (data->type == ECORE_EVENT_KEY_DOWN)
6414      type = ATSPI_KEY_PRESSED_EVENT;
6415    else
6416      type = ATSPI_KEY_RELEASED_EVENT;
6417
6418    eldbus_message_iter_arguments_append(struct_iter, "uiiiisb", type, 0, data->event.keycode, 0, data->event.timestamp, str, is_text);
6419    eldbus_message_iter_container_close(iter, struct_iter);
6420 }
6421
6422 static void
6423 _on_event_del(void *user_data, void *func_data EINA_UNUSED)
6424 {
6425    Key_Event_Info *info = user_data;
6426    _key_event_info_free(info);
6427 }
6428
6429 static void
6430 _on_listener_answer(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
6431 {
6432    Key_Event_Info *info = data;
6433    const char *errname, *errmsg;
6434    Eina_Bool ret = EINA_TRUE;
6435
6436    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(info->bridge, pd);
6437
6438    if (eldbus_message_error_get(msg, &errname, &errmsg))
6439      {
6440         ERR("%s %s", errname, errmsg);
6441         goto reemit;
6442      }
6443    if (!eldbus_message_arguments_get(msg, "b", &ret))
6444      {
6445         ERR("Return message doen not contian return value");
6446         goto reemit;
6447      }
6448    if (ret)
6449      {
6450         _key_event_info_free(info);
6451         return;
6452      }
6453 reemit:
6454    ecore_event_add(info->type, &info->event, _on_event_del, info);
6455    pd->reemited_events = eina_list_append(pd->reemited_events, &info->event);
6456 }
6457
6458 static Eina_Bool
6459 _elm_atspi_bridge_key_filter(void *data, void *loop EINA_UNUSED, int type, void *event)
6460 {
6461    Eldbus_Message *msg;
6462    Eldbus_Message_Iter *iter;
6463    Ecore_Event_Key *key_event = event;
6464    Key_Event_Info *ke;
6465    Eo *bridge = data;
6466
6467    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_TRUE);
6468
6469    // TIZEN_ONLY(20160802): do not handle events if the window is not activated
6470    if (!pd->window_activated) return EINA_TRUE;
6471    //
6472
6473    if ((type != ECORE_EVENT_KEY_DOWN) && (type != ECORE_EVENT_KEY_UP)) return EINA_TRUE;
6474
6475    // check if reemited
6476    if (eina_list_data_find(pd->reemited_events, event))
6477      {
6478         pd->reemited_events = eina_list_remove(pd->reemited_events, event);
6479         return EINA_TRUE;
6480      }
6481
6482    // TIZEN_ONLY(20170118): Not handle events if keyboard is on
6483    if (pd->root)
6484      {
6485         Eina_List *children, *l;
6486         Evas_Object *child;
6487         eo_do(pd->root, children = elm_interface_atspi_accessible_children_get());
6488
6489         EINA_LIST_FOREACH(children, l, child)
6490           {
6491              if (elm_widget_focus_get(child)) break;
6492           }
6493         eina_list_free(children);
6494
6495         Elm_Win_Keyboard_Mode mode;
6496         mode = elm_win_keyboard_mode_get(child);
6497         if (mode == ELM_WIN_KEYBOARD_ON) return EINA_TRUE;
6498      }
6499    //
6500
6501    ke = _key_event_info_new(type, key_event, bridge);
6502    if (!ke) return EINA_TRUE;
6503
6504    msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_DEC,
6505                                         ATSPI_DBUS_INTERFACE_DEC, "NotifyListenersSync");
6506    iter = eldbus_message_iter_get(msg);
6507    _iter_marshall_key_event(iter, ke);
6508
6509    // timeout should be kept reasonaby low to avoid delays
6510    if (!eldbus_connection_send(pd->a11y_bus, msg, _on_listener_answer, ke, 100))
6511      return EINA_TRUE;
6512
6513    return EINA_FALSE;
6514 }
6515
6516 EOLIAN Eina_Bool
6517 _elm_atspi_bridge_connected_get(Eo *obj EINA_UNUSED, Elm_Atspi_Bridge_Data *pd)
6518 {
6519    return pd->connected;
6520 }
6521
6522 EOLIAN Eo*
6523 _elm_atspi_bridge_root_get(Eo *obj EINA_UNUSED, Elm_Atspi_Bridge_Data *pd)
6524 {
6525    if (!pd->root)
6526      {
6527         pd->root = eo_add(ELM_ATSPI_APP_OBJECT_CLASS, NULL);
6528         elm_interface_atspi_accessible_added(pd->root);
6529      }
6530
6531    return pd->root;
6532 }
6533
6534 static void
6535 _properties_changed_cb(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event)
6536 {
6537    Eldbus_Proxy_Event_Property_Changed *ev = event;
6538    Eo *bridge = data;
6539    Eina_Bool val;
6540    const char *ifc = eldbus_proxy_interface_get(ev->proxy);
6541    if (ev->name && !strcmp(ev->name, "ScreenReaderEnabled" ) &&
6542        ifc && !strcmp(A11Y_DBUS_STATUS_INTERFACE, ifc))
6543      {
6544         if (!eina_value_get(ev->value, &val))
6545           {
6546              ERR("Unable to get ScreenReaderEnabled property value");
6547              return;
6548           }
6549         //TIZEN_ONLY(20161027) - Export elm_atspi_bridge_utils_is_screen_reader_enabled
6550         ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6551         pd->screen_reader_enabled = !!val;
6552         //
6553         //TIZEN_ONLY(20160822): When atspi mode is dynamically switched on/off,
6554         //register/unregister access objects accordingly.
6555         // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6556         _elm_win_screen_reader(val);
6557         //
6558         //
6559      }
6560    // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6561    if (ev->name && !strcmp(ev->name, A11Y_DBUS_ENABLED_PROPERTY) &&
6562        ifc && !strcmp(A11Y_DBUS_STATUS_INTERFACE, ifc))
6563      {
6564         if (!eina_value_get(ev->value, &val))
6565           {
6566              // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6567              ERR("Unable to get " A11Y_DBUS_ENABLED_PROPERTY " property value");
6568              return;
6569           }
6570
6571
6572         if (val)
6573           _a11y_connection_init(bridge);
6574         else
6575           {
6576              _elm_win_atspi(EINA_FALSE);
6577              _a11y_connection_shutdown(bridge);
6578           }
6579      }
6580    //
6581 }
6582
6583 EOLIAN Eo_Base*
6584 _elm_atspi_bridge_eo_base_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
6585 {
6586    Eldbus_Proxy *proxy;
6587    Eldbus_Pending *req;
6588
6589    eo_do_super(obj, ELM_ATSPI_BRIDGE_CLASS, eo_constructor());
6590
6591    elm_need_eldbus();
6592
6593    if (!(pd->session_bus = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION)))
6594      {
6595         ERR("Unable to connect to Session Bus");
6596         return NULL;
6597      }
6598    if (!(pd->bus_obj = eldbus_object_get(pd->session_bus, A11Y_DBUS_NAME, A11Y_DBUS_PATH)))
6599      {
6600         ERR("Could not get /org/a11y/bus object");
6601         goto obj_err;
6602      }
6603    if (!(proxy = eldbus_proxy_get(pd->bus_obj, A11Y_DBUS_STATUS_INTERFACE)))
6604      {
6605         ERR("Could not get proxy object for %s interface", A11Y_DBUS_STATUS_INTERFACE);
6606         goto proxy_err;
6607      }
6608    if (!(req = eldbus_proxy_property_get(proxy, "ScreenReaderEnabled", _screen_reader_enabled_get, obj)))
6609      {
6610         ERR("Could not send PropertyGet request");
6611         goto proxy_err;
6612      }
6613    pd->pending_requests = eina_list_append(pd->pending_requests, req);
6614
6615    // TIZEN_ONLY(20170516): connect to at-spi dbus based on org.a11y.Status.IsEnabled property
6616    if (!(req = eldbus_proxy_property_get(proxy, A11Y_DBUS_ENABLED_PROPERTY, _at_spi_client_enabled_get, obj)))
6617      {
6618         ERR("Could not send PropertyGet request");
6619         goto proxy_err;
6620      }
6621
6622    pd->pending_requests = eina_list_append(pd->pending_requests, req);
6623    //
6624
6625    eldbus_proxy_properties_monitor(proxy, EINA_TRUE);
6626    eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
6627                                    _properties_changed_cb, obj);
6628
6629    return obj;
6630
6631 proxy_err:
6632    eldbus_object_unref(pd->bus_obj);
6633    pd->bus_obj = NULL;
6634 obj_err:
6635    eldbus_connection_unref(pd->session_bus);
6636    pd->session_bus = NULL;
6637    return NULL;
6638 }
6639
6640 EOLIAN void
6641 _elm_atspi_bridge_eo_base_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
6642 {
6643    _a11y_connection_shutdown(obj);
6644
6645    if (pd->bus_obj) eldbus_object_unref(pd->bus_obj);
6646    if (pd->session_bus) eldbus_connection_unref(pd->session_bus);
6647    if (pd->root) eo_del(pd->root);
6648
6649    eo_do_super(obj, ELM_ATSPI_BRIDGE_CLASS, eo_destructor());
6650 }
6651
6652 EAPI Eina_Bool
6653 elm_atspi_bridge_object_address_get(Eo *obj, char **bus, char **path)
6654 {
6655    Eo *bridge = _elm_atspi_bridge_get();
6656    if (!bridge)
6657      {
6658         ERR("Connection with accessibility bus not established.");
6659         return EINA_FALSE;
6660      }
6661    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
6662    if (!eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6663      {
6664         ERR("Connection with accessibility bus not established.");
6665         return EINA_FALSE;
6666      }
6667    if (bus) *bus = strdup(eldbus_connection_unique_name_get(pd->a11y_bus));
6668    if (path) *path = strdup(_bridge_path_from_object(bridge, obj));
6669
6670    return EINA_TRUE;
6671 }
6672
6673 static Eina_Bool
6674 _proxy_property_get(const Eldbus_Service_Interface *interface, const char *property,
6675                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg EINA_UNUSED,
6676                          Eldbus_Message **error EINA_UNUSED)
6677 {
6678    char *bus, *path;
6679    Eo *obj = eldbus_service_object_data_get(interface, "_atspi_obj");
6680    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
6681
6682    if (!strcmp(property, "Object"))
6683      {
6684        Eo *parent;
6685        eo_do(obj, parent = eo_parent_get());
6686        if (!elm_atspi_bridge_object_address_get(parent, &bus, &path))
6687           return EINA_FALSE;
6688
6689        Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
6690        if (iter_struct)
6691          {
6692             eldbus_message_iter_basic_append(iter_struct, 's', bus);
6693             eldbus_message_iter_basic_append(iter_struct, 'o', path);
6694             eldbus_message_iter_container_close(iter, iter_struct);
6695          }
6696        free(bus);
6697        free(path);
6698        return EINA_TRUE;
6699      }
6700    return EINA_FALSE;
6701 }
6702
6703 static const Eldbus_Property proxy_properties[] = {
6704    { "Object", "(so)", _proxy_property_get, NULL, 0 },
6705    { NULL, NULL, NULL, NULL, 0 }
6706 };
6707
6708 static const Eldbus_Service_Interface_Desc _proxy_iface_desc = {
6709    ELM_ATSPI_DBUS_INTERFACE_PROXY, socket_methods, NULL, proxy_properties, NULL, NULL
6710 };
6711
6712 static void _embedded_reply_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
6713 {
6714    Eo *parent, *proxy = data;
6715    const char *err, *txt;
6716
6717    if (eldbus_message_error_get(msg, &err, &txt))
6718      {
6719         ERR("AT-SPI: Embedded method call failed: %s %s", err, txt);
6720         eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
6721         return;
6722      }
6723    eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_CONNECTED, NULL));
6724
6725    eo_do(proxy, parent = eo_parent_get());
6726    if (parent)
6727      elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, proxy);
6728 }
6729
6730 static void
6731 _plug_embedded_send(Eldbus_Connection *conn, Eo *proxy, const char *bus, const char *path)
6732 {
6733    char *obj_path = NULL;
6734    Eo *parent;
6735    Eldbus_Message *msg = NULL;
6736
6737    eo_do(proxy, parent = eo_parent_get());
6738    if (!parent) goto fail;
6739
6740    msg = eldbus_message_method_call_new(bus, path, ATSPI_DBUS_INTERFACE_SOCKET, "Embedded");
6741    if (!msg) goto fail;
6742
6743    if (!elm_atspi_bridge_object_address_get(parent, NULL, &obj_path))
6744      goto fail;
6745
6746    if (!eldbus_message_arguments_append(msg, "s", obj_path))
6747      goto fail;
6748
6749    if (!eldbus_connection_send(conn, msg, _embedded_reply_cb, proxy, 100))
6750      goto fail;
6751
6752    ELM_SAFE_FREE(obj_path, free);
6753    return;
6754
6755 fail:
6756    ERR("AT-SPI: Unable to send Embedded request.");
6757    if (msg) eldbus_message_unref(msg);
6758    ELM_SAFE_FREE(obj_path, free);
6759    eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
6760 }
6761
6762 static void _socket_addr_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
6763 {
6764    Eo *proxy = data;
6765    const char *bus, *path, *err, *txt;
6766    Eldbus_Message_Iter *iter, *iter_variant, *iter_struct;
6767
6768    Eo *bridge = _elm_atspi_bridge_get();
6769    if (!bridge)
6770      {
6771         ERR("AT-SPI: Atspi bridge is not enabled.");
6772         return;
6773      }
6774    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6775
6776    if (eldbus_message_error_get(msg, &err, &txt))
6777      {
6778         ERR("Unable to connect to socket: %s %s", err, txt);
6779         goto retry;
6780      }
6781
6782    iter = eldbus_message_iter_get(msg);
6783    if (!eldbus_message_iter_arguments_get(iter, "v", &iter_variant))
6784      {
6785         ERR("Unable to get variant parameter");
6786         goto fail;
6787      }
6788
6789    if (!eldbus_message_iter_arguments_get(iter_variant, "(so)", &iter_struct))
6790      {
6791         ERR("Unable to get so parameters");
6792         goto fail;
6793      }
6794
6795    if (!eldbus_message_iter_arguments_get(iter_struct, "so", &bus, &path))
6796      {
6797         ERR("Unable to get so parameters");
6798         goto fail;
6799      }
6800
6801    eo_do(proxy, elm_obj_atspi_proxy_address_set(bus, path));
6802
6803    _plug_embedded_send(pd->a11y_bus, proxy, bus, path);
6804
6805    return;
6806
6807 fail:
6808    eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
6809    return;
6810
6811 retry:
6812    eo_do(proxy, elm_obj_atspi_proxy_address_get_retry_timer_add());
6813 }
6814
6815 static void
6816 _plug_address_discover(Eldbus_Connection *conn, Eo *proxy, const char *svc_bus, const char *svc_path)
6817 {
6818    Eldbus_Object *dobj;
6819    dobj = eldbus_object_get(conn, svc_bus, svc_path);
6820    if (!dobj)
6821      {
6822         ERR("Unable to get eldbus object from: %s %s", svc_bus, svc_path);
6823         return;
6824      }
6825
6826    Eldbus_Message *msg = eldbus_object_method_call_new(dobj, ELDBUS_FDO_INTERFACE_PROPERTIES, "Get");
6827    eldbus_message_arguments_append(msg, "ss", ELM_ATSPI_DBUS_INTERFACE_PROXY, "Object");
6828    eldbus_object_send(dobj, msg, _socket_addr_get_cb, proxy, 100);
6829 }
6830
6831 static void _plug_connect(Eldbus_Connection *conn, Eo *proxy)
6832 {
6833    const char *bus, *path;
6834
6835    eo_do(proxy, bus = eo_key_data_get("__svc_bus"));
6836    eo_do(proxy, path = eo_key_data_get("__svc_path"));
6837
6838    if (bus && path)
6839      {
6840         _plug_address_discover(conn, proxy, bus, path);
6841         return;
6842      }
6843    else
6844      {
6845         eo_do(proxy, elm_obj_atspi_proxy_address_get(&bus, &path));
6846         if (!bus || !path)
6847           {
6848              ERR("AT-SPI: Elm_Atspi_Proxy bus or path not set. Unable to connect");
6849              eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
6850              return;
6851           }
6852         _plug_embedded_send(conn, proxy, bus, path);
6853      }
6854    return;
6855 }
6856
6857 static Eina_Bool _from_list_remove(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
6858 {
6859    Eina_List **list = data;
6860    *list = eina_list_remove(*list, obj);
6861    return EINA_TRUE;
6862 }
6863
6864 EAPI void elm_atspi_bridge_utils_proxy_connect(Eo *proxy)
6865 {
6866    Eo *bridge = _elm_atspi_bridge_get();
6867
6868    if (!bridge)
6869      {
6870         ERR("AT-SPI: Atspi bridge is not enabled.");
6871         eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
6872         return;
6873      }
6874    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6875
6876    if (!pd->a11y_bus)
6877      {
6878         if (!eina_list_data_find(pd->plug_queue, proxy))
6879           {
6880              pd->plug_queue = eina_list_append(pd->plug_queue, proxy);
6881              eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _from_list_remove, &pd->plug_queue));
6882           }
6883         return;
6884      }
6885    _plug_connect(pd->a11y_bus, proxy);
6886 }
6887
6888 /**
6889  * @brief Service name sanitizer according to specs:
6890  * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
6891  * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-object-path
6892  */
6893 char *_sanitize_service_name(const char *name)
6894 {
6895    char ret[256] = "\0";
6896
6897    if (!name) return NULL;
6898
6899    const char *tmp = name;
6900    char *dst = ret;
6901
6902    // name element should not begin with digit. Swallow non-charater prefix
6903    while ((*tmp != '\0') && !isalpha(*tmp)) tmp++;
6904
6905    // append rest of character valid charactes [A-Z][a-z][0-9]_
6906    while ((*tmp != '\0') && (dst < &ret[sizeof(ret) - 1]))
6907      {
6908         if (isalpha(*tmp) || isdigit(*tmp) || (*tmp == '_'))
6909           *dst++ = *tmp;
6910         tmp++;
6911      }
6912
6913    *++dst = '\0';
6914    return strdup(ret);
6915 }
6916
6917 Eo* _elm_atspi_bridge_utils_proxy_create(Eo *parent, const char *svcname, int svcnum, Elm_Atspi_Proxy_Type type)
6918 {
6919    Eo *ret;
6920    char bus[256], path[256], *name;
6921    int res;
6922
6923    name = _sanitize_service_name(svcname);
6924    if (!name) return NULL;
6925
6926    res = snprintf(bus, sizeof(bus), "elm.atspi.proxy.socket.%s-%d", name, svcnum);
6927    if (res < 0 || (res >= (int)sizeof(bus)))
6928      {
6929         free(name);
6930         return NULL;
6931      }
6932
6933    res = snprintf(path, sizeof(path), "/elm/atspi/proxy/socket/%s/%d", name, svcnum);
6934    if (res < 0 || (res >= (int)sizeof(path)))
6935      {
6936         free(name);
6937         return NULL;
6938      }
6939
6940    free(name);
6941
6942    ret = eo_add(ELM_ATSPI_PROXY_CLASS, parent, elm_obj_atspi_proxy_constructor(type));
6943    if (!ret) return NULL;
6944
6945    eo_do(ret, eo_key_data_set("__svc_bus", eina_stringshare_add(bus)));
6946    eo_do(ret, eo_key_data_set("__svc_path", eina_stringshare_add(path)));
6947
6948    return ret;
6949 }
6950
6951 static Eina_Bool
6952 _on_socket_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED)
6953 {
6954    Eldbus_Service_Interface *ifc = data;
6955    const char *bus;
6956    Eldbus_Connection *conn = eldbus_service_connection_get(ifc);
6957    eo_do(obj, bus = eo_key_data_get("__svc_bus"));
6958    eldbus_name_release(conn, bus, NULL, NULL);
6959    eldbus_service_interface_unregister(ifc);
6960    return EINA_TRUE;
6961 }
6962
6963 static void
6964 _proxy_interface_register(Eldbus_Connection *conn, Eo *proxy, const char *bus, const char *path)
6965 {
6966    Eldbus_Service_Interface *proxy_infc;
6967    Eo *bridge = _elm_atspi_bridge_get();
6968    if (!bridge)
6969      {
6970         ERR("AT-SPI: Atspi bridge is not enabled.");
6971         return;
6972      }
6973    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6974
6975    eldbus_name_request(conn, bus, ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, NULL, NULL);
6976    proxy_infc = eldbus_service_interface_register(pd->a11y_bus, path, &_proxy_iface_desc);
6977    if (!proxy_infc)
6978      ERR("AT-SPI: Proxy interface registration failed");
6979    eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _on_socket_del, proxy_infc));
6980    eldbus_service_object_data_set(proxy_infc, "_atspi_obj", proxy);
6981 }
6982
6983 static void _socket_ifc_create(Eldbus_Connection *conn, Eo *proxy)
6984 {
6985    const char *bus, *path;
6986    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6987    Eo *bridge = _elm_atspi_bridge_get();
6988    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
6989    //
6990
6991    eo_do(proxy, bus = eo_key_data_get("__svc_bus"));
6992    eo_do(proxy, path = eo_key_data_get("__svc_path"));
6993
6994    if (bus && path)
6995      _proxy_interface_register(conn, proxy, bus, path);
6996
6997    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6998    pd->interfaces.socket =
6999       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &socket_iface_desc);
7000    //
7001 }
7002
7003 EAPI void elm_atspi_bridge_utils_proxy_listen(Eo *proxy)
7004 {
7005    Eo *bridge = _elm_atspi_bridge_get();
7006    if (!bridge)
7007      {
7008         ERR("AT-SPI: Atspi bridge is not enabled.");
7009         return;
7010      }
7011    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
7012    if (!pd->a11y_bus)
7013      {
7014         if (!eina_list_data_find(pd->socket_queue, proxy))
7015           {
7016              pd->socket_queue = eina_list_append(pd->socket_queue, proxy);
7017              eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _from_list_remove, &pd->socket_queue));
7018           }
7019         return;
7020      }
7021    _socket_ifc_create(pd->a11y_bus, proxy);
7022 }
7023
7024 //TIZEN_ONLY(20160527) - Add direct reading feature
7025 static void
7026 _on_read_command_call(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
7027 {
7028    const char *errname, *errmsg;
7029    const char *s;
7030    const Eina_Bool b;
7031    const int32_t i;
7032    Elm_Atspi_Say_Info *say_info = data;
7033
7034    if (eldbus_message_error_get(msg, &errname, &errmsg))
7035      {
7036         ERR("%s %s", errname, errmsg);
7037         return;
7038      }
7039
7040    if (say_info)
7041      {
7042         // get read command id and map it to obj
7043         if (eldbus_message_arguments_get(msg, "sbi", &s, &b, &i))
7044           {
7045              if (!read_command_id)
7046                read_command_id = eina_hash_int32_new(NULL);
7047
7048              if (!read_command_id) {
7049                ERR("eina_hash_int32_new() failed to create new map to store callbacks for direct reading commands");
7050                return;
7051              }
7052
7053              eina_hash_add(read_command_id, &i, say_info);
7054           }
7055      }
7056 }
7057
7058 EAPI void
7059 elm_atspi_bridge_utils_say(const char* text,
7060                            Eina_Bool discardable,
7061                            const Elm_Atspi_Say_Signal_Cb func,
7062                            const void *data)
7063 {
7064    Eldbus_Message *msg;
7065    Eldbus_Message_Iter *iter;
7066    Elm_Atspi_Say_Info *say_info = NULL;
7067    Eo *bridge = _elm_atspi_bridge_get();
7068    if (!bridge)
7069      {
7070         ERR("AT-SPI: Atspi bridge is not enabled.");
7071         return;
7072      }
7073    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
7074    if (!pd->a11y_bus)
7075      {
7076         ERR("AT-SPI: a11y bus is not set.");
7077         return;
7078      }
7079
7080    msg = eldbus_message_method_call_new(ELM_ATSPI_DIRECT_READ_BUS,
7081                                         ELM_ATSPI_DIRECT_READ_PATH,
7082                                         ELM_ATSPI_DIRECT_READ_INTERFACE,
7083                                         "ReadCommand");
7084    iter = eldbus_message_iter_get(msg);
7085    eldbus_message_iter_arguments_append(iter, "sb", text, discardable);
7086    if (func) {
7087       say_info = calloc(1, sizeof(Elm_Atspi_Say_Info));
7088       if (say_info) {
7089          say_info->func = func;
7090          say_info->data = (void *)data;
7091       }
7092    }
7093    eldbus_connection_send(pd->a11y_bus, msg, _on_read_command_call, say_info, -1);
7094 }
7095 //
7096
7097 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
7098 static void
7099 _offset_set_reply_cb(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
7100 {
7101    const char *err, *txt;
7102
7103    if (eldbus_message_error_get(msg, &err, &txt))
7104      {
7105         ERR("AT-SPI: SetOffset method call failed: %s %s", err, txt);
7106         return;
7107      }
7108 }
7109
7110 void elm_atspi_bridge_utils_proxy_offset_set(Eo *proxy, int x, int y)
7111 {
7112    const char *bus, *path;
7113    Eo *bridge = _elm_atspi_bridge_get();
7114    if (!bridge) return;
7115
7116    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
7117
7118    if (!pd->a11y_bus) return;
7119
7120    eo_do(proxy, bus = eo_key_data_get("__svc_bus"));
7121    eo_do(proxy, path = eo_key_data_get("__svc_path"));
7122
7123    Eldbus_Message *msg = NULL;
7124
7125    msg = eldbus_message_method_call_new(bus, path, ELM_ATSPI_DBUS_INTERFACE_PROXY, "SetOffset");
7126    if (!msg) goto fail;
7127
7128    if (!eldbus_message_arguments_append(msg, "i", x))
7129      goto fail;
7130
7131    if (!eldbus_message_arguments_append(msg, "i", y))
7132      goto fail;
7133
7134    if (!eldbus_connection_send(pd->a11y_bus, msg, _offset_set_reply_cb, NULL, 100))
7135      goto fail;
7136
7137    return;
7138
7139 fail:
7140    ERR("AT-SPI: Unable to send SetOffset request.");
7141    if (msg) eldbus_message_unref(msg);
7142 }
7143 //
7144 //TIZEN_ONLY(20161027) - Export elm_atspi_bridge_utils_is_screen_reader_enabled
7145 EAPI Eina_Bool elm_atspi_bridge_utils_is_screen_reader_enabled(void)
7146 {
7147    Eo *bridge = _elm_atspi_bridge_get();
7148    if (!bridge)
7149      {
7150         ERR("AT-SPI: Atspi bridge is not enabled.");
7151         return EINA_FALSE;
7152      }
7153    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
7154    return pd->screen_reader_enabled;
7155 }
7156 //
7157 #include "elm_atspi_bridge.eo.c"