Initial commit.
[platform/core/uifw/at-spi2-atk.git] / libspi / 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 #include "bitarray.h"
27
28 #define get_object(message) spi_dbus_get_object(dbus_message_get_path(message))
29
30 static AtkObject *
31 get_object_from_path (const char *path, void *user_data)
32 {
33   return spi_dbus_get_object (path);
34 }
35
36 static dbus_bool_t
37 impl_get_name (const char *path, DBusMessageIter * iter, void *user_data)
38 {
39   AtkObject *object = spi_dbus_get_object (path);
40   if (!object)
41     return FALSE;
42   return droute_return_v_string (iter, atk_object_get_name (object));
43 }
44
45 static char *
46 impl_get_name_str (void *datum)
47 {
48   g_assert (ATK_IS_OBJECT (datum));
49   return g_strdup (atk_object_get_name ((AtkObject *) datum));
50 }
51
52 static dbus_bool_t
53 impl_set_name (const char *path, DBusMessageIter * iter, void *user_data)
54 {
55   AtkObject *object = spi_dbus_get_object (path);
56   const char *name = droute_get_v_string (iter);
57   atk_object_set_name (object, name);
58   return TRUE;
59 }
60
61 static dbus_bool_t
62 impl_get_description (const char *path, DBusMessageIter * iter,
63                       void *user_data)
64 {
65   AtkObject *object = spi_dbus_get_object (path);
66   if (!object)
67     return FALSE;
68   return droute_return_v_string (iter, atk_object_get_description (object));
69 }
70
71 static char *
72 impl_get_description_str (void *datum)
73 {
74   g_assert (ATK_IS_OBJECT (datum));
75   return g_strdup (atk_object_get_description ((AtkObject *) datum));
76 }
77
78 static dbus_bool_t
79 impl_set_description (const char *path, DBusMessageIter * iter,
80                       void *user_data)
81 {
82   AtkObject *object = spi_dbus_get_object (path);
83   const char *description = droute_get_v_string (iter);
84   atk_object_set_description (object, description);
85   return TRUE;
86 }
87
88 static dbus_bool_t
89 impl_get_parent (const char *path, DBusMessageIter * iter, void *user_data)
90 {
91   AtkObject *object = spi_dbus_get_object (path);
92
93   if (!object)
94     return FALSE;
95   return spi_dbus_return_v_object (iter, atk_object_get_parent (object),
96                                    FALSE);
97 }
98
99 static char *
100 impl_get_parent_str (void *datum)
101 {
102   g_assert (ATK_IS_OBJECT (datum));
103   return spi_dbus_get_path (atk_object_get_parent ((AtkObject *) datum));
104 }
105
106 static dbus_bool_t
107 impl_get_childCount (const char *path, DBusMessageIter * iter,
108                      void *user_data)
109 {
110   AtkObject *object = spi_dbus_get_object (path);
111
112   if (!object)
113     return FALSE;
114   return droute_return_v_int32 (iter,
115                                 atk_object_get_n_accessible_children
116                                 (object));
117 }
118
119 static char *
120 impl_get_childCount_str (void *datum)
121 {
122   int count;
123   g_assert (ATK_IS_OBJECT (datum));
124   count = atk_object_get_n_accessible_children ((AtkObject *) datum);
125   return g_strdup_printf ("%d", count);
126 }
127
128 #if 0
129 static DBusMessage *
130 impl_isEqual (DBusConnection * bus, DBusMessage * message, void *user_data)
131 {
132 }
133 #endif
134
135 #if 0
136 static DBusMessage *
137 impl_getChildAtIndex (DBusConnection * bus, DBusMessage * message,
138                       void *user_data)
139 {
140   AtkObject *object = get_object (message);
141   dbus_int32_t index;
142   DBusError error;
143   AtkObject *child;
144
145   if (!object)
146     return spi_dbus_general_error (message);
147   dbus_error_init (&error);
148   if (!dbus_message_get_args
149       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
150     {
151       return SPI_DBUS_RETURN_ERROR (message, &error);
152     }
153   child = atk_object_ref_accessible - child (object, index);
154   return spi_dbus_return_object (message, child, TRUE);
155 }
156 #endif
157
158 static DBusMessage *
159 impl_getChildren (DBusConnection * bus, DBusMessage * message,
160                   void *user_data)
161 {
162   AtkObject *object = get_object (message);
163   gint i;
164   gint count;
165   DBusMessage *reply;
166   DBusMessageIter iter, iter_array;
167
168   if (!object)
169     return spi_dbus_general_error (message);
170   count = atk_object_get_n_accessible_children (object);
171   reply = dbus_message_new_method_return (message);
172   dbus_message_iter_init_append (reply, &iter);
173   if (!dbus_message_iter_open_container
174       (&iter, DBUS_TYPE_ARRAY, "o", &iter_array))
175     goto oom;
176   for (i = 0; i < count; i++)
177     {
178       AtkObject *child = atk_object_ref_accessible_child (object, i);
179       char *path = spi_dbus_get_path (child);
180       if (path)
181         {
182           dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_OBJECT_PATH,
183                                           &path);
184           g_free (path);
185         }
186       if (child)
187         g_object_unref (child);
188     }
189   if (!dbus_message_iter_close_container (&iter, &iter_array))
190     goto oom;
191   return reply;
192 oom:
193   // TODO: handle out-of-memory
194   return reply;
195 }
196
197 static DBusMessage *
198 impl_getIndexInParent (DBusConnection * bus, DBusMessage * message,
199                        void *user_data)
200 {
201   AtkObject *object = get_object (message);
202   dbus_uint32_t rv;
203   DBusMessage *reply;
204
205   if (!object)
206     return spi_dbus_general_error (message);
207   rv = atk_object_get_index_in_parent (object);
208   reply = dbus_message_new_method_return (message);
209   if (reply)
210     {
211       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
212                                 DBUS_TYPE_INVALID);
213     }
214   return reply;
215 }
216
217 #if 0
218 static DBusMessage *
219 impl_getRelationSet (DBusConnection * bus, DBusMessage * message,
220                      void *user_data)
221 {
222 }
223 #endif
224
225 static gboolean
226 spi_init_role_lookup_table (Accessibility_Role * role_table)
227 {
228   int i;
229   /* if it's not in the list below, dunno what it is */
230   for (i = 0; i < ATK_ROLE_LAST_DEFINED; ++i)
231     {
232       role_table[i] = Accessibility_ROLE_UNKNOWN;
233     }
234
235   role_table[ATK_ROLE_INVALID] = Accessibility_ROLE_INVALID;
236   role_table[ATK_ROLE_ACCEL_LABEL] = Accessibility_ROLE_ACCELERATOR_LABEL;
237   role_table[ATK_ROLE_ALERT] = Accessibility_ROLE_ALERT;
238   role_table[ATK_ROLE_ANIMATION] = Accessibility_ROLE_ANIMATION;
239   role_table[ATK_ROLE_ARROW] = Accessibility_ROLE_ARROW;
240   role_table[ATK_ROLE_CALENDAR] = Accessibility_ROLE_CALENDAR;
241   role_table[ATK_ROLE_CANVAS] = Accessibility_ROLE_CANVAS;
242   role_table[ATK_ROLE_CHECK_BOX] = Accessibility_ROLE_CHECK_BOX;
243   role_table[ATK_ROLE_CHECK_MENU_ITEM] = Accessibility_ROLE_CHECK_MENU_ITEM;
244   role_table[ATK_ROLE_COLOR_CHOOSER] = Accessibility_ROLE_COLOR_CHOOSER;
245   role_table[ATK_ROLE_COLUMN_HEADER] = Accessibility_ROLE_COLUMN_HEADER;
246   role_table[ATK_ROLE_COMBO_BOX] = Accessibility_ROLE_COMBO_BOX;
247   role_table[ATK_ROLE_DATE_EDITOR] = Accessibility_ROLE_DATE_EDITOR;
248   role_table[ATK_ROLE_DESKTOP_ICON] = Accessibility_ROLE_DESKTOP_ICON;
249   role_table[ATK_ROLE_DESKTOP_FRAME] = Accessibility_ROLE_DESKTOP_FRAME;
250   role_table[ATK_ROLE_DIAL] = Accessibility_ROLE_DIAL;
251   role_table[ATK_ROLE_DIALOG] = Accessibility_ROLE_DIALOG;
252   role_table[ATK_ROLE_DIRECTORY_PANE] = Accessibility_ROLE_DIRECTORY_PANE;
253   role_table[ATK_ROLE_DRAWING_AREA] = Accessibility_ROLE_DRAWING_AREA;
254   role_table[ATK_ROLE_FILE_CHOOSER] = Accessibility_ROLE_FILE_CHOOSER;
255   role_table[ATK_ROLE_FILLER] = Accessibility_ROLE_FILLER;
256   role_table[ATK_ROLE_FONT_CHOOSER] = Accessibility_ROLE_FONT_CHOOSER;
257   role_table[ATK_ROLE_FRAME] = Accessibility_ROLE_FRAME;
258   role_table[ATK_ROLE_GLASS_PANE] = Accessibility_ROLE_GLASS_PANE;
259   role_table[ATK_ROLE_HTML_CONTAINER] = Accessibility_ROLE_HTML_CONTAINER;
260   role_table[ATK_ROLE_ICON] = Accessibility_ROLE_ICON;
261   role_table[ATK_ROLE_IMAGE] = Accessibility_ROLE_IMAGE;
262   role_table[ATK_ROLE_INTERNAL_FRAME] = Accessibility_ROLE_INTERNAL_FRAME;
263   role_table[ATK_ROLE_LABEL] = Accessibility_ROLE_LABEL;
264   role_table[ATK_ROLE_LAYERED_PANE] = Accessibility_ROLE_LAYERED_PANE;
265   role_table[ATK_ROLE_LIST] = Accessibility_ROLE_LIST;
266   role_table[ATK_ROLE_LIST_ITEM] = Accessibility_ROLE_LIST_ITEM;
267   role_table[ATK_ROLE_MENU] = Accessibility_ROLE_MENU;
268   role_table[ATK_ROLE_MENU_BAR] = Accessibility_ROLE_MENU_BAR;
269   role_table[ATK_ROLE_MENU_ITEM] = Accessibility_ROLE_MENU_ITEM;
270   role_table[ATK_ROLE_OPTION_PANE] = Accessibility_ROLE_OPTION_PANE;
271   role_table[ATK_ROLE_PAGE_TAB] = Accessibility_ROLE_PAGE_TAB;
272   role_table[ATK_ROLE_PAGE_TAB_LIST] = Accessibility_ROLE_PAGE_TAB_LIST;
273   role_table[ATK_ROLE_PANEL] = Accessibility_ROLE_PANEL;
274   role_table[ATK_ROLE_PASSWORD_TEXT] = Accessibility_ROLE_PASSWORD_TEXT;
275   role_table[ATK_ROLE_POPUP_MENU] = Accessibility_ROLE_POPUP_MENU;
276   role_table[ATK_ROLE_PROGRESS_BAR] = Accessibility_ROLE_PROGRESS_BAR;
277   role_table[ATK_ROLE_PUSH_BUTTON] = Accessibility_ROLE_PUSH_BUTTON;
278   role_table[ATK_ROLE_RADIO_BUTTON] = Accessibility_ROLE_RADIO_BUTTON;
279   role_table[ATK_ROLE_RADIO_MENU_ITEM] = Accessibility_ROLE_RADIO_MENU_ITEM;
280   role_table[ATK_ROLE_ROOT_PANE] = Accessibility_ROLE_ROOT_PANE;
281   role_table[ATK_ROLE_ROW_HEADER] = Accessibility_ROLE_ROW_HEADER;
282   role_table[ATK_ROLE_SCROLL_BAR] = Accessibility_ROLE_SCROLL_BAR;
283   role_table[ATK_ROLE_SCROLL_PANE] = Accessibility_ROLE_SCROLL_PANE;
284   role_table[ATK_ROLE_SEPARATOR] = Accessibility_ROLE_SEPARATOR;
285   role_table[ATK_ROLE_SLIDER] = Accessibility_ROLE_SLIDER;
286   role_table[ATK_ROLE_SPIN_BUTTON] = Accessibility_ROLE_SPIN_BUTTON;
287   role_table[ATK_ROLE_SPLIT_PANE] = Accessibility_ROLE_SPLIT_PANE;
288   role_table[ATK_ROLE_STATUSBAR] = Accessibility_ROLE_STATUS_BAR;
289   role_table[ATK_ROLE_TABLE] = Accessibility_ROLE_TABLE;
290   role_table[ATK_ROLE_TABLE_CELL] = Accessibility_ROLE_TABLE_CELL;
291   role_table[ATK_ROLE_TABLE_COLUMN_HEADER] =
292     Accessibility_ROLE_TABLE_COLUMN_HEADER;
293   role_table[ATK_ROLE_TABLE_ROW_HEADER] = Accessibility_ROLE_TABLE_ROW_HEADER;
294   role_table[ATK_ROLE_TEAR_OFF_MENU_ITEM] =
295     Accessibility_ROLE_TEAROFF_MENU_ITEM;
296   role_table[ATK_ROLE_TERMINAL] = Accessibility_ROLE_TERMINAL;
297   role_table[ATK_ROLE_TEXT] = Accessibility_ROLE_TEXT;
298   role_table[ATK_ROLE_TOGGLE_BUTTON] = Accessibility_ROLE_TOGGLE_BUTTON;
299   role_table[ATK_ROLE_TOOL_BAR] = Accessibility_ROLE_TOOL_BAR;
300   role_table[ATK_ROLE_TOOL_TIP] = Accessibility_ROLE_TOOL_TIP;
301   role_table[ATK_ROLE_TREE] = Accessibility_ROLE_TREE;
302   role_table[ATK_ROLE_TREE_TABLE] = Accessibility_ROLE_TREE_TABLE;
303   role_table[ATK_ROLE_UNKNOWN] = Accessibility_ROLE_UNKNOWN;
304   role_table[ATK_ROLE_VIEWPORT] = Accessibility_ROLE_VIEWPORT;
305   role_table[ATK_ROLE_WINDOW] = Accessibility_ROLE_WINDOW;
306   role_table[ATK_ROLE_HEADER] = Accessibility_ROLE_HEADER;
307   role_table[ATK_ROLE_FOOTER] = Accessibility_ROLE_FOOTER;
308   role_table[ATK_ROLE_PARAGRAPH] = Accessibility_ROLE_PARAGRAPH;
309   role_table[ATK_ROLE_RULER] = Accessibility_ROLE_RULER;
310   role_table[ATK_ROLE_APPLICATION] = Accessibility_ROLE_APPLICATION;
311   role_table[ATK_ROLE_AUTOCOMPLETE] = Accessibility_ROLE_AUTOCOMPLETE;
312   role_table[ATK_ROLE_EDITBAR] = Accessibility_ROLE_EDITBAR;
313   role_table[ATK_ROLE_EMBEDDED] = Accessibility_ROLE_EMBEDDED;
314   role_table[ATK_ROLE_ENTRY] = Accessibility_ROLE_ENTRY;
315   role_table[ATK_ROLE_CHART] = Accessibility_ROLE_CHART;
316   role_table[ATK_ROLE_CAPTION] = Accessibility_ROLE_CAPTION;
317   role_table[ATK_ROLE_DOCUMENT_FRAME] = Accessibility_ROLE_DOCUMENT_FRAME;
318   role_table[ATK_ROLE_HEADING] = Accessibility_ROLE_HEADING;
319   role_table[ATK_ROLE_PAGE] = Accessibility_ROLE_PAGE;
320   role_table[ATK_ROLE_SECTION] = Accessibility_ROLE_SECTION;
321   role_table[ATK_ROLE_FORM] = Accessibility_ROLE_FORM;
322   role_table[ATK_ROLE_REDUNDANT_OBJECT] = Accessibility_ROLE_REDUNDANT_OBJECT;
323   role_table[ATK_ROLE_LINK] = Accessibility_ROLE_LINK;
324   role_table[ATK_ROLE_INPUT_METHOD_WINDOW] =
325     Accessibility_ROLE_INPUT_METHOD_WINDOW;
326   return TRUE;
327 }
328
329 Accessibility_Role
330 spi_accessible_role_from_atk_role (AtkRole role)
331 {
332   static gboolean is_initialized = FALSE;
333   static Accessibility_Role spi_role_table[ATK_ROLE_LAST_DEFINED];
334   Accessibility_Role spi_role;
335
336   if (!is_initialized)
337     {
338       is_initialized = spi_init_role_lookup_table (spi_role_table);
339     }
340
341   if (role >= 0 && role < ATK_ROLE_LAST_DEFINED)
342     {
343       spi_role = spi_role_table[role];
344     }
345   else
346     {
347       spi_role = Accessibility_ROLE_EXTENDED;
348     }
349   return spi_role;
350 }
351
352 static DBusMessage *
353 impl_getRole (DBusConnection * bus, DBusMessage * message, void *user_data)
354 {
355   AtkObject *object = get_object (message);
356   gint role;
357   dbus_uint32_t rv;
358   DBusMessage *reply;
359
360   if (!object)
361     return spi_dbus_general_error (message);
362   role = atk_object_get_role (object);
363   rv = spi_accessible_role_from_atk_role (role);
364   reply = dbus_message_new_method_return (message);
365   if (reply)
366     {
367       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
368                                 DBUS_TYPE_INVALID);
369     }
370   return reply;
371 }
372
373 static char *
374 impl_get_role_str (void *datum)
375 {
376   g_assert (ATK_IS_OBJECT (datum));
377   return g_strdup_printf ("%d",
378                           spi_accessible_role_from_atk_role
379                           (atk_object_get_role ((AtkObject *) datum)));
380 }
381
382 static DBusMessage *
383 impl_getRoleName (DBusConnection * bus, DBusMessage * message,
384                   void *user_data)
385 {
386   AtkObject *object = get_object (message);
387   gint role;
388   const char *role_name;
389   DBusMessage *reply;
390
391   if (!object)
392     return spi_dbus_general_error (message);
393   role = atk_object_get_role (object);
394   role_name = atk_role_get_name (role);
395   if (!role_name)
396     role_name = "";
397   reply = dbus_message_new_method_return (message);
398   if (reply)
399     {
400       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
401                                 DBUS_TYPE_INVALID);
402     }
403   return reply;
404 }
405
406 static DBusMessage *
407 impl_getLocalizedRoleName (DBusConnection * bus, DBusMessage * message,
408                            void *user_data)
409 {
410   AtkObject *object = get_object (message);
411   gint role;
412   const char *role_name;
413   DBusMessage *reply;
414
415   if (!object)
416     return spi_dbus_general_error (message);
417   role = atk_object_get_role (object);
418   role_name = atk_role_get_localized_name (role);
419   if (!role_name)
420     role_name = "";
421   reply = dbus_message_new_method_return (message);
422   if (reply)
423     {
424       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
425                                 DBUS_TYPE_INVALID);
426     }
427   return reply;
428 }
429
430 static Accessibility_StateType *accessible_state_types = NULL;
431 static AtkStateType *atk_state_types = NULL;
432
433 static gboolean
434 spi_init_state_type_tables (void)
435 {
436   gint i;
437
438   if (accessible_state_types || atk_state_types)
439     return FALSE;
440   if (!accessible_state_types)
441     accessible_state_types =
442       g_new (Accessibility_StateType, ATK_STATE_LAST_DEFINED);
443   if (!atk_state_types)
444     atk_state_types = g_new (AtkStateType, Accessibility_STATE_LAST_DEFINED);
445   g_return_val_if_fail (accessible_state_types, FALSE);
446   g_return_val_if_fail (atk_state_types, FALSE);
447
448   for (i = 0; i < Accessibility_STATE_LAST_DEFINED; i++)
449     {
450       atk_state_types[i] = ATK_STATE_INVALID;
451     }
452
453   for (i = 0; i < ATK_STATE_LAST_DEFINED; i++)
454     {
455       accessible_state_types[i] = Accessibility_STATE_INVALID;
456     }
457
458   accessible_state_types[ATK_STATE_ACTIVE] = Accessibility_STATE_ACTIVE;
459   atk_state_types[Accessibility_STATE_ACTIVE] = ATK_STATE_ACTIVE;
460   accessible_state_types[ATK_STATE_ARMED] = Accessibility_STATE_ARMED;
461   atk_state_types[Accessibility_STATE_ARMED] = ATK_STATE_ARMED;
462   accessible_state_types[ATK_STATE_BUSY] = Accessibility_STATE_BUSY;
463   atk_state_types[Accessibility_STATE_BUSY] = ATK_STATE_BUSY;
464   accessible_state_types[ATK_STATE_CHECKED] = Accessibility_STATE_CHECKED;
465   atk_state_types[Accessibility_STATE_CHECKED] = ATK_STATE_CHECKED;
466   accessible_state_types[ATK_STATE_DEFUNCT] = Accessibility_STATE_DEFUNCT;
467   atk_state_types[Accessibility_STATE_DEFUNCT] = ATK_STATE_DEFUNCT;
468   accessible_state_types[ATK_STATE_EDITABLE] = Accessibility_STATE_EDITABLE;
469   atk_state_types[Accessibility_STATE_EDITABLE] = ATK_STATE_EDITABLE;
470   accessible_state_types[ATK_STATE_ENABLED] = Accessibility_STATE_ENABLED;
471   atk_state_types[Accessibility_STATE_ENABLED] = ATK_STATE_ENABLED;
472   accessible_state_types[ATK_STATE_EXPANDABLE] =
473     Accessibility_STATE_EXPANDABLE;
474   atk_state_types[Accessibility_STATE_EXPANDABLE] = ATK_STATE_EXPANDABLE;
475   accessible_state_types[ATK_STATE_EXPANDED] = Accessibility_STATE_EXPANDED;
476   atk_state_types[Accessibility_STATE_EXPANDED] = ATK_STATE_EXPANDED;
477   accessible_state_types[ATK_STATE_FOCUSABLE] = Accessibility_STATE_FOCUSABLE;
478   atk_state_types[Accessibility_STATE_FOCUSABLE] = ATK_STATE_FOCUSABLE;
479   accessible_state_types[ATK_STATE_FOCUSED] = Accessibility_STATE_FOCUSED;
480   atk_state_types[Accessibility_STATE_FOCUSED] = ATK_STATE_FOCUSED;
481   accessible_state_types[ATK_STATE_HORIZONTAL] =
482     Accessibility_STATE_HORIZONTAL;
483   atk_state_types[Accessibility_STATE_HORIZONTAL] = ATK_STATE_HORIZONTAL;
484   accessible_state_types[ATK_STATE_ICONIFIED] = Accessibility_STATE_ICONIFIED;
485   atk_state_types[Accessibility_STATE_ICONIFIED] = ATK_STATE_ICONIFIED;
486   accessible_state_types[ATK_STATE_MODAL] = Accessibility_STATE_MODAL;
487   atk_state_types[Accessibility_STATE_MODAL] = ATK_STATE_MODAL;
488   accessible_state_types[ATK_STATE_MULTI_LINE] =
489     Accessibility_STATE_MULTI_LINE;
490   atk_state_types[Accessibility_STATE_MULTI_LINE] = ATK_STATE_MULTI_LINE;
491   accessible_state_types[ATK_STATE_MULTISELECTABLE] =
492     Accessibility_STATE_MULTISELECTABLE;
493   atk_state_types[Accessibility_STATE_MULTISELECTABLE] =
494     ATK_STATE_MULTISELECTABLE;
495   accessible_state_types[ATK_STATE_OPAQUE] = Accessibility_STATE_OPAQUE;
496   atk_state_types[Accessibility_STATE_OPAQUE] = ATK_STATE_OPAQUE;
497   accessible_state_types[ATK_STATE_PRESSED] = Accessibility_STATE_PRESSED;
498   atk_state_types[Accessibility_STATE_PRESSED] = ATK_STATE_PRESSED;
499   accessible_state_types[ATK_STATE_RESIZABLE] = Accessibility_STATE_RESIZABLE;
500   atk_state_types[Accessibility_STATE_RESIZABLE] = ATK_STATE_RESIZABLE;
501   accessible_state_types[ATK_STATE_SELECTABLE] =
502     Accessibility_STATE_SELECTABLE;
503   atk_state_types[Accessibility_STATE_SELECTABLE] = ATK_STATE_SELECTABLE;
504   accessible_state_types[ATK_STATE_SELECTED] = Accessibility_STATE_SELECTED;
505   atk_state_types[Accessibility_STATE_SELECTED] = ATK_STATE_SELECTED;
506   accessible_state_types[ATK_STATE_SENSITIVE] = Accessibility_STATE_SENSITIVE;
507   atk_state_types[Accessibility_STATE_SENSITIVE] = ATK_STATE_SENSITIVE;
508   accessible_state_types[ATK_STATE_SHOWING] = Accessibility_STATE_SHOWING;
509   atk_state_types[Accessibility_STATE_SHOWING] = ATK_STATE_SHOWING;
510   accessible_state_types[ATK_STATE_SINGLE_LINE] =
511     Accessibility_STATE_SINGLE_LINE;
512   atk_state_types[Accessibility_STATE_SINGLE_LINE] = ATK_STATE_SINGLE_LINE;
513   accessible_state_types[ATK_STATE_STALE] = Accessibility_STATE_STALE;
514   atk_state_types[Accessibility_STATE_STALE] = ATK_STATE_STALE;
515   accessible_state_types[ATK_STATE_TRANSIENT] = Accessibility_STATE_TRANSIENT;
516   atk_state_types[Accessibility_STATE_TRANSIENT] = ATK_STATE_TRANSIENT;
517   accessible_state_types[ATK_STATE_VERTICAL] = Accessibility_STATE_VERTICAL;
518   atk_state_types[Accessibility_STATE_VERTICAL] = ATK_STATE_VERTICAL;
519   accessible_state_types[ATK_STATE_VISIBLE] = Accessibility_STATE_VISIBLE;
520   atk_state_types[Accessibility_STATE_VISIBLE] = ATK_STATE_VISIBLE;
521   accessible_state_types[ATK_STATE_MANAGES_DESCENDANTS] =
522     Accessibility_STATE_MANAGES_DESCENDANTS;
523   atk_state_types[Accessibility_STATE_MANAGES_DESCENDANTS] =
524     ATK_STATE_MANAGES_DESCENDANTS;
525   accessible_state_types[ATK_STATE_INDETERMINATE] =
526     Accessibility_STATE_INDETERMINATE;
527   atk_state_types[Accessibility_STATE_INDETERMINATE] =
528     ATK_STATE_INDETERMINATE;
529   accessible_state_types[ATK_STATE_TRUNCATED] = Accessibility_STATE_TRUNCATED;
530   atk_state_types[Accessibility_STATE_TRUNCATED] = ATK_STATE_TRUNCATED;
531   accessible_state_types[ATK_STATE_REQUIRED] = Accessibility_STATE_REQUIRED;
532   atk_state_types[Accessibility_STATE_REQUIRED] = ATK_STATE_REQUIRED;
533   accessible_state_types[ATK_STATE_INVALID_ENTRY] =
534     Accessibility_STATE_INVALID_ENTRY;
535   atk_state_types[Accessibility_STATE_INVALID_ENTRY] =
536     ATK_STATE_INVALID_ENTRY;
537   accessible_state_types[ATK_STATE_SUPPORTS_AUTOCOMPLETION] =
538     Accessibility_STATE_SUPPORTS_AUTOCOMPLETION;
539   atk_state_types[Accessibility_STATE_SUPPORTS_AUTOCOMPLETION] =
540     ATK_STATE_SUPPORTS_AUTOCOMPLETION;
541   accessible_state_types[ATK_STATE_SELECTABLE_TEXT] =
542     Accessibility_STATE_SELECTABLE_TEXT;
543   atk_state_types[Accessibility_STATE_SELECTABLE_TEXT] =
544     ATK_STATE_SELECTABLE_TEXT;
545   accessible_state_types[ATK_STATE_DEFAULT] = Accessibility_STATE_IS_DEFAULT;
546   atk_state_types[Accessibility_STATE_IS_DEFAULT] = ATK_STATE_DEFAULT;
547   accessible_state_types[ATK_STATE_VISITED] = Accessibility_STATE_VISITED;
548   atk_state_types[Accessibility_STATE_VISITED] = ATK_STATE_VISITED;
549
550
551   return TRUE;
552 }
553
554 static void
555 get_state (AtkObject * object, dbus_uint32_t * array)
556 {
557   AtkStateSet *set = atk_object_ref_state_set (object);
558   int i;
559
560   array[0] = 0;
561   array[1] = 0;
562   if (!set)
563     return;
564   spi_init_state_type_tables ();
565
566   g_assert (ATK_STATE_LAST_DEFINED <= 64);
567   for (i = 0; i < ATK_STATE_LAST_DEFINED; i++)
568     {
569       if (atk_state_set_contains_state (set, i))
570         {
571           int a = accessible_state_types[i];
572           g_assert (a < 64);
573           BITARRAY_SET (array, a);
574         }
575     }
576   g_object_unref (set);
577 }
578
579 static DBusMessage *
580 impl_getState (DBusConnection * bus, DBusMessage * message, void *user_data)
581 {
582   AtkObject *object = get_object (message);
583   dbus_uint32_t rv[2];
584   DBusMessage *reply;
585
586   if (!object)
587     return spi_dbus_general_error (message);
588   get_state (object, rv);
589   reply = dbus_message_new_method_return (message);
590   if (reply)
591     {
592       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &rv,
593                                 2, DBUS_TYPE_INVALID);
594     }
595   return reply;
596 }
597
598 static DBusMessage *
599 impl_getAttributes (DBusConnection * bus, DBusMessage * message,
600                     void *user_data)
601 {
602   AtkObject *object = get_object (message);
603   DBusMessage *reply;
604   AtkAttributeSet *attributes;
605   AtkAttribute *attr = NULL;
606   char **retval;
607   gint n_attributes = 0;
608   gint i;
609
610   if (!object)
611     return spi_dbus_general_error (message);
612
613   attributes = atk_object_get_attributes (object);
614   if (attributes)
615     n_attributes = g_slist_length (attributes);
616
617   retval = (char **) g_malloc (n_attributes * sizeof (char *));
618
619   for (i = 0; i < n_attributes; ++i)
620     {
621       attr = g_slist_nth_data (attributes, i);
622       retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
623     }
624   if (attributes)
625     atk_attribute_set_free (attributes);
626   reply = dbus_message_new_method_return (message);
627   if (reply)
628     {
629       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
630                                 &retval, n_attributes, DBUS_TYPE_INVALID);
631     }
632   for (i = 0; i < n_attributes; i++)
633     g_free (retval[i]);
634   g_free (retval);
635   return reply;
636 }
637
638 static DBusMessage *
639 impl_getApplication (DBusConnection * bus, DBusMessage * message,
640                      void *user_data)
641 {
642   AtkObject *root = atk_get_root ();
643   return spi_dbus_return_object (message, root, FALSE);
644 }
645
646 // TODO: sync spec with updates made here
647 static DRouteMethod methods[] = {
648   //{ DROUTE_METHOD, impl_isEqual, "isEqual", "o,obj,i:b,,o" },
649   {DROUTE_METHOD, impl_getChildren, "getChildren", "ao,,o"},
650   {DROUTE_METHOD, impl_getIndexInParent, "getIndexInParent", "i,,o"},
651   //{ DROUTE_METHOD, impl_getRelationSet, "getRelationSet", "a{so},,o" },
652   {DROUTE_METHOD, impl_getRole, "getRole", "u,,o"},
653   {DROUTE_METHOD, impl_getRoleName, "getRoleName", "s,,o"},
654   {DROUTE_METHOD, impl_getLocalizedRoleName, "getLocalizedRoleName", "s,,o"},
655   {DROUTE_METHOD, impl_getState, "getState", "o,,au"},
656   {DROUTE_METHOD, impl_getAttributes, "getAttributes", "as,,o"},
657   {DROUTE_METHOD, impl_getApplication, "getApplication", "o,,o"},
658   {0, NULL, NULL, NULL}
659 };
660
661 static DRouteProperty properties[] = {
662   {impl_get_name, impl_get_name_str, impl_set_name, NULL, "name", "s"},
663   {impl_get_description, impl_get_description_str, impl_set_description, NULL,
664    "description", "s"},
665   {impl_get_parent, impl_get_parent_str, NULL, NULL, "parent", "o"},
666   //{ impl_get_childCount, impl_get_childCount_str, NULL, NULL, "childCount", "n" },
667   {NULL, impl_get_role_str, NULL, NULL, "role", "u"},
668   {NULL, NULL, NULL, NULL, NULL, NULL}
669 };
670
671 void
672 spi_initialize_accessible (DRouteData * data)
673 {
674   droute_add_interface (data, "org.freedesktop.accessibility.Accessible",
675                         methods, properties,
676                         (DRouteGetDatumFunction) get_object_from_path, NULL);
677 };