Merge branch 'master' of git+ssh://git.codethink.co.uk/git/atspi-dbus
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / accessible.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 "accessible.h"
26
27 #define get_object(message) spi_dbus_get_object(dbus_message_get_path(message))
28
29 static AtkObject *
30 get_object_from_path (const char *path, void *user_data)
31 {
32   return spi_dbus_get_object (path);
33 }
34
35 static dbus_bool_t
36 impl_get_name (const char *path, DBusMessageIter * iter, void *user_data)
37 {
38   AtkObject *object = spi_dbus_get_object (path);
39   if (!object)
40     return FALSE;
41   return droute_return_v_string (iter, atk_object_get_name (object));
42 }
43
44 static dbus_bool_t
45 impl_set_name (const char *path, DBusMessageIter * iter, void *user_data)
46 {
47   AtkObject *object = spi_dbus_get_object (path);
48   const char *name = droute_get_v_string (iter);
49   atk_object_set_name (object, name);
50   return TRUE;
51 }
52
53 static dbus_bool_t
54 impl_get_description (const char *path, DBusMessageIter * iter,
55                       void *user_data)
56 {
57   AtkObject *object = spi_dbus_get_object (path);
58   if (!object)
59     return FALSE;
60   return droute_return_v_string (iter, atk_object_get_description (object));
61 }
62
63 static dbus_bool_t
64 impl_set_description (const char *path, DBusMessageIter * iter,
65                       void *user_data)
66 {
67   AtkObject *object = spi_dbus_get_object (path);
68   const char *description = droute_get_v_string (iter);
69   atk_object_set_description (object, description);
70   return TRUE;
71 }
72
73 static dbus_bool_t
74 impl_get_parent (const char *path, DBusMessageIter * iter, void *user_data)
75 {
76   AtkObject *object = spi_dbus_get_object (path);
77
78   if (!object)
79     return FALSE;
80   return spi_dbus_return_v_object (iter, atk_object_get_parent (object),
81                                    FALSE);
82 }
83
84 static dbus_bool_t
85 impl_get_childCount (const char *path, DBusMessageIter * iter,
86                      void *user_data)
87 {
88   AtkObject *object = spi_dbus_get_object (path);
89
90   if (!object)
91     return FALSE;
92   return droute_return_v_int32 (iter,
93                                 atk_object_get_n_accessible_children
94                                 (object));
95 }
96
97 static DBusMessage *
98 impl_getChildren (DBusConnection * bus, DBusMessage * message,
99                   void *user_data)
100 {
101   AtkObject *object = get_object (message);
102   gint i;
103   gint count;
104   DBusMessage *reply;
105   DBusMessageIter iter, iter_array;
106
107   if (!object)
108     return spi_dbus_general_error (message);
109   count = atk_object_get_n_accessible_children (object);
110   reply = dbus_message_new_method_return (message);
111   if (!reply) goto oom;
112   dbus_message_iter_init_append (reply, &iter);
113   if (!dbus_message_iter_open_container
114       (&iter, DBUS_TYPE_ARRAY, "o", &iter_array))
115     goto oom;
116   for (i = 0; i < count; i++)
117     {
118       AtkObject *child = atk_object_ref_accessible_child (object, i);
119       char *path = spi_dbus_get_path (child);
120       if (path)
121         {
122           dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_OBJECT_PATH,
123                                           &path);
124           g_free (path);
125         }
126       if (child)
127         g_object_unref (child);
128     }
129   if (!dbus_message_iter_close_container (&iter, &iter_array))
130     goto oom;
131   return reply;
132 oom:
133   // TODO: handle out-of-memory
134   return reply;
135 }
136
137 static DBusMessage *
138 impl_getIndexInParent (DBusConnection * bus, DBusMessage * message,
139                        void *user_data)
140 {
141   AtkObject *object = get_object (message);
142   dbus_uint32_t rv;
143   DBusMessage *reply;
144
145   if (!object)
146     return spi_dbus_general_error (message);
147   rv = atk_object_get_index_in_parent (object);
148   reply = dbus_message_new_method_return (message);
149   if (reply)
150     {
151       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
152                                 DBUS_TYPE_INVALID);
153     }
154   return reply;
155 }
156
157 static gboolean
158 spi_init_relation_type_table (Accessibility_RelationType *types)
159 {
160   gint i;
161
162   for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
163     types[i] = Accessibility_RELATION_NULL;
164
165   types[ATK_RELATION_CONTROLLED_BY] = Accessibility_RELATION_CONTROLLED_BY;
166   types[ATK_RELATION_CONTROLLER_FOR] = Accessibility_RELATION_CONTROLLER_FOR;
167   types[ATK_RELATION_LABEL_FOR] = Accessibility_RELATION_LABEL_FOR;
168   types[ATK_RELATION_LABELLED_BY] = Accessibility_RELATION_LABELLED_BY;
169   types[ATK_RELATION_MEMBER_OF] = Accessibility_RELATION_MEMBER_OF;
170   types[ATK_RELATION_NODE_CHILD_OF] = Accessibility_RELATION_NODE_CHILD_OF;
171   types[ATK_RELATION_FLOWS_TO] = Accessibility_RELATION_FLOWS_TO;
172   types[ATK_RELATION_FLOWS_FROM] = Accessibility_RELATION_FLOWS_FROM;
173   types[ATK_RELATION_SUBWINDOW_OF] = Accessibility_RELATION_SUBWINDOW_OF;
174   types[ATK_RELATION_EMBEDS] = Accessibility_RELATION_EMBEDS;
175   types[ATK_RELATION_EMBEDDED_BY] = Accessibility_RELATION_EMBEDDED_BY;
176   types[ATK_RELATION_POPUP_FOR] = Accessibility_RELATION_POPUP_FOR;
177   types[ATK_RELATION_PARENT_WINDOW_OF] = Accessibility_RELATION_PARENT_WINDOW_OF;
178   types[ATK_RELATION_DESCRIPTION_FOR] = Accessibility_RELATION_DESCRIPTION_FOR;
179   types[ATK_RELATION_DESCRIBED_BY] = Accessibility_RELATION_DESCRIBED_BY;
180
181   return TRUE;
182 }
183
184 static Accessibility_RelationType
185 spi_relation_type_from_atk_relation_type (AtkRelationType type)
186 {
187   static gboolean is_initialized = FALSE;
188   static Accessibility_RelationType spi_relation_type_table [ATK_RELATION_LAST_DEFINED];
189   Accessibility_RelationType spi_type;
190
191   if (!is_initialized)
192     is_initialized = spi_init_relation_type_table (spi_relation_type_table);       
193
194   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
195     spi_type = spi_relation_type_table[type];
196   else
197     spi_type = Accessibility_RELATION_EXTENDED;
198   return spi_type;
199 }
200
201 static DBusMessage *
202 impl_getRelationSet (DBusConnection * bus, DBusMessage * message,
203                      void *user_data)
204 {
205   AtkObject *object = get_object (message);
206   DBusMessage *reply;
207   AtkRelationSet *set;
208   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
209   gint count;
210   gint i, j;
211
212   if (!object)
213     return spi_dbus_general_error (message);
214   reply = dbus_message_new_method_return (message);
215   if (!reply) return NULL;
216   set = atk_object_ref_relation_set (object);
217   dbus_message_iter_init_append (reply, &iter);
218   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(uao)", &iter_array))
219   {
220     goto oom;
221   }
222   count = atk_relation_set_get_n_relations (set);
223   for (i = 0; i < count; i++)
224   {
225     AtkRelation *r = atk_relation_set_get_relation (set, i);
226     AtkRelationType rt;
227     GPtrArray *target;
228     dbus_uint32_t type;
229     if (!r) continue;
230     rt= atk_relation_get_relation_type (r);
231     type = spi_relation_type_from_atk_relation_type (rt);
232     target = atk_relation_get_target (r);
233     if (!dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
234     {
235       goto oom;
236     }
237     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
238     if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_targets))
239     {
240       goto oom;
241     }
242     for (j = 0; j < target->len; j++)
243     {
244       AtkObject *obj = target->pdata[j];
245       char *path;
246       if (!obj) continue;
247       path = spi_dbus_get_path (obj);
248       dbus_message_iter_append (&iter_targets, DBUS_TYPE_OBJECT_PATH, &path);
249     }
250     dbus_message_iter_close_container (&iter_struct, &iter_targets);
251     dbus_message_iter_close_container (&iter_array, &iter_struct);
252   }
253   dbus_message_iter_close_container (&iter, &iter_array);
254 oom:
255   // TODO: handle out of memory */
256   return reply;
257 }
258
259 static gboolean
260 spi_init_role_lookup_table (Accessibility_Role * role_table)
261 {
262   int i;
263   /* if it's not in the list below, dunno what it is */
264   for (i = 0; i < ATK_ROLE_LAST_DEFINED; ++i)
265     {
266       role_table[i] = Accessibility_ROLE_UNKNOWN;
267     }
268
269   role_table[ATK_ROLE_INVALID] = Accessibility_ROLE_INVALID;
270   role_table[ATK_ROLE_ACCEL_LABEL] = Accessibility_ROLE_ACCELERATOR_LABEL;
271   role_table[ATK_ROLE_ALERT] = Accessibility_ROLE_ALERT;
272   role_table[ATK_ROLE_ANIMATION] = Accessibility_ROLE_ANIMATION;
273   role_table[ATK_ROLE_ARROW] = Accessibility_ROLE_ARROW;
274   role_table[ATK_ROLE_CALENDAR] = Accessibility_ROLE_CALENDAR;
275   role_table[ATK_ROLE_CANVAS] = Accessibility_ROLE_CANVAS;
276   role_table[ATK_ROLE_CHECK_BOX] = Accessibility_ROLE_CHECK_BOX;
277   role_table[ATK_ROLE_CHECK_MENU_ITEM] = Accessibility_ROLE_CHECK_MENU_ITEM;
278   role_table[ATK_ROLE_COLOR_CHOOSER] = Accessibility_ROLE_COLOR_CHOOSER;
279   role_table[ATK_ROLE_COLUMN_HEADER] = Accessibility_ROLE_COLUMN_HEADER;
280   role_table[ATK_ROLE_COMBO_BOX] = Accessibility_ROLE_COMBO_BOX;
281   role_table[ATK_ROLE_DATE_EDITOR] = Accessibility_ROLE_DATE_EDITOR;
282   role_table[ATK_ROLE_DESKTOP_ICON] = Accessibility_ROLE_DESKTOP_ICON;
283   role_table[ATK_ROLE_DESKTOP_FRAME] = Accessibility_ROLE_DESKTOP_FRAME;
284   role_table[ATK_ROLE_DIAL] = Accessibility_ROLE_DIAL;
285   role_table[ATK_ROLE_DIALOG] = Accessibility_ROLE_DIALOG;
286   role_table[ATK_ROLE_DIRECTORY_PANE] = Accessibility_ROLE_DIRECTORY_PANE;
287   role_table[ATK_ROLE_DRAWING_AREA] = Accessibility_ROLE_DRAWING_AREA;
288   role_table[ATK_ROLE_FILE_CHOOSER] = Accessibility_ROLE_FILE_CHOOSER;
289   role_table[ATK_ROLE_FILLER] = Accessibility_ROLE_FILLER;
290   role_table[ATK_ROLE_FONT_CHOOSER] = Accessibility_ROLE_FONT_CHOOSER;
291   role_table[ATK_ROLE_FRAME] = Accessibility_ROLE_FRAME;
292   role_table[ATK_ROLE_GLASS_PANE] = Accessibility_ROLE_GLASS_PANE;
293   role_table[ATK_ROLE_HTML_CONTAINER] = Accessibility_ROLE_HTML_CONTAINER;
294   role_table[ATK_ROLE_ICON] = Accessibility_ROLE_ICON;
295   role_table[ATK_ROLE_IMAGE] = Accessibility_ROLE_IMAGE;
296   role_table[ATK_ROLE_INTERNAL_FRAME] = Accessibility_ROLE_INTERNAL_FRAME;
297   role_table[ATK_ROLE_LABEL] = Accessibility_ROLE_LABEL;
298   role_table[ATK_ROLE_LAYERED_PANE] = Accessibility_ROLE_LAYERED_PANE;
299   role_table[ATK_ROLE_LIST] = Accessibility_ROLE_LIST;
300   role_table[ATK_ROLE_LIST_ITEM] = Accessibility_ROLE_LIST_ITEM;
301   role_table[ATK_ROLE_MENU] = Accessibility_ROLE_MENU;
302   role_table[ATK_ROLE_MENU_BAR] = Accessibility_ROLE_MENU_BAR;
303   role_table[ATK_ROLE_MENU_ITEM] = Accessibility_ROLE_MENU_ITEM;
304   role_table[ATK_ROLE_OPTION_PANE] = Accessibility_ROLE_OPTION_PANE;
305   role_table[ATK_ROLE_PAGE_TAB] = Accessibility_ROLE_PAGE_TAB;
306   role_table[ATK_ROLE_PAGE_TAB_LIST] = Accessibility_ROLE_PAGE_TAB_LIST;
307   role_table[ATK_ROLE_PANEL] = Accessibility_ROLE_PANEL;
308   role_table[ATK_ROLE_PASSWORD_TEXT] = Accessibility_ROLE_PASSWORD_TEXT;
309   role_table[ATK_ROLE_POPUP_MENU] = Accessibility_ROLE_POPUP_MENU;
310   role_table[ATK_ROLE_PROGRESS_BAR] = Accessibility_ROLE_PROGRESS_BAR;
311   role_table[ATK_ROLE_PUSH_BUTTON] = Accessibility_ROLE_PUSH_BUTTON;
312   role_table[ATK_ROLE_RADIO_BUTTON] = Accessibility_ROLE_RADIO_BUTTON;
313   role_table[ATK_ROLE_RADIO_MENU_ITEM] = Accessibility_ROLE_RADIO_MENU_ITEM;
314   role_table[ATK_ROLE_ROOT_PANE] = Accessibility_ROLE_ROOT_PANE;
315   role_table[ATK_ROLE_ROW_HEADER] = Accessibility_ROLE_ROW_HEADER;
316   role_table[ATK_ROLE_SCROLL_BAR] = Accessibility_ROLE_SCROLL_BAR;
317   role_table[ATK_ROLE_SCROLL_PANE] = Accessibility_ROLE_SCROLL_PANE;
318   role_table[ATK_ROLE_SEPARATOR] = Accessibility_ROLE_SEPARATOR;
319   role_table[ATK_ROLE_SLIDER] = Accessibility_ROLE_SLIDER;
320   role_table[ATK_ROLE_SPIN_BUTTON] = Accessibility_ROLE_SPIN_BUTTON;
321   role_table[ATK_ROLE_SPLIT_PANE] = Accessibility_ROLE_SPLIT_PANE;
322   role_table[ATK_ROLE_STATUSBAR] = Accessibility_ROLE_STATUS_BAR;
323   role_table[ATK_ROLE_TABLE] = Accessibility_ROLE_TABLE;
324   role_table[ATK_ROLE_TABLE_CELL] = Accessibility_ROLE_TABLE_CELL;
325   role_table[ATK_ROLE_TABLE_COLUMN_HEADER] =
326     Accessibility_ROLE_TABLE_COLUMN_HEADER;
327   role_table[ATK_ROLE_TABLE_ROW_HEADER] = Accessibility_ROLE_TABLE_ROW_HEADER;
328   role_table[ATK_ROLE_TEAR_OFF_MENU_ITEM] =
329     Accessibility_ROLE_TEAROFF_MENU_ITEM;
330   role_table[ATK_ROLE_TERMINAL] = Accessibility_ROLE_TERMINAL;
331   role_table[ATK_ROLE_TEXT] = Accessibility_ROLE_TEXT;
332   role_table[ATK_ROLE_TOGGLE_BUTTON] = Accessibility_ROLE_TOGGLE_BUTTON;
333   role_table[ATK_ROLE_TOOL_BAR] = Accessibility_ROLE_TOOL_BAR;
334   role_table[ATK_ROLE_TOOL_TIP] = Accessibility_ROLE_TOOL_TIP;
335   role_table[ATK_ROLE_TREE] = Accessibility_ROLE_TREE;
336   role_table[ATK_ROLE_TREE_TABLE] = Accessibility_ROLE_TREE_TABLE;
337   role_table[ATK_ROLE_UNKNOWN] = Accessibility_ROLE_UNKNOWN;
338   role_table[ATK_ROLE_VIEWPORT] = Accessibility_ROLE_VIEWPORT;
339   role_table[ATK_ROLE_WINDOW] = Accessibility_ROLE_WINDOW;
340   role_table[ATK_ROLE_HEADER] = Accessibility_ROLE_HEADER;
341   role_table[ATK_ROLE_FOOTER] = Accessibility_ROLE_FOOTER;
342   role_table[ATK_ROLE_PARAGRAPH] = Accessibility_ROLE_PARAGRAPH;
343   role_table[ATK_ROLE_RULER] = Accessibility_ROLE_RULER;
344   role_table[ATK_ROLE_APPLICATION] = Accessibility_ROLE_APPLICATION;
345   role_table[ATK_ROLE_AUTOCOMPLETE] = Accessibility_ROLE_AUTOCOMPLETE;
346   role_table[ATK_ROLE_EDITBAR] = Accessibility_ROLE_EDITBAR;
347   role_table[ATK_ROLE_EMBEDDED] = Accessibility_ROLE_EMBEDDED;
348   role_table[ATK_ROLE_ENTRY] = Accessibility_ROLE_ENTRY;
349   role_table[ATK_ROLE_CHART] = Accessibility_ROLE_CHART;
350   role_table[ATK_ROLE_CAPTION] = Accessibility_ROLE_CAPTION;
351   role_table[ATK_ROLE_DOCUMENT_FRAME] = Accessibility_ROLE_DOCUMENT_FRAME;
352   role_table[ATK_ROLE_HEADING] = Accessibility_ROLE_HEADING;
353   role_table[ATK_ROLE_PAGE] = Accessibility_ROLE_PAGE;
354   role_table[ATK_ROLE_SECTION] = Accessibility_ROLE_SECTION;
355   role_table[ATK_ROLE_FORM] = Accessibility_ROLE_FORM;
356   role_table[ATK_ROLE_REDUNDANT_OBJECT] = Accessibility_ROLE_REDUNDANT_OBJECT;
357   role_table[ATK_ROLE_LINK] = Accessibility_ROLE_LINK;
358   role_table[ATK_ROLE_INPUT_METHOD_WINDOW] =
359     Accessibility_ROLE_INPUT_METHOD_WINDOW;
360   return TRUE;
361 }
362
363 Accessibility_Role
364 spi_accessible_role_from_atk_role (AtkRole role)
365 {
366   static gboolean is_initialized = FALSE;
367   static Accessibility_Role spi_role_table[ATK_ROLE_LAST_DEFINED];
368   Accessibility_Role spi_role;
369
370   if (!is_initialized)
371     {
372       is_initialized = spi_init_role_lookup_table (spi_role_table);
373     }
374
375   if (role >= 0 && role < ATK_ROLE_LAST_DEFINED)
376     {
377       spi_role = spi_role_table[role];
378     }
379   else
380     {
381       spi_role = Accessibility_ROLE_EXTENDED;
382     }
383   return spi_role;
384 }
385
386 static DBusMessage *
387 impl_getRole (DBusConnection * bus, DBusMessage * message, void *user_data)
388 {
389   AtkObject *object = get_object (message);
390   gint role;
391   dbus_uint32_t rv;
392   DBusMessage *reply;
393
394   if (!object)
395     return spi_dbus_general_error (message);
396   role = atk_object_get_role (object);
397   rv = spi_accessible_role_from_atk_role (role);
398   reply = dbus_message_new_method_return (message);
399   if (reply)
400     {
401       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
402                                 DBUS_TYPE_INVALID);
403     }
404   return reply;
405 }
406
407 static char *
408 impl_get_role_str (void *datum)
409 {
410   g_assert (ATK_IS_OBJECT (datum));
411   return g_strdup_printf ("%d",
412                           spi_accessible_role_from_atk_role
413                           (atk_object_get_role ((AtkObject *) datum)));
414 }
415
416 static DBusMessage *
417 impl_getRoleName (DBusConnection * bus, DBusMessage * message,
418                   void *user_data)
419 {
420   AtkObject *object = get_object (message);
421   gint role;
422   const char *role_name;
423   DBusMessage *reply;
424
425   if (!object)
426     return spi_dbus_general_error (message);
427   role = atk_object_get_role (object);
428   role_name = atk_role_get_name (role);
429   if (!role_name)
430     role_name = "";
431   reply = dbus_message_new_method_return (message);
432   if (reply)
433     {
434       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
435                                 DBUS_TYPE_INVALID);
436     }
437   return reply;
438 }
439
440 static DBusMessage *
441 impl_getLocalizedRoleName (DBusConnection * bus, DBusMessage * message,
442                            void *user_data)
443 {
444   AtkObject *object = get_object (message);
445   gint role;
446   const char *role_name;
447   DBusMessage *reply;
448
449   if (!object)
450     return spi_dbus_general_error (message);
451   role = atk_object_get_role (object);
452   role_name = atk_role_get_localized_name (role);
453   if (!role_name)
454     role_name = "";
455   reply = dbus_message_new_method_return (message);
456   if (reply)
457     {
458       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
459                                 DBUS_TYPE_INVALID);
460     }
461   return reply;
462 }
463
464 static DBusMessage *
465 impl_getState (DBusConnection * bus, DBusMessage * message, void *user_data)
466 {
467   AtkObject *object = get_object (message);
468   dbus_uint32_t rv[2];
469   DBusMessage *reply;
470
471   if (!object)
472     return spi_dbus_general_error (message);
473   spi_atk_state_to_dbus_array (object, rv);
474   reply = dbus_message_new_method_return (message);
475   if (reply)
476     {
477       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &rv,
478                                 2, DBUS_TYPE_INVALID);
479     }
480   return reply;
481 }
482
483 static DBusMessage *
484 impl_getAttributes (DBusConnection * bus, DBusMessage * message,
485                     void *user_data)
486 {
487   AtkObject *object = get_object (message);
488   DBusMessage *reply;
489   AtkAttributeSet *attributes;
490   AtkAttribute *attr = NULL;
491   char **retval;
492   gint n_attributes = 0;
493   gint i;
494
495   if (!object)
496     return spi_dbus_general_error (message);
497
498   attributes = atk_object_get_attributes (object);
499   if (attributes)
500     n_attributes = g_slist_length (attributes);
501
502   retval = (char **) g_malloc (n_attributes * sizeof (char *));
503
504   for (i = 0; i < n_attributes; ++i)
505     {
506       attr = g_slist_nth_data (attributes, i);
507       retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
508     }
509   if (attributes)
510     atk_attribute_set_free (attributes);
511   reply = dbus_message_new_method_return (message);
512   if (reply)
513     {
514       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
515                                 &retval, n_attributes, DBUS_TYPE_INVALID);
516     }
517   for (i = 0; i < n_attributes; i++)
518     g_free (retval[i]);
519   g_free (retval);
520   return reply;
521 }
522
523 static DBusMessage *
524 impl_getApplication (DBusConnection * bus, DBusMessage * message,
525                      void *user_data)
526 {
527   AtkObject *root = atk_get_root ();
528   return spi_dbus_return_object (message, root, FALSE);
529 }
530
531 static DRouteMethod methods[] = {
532   //{impl_isEqual, "isEqual"},
533   {impl_getChildren, "getChildren"},
534   {impl_getIndexInParent, "getIndexInParent"},
535   {impl_getRelationSet, "getRelationSet"},
536   {impl_getRole, "getRole"},
537   {impl_getRoleName, "getRoleName"},
538   {impl_getLocalizedRoleName, "getLocalizedRoleName"},
539   {impl_getState, "getState"},
540   {impl_getAttributes, "getAttributes"},
541   {impl_getApplication, "getApplication"},
542   {NULL, NULL}
543 };
544
545 static DRouteProperty properties[] = {
546   {impl_get_name, impl_set_name, "name"},
547   {impl_get_description, impl_set_description, "description"},
548   {impl_get_parent, NULL, "parent"},
549   //{impl_get_childCount, NULL, "childCount"},
550   //{NULL, NULL, NULL, "role"},
551   {NULL, NULL, NULL}
552 };
553
554 void
555 spi_initialize_accessible (DRouteData * data)
556 {
557   droute_add_interface (data, SPI_DBUS_INTERFACE_ACCESSIBLE,
558                         methods, properties,
559                         (DRouteGetDatumFunction) get_object_from_path, NULL);
560 };