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