2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008 Novell, Inc.
6 * Copyright 2001, 2002 Sun Microsystems Inc.,
7 * Copyright 2001, 2002 Ximian, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 #include <droute/droute.h>
29 #include "atspi/atspi.h"
31 #include "accessible-stateset.h"
32 #include "accessible-register.h"
34 #include "introspection.h"
39 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
42 unsigned int capacity;
47 NEIGHBOR_SEARCH_MODE_NORMAL = 0,
48 NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
49 NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
50 } GetNeighborSearchMode;
52 typedef struct accessibility_navigation_pointer_table {
53 AtspiRole (*object_get_role)(struct accessibility_navigation_pointer_table *t, void *ptr);
54 uint64_t (*object_get_state_set)(struct accessibility_navigation_pointer_table *t, void *ptr);
55 void *(*get_object_in_relation_by_type)(struct accessibility_navigation_pointer_table *t, void *ptr, AtspiRelationType type);
56 unsigned char (*object_is_zero_size)(struct accessibility_navigation_pointer_table *t, void *ptr);
57 void *(*get_parent)(struct accessibility_navigation_pointer_table *t, void *ptr);
58 unsigned char (*object_is_scrollable)(struct accessibility_navigation_pointer_table *t, void *ptr);
59 void *(*get_object_at_point)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
60 unsigned char (*object_contains)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
61 unsigned char (*object_is_proxy)(struct accessibility_navigation_pointer_table *t, void *ptr);
62 void (*get_children)(struct accessibility_navigation_pointer_table *t, void *ptr, vector *v);
63 } accessibility_navigation_pointer_table;
65 static vector vector_init(void)
74 static void vector_free(vector *v)
81 static void vector_reserve(vector *v, unsigned int s)
85 v->objects = (void**)realloc(v->objects, sizeof(v->objects[0]) * s);
90 static void vector_resize(vector *v, unsigned int s)
96 static void *vector_get(vector *v, unsigned int index)
98 return v->objects[index];
101 static void vector_set(vector *v, unsigned int index, void *data)
103 v->objects[index] = data;
106 static unsigned int vector_size(vector *v)
111 #define CALL(fncname, ...) table->fncname(table, __VA_ARGS__)
112 static unsigned char _accept_object_check_role(accessibility_navigation_pointer_table *table, void *obj)
114 AtspiRole role = CALL(object_get_role, obj);
117 case ATSPI_ROLE_APPLICATION:
118 case ATSPI_ROLE_FILLER:
119 case ATSPI_ROLE_SCROLL_PANE:
120 case ATSPI_ROLE_SPLIT_PANE:
121 case ATSPI_ROLE_WINDOW:
122 case ATSPI_ROLE_IMAGE:
123 case ATSPI_ROLE_LIST:
124 case ATSPI_ROLE_ICON:
125 case ATSPI_ROLE_TOOL_BAR:
126 case ATSPI_ROLE_REDUNDANT_OBJECT:
127 case ATSPI_ROLE_COLOR_CHOOSER:
128 case ATSPI_ROLE_PANEL:
129 case ATSPI_ROLE_TREE_TABLE:
130 case ATSPI_ROLE_PAGE_TAB_LIST:
131 case ATSPI_ROLE_PAGE_TAB:
132 case ATSPI_ROLE_SPIN_BUTTON:
133 case ATSPI_ROLE_INPUT_METHOD_WINDOW:
134 case ATSPI_ROLE_EMBEDDED:
135 case ATSPI_ROLE_INVALID:
136 case ATSPI_ROLE_NOTIFICATION:
144 static unsigned char _state_set_is_set(uint64_t state_set, AtspiStateType state)
146 return (state_set & ((uint64_t)1 << (unsigned int)state)) != 0;
149 static unsigned char _object_is_defunct(accessibility_navigation_pointer_table *table, void *ptr)
151 uint64_t states = CALL(object_get_state_set, ptr);
152 return _state_set_is_set(states, ATSPI_STATE_DEFUNCT);
155 static unsigned char _object_role_is_acceptable_when_navigating_next_prev(accessibility_navigation_pointer_table *table, void *obj)
157 AtspiRole role = CALL(object_get_role, obj);
158 return role != ATSPI_ROLE_POPUP_MENU && role != ATSPI_ROLE_DIALOG;
161 static void *_get_object_in_relation_flow(accessibility_navigation_pointer_table *table, void *source, unsigned char forward)
163 return CALL(get_object_in_relation_by_type, source, forward ? ATSPI_RELATION_FLOWS_TO : ATSPI_RELATION_FLOWS_FROM);
166 static unsigned char _object_is_item(accessibility_navigation_pointer_table *table, void *obj)
168 AtspiRole role = CALL(object_get_role, obj);
169 return role == ATSPI_ROLE_LIST_ITEM || role == ATSPI_ROLE_MENU_ITEM;
172 static unsigned char _object_is_highlightable(accessibility_navigation_pointer_table *table, void *obj)
174 uint64_t state_set = CALL(object_get_state_set, obj);
175 return _state_set_is_set(state_set, ATSPI_STATE_HIGHLIGHTABLE);
178 static unsigned char _object_is_showing(accessibility_navigation_pointer_table *table, void *obj)
180 uint64_t state_set = CALL(object_get_state_set, obj);
181 return _state_set_is_set(state_set, ATSPI_STATE_SHOWING);
184 static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table *table, void *obj)
186 uint64_t state_set = CALL(object_get_state_set, obj);
188 _state_set_is_set(state_set, ATSPI_STATE_EXPANDABLE) &&
189 !_state_set_is_set(state_set, ATSPI_STATE_EXPANDED);
192 static unsigned char _object_has_modal_state(accessibility_navigation_pointer_table *table, void *obj)
194 uint64_t state_set = CALL(object_get_state_set, obj);
195 return _state_set_is_set(state_set, ATSPI_STATE_MODAL);
198 static unsigned char _object_is_zero_size(accessibility_navigation_pointer_table *table, void *obj)
200 return CALL(object_is_zero_size, obj);
203 static void *_get_scrollable_parent(accessibility_navigation_pointer_table *table, void *obj)
207 obj = CALL(get_parent, obj);
208 if (obj && CALL(object_is_scrollable, obj)) return obj;
212 static unsigned char _accept_object(accessibility_navigation_pointer_table *table, void *obj)
215 if (!_accept_object_check_role(table, obj)) return 0;
216 if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
217 if (!_object_is_highlightable(table, obj)) return 0;
219 if (_get_scrollable_parent(table, obj) != NULL)
221 void *parent = CALL(get_parent, obj);
225 return !_object_is_item(table, obj) || !_object_is_collapsed(table, parent);
230 if (_object_is_zero_size(table, obj)) return 0;
231 if (!_object_is_showing(table, obj)) return 0;
236 static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigation_pointer_table *table,
237 void *root, int x, int y, unsigned char coordinates_are_screen_based)
239 if (!root) return NULL;
241 void *return_value = NULL;
244 void *target = CALL(get_object_at_point, root, x, y, coordinates_are_screen_based);
247 // always return proxy, so atspi lib can call on it again
248 if (CALL(object_is_proxy, target)) return target;
251 void *relation_obj = CALL(get_object_in_relation_by_type, root, ATSPI_RELATION_CONTROLLED_BY);
252 unsigned char contains = 0;
255 contains = CALL(object_contains, relation_obj, x, y, coordinates_are_screen_based);
256 if (contains) root = relation_obj;
259 if (_accept_object(table, root))
266 if (return_value && _object_has_modal_state(table, return_value)) return_value = NULL;
276 static void *_find_non_defunct_child(accessibility_navigation_pointer_table *table,
277 vector *objects, unsigned int current_index, unsigned char forward)
279 for(; current_index < vector_size(objects); forward ? ++current_index : --current_index)
281 void *n = vector_get(objects, current_index);
282 if (n && !_object_is_defunct(table, n)) return n;
287 static void *_directional_depth_first_search_try_non_defunct_child(accessibility_navigation_pointer_table *table,
288 void *node, vector *children, unsigned char forward)
290 if (vector_size(children) > 0)
292 unsigned char is_showing = _get_scrollable_parent(table, node) == NULL ? _object_is_showing(table, node) : 1;
295 return _find_non_defunct_child(table, children, forward ? 0 : vector_size(children) - 1, forward);
301 static void *_get_next_non_defunct_sibling(accessibility_navigation_pointer_table *table,
302 void *obj, unsigned char forward)
304 if (!obj) return NULL;
305 void *parent = CALL(get_parent, obj);
306 if (!parent) return NULL;
308 vector children = vector_init();
309 CALL(get_children, parent, &children);
310 if (vector_size(&children) == 0)
312 vector_free(&children);
315 unsigned int current = 0;
316 for(; current < vector_size(&children) && vector_get(&children, current) != obj; ++current) ;
317 if (current >= vector_size(&children))
319 vector_free(&children);
322 forward ? ++current : --current;
323 void *ret = _find_non_defunct_child(table, &children, current, forward);
324 vector_free(&children);
328 static void *_directional_depth_first_search_try_non_defunct_sibling(accessibility_navigation_pointer_table *table,
329 unsigned char *all_children_visited_ptr, void *node, void *root, unsigned char forward)
333 void *sibling = _get_next_non_defunct_sibling(table, node, forward);
337 *all_children_visited_ptr = 0;
342 node = CALL(get_parent, node);
343 if (node == NULL || node == root) return NULL;
345 // in backward traversing stop the walk up on parent
353 unsigned int current_search_size;
354 unsigned int counter;
355 } cycle_detection_data;
357 void cycle_detection_initialize(cycle_detection_data *data, const void *key)
361 data->current_search_size = 1;
365 unsigned char cycle_detection_check_if_in_cycle(cycle_detection_data *data, const void *key)
368 if (data->key == key) return 1;
369 if (--data->counter == 0)
371 data->current_search_size <<= 1;
372 if (data->current_search_size == 0) return 1;
373 data->counter = data->current_search_size;
379 static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *table, void *root, void *start, unsigned char forward, GetNeighborSearchMode search_mode)
381 if (root && _object_is_defunct(table, root)) return NULL;
382 if (start && _object_is_defunct(table, start))
388 if (!node) return NULL;
390 // initialization of all-children-visiten flag for start node - we assume
391 // that when we begin at start node and we navigate backward, then all children
392 // are visited, so navigation will ignore start's children and go to
393 // previous sibling available.
394 unsigned char all_children_visited = search_mode != NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT && !forward;
395 unsigned char force_next = search_mode == NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
397 cycle_detection_data cycle_detection;
398 cycle_detection_initialize(&cycle_detection, node);
401 if (_object_is_defunct(table, node)) return NULL;
403 // always accept proxy object from different world
404 if (!force_next && CALL(object_is_proxy, node)) return node;
406 vector children = vector_init();
407 CALL(get_children, node, &children);
411 // 2. parent after all children in backward traversing
412 // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
413 // Objects with those roles shouldnt be reachable, when navigating next / prev.
414 unsigned char all_children_visited_or_moving_forward = (vector_size(&children) == 0 || forward || all_children_visited);
415 if (!force_next && node != start && all_children_visited_or_moving_forward && _accept_object(table, node))
417 if (start == NULL || _object_role_is_acceptable_when_navigating_next_prev(table, node))
419 vector_free(&children);
424 void *next_related_in_direction = !force_next ? _get_object_in_relation_flow(table, node, forward) : NULL;
426 if (next_related_in_direction && _object_is_defunct(table, next_related_in_direction))
427 next_related_in_direction = NULL;
428 unsigned char want_cycle_detection = 0;
429 if (next_related_in_direction)
431 node = next_related_in_direction;
432 want_cycle_detection = 1;
435 void *child = !force_next && !all_children_visited ?
436 _directional_depth_first_search_try_non_defunct_child(table, node, &children, forward) : NULL;
437 if (child != NULL) want_cycle_detection = 1;
440 if (!force_next && node == root)
442 vector_free(&children);
445 all_children_visited = 1;
446 child = _directional_depth_first_search_try_non_defunct_sibling(table, &all_children_visited, node, root, forward);
452 if (want_cycle_detection && cycle_detection_check_if_in_cycle(&cycle_detection, node))
454 vector_free(&children);
457 vector_free(&children);
465 static AtspiRelationType spi_relation_type_from_atk_relation_type (AtkRelationType type);
466 #define MARK_AS_UNUSED(v) do { (void)(v); } while(0)
468 static AtspiRole _object_get_role_impl(accessibility_navigation_pointer_table *table, void *ptr)
470 MARK_AS_UNUSED(table);
471 AtkObject *obj = (AtkObject*)ptr;
472 AtkRole role = atk_object_get_role (obj);
473 AtspiRole rv = spi_accessible_role_from_atk_role (role);
477 static uint64_t _object_get_state_set_impl(accessibility_navigation_pointer_table *table, void *ptr)
479 MARK_AS_UNUSED(table);
480 dbus_uint32_t array[2];
481 spi_atk_state_to_dbus_array((AtkObject*)ptr, array);
482 uint64_t res = array[0] | ((uint64_t)array[1] << 32);
486 static void *_get_object_in_relation_by_type_impl(accessibility_navigation_pointer_table *table, void *ptr, AtspiRelationType expected_relation_type)
488 MARK_AS_UNUSED(table);
490 g_return_val_if_fail (ATK_IS_OBJECT (ptr), NULL);
491 AtkRelationSet *set = atk_object_ref_relation_set (ptr);
494 gint count = atk_relation_set_get_n_relations (set), i;
495 for (i = 0; i < count; i++)
497 AtkRelation *r = atk_relation_set_get_relation (set, i);
500 AtkRelationType rt = atk_relation_get_relation_type (r);
501 AtspiRelationType type = spi_relation_type_from_atk_relation_type (rt);
502 if (expected_relation_type == type)
504 GPtrArray *target = atk_relation_get_target (r);
505 if (target && target->len > 0)
506 return target->pdata[0];
509 g_object_unref (set);
514 static unsigned char _object_is_zero_size_impl(accessibility_navigation_pointer_table *table, void *ptr)
516 MARK_AS_UNUSED(table);
517 AtkObject *obj = (AtkObject*)ptr;
518 g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
520 atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &w, &h, ATSPI_COORD_TYPE_SCREEN);
521 return w == 0 || h == 0;
524 unsigned char _object_is_scrollable_impl(accessibility_navigation_pointer_table *table, void *ptr)
526 AtspiRole role = _object_get_role_impl(table, ptr);
528 case ATSPI_ROLE_SCROLL_PANE: //scroller
529 case ATSPI_ROLE_LIST: //genlist, list
530 case ATSPI_ROLE_TREE_TABLE: //gengrid
531 case ATSPI_ROLE_TOOL_BAR: //toolbar
539 void *_get_parent_impl(accessibility_navigation_pointer_table *table, void *ptr)
541 MARK_AS_UNUSED(table);
542 return atk_object_get_parent((AtkObject*)ptr);
545 void *_get_object_at_point_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
547 MARK_AS_UNUSED(table);
548 AtkObject *obj = (AtkObject*)ptr;
549 g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
550 return atk_component_ref_accessible_at_point (ATK_COMPONENT(obj), x, y,
551 coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
554 unsigned char _object_contains_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
556 MARK_AS_UNUSED(table);
557 AtkObject *obj = (AtkObject*)ptr;
558 g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
560 return atk_component_contains (ATK_COMPONENT(obj), x, y,
561 coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
564 unsigned char _object_is_proxy_impl(accessibility_navigation_pointer_table *table, void *ptr)
566 MARK_AS_UNUSED(table);
570 void _get_children_impl(accessibility_navigation_pointer_table *table, void *ptr, vector *v)
572 MARK_AS_UNUSED(table);
573 AtkObject *obj = (AtkObject*)ptr;
574 gint count = atk_object_get_n_accessible_children (obj);
575 vector_resize(v, (unsigned int)count);
578 for (i = 0; i < count; i++) {
579 AtkObject *child = atk_object_ref_accessible_child (obj, i);
581 vector_set(v, index, child);
583 g_object_unref (child);
586 vector_resize(v, index);
593 accessibility_navigation_pointer_table construct_accessibility_navigation_pointer_table(void)
595 accessibility_navigation_pointer_table table;
596 #define INIT(n) table.n = _## n ## _impl
597 INIT(object_get_role);
598 INIT(object_get_state_set);
599 INIT(get_object_in_relation_by_type);
600 INIT(object_is_zero_size);
602 INIT(object_is_scrollable);
603 INIT(get_object_at_point);
604 INIT(object_contains);
605 INIT(object_is_proxy);
613 static AtkObject *_calculate_navigable_accessible_at_point(AtkObject *root, unsigned char coord_type, int x, int y)
615 accessibility_navigation_pointer_table table = construct_accessibility_navigation_pointer_table();
616 AtkObject *result = (AtkObject*)_calculate_navigable_accessible_at_point_impl(&table, root, x, y, coord_type ? 1 : 0);
620 static AtkObject *_calculate_neighbor(AtkObject *root, AtkObject *start, unsigned char forward, GetNeighborSearchMode search_mode)
622 accessibility_navigation_pointer_table table = construct_accessibility_navigation_pointer_table();
623 AtkObject *result = (AtkObject*)_calculate_neighbor_impl(&table, root, start, forward ? 1 : 0, search_mode);
628 impl_GetNeighbor (DBusConnection * bus, DBusMessage * message, void *user_data)
630 AtkObject *start = (AtkObject *) user_data;
631 dbus_uint32_t direction, search_mode;
632 const char *root_path = NULL;
636 if (!dbus_message_get_args
637 (message, NULL, DBUS_TYPE_STRING, &root_path, DBUS_TYPE_INT32, &direction, DBUS_TYPE_INT32, &search_mode, DBUS_TYPE_INVALID))
639 return droute_invalid_arguments_error (message);
642 AtkObject *root_object = (AtkObject*)spi_global_register_path_to_object(root_path);
643 child = _calculate_neighbor (root_object, start, direction == 1, search_mode);
644 reply = spi_object_return_reference_and_recurse_flag (message, child, 0);
650 impl_GetNavigableAtPoint (DBusConnection * bus, DBusMessage * message,
653 AtkObject *object = (AtkObject *) user_data;
655 dbus_uint32_t coord_type;
659 if (!dbus_message_get_args
660 (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
661 DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
663 return droute_invalid_arguments_error (message);
665 child = _calculate_navigable_accessible_at_point (object, coord_type == ATSPI_COORD_TYPE_SCREEN, x, y);
666 reply = spi_object_return_reference_and_recurse_flag (message, child, 0);
672 _list_children_count_check(AtkObject * object)
681 role = atk_object_get_role (object);
682 if (role == ATK_ROLE_LIST)
684 gint children_count = 0;
685 children_count = atk_object_get_n_accessible_children (object);
686 for (i = 0; i < children_count; i++)
688 AtkObject *child = atk_object_ref_accessible_child (object, i);
689 role = atk_object_get_role (child);
690 if (role == ATK_ROLE_LIST_ITEM)
693 g_object_unref (child);
701 _list_children_count (AtkObject * object)
703 gint list_items_count = 0;
707 list_items_count = _list_children_count_check(object);
708 if (list_items_count > 0)
710 return list_items_count;
713 count = atk_object_get_n_accessible_children (object);
714 for (i = 0; i < count; i++)
716 AtkObject *child = atk_object_ref_accessible_child (object, i);
717 list_items_count = _list_children_count(child);
719 g_object_unref (child);
720 if (list_items_count > 0)
722 return list_items_count;
730 impl_GetReadingMaterial (DBusConnection * bus, DBusMessage * message, void *user_data)
732 AtkObject *object = (AtkObject *) user_data;
734 AtkAttributeSet *attributes;
738 AtkObject *rel_object = NULL;
739 unsigned int size = 0;
741 dbus_uint32_t rv_role;
742 dbus_int32_t rv_index;
743 dbus_uint32_t states[2];
744 dbus_bool_t rv_is_selected = 0;
745 DBusMessage *reply = NULL;
746 DBusMessageIter iter;
747 DBusMessageIter iter_variant;
749 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
750 droute_not_yet_handled_error (message));
752 reply = dbus_message_new_method_return (message);
753 dbus_message_iter_init_append (reply, &iter);
756 attributes = atk_object_get_attributes (object);
757 spi_object_append_attribute_set (&iter, attributes);
758 atk_attribute_set_free (attributes);
761 name = atk_object_get_name (object);
764 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
766 /* name - LABELED_BY relation */
768 set = atk_object_ref_relation_set (object);
769 count = atk_relation_set_get_n_relations (set);
770 for (i = 0; i < count; i++)
772 AtkRelation *r = atk_relation_set_get_relation (set, i);
775 AtkRelationType rt = atk_relation_get_relation_type (r);
776 if (rt == ATK_RELATION_LABELLED_BY)
778 GPtrArray *target = atk_relation_get_target (r);
779 if (target && target->len > 0)
781 rel_object = target->pdata[target->len - 1];
782 name = atk_object_get_name (rel_object);
789 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
791 /* name - text interface */
792 AtkText *text = (AtkText *) object;
793 size = atk_text_get_character_count (text);
794 name = atk_text_get_text (text, 0, size);
797 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
800 role = atk_object_get_role (object);
801 rv_role = spi_accessible_role_from_atk_role (role);
802 dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &rv_role);
805 spi_atk_state_to_dbus_array (object, states);
806 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_variant);
807 for (count = 0; count < 2; count++)
809 dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_UINT32,
812 dbus_message_iter_close_container (&iter, &iter_variant);
814 /* localized role name */
815 name = atk_role_get_localized_name (role);
818 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
821 count = atk_object_get_n_accessible_children (object);
822 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
824 /* current value, increment, max, min */
825 AtkValue *value = (AtkValue *) object;
826 gdouble current_value = 0;
827 gdouble increment = 0;
828 gdouble min_value = 0;
829 gdouble max_value = 0;
830 if (ATK_IS_VALUE(value))
833 atk_value_get_value_and_text (value, ¤t_value, &desc);
835 increment = atk_value_get_increment (value);
837 AtkRange *range = atk_value_get_range(value);
840 min_value = atk_range_get_lower_limit (range);
841 max_value = atk_range_get_upper_limit (range);
842 atk_range_free (range);
845 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, ¤t_value);
846 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &increment);
847 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &max_value);
848 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &min_value);
851 name = atk_object_get_description (object);
854 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
856 /* index in parent */
857 rv_index = atk_object_get_index_in_parent (object);
858 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &rv_index);
860 /* is selected in parent */
861 parent = atk_object_get_parent (object);
864 AtkSelection *selection = (AtkSelection *) parent;
865 if (ATK_IS_SELECTION(selection))
867 rv_is_selected = atk_selection_is_child_selected (selection, rv_index);
870 dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rv_is_selected);
872 /* has checkbox child */
874 count = atk_object_get_n_accessible_children (object);
875 for (i = 0; i < count; i++)
877 AtkObject *child = atk_object_ref_accessible_child (object, i);
878 gint _role = atk_object_get_role (child);
880 g_object_unref (child);
881 if (_role == ATK_ROLE_CHECK_BOX)
887 dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rv_is_selected);
889 /* list children count */
891 if (role == ATK_ROLE_DIALOG)
893 count = _list_children_count(object);
895 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
897 /* first selected child index */
898 /* it is too UX dependent, this is not necessary */
900 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &rv_index);
905 /* does it have to handle PLUG, APPLICATION? */
906 spi_object_append_null_reference (&iter);
910 spi_object_append_reference (&iter, parent);
913 /* parent - states */
914 spi_atk_state_to_dbus_array (parent, states);
915 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_variant);
916 for (count = 0; count < 2; count++)
918 dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_UINT32,
921 dbus_message_iter_close_container (&iter, &iter_variant);
923 /* parent - child count */
924 count = atk_object_get_n_accessible_children (parent);
925 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
928 role = atk_object_get_role (parent);
929 rv_role = spi_accessible_role_from_atk_role (role);
930 dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &rv_role);
932 /* parent selected child count */
936 AtkSelection *selection = (AtkSelection *) parent;
937 if (ATK_IS_SELECTION(selection))
939 count = atk_selection_get_selection_count (selection);
942 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
944 /* relation object - DESCRIBED_BY */
946 set = atk_object_ref_relation_set (object);
947 count = atk_relation_set_get_n_relations (set);
948 for (i = 0; i < count; i++)
950 AtkRelation *r = atk_relation_set_get_relation (set, i);
953 AtkRelationType rt = atk_relation_get_relation_type (r);
954 if (rt == ATK_RELATION_DESCRIBED_BY)
956 GPtrArray *target = atk_relation_get_target (r);
957 if (target && target->len > 0)
959 rel_object = target->pdata[target->len - 1];
966 spi_object_append_null_reference (&iter);
970 spi_object_append_reference (&iter, rel_object);
978 impl_get_Name (DBusMessageIter * iter, void *user_data)
980 AtkObject *object = (AtkObject *) user_data;
982 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
984 return droute_return_v_string (iter, atk_object_get_name (object));
988 impl_get_Description (DBusMessageIter * iter, void *user_data)
990 AtkObject *object = (AtkObject *) user_data;
992 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
994 return droute_return_v_string (iter, atk_object_get_description (object));
998 impl_get_Locale (DBusMessageIter * iter, void *user_data)
1000 AtkObject *object = (AtkObject *) user_data;
1002 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1004 return droute_return_v_string (iter, atk_object_get_object_locale (object));
1008 impl_get_Parent (DBusMessageIter * iter, void *user_data)
1010 AtkObject *obj = (AtkObject *) user_data;
1012 DBusMessageIter iter_variant;
1015 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1017 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
1019 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
1022 parent = atk_object_get_parent (obj);
1025 /* TODO, move in to a 'Plug' wrapper. */
1026 if (ATK_IS_PLUG (obj))
1028 char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
1034 bus_parent = g_strdup (id);
1035 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
1037 DBusMessageIter iter_parent;
1038 *(path_parent++) = '\0';
1039 dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
1041 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
1042 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
1043 dbus_message_iter_close_container (&iter_variant, &iter_parent);
1047 spi_object_append_null_reference (&iter_variant);
1052 spi_object_append_null_reference (&iter_variant);
1055 else if (role != ATSPI_ROLE_APPLICATION)
1056 spi_object_append_null_reference (&iter_variant);
1058 spi_object_append_desktop_reference (&iter_variant);
1062 spi_object_append_reference (&iter_variant, parent);
1066 dbus_message_iter_close_container (iter, &iter_variant);
1071 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
1073 AtkObject *object = (AtkObject *) user_data;
1076 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1078 childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
1080 : atk_object_get_n_accessible_children (object);
1081 return droute_return_v_int32 (iter, childCount);
1084 static DBusMessage *
1085 impl_GetChildAtIndex (DBusConnection * bus,
1086 DBusMessage * message, void *user_data)
1088 AtkObject *object = (AtkObject *) user_data;
1093 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1094 droute_not_yet_handled_error (message));
1095 if (!dbus_message_get_args
1096 (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
1098 return droute_invalid_arguments_error (message);
1101 if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
1103 AtkSocket *socket = ATK_SOCKET (object);
1104 gchar *child_name, *child_path;
1105 child_name = g_strdup (socket->embedded_plug_id);
1106 child_path = g_utf8_strchr (child_name + 1, -1, ':');
1109 DBusMessageIter iter, iter_socket;
1110 *(child_path++) = '\0';
1111 reply = dbus_message_new_method_return (message);
1114 dbus_message_iter_init_append (reply, &iter);
1115 dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
1117 dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
1118 dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
1119 dbus_message_iter_close_container (&iter, &iter_socket);
1122 g_free (child_name);
1124 child = atk_object_ref_accessible_child (object, i);
1125 reply = spi_object_return_reference (message, child);
1126 g_object_unref (child);
1131 static DBusMessage *
1132 impl_GetChildren (DBusConnection * bus,
1133 DBusMessage * message, void *user_data)
1135 AtkObject *object = (AtkObject *) user_data;
1139 DBusMessageIter iter, iter_array;
1141 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1142 droute_not_yet_handled_error (message));
1143 count = atk_object_get_n_accessible_children (object);
1144 reply = dbus_message_new_method_return (message);
1147 dbus_message_iter_init_append (reply, &iter);
1148 if (!dbus_message_iter_open_container
1149 (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
1151 for (i = 0; i < count; i++)
1153 AtkObject *child = atk_object_ref_accessible_child (object, i);
1154 spi_object_append_reference (&iter_array, child);
1156 g_object_unref (child);
1158 if (!dbus_message_iter_close_container (&iter, &iter_array))
1162 // TODO: handle out-of-memory
1166 static DBusMessage *
1167 impl_GetIndexInParent (DBusConnection * bus,
1168 DBusMessage * message, void *user_data)
1170 AtkObject *object = (AtkObject *) user_data;
1174 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1175 droute_not_yet_handled_error (message));
1177 rv = atk_object_get_index_in_parent (object);
1178 reply = dbus_message_new_method_return (message);
1179 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv, DBUS_TYPE_INVALID);
1184 spi_init_relation_type_table (AtspiRelationType * types)
1188 for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
1189 types[i] = ATSPI_RELATION_NULL;
1191 types[ATK_RELATION_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY;
1192 types[ATK_RELATION_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR;
1193 types[ATK_RELATION_LABEL_FOR] = ATSPI_RELATION_LABEL_FOR;
1194 types[ATK_RELATION_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY;
1195 types[ATK_RELATION_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF;
1196 types[ATK_RELATION_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF;
1197 types[ATK_RELATION_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO;
1198 types[ATK_RELATION_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM;
1199 types[ATK_RELATION_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF;
1200 types[ATK_RELATION_EMBEDS] = ATSPI_RELATION_EMBEDS;
1201 types[ATK_RELATION_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY;
1202 types[ATK_RELATION_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR;
1203 types[ATK_RELATION_PARENT_WINDOW_OF] =
1204 ATSPI_RELATION_PARENT_WINDOW_OF;
1205 types[ATK_RELATION_DESCRIPTION_FOR] =
1206 ATSPI_RELATION_DESCRIPTION_FOR;
1207 types[ATK_RELATION_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY;
1208 types[ATK_RELATION_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF;
1213 static AtspiRelationType
1214 spi_relation_type_from_atk_relation_type (AtkRelationType type)
1216 static gboolean is_initialized = FALSE;
1217 static AtspiRelationType
1218 spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
1219 AtspiRelationType spi_type;
1221 if (!is_initialized)
1222 is_initialized = spi_init_relation_type_table (spi_relation_type_table);
1224 if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
1225 spi_type = spi_relation_type_table[type];
1227 spi_type = ATSPI_RELATION_EXTENDED;
1231 static DBusMessage *
1232 impl_GetRelationSet (DBusConnection * bus,
1233 DBusMessage * message, void *user_data)
1235 AtkObject *object = (AtkObject *) user_data;
1237 AtkRelationSet *set;
1238 DBusMessageIter iter, iter_array, iter_struct, iter_targets;
1242 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1243 droute_not_yet_handled_error (message));
1244 reply = dbus_message_new_method_return (message);
1247 set = atk_object_ref_relation_set (object);
1248 dbus_message_iter_init_append (reply, &iter);
1249 if (!dbus_message_iter_open_container
1250 (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
1256 count = atk_relation_set_get_n_relations (set);
1257 for (i = 0; i < count; i++)
1259 AtkRelation *r = atk_relation_set_get_relation (set, i);
1265 rt = atk_relation_get_relation_type (r);
1266 type = spi_relation_type_from_atk_relation_type (rt);
1267 target = atk_relation_get_target (r);
1268 if (!dbus_message_iter_open_container
1269 (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
1273 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
1274 if (!dbus_message_iter_open_container
1275 (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
1279 for (j = 0; j < target->len; j++)
1281 AtkObject *obj = target->pdata[j];
1284 spi_object_append_reference (&iter_targets, obj);
1286 dbus_message_iter_close_container (&iter_struct, &iter_targets);
1287 dbus_message_iter_close_container (&iter_array, &iter_struct);
1289 dbus_message_iter_close_container (&iter, &iter_array);
1292 g_object_unref (set);
1293 // TODO: handle out of memory */
1297 static DBusMessage *
1298 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
1300 AtkObject *object = (AtkObject *) user_data;
1305 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1306 droute_not_yet_handled_error (message));
1307 role = atk_object_get_role (object);
1308 rv = spi_accessible_role_from_atk_role (role);
1309 reply = dbus_message_new_method_return (message);
1312 dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
1318 static DBusMessage *
1319 impl_GetRoleName (DBusConnection * bus,
1320 DBusMessage * message, void *user_data)
1322 AtkObject *object = (AtkObject *) user_data;
1324 const char *role_name;
1327 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1328 droute_not_yet_handled_error (message));
1329 role = atk_object_get_role (object);
1330 role_name = atk_role_get_name (role);
1333 reply = dbus_message_new_method_return (message);
1336 dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
1342 static DBusMessage *
1343 impl_GetLocalizedRoleName (DBusConnection * bus,
1344 DBusMessage * message, void *user_data)
1346 AtkObject *object = (AtkObject *) user_data;
1348 const char *role_name;
1351 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1352 droute_not_yet_handled_error (message));
1353 role = atk_object_get_role (object);
1354 role_name = atk_role_get_localized_name (role);
1357 reply = dbus_message_new_method_return (message);
1360 dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
1366 static DBusMessage *
1367 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
1369 AtkObject *object = (AtkObject *) user_data;
1371 DBusMessage *reply = NULL;
1372 DBusMessageIter iter, iter_array;
1374 dbus_uint32_t states[2];
1378 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1379 droute_not_yet_handled_error (message));
1381 reply = dbus_message_new_method_return (message);
1382 dbus_message_iter_init_append (reply, &iter);
1384 spi_atk_state_to_dbus_array (object, states);
1385 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
1386 for (count = 0; count < 2; count++)
1388 dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
1391 dbus_message_iter_close_container (&iter, &iter_array);
1395 static DBusMessage *
1396 impl_GetAttributes (DBusConnection * bus,
1397 DBusMessage * message, void *user_data)
1399 AtkObject *object = (AtkObject *) user_data;
1400 AtkAttributeSet *attributes;
1401 DBusMessage *reply = NULL;
1402 DBusMessageIter iter;
1404 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1405 droute_not_yet_handled_error (message));
1407 attributes = atk_object_get_attributes (object);
1409 reply = dbus_message_new_method_return (message);
1410 dbus_message_iter_init_append (reply, &iter);
1411 spi_object_append_attribute_set (&iter, attributes);
1413 atk_attribute_set_free (attributes);
1419 impl_get_Attributes (DBusMessageIter * iter, void *user_data)
1421 DBusMessageIter iter_variant;
1422 AtkObject *object = (AtkObject *) user_data;
1423 AtkAttributeSet *attributes;
1425 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1427 attributes = atk_object_get_attributes (object);
1429 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "a{ss}", &iter_variant);
1430 spi_object_append_attribute_set (&iter_variant, attributes);
1431 dbus_message_iter_close_container (iter, &iter_variant);
1433 atk_attribute_set_free (attributes);
1438 static DBusMessage *
1439 impl_GetApplication (DBusConnection * bus,
1440 DBusMessage * message, void *user_data)
1442 return spi_object_return_reference (message, atk_get_root ());
1445 static DBusMessage *
1446 impl_GetInterfaces (DBusConnection * bus,
1447 DBusMessage * message, void *user_data)
1449 AtkObject *object = (AtkObject *) user_data;
1451 DBusMessageIter iter, iter_array;
1453 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1454 droute_not_yet_handled_error (message));
1455 reply = dbus_message_new_method_return (message);
1458 dbus_message_iter_init_append (reply, &iter);
1459 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
1461 spi_object_append_interfaces (&iter_array, object);
1462 dbus_message_iter_close_container (&iter, &iter_array);
1467 static DRouteMethod methods[] = {
1468 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
1469 {impl_GetNavigableAtPoint, "GetNavigableAtPoint"},
1470 {impl_GetNeighbor, "GetNeighbor"},
1471 {impl_GetReadingMaterial, "GetReadingMaterial"},
1473 {impl_GetChildAtIndex, "GetChildAtIndex"},
1474 {impl_GetChildren, "GetChildren"},
1475 {impl_GetIndexInParent, "GetIndexInParent"},
1476 {impl_GetRelationSet, "GetRelationSet"},
1477 {impl_GetRole, "GetRole"},
1478 {impl_GetRoleName, "GetRoleName"},
1479 {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
1480 {impl_GetState, "GetState"},
1481 {impl_GetAttributes, "GetAttributes"},
1482 {impl_GetApplication, "GetApplication"},
1483 {impl_GetInterfaces, "GetInterfaces"},
1487 static DRouteProperty properties[] = {
1488 {impl_get_Name, NULL, "Name"},
1489 {impl_get_Description, NULL, "Description"},
1490 {impl_get_Locale, NULL, "Locale"},
1491 {impl_get_Parent, NULL, "Parent"},
1492 {impl_get_ChildCount, NULL, "ChildCount"},
1493 {impl_get_Attributes, NULL, "Attributes"},
1498 spi_initialize_accessible (DRoutePath * path)
1500 spi_atk_add_interface (path,
1501 ATSPI_DBUS_INTERFACE_ACCESSIBLE,
1502 spi_org_a11y_atspi_Accessible,
1503 methods, properties);