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