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