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