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