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