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