1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_COMPONENT_PROTECTED
6 #define EFL_ACCESS_OBJECT_PROTECTED
7 #define EFL_ACCESS_ACTION_PROTECTED
8 #define EFL_ACCESS_VALUE_PROTECTED
9 #define EFL_ACCESS_SELECTION_PROTECTED
10 #define EFL_ACCESS_TEXT_PROTECTED
11 #define EFL_ACCESS_EDITABLE_TEXT_PROTECTED
12 
13 
14 #include "atspi/atspi-constants.h"
15 
16 #include <stdint.h>
17 #include <assert.h>
18 #include <Elementary.h>
19 #include "elm_priv.h"
20 
21 /*
22  * Accessibility Bus info not defined in atspi-constants.h
23  */
24 #define A11Y_DBUS_NAME "org.a11y.Bus"
25 #define A11Y_DBUS_PATH "/org/a11y/bus"
26 #define A11Y_DBUS_INTERFACE "org.a11y.Bus"
27 #define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
28 #define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
29 
30 #define CACHE_ITEM_SIGNATURE "((so)(so)(so)a(so)assusau)"
31 #define CACHE_INTERFACE_PATH "/org/a11y/atspi/cache"
32 
33 #define ELM_ACCESS_OBJECT_PATH_ROOT "root"
34 #define ELM_ACCESS_OBJECT_PATH_PREFIX  "/org/a11y/atspi/accessible/"
35 #define ELM_ACCESS_OBJECT_PATH_PREFIX2  "/org/a11y/atspi/accessible"
36 #define ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE ELM_ACCESS_OBJECT_PATH_PREFIX "%llu"
37 
38 #define SIZE(x) sizeof(x)/sizeof(x[0])
39 #define ELM_ATSPI_BRIDGE_CLASS_NAME "__Elm_Atspi_Bridge"
40 
41 #define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, sd) \
42    Elm_Atspi_Bridge_Data *sd = efl_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
43    if (!sd) return;
44 
45 #define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(obj, sd, val) \
46    Elm_Atspi_Bridge_Data *sd = efl_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
47    if (!sd) return val;
48 
49 #define ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg, error) \
50    if (!(obj) || !efl_isa(obj, class)) \
51      { \
52         *(error) = _dbus_invalid_ref_error_new(msg); \
53         return EINA_FALSE; \
54      }
55 
56 #define ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg) \
57    if (!(obj) || !efl_isa(obj, class)) \
58      return _dbus_invalid_ref_error_new(msg);
59 
60 #define ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg) \
61    if (!obj) \
62      return _dbus_invalid_ref_error_new(msg);
63 
64 typedef struct Key_Event_Info {
65      Ecore_Event_Key event;
66      int type;
67      Eo *bridge;
68 } Key_Event_Info;
69 
70 typedef struct _Elm_Atspi_Bridge_Data
71 {
72    Eldbus_Connection *session_bus;
73    Eldbus_Connection *a11y_bus;
74    Eina_Hash *cache;
75    Eldbus_Service_Interface *cache_interface;
76    Eldbus_Signal_Handler *register_hdl;
77    Eldbus_Signal_Handler *unregister_hdl;
78    unsigned long object_broadcast_mask;
79    unsigned long object_property_broadcast_mask;
80    unsigned long object_children_broadcast_mask;
81    unsigned long long object_state_broadcast_mask;
82    unsigned long long window_signal_broadcast_mask;
83    Ecore_Event_Filter *key_flr;
84    Eldbus_Object *bus_obj;
85    Eina_List *pending_requests;
86    int id;
87    Eina_Hash *state_hash;
88    struct {
89         Eldbus_Service_Interface *accessible;
90         Eldbus_Service_Interface *application;
91         Eldbus_Service_Interface *action;
92         Eldbus_Service_Interface *component;
93         Eldbus_Service_Interface *collection;
94         Eldbus_Service_Interface *editable_text;
95         Eldbus_Service_Interface *image;
96         Eldbus_Service_Interface *selection;
97         Eldbus_Service_Interface *text;
98         Eldbus_Service_Interface *value;
99    } interfaces;
100    Efl_Access_Event_Handler *event_hdlr;
101    Eina_Hash *event_hash;
102    Eina_Bool connected : 1;
103 } Elm_Atspi_Bridge_Data;
104 
105 
106 struct collection_match_rule {
107      Efl_Access_State_Set states;
108      AtspiCollectionMatchType statematchtype;
109      Eina_List *attributes;
110      AtspiCollectionMatchType attributematchtype;
111      uint64_t roles[2];
112      AtspiCollectionMatchType rolematchtype;
113      Eina_List *ifaces;
114      AtspiCollectionMatchType interfacematchtype;
115      Eina_Bool reverse : 1;
116 };
117 
118 static Eo *_instance;
119 static int _init_count = 0;
120 
121 // Object Event handlers
122 static void _state_changed_signal_send(void *data, const Efl_Event *event);
123 static void _bounds_changed_signal_send(void *data, const Efl_Event *event);
124 static void _property_changed_signal_send(void *data, const Efl_Event *event);
125 static void _value_property_changed_signal_send(void *data, const Efl_Event *event);
126 static void _children_changed_signal_send(void *data, const Efl_Event *event);
127 static void _window_signal_send(void *data, const Efl_Event *event);
128 static void _visible_data_changed_signal_send(void *data, const Efl_Event *event);
129 static void _active_descendant_changed_signal_send(void *data, const Efl_Event *event);
130 static void _selection_signal_send(void *data, const Efl_Event *event);
131 static void _text_text_inserted_send(void *data, const Efl_Event *event);
132 static void _text_text_removed_send(void *data, const Efl_Event *event);
133 static void _text_caret_moved_send(void *data, const Efl_Event *event);
134 static void _text_selection_changed_send(void *data, const Efl_Event *event);
135 
136 // bridge private methods
137 static void _bridge_object_register(Eo *bridge, Eo *obj);
138 static void _bridge_object_unregister(Eo *bridge, Eo *obj);
139 static const char * _path_from_object(const Eo *eo);
140 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, ...);
141 static Eo * _bridge_object_from_path(Eo *bridge, const char *path);
142 static void _bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj);
143 
144 // utility functions
145 static void _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj);
146 static Eina_Bool _elm_atspi_bridge_key_filter(void *data, void *loop, int type, void *event);
147 static void _object_desktop_reference_append(Eldbus_Message_Iter *iter);
148 static void _on_object_add(void *data, const Efl_Event *event);
149 static void _on_object_del(void *data, const Efl_Event *event);
150 
151 typedef struct {
152      const Efl_Event_Description *desc;
153      const Efl_Event_Cb callback;
154 } Elm_Atspi_Bridge_Event_Handler;
155 
156 static const Elm_Atspi_Bridge_Event_Handler event_handlers[] = {
157    { EFL_ACCESS_OBJECT_EVENT_CHILDREN_CHANGED, _children_changed_signal_send},
158    { EFL_ACCESS_OBJECT_EVENT_PROPERTY_CHANGED, _property_changed_signal_send},
159    { EFL_ACCESS_OBJECT_EVENT_BOUNDS_CHANGED, _bounds_changed_signal_send},
160    { EFL_ACCESS_OBJECT_EVENT_STATE_CHANGED, _state_changed_signal_send},
161    { EFL_ACCESS_OBJECT_EVENT_VISIBLE_DATA_CHANGED, _visible_data_changed_signal_send},
162    { EFL_ACCESS_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED, _active_descendant_changed_signal_send},
163    { EFL_ACCESS_OBJECT_EVENT_ADDED, _on_object_add},
164    { EFL_ACCESS_OBJECT_EVENT_REMOVED, _on_object_del},
165    { EFL_ACCESS_WINDOW_EVENT_WINDOW_CREATED, _window_signal_send},
166    { EFL_ACCESS_WINDOW_EVENT_WINDOW_DESTROYED, _window_signal_send},
167    { EFL_ACCESS_WINDOW_EVENT_WINDOW_ACTIVATED, _window_signal_send},
168    { EFL_ACCESS_WINDOW_EVENT_WINDOW_DEACTIVATED, _window_signal_send},
169    { EFL_ACCESS_WINDOW_EVENT_WINDOW_MAXIMIZED, _window_signal_send},
170    { EFL_ACCESS_WINDOW_EVENT_WINDOW_MINIMIZED, _window_signal_send},
171    { EFL_ACCESS_WINDOW_EVENT_WINDOW_RESTORED, _window_signal_send},
172    { EFL_ACCESS_SELECTION_EVENT_ACCESS_SELECTION_CHANGED, _selection_signal_send},
173    { EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_CARET_MOVED, _text_caret_moved_send },
174    { EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_INSERTED, _text_text_inserted_send },
175    { EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_REMOVED, _text_text_removed_send },
176    { EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_SELECTION_CHANGED, _text_selection_changed_send },
177    { EFL_UI_RANGE_EVENT_CHANGED, _value_property_changed_signal_send }
178 };
179 
180 enum _Atspi_Object_Child_Event_Type
181 {
182    ATSPI_OBJECT_CHILD_ADDED = 0,
183    ATSPI_OBJECT_CHILD_REMOVED
184 };
185 
186 enum _Atspi_Object_Property
187 {
188    ATSPI_OBJECT_PROPERTY_NAME = 0,
189    ATSPI_OBJECT_PROPERTY_DESCRIPTION,
190    ATSPI_OBJECT_PROPERTY_VALUE,
191    ATSPI_OBJECT_PROPERTY_ROLE,
192    ATSPI_OBJECT_PROPERTY_PARENT,
193    ATSPI_OBJECT_PROPERTY_LAST
194 };
195 
196 enum _Atspi_Object_Signals {
197    ATSPI_OBJECT_EVENT_PROPERTY_CHANGED = 0,
198    ATSPI_OBJECT_EVENT_BOUNDS_CHANGED,
199    ATSPI_OBJECT_EVENT_LINK_SELECTED,
200    ATSPI_OBJECT_EVENT_STATE_CHANGED,
201    ATSPI_OBJECT_EVENT_CHILDREN_CHANGED,
202    ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED,
203    ATSPI_OBJECT_EVENT_SELECTION_CHANGED,
204    ATSPI_OBJECT_EVENT_MODEL_CHANGED,
205    ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED,
206    ATSPI_OBJECT_EVENT_ROW_INSERTED,
207    ATSPI_OBJECT_EVENT_ROW_REORDERED,
208    ATSPI_OBJECT_EVENT_ROW_DELETED,
209    ATSPI_OBJECT_EVENT_COLUMN_INSERTED,
210    ATSPI_OBJECT_EVENT_COLUMN_REORDERED,
211    ATSPI_OBJECT_EVENT_COLUMN_DELETED,
212    ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED,
213    ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED,
214    ATSPI_OBJECT_EVENT_TEXT_CHANGED,
215    ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED,
216    ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED,
217    ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED,
218 };
219 
220 enum _Atspi_Window_Signals
221 {
222    ATSPI_WINDOW_EVENT_PROPERTY_CHANGE = 0,
223    ATSPI_WINDOW_EVENT_MINIMIZE,
224    ATSPI_WINDOW_EVENT_MAXIMIZE,
225    ATSPI_WINDOW_EVENT_RESTORE,
226    ATSPI_WINDOW_EVENT_CLOSE,
227    ATSPI_WINDOW_EVENT_CREATE,
228    ATSPI_WINDOW_EVENT_REPARENT,
229    ATSPI_WINDOW_EVENT_DESKTOPCREATE,
230    ATSPI_WINDOW_EVENT_DESKTOPDESTROY,
231    ATSPI_WINDOW_EVENT_DESTROY,
232    ATSPI_WINDOW_EVENT_ACTIVATE,
233    ATSPI_WINDOW_EVENT_DEACTIVATE,
234    ATSPI_WINDOW_EVENT_RAISE,
235    ATSPI_WINDOW_EVENT_LOWER,
236    ATSPI_WINDOW_EVENT_MOVE,
237    ATSPI_WINDOW_EVENT_RESIZE,
238    ATSPI_WINDOW_EVENT_SHADE,
239    ATSPI_WINDOW_EVENT_UUSHADE,
240    ATSPI_WINDOW_EVENT_RESTYLE,
241 };
242 
243 static const Eldbus_Signal _event_obj_signals[] = {
244    [ATSPI_OBJECT_EVENT_PROPERTY_CHANGED] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
245    [ATSPI_OBJECT_EVENT_BOUNDS_CHANGED] = {"BoundsChanged", ELDBUS_ARGS({"siiv(iiii)", NULL}), 0},
246    [ATSPI_OBJECT_EVENT_LINK_SELECTED] = {"LinkSelected", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
247    [ATSPI_OBJECT_EVENT_STATE_CHANGED] = {"StateChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
248    [ATSPI_OBJECT_EVENT_CHILDREN_CHANGED] = {"ChildrenChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
249    [ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED] = {"VisibleDataChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
250    [ATSPI_OBJECT_EVENT_SELECTION_CHANGED] = {"SelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
251    [ATSPI_OBJECT_EVENT_MODEL_CHANGED] = {"ModelChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
252    [ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED] = {"ActiveDescendantChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
253    [ATSPI_OBJECT_EVENT_ROW_INSERTED] = {"RowInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
254    [ATSPI_OBJECT_EVENT_ROW_REORDERED] = {"RowReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
255    [ATSPI_OBJECT_EVENT_ROW_DELETED] = {"RowDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
256    [ATSPI_OBJECT_EVENT_COLUMN_INSERTED] = {"ColumnInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
257    [ATSPI_OBJECT_EVENT_COLUMN_REORDERED] = {"ColumnReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
258    [ATSPI_OBJECT_EVENT_COLUMN_DELETED] = {"ColumnDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
259    [ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED] = {"TextBoundsChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
260    [ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED] = {"TextSelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
261    [ATSPI_OBJECT_EVENT_TEXT_CHANGED] = {"TextChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
262    [ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED] = {"TextAttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
263    [ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED] = {"TextCaretMoved", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
264    [ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED] = {"AttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
265    {NULL, ELDBUS_ARGS({NULL, NULL}), 0}
266 };
267 
268 static const Eldbus_Signal _window_obj_signals[] = {
269    [ATSPI_WINDOW_EVENT_PROPERTY_CHANGE] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
270    [ATSPI_WINDOW_EVENT_MINIMIZE] = {"Minimize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
271    [ATSPI_WINDOW_EVENT_MAXIMIZE] = {"Maximize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
272    [ATSPI_WINDOW_EVENT_RESTORE] = {"Restore", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
273    [ATSPI_WINDOW_EVENT_CLOSE] = {"Close", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
274    [ATSPI_WINDOW_EVENT_CREATE] = {"Create", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
275    [ATSPI_WINDOW_EVENT_REPARENT] = {"Reparent", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
276    [ATSPI_WINDOW_EVENT_DESKTOPCREATE] = {"DesktopCreate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
277    [ATSPI_WINDOW_EVENT_DESKTOPDESTROY] = {"DesktopDestroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
278    [ATSPI_WINDOW_EVENT_DESTROY] = {"Destroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
279    [ATSPI_WINDOW_EVENT_ACTIVATE] = {"Activate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
280    [ATSPI_WINDOW_EVENT_DEACTIVATE] = {"Deactivate", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
281    [ATSPI_WINDOW_EVENT_RAISE] = {"Raise", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
282    [ATSPI_WINDOW_EVENT_LOWER] = {"Lower", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
283    [ATSPI_WINDOW_EVENT_MOVE] = {"Move", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
284    [ATSPI_WINDOW_EVENT_RESIZE] = {"Resize", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
285    [ATSPI_WINDOW_EVENT_SHADE] = {"Shade", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
286    [ATSPI_WINDOW_EVENT_UUSHADE] = {"uUshade", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
287    [ATSPI_WINDOW_EVENT_RESTYLE] = {"Restyle", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
288    {NULL, ELDBUS_ARGS({NULL, NULL}), 0}
289 };
290 
291 static const int elm_roles_to_atspi_roles[][2] = {
292    { EFL_ACCESS_ROLE_INVALID, ATSPI_ROLE_INVALID },
293    { EFL_ACCESS_ROLE_ACCELERATOR_LABEL, ATSPI_ROLE_ACCELERATOR_LABEL },
294    { EFL_ACCESS_ROLE_ALERT, ATSPI_ROLE_ALERT },
295    { EFL_ACCESS_ROLE_ANIMATION, ATSPI_ROLE_ANIMATION },
296    { EFL_ACCESS_ROLE_ARROW, ATSPI_ROLE_ARROW },
297    { EFL_ACCESS_ROLE_CALENDAR, ATSPI_ROLE_CALENDAR },
298    { EFL_ACCESS_ROLE_CANVAS, ATSPI_ROLE_CANVAS },
299    { EFL_ACCESS_ROLE_CHECK_BOX, ATSPI_ROLE_CHECK_BOX },
300    { EFL_ACCESS_ROLE_CHECK_MENU_ITEM, ATSPI_ROLE_CHECK_MENU_ITEM },
301    { EFL_ACCESS_ROLE_COLOR_CHOOSER, ATSPI_ROLE_COLOR_CHOOSER },
302    { EFL_ACCESS_ROLE_COLUMN_HEADER, ATSPI_ROLE_COLUMN_HEADER },
303    { EFL_ACCESS_ROLE_COMBO_BOX, ATSPI_ROLE_COMBO_BOX },
304    { EFL_ACCESS_ROLE_DATE_EDITOR, ATSPI_ROLE_DATE_EDITOR },
305    { EFL_ACCESS_ROLE_DESKTOP_ICON, ATSPI_ROLE_DESKTOP_ICON },
306    { EFL_ACCESS_ROLE_DESKTOP_FRAME, ATSPI_ROLE_DESKTOP_FRAME },
307    { EFL_ACCESS_ROLE_DIAL, ATSPI_ROLE_DIAL },
308    { EFL_ACCESS_ROLE_DIALOG, ATSPI_ROLE_DIALOG },
309    { EFL_ACCESS_ROLE_DIRECTORY_PANE, ATSPI_ROLE_DIRECTORY_PANE },
310    { EFL_ACCESS_ROLE_DRAWING_AREA, ATSPI_ROLE_DRAWING_AREA },
311    { EFL_ACCESS_ROLE_FILE_CHOOSER, ATSPI_ROLE_FILE_CHOOSER },
312    { EFL_ACCESS_ROLE_FILLER, ATSPI_ROLE_FILLER },
313    { EFL_ACCESS_ROLE_FOCUS_TRAVERSABLE, ATSPI_ROLE_FOCUS_TRAVERSABLE },
314    { EFL_ACCESS_ROLE_FONT_CHOOSER, ATSPI_ROLE_FONT_CHOOSER },
315    { EFL_ACCESS_ROLE_FRAME, ATSPI_ROLE_FRAME },
316    { EFL_ACCESS_ROLE_GLASS_PANE, ATSPI_ROLE_GLASS_PANE },
317    { EFL_ACCESS_ROLE_HTML_CONTAINER, ATSPI_ROLE_HTML_CONTAINER },
318    { EFL_ACCESS_ROLE_ICON, ATSPI_ROLE_ICON },
319    { EFL_ACCESS_ROLE_IMAGE, ATSPI_ROLE_IMAGE },
320    { EFL_ACCESS_ROLE_INTERNAL_FRAME, ATSPI_ROLE_INTERNAL_FRAME },
321    { EFL_ACCESS_ROLE_LABEL, ATSPI_ROLE_LABEL },
322    { EFL_ACCESS_ROLE_LAYERED_PANE, ATSPI_ROLE_LAYERED_PANE },
323    { EFL_ACCESS_ROLE_LIST, ATSPI_ROLE_LIST },
324    { EFL_ACCESS_ROLE_LIST_ITEM, ATSPI_ROLE_LIST_ITEM },
325    { EFL_ACCESS_ROLE_MENU, ATSPI_ROLE_MENU },
326    { EFL_ACCESS_ROLE_MENU_BAR, ATSPI_ROLE_MENU_BAR },
327    { EFL_ACCESS_ROLE_MENU_ITEM, ATSPI_ROLE_MENU_ITEM },
328    { EFL_ACCESS_ROLE_OPTION_PANE, ATSPI_ROLE_OPTION_PANE },
329    { EFL_ACCESS_ROLE_PAGE_TAB, ATSPI_ROLE_PAGE_TAB },
330    { EFL_ACCESS_ROLE_PAGE_TAB_LIST, ATSPI_ROLE_PAGE_TAB_LIST },
331    { EFL_ACCESS_ROLE_PANEL, ATSPI_ROLE_PANEL },
332    { EFL_ACCESS_ROLE_PASSWORD_TEXT, ATSPI_ROLE_PASSWORD_TEXT },
333    { EFL_ACCESS_ROLE_POPUP_MENU, ATSPI_ROLE_POPUP_MENU },
334    { EFL_ACCESS_ROLE_PROGRESS_BAR, ATSPI_ROLE_PROGRESS_BAR },
335    { EFL_ACCESS_ROLE_PUSH_BUTTON, ATSPI_ROLE_PUSH_BUTTON },
336    { EFL_ACCESS_ROLE_RADIO_BUTTON, ATSPI_ROLE_RADIO_BUTTON },
337    { EFL_ACCESS_ROLE_RADIO_MENU_ITEM, ATSPI_ROLE_RADIO_MENU_ITEM },
338    { EFL_ACCESS_ROLE_ROOT_PANE, ATSPI_ROLE_ROOT_PANE },
339    { EFL_ACCESS_ROLE_ROW_HEADER, ATSPI_ROLE_ROW_HEADER },
340    { EFL_ACCESS_ROLE_SCROLL_BAR, ATSPI_ROLE_SCROLL_BAR },
341    { EFL_ACCESS_ROLE_SCROLL_PANE, ATSPI_ROLE_SCROLL_PANE },
342    { EFL_ACCESS_ROLE_SEPARATOR, ATSPI_ROLE_SEPARATOR },
343    { EFL_ACCESS_ROLE_SLIDER, ATSPI_ROLE_SLIDER },
344    { EFL_ACCESS_ROLE_SPIN_BUTTON, ATSPI_ROLE_SPIN_BUTTON },
345    { EFL_ACCESS_ROLE_SPLIT_PANE, ATSPI_ROLE_SPLIT_PANE },
346    { EFL_ACCESS_ROLE_STATUS_BAR, ATSPI_ROLE_STATUS_BAR },
347    { EFL_ACCESS_ROLE_TABLE, ATSPI_ROLE_TABLE },
348    { EFL_ACCESS_ROLE_TABLE_CELL, ATSPI_ROLE_TABLE_CELL },
349    { EFL_ACCESS_ROLE_TABLE_COLUMN_HEADER, ATSPI_ROLE_TABLE_COLUMN_HEADER },
350    { EFL_ACCESS_ROLE_TABLE_ROW_HEADER, ATSPI_ROLE_TABLE_ROW_HEADER },
351    { EFL_ACCESS_ROLE_TEAROFF_MENU_ITEM, ATSPI_ROLE_TEAROFF_MENU_ITEM },
352    { EFL_ACCESS_ROLE_TERMINAL, ATSPI_ROLE_TERMINAL },
353    { EFL_ACCESS_ROLE_TEXT, ATSPI_ROLE_TEXT },
354    { EFL_ACCESS_ROLE_TOGGLE_BUTTON, ATSPI_ROLE_TOGGLE_BUTTON },
355    { EFL_ACCESS_ROLE_TOOL_BAR, ATSPI_ROLE_TOOL_BAR },
356    { EFL_ACCESS_ROLE_TOOL_TIP, ATSPI_ROLE_TOOL_TIP },
357    { EFL_ACCESS_ROLE_TREE, ATSPI_ROLE_TREE },
358    { EFL_ACCESS_ROLE_TREE_TABLE, ATSPI_ROLE_TREE_TABLE },
359    { EFL_ACCESS_ROLE_UNKNOWN, ATSPI_ROLE_UNKNOWN },
360    { EFL_ACCESS_ROLE_VIEWPORT, ATSPI_ROLE_VIEWPORT },
361    { EFL_ACCESS_ROLE_WINDOW, ATSPI_ROLE_WINDOW },
362    { EFL_ACCESS_ROLE_EXTENDED, ATSPI_ROLE_EXTENDED },
363    { EFL_ACCESS_ROLE_HEADER, ATSPI_ROLE_HEADER },
364    { EFL_ACCESS_ROLE_FOOTER, ATSPI_ROLE_FOOTER },
365    { EFL_ACCESS_ROLE_PARAGRAPH, ATSPI_ROLE_PARAGRAPH },
366    { EFL_ACCESS_ROLE_RULER, ATSPI_ROLE_RULER },
367    { EFL_ACCESS_ROLE_APPLICATION, ATSPI_ROLE_APPLICATION },
368    { EFL_ACCESS_ROLE_AUTOCOMPLETE, ATSPI_ROLE_AUTOCOMPLETE },
369    { EFL_ACCESS_ROLE_EDITBAR, ATSPI_ROLE_EDITBAR },
370    { EFL_ACCESS_ROLE_EMBEDDED, ATSPI_ROLE_EMBEDDED },
371    { EFL_ACCESS_ROLE_ENTRY, ATSPI_ROLE_ENTRY },
372    { EFL_ACCESS_ROLE_CHART, ATSPI_ROLE_CHART },
373    { EFL_ACCESS_ROLE_CAPTION, ATSPI_ROLE_CAPTION },
374    { EFL_ACCESS_ROLE_DOCUMENT_FRAME, ATSPI_ROLE_DOCUMENT_FRAME },
375    { EFL_ACCESS_ROLE_HEADING, ATSPI_ROLE_HEADING },
376    { EFL_ACCESS_ROLE_PAGE, ATSPI_ROLE_PAGE },
377    { EFL_ACCESS_ROLE_SECTION, ATSPI_ROLE_SECTION },
378    { EFL_ACCESS_ROLE_REDUNDANT_OBJECT, ATSPI_ROLE_REDUNDANT_OBJECT },
379    { EFL_ACCESS_ROLE_FORM, ATSPI_ROLE_FORM },
380    { EFL_ACCESS_ROLE_LINK, ATSPI_ROLE_LINK },
381    { EFL_ACCESS_ROLE_INPUT_METHOD_WINDOW, ATSPI_ROLE_INPUT_METHOD_WINDOW },
382    { EFL_ACCESS_ROLE_TABLE_ROW, ATSPI_ROLE_TABLE_ROW },
383    { EFL_ACCESS_ROLE_TREE_ITEM, ATSPI_ROLE_TREE_ITEM },
384    { EFL_ACCESS_ROLE_DOCUMENT_SPREADSHEET, ATSPI_ROLE_DOCUMENT_SPREADSHEET },
385    { EFL_ACCESS_ROLE_DOCUMENT_PRESENTATION, ATSPI_ROLE_DOCUMENT_PRESENTATION },
386    { EFL_ACCESS_ROLE_DOCUMENT_TEXT, ATSPI_ROLE_DOCUMENT_TEXT },
387    { EFL_ACCESS_ROLE_DOCUMENT_WEB, ATSPI_ROLE_DOCUMENT_WEB },
388    { EFL_ACCESS_ROLE_DOCUMENT_EMAIL, ATSPI_ROLE_DOCUMENT_EMAIL },
389    { EFL_ACCESS_ROLE_COMMENT, ATSPI_ROLE_COMMENT },
390    { EFL_ACCESS_ROLE_LIST_BOX, ATSPI_ROLE_LIST_BOX },
391    { EFL_ACCESS_ROLE_GROUPING, ATSPI_ROLE_GROUPING },
392    { EFL_ACCESS_ROLE_IMAGE_MAP, ATSPI_ROLE_IMAGE_MAP },
393    { EFL_ACCESS_ROLE_NOTIFICATION, ATSPI_ROLE_NOTIFICATION },
394    { EFL_ACCESS_ROLE_INFO_BAR, ATSPI_ROLE_INFO_BAR },
395    { EFL_ACCESS_ROLE_LAST_DEFINED, ATSPI_ROLE_LAST_DEFINED },
396 };
397 
398 struct atspi_state_desc
399 {
400    Efl_Access_State_Type elm_state;
401    AtspiStateType atspi_state;
402    const char *name;
403 };
404 
405 static const struct atspi_state_desc elm_states_to_atspi_state[] = {
406    { EFL_ACCESS_STATE_TYPE_INVALID, ATSPI_STATE_INVALID, "invalid" },
407    { EFL_ACCESS_STATE_TYPE_ACTIVE, ATSPI_STATE_ACTIVE, "active" },
408    { EFL_ACCESS_STATE_TYPE_ARMED, ATSPI_STATE_ARMED, "armed" },
409    { EFL_ACCESS_STATE_TYPE_BUSY, ATSPI_STATE_BUSY, "busy" },
410    { EFL_ACCESS_STATE_TYPE_CHECKED, ATSPI_STATE_CHECKED, "checked" },
411    { EFL_ACCESS_STATE_TYPE_COLLAPSED, ATSPI_STATE_COLLAPSED, "collapsed" },
412    { EFL_ACCESS_STATE_TYPE_DEFUNCT, ATSPI_STATE_DEFUNCT, "defunct" },
413    { EFL_ACCESS_STATE_TYPE_EDITABLE, ATSPI_STATE_EDITABLE, "editable" },
414    { EFL_ACCESS_STATE_TYPE_ENABLED, ATSPI_STATE_ENABLED, "enabled" },
415    { EFL_ACCESS_STATE_TYPE_EXPANDABLE, ATSPI_STATE_EXPANDABLE, "expandable" },
416    { EFL_ACCESS_STATE_TYPE_EXPANDED, ATSPI_STATE_EXPANDED, "expanded" },
417    { EFL_ACCESS_STATE_TYPE_FOCUSABLE, ATSPI_STATE_FOCUSABLE, "focusable" },
418    { EFL_ACCESS_STATE_TYPE_FOCUSED, ATSPI_STATE_FOCUSED, "focused" },
419    { EFL_ACCESS_STATE_TYPE_HAS_TOOLTIP, ATSPI_STATE_HAS_TOOLTIP, "has-tooltip" },
420    { EFL_ACCESS_STATE_TYPE_HORIZONTAL, ATSPI_STATE_HORIZONTAL, "horizontal" },
421    { EFL_ACCESS_STATE_TYPE_MINIMIZED, ATSPI_STATE_ICONIFIED, "minimized" },
422    { EFL_ACCESS_STATE_TYPE_MODAL, ATSPI_STATE_MODAL, "modal" },
423    { EFL_ACCESS_STATE_TYPE_MULTI_LINE, ATSPI_STATE_MULTI_LINE, "multi-line" },
424    { EFL_ACCESS_STATE_TYPE_MULTISELECTABLE, ATSPI_STATE_MULTISELECTABLE, "multiselectable" },
425    { EFL_ACCESS_STATE_TYPE_OPAQUE, ATSPI_STATE_OPAQUE, "opaque" },
426    { EFL_ACCESS_STATE_TYPE_PRESSED, ATSPI_STATE_PRESSED, "pressed" },
427    { EFL_ACCESS_STATE_TYPE_RESIZABLE, ATSPI_STATE_RESIZABLE, "resizable" },
428    { EFL_ACCESS_STATE_TYPE_SELECTABLE, ATSPI_STATE_SELECTABLE, "selectable" },
429    { EFL_ACCESS_STATE_TYPE_SELECTED, ATSPI_STATE_SELECTED, "selected" },
430    { EFL_ACCESS_STATE_TYPE_SENSITIVE, ATSPI_STATE_SENSITIVE, "sensitive" },
431    { EFL_ACCESS_STATE_TYPE_SHOWING, ATSPI_STATE_SHOWING, "showing" },
432    { EFL_ACCESS_STATE_TYPE_SINGLE_LINE, ATSPI_STATE_SINGLE_LINE, "single-line" },
433    { EFL_ACCESS_STATE_TYPE_STALE, ATSPI_STATE_STALE, "stale" },
434    { EFL_ACCESS_STATE_TYPE_TRANSIENT, ATSPI_STATE_TRANSIENT, "transient" },
435    { EFL_ACCESS_STATE_TYPE_VERTICAL, ATSPI_STATE_VERTICAL, "vertical" },
436    { EFL_ACCESS_STATE_TYPE_VISIBLE, ATSPI_STATE_VISIBLE, "visible" },
437    { EFL_ACCESS_STATE_TYPE_MANAGES_DESCENDANTS, ATSPI_STATE_MANAGES_DESCENDANTS, "manages-descendants" },
438    { EFL_ACCESS_STATE_TYPE_INDETERMINATE, ATSPI_STATE_INDETERMINATE, "indeterminate" },
439    { EFL_ACCESS_STATE_TYPE_REQUIRED, ATSPI_STATE_REQUIRED, "required" },
440    { EFL_ACCESS_STATE_TYPE_TRUNCATED, ATSPI_STATE_TRUNCATED, "truncated" },
441    { EFL_ACCESS_STATE_TYPE_ANIMATED, ATSPI_STATE_ANIMATED, "animated" },
442    { EFL_ACCESS_STATE_TYPE_INVALID_ENTRY, ATSPI_STATE_INVALID_ENTRY, "invalid-entry" },
443    { EFL_ACCESS_STATE_TYPE_SUPPORTS_AUTOCOMPLETION, ATSPI_STATE_SUPPORTS_AUTOCOMPLETION, "supports-autocompletion" },
444    { EFL_ACCESS_STATE_TYPE_SELECTABLE_TEXT, ATSPI_STATE_SELECTABLE_TEXT, "selectable-text" },
445    { EFL_ACCESS_STATE_TYPE_IS_DEFAULT, ATSPI_STATE_IS_DEFAULT, "is-default" },
446    { EFL_ACCESS_STATE_TYPE_VISITED, ATSPI_STATE_VISITED, "visited" },
447    { EFL_ACCESS_STATE_TYPE_LAST_DEFINED, ATSPI_STATE_LAST_DEFINED, "last-defined" },
448 };
449 
450 static const int elm_relation_to_atspi_relation_mapping[] = {
451    [EFL_ACCESS_RELATION_TYPE_NULL] =  ATSPI_RELATION_NULL,
452    [EFL_ACCESS_RELATION_TYPE_LABEL_FOR] =  ATSPI_RELATION_LABEL_FOR,
453    [EFL_ACCESS_RELATION_TYPE_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY,
454    [EFL_ACCESS_RELATION_TYPE_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR,
455    [EFL_ACCESS_RELATION_TYPE_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY,
456    [EFL_ACCESS_RELATION_TYPE_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF,
457    [EFL_ACCESS_RELATION_TYPE_TOOLTIP_FOR] = ATSPI_RELATION_TOOLTIP_FOR,
458    [EFL_ACCESS_RELATION_TYPE_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF,
459    [EFL_ACCESS_RELATION_TYPE_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF,
460    [EFL_ACCESS_RELATION_TYPE_EXTENDED] = ATSPI_RELATION_EXTENDED,
461    [EFL_ACCESS_RELATION_TYPE_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO,
462    [EFL_ACCESS_RELATION_TYPE_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM,
463    [EFL_ACCESS_RELATION_TYPE_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF,
464    [EFL_ACCESS_RELATION_TYPE_EMBEDS] = ATSPI_RELATION_EMBEDS,
465    [EFL_ACCESS_RELATION_TYPE_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY,
466    [EFL_ACCESS_RELATION_TYPE_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR,
467    [EFL_ACCESS_RELATION_TYPE_PARENT_WINDOW_OF] = ATSPI_RELATION_PARENT_WINDOW_OF,
468    [EFL_ACCESS_RELATION_TYPE_DESCRIPTION_FOR] = ATSPI_RELATION_DESCRIPTION_FOR,
469    [EFL_ACCESS_RELATION_TYPE_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY,
470    [EFL_ACCESS_RELATION_TYPE_LAST_DEFINED] = ATSPI_RELATION_LAST_DEFINED,
471 };
472 
_dbus_invalid_ref_error_new(const Eldbus_Message * msg)473 static inline Eldbus_Message *_dbus_invalid_ref_error_new(const Eldbus_Message *msg)
474 {
475   return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.UnknownObject", "Path is not valid accessible object reference.");
476 }
477 
_elm_relation_to_atspi_relation(Efl_Access_Relation_Type type)478 static AtspiRelationType _elm_relation_to_atspi_relation(Efl_Access_Relation_Type type)
479 {
480    if ((type < EFL_ACCESS_RELATION_TYPE_LAST_DEFINED) && (type > EFL_ACCESS_RELATION_TYPE_NULL))
481      return elm_relation_to_atspi_relation_mapping[type];
482    return ATSPI_RELATION_NULL;
483 }
484 
485 static Eldbus_Message *
_accessible_get_role(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)486 _accessible_get_role(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
487 {
488    const char *obj_path = eldbus_message_path_get(msg);
489    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
490    Eo *obj = _bridge_object_from_path(bridge, obj_path);
491    AtspiRole atspi_role = ATSPI_ROLE_INVALID;
492    Efl_Access_Role role;
493 
494    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
495 
496    role = efl_access_object_role_get(obj);
497 
498    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
499    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
500 
501    atspi_role = role > EFL_ACCESS_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
502    eldbus_message_arguments_append(ret, "u", atspi_role);
503    return ret;
504 }
505 
506 static Eldbus_Message *
_accessible_get_role_name(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)507 _accessible_get_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
508 {
509    const char *role_name = NULL, *obj_path = eldbus_message_path_get(msg);
510    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
511    Eo *obj = _bridge_object_from_path(bridge, obj_path);
512 
513    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
514 
515    role_name = efl_access_object_role_name_get(obj);
516 
517    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
518    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
519    eldbus_message_arguments_append(ret, "s", role_name);
520 
521    return ret;
522 }
523 
524 static Eldbus_Message *
_accessible_get_localized_role_name(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)525 _accessible_get_localized_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
526 {
527    const char *l_role_name = NULL, *obj_path = eldbus_message_path_get(msg);
528    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
529    Eo *obj = _bridge_object_from_path(bridge, obj_path);
530 
531    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
532 
533    l_role_name = efl_access_object_localized_role_name_get(obj);
534    EINA_SAFETY_ON_NULL_RETURN_VAL(l_role_name, NULL);
535 
536    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
537    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
538    eldbus_message_arguments_append(ret, "s", l_role_name);
539 
540    return ret;
541 }
542 
543 static Eldbus_Message *
_accessible_get_children(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)544 _accessible_get_children(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
545 {
546    const char *obj_path = eldbus_message_path_get(msg);
547    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
548    Eo *obj = _bridge_object_from_path(bridge, obj_path);
549    Eina_List *children_list = NULL, *l;
550    Eldbus_Message *ret;
551    Eldbus_Message_Iter *iter, *iter_array;
552    Eo *children;
553 
554    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
555 
556    children_list = efl_access_object_access_children_get(obj);
557 
558    ret = eldbus_message_method_return_new(msg);
559    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
560 
561    iter = eldbus_message_iter_get(ret);
562    iter_array = eldbus_message_iter_container_new(iter, 'a', "(so)");
563    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
564 
565    EINA_LIST_FOREACH(children_list, l, children)
566      {
567         _bridge_iter_object_reference_append(bridge, iter_array, children);
568         _bridge_object_register(bridge, children);
569      }
570 
571    eldbus_message_iter_container_close(iter, iter_array);
572    eina_list_free(children_list);
573 
574    return ret;
575 
576 fail:
577    if (ret) eldbus_message_unref(ret);
578    return NULL;
579 }
580 
581 static Eldbus_Message *
_accessible_get_application(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)582 _accessible_get_application(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
583 {
584    Eldbus_Message *ret;
585    const char *obj_path = eldbus_message_path_get(msg);
586    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
587    Eo *root, *obj = _bridge_object_from_path(bridge, obj_path);
588 
589    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
590 
591    ret = eldbus_message_method_return_new(msg);
592    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
593 
594    Eldbus_Message_Iter *iter = eldbus_message_iter_get(ret);
595    root = efl_access_object_access_root_get();
596    _bridge_iter_object_reference_append(bridge, iter, root);
597 
598    return ret;
599 }
600 
601 static Eldbus_Message *
_accessible_attributes_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)602 _accessible_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
603 {
604    Eina_List *attrs = NULL, *l;
605    Efl_Access_Attribute *attr;
606    Eldbus_Message_Iter *iter, *iter_dict = NULL, *iter_entry;
607    Eldbus_Message *ret;
608 
609    const char *obj_path = eldbus_message_path_get(msg);
610    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
611    Eo *obj = _bridge_object_from_path(bridge, obj_path);
612 
613    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
614 
615    ret = eldbus_message_method_return_new(msg);
616    if (!ret) goto error;
617 
618    attrs = efl_access_object_attributes_get(obj);
619 
620    iter = eldbus_message_iter_get(ret);
621    if (!iter) goto error;
622 
623    iter_dict = eldbus_message_iter_container_new(iter, 'a', "{ss}");
624    if (!iter_dict) goto error;
625 
626 
627    EINA_LIST_FOREACH(attrs, l, attr)
628      {
629         iter_entry = eldbus_message_iter_container_new(iter_dict, 'e', NULL);
630         if (!iter_entry) goto error;
631         eldbus_message_iter_arguments_append(iter_entry, "ss", attr->key, attr->value);
632         eldbus_message_iter_container_close(iter_dict, iter_entry);
633      }
634 
635    eldbus_message_iter_container_close(iter, iter_dict);
636    efl_access_attributes_list_free(attrs);
637    return ret;
638 
639 error:
640    if (iter_dict) eldbus_message_iter_container_close(iter, iter_dict);
641    if (ret) eldbus_message_unref(ret);
642    efl_access_attributes_list_free(attrs);
643    return NULL;
644 }
645 
646 static Eldbus_Message *
_accessible_interfaces_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)647 _accessible_interfaces_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
648 {
649    Eldbus_Message *ret;
650    Eldbus_Message_Iter *iter;
651    const char *obj_path = eldbus_message_path_get(msg);
652    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
653    Eo *obj = _bridge_object_from_path(bridge, obj_path);
654 
655    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
656 
657    ret = eldbus_message_method_return_new(msg);
658    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
659 
660    iter = eldbus_message_iter_get(ret);
661    _iter_interfaces_append(iter, obj);
662 
663    return ret;
664 }
665 
666 static uint64_t
_elm_atspi_state_set_to_atspi_state_set(Efl_Access_State_Set states)667 _elm_atspi_state_set_to_atspi_state_set(Efl_Access_State_Set states)
668 {
669    uint64_t ret = 0;
670    unsigned int i = 0;
671 
672    for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
673      {
674         if (STATE_TYPE_GET(states, elm_states_to_atspi_state[i].elm_state))
675           STATE_TYPE_SET(ret, elm_states_to_atspi_state[i].atspi_state);
676      }
677    return ret;
678 }
679 
680 static Efl_Access_State_Set
_atspi_state_set_to_elm_atspi_state_set(uint64_t states)681 _atspi_state_set_to_elm_atspi_state_set(uint64_t states)
682 {
683    //Currently Elm_Atspi_State and Atspi_State_Set are binary compatible,
684    //implement proper coversion when it will be needed.
685    Efl_Access_State_Set ret = states;
686    return ret;
687 }
688 
689 static Eina_Hash*
_elm_atspi_state_hash_build(void)690 _elm_atspi_state_hash_build(void)
691 {
692    Eina_Hash *ret = eina_hash_string_superfast_new(NULL);
693    unsigned int i = 0;
694 
695    for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
696      eina_hash_add(ret, elm_states_to_atspi_state[i].name, &elm_states_to_atspi_state[i]);
697 
698    return ret;
699 }
700 
701 static Eina_Hash*
_elm_atspi_event_hash_build(void)702 _elm_atspi_event_hash_build(void)
703 {
704    Eina_Hash *ret = eina_hash_pointer_new(NULL);
705    unsigned int i = 0;
706 
707    for (i = 0; i < SIZE(event_handlers); i++)
708      eina_hash_add(ret, &(event_handlers[i].desc), event_handlers[i].callback);
709 
710    return ret;
711 }
712 
713 static Eldbus_Message *
_accessible_get_state(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)714 _accessible_get_state(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
715 {
716    Eldbus_Message *ret;
717    Eldbus_Message_Iter *iter, *iter_array;
718    Efl_Access_State_Set states;
719    uint64_t atspi_states = 0;
720 
721    const char *obj_path = eldbus_message_path_get(msg);
722    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
723    Eo *obj = _bridge_object_from_path(bridge, obj_path);
724 
725    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
726 
727    ret = eldbus_message_method_return_new(msg);
728    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
729 
730    iter = eldbus_message_iter_get(ret);
731    iter_array = eldbus_message_iter_container_new(iter, 'a', "u");
732    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
733 
734    states = efl_access_object_state_set_get(obj);
735 
736    atspi_states = _elm_atspi_state_set_to_atspi_state_set(states);
737 
738    unsigned int s1 = atspi_states & 0xFFFFFFFF;
739    unsigned int s2 = (atspi_states >> 32) & 0xFFFFFFFF;
740 
741    eldbus_message_iter_basic_append(iter_array, 'u', s1);
742    eldbus_message_iter_basic_append(iter_array, 'u', s2);
743    eldbus_message_iter_container_close(iter, iter_array);
744 
745    return ret;
746 
747 fail:
748    if (ret) eldbus_message_unref(ret);
749    return NULL;
750 }
751 
752 static Eldbus_Message *
_accessible_get_index_in_parent(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)753 _accessible_get_index_in_parent(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
754 {
755    const char *obj_path = eldbus_message_path_get(msg);
756    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
757    Eo *obj = _bridge_object_from_path(bridge, obj_path);
758    Eldbus_Message *ret;
759    int idx = -1;
760 
761    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
762 
763    ret = eldbus_message_method_return_new(msg);
764    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
765 
766    idx = efl_access_object_index_in_parent_get(obj);
767 
768    eldbus_message_arguments_append(ret, "i", idx);
769 
770    return ret;
771 }
772 
773 static Eldbus_Message *
_accessible_child_at_index(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)774 _accessible_child_at_index(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
775 {
776    const char *obj_path = eldbus_message_path_get(msg);
777    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
778    Eo *obj = _bridge_object_from_path(bridge, obj_path);
779    Eo *child = NULL;
780    Eina_List *children = NULL;
781    int idx;
782    Eldbus_Message *ret;
783    Eldbus_Message_Iter *iter;
784 
785    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
786 
787    if (!eldbus_message_arguments_get(msg, "i", &idx))
788      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
789 
790    ret = eldbus_message_method_return_new(msg);
791    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
792 
793    iter = eldbus_message_iter_get(ret);
794    children = efl_access_object_access_children_get(obj);
795 
796    child = eina_list_nth(children, idx);
797    _bridge_iter_object_reference_append(bridge, iter, child);
798    _bridge_object_register(bridge, child);
799    eina_list_free(children);
800 
801    return ret;
802 }
803 
804 static Eldbus_Message *
_accessible_get_relation_set(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)805 _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
806 {
807    const char *obj_path = eldbus_message_path_get(msg);
808    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
809    Eo *rel_obj, *obj = _bridge_object_from_path(bridge, obj_path);
810    Eldbus_Message *ret = NULL;
811    Eldbus_Message_Iter *iter = NULL, *iter_array = NULL, *iter_array2 = NULL, *iter_struct;
812    const Efl_Access_Relation *rel;
813    Eina_List *l;
814    Eina_Iterator *it;
815 
816    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
817 
818    ret = eldbus_message_method_return_new(msg);
819    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
820 
821    iter = eldbus_message_iter_get(ret);
822    iter_array = eldbus_message_iter_container_new(iter, 'a', "(ua(so))");
823    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
824 
825    it = efl_access_object_relations_get(obj);
826    EINA_ITERATOR_FOREACH(it, rel)
827      {
828         iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
829         eldbus_message_iter_basic_append(iter_struct, 'u', _elm_relation_to_atspi_relation(rel->type));
830         iter_array2 = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
831         EINA_SAFETY_ON_NULL_GOTO(iter_array2, fail);
832         EINA_LIST_FOREACH(rel->objects, l, rel_obj)
833           {
834              _bridge_iter_object_reference_append(bridge, iter_array2, rel_obj);
835              _bridge_object_register(bridge, rel_obj);
836           }
837         eldbus_message_iter_container_close(iter_struct, iter_array2);
838         eldbus_message_iter_container_close(iter_array, iter_struct);
839      }
840    eina_iterator_free(it);
841    eldbus_message_iter_container_close(iter, iter_array);
842 
843    return ret;
844 
845 fail:
846    eldbus_message_unref(ret);
847    return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get relation set.");
848 }
849 
850 static const Eldbus_Method accessible_methods[] = {
851    { "GetChildAtIndex", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"(so)", "Accessible"}), _accessible_child_at_index, 0 },
852    { "GetChildren", NULL, ELDBUS_ARGS({"a(so)", "children"}), _accessible_get_children, 0 },
853    { "GetIndexInParent", NULL, ELDBUS_ARGS({"i", "index"}), _accessible_get_index_in_parent, 0 },
854    { "GetRelationSet", NULL, ELDBUS_ARGS({"a(ua(so))", NULL}), _accessible_get_relation_set, 0 },
855    { "GetRole", NULL, ELDBUS_ARGS({"u", "Role"}), _accessible_get_role, 0 },
856    { "GetRoleName", NULL, ELDBUS_ARGS({"s", "Name"}), _accessible_get_role_name, 0 },
857    { "GetLocalizedRoleName", NULL, ELDBUS_ARGS({"s", "LocalizedName"}), _accessible_get_localized_role_name, 0},
858    { "GetState", NULL, ELDBUS_ARGS({"au", NULL}), _accessible_get_state, 0},
859    { "GetApplication", NULL, ELDBUS_ARGS({"(so)", NULL}), _accessible_get_application, 0},
860    { "GetAttributes", NULL, ELDBUS_ARGS({"a{ss}", NULL}), _accessible_attributes_get, 0},
861    { "GetInterfaces", NULL, ELDBUS_ARGS({"as", NULL}), _accessible_interfaces_get, 0},
862    { NULL, NULL, NULL, NULL, 0 }
863 };
864 
865 static Eldbus_Message *
_selection_selected_child_get(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)866 _selection_selected_child_get(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
867 {
868    const char *obj_path = eldbus_message_path_get(msg);
869    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
870    Eo *obj = _bridge_object_from_path(bridge, obj_path);
871    Eo *child = NULL;
872 
873    int idx;
874    Eldbus_Message *ret;
875    Eldbus_Message_Iter *iter;
876 
877    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
878 
879    if (!eldbus_message_arguments_get(msg, "i", &idx))
880      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
881 
882    ret = eldbus_message_method_return_new(msg);
883    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
884 
885    iter = eldbus_message_iter_get(ret);
886    child = efl_access_selection_selected_child_get(obj, idx);
887 
888    _bridge_iter_object_reference_append(bridge, iter, child);
889    _bridge_object_register(bridge, child);
890 
891    return ret;
892 }
893 
894 static Eldbus_Message *
_selection_child_select(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)895 _selection_child_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
896 {
897    const char *obj_path = eldbus_message_path_get(msg);
898    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
899    Eo *obj = _bridge_object_from_path(bridge, obj_path);
900    int idx;
901    Eldbus_Message *ret;
902    Eina_Bool result;
903 
904    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
905 
906    if (!eldbus_message_arguments_get(msg, "i", &idx))
907      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
908 
909    ret = eldbus_message_method_return_new(msg);
910    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
911 
912    result = efl_access_selection_child_select(obj, idx);
913    eldbus_message_arguments_append(ret, "b", result);
914 
915    return ret;
916 }
917 
918 static Eldbus_Message *
_selection_selected_child_deselect(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)919 _selection_selected_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
920 {
921    const char *obj_path = eldbus_message_path_get(msg);
922    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
923    Eo *obj = _bridge_object_from_path(bridge, obj_path);
924    int idx;
925    Eldbus_Message *ret;
926    Eina_Bool result;
927 
928    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
929 
930    if (!eldbus_message_arguments_get(msg, "i", &idx))
931      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
932 
933    ret = eldbus_message_method_return_new(msg);
934    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
935 
936    result = efl_access_selection_selected_child_deselect(obj, idx);
937    eldbus_message_arguments_append(ret, "b", result);
938 
939    return ret;
940 }
941 
942 static Eldbus_Message *
_selection_is_child_selected(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)943 _selection_is_child_selected(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
944 {
945    const char *obj_path = eldbus_message_path_get(msg);
946    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
947    Eo *obj = _bridge_object_from_path(bridge, obj_path);
948    int idx;
949    Eldbus_Message *ret;
950    Eina_Bool result;
951 
952    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
953 
954    if (!eldbus_message_arguments_get(msg, "i", &idx))
955      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
956 
957    ret = eldbus_message_method_return_new(msg);
958    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
959 
960    result = efl_access_selection_is_child_selected(obj, idx);
961    eldbus_message_arguments_append(ret, "b", result);
962 
963    return ret;
964 }
965 
966 static Eldbus_Message *
_selection_all_children_select(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)967 _selection_all_children_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
968 {
969    const char *obj_path = eldbus_message_path_get(msg);
970    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
971    Eo *obj = _bridge_object_from_path(bridge, obj_path);
972    Eldbus_Message *ret;
973    Eina_Bool result;
974 
975    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
976 
977    ret = eldbus_message_method_return_new(msg);
978    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
979 
980    result = efl_access_selection_all_children_select(obj);
981    eldbus_message_arguments_append(ret, "b", result);
982 
983    return ret;
984 }
985 
986 static Eldbus_Message *
_selection_clear(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)987 _selection_clear(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
988 {
989    const char *obj_path = eldbus_message_path_get(msg);
990    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
991    Eo *obj = _bridge_object_from_path(bridge, obj_path);
992    Eldbus_Message *ret;
993    Eina_Bool result;
994 
995    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
996 
997    ret = eldbus_message_method_return_new(msg);
998    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
999 
1000    result = efl_access_selection_clear(obj);
1001    eldbus_message_arguments_append(ret, "b", result);
1002 
1003    return ret;
1004 }
1005 
1006 static Eldbus_Message *
_selection_child_deselect(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1007 _selection_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1008 {
1009    const char *obj_path = eldbus_message_path_get(msg);
1010    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1011    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1012    int idx;
1013    Eldbus_Message *ret;
1014    Eina_Bool result;
1015 
1016    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
1017 
1018    if (!eldbus_message_arguments_get(msg, "i", &idx))
1019      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1020 
1021    ret = eldbus_message_method_return_new(msg);
1022    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1023 
1024    result = efl_access_selection_child_deselect(obj, idx);
1025    eldbus_message_arguments_append(ret, "b", result);
1026 
1027    return ret;
1028 }
1029 
1030 static const Eldbus_Method selection_methods[] = {
1031    { "GetSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"(so)", "Accessible"}), _selection_selected_child_get, 0 },
1032    { "SelectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_select, 0 },
1033    { "DeselectSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_selected_child_deselect, 0 },
1034    { "IsChildSelected", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_is_child_selected, 0 },
1035    { "SelectAll", NULL, ELDBUS_ARGS({"b", "result"}), _selection_all_children_select, 0},
1036    { "ClearSelection", NULL, ELDBUS_ARGS({"b", "result"}), _selection_clear, 0},
1037    { "DeselectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_deselect, 0 },
1038    { NULL, NULL, NULL, NULL, 0 }
1039 };
1040 
1041 static Eldbus_Message *
_action_description_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1042 _action_description_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1043 {
1044    const char *description, *obj_path = eldbus_message_path_get(msg);
1045    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1046    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1047    int idx;
1048    Eldbus_Message *ret;
1049 
1050    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1051 
1052    if (!eldbus_message_arguments_get(msg, "i", &idx))
1053      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1054 
1055    ret = eldbus_message_method_return_new(msg);
1056    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1057 
1058    description = efl_access_action_description_get(obj, idx);
1059    description = description ? description : "";
1060    eldbus_message_arguments_append(ret, "s", description);
1061 
1062    return ret;
1063 }
1064 
1065 static Eldbus_Message *
_action_name_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1066 _action_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1067 {
1068    const char *name, *obj_path = eldbus_message_path_get(msg);
1069    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1070    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1071    int idx;
1072    Eldbus_Message *ret;
1073 
1074    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1075 
1076    if (!eldbus_message_arguments_get(msg, "i", &idx))
1077      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1078 
1079    ret = eldbus_message_method_return_new(msg);
1080    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1081 
1082    name = efl_access_action_name_get(obj, idx);
1083    name = name ? name : "";
1084    eldbus_message_arguments_append(ret, "s", name);
1085 
1086    return ret;
1087 }
1088 
1089 static Eldbus_Message *
_action_localized_name_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1090 _action_localized_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1091 {
1092    const char *name, *obj_path = eldbus_message_path_get(msg);
1093    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1094    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1095    int idx;
1096    Eldbus_Message *ret;
1097 
1098    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1099 
1100    if (!eldbus_message_arguments_get(msg, "i", &idx))
1101      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1102 
1103    ret = eldbus_message_method_return_new(msg);
1104    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1105 
1106    name = efl_access_action_localized_name_get(obj, idx);
1107    name = name ? name : "";
1108    eldbus_message_arguments_append(ret, "s", name);
1109 
1110    return ret;
1111 }
1112 
1113 static Eldbus_Message *
_action_key_binding_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1114 _action_key_binding_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1115 {
1116    const char *obj_path = eldbus_message_path_get(msg);
1117    char *key;
1118    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1119    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1120    int idx;
1121    Eldbus_Message *ret;
1122 
1123    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1124 
1125    if (!eldbus_message_arguments_get(msg, "i", &idx))
1126      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1127 
1128    ret = eldbus_message_method_return_new(msg);
1129    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1130 
1131    key = efl_access_action_keybinding_get(obj, idx);
1132    eldbus_message_arguments_append(ret, "s", key ? key : "");
1133    if (key) free(key);
1134 
1135    return ret;
1136 }
1137 
1138 static Eldbus_Message *
_action_actions_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1139 _action_actions_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1140 {
1141    const char *action, *obj_path = eldbus_message_path_get(msg);
1142    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1143    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1144    Eina_List *actions;
1145    Eldbus_Message *ret;
1146    Eldbus_Message_Iter *iter, *iter_array = NULL;
1147 
1148    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1149 
1150    ret = eldbus_message_method_return_new(msg);
1151    if (!ret) goto error;
1152 
1153    iter = eldbus_message_iter_get(ret);
1154    if (!iter) goto error;
1155 
1156    iter_array = eldbus_message_iter_container_new(iter, 'a', "sss");
1157    if (!iter_array) goto error;
1158 
1159    actions = efl_access_action_actions_get(obj);
1160 
1161    int id = 0;
1162    EINA_LIST_FREE(actions, action)
1163      {
1164         const char *descr;
1165         char *key;
1166 
1167         key = efl_access_action_keybinding_get(obj, id);
1168         descr = efl_access_action_description_get(obj, id);
1169         descr = descr ? descr : "";
1170         eldbus_message_iter_arguments_append(iter_array, "sss", action, descr, key ? key : "");
1171         if (key) free(key);
1172         id++;
1173      }
1174    eldbus_message_iter_container_close(iter, iter_array);
1175    return ret;
1176 
1177 error:
1178    if (ret) eldbus_message_unref(ret);
1179    return NULL;
1180 }
1181 
1182 static Eldbus_Message *
_action_action_do(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1183 _action_action_do(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1184 {
1185    const char *obj_path = eldbus_message_path_get(msg);
1186    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1187    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1188    int idx;
1189    Eldbus_Message *ret;
1190    Eina_Bool result;
1191 
1192    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
1193 
1194    if (!eldbus_message_arguments_get(msg, "i", &idx))
1195      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1196 
1197    ret = eldbus_message_method_return_new(msg);
1198    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1199 
1200    result = efl_access_action_do(obj, idx);
1201    eldbus_message_arguments_append(ret, "b", result);
1202 
1203    return ret;
1204 }
1205 
1206 static const Eldbus_Method action_methods[] = {
1207    { "GetDescription", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "description"}), _action_description_get, 0 },
1208    { "GetName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_name_get, 0 },
1209    { "GetLocalizedName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_localized_name_get, 0 },
1210    { "GetKeyBinding", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "key"}), _action_key_binding_get, 0 },
1211    { "GetActions", NULL, ELDBUS_ARGS({"a(sss)", "actions"}), _action_actions_get, 0 },
1212    { "DoAction", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"b", "result"}), _action_action_do, 0 },
1213    { NULL, NULL, NULL, NULL, 0 }
1214 };
1215 
1216 static Eldbus_Message *
_image_extents_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1217 _image_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1218 {
1219    AtspiCoordType type;
1220    Eldbus_Message *ret;
1221    const char *obj_path = eldbus_message_path_get(msg);
1222    Eina_Bool screen_coords;
1223    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1224    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1225    Eina_Rect r;
1226 
1227    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
1228 
1229    if (!eldbus_message_arguments_get(msg, "u", &type))
1230      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1231 
1232    ret = eldbus_message_method_return_new(msg);
1233    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1234 
1235    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1236    r = efl_access_component_extents_get(obj, screen_coords);
1237    eldbus_message_arguments_append(ret, "iiii", r.x, r.y, r.w, r.h);
1238 
1239    return ret;
1240 }
1241 
1242 static Eldbus_Message *
_image_position_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1243 _image_position_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1244 {
1245    AtspiCoordType type;
1246    Eldbus_Message *ret;
1247    const char *obj_path = eldbus_message_path_get(msg);
1248    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1249    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1250    int x = -1, y = -1;
1251    Eina_Bool screen_coords;
1252 
1253    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
1254 
1255    if (!eldbus_message_arguments_get(msg, "u", &type))
1256      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
1257 
1258    ret = eldbus_message_method_return_new(msg);
1259    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1260 
1261    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1262    if (screen_coords)
1263      efl_access_component_screen_position_get(obj, &x, &y);
1264    else
1265      evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1266    eldbus_message_arguments_append(ret, "i", x);
1267    eldbus_message_arguments_append(ret, "i", y);
1268 
1269    return ret;
1270 }
1271 
1272 static Eldbus_Message *
_image_size_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1273 _image_size_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1274 {
1275    Eldbus_Message *ret;
1276    const char *obj_path = eldbus_message_path_get(msg);
1277    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1278    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1279    int w = -1, h = -1;
1280 
1281    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
1282 
1283    ret = eldbus_message_method_return_new(msg);
1284    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1285 
1286    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1287    eldbus_message_arguments_append(ret, "i", w);
1288    eldbus_message_arguments_append(ret, "i", h);
1289 
1290    return ret;
1291 }
1292 
1293 static const Eldbus_Method image_methods[] = {
1294    { "GetImageExtents", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"iiii", "extents"}), _image_extents_get, 0 },
1295    { "GetImagePosition", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}), _image_position_get, 0 },
1296    { "GetImageSize", NULL, ELDBUS_ARGS({"i", "width"}, {"i", "height"}), _image_size_get, 0 },
1297    { NULL, NULL, NULL, NULL, 0 }
1298 };
1299 
1300 static Eldbus_Message *
_text_string_at_offset_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1301 _text_string_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1302 {
1303    const char *obj_path = eldbus_message_path_get(msg);
1304    char *str;
1305    Efl_Access_Text_Granularity gran;
1306    int start = 0, end = 0;
1307    Eldbus_Message *ret;
1308    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1309    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1310 
1311    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1312 
1313    if (!eldbus_message_arguments_get(msg, "iu", &start, &gran))
1314      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and granularity expected.");
1315 
1316    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1317      {
1318         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
1319         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
1320         efl_text_cursor_object_position_set(sel1, start);
1321         efl_text_cursor_object_position_set(sel2, start);
1322 
1323         switch(gran)
1324           {
1325            case EFL_ACCESS_TEXT_GRANULARITY_CHAR:
1326              efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
1327              break;
1328 
1329            case EFL_ACCESS_TEXT_GRANULARITY_WORD:
1330              efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
1331              efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
1332              break;
1333 
1334            case EFL_ACCESS_TEXT_GRANULARITY_LINE:
1335              efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START);
1336              efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
1337              break;
1338 
1339            case EFL_ACCESS_TEXT_GRANULARITY_PARAGRAPH:
1340              efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_START);
1341              efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_END);
1342              break;
1343 
1344            case EFL_ACCESS_TEXT_GRANULARITY_SENTENCE: /* this one is not supported by efl */
1345            default:
1346              efl_del(sel1);
1347              efl_del(sel2);
1348              return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Granularity not suported.");
1349           }
1350 
1351         str = efl_text_cursor_object_range_text_get(sel1, sel2);
1352         start = efl_text_cursor_object_position_get(sel1);
1353         end = efl_text_cursor_object_position_get(sel2);
1354 
1355         efl_del(sel1);
1356         efl_del(sel2);
1357      }
1358    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1359      {
1360         efl_access_text_string_get(obj, gran, &start, &end, &str);
1361      }
1362    else
1363      {
1364         return _dbus_invalid_ref_error_new(msg);
1365      }
1366 
1367    str = str ? str : strdup("");
1368 
1369    ret = eldbus_message_method_return_new(msg);
1370    EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
1371 
1372    eldbus_message_arguments_append(ret, "sii", str, start, end);
1373 
1374 cleanup:
1375    free(str);
1376    return ret;
1377 }
1378 
1379 static Eldbus_Message *
_text_text_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1380 _text_text_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1381 {
1382    const char *obj_path = eldbus_message_path_get(msg);
1383    char *str;
1384    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1385    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1386    int start, end;
1387 
1388    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1389 
1390    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
1391      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end offset expected.");
1392 
1393    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1394      {
1395         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
1396         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
1397         efl_text_cursor_object_position_set(sel1, start);
1398         efl_text_cursor_object_position_set(sel2, end);
1399         str = efl_text_cursor_object_range_text_get(sel1, sel2);
1400         efl_del(sel1);
1401         efl_del(sel2);
1402      }
1403    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1404      {
1405         str = efl_access_text_get(obj, start, end);
1406      }
1407    else
1408      {
1409         return _dbus_invalid_ref_error_new(msg);
1410      }
1411 
1412    str = str ? str : strdup("");
1413 
1414    Eldbus_Message *ret = eldbus_message_method_return_new(msg);
1415    EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
1416 
1417    eldbus_message_arguments_append(ret, "s", str);
1418 
1419 cleanup:
1420    free(str);
1421    return ret;
1422 }
1423 
1424 static Eldbus_Message *
_text_caret_offset_set(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1425 _text_caret_offset_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1426 {
1427    const char *obj_path = eldbus_message_path_get(msg);
1428    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1429    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1430    int offset;
1431    Eldbus_Message *ret;
1432    Eina_Bool res;
1433 
1434    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1435 
1436    if (!eldbus_message_arguments_get(msg, "i", &offset))
1437      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
1438 
1439    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1440      {
1441         Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
1442         efl_text_cursor_object_position_set(cur, offset);
1443         res = EINA_TRUE;
1444      }
1445    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1446      {
1447         res = efl_access_text_caret_offset_set(obj, offset);
1448      }
1449    else
1450      {
1451         return _dbus_invalid_ref_error_new(msg);
1452      }
1453 
1454    ret = eldbus_message_method_return_new(msg);
1455    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1456 
1457    eldbus_message_arguments_append(ret, "b", res);
1458 
1459    return ret;
1460 }
1461 
1462 static Eldbus_Message *
_text_character_at_offset_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1463 _text_character_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1464 {
1465    const char *obj_path = eldbus_message_path_get(msg);
1466    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1467    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1468    int offset;
1469    Eldbus_Message *ret;
1470    Eina_Unicode res;
1471 
1472    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1473 
1474    if (!eldbus_message_arguments_get(msg, "i", &offset))
1475      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
1476 
1477    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1478      {
1479         Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
1480         efl_text_cursor_object_position_set(cur, offset);
1481         res = efl_text_cursor_object_content_get(cur);
1482         efl_del(cur);
1483      }
1484    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1485      {
1486         res = efl_access_text_character_get(obj, offset);
1487      }
1488    else
1489      {
1490         return _dbus_invalid_ref_error_new(msg);
1491      }
1492 
1493    ret = eldbus_message_method_return_new(msg);
1494    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1495    eldbus_message_arguments_append(ret, "i", res);
1496 
1497    return ret;
1498 }
1499 
1500 static Efl_Access_Text_Attribute*
_text_attribute_value_get_text_attribute(Efl_Text_Attribute_Handle * annotation)1501 _text_attribute_value_get_text_attribute(Efl_Text_Attribute_Handle *annotation)
1502 {
1503    Efl_Access_Text_Attribute *ret;
1504    const char *txt;
1505 
1506    txt = efl_text_formatter_attribute_get(annotation);
1507    if (!txt) return NULL;
1508 
1509    ret = calloc(1, sizeof(Efl_Access_Text_Attribute));
1510    if (!ret) return NULL;
1511 
1512    ret->value = eina_stringshare_add(txt);
1513    int size = strlen(txt);
1514    ret->name = eina_stringshare_add_length(txt, size);
1515 
1516    return ret;
1517 }
1518 
1519 static Eldbus_Message *
_text_attribute_value_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1520 _text_attribute_value_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1521 {
1522    const char *name, *obj_path = eldbus_message_path_get(msg);
1523    char *value = NULL;
1524    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1525    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1526    int start = 0, end = 0;
1527    Eldbus_Message *ret;
1528    Eina_Bool res = EINA_FALSE;
1529    Eina_Iterator *annotations;
1530    Efl_Access_Text_Attribute *attr;
1531    Efl_Text_Attribute_Handle *an;
1532 
1533    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1534 
1535    if (!eldbus_message_arguments_get(msg, "is", &start, &name))
1536      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and attribute name expected.");
1537 
1538    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1539      {
1540         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
1541         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
1542         end = start+1;
1543         efl_text_cursor_object_position_set(sel1, start);
1544         efl_text_cursor_object_position_set(sel2, end);
1545         annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
1546 
1547         if (annotations)
1548           {
1549              EINA_ITERATOR_FOREACH(annotations, an)
1550                {
1551                   attr = _text_attribute_value_get_text_attribute(an);
1552                   if (!attr) continue;
1553                   if (!strcmp(attr->name, name))
1554                      {
1555                        value = attr->value ? eina_strdup(attr->value) : NULL;
1556                        res = EINA_TRUE;
1557                      }
1558                   elm_atspi_text_text_attribute_free(attr);
1559                   if (res)
1560                       break;
1561                }
1562              eina_iterator_free(annotations);
1563           }
1564 
1565         efl_del(sel1);
1566         efl_del(sel2);
1567      }
1568    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1569      {
1570         res = efl_access_text_attribute_get(obj, name, &start, &end, &value);
1571      }
1572    else
1573      {
1574         return _dbus_invalid_ref_error_new(msg);
1575      }
1576 
1577    ret = eldbus_message_method_return_new(msg);
1578    EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
1579    eldbus_message_arguments_append(ret, "siib", value ? value : "", start, end, res);
1580 
1581 cleanup:
1582    free(value);
1583    return ret;
1584 }
1585 
1586 static Eldbus_Message *
_text_attributes_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1587 _text_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1588 {
1589    const char *obj_path = eldbus_message_path_get(msg);
1590    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1591    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1592    int start = 0, end = 0;
1593    Eldbus_Message *ret;
1594    Eldbus_Message_Iter *iter, *iter_array;
1595    Efl_Access_Text_Attribute *attr;
1596 
1597    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1598 
1599    if (!eldbus_message_arguments_get(msg, "i", &start))
1600      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
1601 
1602    ret = eldbus_message_method_return_new(msg);
1603    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1604 
1605    iter = eldbus_message_iter_get(ret);
1606    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
1607    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
1608 
1609    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1610      {
1611         Eina_Iterator *annotations;
1612         Efl_Text_Attribute_Handle *an;
1613         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
1614         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
1615 
1616         end = start+1;
1617         efl_text_cursor_object_position_set(sel1, start);
1618         efl_text_cursor_object_position_set(sel2, end);
1619         annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
1620 
1621         efl_del(sel1);
1622         efl_del(sel2);
1623 
1624         if (annotations)
1625           {
1626              EINA_ITERATOR_FOREACH(annotations, an)
1627                {
1628                   attr = _text_attribute_value_get_text_attribute(an);
1629                   if (!attr) continue;
1630                   eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
1631                   elm_atspi_text_text_attribute_free(attr);
1632                }
1633              eina_iterator_free(annotations);
1634           }
1635      }
1636    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1637      {
1638         Eina_List *attrs = NULL;
1639         efl_access_text_attributes_get(obj, &start, &end, &attrs);
1640         EINA_LIST_FREE(attrs, attr)
1641           {
1642              eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
1643              elm_atspi_text_text_attribute_free(attr);
1644           }
1645      }
1646    else
1647      {
1648         eldbus_message_iter_container_close(iter, iter_array);
1649         goto fail;
1650      }
1651 
1652    eldbus_message_iter_container_close(iter, iter_array);
1653    eldbus_message_iter_arguments_append(iter, "ii", start, end);
1654 
1655    return ret;
1656 
1657 fail:
1658    if (ret) eldbus_message_unref(ret);
1659    return NULL;
1660 }
1661 
1662 static Eldbus_Message *
_text_default_attributes_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1663 _text_default_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1664 {
1665    const char *obj_path = eldbus_message_path_get(msg);
1666    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1667    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1668    Eldbus_Message *ret;
1669    Eldbus_Message_Iter *iter, *iter_array;
1670    Eina_List *attrs = NULL;
1671    Efl_Access_Text_Attribute *attr;
1672 
1673    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1674 
1675    ret = eldbus_message_method_return_new(msg);
1676    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1677 
1678    iter = eldbus_message_iter_get(ret);
1679    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
1680    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
1681 
1682    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1683      {
1684         Eina_Iterator *annotations;
1685         Efl_Text_Attribute_Handle *an;
1686         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
1687         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
1688 
1689         efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
1690         efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
1691         annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
1692 
1693         EINA_ITERATOR_FOREACH(annotations, an)
1694           {
1695              Efl_Access_Text_Attribute *attr = _text_attribute_value_get_text_attribute(an);
1696              if (!attr) continue;
1697              attrs = eina_list_append(attrs, attr);
1698           }
1699         eina_iterator_free(annotations);
1700 
1701         efl_del(sel1);
1702         efl_del(sel2);
1703      }
1704    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1705      {
1706         attrs = efl_access_text_default_attributes_get(obj);
1707      }
1708    else
1709      {
1710         eldbus_message_unref(ret);
1711         eldbus_message_iter_container_close(iter, iter_array);
1712         return _dbus_invalid_ref_error_new(msg);
1713      }
1714 
1715    EINA_LIST_FREE(attrs, attr)
1716     {
1717       eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
1718       elm_atspi_text_text_attribute_free(attr);
1719     }
1720 
1721    eldbus_message_iter_container_close(iter, iter_array);
1722 
1723    return ret;
1724 
1725 fail:
1726    if (ret) eldbus_message_unref(ret);
1727    return NULL;
1728 }
1729 
1730 static Eina_Rect
_text_interactive_get_pos(Eo * obj,Eina_Rect rect,Eina_Bool screen_coords)1731 _text_interactive_get_pos(Eo *obj, Eina_Rect rect, Eina_Bool screen_coords)
1732 {
1733    Eina_Position2D scroller_shift = efl_ui_scrollable_content_pos_get(obj);
1734    Eina_Rect viewport = efl_ui_scrollable_viewport_geometry_get(obj);
1735    Eina_Rect r_obj = efl_access_component_extents_get(obj, EINA_TRUE);
1736 
1737    /* In widget coords */
1738    rect.x -= scroller_shift.x;
1739    rect.y -= scroller_shift.y;
1740    rect.x += viewport.x;
1741    rect.y += viewport.y;
1742 
1743 
1744    /* Is it still visible? */
1745    if (rect.x < viewport.x)
1746      {
1747         rect.w += rect.x - viewport.x;
1748         rect.x = viewport.x;
1749      }
1750 
1751    if (rect.y < viewport.y)
1752      {
1753         rect.h += rect.y - viewport.y;
1754         rect.y = viewport.y;
1755      }
1756 
1757    rect.w = viewport.w < (rect.x + rect.w) ? viewport.w - rect.x : rect.w;
1758    rect.h = viewport.h < (rect.y + rect.h) ? viewport.h - rect.y : rect.h;
1759 
1760    /* If not visible set to 0 both sides */
1761    if (rect.w <= 0 || rect.h <= 0)
1762      {
1763         rect.w = 0;
1764         rect.h = 0;
1765      }
1766 
1767    /* Transform to screen coords */
1768    rect.x += r_obj.x;
1769    rect.y += r_obj.y;
1770 
1771    /* Transform to window coords */
1772    if (!screen_coords)
1773      {
1774         Eo *win = elm_object_top_widget_get(obj);
1775         Eina_Rect r_win = efl_access_component_extents_get(win, EINA_TRUE);
1776         rect.x -= r_win.x;
1777         rect.y -= r_win.y;
1778      }
1779 
1780    return rect;
1781 }
1782 
1783 static Eldbus_Message *
_text_character_extents_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1784 _text_character_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1785 {
1786    const char *obj_path = eldbus_message_path_get(msg);
1787    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1788    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1789    int offset;
1790    Eina_Rect rect;
1791    AtspiCoordType type;
1792    Eina_Bool screen_coords, res;
1793    Eldbus_Message *ret;
1794 
1795    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1796 
1797    if (!eldbus_message_arguments_get(msg, "iu", &offset, &type))
1798      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
1799 
1800    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1801 
1802    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1803      {
1804         Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
1805         efl_text_cursor_object_position_set(cur, offset);
1806         rect = efl_text_cursor_object_cursor_geometry_get(cur, EFL_TEXT_CURSOR_TYPE_UNDER);
1807         efl_del(cur);
1808         rect = _text_interactive_get_pos(obj, rect, screen_coords);
1809         res = rect.w != 0 ? EINA_TRUE : EINA_FALSE;
1810      }
1811    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1812      {
1813         res = efl_access_text_character_extents_get(obj, offset, screen_coords, &rect);
1814      }
1815    else
1816      {
1817         return _dbus_invalid_ref_error_new(msg);
1818      }
1819 
1820    if (!res)
1821      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get character extents.");
1822 
1823    ret = eldbus_message_method_return_new(msg);
1824    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1825    eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
1826 
1827    return ret;
1828 }
1829 
1830 static Eldbus_Message *
_text_offset_at_point_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1831 _text_offset_at_point_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1832 {
1833    const char *obj_path = eldbus_message_path_get(msg);
1834    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1835    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1836    int offset, x, y;
1837    AtspiCoordType type;
1838    Eina_Bool screen_coords;
1839    Eldbus_Message *ret;
1840 
1841    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1842 
1843    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &type))
1844      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
1845 
1846    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
1847 
1848    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1849      {
1850         if (screen_coords)
1851           {
1852              Eina_Rect rect = efl_access_component_extents_get(obj, screen_coords);
1853              x -= rect.x;
1854              y -= rect.y;
1855           }
1856         else
1857           {
1858              Eo *win = elm_object_top_widget_get(obj);
1859              Eina_Rect r_win = efl_access_component_extents_get(win, EINA_TRUE);
1860              Eina_Rect r_obj = efl_access_component_extents_get(obj, EINA_TRUE);
1861              x -= r_obj.x - r_win.x;
1862              y -= r_obj.y - r_win.y;
1863           }
1864         Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
1865         efl_text_cursor_object_char_coord_set(cur, EINA_POSITION2D(x,y));
1866         offset = efl_text_cursor_object_position_get(cur);
1867         efl_del(cur);
1868      }
1869    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1870      {
1871         offset = efl_access_text_offset_at_point_get(obj, screen_coords, x, y);
1872      }
1873    else
1874      {
1875         return _dbus_invalid_ref_error_new(msg);
1876      }
1877 
1878    ret = eldbus_message_method_return_new(msg);
1879    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1880    eldbus_message_arguments_append(ret, "i", offset);
1881 
1882    return ret;
1883 }
1884 
1885 static Eldbus_Message *
_text_n_selections_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1886 _text_n_selections_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1887 {
1888    const char *obj_path = eldbus_message_path_get(msg);
1889    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1890    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1891    int n;
1892    Eldbus_Message *ret;
1893 
1894    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
1895 
1896    ret = eldbus_message_method_return_new(msg);
1897    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1898 
1899    n = efl_access_text_selections_count_get(obj);
1900 
1901    eldbus_message_arguments_append(ret, "i", n);
1902 
1903    return ret;
1904 }
1905 
1906 static Eldbus_Message *
_text_selection_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1907 _text_selection_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1908 {
1909    const char *obj_path = eldbus_message_path_get(msg);
1910    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1911    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1912    int sel_num, start = 0, end = 0;
1913    Eldbus_Message *ret;
1914 
1915    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1916 
1917    if (!eldbus_message_arguments_get(msg, "i", &sel_num))
1918      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
1919 
1920    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1921      {
1922         if (sel_num == 0)
1923           {
1924              Efl_Text_Cursor_Object *sel1, *sel2;
1925              efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
1926              start = efl_text_cursor_object_position_get(sel1);
1927              end = efl_text_cursor_object_position_get(sel2);
1928           }
1929      }
1930    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1931      {
1932         efl_access_text_access_selection_get(obj, sel_num, &start, &end);
1933      }
1934    else
1935      {
1936         return _dbus_invalid_ref_error_new(msg);
1937      }
1938 
1939    ret = eldbus_message_method_return_new(msg);
1940    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1941    eldbus_message_arguments_append(ret, "ii", start, end);
1942 
1943    return ret;
1944 }
1945 
1946 static Eldbus_Message *
_text_selection_add(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1947 _text_selection_add(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1948 {
1949    const char *obj_path = eldbus_message_path_get(msg);
1950    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
1951    Eo *obj = _bridge_object_from_path(bridge, obj_path);
1952    int start, end;
1953    Eina_Bool res;
1954    Eldbus_Message *ret;
1955 
1956    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1957 
1958    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
1959      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end text offset expected.");
1960 
1961    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
1962      {
1963         Efl_Text_Cursor_Object *sel1, *sel2;
1964         efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
1965         efl_text_cursor_object_position_set(sel1, start);
1966         efl_text_cursor_object_position_set(sel2, end);
1967         res = EINA_TRUE;
1968      }
1969    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
1970      {
1971         res = efl_access_text_selection_add(obj, start, end);
1972      }
1973    else
1974      {
1975         return _dbus_invalid_ref_error_new(msg);
1976      }
1977 
1978    ret = eldbus_message_method_return_new(msg);
1979    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
1980    eldbus_message_arguments_append(ret, "b", res);
1981 
1982    return ret;
1983 }
1984 
1985 static Eldbus_Message *
_text_selection_remove(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)1986 _text_selection_remove(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
1987 {
1988    const char *obj_path = eldbus_message_path_get(msg);
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    int sel_num;
1992    Eina_Bool res = EINA_FALSE;
1993    Eldbus_Message *ret;
1994 
1995    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
1996 
1997    if (!eldbus_message_arguments_get(msg, "i", &sel_num))
1998      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
1999 
2000    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
2001      {
2002         if (sel_num == 0)
2003           {
2004              Efl_Text_Cursor_Object *sel1, *sel2;
2005              efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
2006              efl_text_cursor_object_range_delete(sel1, sel2);
2007              res = EINA_TRUE;
2008           }
2009      }
2010    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
2011      {
2012         res = efl_access_text_selection_remove(obj, sel_num);
2013      }
2014    else
2015      {
2016         return _dbus_invalid_ref_error_new(msg);
2017      }
2018 
2019    ret = eldbus_message_method_return_new(msg);
2020    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2021    eldbus_message_arguments_append(ret, "b", res);
2022 
2023    return ret;
2024 }
2025 
2026 static Eldbus_Message *
_text_selection_set(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2027 _text_selection_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2028 {
2029    const char *obj_path = eldbus_message_path_get(msg);
2030    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2031    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2032    int sel_num, start, end;
2033    Eina_Bool res = EINA_FALSE;
2034    Eldbus_Message *ret;
2035 
2036    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
2037 
2038    if (!eldbus_message_arguments_get(msg, "iii", &sel_num, &start, &end))
2039      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2040 
2041    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
2042      {
2043         if (sel_num == 0)
2044           {
2045              Efl_Text_Cursor_Object *sel1, *sel2;
2046              efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
2047              efl_text_cursor_object_position_set(sel1, start);
2048              efl_text_cursor_object_position_set(sel2, end);
2049              res = EINA_TRUE;
2050           }
2051      }
2052    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
2053      {
2054         res = efl_access_text_access_selection_set(obj, sel_num, start, end);
2055      }
2056    else
2057      {
2058         return _dbus_invalid_ref_error_new(msg);
2059      }
2060 
2061    ret = eldbus_message_method_return_new(msg);
2062    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2063    eldbus_message_arguments_append(ret, "b", res);
2064 
2065    return ret;
2066 }
2067 
2068 static Eldbus_Message *
_text_range_extents_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2069 _text_range_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2070 {
2071    const char *obj_path = eldbus_message_path_get(msg);
2072    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2073    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2074    int start, end;
2075    Eina_Rect rect;
2076    Eina_Bool screen_coords, res;
2077    AtspiCoordType type;
2078    Eldbus_Message *ret;
2079 
2080    ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
2081 
2082    if (!eldbus_message_arguments_get(msg, "iiu", &start, &end, &type))
2083      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
2084 
2085    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2086 
2087    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
2088      {
2089         Eina_Rectangle *r;
2090         Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
2091         Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
2092         efl_text_cursor_object_position_set(sel1, start);
2093         efl_text_cursor_object_position_set(sel2, end);
2094         Eina_Iterator *range = efl_text_cursor_object_range_precise_geometry_get(sel1, sel2);
2095 
2096         /* This rect represent coordinates x1, y1, x2, y2 (not x,y,w,h).
2097          * In this way we bypass corner cases
2098          * (like range is empty or first rectangle is empty). */
2099         rect = EINA_RECT(1000000, 1000000, 0, 0);
2100 
2101         EINA_ITERATOR_FOREACH(range, r)
2102           {
2103              rect.x = r->x < rect.x ? r->x : rect.x;
2104              rect.y = r->y < rect.y ? r->y : rect.y;
2105              rect.w = r->x+r->w > rect.w ? r->x+r->w : rect.w;
2106              rect.h = r->y+r->h > rect.h ? r->y+r->h : rect.h;
2107           }
2108         eina_iterator_free(range);
2109 
2110         efl_del(sel1);
2111         efl_del(sel2);
2112 
2113         /* Let's change coordinates to x,y,w,h */
2114         rect.w -= rect.x;
2115         rect.h -= rect.y;
2116 
2117         rect = _text_interactive_get_pos(obj, rect, screen_coords);
2118 
2119         res = rect.w != 0 ? EINA_TRUE : EINA_FALSE;
2120      }
2121    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
2122      {
2123         res = efl_access_text_range_extents_get(obj, screen_coords, start, end, &rect);
2124      }
2125    else
2126      {
2127         return _dbus_invalid_ref_error_new(msg);
2128      }
2129 
2130    if (!res)
2131      {
2132         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Can't get range extents.");
2133      }
2134 
2135    ret = eldbus_message_method_return_new(msg);
2136    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2137    eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
2138 
2139    return ret;
2140 }
2141 
2142 static Eldbus_Message *
_text_bounded_ranges_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2143 _text_bounded_ranges_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2144 {
2145    const char *obj_path = eldbus_message_path_get(msg);
2146    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2147    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2148    Eina_Rect rect;
2149    Eina_Bool screen_coords;
2150    AtspiCoordType type;
2151    Efl_Access_Text_Clip_Type xclip, yclip;
2152    Eina_List *ranges;
2153    Eldbus_Message *ret;
2154    Efl_Access_Text_Range *range;
2155    Eldbus_Message_Iter *iter, *iter_array, *iter_struct, *iter_var;
2156 
2157    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
2158 
2159    if (!eldbus_message_arguments_get(msg, "iiiiuuu", &rect.x, &rect.y, &rect.w, &rect.h, &type, &xclip, &yclip))
2160      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.");
2161 
2162    ret = eldbus_message_method_return_new(msg);
2163    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2164 
2165    iter = eldbus_message_iter_get(ret);
2166    iter_array = eldbus_message_iter_container_new(iter, 'a', "(iisv)");
2167    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2168 
2169    screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
2170    ranges = efl_access_text_bounded_ranges_get(obj, screen_coords, rect, xclip, yclip);
2171 
2172    EINA_LIST_FREE(ranges, range)
2173      {
2174         iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
2175         if (iter_struct)
2176           {
2177              eldbus_message_iter_basic_append(iter_struct, 'i', range->start_offset);
2178              eldbus_message_iter_basic_append(iter_struct, 'i', range->end_offset);
2179              eldbus_message_iter_basic_append(iter_struct, 's', range->content ? range->content : "");
2180              /* AT-SPI specification requires variant type in return, however
2181               * ATK or other implementations as well as AT Clients don't use it .
2182               * To cover spec a dummy value will be returned */
2183              iter_var = eldbus_message_iter_container_new(iter_struct, 'v', "i");
2184              if (iter_var)
2185                {
2186                   eldbus_message_iter_basic_append(iter_var, 'i', 0);
2187                   eldbus_message_iter_container_close(iter_struct, iter_var);
2188                }
2189              eldbus_message_iter_container_close(iter_array, iter_struct);
2190           }
2191         elm_atspi_text_text_range_free(range);
2192      }
2193 
2194    eldbus_message_iter_container_close(iter, iter_array);
2195 
2196    return ret;
2197 
2198 fail:
2199    if (ret) eldbus_message_unref(ret);
2200    return NULL;
2201 }
2202 
2203 static Eldbus_Message *
_text_run_attributes_get(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2204 _text_run_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2205 {
2206    const char *obj_path = eldbus_message_path_get(msg);
2207    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2208    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2209    int start = 0, end = 0;
2210    Eldbus_Message *ret;
2211    Eldbus_Message_Iter *iter, *iter_array;
2212    Eina_List *attrs, *defaults;
2213    Efl_Access_Text_Attribute *attr;
2214    Eina_Bool incl_def;
2215 
2216    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
2217 
2218    if (!eldbus_message_arguments_get(msg, "ib", &start, &incl_def))
2219      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and include defaults flag expected.");
2220 
2221    ret = eldbus_message_method_return_new(msg);
2222    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2223 
2224    iter = eldbus_message_iter_get(ret);
2225    iter_array = eldbus_message_iter_container_new(iter, 'a', "{ss}");
2226    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
2227 
2228    efl_access_text_attributes_get(obj, &start, &end, &attrs);
2229 
2230    if (incl_def)
2231      {
2232         defaults = efl_access_text_default_attributes_get(obj);
2233         attrs = eina_list_merge(attrs, defaults);
2234      }
2235 
2236    EINA_LIST_FREE(attrs, attr)
2237      {
2238         eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
2239         elm_atspi_text_text_attribute_free(attr);
2240      }
2241 
2242    eldbus_message_iter_container_close(iter, iter_array);
2243    eldbus_message_iter_arguments_append(iter, "ii", start, end);
2244 
2245    return ret;
2246 
2247 fail:
2248    if (ret) eldbus_message_unref(ret);
2249    return NULL;
2250 }
2251 
2252 static const Eldbus_Method text_methods[] = {
2253    { "GetTextAtOffset", ELDBUS_ARGS({"i", "offset"}, {"u", "granularity"}), ELDBUS_ARGS({"s", "string"}, {"i", "startOffset"}, {"i", "endOffset"}), _text_string_at_offset_get, 0 },
2254    { "GetText", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"s", "string"}), _text_text_get, 0 },
2255    { "SetCaretOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"b", NULL}), _text_caret_offset_set, 0 },
2256    { "GetCharacterAtOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"i", NULL}), _text_character_at_offset_get, 0 },
2257    { "GetAttributeValue", ELDBUS_ARGS({"i", "offset"}, {"s", "attributeName"}), ELDBUS_ARGS({"s", NULL}, {"i", "startOffset"}, {"i", "endOffset"}, {"b", "defined"}), _text_attribute_value_get, 0 },
2258    { "GetAttributes", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_attributes_get, 0 },
2259    { "GetDefaultAttributes", NULL, ELDBUS_ARGS({"a(ss)", NULL}), _text_default_attributes_get, 0 },
2260    { "GetCharacterExtents", ELDBUS_ARGS({"i", "offset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_character_extents_get, 0 },
2261    { "GetOffsetAtPoint", ELDBUS_ARGS({"i", "x"}, {"i","y"}, {"u", "coordType"}), ELDBUS_ARGS({"i", NULL}), _text_offset_at_point_get, 0 },
2262    { "GetNSelections", NULL, ELDBUS_ARGS({"i", NULL}), _text_n_selections_get, 0 },
2263    { "GetSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), _text_selection_get, 0 },
2264    { "AddSelection", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_add, 0 },
2265    { "RemoveSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"b", NULL}), _text_selection_remove, 0 },
2266    { "SetSelection", ELDBUS_ARGS({"i", "selectionNum"}, {"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_set, 0 },
2267    { "GetRangeExtents", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_range_extents_get, 0 },
2268    { "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 },
2269    { "GetAttributeRun", ELDBUS_ARGS({"i", "offset"}, {"b", "includeDefaults"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_run_attributes_get, 0 },
2270    { NULL, NULL, NULL, NULL, 0 }
2271 };
2272 
2273 static Eldbus_Message *
_editable_text_text_content_set(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2274 _editable_text_text_content_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2275 {
2276    const char *obj_path = eldbus_message_path_get(msg);
2277    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2278    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2279    const char *content;
2280    Eldbus_Message *ret;
2281    Eina_Bool res;
2282 
2283    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2284 
2285    if (!eldbus_message_arguments_get(msg, "s", &content))
2286      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "String expected.");
2287 
2288    ret = eldbus_message_method_return_new(msg);
2289    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2290 
2291    res = efl_access_editable_text_content_set(obj, content);
2292 
2293    eldbus_message_arguments_append(ret, "b", res);
2294 
2295    return ret;
2296 }
2297 
2298 static Eldbus_Message *
_editable_text_text_insert(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2299 _editable_text_text_insert(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2300 {
2301    const char *obj_path = eldbus_message_path_get(msg);
2302    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2303    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2304    const char *text;
2305    Eldbus_Message *ret;
2306    int pos, len;
2307    Eina_Bool res;
2308 
2309    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2310 
2311    if (!eldbus_message_arguments_get(msg, "isi", &pos, &text, &len))
2312      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Position, string, length expected.");
2313 
2314    ret = eldbus_message_method_return_new(msg);
2315    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2316 
2317    res = efl_access_editable_text_insert(obj, text, pos);
2318 
2319    eldbus_message_arguments_append(ret, "b", res);
2320 
2321    return ret;
2322 }
2323 
2324 static Eldbus_Message *
_editable_text_text_copy(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2325 _editable_text_text_copy(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2326 {
2327    const char *obj_path = eldbus_message_path_get(msg);
2328    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2329    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2330    Eldbus_Message *ret;
2331    int start, end;
2332    Eina_Bool res;
2333 
2334    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2335 
2336    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2337      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2338 
2339    ret = eldbus_message_method_return_new(msg);
2340    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2341 
2342    res = efl_access_editable_text_copy(obj, start, end);
2343 
2344    eldbus_message_arguments_append(ret, "b", res);
2345 
2346    return ret;
2347 }
2348 
2349 static Eldbus_Message *
_editable_text_text_cut(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2350 _editable_text_text_cut(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2351 {
2352    const char *obj_path = eldbus_message_path_get(msg);
2353    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2354    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2355    Eldbus_Message *ret;
2356    int start, end;
2357    Eina_Bool res;
2358 
2359    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2360 
2361    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2362      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2363 
2364    ret = eldbus_message_method_return_new(msg);
2365    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2366 
2367    res = efl_access_editable_text_cut(obj, start, end);
2368 
2369    eldbus_message_arguments_append(ret, "b", res);
2370 
2371    return ret;
2372 }
2373 
2374 static Eldbus_Message *
_editable_text_text_delete(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2375 _editable_text_text_delete(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2376 {
2377    const char *obj_path = eldbus_message_path_get(msg);
2378    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2379    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2380    Eldbus_Message *ret;
2381    int start, end;
2382    Eina_Bool res;
2383 
2384    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2385 
2386    if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
2387      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2388 
2389    ret = eldbus_message_method_return_new(msg);
2390    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2391 
2392    res = efl_access_editable_text_delete(obj, start, end);
2393 
2394    eldbus_message_arguments_append(ret, "b", res);
2395 
2396    return ret;
2397 }
2398 
2399 static Eldbus_Message *
_editable_text_text_paste(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)2400 _editable_text_text_paste(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
2401 {
2402    const char *obj_path = eldbus_message_path_get(msg);
2403    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2404    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2405    Eldbus_Message *ret;
2406    int pos;
2407    Eina_Bool res;
2408 
2409    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
2410 
2411    if (!eldbus_message_arguments_get(msg, "i", &pos))
2412      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
2413 
2414    ret = eldbus_message_method_return_new(msg);
2415    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
2416 
2417    res = efl_access_editable_text_paste(obj, pos);
2418 
2419    eldbus_message_arguments_append(ret, "b", res);
2420 
2421    return ret;
2422 }
2423 
2424 static const Eldbus_Method editable_text_methods[] = {
2425    { "SetTextContents", ELDBUS_ARGS({"s", "newcontents"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_content_set, 0 },
2426    { "InsertText", ELDBUS_ARGS({"i", "position"}, {"s", "text"}, {"i", "length"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_insert, 0 },
2427    { "CopyText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), NULL, _editable_text_text_copy, 0 },
2428    { "CutText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_cut, 0 },
2429    { "DeleteText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_delete, 0 },
2430    { "PasteText", ELDBUS_ARGS({"i", "position"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_paste, 0 },
2431    { NULL, NULL, NULL, NULL, 0 }
2432 };
2433 
2434 static Eo *
_bridge_object_from_path(Eo * bridge,const char * path)2435 _bridge_object_from_path(Eo *bridge, const char *path)
2436 {
2437    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2438    unsigned long long eo_ptr = 0;
2439    Eo *eo = NULL;
2440    const char *tmp = path;
2441    Eo *ret, *root;
2442 
2443    int len = strlen(ELM_ACCESS_OBJECT_PATH_PREFIX);
2444    if (strncmp(path, ELM_ACCESS_OBJECT_PATH_PREFIX, len))
2445      return NULL;
2446 
2447    tmp = path + len; /* Skip over the prefix */
2448    if (!strcmp(ELM_ACCESS_OBJECT_PATH_ROOT, tmp))
2449      {
2450         root = efl_access_object_access_root_get();
2451         return root;
2452      }
2453 
2454    sscanf(tmp, "%llu", &eo_ptr);
2455    eo = (Eo *) (uintptr_t) eo_ptr;
2456 
2457    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
2458    if (!eina_hash_find(pd->cache, &eo))
2459      {
2460         WRN("Request for non-registered object: %s", path);
2461         return NULL;
2462      }
2463 
2464    ret = efl_isa(eo, EFL_ACCESS_OBJECT_MIXIN) ? eo : NULL;
2465 
2466    return ret;
2467 }
2468 
2469 static const char *
_path_from_object(const Eo * eo)2470 _path_from_object(const Eo *eo)
2471 {
2472    static char path[64];
2473    Eo *root;
2474 
2475    if (!eo)
2476      return ATSPI_DBUS_PATH_NULL;
2477    root = efl_access_object_access_root_get();
2478 
2479    if (eo == root)
2480      snprintf(path, sizeof(path), "%s%s", ELM_ACCESS_OBJECT_PATH_PREFIX, ELM_ACCESS_OBJECT_PATH_ROOT);
2481    else
2482      snprintf(path, sizeof(path), ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE, (unsigned long long)(uintptr_t)eo);
2483    return path;
2484 }
2485 
2486 static Eina_Bool
_accessible_property_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2487 _accessible_property_get(const Eldbus_Service_Interface *interface, const char *property,
2488                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2489                          Eldbus_Message **error)
2490 {
2491    const char *ret = NULL, *obj_path = eldbus_message_path_get(request_msg);
2492    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2493    Eo *ret_obj = NULL, *obj = _bridge_object_from_path(bridge, obj_path);
2494 
2495    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, request_msg, error);
2496 
2497    if (!strcmp(property, "Name"))
2498      {
2499         ret = efl_access_object_i18n_name_get(obj);
2500         if (!ret)
2501           ret = "";
2502         eldbus_message_iter_basic_append(iter, 's', ret);
2503         return EINA_TRUE;
2504      }
2505    else if (!strcmp(property, "Description"))
2506      {
2507         ret = efl_access_object_description_get(obj);
2508         if (!ret)
2509           ret = "";
2510         eldbus_message_iter_basic_append(iter, 's', ret);
2511         return EINA_TRUE;
2512      }
2513    else if (!strcmp(property, "Parent"))
2514      {
2515        ret_obj = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
2516        Efl_Access_Role role = EFL_ACCESS_ROLE_INVALID;
2517        role = efl_access_object_role_get(obj);
2518        if ((!ret_obj) && (EFL_ACCESS_ROLE_APPLICATION == role))
2519          _object_desktop_reference_append(iter);
2520        else
2521          _bridge_iter_object_reference_append(bridge, iter, ret_obj);
2522        return EINA_TRUE;
2523      }
2524    else if (!strcmp(property, "ChildCount"))
2525      {
2526         Eina_List *l = NULL;
2527         l = efl_access_object_access_children_get(obj);
2528         eldbus_message_iter_basic_append(iter, 'i', eina_list_count(l));
2529         eina_list_free(l);
2530         return EINA_TRUE;
2531      }
2532    return EINA_FALSE;
2533 }
2534 
2535 static Eina_Bool
_selection_property_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2536 _selection_property_get(const Eldbus_Service_Interface *interface, const char *property,
2537                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2538                          Eldbus_Message **error)
2539 {
2540    int n;
2541    const char *obj_path = eldbus_message_path_get(request_msg);
2542    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2543    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2544 
2545    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, request_msg, error);
2546 
2547    if (!strcmp(property, "NSelectedChildren"))
2548      {
2549         n = efl_access_selection_selected_children_count_get(obj);
2550         eldbus_message_iter_basic_append(iter, 'i', n);
2551         return EINA_TRUE;
2552      }
2553    return EINA_FALSE;
2554 }
2555 
2556 static Eina_Bool
_action_property_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2557 _action_property_get(const Eldbus_Service_Interface *interface, const char *property,
2558                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2559                          Eldbus_Message **error)
2560 {
2561    Eina_List *actions;
2562    const char *obj_path = eldbus_message_path_get(request_msg);
2563    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2564    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2565 
2566    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, request_msg, error);
2567 
2568    if (!strcmp(property, "NActions"))
2569      {
2570         actions = efl_access_action_actions_get(obj);
2571         eldbus_message_iter_basic_append(iter, 'i', eina_list_count(actions));
2572         eina_list_free(actions);
2573         return EINA_TRUE;
2574      }
2575    return EINA_FALSE;
2576 }
2577 
2578 static Eldbus_Message*
_value_properties_set(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg)2579 _value_properties_set(const Eldbus_Service_Interface *interface, const char *property,
2580                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg)
2581 {
2582    double value;
2583    Eina_Bool ret;
2584    const char *obj_path = eldbus_message_path_get(request_msg);
2585    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2586    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2587 
2588    if (elm_widget_is_legacy(obj)) {
2589       ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_VALUE_INTERFACE, request_msg);
2590    }
2591    else if(efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE)) {
2592       ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_UI_RANGE_DISPLAY_INTERFACE, request_msg);
2593    }
2594 
2595    if (!eldbus_message_iter_arguments_get(iter, "d", &value))
2596      {
2597        return eldbus_message_error_new(request_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: double.");
2598      }
2599 
2600    if (!strcmp(property, "CurrentValue"))
2601      {
2602         if (elm_widget_is_legacy(obj))
2603             ret = efl_access_value_and_text_set(obj, value, NULL);
2604         else if(efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE)) {
2605             efl_ui_range_value_set(obj, value);
2606             ret = EINA_DBL_EQ(efl_ui_range_value_get(obj), value);
2607         }
2608         else ret = EINA_FALSE;
2609         Eldbus_Message *answer = eldbus_message_method_return_new(request_msg);
2610         eldbus_message_arguments_append(answer, "b", ret);
2611         return answer;
2612      }
2613 
2614    return NULL;
2615 }
2616 
2617 static Eina_Bool
_value_properties_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2618 _value_properties_get(const Eldbus_Service_Interface *interface, const char *property,
2619                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2620                          Eldbus_Message **error)
2621 {
2622    double value;
2623    const char *obj_path = eldbus_message_path_get(request_msg);
2624    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2625    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2626 
2627    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_UI_RANGE_DISPLAY_INTERFACE, request_msg, error);
2628 
2629    if (!strcmp(property, "CurrentValue"))
2630      {
2631         value = efl_ui_range_value_get(obj);
2632         eldbus_message_iter_basic_append(iter, 'd', value);
2633         return EINA_TRUE;
2634      }
2635    if (!strcmp(property, "MinimumValue"))
2636      {
2637         efl_ui_range_limits_get(obj, &value, NULL);
2638         eldbus_message_iter_basic_append(iter, 'd', value);
2639         return EINA_TRUE;
2640      }
2641    if (!strcmp(property, "MaximumValue"))
2642      {
2643         efl_ui_range_limits_get(obj, NULL, &value);
2644         eldbus_message_iter_basic_append(iter, 'd', value);
2645         return EINA_TRUE;
2646      }
2647    if (!strcmp(property, "MinimumIncrement"))
2648      {
2649      if(efl_isa(obj, EFL_UI_RANGE_INTERACTIVE_INTERFACE)) {
2650         value = efl_ui_range_step_get(obj);
2651         }
2652      else { value = 0; }
2653         eldbus_message_iter_basic_append(iter, 'd', value);
2654         return EINA_TRUE;
2655      }
2656    return EINA_FALSE;
2657 }
2658 
2659 static Eina_Bool
_image_properties_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2660 _image_properties_get(const Eldbus_Service_Interface *interface, const char *property,
2661                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2662                          Eldbus_Message **error)
2663 {
2664    const char *value;
2665    const char *obj_path = eldbus_message_path_get(request_msg);
2666    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2667    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2668 
2669    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, request_msg, error);
2670 
2671    if (!strcmp(property, "ImageDescription"))
2672      {
2673         value = efl_access_object_description_get(obj);
2674         value = value ? value : "";
2675         eldbus_message_iter_basic_append(iter, 's', value);
2676         return EINA_TRUE;
2677      }
2678    if (!strcmp(property, "ImageLocale"))
2679      {
2680         value = efl_access_object_translation_domain_get(obj);
2681         value = value ? value : "";
2682         eldbus_message_iter_basic_append(iter, 's', value);
2683         return EINA_TRUE;
2684      }
2685    return EINA_FALSE;
2686 }
2687 
2688 static Eina_Bool
_text_properties_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2689 _text_properties_get(const Eldbus_Service_Interface *interface, const char *property,
2690                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2691                          Eldbus_Message **error)
2692 {
2693    const char *obj_path = eldbus_message_path_get(request_msg);
2694    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2695    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2696    int result;
2697    Eina_Bool checkCarretOffset = EINA_FALSE;
2698    Eina_Bool checkCharacterCount = EINA_FALSE;
2699 
2700    if (!obj)
2701      {
2702         *(error) = _dbus_invalid_ref_error_new(request_msg);
2703         return EINA_FALSE;
2704      }
2705 
2706    if (!strcmp(property, "CharacterCount"))
2707      checkCharacterCount = EINA_TRUE;
2708    else if (!strcmp(property, "CaretOffset"))
2709      checkCarretOffset = EINA_TRUE;
2710    else
2711      return EINA_FALSE;
2712 
2713    if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
2714      {
2715         if (checkCharacterCount)
2716           {
2717              Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
2718              efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
2719              result = efl_text_cursor_object_position_get(cur);
2720              efl_del(cur);
2721           }
2722 
2723         if (checkCarretOffset)
2724           {
2725              Efl_Text_Cursor_Object *main_cur = efl_text_interactive_main_cursor_get(obj);
2726              result = efl_text_cursor_object_position_get(main_cur);
2727           }
2728      }
2729    else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
2730      {
2731         if (checkCharacterCount)
2732           result = efl_access_text_character_count_get(obj);
2733 
2734         if (checkCarretOffset)
2735           result = efl_access_text_caret_offset_get(obj);
2736      }
2737    else
2738      {
2739         *(error) = _dbus_invalid_ref_error_new(request_msg);
2740         return EINA_FALSE;
2741      }
2742 
2743    eldbus_message_iter_basic_append(iter, 'i', result);
2744    return EINA_TRUE;
2745 }
2746 
2747 static Eldbus_Message*
_application_properties_set(const Eldbus_Service_Interface * iface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * input_msg)2748 _application_properties_set(const Eldbus_Service_Interface *iface, const char *property, Eldbus_Message_Iter *iter, const Eldbus_Message *input_msg)
2749 {
2750    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2751    const char *obj_path = eldbus_message_path_get(input_msg);
2752    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2753    int value;
2754 
2755    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
2756    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, input_msg);
2757 
2758    if (!eldbus_message_iter_arguments_get(iter, "i", &value))
2759      {
2760        return eldbus_message_error_new(input_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: int.");
2761      }
2762 
2763    if (!strcmp(property, "Id"))
2764      {
2765         pd->id = value;
2766         Eldbus_Message *answer = eldbus_message_method_return_new(input_msg);
2767         eldbus_message_arguments_append(answer, "b", EINA_TRUE);
2768         return answer;
2769      }
2770 
2771    return NULL;
2772 }
2773 
2774 static Eina_Bool
_application_properties_get(const Eldbus_Service_Interface * interface,const char * property,Eldbus_Message_Iter * iter,const Eldbus_Message * request_msg,Eldbus_Message ** error)2775 _application_properties_get(const Eldbus_Service_Interface *interface, const char *property,
2776                          Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
2777                          Eldbus_Message **error)
2778 {
2779    const char *obj_path = eldbus_message_path_get(request_msg);
2780    Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
2781    Eo *obj = _bridge_object_from_path(bridge, obj_path);
2782 
2783    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
2784    ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, request_msg, error);
2785 
2786    if (!strcmp(property, "ToolkitName"))
2787      {
2788         eldbus_message_iter_basic_append(iter, 's', "elementary");
2789         return EINA_TRUE;
2790      }
2791    if (!strcmp(property, "Version"))
2792      {
2793         char buf[64];
2794         snprintf(buf, sizeof(buf), "%d.%d", ELM_VERSION_MAJOR, ELM_VERSION_MINOR);
2795         eldbus_message_iter_basic_append(iter, 's', buf);
2796         return EINA_TRUE;
2797      }
2798    if (!strcmp(property, "Id"))
2799      {
2800         eldbus_message_iter_basic_append(iter, 'i', pd->id);
2801         return EINA_TRUE;
2802      }
2803    return EINA_FALSE;
2804 }
2805 
2806 static const Eldbus_Property accessible_properties[] = {
2807    { "Name", "s", NULL, NULL, 0 },
2808    { "Description", "s", NULL, NULL, 0 },
2809    { "Parent", "(so)", NULL, NULL, 0 },
2810    { "ChildCount", "i", NULL, NULL, 0 },
2811    { NULL, NULL, NULL, NULL, 0 }
2812 };
2813 
2814 static const Eldbus_Property action_properties[] = {
2815    { "NActions", "i", _action_property_get, NULL, 0 },
2816    { NULL, NULL, NULL, NULL, 0 }
2817 };
2818 
2819 static const Eldbus_Property value_properties[] = {
2820    { "MinimumValue", "d", NULL, NULL, 0 },
2821    { "MaximumValue", "d", NULL, NULL, 0 },
2822    { "MinimumIncrement", "d", NULL, NULL, 0 },
2823    { "CurrentValue", "d", NULL, NULL, 0 },
2824    { NULL, NULL, NULL, NULL, 0 }
2825 };
2826 
2827 static const Eldbus_Property image_properties[] = {
2828    { "ImageDescription", "s", NULL, NULL, 0 },
2829    { "ImageLocale", "s", NULL, NULL, 0 },
2830    { NULL, NULL, NULL, NULL, 0 }
2831 };
2832 
2833 static const Eldbus_Property selection_properties[] = {
2834    { "NSelectedChildren", "i", _selection_property_get, NULL, 0 },
2835    { NULL, NULL, NULL, NULL, 0 }
2836 };
2837 
2838 static const Eldbus_Property text_properties[] = {
2839    { "CharacterCount", "i", NULL, NULL, 0 },
2840    { "CaretOffset", "i", NULL, NULL, 0 },
2841    { NULL, NULL, NULL, NULL, 0 }
2842 };
2843 
2844 static const Eldbus_Property application_properties[] = {
2845    { "ToolkitName", "s", NULL, NULL, 0 },
2846    { "Version", "s", NULL, NULL, 0 },
2847    { "Id", "i", NULL, NULL, 0 },
2848    { NULL, NULL, NULL, NULL, 0 }
2849 };
2850 
2851 static const Eldbus_Service_Interface_Desc accessible_iface_desc = {
2852    ATSPI_DBUS_INTERFACE_ACCESSIBLE, accessible_methods, NULL, accessible_properties, _accessible_property_get, NULL
2853 };
2854 
2855 static const Eldbus_Service_Interface_Desc action_iface_desc = {
2856    ATSPI_DBUS_INTERFACE_ACTION, action_methods, NULL, action_properties, NULL, NULL
2857 };
2858 
2859 static const Eldbus_Service_Interface_Desc value_iface_desc = {
2860    ATSPI_DBUS_INTERFACE_VALUE, NULL, NULL, value_properties, _value_properties_get, _value_properties_set
2861 };
2862 
2863 static const Eldbus_Service_Interface_Desc image_iface_desc = {
2864    ATSPI_DBUS_INTERFACE_IMAGE, image_methods, NULL, image_properties, _image_properties_get, NULL
2865 };
2866 
2867 static const Eldbus_Service_Interface_Desc selection_iface_desc = {
2868    ATSPI_DBUS_INTERFACE_SELECTION, selection_methods, NULL, selection_properties, NULL, NULL
2869 };
2870 
2871 static const Eldbus_Service_Interface_Desc text_iface_desc = {
2872    ATSPI_DBUS_INTERFACE_TEXT, text_methods, NULL, text_properties, _text_properties_get, NULL
2873 };
2874 
2875 static const Eldbus_Service_Interface_Desc editable_text_iface_desc = {
2876    ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, editable_text_methods, NULL, NULL, NULL, NULL
2877 };
2878 
2879 static const Eldbus_Service_Interface_Desc application_iface_desc = {
2880    ATSPI_DBUS_INTERFACE_APPLICATION, NULL, NULL, application_properties, _application_properties_get, _application_properties_set
2881 };
2882 
2883 void
_collection_match_rule_free(struct collection_match_rule * rule)2884 _collection_match_rule_free(struct collection_match_rule *rule)
2885 {
2886    Efl_Access_Attribute *attr;
2887    eina_list_free(rule->ifaces);
2888    EINA_LIST_FREE(rule->attributes, attr)
2889      {
2890         eina_stringshare_del(attr->key);
2891         eina_stringshare_del(attr->value);
2892      }
2893 }
2894 
2895 static void
_collection_roles_convert(uint64_t roles[2])2896 _collection_roles_convert(uint64_t roles[2])
2897 {
2898    // Currently elm roles and atspi roles are binary compatible.
2899    // Implement this function when it will be needed.
2900    (void)roles;
2901 }
2902 
2903 static Eina_Bool
_collection_iter_match_rule_get(Eldbus_Message_Iter * iter,struct collection_match_rule * rule)2904 _collection_iter_match_rule_get(Eldbus_Message_Iter *iter, struct collection_match_rule *rule)
2905 {
2906    Eldbus_Message_Iter *states_iter, *attrib_iter, *iter_arg, *role_iter, *ifc_iter;
2907    unsigned int *array;
2908    int array_count, state_match, attrib_match, role_match, ifc_match, reverse;
2909    const char *ifc_name;
2910 
2911    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))
2912      {
2913         ERR("Unable to get message arguments");
2914         return EINA_FALSE;
2915      }
2916 
2917    memset(rule, 0x0, sizeof(struct collection_match_rule));
2918    rule->statematchtype = state_match;
2919    rule->attributematchtype = attrib_match;
2920    rule->rolematchtype = role_match;
2921    rule->interfacematchtype = ifc_match;
2922    rule->reverse = reverse;
2923 
2924    if (!eldbus_message_iter_fixed_array_get(states_iter, 'i', &array, &array_count))
2925      return EINA_FALSE;
2926 
2927    //Roles according to libatspi implementation are transferred in 2-int element fixed bit array
2928    if (array_count != 2)
2929      {
2930         ERR("Unexpected states array size");
2931         return EINA_FALSE;
2932      }
2933    uint64_t states = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
2934    rule->states = _atspi_state_set_to_elm_atspi_state_set(states);
2935 
2936    //Roles according to libatspi implementation are transferred in 4-int element fixed bit array
2937    if (!eldbus_message_iter_fixed_array_get(role_iter, 'i', &array, &array_count))
2938      return EINA_FALSE;
2939 
2940    if (array_count != 4)
2941      {
2942         ERR("Unexpected roles array size");
2943         return EINA_FALSE;
2944      }
2945 
2946    //convert atspi roles to elm_roles
2947    rule->roles[0] = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
2948    rule->roles[1] = ((uint64_t)array[2] | ((uint64_t)array[3] << 32));
2949 
2950    _collection_roles_convert(rule->roles);
2951 
2952    //Get matching properties
2953    while (eldbus_message_iter_get_and_next(attrib_iter, '{', &iter_arg))
2954      {
2955         const char *key, *value;
2956         if (eldbus_message_iter_arguments_get(iter_arg, "ss", &key, &value))
2957           {
2958              Efl_Access_Attribute *attrib = calloc(1, sizeof(Efl_Access_Attribute));
2959              attrib->key = eina_stringshare_add(key);
2960              attrib->value = eina_stringshare_add(value);
2961              rule->attributes = eina_list_append(rule->attributes, attrib);
2962           }
2963      }
2964 
2965    //Get interfaces to match
2966    while (eldbus_message_iter_get_and_next(ifc_iter, 's', &ifc_name))
2967      {
2968         const Efl_Class *class = NULL;
2969         if (!strcmp(ifc_name, "action"))
2970           class = EFL_ACCESS_ACTION_MIXIN;
2971         else if (!strcmp(ifc_name, "component"))
2972           class = EFL_ACCESS_COMPONENT_MIXIN;
2973         else if (!strcmp(ifc_name, "editabletext"))
2974           class = EFL_ACCESS_EDITABLE_TEXT_INTERFACE;
2975         else if (!strcmp(ifc_name, "text"))
2976           class = EFL_ACCESS_TEXT_INTERFACE;
2977         else if (!strcmp(ifc_name, "image"))
2978           class = EFL_ACCESS_SELECTION_INTERFACE;
2979         else if (!strcmp(ifc_name, "value"))
2980         {
2981            class = EFL_ACCESS_VALUE_INTERFACE;
2982            rule->ifaces = eina_list_append(rule->ifaces, EFL_UI_RANGE_DISPLAY_INTERFACE); //alternative interface
2983         }
2984 
2985         if (class)
2986           rule->ifaces = eina_list_append(rule->ifaces, class);
2987         else
2988           {
2989              _collection_match_rule_free(rule);
2990              return EINA_FALSE;
2991           }
2992      }
2993 
2994    return EINA_TRUE;
2995 }
2996 
2997 static Eina_Bool
_collection_match_interfaces_helper(Eo * obj,Eina_List * ifcs,Eina_Bool condition,Eina_Bool ret_if_true,Eina_Bool ret_if_false)2998 _collection_match_interfaces_helper(Eo *obj, Eina_List *ifcs, Eina_Bool condition, Eina_Bool ret_if_true, Eina_Bool ret_if_false)
2999 {
3000    Efl_Class *class;
3001    Eina_List *l;
3002 
3003    EINA_LIST_FOREACH(ifcs, l, class)
3004      {
3005         if (efl_isa(obj, class) == condition)
3006           return ret_if_true;
3007      }
3008    return ret_if_false;
3009 }
3010 
3011 static Eina_Bool
_collection_match_interfaces_lookup(Eo * obj,struct collection_match_rule * rule)3012 _collection_match_interfaces_lookup(Eo *obj, struct collection_match_rule *rule)
3013 {
3014    Eina_Bool ret = EINA_FALSE;
3015 
3016    switch (rule->interfacematchtype)
3017      {
3018         case ATSPI_Collection_MATCH_INVALID:
3019            ret = EINA_TRUE;
3020            break;
3021         case ATSPI_Collection_MATCH_ALL:
3022            ret = _collection_match_interfaces_helper(
3023               obj, rule->ifaces, EINA_FALSE, EINA_FALSE, EINA_TRUE);
3024            break;
3025         case ATSPI_Collection_MATCH_ANY:
3026            ret = _collection_match_interfaces_helper(
3027               obj, rule->ifaces, EINA_TRUE, EINA_TRUE, EINA_FALSE);
3028            break;
3029         case ATSPI_Collection_MATCH_NONE:
3030            ret = _collection_match_interfaces_helper(
3031               obj, rule->ifaces, EINA_TRUE, EINA_FALSE, EINA_TRUE);
3032            break;
3033         default:
3034            break;
3035      }
3036    return ret;
3037 }
3038 
3039 static Eina_Bool
_collection_match_states_lookup(Eo * obj,struct collection_match_rule * rule)3040 _collection_match_states_lookup(Eo *obj, struct collection_match_rule *rule)
3041 {
3042    Eina_Bool ret = EINA_FALSE;
3043    Efl_Access_State_Set ss;
3044 
3045    ss = efl_access_object_state_set_get(obj);
3046 
3047    switch (rule->statematchtype)
3048      {
3049         case ATSPI_Collection_MATCH_INVALID:
3050            ret = EINA_TRUE;
3051            break;
3052         case ATSPI_Collection_MATCH_ALL:
3053            ret = (ss & rule->states) == rule->states;
3054            break;
3055         case ATSPI_Collection_MATCH_ANY:
3056            ret = (ss & rule->states) > 0;
3057            break;
3058         case ATSPI_Collection_MATCH_NONE:
3059            ret = (ss & rule->states) == 0;
3060            break;
3061         default:
3062            break;
3063      }
3064 
3065    return ret;
3066 }
3067 
3068 static Eina_Bool
_collection_match_roles_lookup(Eo * obj,struct collection_match_rule * rule)3069 _collection_match_roles_lookup(Eo *obj, struct collection_match_rule *rule)
3070 {
3071    Eina_Bool ret = EINA_FALSE;
3072    Efl_Access_Role role;
3073    int64_t role_set;
3074 
3075    role = efl_access_object_role_get(obj);
3076 
3077    if (role >= 64)
3078      {
3079         role -= 64;
3080         role_set = rule->roles[1];
3081      }
3082    else
3083      role_set = rule->roles[0];
3084 
3085    if (role >= 64)
3086      {
3087         ERR("Efl_Access_Role enum value exceeds 127. Unable to compare with roles bit field.");
3088         return EINA_FALSE;
3089      }
3090 
3091    switch (rule->rolematchtype)
3092      {
3093         case ATSPI_Collection_MATCH_INVALID:
3094            ret = EINA_TRUE;
3095            break;
3096         case ATSPI_Collection_MATCH_ALL:
3097         case ATSPI_Collection_MATCH_ANY:
3098            ret = (role_set & (1ULL << role)) > 0;
3099            break;
3100         case ATSPI_Collection_MATCH_NONE:
3101            ret = (role_set & (1ULL << role)) == 0;
3102            break;
3103         default:
3104            break;
3105      }
3106 
3107    return ret;
3108 }
3109 
3110 static Eina_Bool
_collection_match_attributes_helper(Eina_List * obj_attribs,Eina_List * attribs,AtspiCollectionMatchType mode)3111 _collection_match_attributes_helper(Eina_List *obj_attribs, Eina_List *attribs, AtspiCollectionMatchType mode)
3112 {
3113    Eina_List *l, *l2;
3114    Efl_Access_Attribute *attr, *attr2;
3115    Eina_Bool obj_empty = eina_list_count(obj_attribs) == 0;
3116    Eina_Bool empty = eina_list_count(attribs) == 0;
3117 
3118    switch (mode)
3119      {
3120         case ATSPI_Collection_MATCH_ANY:
3121            if (empty || obj_empty) return EINA_FALSE;
3122            break;
3123         case ATSPI_Collection_MATCH_ALL:
3124            if (empty) return EINA_TRUE;
3125            if (obj_empty) return EINA_FALSE;
3126            break;
3127         case ATSPI_Collection_MATCH_NONE:
3128            if (empty || obj_empty) return EINA_TRUE;
3129            break;
3130         case ATSPI_Collection_MATCH_EMPTY:
3131            if (empty && obj_empty) return EINA_TRUE;
3132            if (empty || obj_empty) return EINA_FALSE;
3133            break;
3134         case ATSPI_Collection_MATCH_INVALID:
3135         case ATSPI_Collection_MATCH_LAST_DEFINED:
3136            assert(0);
3137            break;
3138      }
3139    EINA_LIST_FOREACH(attribs, l, attr)
3140      {
3141        Eina_Bool found = EINA_FALSE;
3142        EINA_LIST_FOREACH(obj_attribs, l2, attr2)
3143          {
3144             Eina_Bool compare = (attr->key && attr2->key &&
3145                  attr->value && attr2->value &&
3146                  !strcmp(attr->key, attr2->key) &&
3147                  !strcmp(attr->value, attr2->value));
3148             if (compare)
3149               {
3150                  found = EINA_TRUE;
3151                  break;
3152               }
3153          }
3154        switch (mode)
3155          {
3156             case ATSPI_Collection_MATCH_EMPTY:
3157             case ATSPI_Collection_MATCH_ALL:
3158                if (!found) return EINA_FALSE;
3159                break;
3160             case ATSPI_Collection_MATCH_ANY:
3161                if (found) return EINA_TRUE;
3162                break;
3163             case ATSPI_Collection_MATCH_NONE:
3164                if (found) return EINA_FALSE;
3165                break;
3166             case ATSPI_Collection_MATCH_INVALID:
3167             case ATSPI_Collection_MATCH_LAST_DEFINED:
3168                assert(0);
3169                break;
3170          }
3171      }
3172 
3173    switch (mode)
3174      {
3175         case ATSPI_Collection_MATCH_EMPTY:
3176         case ATSPI_Collection_MATCH_ALL:
3177         case ATSPI_Collection_MATCH_NONE:
3178            return EINA_TRUE;
3179         case ATSPI_Collection_MATCH_ANY:
3180            return EINA_FALSE;
3181         case ATSPI_Collection_MATCH_INVALID:
3182         case ATSPI_Collection_MATCH_LAST_DEFINED:
3183            assert(0);
3184            break;
3185      }
3186    return EINA_FALSE;
3187 }
3188 
3189 static Eina_Bool
_collection_match_attributes_lookup(Eo * obj,struct collection_match_rule * rule)3190 _collection_match_attributes_lookup(Eo *obj, struct collection_match_rule *rule)
3191 {
3192    Eina_Bool ret = EINA_FALSE;
3193    Eina_List *obj_attribs;
3194 
3195    obj_attribs = efl_access_object_attributes_get(obj);
3196 
3197    switch (rule->attributematchtype)
3198      {
3199         case ATSPI_Collection_MATCH_INVALID:
3200            ret = EINA_TRUE;
3201            break;
3202         case ATSPI_Collection_MATCH_ALL:
3203         case ATSPI_Collection_MATCH_ANY:
3204         case ATSPI_Collection_MATCH_NONE:
3205         case ATSPI_Collection_MATCH_EMPTY:
3206            ret = _collection_match_attributes_helper(obj_attribs, rule->attributes, rule->attributematchtype);
3207            break;
3208         default:
3209            DBG("invalid match type");
3210            break;
3211      }
3212 
3213    efl_access_attributes_list_free(obj_attribs);
3214 
3215    return ret;
3216 }
3217 
3218 static int
_collection_sort_order_canonical(struct collection_match_rule * rule,Eina_List ** ls,int count,int max,Eo * obj,long index,Eina_Bool flag,Eo * pobj,Eina_Bool recurse,Eina_Bool traverse)3219 _collection_sort_order_canonical(struct collection_match_rule *rule, Eina_List **ls,
3220                       int count, int max,
3221                       Eo *obj, long index, Eina_Bool flag,
3222                       Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
3223 {
3224    int i = index;
3225    Eina_List *children;
3226    children = efl_access_object_access_children_get(obj);
3227    long acount = eina_list_count(children);
3228    Eina_Bool prev = pobj ? EINA_TRUE : EINA_FALSE;
3229 
3230    for (; i < acount && (max == 0 || count < max); i++)
3231      {
3232         Eo *child = eina_list_nth(children, i);
3233 
3234         if (prev && child == pobj)
3235           {
3236              eina_list_free(children);
3237              return count;
3238           }
3239 
3240         if (flag && _collection_match_interfaces_lookup(child, rule)
3241             && _collection_match_states_lookup(child, rule)
3242             && _collection_match_roles_lookup(child, rule)
3243             && _collection_match_attributes_lookup(child, rule))
3244           {
3245              *ls = eina_list_append(*ls, child);
3246              count++;
3247           }
3248 
3249        if (!flag)
3250          flag = EINA_TRUE;
3251 
3252        if (recurse && traverse)
3253          count = _collection_sort_order_canonical(rule, ls, count,
3254                                                   max, child, 0, EINA_TRUE,
3255                                                   pobj, recurse, traverse);
3256      }
3257    eina_list_free(children);
3258    return count;
3259 }
3260 
3261 static int
_collection_sort_order_reverse_canonical(struct collection_match_rule * rule,Eina_List ** ls,int count,int max,Eo * obj,Eina_Bool flag,Eo * pobj)3262 _collection_sort_order_reverse_canonical(struct collection_match_rule *rule, Eina_List **ls,
3263                       int count, int max, Eo *obj, Eina_Bool flag, Eo *pobj)
3264 {
3265   Eo *nextobj, *parent;
3266   long indexinparent;
3267   Eina_List *children;
3268 
3269   /* This breaks us out of the recursion. */
3270   if (!obj || obj == pobj)
3271     {
3272       return count;
3273     }
3274 
3275   /* Add to the list if it matches */
3276   if (flag && _collection_match_interfaces_lookup(obj, rule)
3277       && _collection_match_states_lookup(obj, rule)
3278       && _collection_match_roles_lookup(obj, rule)
3279       && _collection_match_attributes_lookup(obj, rule)
3280       && (max == 0 || count < max))
3281     {
3282        *ls = eina_list_append(*ls, obj);
3283        count++;
3284     }
3285 
3286   if (!flag)
3287     flag = EINA_TRUE;
3288 
3289   /* Get the current nodes index in it's parent and the parent object. */
3290   indexinparent = efl_access_object_index_in_parent_get(obj);
3291   parent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
3292 
3293   if ((indexinparent > 0) && ((max == 0) || (count < max)))
3294     {
3295        /* there are still some siblings to visit so get the previous sibling
3296           and get it's last descendant.
3297           First, get the previous sibling */
3298        children = efl_access_object_access_children_get(parent);
3299        nextobj = eina_list_nth(children, indexinparent - 1);
3300        eina_list_free(children);
3301 
3302        /* Now, drill down the right side to the last descendant */
3303        do {
3304             children = efl_access_object_access_children_get(nextobj);
3305             if (children) nextobj = eina_list_last_data_get(children);
3306             eina_list_free(children);
3307        } while (children);
3308 
3309        /* recurse with the last descendant */
3310        count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
3311                                        nextobj, EINA_TRUE, pobj);
3312     }
3313   else if (max == 0 || count < max)
3314     {
3315       /* no more siblings so next node must be the parent */
3316       count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
3317                                         parent, EINA_TRUE, pobj);
3318 
3319     }
3320   return count;
3321 }
3322 
3323 static int
_collection_inbackorder(Eo * collection,struct collection_match_rule * rule,Eina_List ** list,int max,Eo * obj)3324 _collection_inbackorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
3325                         int max, Eo *obj)
3326 {
3327    *list = eina_list_append(*list, obj);
3328 
3329    _collection_sort_order_reverse_canonical(rule, list, 0, max, obj, EINA_TRUE, collection);
3330 
3331    *list = eina_list_remove_list(*list, *list);
3332 
3333    return 0;
3334 }
3335 
3336 static int
_collection_inorder(Eo * collection,struct collection_match_rule * rule,Eina_List ** list,int count,int max,Eo * obj,Eina_Bool traverse)3337 _collection_inorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
3338                     int count, int max, Eo *obj, Eina_Bool traverse)
3339 {
3340    int idx = 0;
3341 
3342    count = _collection_sort_order_canonical(rule, list, count, max, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
3343 
3344   while ((max == 0 || count < max) && obj && obj != collection)
3345     {
3346        Eo *parent;
3347        parent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
3348        idx = efl_access_object_index_in_parent_get(obj);
3349        count = _collection_sort_order_canonical(rule, list, count, max, parent,
3350                                      idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
3351        obj = parent;
3352     }
3353 
3354   if (max == 0 || count < max)
3355     count = _collection_sort_order_canonical(rule, list, count, max,
3356                                     obj, idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
3357 
3358   return count;
3359 }
3360 
3361 static int
_collection_query(struct collection_match_rule * rule,AtspiCollectionSortOrder sortby,Eina_List ** list,int count,int max,Eo * obj,long index,Eina_Bool flag,Eo * pobj,Eina_Bool recurse,Eina_Bool traverse)3362 _collection_query(struct collection_match_rule *rule, AtspiCollectionSortOrder sortby,
3363                          Eina_List **list, int count, int max, Eo *obj, long index,
3364                          Eina_Bool flag, Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
3365 {
3366    switch (sortby)
3367      {
3368         case ATSPI_Collection_SORT_ORDER_CANONICAL:
3369            count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
3370                                                     pobj, recurse, traverse);
3371            break;
3372         case ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL:
3373            count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
3374                                                     pobj, recurse, traverse);
3375            *list = eina_list_reverse(*list);
3376            break;
3377         default:
3378           count = 0;
3379           WRN("Unhandled sort method");
3380           break;
3381      }
3382    return count;
3383 }
3384 
3385 static Eldbus_Message*
_collection_return_msg_from_list(Elm_Atspi_Bridge * bridge,const Eldbus_Message * msg,const Eina_List * objs)3386 _collection_return_msg_from_list(Elm_Atspi_Bridge *bridge, const Eldbus_Message *msg, const Eina_List *objs)
3387 {
3388    Eldbus_Message *ret;
3389    const Eina_List *l;
3390    Eldbus_Message_Iter *iter, *array_iter;
3391    Eo *obj;
3392 
3393    ret = eldbus_message_method_return_new(msg);
3394    if (!ret) return NULL;
3395 
3396    iter = eldbus_message_iter_get(ret);
3397    array_iter = eldbus_message_iter_container_new(iter, 'a', "(so)");
3398 
3399    EINA_LIST_FOREACH(objs, l, obj)
3400      {
3401         _bridge_object_register(bridge, obj);
3402         _bridge_iter_object_reference_append(bridge, array_iter, obj);
3403      }
3404 
3405    eldbus_message_iter_container_close(iter, array_iter);
3406    return ret;
3407 }
3408 
3409 static Eina_List*
_collection_get_matches_from_handle(Eo * collection,Eo * current,struct collection_match_rule * rule,AtspiCollectionSortOrder sortby,AtspiCollectionTreeTraversalType tree,int max,Eina_Bool traverse)3410 _collection_get_matches_from_handle(Eo *collection, Eo *current, struct collection_match_rule *rule, AtspiCollectionSortOrder sortby, AtspiCollectionTreeTraversalType tree, int max, Eina_Bool traverse)
3411 {
3412    Eina_List *result = NULL;
3413    Eo *parent;
3414    int idx;
3415 
3416    switch (tree)
3417      {
3418       case ATSPI_Collection_TREE_INORDER:
3419            _collection_inorder(collection, rule, &result, 0, max, current, traverse);
3420          if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
3421            result = eina_list_reverse(result);
3422          break;
3423       case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
3424          idx = efl_access_object_index_in_parent_get(current);
3425          parent = efl_provider_find(efl_parent_get(current), EFL_ACCESS_OBJECT_MIXIN);
3426          _collection_query(rule, sortby, &result, 0, max, parent, idx, EINA_FALSE, NULL, EINA_TRUE, traverse);
3427          break;
3428       case ATSPI_Collection_TREE_RESTRICT_SIBLING:
3429          _collection_query(rule, sortby, &result, 0, max, current, 0, EINA_FALSE, NULL, EINA_TRUE, traverse);
3430          break;
3431       default:
3432          ERR("Tree parameter value not handled");
3433          break;
3434      }
3435    return result;
3436 }
3437 
3438 static Eldbus_Message*
_collection_get_matches_from(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg EINA_UNUSED)3439 _collection_get_matches_from(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
3440 {
3441    const char *obj_path = eldbus_message_path_get(msg);
3442    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3443    Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
3444    Eldbus_Message *ret;
3445    Eldbus_Message_Iter *iter, *rule_iter;
3446    struct collection_match_rule rule;
3447    int count;
3448    AtspiCollectionTreeTraversalType tree;
3449    Eina_Bool traverse;
3450    AtspiCollectionSortOrder sortby;
3451    Eina_List *result = NULL;
3452 
3453    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
3454 
3455    iter = eldbus_message_iter_get(msg);
3456    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3457 
3458    if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uuib", &obj_path, &rule_iter, &sortby, &tree, &count, &traverse))
3459      {
3460         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
3461      }
3462 
3463    current = _bridge_object_from_path(bridge, obj_path);
3464 
3465    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, EFL_ACCESS_OBJECT_MIXIN, msg);
3466 
3467    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3468      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3469 
3470    result = _collection_get_matches_from_handle(obj, current, &rule, sortby, tree, count, traverse);
3471    ret = _collection_return_msg_from_list(bridge, msg, result);
3472 
3473    eina_list_free(result);
3474    _collection_match_rule_free(&rule);
3475 
3476    return ret;
3477 }
3478 
3479 static Eina_List*
_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)3480 _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)
3481 {
3482    Eina_List *result = NULL;
3483    Eo *collection = obj;
3484 
3485    if (limit)
3486      collection = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
3487 
3488    switch (tree)
3489      {
3490       case ATSPI_Collection_TREE_INORDER:
3491          _collection_inbackorder(obj, rule, &result, max, current);
3492          if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
3493            result = eina_list_reverse(result);
3494          break;
3495       case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
3496          _collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
3497          break;
3498       case ATSPI_Collection_TREE_RESTRICT_SIBLING:
3499          _collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
3500          break;
3501       default:
3502          ERR("Tree parameter value not handled");
3503          break;
3504      }
3505 
3506    return result;
3507 }
3508 
3509 static Eldbus_Message*
_collection_get_matches_to(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg EINA_UNUSED)3510 _collection_get_matches_to(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
3511 {
3512    const char *obj_path = eldbus_message_path_get(msg);
3513    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3514    Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
3515    Eldbus_Message *ret;
3516    Eldbus_Message_Iter *iter, *rule_iter;
3517    struct collection_match_rule rule;
3518    int count;
3519    AtspiCollectionTreeTraversalType tree;
3520    Eina_Bool traverse;
3521    AtspiCollectionSortOrder sortby;
3522    Eina_List *result = NULL;
3523    Eina_Bool limit;
3524 
3525    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
3526 
3527    iter = eldbus_message_iter_get(msg);
3528    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3529 
3530    if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uubib", &obj_path, &rule_iter, &sortby, &tree, &limit, &count, &traverse))
3531      {
3532         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, tree, limit count or traverse values.");
3533      }
3534 
3535    current = _bridge_object_from_path(bridge, obj_path);
3536 
3537    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, EFL_ACCESS_OBJECT_MIXIN, msg);
3538 
3539    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3540      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3541 
3542    result = _collection_get_matches_to_handle(obj, current, &rule, sortby, tree, limit, count, traverse);
3543    ret = _collection_return_msg_from_list(bridge, msg, result);
3544 
3545    eina_list_free(result);
3546    _collection_match_rule_free(&rule);
3547 
3548    return ret;
3549 }
3550 
3551 static Eldbus_Message*
_collection_get_matches(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)3552 _collection_get_matches(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
3553 {
3554    const char *obj_path = eldbus_message_path_get(msg);
3555    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3556    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3557    Eldbus_Message *ret;
3558    Eldbus_Message_Iter *iter, *rule_iter;
3559    struct collection_match_rule rule;
3560    int count;
3561    Eina_Bool traverse;
3562    AtspiCollectionSortOrder sortby;
3563    Eina_List *result = NULL;
3564 
3565    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
3566 
3567    iter = eldbus_message_iter_get(msg);
3568    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
3569 
3570    if (!eldbus_message_iter_arguments_get(iter, "(aiia{ss}iaiiasib)uib", &rule_iter, &sortby, &count, &traverse))
3571      {
3572         return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
3573      }
3574 
3575    if (!_collection_iter_match_rule_get(rule_iter, &rule))
3576      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
3577 
3578    _collection_query(&rule, sortby, &result, 0, count, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
3579 
3580    ret = _collection_return_msg_from_list(bridge, msg, result);
3581 
3582    eina_list_free(result);
3583    _collection_match_rule_free(&rule);
3584 
3585    return ret;
3586 }
3587 
3588 static const Eldbus_Method collection_methods[] = {
3589    { "GetMatchesFrom",
3590       ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
3591                   {"u", "sortby"}, {"u", "tree"}, {"i", "count"}, {"b", "traverse"}),
3592       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_from, 0 },
3593    { "GetMatchesTo",
3594       ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
3595                   {"u", "sortby"}, {"u", "tree"}, {"b", "limit_scope"},
3596                   {"i", "count"}, {"b", "traverse"}),
3597       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_to, 0 },
3598    { "GetMatches",
3599       ELDBUS_ARGS({"(aiia{ss}iaiiasib)", "match_rule"},
3600                   {"u", "sortby"}, {"i", "count"}, {"b", "traverse"}),
3601       ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches, 0 },
3602    { NULL, NULL, NULL, NULL, 0 }
3603 };
3604 
3605 static const Eldbus_Service_Interface_Desc collection_iface_desc = {
3606    ATSPI_DBUS_INTERFACE_COLLECTION, collection_methods, NULL, NULL, NULL, NULL
3607 };
3608 
3609 static void
_bridge_iter_object_reference_append(Eo * bridge,Eldbus_Message_Iter * iter,const Eo * obj)3610 _bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj)
3611 {
3612    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
3613    Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
3614    EINA_SAFETY_ON_NULL_RETURN(iter);
3615    const char *path = _path_from_object(obj);
3616    eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(pd->a11y_bus));
3617    eldbus_message_iter_basic_append(iter_struct, 'o', path);
3618    eldbus_message_iter_container_close(iter, iter_struct);
3619 }
3620 
3621 static void
_object_desktop_reference_append(Eldbus_Message_Iter * iter)3622 _object_desktop_reference_append(Eldbus_Message_Iter *iter)
3623 {
3624   Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
3625   EINA_SAFETY_ON_NULL_RETURN(iter);
3626 
3627   eldbus_message_iter_basic_append(iter_struct, 's', ATSPI_DBUS_NAME_REGISTRY);
3628   eldbus_message_iter_basic_append(iter_struct, 'o', ATSPI_DBUS_PATH_ROOT);
3629   eldbus_message_iter_container_close(iter, iter_struct);
3630 }
3631 
3632 static void
_iter_interfaces_append(Eldbus_Message_Iter * iter,const Eo * obj)3633 _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj)
3634 {
3635   Eldbus_Message_Iter *iter_array;
3636   iter_array = eldbus_message_iter_container_new(iter, 'a', "s");
3637   if (!iter_array) return;
3638 
3639   if (efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
3640     {
3641        eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACCESSIBLE);
3642        eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COLLECTION);
3643     }
3644   if (efl_isa(obj, EFL_ACCESS_ACTION_MIXIN))
3645     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACTION);
3646   if (efl_isa(obj, ELM_ATSPI_APP_OBJECT_CLASS))
3647     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_APPLICATION);
3648   if (efl_isa(obj, EFL_ACCESS_COMPONENT_MIXIN))
3649     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COMPONENT);
3650   if (efl_isa(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE))
3651     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_EDITABLE_TEXT);
3652   if (efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
3653     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_IMAGE);
3654   if (efl_isa(obj, EFL_ACCESS_SELECTION_INTERFACE))
3655     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_SELECTION);
3656   if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
3657     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_TEXT);
3658   if (efl_isa(obj, EFL_ACCESS_VALUE_INTERFACE))
3659     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_VALUE);
3660   if (efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE))
3661     eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_VALUE);
3662 
3663   eldbus_message_iter_container_close(iter, iter_array);
3664 }
3665 
3666 static Eina_Bool
_cache_item_reference_append_cb(Eo * bridge,Eo * data,Eldbus_Message_Iter * iter_array)3667 _cache_item_reference_append_cb(Eo *bridge, Eo *data, Eldbus_Message_Iter *iter_array)
3668 {
3669   if (!efl_ref_count(data) || efl_destructed_is(data))
3670     return EINA_TRUE;
3671 
3672   Eldbus_Message_Iter *iter_struct, *iter_sub_array;
3673   Efl_Access_State_Set states;
3674   Efl_Access_Role role;
3675   Eo *root;
3676   root = efl_access_object_access_root_get();
3677 
3678   role = efl_access_object_role_get(data);
3679 
3680   iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
3681   EINA_SAFETY_ON_NULL_RETURN_VAL(iter_struct, EINA_TRUE);
3682 
3683   /* Marshall object path */
3684   _bridge_iter_object_reference_append(bridge, iter_struct, data);
3685 
3686   /* Marshall application */
3687   _bridge_iter_object_reference_append(bridge, iter_struct, root);
3688 
3689   Eo *parent = NULL;
3690   parent = efl_provider_find(efl_parent_get(data), EFL_ACCESS_OBJECT_MIXIN);
3691   /* Marshall parent */
3692   if ((!parent) && (EFL_ACCESS_ROLE_APPLICATION == role))
3693     _object_desktop_reference_append(iter_struct);
3694   else
3695     _bridge_iter_object_reference_append(bridge, iter_struct, parent);
3696 
3697   /* Marshall children  */
3698   Eina_List *children_list = NULL, *l;
3699   Eo *child;
3700 
3701   children_list = efl_access_object_access_children_get(data);
3702   iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
3703   EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail);
3704 
3705   EINA_LIST_FOREACH(children_list, l, child)
3706      _bridge_iter_object_reference_append(bridge, iter_sub_array, child);
3707 
3708   eldbus_message_iter_container_close(iter_struct, iter_sub_array);
3709   eina_list_free(children_list);
3710 
3711   /* Marshall interfaces */
3712   _iter_interfaces_append(iter_struct, data);
3713 
3714   /* Marshall name */
3715   const char *name = NULL;
3716   name = efl_access_object_i18n_name_get(data);
3717   if (!name)
3718     name = "";
3719 
3720   eldbus_message_iter_basic_append(iter_struct, 's', name);
3721 
3722   /* Marshall role */
3723   eldbus_message_iter_basic_append(iter_struct, 'u', role);
3724 
3725   /* Marshall description */
3726   const char* description = NULL;
3727   description = efl_access_object_description_get(data);
3728   if (!description)
3729     description = "";
3730   eldbus_message_iter_basic_append(iter_struct, 's', description);
3731 
3732   /* Marshall state set */
3733   iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "u");
3734   EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail);
3735 
3736   states = efl_access_object_state_set_get(data);
3737 
3738   unsigned int s1 = states & 0xFFFFFFFF;
3739   unsigned int s2 = (states >> 32) & 0xFFFFFFFF;
3740   eldbus_message_iter_basic_append(iter_sub_array, 'u', s1);
3741   eldbus_message_iter_basic_append(iter_sub_array, 'u', s2);
3742 
3743   eldbus_message_iter_container_close(iter_struct, iter_sub_array);
3744   eldbus_message_iter_container_close(iter_array, iter_struct);
3745 
3746   return EINA_TRUE;
3747 
3748 fail:
3749   if (iter_struct) eldbus_message_iter_del(iter_struct);
3750   return EINA_TRUE;
3751 }
3752 
3753 static Eldbus_Message *
_cache_get_items(const Eldbus_Service_Interface * iface,const Eldbus_Message * msg)3754 _cache_get_items(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
3755 {
3756    Eldbus_Message_Iter *iter, *iter_array;
3757    Eldbus_Message *ret;
3758    Eina_List *to_process;
3759    Eo *root;
3760 
3761    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3762    if (!bridge) return NULL;
3763 
3764    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
3765 
3766    ret = eldbus_message_method_return_new(msg);
3767    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3768 
3769    iter = eldbus_message_iter_get(ret);
3770    iter_array = eldbus_message_iter_container_new(iter, 'a', CACHE_ITEM_SIGNATURE);
3771    EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
3772 
3773    root = efl_access_object_access_root_get();
3774    to_process = eina_list_append(NULL, root);
3775 
3776    while (to_process)
3777      {
3778         Eo *obj = eina_list_data_get(to_process);
3779         to_process = eina_list_remove_list(to_process, to_process);
3780         _cache_item_reference_append_cb(bridge, obj, iter_array);
3781         _bridge_object_register(bridge, obj);
3782 
3783         Eina_List *children;
3784         children = efl_access_object_access_children_get(obj);
3785         to_process = eina_list_merge(to_process, children);
3786      }
3787 
3788    eldbus_message_iter_container_close(iter, iter_array);
3789 
3790    return ret;
3791 fail:
3792    if (ret) eldbus_message_unref(ret);
3793    return NULL;
3794 }
3795 
3796 static const Eldbus_Method cache_methods[] = {
3797    { "GetItems", NULL, ELDBUS_ARGS({CACHE_ITEM_SIGNATURE, "items"}), _cache_get_items, 0 },
3798    { NULL, NULL, NULL, NULL, 0 }
3799 };
3800 
3801 static const Eldbus_Signal cache_signals[] = {
3802   [ATSPI_OBJECT_CHILD_ADDED] = { "AddAccessible", ELDBUS_ARGS({"((so)(so)a(so)assusau)", "added"}), 0},
3803   [ATSPI_OBJECT_CHILD_REMOVED] = { "RemoveAccessible", ELDBUS_ARGS({ "(so)", "removed" }), 0},
3804   {NULL, NULL, 0}
3805 };
3806 
3807 static const Eldbus_Service_Interface_Desc cache_iface_desc = {
3808    ATSPI_DBUS_INTERFACE_CACHE, cache_methods, cache_signals, NULL, NULL, NULL
3809 };
3810 
3811 // Component interface
3812 static Eldbus_Message *
_component_contains(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3813 _component_contains(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3814 {
3815    const char *obj_path = eldbus_message_path_get(msg);
3816    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3817    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3818    int x, y;
3819    Eina_Bool contains = EINA_FALSE;
3820    AtspiCoordType coord_type;
3821    Eldbus_Message *ret;
3822 
3823    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3824 
3825    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
3826      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
3827 
3828    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
3829    contains = efl_access_component_contains(obj, type, x, y);
3830 
3831    ret = eldbus_message_method_return_new(msg);
3832    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3833 
3834    eldbus_message_arguments_append(ret, "b", contains);
3835 
3836    return ret;
3837 }
3838 
3839 static Eldbus_Message *
_component_get_accessible_at_point(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3840 _component_get_accessible_at_point(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3841 {
3842    const char *obj_path = eldbus_message_path_get(msg);
3843    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3844    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3845    int x, y;
3846    Eo *accessible = NULL;
3847    AtspiCoordType coord_type;
3848    Eldbus_Message *ret;
3849    Eldbus_Message_Iter *iter;
3850 
3851    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3852 
3853    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
3854      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
3855 
3856    ret = eldbus_message_method_return_new(msg);
3857    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3858 
3859    iter = eldbus_message_iter_get(ret);
3860    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
3861    accessible = efl_access_component_accessible_at_point_get(obj, type, x, y);
3862    _bridge_iter_object_reference_append(bridge, iter, accessible);
3863    _bridge_object_register(bridge, accessible);
3864 
3865    return ret;
3866 }
3867 
3868 static Eldbus_Message *
_component_get_extents(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3869 _component_get_extents(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3870 {
3871    const char *obj_path = eldbus_message_path_get(msg);
3872    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3873    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3874    AtspiCoordType coord_type;
3875    Eldbus_Message *ret;
3876    Eldbus_Message_Iter *iter, *iter_struct;
3877    Eina_Rect r;
3878 
3879    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3880 
3881    if (!eldbus_message_arguments_get(msg, "u", &coord_type))
3882      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
3883 
3884    ret = eldbus_message_method_return_new(msg);
3885    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3886 
3887    iter = eldbus_message_iter_get(ret);
3888 
3889    r = efl_access_component_extents_get(obj, (coord_type == ATSPI_COORD_TYPE_SCREEN));
3890    iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
3891    EINA_SAFETY_ON_NULL_GOTO(iter_struct, fail);
3892 
3893    eldbus_message_iter_basic_append(iter_struct, 'i', r.x);
3894    eldbus_message_iter_basic_append(iter_struct, 'i', r.y);
3895    eldbus_message_iter_basic_append(iter_struct, 'i', r.w);
3896    eldbus_message_iter_basic_append(iter_struct, 'i', r.h);
3897 
3898    eldbus_message_iter_container_close(iter, iter_struct);
3899 
3900    return ret;
3901 fail:
3902    if (ret) eldbus_message_unref(ret);
3903    return NULL;
3904 }
3905 
3906 static Eldbus_Message *
_component_get_position(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3907 _component_get_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3908 {
3909    const char *obj_path = eldbus_message_path_get(msg);
3910    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3911    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3912    int x = 1, y = 1;
3913    AtspiCoordType coord_type;
3914    Eldbus_Message *ret;
3915 
3916    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3917 
3918    if (!eldbus_message_arguments_get(msg, "u", &coord_type))
3919      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
3920 
3921    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
3922    if (efl_gfx_entity_visible_get(obj))
3923      {
3924         if (type)
3925           efl_access_component_screen_position_get(obj, &x, &y);
3926         else
3927           evas_object_geometry_get(obj, &x, &y, NULL, NULL);
3928      }
3929 
3930    ret = eldbus_message_method_return_new(msg);
3931    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3932 
3933    eldbus_message_arguments_append(ret, "i", x);
3934    eldbus_message_arguments_append(ret, "i", y);
3935 
3936    return ret;
3937 }
3938 
3939 static Eldbus_Message *
_component_get_size(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3940 _component_get_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3941 {
3942    const char *obj_path = eldbus_message_path_get(msg);
3943    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3944    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3945    int x = -1, y = -1;
3946    Eldbus_Message *ret;
3947 
3948    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3949 
3950    if (efl_gfx_entity_visible_get(obj))
3951      evas_object_geometry_get(obj, NULL, NULL, &x, &y);
3952 
3953    ret = eldbus_message_method_return_new(msg);
3954    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3955 
3956    eldbus_message_arguments_append(ret, "i", x);
3957    eldbus_message_arguments_append(ret, "i", y);
3958 
3959    return ret;
3960 }
3961 
3962 static AtspiComponentLayer
_elm_layer_2_atspi_layer(int layer)3963 _elm_layer_2_atspi_layer(int layer)
3964 {
3965    if (layer <= ELM_OBJECT_LAYER_BACKGROUND) return ATSPI_LAYER_CANVAS;
3966    if (layer < ELM_OBJECT_LAYER_FOCUS) return ATSPI_LAYER_WIDGET;
3967    if (layer <= ELM_OBJECT_LAYER_TOOLTIP) return ATSPI_LAYER_POPUP;
3968 
3969    return ATSPI_LAYER_OVERLAY;
3970 }
3971 
3972 static Eldbus_Message *
_component_get_layer(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3973 _component_get_layer(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3974 {
3975    const char *obj_path = eldbus_message_path_get(msg);
3976    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
3977    Eo *obj = _bridge_object_from_path(bridge, obj_path);
3978    int layer = -1;
3979    Eldbus_Message *ret;
3980    AtspiComponentLayer atspi_layer;
3981 
3982    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
3983 
3984    if (efl_gfx_entity_visible_get(obj))
3985      layer = evas_object_layer_get(obj);
3986 
3987    ret = eldbus_message_method_return_new(msg);
3988    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
3989 
3990    atspi_layer = _elm_layer_2_atspi_layer(layer);
3991    eldbus_message_arguments_append(ret, "u", atspi_layer);
3992 
3993    return ret;
3994 }
3995 
3996 static Eldbus_Message *
_component_grab_focus(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)3997 _component_grab_focus(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
3998 {
3999    const char *obj_path = eldbus_message_path_get(msg);
4000    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4001    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4002    Eldbus_Message *ret;
4003    Eina_Bool focus = EINA_FALSE;
4004 
4005    if (!obj)
4006      return _dbus_invalid_ref_error_new(msg);
4007 
4008    focus = efl_access_component_focus_grab(obj);
4009 
4010    ret = eldbus_message_method_return_new(msg);
4011    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4012 
4013    eldbus_message_arguments_append(ret, "b", focus);
4014 
4015    return ret;
4016 }
4017 
4018 static Eldbus_Message *
_component_get_alpha(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)4019 _component_get_alpha(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4020 {
4021    const char *obj_path = eldbus_message_path_get(msg);
4022    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4023    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4024    Eldbus_Message *ret;
4025    double alpha = -1;
4026    int a;
4027 
4028    if (!obj)
4029      return _dbus_invalid_ref_error_new(msg);
4030 
4031    if (efl_gfx_entity_visible_get(obj))
4032      {
4033         evas_object_color_get(obj, NULL, NULL, NULL, &a);
4034         alpha = a / 255.0;
4035      }
4036 
4037    ret = eldbus_message_method_return_new(msg);
4038    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4039 
4040    eldbus_message_arguments_append(ret, "d", alpha);
4041 
4042    return ret;
4043 }
4044 
4045 static Eldbus_Message *
_component_set_extends(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)4046 _component_set_extends(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4047 {
4048    const char *obj_path = eldbus_message_path_get(msg);
4049    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4050    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4051    AtspiCoordType coord_type;
4052    Eldbus_Message *ret;
4053    int x, y, w, h;
4054    Eina_Bool result = EINA_FALSE;
4055 
4056    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
4057 
4058    if (!eldbus_message_arguments_get(msg, "iiiiu", &x, &y, &w, &h, &coord_type))
4059      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4060 
4061    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4062    result = efl_access_component_extents_set(obj, type, EINA_RECT(x, y, w, h));
4063 
4064    ret = eldbus_message_method_return_new(msg);
4065    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4066 
4067    eldbus_message_arguments_append(ret, "b", result);
4068 
4069    return ret;
4070 }
4071 
4072 static Eldbus_Message *
_component_set_position(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)4073 _component_set_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4074 {
4075    const char *obj_path = eldbus_message_path_get(msg);
4076    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4077    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4078    int x = -1, y = -1;
4079    Eina_Bool result = EINA_FALSE;
4080    AtspiCoordType coord_type;
4081    Eldbus_Message *ret;
4082 
4083    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
4084 
4085    if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
4086      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4087 
4088    Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
4089    if (efl_gfx_entity_visible_get(obj))
4090      {
4091         if (type)
4092           result = efl_access_component_screen_position_set(obj, x, y);
4093         else
4094           {
4095              result = EINA_TRUE;
4096              evas_object_move(obj, x, y);
4097           }
4098      }
4099 
4100    ret = eldbus_message_method_return_new(msg);
4101    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4102 
4103    eldbus_message_arguments_append(ret, "b", result);
4104 
4105    return ret;
4106 }
4107 
4108 static Eldbus_Message *
_component_set_size(const Eldbus_Service_Interface * iface EINA_UNUSED,const Eldbus_Message * msg)4109 _component_set_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
4110 {
4111    const char *obj_path = eldbus_message_path_get(msg);
4112    Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
4113    Eo *obj = _bridge_object_from_path(bridge, obj_path);
4114    int w, h;
4115    Eina_Bool result = EINA_TRUE;
4116    Eldbus_Message *ret;
4117 
4118    ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
4119 
4120    if (!eldbus_message_arguments_get(msg, "ii", &w, &h))
4121      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
4122 
4123    evas_object_resize(obj, w, h);
4124 
4125    ret = eldbus_message_method_return_new(msg);
4126    EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
4127 
4128    eldbus_message_arguments_append(ret, "b", result);
4129 
4130    return ret;
4131 }
4132 
4133 static const Eldbus_Method component_methods[] = {
4134    { "Contains", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "contains"}), _component_contains, 0 },
4135    { "GetAccessibleAtPoint", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"(so)", "accessible"}), _component_get_accessible_at_point, 0 },
4136    { "GetExtents", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"(iiii)", "extents"}), _component_get_extents, 0 },
4137    { "GetPosition", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"i", "x"}, {"i","y"}), _component_get_position, 0 },
4138    { "GetSize", NULL, ELDBUS_ARGS({"i", "w"}, {"i", "h"}), _component_get_size, 0 },
4139    { "GetLayer", NULL, ELDBUS_ARGS({"u", "layer"}), _component_get_layer, 0 },
4140 //   { "GetMDIZOrder", NULL, ELDBUS_ARGS({"n", "MDIZOrder"}), _component_get_mdizorder, 0 },
4141    { "GrabFocus", NULL, ELDBUS_ARGS({"b", "focus"}), _component_grab_focus, 0 },
4142    { "GetAlpha", NULL, ELDBUS_ARGS({"d", "alpha"}), _component_get_alpha, 0 },
4143    { "SetExtents", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "width"}, {"i", "height"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_extends, 0 },
4144    { "SetPosition", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_position, 0 },
4145    { "SetSize", ELDBUS_ARGS({"i", "width"}, {"i", "height"}), ELDBUS_ARGS({"b", "result"}), _component_set_size, 0 },
4146    { NULL, NULL, NULL, NULL, 0 }
4147 };
4148 
4149 static const Eldbus_Service_Interface_Desc component_iface_desc = {
4150    ATSPI_DBUS_INTERFACE_COMPONENT, component_methods, NULL, NULL, NULL, NULL
4151 };
4152 
4153 static void
_on_elm_atspi_bridge_app_register(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)4154 _on_elm_atspi_bridge_app_register(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
4155 {
4156    const char *errname, *errmsg;
4157 
4158    if (eldbus_message_error_get(msg, &errname, &errmsg))
4159      {
4160         ERR("%s %s", errname, errmsg);
4161         return;
4162      }
4163    DBG("Application successfully registered at ATSPI2 bus.");
4164 }
4165 
4166 EAPI Eina_Bool
_elm_atspi_bridge_app_register(Eo * bridge)4167 _elm_atspi_bridge_app_register(Eo *bridge)
4168 {
4169    Eo *root;
4170    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
4171 
4172    Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
4173                                     ATSPI_DBUS_PATH_ROOT,
4174                                     ATSPI_DBUS_INTERFACE_SOCKET,
4175                                     "Embed");
4176    Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
4177 
4178    root = efl_access_object_access_root_get();
4179    _bridge_iter_object_reference_append(bridge, iter, root);
4180    eldbus_connection_send(pd->a11y_bus, message, _on_elm_atspi_bridge_app_register, NULL, -1);
4181 
4182    return EINA_TRUE;
4183 }
4184 
4185 EAPI Eina_Bool
_elm_atspi_bridge_app_unregister(Eo * bridge)4186 _elm_atspi_bridge_app_unregister(Eo *bridge)
4187 {
4188    Eo *root;
4189    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
4190 
4191    root = efl_access_object_access_root_get();
4192 
4193    Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
4194                                     ATSPI_DBUS_PATH_ROOT,
4195                                     ATSPI_DBUS_INTERFACE_SOCKET,
4196                                     "Unembed");
4197    Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
4198 
4199    _bridge_iter_object_reference_append(bridge, iter, root);
4200    eldbus_connection_send(pd->a11y_bus, message, NULL, NULL, -1);
4201 
4202    return EINA_TRUE;
4203 }
4204 
4205 static void
_cache_register(Eo * obj)4206 _cache_register(Eo *obj)
4207 {
4208    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
4209    pd->cache_interface = eldbus_service_interface_register(pd->a11y_bus, CACHE_INTERFACE_PATH, &cache_iface_desc);
4210    eldbus_service_object_data_set(pd->cache_interface, ELM_ATSPI_BRIDGE_CLASS_NAME, obj);
4211 }
4212 
4213 static void
_set_broadcast_flag(const char * event,Eo * bridge)4214 _set_broadcast_flag(const char *event, Eo *bridge)
4215 {
4216    char **tokens;
4217    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4218 
4219    tokens = eina_str_split(event, ":", 3);
4220 
4221    if (!tokens) return;
4222 
4223    if (!strcmp(tokens[0], "Object"))
4224      {
4225         if (!tokens[1] || *tokens[1] == '\0') goto end; // do not handle "Object:*"
4226         else if (!strcmp(tokens[1], "StateChanged"))
4227           {
4228              if (!tokens[2] || *tokens[2] == '\0')
4229                pd->object_state_broadcast_mask = -1; // broadcast all
4230              eina_str_tolower(&tokens[2]);
4231              struct atspi_state_desc *sd = eina_hash_find(pd->state_hash, tokens[2]);
4232              if (sd)
4233                STATE_TYPE_SET(pd->object_state_broadcast_mask, sd->elm_state);
4234           }
4235         else if (!strcmp(tokens[1], "PropertyChange"))
4236           {
4237              if (!tokens[2] || *tokens[2] == '\0')
4238                pd->object_property_broadcast_mask = -1; //broadcast all
4239              else if (!strcmp(tokens[2], "AccessibleValue"))
4240                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_VALUE);
4241              else if (!strcmp(tokens[2], "AccessibleName"))
4242                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_NAME);
4243              else if (!strcmp(tokens[2], "AccessibleDescription"))
4244                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_DESCRIPTION);
4245              else if (!strcmp(tokens[2], "AccessibleParent"))
4246                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_PARENT);
4247              else if (!strcmp(tokens[2], "AccessibleRole"))
4248                STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_ROLE);
4249           }
4250         else if (!strcmp(tokens[1], "ChildrenChanged"))
4251           {
4252              if (!tokens[2] || *tokens[2] == '\0')
4253                pd->object_children_broadcast_mask = -1; // broadcast all
4254              else if (!strcmp(tokens[2], "add"))
4255                STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_ADDED);
4256              else if (!strcmp(tokens[2], "remove"))
4257                STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_REMOVED);
4258           }
4259         else if (!strcmp(tokens[1], "TextChanged"))
4260           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED);
4261         else if (!strcmp(tokens[1], "TextCaretMoved"))
4262           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED);
4263         else if (!strcmp(tokens[1], "TextBoundsChanged"))
4264           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED);
4265         else if (!strcmp(tokens[1], "TextSelectionChanged"))
4266           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED);
4267         else if (!strcmp(tokens[1], "TextAttributesChanged"))
4268           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED);
4269         else if (!strcmp(tokens[1], "VisibleDataChanged"))
4270           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED);
4271         else if (!strcmp(tokens[1], "ActiveDescendantChanged"))
4272           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED);
4273         else if (!strcmp(tokens[1], "SelectionChanged"))
4274           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_SELECTION_CHANGED);
4275         else if (!strcmp(tokens[1], "BoundsChanged"))
4276           STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_BOUNDS_CHANGED);
4277      }
4278    else if (!strcmp(tokens[0], "Window"))
4279      {
4280         if (!tokens[1] || *tokens[1] == '\0')
4281           pd->window_signal_broadcast_mask = -1; // broadcast all
4282         else if (!strcmp(tokens[1], "Create"))
4283           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_CREATE);
4284         else if (!strcmp(tokens[1], "Destroy"))
4285           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DESTROY);
4286         else if (!strcmp(tokens[1], "Activate"))
4287           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_ACTIVATE);
4288         else if (!strcmp(tokens[1], "Deactivate"))
4289           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DEACTIVATE);
4290         else if (!strcmp(tokens[1], "Maximize"))
4291           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MAXIMIZE);
4292         else if (!strcmp(tokens[1], "Minimize"))
4293           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MINIMIZE);
4294         else if (!strcmp(tokens[1], "Resize"))
4295           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESIZE);
4296         else if (!strcmp(tokens[1], "Restore"))
4297           STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESTORE);
4298      }
4299 
4300 end:
4301    free(tokens[0]);
4302    free(tokens);
4303 }
4304 
4305 static void
_registered_listeners_get(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending)4306 _registered_listeners_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
4307 {
4308    const char *event, *bus;
4309    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4310    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
4311 
4312    DBG("Updating registered ATSPI signals list.");
4313    pd->object_broadcast_mask = 0;
4314    pd->object_children_broadcast_mask = 0;
4315    pd->object_property_broadcast_mask = 0;
4316    pd->object_state_broadcast_mask = 0;
4317    pd->window_signal_broadcast_mask = 0;
4318 
4319    if (eldbus_message_error_get(msg, &event, &bus))
4320      {
4321         WRN("%s %s", event, bus);
4322         return;
4323      }
4324    Eldbus_Message_Iter *iter, *siter;
4325    if (!eldbus_message_arguments_get(msg, "a(ss)", &iter))
4326      {
4327         ERR("Invalid answer type from GetRegisteredEvents method call!");
4328         return;
4329      }
4330    while (eldbus_message_iter_get_and_next(iter, 'r', &siter))
4331      {
4332         if (!eldbus_message_iter_arguments_get(siter, "ss", &bus, &event))
4333           ERR("Cannot get bus and event from registered listener");
4334         else _set_broadcast_flag(event, data);
4335      }
4336 
4337    if (!pd->connected)
4338       efl_event_callback_legacy_call(data, ELM_ATSPI_BRIDGE_EVENT_CONNECTED, NULL);
4339    pd->connected = EINA_TRUE;
4340 }
4341 
4342 static void
_registered_events_list_update(Eo * bridge)4343 _registered_events_list_update(Eo *bridge)
4344 {
4345    Eldbus_Message *msg;
4346    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4347    Eldbus_Pending *p;
4348 
4349    msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "GetRegisteredEvents");
4350    p = eldbus_connection_send(pd->a11y_bus, msg, _registered_listeners_get, bridge, -1);
4351    pd->pending_requests = eina_list_append(pd->pending_requests, p);
4352 }
4353 
4354 static void
_handle_listener_change(void * data,const Eldbus_Message * msg EINA_UNUSED)4355 _handle_listener_change(void *data, const Eldbus_Message *msg EINA_UNUSED)
4356 {
4357    _registered_events_list_update(data);
4358 }
4359 
4360 static void
_state_changed_signal_send(void * data,const Efl_Event * event)4361 _state_changed_signal_send(void *data, const Efl_Event *event)
4362 {
4363    Efl_Access_Event_State_Changed_Data *state_data = event->info;
4364    const char *type_desc;
4365    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4366 
4367    if (!STATE_TYPE_GET(pd->object_state_broadcast_mask, state_data->type))
4368      {
4369         efl_event_callback_stop(event->object);
4370         return;
4371      }
4372 
4373    if ((state_data->type > EFL_ACCESS_STATE_TYPE_LAST_DEFINED) ||
4374         (int)state_data->type < 0)
4375      {
4376         efl_event_callback_stop(event->object);
4377         return;
4378      }
4379 
4380    type_desc = elm_states_to_atspi_state[state_data->type].name;
4381 
4382    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4383                        &_event_obj_signals[ATSPI_OBJECT_EVENT_STATE_CHANGED], type_desc, state_data->new_value, 0, NULL);
4384 }
4385 
4386 static void
_bounds_changed_signal_send(void * data,const Efl_Event * event)4387 _bounds_changed_signal_send(void *data, const Efl_Event *event)
4388 {
4389    Efl_Access_Event_Geometry_Changed_Data *geo_data = event->info;
4390 
4391    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4392                        &_event_obj_signals[ATSPI_OBJECT_EVENT_BOUNDS_CHANGED], "", 0, 0, "(iiii)",
4393                        geo_data->x, geo_data->y, geo_data->width, geo_data->height);
4394 }
4395 
4396 static void
_property_changed_signal_send(void * data,const Efl_Event * event)4397 _property_changed_signal_send(void *data, const Efl_Event *event)
4398 {
4399    const char *property = event->info;
4400    char *atspi_desc;
4401    enum _Atspi_Object_Property prop = ATSPI_OBJECT_PROPERTY_LAST;
4402 
4403    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4404 
4405    if (!strcmp(property, "parent"))
4406      {
4407         prop = ATSPI_OBJECT_PROPERTY_PARENT;
4408         atspi_desc = "accessible-parent";
4409      }
4410    else if (!strcmp(property, "i18n_name"))
4411      {
4412         prop = ATSPI_OBJECT_PROPERTY_NAME;
4413         atspi_desc = "accessible-name";
4414      }
4415    else if (!strcmp(property, "description"))
4416      {
4417         prop = ATSPI_OBJECT_PROPERTY_DESCRIPTION;
4418         atspi_desc = "accessible-description";
4419      }
4420    else if (!strcmp(property, "role"))
4421      {
4422         prop = ATSPI_OBJECT_PROPERTY_ROLE;
4423         atspi_desc = "accessible-role";
4424      }
4425    else if (!strcmp(property, "value"))
4426      {
4427         prop = ATSPI_OBJECT_PROPERTY_VALUE;
4428         atspi_desc = "accessible-value";
4429      }
4430    if (prop == ATSPI_OBJECT_PROPERTY_LAST)
4431      {
4432         ERR("Unrecognized property name!");
4433         efl_event_callback_stop(event->object);
4434         return;
4435      }
4436    if (!STATE_TYPE_GET(pd->object_property_broadcast_mask, prop))
4437      {
4438         DBG("Masking property %s changed event.", property);
4439         efl_event_callback_stop(event->object);
4440         return;
4441      }
4442 
4443    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4444                        &_event_obj_signals[ATSPI_OBJECT_EVENT_PROPERTY_CHANGED], atspi_desc, 0, 0, NULL);
4445 }
4446 
4447 static void
_value_property_changed_signal_send(void * data,const Efl_Event * event)4448 _value_property_changed_signal_send(void *data, const Efl_Event *event)
4449 {
4450    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4451 
4452    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4453                        &_event_obj_signals[ATSPI_OBJECT_EVENT_PROPERTY_CHANGED], "accessible-value", 0, 0, NULL);
4454 }
4455 
4456 static void
_visible_data_changed_signal_send(void * data,const Efl_Event * event)4457 _visible_data_changed_signal_send(void *data, const Efl_Event *event)
4458 {
4459    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4460 
4461    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED))
4462      {
4463         efl_event_callback_stop(event->object);
4464         return;
4465      }
4466 
4467    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4468                        &_event_obj_signals[ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED], "",
4469                        0, 0, NULL);
4470 }
4471 
4472 static void
_active_descendant_changed_signal_send(void * data,const Efl_Event * event)4473 _active_descendant_changed_signal_send(void *data, const Efl_Event *event)
4474 {
4475    Eo *child = event->info;
4476    int idx;
4477 
4478    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4479 
4480    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED))
4481      {
4482         efl_event_callback_stop(event->object);
4483         return;
4484      }
4485 
4486    idx = efl_access_object_index_in_parent_get(child);
4487 
4488    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4489                        &_event_obj_signals[ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED], "",
4490                        idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), child);
4491 }
4492 
4493 static void
_children_changed_signal_send(void * data,const Efl_Event * event)4494 _children_changed_signal_send(void *data, const Efl_Event *event)
4495 {
4496    const char *atspi_desc = NULL;
4497    Efl_Access_Event_Children_Changed_Data *ev_data = event->info;
4498    int idx;
4499    enum _Atspi_Object_Child_Event_Type type;
4500 
4501    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4502 
4503    if (ev_data->is_added)
4504      {
4505         type = ATSPI_OBJECT_CHILD_ADDED;
4506         atspi_desc = "add";
4507      }
4508    else
4509      {
4510         type = ATSPI_OBJECT_CHILD_REMOVED;
4511         atspi_desc = "remove";
4512      }
4513 
4514    if (!STATE_TYPE_GET(pd->object_children_broadcast_mask, type))
4515      {
4516         efl_event_callback_stop(event->object);
4517         return;
4518      }
4519 
4520    idx = efl_access_object_index_in_parent_get(ev_data->child);
4521    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4522                        &_event_obj_signals[ATSPI_OBJECT_EVENT_CHILDREN_CHANGED], atspi_desc,
4523                        idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), ev_data->child);
4524 }
4525 
4526 static void
_window_signal_send(void * data,const Efl_Event * event)4527 _window_signal_send(void *data, const Efl_Event *event)
4528 {
4529    enum _Atspi_Window_Signals type;
4530 
4531    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4532 
4533    if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_CREATED)
4534      type = ATSPI_WINDOW_EVENT_CREATE;
4535    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_DESTROYED)
4536      type = ATSPI_WINDOW_EVENT_DESTROY;
4537    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_DEACTIVATED)
4538      type = ATSPI_WINDOW_EVENT_DEACTIVATE;
4539    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_ACTIVATED)
4540      type = ATSPI_WINDOW_EVENT_ACTIVATE;
4541    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_MAXIMIZED)
4542      type = ATSPI_WINDOW_EVENT_MAXIMIZE;
4543    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_MINIMIZED)
4544      type = ATSPI_WINDOW_EVENT_MINIMIZE;
4545    else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_RESTORED)
4546      type = ATSPI_WINDOW_EVENT_RESTORE;
4547    else
4548      {
4549         efl_event_callback_stop(event->object);
4550         return;
4551      }
4552 
4553    if (!STATE_TYPE_GET(pd->window_signal_broadcast_mask, type))
4554      {
4555         efl_event_callback_stop(event->object);
4556         return;
4557      }
4558 
4559    if (!pd->a11y_bus)
4560      {
4561         ERR("A11Y connection closed. Unable to send ATSPI event.");
4562         efl_event_callback_stop(event->object);
4563         return;
4564      }
4565 
4566    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_WINDOW,
4567                        &_window_obj_signals[type], "", 0, 0, "i", 0);
4568 }
4569 
4570 static void
_selection_signal_send(void * data,const Efl_Event * event)4571 _selection_signal_send(void *data, const Efl_Event *event)
4572 {
4573    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4574 
4575    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_SELECTION_CHANGED))
4576      {
4577         efl_event_callback_stop(event->object);
4578         return;
4579      }
4580 
4581    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4582                        &_event_obj_signals[ATSPI_OBJECT_EVENT_SELECTION_CHANGED], "", 0, 0, "i", 0);
4583 }
4584 
_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,...)4585 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, ...)
4586 {
4587    Eldbus_Message *msg;
4588    Eldbus_Message_Iter *iter , *iter_stack[64], *iter_struct;
4589    va_list va;
4590    Eo *atspi_obj, *root;
4591    const char *path;
4592    int top = 0;
4593 
4594    EINA_SAFETY_ON_NULL_RETURN(infc);
4595    EINA_SAFETY_ON_NULL_RETURN(signal);
4596    EINA_SAFETY_ON_NULL_RETURN(minor);
4597    EINA_SAFETY_ON_NULL_RETURN(obj);
4598    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4599 
4600    path = _path_from_object(obj);
4601    root = efl_access_object_access_root_get();
4602 
4603    msg = eldbus_message_signal_new(path, infc, signal->name);
4604    if (!msg) return;
4605 
4606    va_start(va, variant_sig);
4607 
4608    iter = eldbus_message_iter_get(msg);
4609    eldbus_message_iter_arguments_append(iter, "sii", minor, det1, det2);
4610 
4611    if (variant_sig)
4612      {
4613         iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', variant_sig);
4614 
4615         const char *tmp = variant_sig;
4616         while (*tmp)
4617           {
4618              switch (*tmp)
4619                {
4620                 case '(':
4621                    iter_stack[top + 1] = eldbus_message_iter_container_new(iter_stack[top], 'r', NULL);
4622                    top++;
4623                    break;
4624                 case 's':
4625                    eldbus_message_iter_basic_append(iter_stack[top], 's', va_arg(va, char*));
4626                    break;
4627                 case 'i':
4628                    eldbus_message_iter_basic_append(iter_stack[top], 'i', va_arg(va, int));
4629                    break;
4630                 case 'o':
4631                    atspi_obj = va_arg(va, Eo*);
4632                    path = _path_from_object(atspi_obj);
4633                    eldbus_message_iter_basic_append(iter_stack[top], 'o', path);
4634                    break;
4635                 case ')':
4636                    eldbus_message_iter_container_close(iter_stack[top - 1], iter_stack[top]);
4637                    top--;
4638                    break;
4639                 default:
4640                    ERR("Not supported d-bus type: %c.", *tmp);
4641                    break;
4642                }
4643              tmp++;
4644           }
4645      }
4646    else // AT-SPI implementation forces checks on variant in signature even if not used.
4647      {
4648         iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', "i");
4649         eldbus_message_iter_basic_append(iter_stack[top], 'i', 0);
4650      }
4651 
4652    va_end(va);
4653    if (top != 0)
4654      ERR("Invalid d-bus signature: () do not match.");
4655 
4656    eldbus_message_iter_container_close(iter, iter_stack[0]);
4657 
4658    iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
4659    path = _path_from_object(root);
4660    eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(pd->a11y_bus));
4661    eldbus_message_iter_basic_append(iter_struct, 'o', path);
4662    eldbus_message_iter_container_close(iter, iter_struct);
4663 
4664    eldbus_connection_send(pd->a11y_bus, msg, NULL, NULL, -1);
4665    DBG("Send %s.%s[%s,%d,%d]", infc, signal->name, minor, det1, det2);
4666 }
4667 
4668 static void
_text_caret_moved_send(void * data,const Efl_Event * event)4669 _text_caret_moved_send(void *data, const Efl_Event *event)
4670 {
4671    int cursor_pos = 0;
4672 
4673    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4674 
4675    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED))
4676      return;
4677 
4678    cursor_pos = efl_access_text_caret_offset_get(event->object);
4679 
4680    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4681                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED], "", cursor_pos, 0, NULL);
4682 }
4683 
4684 static void
_text_text_inserted_send(void * data,const Efl_Event * event)4685 _text_text_inserted_send(void *data, const Efl_Event *event)
4686 {
4687    Efl_Access_Text_Change_Info *info = event->info;
4688 
4689    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4690 
4691    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
4692      return;
4693 
4694    if (!info->content)
4695      {
4696         WRN("Try to send signal with NULL value");
4697         return;
4698      }
4699 
4700    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4701                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "insert", info->pos, info->len, "s", info->content);
4702 }
4703 
4704 static void
_text_text_removed_send(void * data,const Efl_Event * event)4705 _text_text_removed_send(void *data, const Efl_Event *event)
4706 {
4707    Efl_Access_Text_Change_Info *info = event->info;
4708 
4709    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4710 
4711    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
4712      return;
4713 
4714    if (!info->content)
4715      {
4716         WRN("Try to send signal with NULL value");
4717         return;
4718      }
4719 
4720    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4721                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "delete", info->pos, info->len, "s", info->content);
4722 }
4723 
4724 static void
_text_selection_changed_send(void * data,const Efl_Event * event)4725 _text_selection_changed_send(void *data, const Efl_Event *event)
4726 {
4727    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4728 
4729    if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED))
4730      return;
4731 
4732    _bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
4733                        &_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED], "", 0, 0, NULL);
4734 }
4735 
4736 static void
_event_handlers_register(Eo * bridge)4737 _event_handlers_register(Eo *bridge)
4738 {
4739    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4740 
4741    _registered_events_list_update(bridge);
4742 
4743    // register signal handlers in order to update list of registered listeners of ATSPI-Clients
4744    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);
4745    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);
4746 
4747    pd->key_flr = ecore_event_filter_add(NULL, _elm_atspi_bridge_key_filter, NULL, bridge);
4748 }
4749 
4750 static void
_bridge_object_unregister(Eo * bridge,Eo * obj)4751 _bridge_object_unregister(Eo *bridge, Eo *obj)
4752 {
4753    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4754 
4755    eina_hash_del(pd->cache, &obj, obj);
4756 }
4757 
4758 static void
_on_object_add(void * data,const Efl_Event * event)4759 _on_object_add(void *data, const Efl_Event *event)
4760 {
4761    Eldbus_Message *sig;
4762    Eldbus_Message_Iter *iter;
4763 
4764    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4765 
4766    sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_ADDED);
4767    iter = eldbus_message_iter_get(sig);
4768    _cache_item_reference_append_cb(data, event->object, iter);
4769 
4770    eldbus_service_signal_send(pd->cache_interface, sig);
4771 }
4772 
4773 static void
_on_object_del(void * data,const Efl_Event * event)4774 _on_object_del(void *data, const Efl_Event *event)
4775 {
4776    Eldbus_Message *sig;
4777 
4778    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4779 
4780    _bridge_object_unregister(data, event->object);
4781 
4782    sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_REMOVED);
4783    Eldbus_Message_Iter *iter = eldbus_message_iter_get(sig);
4784    _bridge_iter_object_reference_append(data, iter, event->object);
4785    eldbus_service_signal_send(pd->cache_interface, sig);
4786 }
4787 
4788 static void
_interfaces_unregister(Eo * bridge)4789 _interfaces_unregister(Eo *bridge)
4790 {
4791     ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4792 
4793 #define INTERFACE_SAFE_FREE(ifc) \
4794    if (ifc) \
4795       eldbus_service_interface_unregister(ifc); \
4796    ifc = NULL;
4797 
4798    INTERFACE_SAFE_FREE(pd->interfaces.accessible);
4799    INTERFACE_SAFE_FREE(pd->interfaces.application);
4800    INTERFACE_SAFE_FREE(pd->interfaces.action);
4801    INTERFACE_SAFE_FREE(pd->interfaces.component);
4802    INTERFACE_SAFE_FREE(pd->interfaces.collection);
4803    INTERFACE_SAFE_FREE(pd->interfaces.editable_text);
4804    INTERFACE_SAFE_FREE(pd->interfaces.image);
4805    INTERFACE_SAFE_FREE(pd->interfaces.selection);
4806    INTERFACE_SAFE_FREE(pd->interfaces.text);
4807    INTERFACE_SAFE_FREE(pd->interfaces.value);
4808 }
4809 
4810 static void
_a11y_connection_shutdown(Eo * bridge)4811 _a11y_connection_shutdown(Eo *bridge)
4812 {
4813    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4814    Eldbus_Pending *pending;
4815 
4816    if (pd->connected)
4817       _elm_atspi_bridge_app_unregister(bridge);
4818 
4819    if (pd->cache)
4820      eina_hash_free(pd->cache);
4821    pd->cache = NULL;
4822 
4823    if (pd->cache_interface)
4824      eldbus_service_object_unregister(pd->cache_interface);
4825    pd->cache_interface = NULL;
4826 
4827    _interfaces_unregister(bridge);
4828 
4829    if (pd->key_flr) ecore_event_filter_del(pd->key_flr);
4830    pd->key_flr = NULL;
4831 
4832    if (pd->register_hdl) eldbus_signal_handler_del(pd->register_hdl);
4833    pd->register_hdl = NULL;
4834 
4835    if (pd->unregister_hdl) eldbus_signal_handler_del(pd->unregister_hdl);
4836    pd->unregister_hdl = NULL;
4837 
4838    EINA_LIST_FREE(pd->pending_requests, pending)
4839       eldbus_pending_cancel(pending);
4840    pd->pending_requests = NULL;
4841 
4842    if (pd->a11y_bus) eldbus_connection_unref(pd->a11y_bus);
4843    pd->a11y_bus = NULL;
4844 
4845    if (pd->state_hash) eina_hash_free(pd->state_hash);
4846    pd->state_hash = NULL;
4847 
4848    if (pd->event_hash) eina_hash_free(pd->event_hash);
4849    pd->event_hash = NULL;
4850 
4851    efl_access_object_event_handler_del(pd->event_hdlr);
4852    pd->event_hdlr = NULL;
4853 
4854    efl_event_callback_legacy_call(bridge, ELM_ATSPI_BRIDGE_EVENT_DISCONNECTED, NULL);
4855    pd->connected = EINA_FALSE;
4856 }
4857 
_disconnect_cb(void * data,Eldbus_Connection * conn EINA_UNUSED,void * event_info EINA_UNUSED)4858 static void _disconnect_cb(void *data, Eldbus_Connection *conn EINA_UNUSED, void *event_info EINA_UNUSED)
4859 {
4860    _a11y_connection_shutdown(data);
4861 }
4862 
4863 static void
_interfaces_register(Eo * bridge)4864 _interfaces_register(Eo *bridge)
4865 {
4866    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4867 
4868    pd->interfaces.accessible =
4869       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &accessible_iface_desc);
4870    eldbus_service_object_data_set(pd->interfaces.accessible, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4871 
4872    pd->interfaces.application =
4873       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &application_iface_desc);
4874    eldbus_service_object_data_set(pd->interfaces.application, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4875 
4876    pd->interfaces.action =
4877       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &action_iface_desc);
4878    eldbus_service_object_data_set(pd->interfaces.action, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4879 
4880    pd->interfaces.component =
4881       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &component_iface_desc);
4882    eldbus_service_object_data_set(pd->interfaces.component, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4883 
4884    pd->interfaces.collection =
4885       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &collection_iface_desc);
4886    eldbus_service_object_data_set(pd->interfaces.collection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4887 
4888    pd->interfaces.editable_text =
4889       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &editable_text_iface_desc);
4890    eldbus_service_object_data_set(pd->interfaces.editable_text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4891 
4892    pd->interfaces.image =
4893       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &image_iface_desc);
4894    eldbus_service_object_data_set(pd->interfaces.image, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4895 
4896    pd->interfaces.selection =
4897       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &selection_iface_desc);
4898    eldbus_service_object_data_set(pd->interfaces.selection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4899 
4900    pd->interfaces.text =
4901       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &text_iface_desc);
4902    eldbus_service_object_data_set(pd->interfaces.text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4903 
4904    pd->interfaces.value =
4905       eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &value_iface_desc);
4906    eldbus_service_object_data_set(pd->interfaces.value, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
4907 }
4908 
4909 static void
_bridge_accessible_event_dispatch(void * data,const Efl_Event * event)4910 _bridge_accessible_event_dispatch(void *data, const Efl_Event *event)
4911 {
4912    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4913 
4914    _bridge_object_register(data, event->object);
4915 
4916    Efl_Event_Cb cb = eina_hash_find(pd->event_hash, &event->desc);
4917    return cb ? cb(data, event) : EINA_TRUE;
4918 }
4919 
4920 static void
_a11y_bus_initialize(Eo * obj,const char * socket_addr)4921 _a11y_bus_initialize(Eo *obj, const char *socket_addr)
4922 {
4923    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
4924 
4925    pd->a11y_bus = eldbus_private_address_connection_get(socket_addr);
4926    if (!pd->a11y_bus)
4927      return;
4928 
4929    eldbus_connection_event_callback_add(pd->a11y_bus, ELDBUS_CONNECTION_EVENT_DISCONNECTED, _disconnect_cb, obj);
4930 
4931    // init data structures
4932    pd->cache = eina_hash_pointer_new(NULL);
4933    pd->state_hash = _elm_atspi_state_hash_build();
4934    pd->event_hash = _elm_atspi_event_hash_build();
4935 
4936    // dbus init
4937    _cache_register(obj);
4938    _interfaces_register(obj);
4939    _event_handlers_register(obj);
4940    _elm_atspi_bridge_app_register(obj);
4941 
4942    // register accessible object event listener
4943    pd->event_hdlr = efl_access_object_event_handler_add(_bridge_accessible_event_dispatch, obj);
4944 }
4945 
4946 static void
_a11y_bus_address_get(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending)4947 _a11y_bus_address_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
4948 {
4949    const char *errname, *errmsg, *sock_addr = NULL;
4950    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4951 
4952    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
4953 
4954    if (eldbus_message_error_get(msg, &errname, &errmsg))
4955      {
4956         ERR("%s %s", errname, errmsg);
4957         return;
4958      }
4959 
4960    if (!eldbus_message_arguments_get(msg, "s", &sock_addr) || !sock_addr)
4961      {
4962         ERR("Could not get A11Y Bus socket address.");
4963         return;
4964      }
4965 
4966    _a11y_bus_initialize((Eo*)data, sock_addr);
4967 }
4968 
_a11y_connection_init(Eo * bridge)4969 static void _a11y_connection_init(Eo *bridge)
4970 {
4971    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4972    Eina_Bool is_connected;
4973 
4974    is_connected = elm_obj_atspi_bridge_connected_get(bridge);
4975 
4976    if (is_connected) return;
4977 
4978    Eldbus_Message *m = eldbus_object_method_call_new(pd->bus_obj, A11Y_DBUS_INTERFACE, "GetAddress");
4979    Eldbus_Pending *p = eldbus_object_send(pd->bus_obj, m, _a11y_bus_address_get, bridge, 100);
4980 
4981    if (p)
4982       pd->pending_requests = eina_list_append(pd->pending_requests, p);
4983 }
4984 
4985 static void
_screen_reader_enabled_get(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending)4986 _screen_reader_enabled_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
4987 {
4988    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4989    const char *errname, *errmsg;
4990    Eina_Bool is_enabled;
4991    Eldbus_Message_Iter *variant;
4992 
4993    pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
4994 
4995    if (eldbus_message_error_get(msg, &errname, &errmsg))
4996      {
4997         /* don't print warnings for user-canceled calls */
4998         if (!eina_streq(errname, "org.enlightenment.DBus.Canceled"))
4999           WRN("%s %s", errname, errmsg);
5000         return;
5001      }
5002    if (!eldbus_message_arguments_get(msg, "v", &variant))
5003      {
5004         ERR("'ScreenReaderEnabled' not packed into variant.");
5005         return;
5006      }
5007    if (!eldbus_message_iter_arguments_get(variant, "b", &is_enabled))
5008      {
5009         ERR("Could not get 'ScreenReaderEnabled' boolean property");
5010         return;
5011      }
5012 
5013    if (is_enabled)
5014      _a11y_connection_init(data);
5015    else
5016      DBG("AT-SPI2 stack not enabled.");
5017 }
5018 
_bridge_object_register(Eo * bridge,Eo * obj)5019 static void _bridge_object_register(Eo *bridge, Eo *obj)
5020 {
5021    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
5022 
5023    if (!efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
5024      {
5025         WRN("Unable to register class w/o Efl_Access_Object!");
5026         return;
5027      }
5028 
5029    if (eina_hash_find(pd->cache, &obj))
5030         return;
5031 
5032    eina_hash_add(pd->cache, &obj, obj);
5033 }
5034 
5035 void
_elm_atspi_bridge_init(void)5036 _elm_atspi_bridge_init(void)
5037 {
5038    if (!_init_count)
5039      {
5040         _instance = efl_add_ref(ELM_ATSPI_BRIDGE_CLASS, NULL);
5041         _init_count = 1;
5042      }
5043 }
5044 
5045 EAPI Eo*
_elm_atspi_bridge_get(void)5046 _elm_atspi_bridge_get(void)
5047 {
5048    return _instance;
5049 }
5050 
5051 void
_elm_atspi_bridge_shutdown(void)5052 _elm_atspi_bridge_shutdown(void)
5053 {
5054    if (_init_count)
5055      {
5056         efl_unref(_instance);
5057         _init_count = 0;
5058      }
5059    _efl_access_shutdown();
5060 }
5061 
5062 static Key_Event_Info*
_key_event_info_new(int event_type,const Ecore_Event_Key * data,Eo * bridge)5063 _key_event_info_new(int event_type, const Ecore_Event_Key *data, Eo *bridge)
5064 {
5065    Key_Event_Info *ret;
5066    EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
5067 
5068    ret = calloc(1, sizeof(Key_Event_Info));
5069 
5070    ret->type = event_type;
5071    ret->event = *data;
5072    ret->bridge = bridge;
5073 
5074    ret->event.keyname = eina_stringshare_add(data->keyname);
5075    ret->event.key = eina_stringshare_add(data->key);
5076    ret->event.string = eina_stringshare_add(data->string);
5077    ret->event.compose = eina_stringshare_add(data->compose);
5078    ret->event.modifiers = data->modifiers;
5079 
5080    // not sure why it is here, but explicite keep it NULLed.
5081    ret->event.data = NULL;
5082 
5083    return ret;
5084 }
5085 
5086 static void
_key_event_info_free(Key_Event_Info * data)5087 _key_event_info_free(Key_Event_Info *data)
5088 {
5089    EINA_SAFETY_ON_NULL_RETURN(data);
5090 
5091    eina_stringshare_del(data->event.keyname);
5092    eina_stringshare_del(data->event.key);
5093    eina_stringshare_del(data->event.string);
5094    eina_stringshare_del(data->event.compose);
5095 
5096    free(data);
5097 }
5098 
5099 static short
_ecore_modifiers_2_atspi(unsigned int modifiers)5100 _ecore_modifiers_2_atspi(unsigned int modifiers)
5101 {
5102    short ret = 0;
5103 
5104    if (modifiers & ECORE_EVENT_MODIFIER_SHIFT)
5105      ret |= (1 << ATSPI_MODIFIER_SHIFT);
5106    if (modifiers & ECORE_EVENT_MODIFIER_CAPS)
5107      ret |= (1 << ATSPI_MODIFIER_SHIFTLOCK);
5108    if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
5109      ret |= (1 << ATSPI_MODIFIER_CONTROL);
5110    if (modifiers & ECORE_EVENT_MODIFIER_ALT)
5111      ret |= (1 << ATSPI_MODIFIER_ALT);
5112    if (modifiers & ECORE_EVENT_MODIFIER_WIN)
5113      ret |= (1 << ATSPI_MODIFIER_META);
5114    if (modifiers & ECORE_EVENT_MODIFIER_NUM)
5115      ret |= (1 << ATSPI_MODIFIER_NUMLOCK);
5116 
5117    return ret;
5118 }
5119 
5120 static void
_iter_marshall_key_event(Eldbus_Message_Iter * iter,Key_Event_Info * data)5121 _iter_marshall_key_event(Eldbus_Message_Iter *iter, Key_Event_Info *data)
5122 {
5123    Eldbus_Message_Iter *struct_iter;
5124    EINA_SAFETY_ON_NULL_RETURN(data);
5125 
5126    struct_iter = eldbus_message_iter_container_new(iter, 'r', NULL);
5127 
5128    const char *str = data->event.keyname ? data->event.keyname : "";
5129    int is_text = data->event.keyname ? 1 : 0;
5130    int type;
5131    if (data->type == ECORE_EVENT_KEY_DOWN)
5132      type = ATSPI_KEY_PRESSED_EVENT;
5133    else
5134      type = ATSPI_KEY_RELEASED_EVENT;
5135 
5136    eldbus_message_iter_arguments_append(struct_iter, "uinnisb", type, 0, data->event.keycode, _ecore_modifiers_2_atspi(data->event.modifiers), data->event.timestamp, str, is_text);
5137    eldbus_message_iter_container_close(iter, struct_iter);
5138 }
5139 
5140 static Eina_Bool
_elm_atspi_bridge_key_filter(void * data,void * loop EINA_UNUSED,int type,void * event)5141 _elm_atspi_bridge_key_filter(void *data, void *loop EINA_UNUSED, int type, void *event)
5142 {
5143    Ecore_Event_Key *key_event = event;
5144    Key_Event_Info *ke;
5145    Eldbus_Object *dobj;
5146    Eldbus_Proxy *proxy;
5147    Eldbus_Message *req;
5148    Eldbus_Message_Iter *iter;
5149    Eldbus_Message *reply;
5150    Eina_Bool ret = EINA_TRUE;
5151    const char *errname = NULL, *errmsg = NULL;
5152    Eo *bridge = data;
5153 
5154    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_TRUE);
5155 
5156    if ((type != ECORE_EVENT_KEY_DOWN) && (type != ECORE_EVENT_KEY_UP)) return EINA_TRUE;
5157 
5158    if (!(dobj = eldbus_object_get(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_DEC)))
5159      {
5160         ERR("Failed to create eldbus object for: " ATSPI_DBUS_PATH_DEC);
5161         return EINA_TRUE;
5162      }
5163 
5164    if (!(proxy = eldbus_proxy_get(dobj, ATSPI_DBUS_INTERFACE_DEC)))
5165      {
5166         ERR("Failed to create proxy object for: " ATSPI_DBUS_INTERFACE_DEC);
5167         return EINA_TRUE;
5168      }
5169 
5170    if (!(req = eldbus_proxy_method_call_new(proxy, "NotifyListenersSync")))
5171      {
5172         ERR("Failed to create method call on: " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync");
5173         return EINA_TRUE;
5174      }
5175 
5176    ke = _key_event_info_new(type, key_event, bridge);
5177    if (!ke)
5178      {
5179         eldbus_message_unref(req);
5180         return EINA_TRUE;
5181      }
5182 
5183    iter = eldbus_message_iter_get(req);
5184    _iter_marshall_key_event(iter, ke);
5185    _key_event_info_free(ke);
5186 
5187    // timeout should be kept reasonably low to avoid delays
5188    if (!(reply = eldbus_proxy_send_and_block(proxy, req, 100)))
5189      {
5190         ERR("Unable to call method " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync");
5191         return EINA_TRUE;
5192      }
5193 
5194    if (eldbus_message_error_get(reply, &errname, &errmsg))
5195      ERR("Error in call method " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync" ": %s %s", errname, errmsg);
5196    else
5197      if (!eldbus_message_arguments_get(reply, "b", &ret))
5198        ERR("Invalid answer signature");
5199 
5200    eldbus_message_unref(reply);
5201 
5202    if (ret)
5203      return EINA_FALSE;
5204 
5205    return EINA_FALSE;
5206 }
5207 
5208 EOLIAN Eina_Bool
_elm_atspi_bridge_connected_get(const Eo * obj EINA_UNUSED,Elm_Atspi_Bridge_Data * pd)5209 _elm_atspi_bridge_connected_get(const Eo *obj EINA_UNUSED, Elm_Atspi_Bridge_Data *pd)
5210 {
5211    return pd->connected;
5212 }
5213 
5214 static void
_properties_changed_cb(void * data,Eldbus_Proxy * proxy EINA_UNUSED,void * event)5215 _properties_changed_cb(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event)
5216 {
5217    Eldbus_Proxy_Event_Property_Changed *ev = event;
5218    Eo *bridge = data;
5219    Eina_Bool val;
5220    const char *ifc = eldbus_proxy_interface_get(ev->proxy);
5221    if (ev->name && !strcmp(ev->name, "ScreenReaderEnabled" ) &&
5222        ifc && !strcmp(A11Y_DBUS_STATUS_INTERFACE, ifc))
5223      {
5224         if (!eina_value_get(ev->value, &val))
5225           {
5226              ERR("Unable to get ScreenReaderEnabled property value");
5227              return;
5228           }
5229         if (val)
5230           _a11y_connection_init(bridge);
5231         else
5232           _a11y_connection_shutdown(bridge);
5233      }
5234 }
5235 
5236 EOLIAN Efl_Object*
_elm_atspi_bridge_efl_object_constructor(Eo * obj,Elm_Atspi_Bridge_Data * pd)5237 _elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
5238 {
5239    Eldbus_Proxy *proxy;
5240    Eldbus_Pending *req;
5241 
5242    efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
5243 
5244    elm_need_eldbus();
5245 
5246    if (!(pd->session_bus = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION)))
5247      {
5248         ERR("Unable to connect to Session Bus");
5249         return NULL;
5250      }
5251    if (!(pd->bus_obj = eldbus_object_get(pd->session_bus, A11Y_DBUS_NAME, A11Y_DBUS_PATH)))
5252      {
5253         ERR("Could not get /org/a11y/bus object");
5254         goto obj_err;
5255      }
5256    if (!(proxy = eldbus_proxy_get(pd->bus_obj, A11Y_DBUS_STATUS_INTERFACE)))
5257      {
5258         ERR("Could not get proxy object for %s interface", A11Y_DBUS_STATUS_INTERFACE);
5259         goto proxy_err;
5260      }
5261    if (!(req = eldbus_proxy_property_get(proxy, "ScreenReaderEnabled", _screen_reader_enabled_get, obj)))
5262      {
5263         ERR("Could not send PropertyGet request");
5264         goto proxy_err;
5265      }
5266    pd->pending_requests = eina_list_append(pd->pending_requests, req);
5267 
5268    eldbus_proxy_properties_monitor(proxy, EINA_TRUE);
5269    eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
5270                                    _properties_changed_cb, obj);
5271 
5272    return obj;
5273 
5274 proxy_err:
5275    eldbus_object_unref(pd->bus_obj);
5276    pd->bus_obj = NULL;
5277 obj_err:
5278    eldbus_connection_unref(pd->session_bus);
5279    pd->session_bus = NULL;
5280    return NULL;
5281 }
5282 
5283 EOLIAN void
_elm_atspi_bridge_efl_object_destructor(Eo * obj,Elm_Atspi_Bridge_Data * pd)5284 _elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
5285 {
5286    _a11y_connection_shutdown(obj);
5287 
5288    if (pd->bus_obj) eldbus_object_unref(pd->bus_obj);
5289    if (pd->session_bus) eldbus_connection_unref(pd->session_bus);
5290 
5291    efl_destructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
5292 }
5293 
5294 #include "elm_atspi_bridge_eo.c"
5295