Add "GetReadingMaterial" interface method
[platform/upstream/at-spi2-atk.git] / atk-adaptor / adaptors / accessible-adaptor.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008 Novell, Inc.
6  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 #include <atk/atk.h>
26 #include <droute/droute.h>
27 #include "bridge.h"
28
29 #include "atspi/atspi.h"
30 #include "spi-dbus.h"
31 #include "accessible-stateset.h"
32 #include "accessible-register.h"
33 #include "object.h"
34 #include "introspection.h"
35 #include <string.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38
39 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
40 typedef struct {
41    void **objects;
42    unsigned int capacity;
43    unsigned int size;
44 } vector;
45
46 typedef enum {
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;
51
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;
64
65 static vector vector_init(void)
66 {
67    vector v;
68    v.objects = NULL;
69    v.capacity = 0;
70    v.size = 0;
71    return v;
72 }
73
74 static void vector_free(vector *v)
75 {
76    free(v->objects);
77    v->objects = NULL;
78    v->capacity = 0;
79    v->size = 0;
80 }
81 static void vector_reserve(vector *v, unsigned int s)
82 {
83    if (s > v->capacity)
84      {
85        v->objects = (void**)realloc(v->objects, sizeof(v->objects[0]) * s);
86        v->capacity = s;
87      }
88 }
89
90 static void vector_resize(vector *v, unsigned int s)
91 {
92    vector_reserve(v, s);
93    v->size = s;
94 }
95
96 static void *vector_get(vector *v, unsigned int index)
97 {
98    return v->objects[index];
99 }
100
101 static void vector_set(vector *v, unsigned int index, void *data)
102 {
103    v->objects[index] = data;
104 }
105
106 static unsigned int vector_size(vector *v)
107 {
108    return v->size;
109 }
110
111 #define CALL(fncname, ...) table->fncname(table, __VA_ARGS__)
112 static unsigned char _accept_object_check_role(accessibility_navigation_pointer_table *table, void *obj)
113 {
114    AtspiRole role = CALL(object_get_role, obj);
115    switch (role)
116      {
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:
137          return 0;
138        default:
139          break;
140      }
141    return 1;
142 }
143
144 static unsigned char _state_set_is_set(uint64_t state_set, AtspiStateType state)
145 {
146    return (state_set & ((uint64_t)1 << (unsigned int)state)) != 0;
147 }
148
149 static unsigned char _object_is_defunct(accessibility_navigation_pointer_table *table, void *ptr)
150 {
151    uint64_t states = CALL(object_get_state_set, ptr);
152    return _state_set_is_set(states, ATSPI_STATE_DEFUNCT);
153 }
154
155 static unsigned char _object_role_is_acceptable_when_navigating_next_prev(accessibility_navigation_pointer_table *table, void *obj)
156 {
157    AtspiRole role = CALL(object_get_role, obj);
158    return role != ATSPI_ROLE_POPUP_MENU && role != ATSPI_ROLE_DIALOG;
159 }
160
161 static void *_get_object_in_relation_flow(accessibility_navigation_pointer_table *table, void *source, unsigned char forward)
162 {
163     return CALL(get_object_in_relation_by_type, source, forward ? ATSPI_RELATION_FLOWS_TO : ATSPI_RELATION_FLOWS_FROM);
164 }
165
166 static unsigned char _object_is_item(accessibility_navigation_pointer_table *table, void *obj)
167 {
168    AtspiRole role = CALL(object_get_role, obj);
169    return role == ATSPI_ROLE_LIST_ITEM || role == ATSPI_ROLE_MENU_ITEM;
170 }
171
172 static unsigned char _object_is_highlightable(accessibility_navigation_pointer_table *table, void *obj)
173 {
174    uint64_t state_set = CALL(object_get_state_set, obj);
175    return _state_set_is_set(state_set, ATSPI_STATE_HIGHLIGHTABLE);
176 }
177
178 static unsigned char _object_is_showing(accessibility_navigation_pointer_table *table, void *obj)
179 {
180    uint64_t state_set = CALL(object_get_state_set, obj);
181    return _state_set_is_set(state_set, ATSPI_STATE_SHOWING);
182 }
183
184 static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table *table, void *obj)
185 {
186    uint64_t state_set = CALL(object_get_state_set, obj);
187    return
188       _state_set_is_set(state_set, ATSPI_STATE_EXPANDABLE) &&
189       !_state_set_is_set(state_set, ATSPI_STATE_EXPANDED);
190 }
191
192 static unsigned char _object_has_modal_state(accessibility_navigation_pointer_table *table, void *obj)
193 {
194    uint64_t state_set = CALL(object_get_state_set, obj);
195    return _state_set_is_set(state_set, ATSPI_STATE_MODAL);
196 }
197
198 static unsigned char _object_is_zero_size(accessibility_navigation_pointer_table *table, void *obj)
199 {
200    return CALL(object_is_zero_size, obj);
201 }
202
203 static void *_get_scrollable_parent(accessibility_navigation_pointer_table *table, void *obj)
204 {
205    while(obj)
206      {
207        obj = CALL(get_parent, obj);
208        if (obj && CALL(object_is_scrollable, obj)) return obj;
209      }
210    return NULL;
211 }
212 static unsigned char _accept_object(accessibility_navigation_pointer_table *table, void *obj)
213 {
214    if (!obj) return 0;
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;
218
219    if (_get_scrollable_parent(table, obj) != NULL)
220      {
221        void *parent = CALL(get_parent, obj);
222
223        if (parent)
224          {
225            return !_object_is_item(table, obj) || !_object_is_collapsed(table, parent);
226          }
227      }
228    else
229      {
230        if (_object_is_zero_size(table, obj)) return 0;
231        if (!_object_is_showing(table, obj)) return 0;
232      }
233    return 1;
234 }
235
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)
238 {
239    if (!root) return NULL;
240
241    void *return_value = NULL;
242    while (1)
243      {
244        void *target = CALL(get_object_at_point, root, x, y, coordinates_are_screen_based);
245        if (!target) break;
246
247        // always return proxy, so atspi lib can call on it again
248        if (CALL(object_is_proxy, target)) return target;
249
250        root = target;
251        void *relation_obj = CALL(get_object_in_relation_by_type, root, ATSPI_RELATION_CONTROLLED_BY);
252        unsigned char contains = 0;
253        if (relation_obj)
254          {
255            contains = CALL(object_contains, relation_obj, x, y, coordinates_are_screen_based);
256            if (contains) root = relation_obj;
257          }
258
259        if (_accept_object(table, root))
260          {
261            return_value = root;
262            if (contains) break;
263          }
264      }
265
266    if (return_value && _object_has_modal_state(table, return_value)) return_value = NULL;
267    return return_value;
268 }
269
270
271
272
273
274
275
276 static void *_find_non_defunct_child(accessibility_navigation_pointer_table *table,
277             vector *objects, unsigned int current_index, unsigned char forward)
278 {
279    for(; current_index < vector_size(objects); forward ? ++current_index : --current_index)
280      {
281        void *n = vector_get(objects, current_index);
282        if (n && !_object_is_defunct(table, n)) return n;
283      }
284    return NULL;
285 }
286
287 static void *_directional_depth_first_search_try_non_defunct_child(accessibility_navigation_pointer_table *table,
288             void *node, vector *children, unsigned char forward)
289 {
290    if (vector_size(children) > 0)
291      {
292        unsigned char is_showing = _get_scrollable_parent(table, node) == NULL ? _object_is_showing(table, node) : 1;
293        if (is_showing)
294          {
295            return _find_non_defunct_child(table, children, forward ? 0 : vector_size(children) - 1, forward);
296          }
297      }
298    return NULL;
299 }
300
301 static void *_get_next_non_defunct_sibling(accessibility_navigation_pointer_table *table,
302             void *obj, unsigned char forward)
303 {
304    if (!obj) return NULL;
305    void *parent = CALL(get_parent, obj);
306    if (!parent) return NULL;
307
308    vector children = vector_init();
309    CALL(get_children, parent, &children);
310    if (vector_size(&children) == 0)
311      {
312        vector_free(&children);
313        return NULL;
314      }
315    unsigned int current = 0;
316    for(; current < vector_size(&children) && vector_get(&children, current) != obj; ++current) ;
317    if (current >= vector_size(&children))
318      {
319        vector_free(&children);
320        return NULL;
321      }
322    forward ? ++current : --current;
323    void *ret = _find_non_defunct_child(table, &children, current, forward);
324    vector_free(&children);
325    return ret;
326 }
327
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)
330 {
331    while(1)
332      {
333        void *sibling = _get_next_non_defunct_sibling(table, node, forward);
334        if (sibling != NULL)
335          {
336            node = sibling;
337            *all_children_visited_ptr = 0;
338            break;
339          }
340
341        // walk up...
342        node = CALL(get_parent, node);
343        if (node == NULL || node == root) return NULL;
344
345        // in backward traversing stop the walk up on parent
346        if (!forward) break;
347      }
348    return node;
349 }
350
351 typedef struct {
352     const void *key;
353     unsigned int current_search_size;
354     unsigned int counter;
355 } cycle_detection_data;
356
357 void cycle_detection_initialize(cycle_detection_data *data, const void *key)
358 {
359    if (!data) return;
360    data->key = key;
361    data->current_search_size = 1;
362    data->counter = 1;
363 }
364
365 unsigned char cycle_detection_check_if_in_cycle(cycle_detection_data *data, const void *key)
366 {
367    if (!data) return 1;
368    if (data->key == key) return 1;
369    if (--data->counter == 0)
370      {
371        data->current_search_size <<= 1;
372        if (data->current_search_size == 0) return 1;
373        data->counter = data->current_search_size;
374        data->key = key;
375      }
376    return 0;
377 }
378
379 static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *table, void *root, void *start, unsigned char forward, GetNeighborSearchMode search_mode)
380 {
381    if (root && _object_is_defunct(table, root)) return NULL;
382    if (start && _object_is_defunct(table, start))
383      {
384        start = root;
385        forward = 1;
386      }
387    void *node = start;
388    if (!node) return NULL;
389
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;
396
397    cycle_detection_data cycle_detection;
398    cycle_detection_initialize(&cycle_detection, node);
399    while (node)
400      {
401        if (_object_is_defunct(table, node)) return NULL;
402
403        // always accept proxy object from different world
404        if (!force_next && CALL(object_is_proxy, node)) return node;
405
406        vector children = vector_init();
407        CALL(get_children, node, &children);
408
409        // do accept:
410        // 1. not start node
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))
416          {
417            if (start == NULL || _object_role_is_acceptable_when_navigating_next_prev(table, node))
418              {
419                vector_free(&children);
420                return node;
421              }
422          }
423
424        void *next_related_in_direction = !force_next ? _get_object_in_relation_flow(table, node, forward) : NULL;
425
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)
430          {
431            node = next_related_in_direction;
432            want_cycle_detection = 1;
433          }
434        else {
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;
438            else
439              {
440                if (!force_next && node == root)
441                  {
442                    vector_free(&children);
443                    return NULL;
444                  }
445                all_children_visited = 1;
446                child = _directional_depth_first_search_try_non_defunct_sibling(table, &all_children_visited, node, root, forward);
447              }
448            node = child;
449        }
450
451        force_next = 0;
452        if (want_cycle_detection && cycle_detection_check_if_in_cycle(&cycle_detection, node))
453          {
454            vector_free(&children);
455            return NULL;
456          }
457        vector_free(&children);
458      }
459    return NULL;
460 }
461
462
463
464
465 static AtspiRelationType spi_relation_type_from_atk_relation_type (AtkRelationType type);
466 #define MARK_AS_UNUSED(v) do { (void)(v); } while(0)
467
468 static AtspiRole _object_get_role_impl(accessibility_navigation_pointer_table *table, void *ptr)
469 {
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);
474   return rv;
475 }
476
477 static uint64_t _object_get_state_set_impl(accessibility_navigation_pointer_table *table, void *ptr)
478 {
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);
483   return res;
484 }
485
486 static void *_get_object_in_relation_by_type_impl(accessibility_navigation_pointer_table *table, void *ptr, AtspiRelationType expected_relation_type)
487 {
488   MARK_AS_UNUSED(table);
489   if (ptr) {
490     g_return_val_if_fail (ATK_IS_OBJECT (ptr), NULL);
491     AtkRelationSet *set = atk_object_ref_relation_set (ptr);
492     if (!set)
493       return NULL;
494     gint count = atk_relation_set_get_n_relations (set), i;
495     for (i = 0; i < count; i++)
496     {
497       AtkRelation *r = atk_relation_set_get_relation (set, i);
498       if (!r)
499         continue;
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)
503       {
504         GPtrArray *target = atk_relation_get_target (r);
505         if (target && target->len > 0)
506           return target->pdata[0];
507       }
508     }
509     g_object_unref (set);
510   }
511   return NULL;
512 }
513
514 static unsigned char _object_is_zero_size_impl(accessibility_navigation_pointer_table *table, void *ptr)
515 {
516   MARK_AS_UNUSED(table);
517   AtkObject *obj = (AtkObject*)ptr;
518   g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
519   gint x, y, w, h;
520   atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &w, &h, ATSPI_COORD_TYPE_SCREEN);
521   return w == 0 || h == 0;
522 }
523
524 unsigned char _object_is_scrollable_impl(accessibility_navigation_pointer_table *table, void *ptr)
525 {
526   AtspiRole role = _object_get_role_impl(table, ptr);
527   switch (role) {
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
532       return 1;
533   default:
534       break;
535   }
536   return 0;
537 }
538
539 void *_get_parent_impl(accessibility_navigation_pointer_table *table, void *ptr)
540 {
541   MARK_AS_UNUSED(table);
542   return atk_object_get_parent((AtkObject*)ptr);
543 }
544
545 void *_get_object_at_point_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
546 {
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);
552 }
553
554 unsigned char _object_contains_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
555 {
556   MARK_AS_UNUSED(table);
557   AtkObject *obj = (AtkObject*)ptr;
558   g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
559
560   return atk_component_contains (ATK_COMPONENT(obj), x, y,
561         coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
562 }
563
564 unsigned char _object_is_proxy_impl(accessibility_navigation_pointer_table *table, void *ptr)
565 {
566   MARK_AS_UNUSED(table);
567   return 0;
568 }
569
570 void _get_children_impl(accessibility_navigation_pointer_table *table, void *ptr, vector *v)
571 {
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);
576
577     gint i, index = 0;
578     for (i = 0; i < count; i++) {
579         AtkObject *child = atk_object_ref_accessible_child (obj, i);
580         if (child) {
581             vector_set(v, index, child);
582             ++index;
583             g_object_unref (child);
584         }
585     }
586     vector_resize(v, index);
587 }
588
589
590
591
592
593 accessibility_navigation_pointer_table construct_accessibility_navigation_pointer_table(void)
594 {
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);
601    INIT(get_parent);
602    INIT(object_is_scrollable);
603    INIT(get_object_at_point);
604    INIT(object_contains);
605    INIT(object_is_proxy);
606    INIT(get_children);
607 #undef INIT
608    return table;
609 }
610
611
612
613 static AtkObject *_calculate_navigable_accessible_at_point(AtkObject *root, unsigned char coord_type, int x, int y)
614 {
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);
617    return result;
618 }
619
620 static AtkObject *_calculate_neighbor(AtkObject *root, AtkObject *start, unsigned char forward, GetNeighborSearchMode search_mode)
621 {
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);
624    return result;
625 }
626
627 static DBusMessage *
628 impl_GetNeighbor (DBusConnection * bus, DBusMessage * message, void *user_data)
629 {
630   AtkObject *start = (AtkObject *) user_data;
631   dbus_uint32_t direction, search_mode;
632   const char *root_path = NULL;
633   DBusMessage *reply;
634   AtkObject *child;
635
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))
638     {
639       return droute_invalid_arguments_error (message);
640     }
641
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);
645
646   return reply;
647 }
648
649 static DBusMessage *
650 impl_GetNavigableAtPoint (DBusConnection * bus, DBusMessage * message,
651                            void *user_data)
652 {
653   AtkObject *object = (AtkObject *) user_data;
654   dbus_int32_t x, y;
655   dbus_uint32_t coord_type;
656   DBusMessage *reply;
657   AtkObject *child;
658
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))
662     {
663       return droute_invalid_arguments_error (message);
664     }
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);
667
668   return reply;
669 }
670
671 static int
672 _list_children_count_check(AtkObject * object)
673 {
674    gint role;
675    gint i;
676    gint list_count = 0;
677
678    if (!object)
679      return 0;
680
681   role = atk_object_get_role (object);
682   if (role == ATK_ROLE_LIST)
683     {
684       gint children_count = 0;
685       children_count = atk_object_get_n_accessible_children (object);
686       for (i = 0; i < children_count; i++)
687         {
688           AtkObject *child = atk_object_ref_accessible_child (object, i);
689           role = atk_object_get_role (child);
690           if (role == ATK_ROLE_LIST_ITEM)
691             list_count++;
692           if (child)
693             g_object_unref (child);
694         }
695     }
696
697    return list_count;
698 }
699
700 static gint
701 _list_children_count (AtkObject * object)
702 {
703   gint list_items_count = 0;
704   gint count = 0;
705   gint i;
706
707   list_items_count = _list_children_count_check(object);
708   if (list_items_count > 0)
709     {
710        return list_items_count;
711     }
712
713   count = atk_object_get_n_accessible_children (object);
714   for (i = 0; i < count; i++)
715     {
716       AtkObject *child = atk_object_ref_accessible_child (object, i);
717       list_items_count = _list_children_count(child);
718       if (child)
719         g_object_unref (child);
720       if (list_items_count > 0)
721         {
722            return list_items_count;
723         }
724     }
725
726   return 0;
727 }
728
729 static DBusMessage *
730 impl_GetReadingMaterial (DBusConnection * bus, DBusMessage * message, void *user_data)
731 {
732   AtkObject *object = (AtkObject *) user_data;
733   AtkObject *parent;
734   AtkAttributeSet *attributes;
735   const char *name;
736   AtkRelationSet *set;
737   gint count, i;
738   AtkObject *rel_object = NULL;
739   unsigned int size = 0;
740   gint role;
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;
748
749   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
750                         droute_not_yet_handled_error (message));
751
752   reply = dbus_message_new_method_return (message);
753   dbus_message_iter_init_append (reply, &iter);
754
755   /* attributes */
756   attributes = atk_object_get_attributes (object);
757   spi_object_append_attribute_set (&iter, attributes);
758   atk_attribute_set_free (attributes);
759
760   /* name */
761   name = atk_object_get_name (object);
762   if (!name)
763     name = "";
764   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
765
766   /* name - LABELED_BY relation */
767   name = NULL;
768   set = atk_object_ref_relation_set (object);
769   count = atk_relation_set_get_n_relations (set);
770   for (i = 0; i < count; i++)
771   {
772     AtkRelation *r = atk_relation_set_get_relation (set, i);
773     if (!r)
774       continue;
775     AtkRelationType rt = atk_relation_get_relation_type (r);
776     if (rt == ATK_RELATION_LABELLED_BY)
777     {
778       GPtrArray *target = atk_relation_get_target (r);
779       if (target && target->len > 0)
780       {
781         rel_object = target->pdata[target->len - 1];
782         name = atk_object_get_name (rel_object);
783         break;
784       }
785     }
786   }
787   if (!name)
788     name = "";
789   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
790
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);
795   if (!name)
796     name = "";
797   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
798
799   /* role */
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);
803
804   /* states */
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++)
808     {
809       dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_UINT32,
810                                       &states[count]);
811     }
812   dbus_message_iter_close_container (&iter, &iter_variant);
813
814   /* localized role name */
815   name = atk_role_get_localized_name (role);
816   if (!name)
817     name = "";
818   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
819
820   /* child count */
821   count = atk_object_get_n_accessible_children (object);
822   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
823
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))
831   {
832     gchar *desc = NULL;
833     atk_value_get_value_and_text (value, &current_value, &desc);
834
835     increment = atk_value_get_increment (value);
836
837     AtkRange *range = atk_value_get_range(value);
838     if (range)
839       {
840         min_value = atk_range_get_lower_limit (range);
841         max_value = atk_range_get_upper_limit (range);
842         atk_range_free (range);
843       }
844   }
845   dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &current_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);
849
850   /* description */
851   name = atk_object_get_description (object);
852   if (!name)
853     name = "";
854   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
855
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);
859
860   /* is selected in parent */
861   parent = atk_object_get_parent (object);
862   if (parent)
863     {
864       AtkSelection *selection = (AtkSelection *) parent;
865       if (ATK_IS_SELECTION(selection))
866         {
867           rv_is_selected = atk_selection_is_child_selected (selection, rv_index);
868         }
869     }
870   dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rv_is_selected);
871
872   /* has checkbox child */
873   rv_is_selected = 0;
874   count = atk_object_get_n_accessible_children (object);
875   for (i = 0; i < count; i++)
876     {
877       AtkObject *child = atk_object_ref_accessible_child (object, i);
878       gint _role = atk_object_get_role (child);
879       if (child)
880         g_object_unref (child);
881       if (_role == ATK_ROLE_CHECK_BOX)
882         {
883           rv_is_selected = 1;
884           break;
885         }
886     }
887   dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rv_is_selected);
888
889   /* list children count */
890   count = 0;
891   if (role == ATK_ROLE_DIALOG)
892     {
893       count = _list_children_count(object);
894     }
895   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
896
897   /* first selected child index */
898   /* it is too UX dependent, this is not necessary */
899   rv_index = 0;
900   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &rv_index);
901
902   /* parent */
903   if (!parent)
904     {
905       /* does it have to handle PLUG, APPLICATION? */
906       spi_object_append_null_reference (&iter);
907     }
908   else
909     {
910       spi_object_append_reference (&iter, parent);
911     }
912
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++)
917     {
918       dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_UINT32,
919                                       &states[count]);
920     }
921   dbus_message_iter_close_container (&iter, &iter_variant);
922
923   /* parent - child count */
924   count = atk_object_get_n_accessible_children (parent);
925   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
926
927   /* parent role */
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);
931
932   /* parent selected child count */
933   count = 0;
934   if (parent)
935     {
936       AtkSelection *selection = (AtkSelection *) parent;
937       if (ATK_IS_SELECTION(selection))
938         {
939           count = atk_selection_get_selection_count (selection);
940         }
941     }
942   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &count);
943
944   /* relation object - DESCRIBED_BY */
945   rel_object = NULL;
946   set = atk_object_ref_relation_set (object);
947   count = atk_relation_set_get_n_relations (set);
948   for (i = 0; i < count; i++)
949   {
950     AtkRelation *r = atk_relation_set_get_relation (set, i);
951     if (!r)
952       continue;
953     AtkRelationType rt = atk_relation_get_relation_type (r);
954     if (rt == ATK_RELATION_DESCRIBED_BY)
955     {
956       GPtrArray *target = atk_relation_get_target (r);
957       if (target && target->len > 0)
958       {
959         rel_object = target->pdata[target->len - 1];
960         break;
961       }
962     }
963   }
964   if (!rel_object)
965     {
966       spi_object_append_null_reference (&iter);
967     }
968   else
969     {
970       spi_object_append_reference (&iter, rel_object);
971     }
972
973   return reply;
974 }
975 //
976
977 static dbus_bool_t
978 impl_get_Name (DBusMessageIter * iter, void *user_data)
979 {
980   AtkObject *object = (AtkObject *) user_data;
981
982   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
983
984   return droute_return_v_string (iter, atk_object_get_name (object));
985 }
986
987 static dbus_bool_t
988 impl_get_Description (DBusMessageIter * iter, void *user_data)
989 {
990   AtkObject *object = (AtkObject *) user_data;
991
992   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
993
994   return droute_return_v_string (iter, atk_object_get_description (object));
995 }
996
997 static dbus_bool_t
998 impl_get_Locale (DBusMessageIter * iter, void *user_data)
999 {
1000   AtkObject *object = (AtkObject *) user_data;
1001
1002   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1003
1004   return droute_return_v_string (iter, atk_object_get_object_locale (object));
1005 }
1006
1007 static dbus_bool_t
1008 impl_get_Parent (DBusMessageIter * iter, void *user_data)
1009 {
1010   AtkObject *obj = (AtkObject *) user_data;
1011   AtkObject *parent;
1012   DBusMessageIter iter_variant;
1013   dbus_uint32_t role;
1014
1015   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1016
1017   role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
1018
1019   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
1020                                     &iter_variant);
1021
1022   parent = atk_object_get_parent (obj);
1023   if (parent == NULL)
1024     {
1025       /* TODO, move in to a 'Plug' wrapper. */
1026       if (ATK_IS_PLUG (obj))
1027         {
1028           char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
1029           char *bus_parent;
1030           char *path_parent;
1031
1032           if (id)
1033             {
1034               bus_parent = g_strdup (id);
1035               if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
1036                 {
1037                   DBusMessageIter iter_parent;
1038                   *(path_parent++) = '\0';
1039                   dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
1040                                                     &iter_parent);
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);
1044                 }
1045               else
1046                 {
1047                   spi_object_append_null_reference (&iter_variant);
1048                 }
1049             }
1050           else
1051             {
1052               spi_object_append_null_reference (&iter_variant);
1053             }
1054         }
1055       else if (role != ATSPI_ROLE_APPLICATION)
1056          spi_object_append_null_reference (&iter_variant);
1057       else
1058          spi_object_append_desktop_reference (&iter_variant);
1059       }
1060   else
1061     {
1062       spi_object_append_reference (&iter_variant, parent);
1063     }
1064
1065
1066   dbus_message_iter_close_container (iter, &iter_variant);
1067   return TRUE;
1068 }
1069
1070 static dbus_bool_t
1071 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
1072 {
1073   AtkObject *object = (AtkObject *) user_data;
1074   int childCount;
1075
1076   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1077
1078   childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
1079                ? 1
1080                : atk_object_get_n_accessible_children (object);
1081   return droute_return_v_int32 (iter, childCount);
1082 }
1083
1084 static DBusMessage *
1085 impl_GetChildAtIndex (DBusConnection * bus,
1086                       DBusMessage * message, void *user_data)
1087 {
1088   AtkObject *object = (AtkObject *) user_data;
1089   DBusMessage *reply;
1090   dbus_int32_t i;
1091   AtkObject *child;
1092
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))
1097     {
1098       return droute_invalid_arguments_error (message);
1099     }
1100
1101   if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
1102     {
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, ':');
1107       if (child_path)
1108         {
1109           DBusMessageIter iter, iter_socket;
1110           *(child_path++) = '\0';
1111           reply = dbus_message_new_method_return (message);
1112           if (!reply)
1113             return NULL;
1114           dbus_message_iter_init_append (reply, &iter);
1115           dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
1116                                             &iter_socket);
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);
1120           return reply;
1121         }
1122       g_free (child_name);
1123     }
1124   child = atk_object_ref_accessible_child (object, i);
1125   reply = spi_object_return_reference (message, child);
1126   g_object_unref (child);
1127
1128   return reply;
1129 }
1130
1131 static DBusMessage *
1132 impl_GetChildren (DBusConnection * bus,
1133                   DBusMessage * message, void *user_data)
1134 {
1135   AtkObject *object = (AtkObject *) user_data;
1136   gint i;
1137   gint count;
1138   DBusMessage *reply;
1139   DBusMessageIter iter, iter_array;
1140
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);
1145   if (!reply)
1146     goto oom;
1147   dbus_message_iter_init_append (reply, &iter);
1148   if (!dbus_message_iter_open_container
1149       (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
1150     goto oom;
1151   for (i = 0; i < count; i++)
1152     {
1153       AtkObject *child = atk_object_ref_accessible_child (object, i);
1154       spi_object_append_reference (&iter_array, child);
1155       if (child)
1156         g_object_unref (child);
1157     }
1158   if (!dbus_message_iter_close_container (&iter, &iter_array))
1159     goto oom;
1160   return reply;
1161 oom:
1162   // TODO: handle out-of-memory
1163   return reply;
1164 }
1165
1166 static DBusMessage *
1167 impl_GetIndexInParent (DBusConnection * bus,
1168                        DBusMessage * message, void *user_data)
1169 {
1170   AtkObject *object = (AtkObject *) user_data;
1171   dbus_int32_t rv;
1172   DBusMessage *reply;
1173
1174   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1175                         droute_not_yet_handled_error (message));
1176
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);
1180   return reply;
1181 }
1182
1183 static gboolean
1184 spi_init_relation_type_table (AtspiRelationType * types)
1185 {
1186   gint i;
1187
1188   for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
1189     types[i] = ATSPI_RELATION_NULL;
1190
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;
1209
1210   return TRUE;
1211 }
1212
1213 static AtspiRelationType
1214 spi_relation_type_from_atk_relation_type (AtkRelationType type)
1215 {
1216   static gboolean is_initialized = FALSE;
1217   static AtspiRelationType
1218     spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
1219   AtspiRelationType spi_type;
1220
1221   if (!is_initialized)
1222     is_initialized = spi_init_relation_type_table (spi_relation_type_table);
1223
1224   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
1225     spi_type = spi_relation_type_table[type];
1226   else
1227     spi_type = ATSPI_RELATION_EXTENDED;
1228   return spi_type;
1229 }
1230
1231 static DBusMessage *
1232 impl_GetRelationSet (DBusConnection * bus,
1233                      DBusMessage * message, void *user_data)
1234 {
1235   AtkObject *object = (AtkObject *) user_data;
1236   DBusMessage *reply;
1237   AtkRelationSet *set;
1238   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
1239   gint count;
1240   gint i, j;
1241
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);
1245   if (!reply)
1246     return NULL;
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))
1251     {
1252       goto oom;
1253     }
1254   count = 0;
1255   if (set)
1256     count = atk_relation_set_get_n_relations (set);
1257   for (i = 0; i < count; i++)
1258     {
1259       AtkRelation *r = atk_relation_set_get_relation (set, i);
1260       AtkRelationType rt;
1261       GPtrArray *target;
1262       dbus_uint32_t type;
1263       if (!r)
1264         continue;
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))
1270         {
1271           goto oom;
1272         }
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))
1276         {
1277           goto oom;
1278         }
1279       for (j = 0; j < target->len; j++)
1280         {
1281           AtkObject *obj = target->pdata[j];
1282           if (!obj)
1283             continue;
1284           spi_object_append_reference (&iter_targets, obj);
1285         }
1286       dbus_message_iter_close_container (&iter_struct, &iter_targets);
1287       dbus_message_iter_close_container (&iter_array, &iter_struct);
1288     }
1289   dbus_message_iter_close_container (&iter, &iter_array);
1290 oom:
1291   if (set)
1292     g_object_unref (set);
1293   // TODO: handle out of memory */
1294   return reply;
1295 }
1296
1297 static DBusMessage *
1298 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
1299 {
1300   AtkObject *object = (AtkObject *) user_data;
1301   gint role;
1302   dbus_uint32_t rv;
1303   DBusMessage *reply;
1304
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);
1310   if (reply)
1311     {
1312       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
1313                                 DBUS_TYPE_INVALID);
1314     }
1315   return reply;
1316 }
1317
1318 static DBusMessage *
1319 impl_GetRoleName (DBusConnection * bus,
1320                   DBusMessage * message, void *user_data)
1321 {
1322   AtkObject *object = (AtkObject *) user_data;
1323   gint role;
1324   const char *role_name;
1325   DBusMessage *reply;
1326
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);
1331   if (!role_name)
1332     role_name = "";
1333   reply = dbus_message_new_method_return (message);
1334   if (reply)
1335     {
1336       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
1337                                 DBUS_TYPE_INVALID);
1338     }
1339   return reply;
1340 }
1341
1342 static DBusMessage *
1343 impl_GetLocalizedRoleName (DBusConnection * bus,
1344                            DBusMessage * message, void *user_data)
1345 {
1346   AtkObject *object = (AtkObject *) user_data;
1347   gint role;
1348   const char *role_name;
1349   DBusMessage *reply;
1350
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);
1355   if (!role_name)
1356     role_name = "";
1357   reply = dbus_message_new_method_return (message);
1358   if (reply)
1359     {
1360       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
1361                                 DBUS_TYPE_INVALID);
1362     }
1363   return reply;
1364 }
1365
1366 static DBusMessage *
1367 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
1368 {
1369   AtkObject *object = (AtkObject *) user_data;
1370
1371   DBusMessage *reply = NULL;
1372   DBusMessageIter iter, iter_array;
1373
1374   dbus_uint32_t states[2];
1375
1376   guint count;
1377
1378   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1379                         droute_not_yet_handled_error (message));
1380
1381   reply = dbus_message_new_method_return (message);
1382   dbus_message_iter_init_append (reply, &iter);
1383
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++)
1387     {
1388       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
1389                                       &states[count]);
1390     }
1391   dbus_message_iter_close_container (&iter, &iter_array);
1392   return reply;
1393 }
1394
1395 static DBusMessage *
1396 impl_GetAttributes (DBusConnection * bus,
1397                     DBusMessage * message, void *user_data)
1398 {
1399   AtkObject *object = (AtkObject *) user_data;
1400   AtkAttributeSet *attributes;
1401   DBusMessage *reply = NULL;
1402   DBusMessageIter iter;
1403
1404   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
1405                         droute_not_yet_handled_error (message));
1406
1407   attributes = atk_object_get_attributes (object);
1408
1409   reply = dbus_message_new_method_return (message);
1410   dbus_message_iter_init_append (reply, &iter);
1411   spi_object_append_attribute_set (&iter, attributes);
1412
1413   atk_attribute_set_free (attributes);
1414
1415   return reply;
1416 }
1417
1418 static dbus_bool_t
1419 impl_get_Attributes (DBusMessageIter * iter, void *user_data)
1420 {
1421   DBusMessageIter iter_variant;
1422   AtkObject *object = (AtkObject *) user_data;
1423   AtkAttributeSet *attributes;
1424
1425   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
1426
1427   attributes = atk_object_get_attributes (object);
1428
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);
1432
1433   atk_attribute_set_free (attributes);
1434
1435   return TRUE;
1436 }
1437
1438 static DBusMessage *
1439 impl_GetApplication (DBusConnection * bus,
1440                      DBusMessage * message, void *user_data)
1441 {
1442   return spi_object_return_reference (message, atk_get_root ());
1443 }
1444
1445 static DBusMessage *
1446 impl_GetInterfaces (DBusConnection * bus,
1447                     DBusMessage * message, void *user_data)
1448 {
1449   AtkObject *object = (AtkObject *) user_data;
1450   DBusMessage *reply;
1451   DBusMessageIter iter, iter_array;
1452
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);
1456   if (reply)
1457     {
1458       dbus_message_iter_init_append (reply, &iter);
1459       dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
1460                                         &iter_array);
1461       spi_object_append_interfaces (&iter_array, object);
1462       dbus_message_iter_close_container (&iter, &iter_array);
1463     }
1464   return reply;
1465 }
1466
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"},
1472 //
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"},
1484   {NULL, NULL}
1485 };
1486
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"},
1494   {NULL, NULL, NULL}
1495 };
1496
1497 void
1498 spi_initialize_accessible (DRoutePath * path)
1499 {
1500   spi_atk_add_interface (path,
1501                          ATSPI_DBUS_INTERFACE_ACCESSIBLE,
1502                          spi_org_a11y_atspi_Accessible,
1503                          methods, properties);
1504 };