a84052a03325df746fc06972de65419aff551e8f
[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
38
39
40
41
42
43
44
45
46
47
48
49
50 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
51 static AtspiRelationType spi_relation_type_from_atk_relation_type (AtkRelationType type);
52
53 static AtspiRole _object_get_role_impl(void *ptr)
54 {
55   AtkObject *obj = (AtkObject*)ptr;
56   AtkRole role = atk_object_get_role (obj);
57   AtspiRole rv = spi_accessible_role_from_atk_role (role);
58   return rv;
59 }
60
61 static uint64_t _object_get_state_set_impl(void *ptr)
62 {
63   dbus_uint32_t array[2];
64   spi_atk_state_to_dbus_array((AtkObject*)ptr, array);
65   uint64_t res = array[0] | ((uint64_t)array[1] << 32);
66   return res;
67 }
68
69 static void *_get_object_in_relation_by_type_impl(void *ptr, AtspiRelationType expected_relation_type)
70 {
71   if (ptr) {
72     g_return_val_if_fail (ATK_IS_OBJECT (ptr), NULL);
73     AtkRelationSet *set = atk_object_ref_relation_set (ptr);
74     if (!set)
75       return NULL;
76     gint count = atk_relation_set_get_n_relations (set), i;
77     for (i = 0; i < count; i++)
78     {
79       AtkRelation *r = atk_relation_set_get_relation (set, i);
80       if (!r)
81         continue;
82       AtkRelationType rt = atk_relation_get_relation_type (r);
83       AtspiRelationType type = spi_relation_type_from_atk_relation_type (rt);
84       if (expected_relation_type == type)
85       {
86         GPtrArray *target = atk_relation_get_target (r);
87         if (target && target->len > 0)
88           return target->pdata[0];
89       }
90     }
91     g_object_unref (set);
92   }
93   return NULL;
94 }
95
96 static unsigned char _object_is_zero_size_impl(void *ptr)
97 {
98   AtkObject *obj = (AtkObject*)obj;
99   g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
100   gint x, y, w, h;
101   atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &w, &h, ATSPI_COORD_TYPE_SCREEN);
102   return w == 0 || h == 0;
103 }
104
105 unsigned char _object_is_scrollable_impl(void *ptr)
106 {
107   AtspiRole role = _object_get_role_impl(ptr);
108   switch (role) {
109   case ATSPI_ROLE_SCROLL_PANE:    //scroller
110   case ATSPI_ROLE_LIST:           //genlist, list
111   case ATSPI_ROLE_TREE_TABLE:     //gengrid
112   case ATSPI_ROLE_TOOL_BAR:       //toolbar
113       return 1;
114   default:
115       break;
116   }
117   return 0;
118 }
119
120 void *_get_parent_impl(void *ptr)
121 {
122   return atk_object_get_parent((AtkObject*)ptr);
123 }
124
125 void *_object_at_point_get_impl(void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
126 {
127   AtkObject *obj = (AtkObject*)ptr;
128   g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
129   return atk_component_ref_accessible_at_point (ATK_COMPONENT(obj), x, y,
130           coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
131 }
132
133 unsigned char _object_contains_impl(void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
134 {
135   AtkObject *obj = (AtkObject*)ptr;
136   g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
137
138   return atk_component_contains (ATK_COMPONENT(obj), x, y,
139         coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
140 }
141
142 unsigned char _object_is_proxy_impl(void *ptr)
143 {
144   return 0;
145 }
146
147 typedef struct {
148    AtspiRole (*object_get_role)(void *ptr);
149    uint64_t (*object_get_state_set)(void *ptr);
150    void *(*get_object_in_relation_by_type)(void *ptr, AtspiRelationType type);
151    unsigned char (*object_is_zero_size)(void *ptr);
152    void *(*get_parent)(void *ptr);
153    unsigned char (*object_is_scrollable)(void *ptr);
154    void *(*object_at_point_get)(void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
155    unsigned char (*object_contains)(void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
156    unsigned char (*object_is_proxy)(void *ptr);
157 } accessibility_navigation_pointer_table;
158
159 static unsigned char _accept_object_check_role(accessibility_navigation_pointer_table *table, void *obj)
160 {
161    AtspiRole role = table->object_get_role(obj);
162    switch (role)
163      {
164        case ATSPI_ROLE_APPLICATION:
165        case ATSPI_ROLE_FILLER:
166        case ATSPI_ROLE_SCROLL_PANE:
167        case ATSPI_ROLE_SPLIT_PANE:
168        case ATSPI_ROLE_WINDOW:
169        case ATSPI_ROLE_IMAGE:
170        case ATSPI_ROLE_LIST:
171        case ATSPI_ROLE_ICON:
172        case ATSPI_ROLE_TOOL_BAR:
173        case ATSPI_ROLE_REDUNDANT_OBJECT:
174        case ATSPI_ROLE_COLOR_CHOOSER:
175        case ATSPI_ROLE_PANEL:
176        case ATSPI_ROLE_TREE_TABLE:
177        case ATSPI_ROLE_PAGE_TAB_LIST:
178        case ATSPI_ROLE_PAGE_TAB:
179        case ATSPI_ROLE_SPIN_BUTTON:
180        case ATSPI_ROLE_INPUT_METHOD_WINDOW:
181        case ATSPI_ROLE_EMBEDDED:
182        case ATSPI_ROLE_INVALID:
183        case ATSPI_ROLE_NOTIFICATION:
184          return 0;
185        default:
186          break;
187      }
188    return 1;
189 }
190
191 static unsigned char _state_set_is_set(uint64_t state_set, AtspiStateType state)
192 {
193    return (state_set & ((uint64_t)1 << (unsigned int)state)) != 0;
194 }
195
196 static unsigned char _object_is_item(accessibility_navigation_pointer_table *table, void *obj)
197 {
198    AtspiRole role = table->object_get_role(obj);
199    return role == ATSPI_ROLE_LIST_ITEM || role == ATSPI_ROLE_MENU_ITEM;
200 }
201
202 static unsigned char _object_is_highlightable(accessibility_navigation_pointer_table *table, void *obj)
203 {
204    uint64_t state_set = table->object_get_state_set(obj);
205    return _state_set_is_set(state_set, ATSPI_STATE_HIGHLIGHTABLE);
206 }
207
208 static unsigned char _object_is_showing(accessibility_navigation_pointer_table *table, void *obj)
209 {
210    uint64_t state_set = table->object_get_state_set(obj);
211    return _state_set_is_set(state_set, ATSPI_STATE_SHOWING);
212 }
213
214 static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table *table, void *obj)
215 {
216    uint64_t state_set = table->object_get_state_set(obj);
217    return
218       _state_set_is_set(state_set, ATSPI_STATE_EXPANDABLE) &&
219       !_state_set_is_set(state_set, ATSPI_STATE_EXPANDED);
220 }
221
222 static unsigned char _object_has_modal_state(accessibility_navigation_pointer_table *table, void *obj)
223 {
224    uint64_t state_set = table->object_get_state_set(obj);
225    return _state_set_is_set(state_set, ATSPI_STATE_MODAL);
226 }
227
228 static unsigned char _object_is_zero_size(accessibility_navigation_pointer_table *table, void *obj)
229 {
230    return table->object_is_zero_size(obj);
231 }
232
233 static void *_get_scrollable_parent(accessibility_navigation_pointer_table *table, void *obj)
234 {
235    while(obj)
236      {
237        obj = table->get_parent(obj);
238        if (obj && table->object_is_scrollable(obj)) return obj;
239      }
240    return NULL;
241 }
242 static unsigned char _accept_object(accessibility_navigation_pointer_table *table, void *obj)
243 {
244    if (!obj) return 0;
245    if (!_accept_object_check_role(table, obj)) return 0;
246    if (table->get_object_in_relation_by_type(obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
247    if (!_object_is_highlightable(table, obj)) return 0;
248
249    if (_get_scrollable_parent(table, obj) != NULL)
250      {
251        void *parent = table->get_parent(obj);
252
253        if (parent)
254          {
255            return !_object_is_item(table, obj) || !_object_is_collapsed(table, parent);
256          }
257      }
258    else
259      {
260        if (_object_is_zero_size(table, obj)) return 0;
261        if (!_object_is_showing(table, obj)) return 0;
262      }
263    return 1;
264 }
265
266 static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigation_pointer_table *table,
267           void *root, int x, int y, unsigned char coordinates_are_screen_based)
268 {
269    if (!root) return NULL;
270
271    void *return_value = NULL;
272    while (1)
273      {
274        void *target = table->object_at_point_get(root, x, y, coordinates_are_screen_based);
275        if (!target) break;
276
277        // always return proxy, so atspi lib can call on it again
278        if (table->object_is_proxy(target)) return target;
279
280        root = target;
281        void *relation_obj = table->get_object_in_relation_by_type(root, ATSPI_RELATION_CONTROLLED_BY);
282        unsigned char contains = 0;
283        if (relation_obj)
284          {
285            contains = table->object_contains(relation_obj, x, y, coordinates_are_screen_based);
286            if (contains) root = relation_obj;
287          }
288
289        if (_accept_object(table, root))
290          {
291            return_value = root;
292            if (contains) break;
293          }
294      }
295
296    if (return_value && _object_has_modal_state(table, return_value)) return_value = NULL;
297    return return_value;
298 }
299
300 accessibility_navigation_pointer_table construct_accessibility_navigation_pointer_table(void)
301 {
302    accessibility_navigation_pointer_table table;
303 #define INIT(n) table.n = _## n ## _impl
304    INIT(object_get_role);
305    INIT(object_get_state_set);
306    INIT(get_object_in_relation_by_type);
307    INIT(object_is_zero_size);
308    INIT(get_parent);
309    INIT(object_is_scrollable);
310    INIT(object_at_point_get);
311    INIT(object_contains);
312    INIT(object_is_proxy);
313 #undef INIT
314    return table;
315 }
316 static AtkObject *_calculate_navigable_accessible_at_point(AtkObject *root, unsigned char coord_type, int x, int y)
317 {
318    accessibility_navigation_pointer_table table = construct_accessibility_navigation_pointer_table();
319    AtkObject *result = (AtkObject*)_calculate_navigable_accessible_at_point_impl(&table, root, x, y, coord_type ? 1 : 0);
320    return result;
321 }
322
323 static DBusMessage *
324 impl_GetNavigableAtPoint (DBusConnection * bus, DBusMessage * message,
325                            void *user_data)
326 {
327   AtkObject *object = (AtkObject *) user_data;
328   dbus_int32_t x, y;
329   dbus_uint32_t coord_type;
330   DBusMessage *reply;
331   AtkObject *child;
332
333   g_return_val_if_fail (ATK_IS_COMPONENT (object),
334                         droute_not_yet_handled_error (message));
335
336   if (!dbus_message_get_args
337       (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
338        DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
339     {
340       return droute_invalid_arguments_error (message);
341     }
342   child = (AtkObject*)
343       _calculate_navigable_accessible_at_point (object, coord_type == ATSPI_COORD_TYPE_SCREEN, x, y);
344
345   reply = spi_object_return_reference_and_recurse_flag (message, child, 0);
346   if (child)
347     g_object_unref (child);
348
349   return reply;
350 }
351 //
352
353 static dbus_bool_t
354 impl_get_Name (DBusMessageIter * iter, void *user_data)
355 {
356   AtkObject *object = (AtkObject *) user_data;
357
358   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
359
360   return droute_return_v_string (iter, atk_object_get_name (object));
361 }
362
363 static dbus_bool_t
364 impl_get_Description (DBusMessageIter * iter, void *user_data)
365 {
366   AtkObject *object = (AtkObject *) user_data;
367
368   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
369
370   return droute_return_v_string (iter, atk_object_get_description (object));
371 }
372
373 static dbus_bool_t
374 impl_get_Locale (DBusMessageIter * iter, void *user_data)
375 {
376   AtkObject *object = (AtkObject *) user_data;
377
378   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
379
380   return droute_return_v_string (iter, atk_object_get_object_locale (object));
381 }
382
383 static dbus_bool_t
384 impl_get_Parent (DBusMessageIter * iter, void *user_data)
385 {
386   AtkObject *obj = (AtkObject *) user_data;
387   AtkObject *parent;
388   DBusMessageIter iter_variant;
389   dbus_uint32_t role;
390
391   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
392
393   role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
394
395   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
396                                     &iter_variant);
397
398   parent = atk_object_get_parent (obj);
399   if (parent == NULL)
400     {
401       /* TODO, move in to a 'Plug' wrapper. */
402       if (ATK_IS_PLUG (obj))
403         {
404           char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
405           char *bus_parent;
406           char *path_parent;
407
408           if (id)
409             {
410               bus_parent = g_strdup (id);
411               if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
412                 {
413                   DBusMessageIter iter_parent;
414                   *(path_parent++) = '\0';
415                   dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
416                                                     &iter_parent);
417                   dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
418                   dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
419                   dbus_message_iter_close_container (&iter_variant, &iter_parent);
420                 }
421               else
422                 {
423                   spi_object_append_null_reference (&iter_variant);
424                 }
425             }
426           else
427             {
428               spi_object_append_null_reference (&iter_variant);
429             }
430         }
431       else if (role != ATSPI_ROLE_APPLICATION)
432          spi_object_append_null_reference (&iter_variant);
433       else
434          spi_object_append_desktop_reference (&iter_variant);
435       }
436   else
437     {
438       spi_object_append_reference (&iter_variant, parent);
439     }
440
441
442   dbus_message_iter_close_container (iter, &iter_variant);
443   return TRUE;
444 }
445
446 static dbus_bool_t
447 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
448 {
449   AtkObject *object = (AtkObject *) user_data;
450   int childCount;
451
452   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
453
454   childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
455                ? 1
456                : atk_object_get_n_accessible_children (object);
457   return droute_return_v_int32 (iter, childCount);
458 }
459
460 static DBusMessage *
461 impl_GetChildAtIndex (DBusConnection * bus,
462                       DBusMessage * message, void *user_data)
463 {
464   AtkObject *object = (AtkObject *) user_data;
465   DBusMessage *reply;
466   dbus_int32_t i;
467   AtkObject *child;
468
469   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
470                         droute_not_yet_handled_error (message));
471   if (!dbus_message_get_args
472        (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
473     {
474       return droute_invalid_arguments_error (message);
475     }
476
477   if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
478     {
479       AtkSocket *socket = ATK_SOCKET (object);
480       gchar *child_name, *child_path;
481       child_name = g_strdup (socket->embedded_plug_id);
482       child_path = g_utf8_strchr (child_name + 1, -1, ':');
483       if (child_path)
484         {
485           DBusMessageIter iter, iter_socket;
486           *(child_path++) = '\0';
487           reply = dbus_message_new_method_return (message);
488           if (!reply)
489             return NULL;
490           dbus_message_iter_init_append (reply, &iter);
491           dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
492                                             &iter_socket);
493           dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
494           dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
495           dbus_message_iter_close_container (&iter, &iter_socket);
496           return reply;
497         }
498       g_free (child_name);
499     }
500   child = atk_object_ref_accessible_child (object, i);
501   reply = spi_object_return_reference (message, child);
502   g_object_unref (child);
503
504   return reply;
505 }
506
507 static DBusMessage *
508 impl_GetChildren (DBusConnection * bus,
509                   DBusMessage * message, void *user_data)
510 {
511   AtkObject *object = (AtkObject *) user_data;
512   gint i;
513   gint count;
514   DBusMessage *reply;
515   DBusMessageIter iter, iter_array;
516
517   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
518                         droute_not_yet_handled_error (message));
519   count = atk_object_get_n_accessible_children (object);
520   reply = dbus_message_new_method_return (message);
521   if (!reply)
522     goto oom;
523   dbus_message_iter_init_append (reply, &iter);
524   if (!dbus_message_iter_open_container
525       (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
526     goto oom;
527   for (i = 0; i < count; i++)
528     {
529       AtkObject *child = atk_object_ref_accessible_child (object, i);
530       spi_object_append_reference (&iter_array, child);
531       if (child)
532         g_object_unref (child);
533     }
534   if (!dbus_message_iter_close_container (&iter, &iter_array))
535     goto oom;
536   return reply;
537 oom:
538   // TODO: handle out-of-memory
539   return reply;
540 }
541
542 static DBusMessage *
543 impl_GetIndexInParent (DBusConnection * bus,
544                        DBusMessage * message, void *user_data)
545 {
546   AtkObject *object = (AtkObject *) user_data;
547   dbus_int32_t rv;
548   DBusMessage *reply;
549
550   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
551                         droute_not_yet_handled_error (message));
552
553   rv = atk_object_get_index_in_parent (object);
554   reply = dbus_message_new_method_return (message);
555   dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv, DBUS_TYPE_INVALID);
556   return reply;
557 }
558
559 static gboolean
560 spi_init_relation_type_table (AtspiRelationType * types)
561 {
562   gint i;
563
564   for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
565     types[i] = ATSPI_RELATION_NULL;
566
567   types[ATK_RELATION_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY;
568   types[ATK_RELATION_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR;
569   types[ATK_RELATION_LABEL_FOR] = ATSPI_RELATION_LABEL_FOR;
570   types[ATK_RELATION_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY;
571   types[ATK_RELATION_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF;
572   types[ATK_RELATION_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF;
573   types[ATK_RELATION_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO;
574   types[ATK_RELATION_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM;
575   types[ATK_RELATION_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF;
576   types[ATK_RELATION_EMBEDS] = ATSPI_RELATION_EMBEDS;
577   types[ATK_RELATION_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY;
578   types[ATK_RELATION_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR;
579   types[ATK_RELATION_PARENT_WINDOW_OF] =
580     ATSPI_RELATION_PARENT_WINDOW_OF;
581   types[ATK_RELATION_DESCRIPTION_FOR] =
582     ATSPI_RELATION_DESCRIPTION_FOR;
583   types[ATK_RELATION_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY;
584   types[ATK_RELATION_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF;
585
586   return TRUE;
587 }
588
589 static AtspiRelationType
590 spi_relation_type_from_atk_relation_type (AtkRelationType type)
591 {
592   static gboolean is_initialized = FALSE;
593   static AtspiRelationType
594     spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
595   AtspiRelationType spi_type;
596
597   if (!is_initialized)
598     is_initialized = spi_init_relation_type_table (spi_relation_type_table);
599
600   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
601     spi_type = spi_relation_type_table[type];
602   else
603     spi_type = ATSPI_RELATION_EXTENDED;
604   return spi_type;
605 }
606
607 static DBusMessage *
608 impl_GetRelationSet (DBusConnection * bus,
609                      DBusMessage * message, void *user_data)
610 {
611   AtkObject *object = (AtkObject *) user_data;
612   DBusMessage *reply;
613   AtkRelationSet *set;
614   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
615   gint count;
616   gint i, j;
617
618   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
619                         droute_not_yet_handled_error (message));
620   reply = dbus_message_new_method_return (message);
621   if (!reply)
622     return NULL;
623   set = atk_object_ref_relation_set (object);
624   dbus_message_iter_init_append (reply, &iter);
625   if (!dbus_message_iter_open_container
626       (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
627     {
628       goto oom;
629     }
630   count = 0;
631   if (set)
632     count = atk_relation_set_get_n_relations (set);
633   for (i = 0; i < count; i++)
634     {
635       AtkRelation *r = atk_relation_set_get_relation (set, i);
636       AtkRelationType rt;
637       GPtrArray *target;
638       dbus_uint32_t type;
639       if (!r)
640         continue;
641       rt = atk_relation_get_relation_type (r);
642       type = spi_relation_type_from_atk_relation_type (rt);
643       target = atk_relation_get_target (r);
644       if (!dbus_message_iter_open_container
645           (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
646         {
647           goto oom;
648         }
649       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
650       if (!dbus_message_iter_open_container
651           (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
652         {
653           goto oom;
654         }
655       for (j = 0; j < target->len; j++)
656         {
657           AtkObject *obj = target->pdata[j];
658           if (!obj)
659             continue;
660           spi_object_append_reference (&iter_targets, obj);
661         }
662       dbus_message_iter_close_container (&iter_struct, &iter_targets);
663       dbus_message_iter_close_container (&iter_array, &iter_struct);
664     }
665   dbus_message_iter_close_container (&iter, &iter_array);
666 oom:
667   if (set)
668     g_object_unref (set);
669   // TODO: handle out of memory */
670   return reply;
671 }
672
673 static DBusMessage *
674 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
675 {
676   AtkObject *object = (AtkObject *) user_data;
677   gint role;
678   dbus_uint32_t rv;
679   DBusMessage *reply;
680
681   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
682                         droute_not_yet_handled_error (message));
683   role = atk_object_get_role (object);
684   rv = spi_accessible_role_from_atk_role (role);
685   reply = dbus_message_new_method_return (message);
686   if (reply)
687     {
688       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
689                                 DBUS_TYPE_INVALID);
690     }
691   return reply;
692 }
693
694 static DBusMessage *
695 impl_GetRoleName (DBusConnection * bus,
696                   DBusMessage * message, void *user_data)
697 {
698   AtkObject *object = (AtkObject *) user_data;
699   gint role;
700   const char *role_name;
701   DBusMessage *reply;
702
703   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
704                         droute_not_yet_handled_error (message));
705   role = atk_object_get_role (object);
706   role_name = atk_role_get_name (role);
707   if (!role_name)
708     role_name = "";
709   reply = dbus_message_new_method_return (message);
710   if (reply)
711     {
712       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
713                                 DBUS_TYPE_INVALID);
714     }
715   return reply;
716 }
717
718 static DBusMessage *
719 impl_GetLocalizedRoleName (DBusConnection * bus,
720                            DBusMessage * message, void *user_data)
721 {
722   AtkObject *object = (AtkObject *) user_data;
723   gint role;
724   const char *role_name;
725   DBusMessage *reply;
726
727   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
728                         droute_not_yet_handled_error (message));
729   role = atk_object_get_role (object);
730   role_name = atk_role_get_localized_name (role);
731   if (!role_name)
732     role_name = "";
733   reply = dbus_message_new_method_return (message);
734   if (reply)
735     {
736       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
737                                 DBUS_TYPE_INVALID);
738     }
739   return reply;
740 }
741
742 static DBusMessage *
743 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
744 {
745   AtkObject *object = (AtkObject *) user_data;
746
747   DBusMessage *reply = NULL;
748   DBusMessageIter iter, iter_array;
749
750   dbus_uint32_t states[2];
751
752   guint count;
753
754   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
755                         droute_not_yet_handled_error (message));
756
757   reply = dbus_message_new_method_return (message);
758   dbus_message_iter_init_append (reply, &iter);
759
760   spi_atk_state_to_dbus_array (object, states);
761   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
762   for (count = 0; count < 2; count++)
763     {
764       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
765                                       &states[count]);
766     }
767   dbus_message_iter_close_container (&iter, &iter_array);
768   return reply;
769 }
770
771 static DBusMessage *
772 impl_GetAttributes (DBusConnection * bus,
773                     DBusMessage * message, void *user_data)
774 {
775   AtkObject *object = (AtkObject *) user_data;
776   AtkAttributeSet *attributes;
777   DBusMessage *reply = NULL;
778   DBusMessageIter iter;
779
780   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
781                         droute_not_yet_handled_error (message));
782
783   attributes = atk_object_get_attributes (object);
784
785   reply = dbus_message_new_method_return (message);
786   dbus_message_iter_init_append (reply, &iter);
787   spi_object_append_attribute_set (&iter, attributes);
788
789   atk_attribute_set_free (attributes);
790
791   return reply;
792 }
793
794 static dbus_bool_t
795 impl_get_Attributes (DBusMessageIter * iter, void *user_data)
796 {
797   DBusMessageIter iter_variant;
798   AtkObject *object = (AtkObject *) user_data;
799   AtkAttributeSet *attributes;
800
801   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
802
803   attributes = atk_object_get_attributes (object);
804
805   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "a{ss}", &iter_variant);
806   spi_object_append_attribute_set (&iter_variant, attributes);
807   dbus_message_iter_close_container (iter, &iter_variant);
808
809   atk_attribute_set_free (attributes);
810
811   return TRUE;
812 }
813
814 static DBusMessage *
815 impl_GetApplication (DBusConnection * bus,
816                      DBusMessage * message, void *user_data)
817 {
818   return spi_object_return_reference (message, atk_get_root ());
819 }
820
821 static DBusMessage *
822 impl_GetInterfaces (DBusConnection * bus,
823                     DBusMessage * message, void *user_data)
824 {
825   AtkObject *object = (AtkObject *) user_data;
826   DBusMessage *reply;
827   DBusMessageIter iter, iter_array;
828
829   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
830                         droute_not_yet_handled_error (message));
831   reply = dbus_message_new_method_return (message);
832   if (reply)
833     {
834       dbus_message_iter_init_append (reply, &iter);
835       dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
836                                         &iter_array);
837       spi_object_append_interfaces (&iter_array, object);
838       dbus_message_iter_close_container (&iter, &iter_array);
839     }
840   return reply;
841 }
842
843 static DRouteMethod methods[] = {
844 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
845   {impl_GetNavigableAtPoint, "GetNavigableAtPoint"},
846 //
847   {impl_GetChildAtIndex, "GetChildAtIndex"},
848   {impl_GetChildren, "GetChildren"},
849   {impl_GetIndexInParent, "GetIndexInParent"},
850   {impl_GetRelationSet, "GetRelationSet"},
851   {impl_GetRole, "GetRole"},
852   {impl_GetRoleName, "GetRoleName"},
853   {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
854   {impl_GetState, "GetState"},
855   {impl_GetAttributes, "GetAttributes"},
856   {impl_GetApplication, "GetApplication"},
857   {impl_GetInterfaces, "GetInterfaces"},
858   {NULL, NULL}
859 };
860
861 static DRouteProperty properties[] = {
862   {impl_get_Name, NULL, "Name"},
863   {impl_get_Description, NULL, "Description"},
864   {impl_get_Locale, NULL, "Locale"},
865   {impl_get_Parent, NULL, "Parent"},
866   {impl_get_ChildCount, NULL, "ChildCount"},
867   {impl_get_Attributes, NULL, "Attributes"},
868   {NULL, NULL, NULL}
869 };
870
871 void
872 spi_initialize_accessible (DRoutePath * path)
873 {
874   spi_atk_add_interface (path,
875                          ATSPI_DBUS_INTERFACE_ACCESSIBLE,
876                          spi_org_a11y_atspi_Accessible,
877                          methods, properties);
878 };