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