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