summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinwoo Kim <cinoo.kim@samsung.com>2018-01-19 10:49:00 +0900
committerShinwoo Kim <cinoo.kim@samsung.com>2018-01-19 11:03:17 +0900
commit0fb6f0c120f08a48bcf5b44cb44afb0f4a90fb2e (patch)
tree9ff386b406d88aabf52a5267e84b7ec088222e7b
Start EAT project
-rw-r--r--README13
-rw-r--r--atspi_viewer.c500
-rw-r--r--atspi_viewer.edc26
3 files changed, 539 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..88fbe18
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
1EAT
2===
3
4EAT is an Assistive Technology client written by EFL library to browse
5accessibility tree of running application exposing the assistive technology
6service provider interface.
7
8
9REQUIREMENTS
10------------
11Required by default:
12
13 * libatspi2.0-0
diff --git a/atspi_viewer.c b/atspi_viewer.c
new file mode 100644
index 0000000..1ff3737
--- /dev/null
+++ b/atspi_viewer.c
@@ -0,0 +1,500 @@
1/* gcc -o atspi_viewer ./atspi_viewer.c `pkg-config --cflags --libs ecore atspi-2 eldbus gobject-2.0 elementary evas` */
2
3#include <stdio.h>
4#include <Ecore.h>
5#include <atspi/atspi.h>
6#include <Eldbus.h>
7#include <Elementary.h>
8#include <Evas.h>
9
10#define ERROR(fmt, ...) \
11 fprintf(stderr, fmt, ##__VA_ARGS__); \
12 fprintf(stderr, "\n");
13
14#define DEBUG(fmt, ...) \
15 fprintf(stderr, fmt, ##__VA_ARGS__); \
16 fprintf(stderr, "\n");
17
18static Eina_Bool _dbus_set_property_bool(Eldbus_Connection_Type connection_type,
19 const char *bus,
20 const char *path,
21 const char *interface,
22 const char *property,
23 Eina_Bool value)
24{
25 Eldbus_Connection *conn;
26 Eldbus_Object *dobj;
27 Eldbus_Proxy *proxy;
28 Eldbus_Message *req;
29
30 Eina_Bool ret = EINA_FALSE;
31 Eldbus_Message_Iter *iter;
32
33 eldbus_init();
34
35 if (!(conn = eldbus_connection_get(connection_type))) {
36 ERROR("Connection to dbus failed");
37 return EINA_FALSE;
38 }
39 if (!(dobj = eldbus_object_get(conn, bus, path))) {
40 ERROR("Failed to create eldbus object");
41 goto fail_obj;
42 }
43 if (!(proxy = eldbus_proxy_get(dobj, "org.freedesktop.DBus.Properties"))) {
44 ERROR("Failed to create proxy object for 'org.freedesktop.DBus.Properties'");
45 goto fail_proxy;
46 }
47 if (!(req = eldbus_proxy_method_call_new(proxy, "Set"))) {
48 ERROR("Failed to create method call on org.freedesktop.DBus.Properties.Set");
49 goto fail_proxy;
50 }
51 eldbus_message_ref(req);
52
53 if (!eldbus_message_arguments_append(req, "ss", interface, property)) {
54 ERROR("Failed to append message args");
55 goto fail_msg;
56 }
57 if (!(iter = eldbus_message_iter_container_new(eldbus_message_iter_get(req), 'v', "b"))) {
58 ERROR("Unable to create variant iterator");
59 goto fail_msg;
60 }
61 if (!eldbus_message_iter_arguments_append(iter, "b", value)) {
62 ERROR("Unable to append to variant iterator");
63 goto fail_msg;
64 }
65 if (!eldbus_message_iter_container_close(eldbus_message_iter_get(req), iter)) {
66 ERROR("Failed to close variant iterator");
67 goto fail_msg;
68 }
69 eldbus_proxy_send(proxy, req, NULL, NULL, -1.0);
70 ret = EINA_TRUE;
71
72fail_msg:
73 eldbus_message_unref(req);
74fail_proxy:
75 eldbus_object_unref(dobj);
76fail_obj:
77 eldbus_connection_unref(conn);
78
79 eldbus_shutdown();
80
81 return ret;
82}
83
84Eina_Bool screen_reader_switch_enabled_set(Eina_Bool value)
85{
86 return _dbus_set_property_bool(ELDBUS_CONNECTION_TYPE_SESSION,
87 "org.a11y.Bus",
88 "/org/a11y/bus",
89 "org.a11y.Status",
90 "ScreenReaderEnabled", value);
91}
92
93static void
94viewer_information_get(void)
95{
96 AtspiAccessible *desktop = atspi_get_desktop(0);
97 if (!desktop)
98 {
99 ERROR("No desktop!");
100 return;
101 }
102
103 int n_children = atspi_accessible_get_child_count(desktop, NULL);
104 DEBUG("children: %d", n_children);
105
106 int i;
107 for (i = 0; i < n_children; i++)
108 {
109 AtspiAccessible *app = atspi_accessible_get_child_at_index(desktop, i, NULL);
110 if (!app) continue;
111
112 gchar *name = atspi_accessible_get_name(app, NULL);
113 int n_app_children = atspi_accessible_get_child_count(app, NULL);
114 int j;
115 DEBUG("%d. %s", i, name);
116 for (j = 0; j < n_app_children; j++)
117 {
118 AtspiAccessible *win = atspi_accessible_get_child_at_index(app, j, NULL);
119 name = atspi_accessible_get_name(win, NULL);
120 DEBUG(" %s", name);
121 g_object_unref(win);
122 }
123 g_object_unref(app);
124 }
125 g_object_unref(desktop);
126}
127
128static char *
129gl_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
130{
131 char buf[256];
132 AtspiAccessible *accessible = data;
133 gchar *name = atspi_accessible_get_name(accessible, NULL);
134 gchar *role_name = atspi_accessible_get_role_name(accessible, NULL);
135 snprintf(buf, sizeof(buf), "[%s] %s", role_name, name);
136 g_free(name);
137 g_free(role_name);
138 return strdup(buf);
139}
140
141Eina_Bool gl_state_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
142{
143 return EINA_FALSE;
144}
145
146char *state_to_char(AtspiStateType state)
147{
148 switch (state) {
149 case ATSPI_STATE_INVALID:
150 return strdup("ATSPI_STATE_INVALID");
151 case ATSPI_STATE_ACTIVE:
152 return strdup("ATSPI_STATE_ACTIVE");
153 case ATSPI_STATE_ARMED:
154 return strdup("ATSPI_STATE_ARMED");
155 case ATSPI_STATE_BUSY:
156 return strdup("ATSPI_STATE_BUSY");
157 case ATSPI_STATE_CHECKED:
158 return strdup("ATSPI_STATE_CHECKED");
159 case ATSPI_STATE_COLLAPSED:
160 return strdup("ATSPI_STATE_COLLAPSED");
161 case ATSPI_STATE_DEFUNCT:
162 return strdup("ATSPI_STATE_DEFUNCT");
163 case ATSPI_STATE_EDITABLE:
164 return strdup("ATSPI_STATE_EDITABLE");
165 case ATSPI_STATE_ENABLED:
166 return strdup("ATSPI_STATE_ENABLED");
167 case ATSPI_STATE_EXPANDABLE:
168 return strdup("ATSPI_STATE_EXPANDABLE");
169 case ATSPI_STATE_EXPANDED:
170 return strdup("ATSPI_STATE_EXPANDED");
171 case ATSPI_STATE_FOCUSABLE:
172 return strdup("ATSPI_STATE_FOCUSABLE");
173 case ATSPI_STATE_FOCUSED:
174 return strdup("ATSPI_STATE_FOCUSED");
175 case ATSPI_STATE_HAS_TOOLTIP:
176 return strdup("ATSPI_STATE_HAS_TOOLTIP");
177 case ATSPI_STATE_HORIZONTAL:
178 return strdup("ATSPI_STATE_HORIZONTAL");
179 case ATSPI_STATE_ICONIFIED:
180 return strdup("ATSPI_STATE_ICONIFIED");
181 case ATSPI_STATE_MULTI_LINE:
182 return strdup("ATSPI_STATE_MULTI_LINE");
183 case ATSPI_STATE_MULTISELECTABLE:
184 return strdup("ATSPI_STATE_MULTISELECTABLE");
185 case ATSPI_STATE_OPAQUE:
186 return strdup("ATSPI_STATE_OPAQUE");
187 case ATSPI_STATE_PRESSED:
188 return strdup("ATSPI_STATE_PRESSED");
189 case ATSPI_STATE_RESIZABLE:
190 return strdup("ATSPI_STATE_RESIZABLE");
191 case ATSPI_STATE_SELECTABLE:
192 return strdup("ATSPI_STATE_SELECTABLE");
193 case ATSPI_STATE_SELECTED:
194 return strdup("ATSPI_STATE_SELECTED");
195 case ATSPI_STATE_SENSITIVE:
196 return strdup("ATSPI_STATE_SENSITIVE");
197 case ATSPI_STATE_SHOWING:
198 return strdup("ATSPI_STATE_SHOWING");
199 case ATSPI_STATE_SINGLE_LINE:
200 return strdup("ATSPI_STATE_SINGLE_LINE");
201 case ATSPI_STATE_STALE:
202 return strdup("ATSPI_STATE_STALE");
203 case ATSPI_STATE_TRANSIENT:
204 return strdup("ATSPI_STATE_TRANSIENT");
205 case ATSPI_STATE_VERTICAL:
206 return strdup("ATSPI_STATE_VERTICAL");
207 case ATSPI_STATE_VISIBLE:
208 return strdup("ATSPI_STATE_VISIBLE");
209 case ATSPI_STATE_MANAGES_DESCENDANTS:
210 return strdup("ATSPI_STATE_MANAGES_DESCENDANTS");
211 case ATSPI_STATE_INDETERMINATE:
212 return strdup("ATSPI_STATE_INDETERMINATE");
213 case ATSPI_STATE_REQUIRED:
214 return strdup("ATSPI_STATE_REQUIRED");
215 case ATSPI_STATE_TRUNCATED:
216 return strdup("ATSPI_STATE_TRUNCATED");
217 case ATSPI_STATE_ANIMATED:
218 return strdup("ATSPI_STATE_ANIMATED");
219 case ATSPI_STATE_INVALID_ENTRY:
220 return strdup("ATSPI_STATE_INVALID_ENTRY");
221 case ATSPI_STATE_SUPPORTS_AUTOCOMPLETION:
222 return strdup("ATSPI_STATE_SUPPORTS_AUTOCOMPLETION");
223 case ATSPI_STATE_SELECTABLE_TEXT:
224 return strdup("ATSPI_STATE_SELECTABLE_TEXT");
225 case ATSPI_STATE_IS_DEFAULT:
226 return strdup("ATSPI_STATE_IS_DEFAULT");
227 case ATSPI_STATE_VISITED:
228 return strdup("ATSPI_STATE_VISITED");
229 case ATSPI_STATE_CHECKABLE:
230 return strdup("ATSPI_STATE_CHECKABLE");
231 case ATSPI_STATE_HAS_POPUP:
232 return strdup("ATSPI_STATE_HAS_POPUP");
233 case ATSPI_STATE_READ_ONLY:
234 return strdup("ATSPI_STATE_READ_ONLY");
235 case ATSPI_STATE_LAST_DEFINED:
236 return strdup("ATSPI_STATE_LAST_DEFINED");
237 case ATSPI_STATE_MODAL:
238 return strdup("ATSPI_STATE_MODAL");
239 default:
240 return strdup("\0");
241 }
242}
243
244static void
245gl4_sel(void *data EINA_UNUSED, Evas_Object *obj, void *event_info)
246{
247 Elm_Object_Item *glit = event_info;
248 int depth = elm_genlist_item_expanded_depth_get(glit);
249 printf("Item selected callback %p - expanded depth = %d\n", glit, depth);
250
251 AtspiAccessible *accessible = (AtspiAccessible *) elm_object_item_data_get(glit);
252
253 char txt[256];
254 Eina_Strbuf *buf;
255 buf = eina_strbuf_new();
256
257 AtspiAccessible *app = atspi_accessible_get_application(accessible, NULL);
258 gchar *toolkit = atspi_accessible_get_toolkit_name(app, NULL);
259 snprintf(txt, sizeof(txt), "<br/>[Toolkit]<br/>%s<br/>", toolkit);
260 eina_strbuf_append_length(buf, txt, strlen(txt));
261 free(toolkit);
262 g_object_unref(app);
263
264 AtspiRect *rect = NULL;
265 AtspiComponent *comp = NULL;
266 comp = atspi_accessible_get_component_iface(accessible);
267 rect = atspi_component_get_extents(comp, ATSPI_COORD_TYPE_SCREEN, NULL);
268
269 snprintf(txt, sizeof(txt), "<br/>[Extents:Screen]<br/>%d, %d, %d, %d<br/>", rect->x, rect->y, rect->width, rect->height);
270 eina_strbuf_append_length(buf, txt, strlen(txt));
271 free(rect);
272
273 rect = atspi_component_get_extents(comp, ATSPI_COORD_TYPE_WINDOW, NULL);
274 snprintf(txt, sizeof(txt), "<br/>[Extents:Window]<br/>%d, %d, %d, %d<br/>", rect->x, rect->y, rect->width, rect->height);
275 eina_strbuf_append_length(buf, txt, strlen(txt));
276 free(rect);
277
278 snprintf(txt, sizeof(txt), "<br/>[States]<br/>");
279 eina_strbuf_append_length(buf, txt, strlen(txt));
280
281 AtspiStateSet *st = atspi_accessible_get_state_set(accessible);
282 GArray *states = atspi_state_set_get_states(st);
283
284 char *state_name = NULL;
285 AtspiStateType stat;
286 int a;
287 for (a = 0; states && (a < states->len); ++a)
288 {
289 stat = g_array_index(states, AtspiStateType, a);
290 state_name = state_to_char(stat);
291 snprintf(txt, sizeof(txt), "%s<br/>", state_name);
292 eina_strbuf_append_length(buf, txt, strlen(txt));
293 free(state_name);
294 }
295 if (states)
296 g_array_free(states, 0);
297
298 snprintf(txt, sizeof(txt), "<br/>[Interfaces]<br/>");
299 eina_strbuf_append_length(buf, txt, strlen(txt));
300
301 char *interface_name = NULL;
302 GArray *ifaces = atspi_accessible_get_interfaces(accessible);
303 for (a = 0; ifaces && (a < ifaces->len); ++a)
304 {
305 interface_name = g_array_index(ifaces, char *, a);
306 snprintf(txt, sizeof(txt), "%s<br/>", interface_name);
307 eina_strbuf_append_length(buf, txt, strlen(txt));
308 g_free(interface_name);
309 }
310 if (ifaces)
311 g_array_free(ifaces, FALSE);
312
313 char *ret = eina_strbuf_string_steal(buf);
314 eina_strbuf_free(buf);
315 Evas_Object *ly = evas_object_data_get(obj, "detail_view_layout");
316 Evas_Object *lb = elm_label_add(ly);
317 elm_object_text_set(lb, ret);
318 free(ret);
319
320 evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
321 evas_object_size_hint_align_set(lb, EVAS_HINT_FILL, EVAS_HINT_FILL);
322 elm_object_part_content_set(ly, "swallow.detail.label", lb);
323}
324
325static void
326gl9_exp_req(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
327{
328 Elm_Object_Item *glit = event_info;
329 elm_genlist_item_expanded_set(glit, EINA_TRUE);
330}
331
332static void
333gl9_con_req(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
334{
335 Elm_Object_Item *glit = event_info;
336 elm_genlist_item_expanded_set(glit, EINA_FALSE);
337}
338
339static void
340gl9_exp(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
341{
342 Elm_Genlist_Item_Class *itc1;
343 itc1 = elm_genlist_item_class_new();
344 itc1->item_style = "default";
345 itc1->func.text_get = gl_text_get;
346 itc1->func.content_get = NULL;
347 itc1->func.state_get = gl_state_get;
348 itc1->func.del = NULL;
349
350 Elm_Object_Item *glit = event_info;
351 Evas_Object *gl = elm_object_item_widget_get(glit);
352 AtspiAccessible *accessible = (AtspiAccessible *) elm_object_item_data_get(glit);
353
354 int n_children = atspi_accessible_get_child_count(accessible, NULL);
355
356 int i;
357 for (i = 0; i < n_children; i++)
358 {
359 AtspiAccessible *child = atspi_accessible_get_child_at_index(accessible, i, NULL);
360 int n = atspi_accessible_get_child_count(child, NULL);
361 if (n > 0)
362 {
363 elm_genlist_item_append(gl, itc1,
364 child/* item data */,
365 glit/* parent */,
366 ELM_GENLIST_ITEM_TREE, gl4_sel/* func */,
367 NULL/* func data */);
368 }
369 else
370 {
371 elm_genlist_item_append(gl, itc1,
372 child/* item data */,
373 glit/* parent */,
374 ELM_GENLIST_ITEM_NONE, gl4_sel/* func */,
375 NULL/* func data */);
376 }
377 }
378
379 elm_genlist_item_class_free(itc1);
380}
381
382static void
383gl9_con(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
384{
385 Elm_Object_Item *glit = event_info;
386 elm_genlist_item_subitems_clear(glit);
387}
388
389static void
390_main_win_del_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
391{
392 elm_exit();
393}
394
395static void
396ui_create(void)
397{
398 Evas_Object *win;
399 win = elm_win_util_standard_add("atspi-viewer", "Atspi Viewer");
400 elm_win_autodel_set(win, EINA_TRUE);
401 evas_object_smart_callback_add(win, "delete,request", _main_win_del_cb,
402 NULL);
403
404 Evas_Object *hbx = elm_box_add(win);
405 elm_box_horizontal_set(hbx, EINA_TRUE);
406 evas_object_size_hint_weight_set(hbx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
407 elm_win_resize_object_add(win, hbx);
408
409 Evas_Object *bx = elm_box_add(win);
410 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
411 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
412 evas_object_show(bx);
413
414 evas_object_show(hbx);
415 elm_box_pack_end(hbx, bx);
416
417 Evas_Object *gl = elm_genlist_add(win);
418 evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
419 evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
420 elm_box_pack_end(bx, gl);
421 evas_object_show(gl);
422
423 Elm_Genlist_Item_Class *itc1;
424 itc1 = elm_genlist_item_class_new();
425 itc1->item_style = "default";
426 itc1->func.text_get = gl_text_get;
427 itc1->func.content_get = NULL;
428 itc1->func.state_get = gl_state_get;
429 itc1->func.del = NULL;
430
431 AtspiAccessible *desktop = atspi_get_desktop(0);
432 if (!desktop)
433 {
434 ERROR("No desktop!");
435 return;
436 }
437
438 int n_children = atspi_accessible_get_child_count(desktop, NULL);
439 DEBUG("children: %d", n_children);
440
441 int i;
442 for (i = 0; i < n_children; i++)
443 {
444 AtspiAccessible *app = atspi_accessible_get_child_at_index(desktop, i, NULL);
445 if (!app) continue;
446
447 int n = atspi_accessible_get_child_count(app, NULL);
448 if (n == 0)
449 {
450 g_object_unref(app);
451 continue;
452 }
453
454 Elm_Object_Item *git;
455 git = elm_genlist_item_append(gl, itc1,
456 (void *)app/* item data */, NULL/* parent */, ELM_GENLIST_ITEM_TREE, gl4_sel/* func */,
457 NULL/* func data */);
458 elm_genlist_item_select_mode_set(git, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
459 }
460 g_object_unref(desktop);
461
462 elm_genlist_item_class_free(itc1);
463
464 evas_object_smart_callback_add(gl, "expand,request", gl9_exp_req, NULL);
465 evas_object_smart_callback_add(gl, "contract,request", gl9_con_req, NULL);
466 evas_object_smart_callback_add(gl, "expanded", gl9_exp, NULL);
467 evas_object_smart_callback_add(gl, "contracted", gl9_con, NULL);
468
469 Evas_Object *ly;
470 ly = elm_layout_add(win);
471 elm_layout_file_set(ly, "./atspi_viewer.edj", "detail");
472 evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
473 evas_object_size_hint_align_set(ly, EVAS_HINT_FILL, EVAS_HINT_FILL);
474 elm_box_pack_end(hbx, ly);
475 evas_object_show(ly);
476
477 evas_object_data_set(gl, "detail_view_layout", ly);
478
479 evas_object_resize(win, 680, 800);
480 evas_object_show(win);
481}
482
483int main(int argc, char **argv)
484{
485 ecore_init();
486 atspi_init();
487 screen_reader_switch_enabled_set(EINA_TRUE);
488 elm_init(argc, argv);
489
490 //viewer_information_get();
491 ui_create();
492
493 elm_run();
494
495 //screen_reader_switch_enabled_set(EINA_FALSE);
496 //atspi_exit();
497 //ecore_shutdown();
498
499 return 0;
500}
diff --git a/atspi_viewer.edc b/atspi_viewer.edc
new file mode 100644
index 0000000..40f3c54
--- /dev/null
+++ b/atspi_viewer.edc
@@ -0,0 +1,26 @@
1collections {
2 group { "detail";
3 parts {
4 rect { "base";
5 desc { "default";
6 min: 200 200;
7 color: 0 0 0 0;
8 }
9 }
10
11 part { name: "swallow.detail.label"; type: SWALLOW;
12 description { state: "default" 0.0;
13 rel1 {
14 to: "base";
15 relative: 0.01 0.01;
16 }
17 rel2 {
18 to: "base";
19 relative: 0.99 0.5;
20 }
21 }
22 }
23
24 }
25 }
26}