f053f24e4d6de272ea1edf3803d53cdaa2942bee
[platform/upstream/at-spi2-atk.git] / atk-adaptor / object.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 2008, 2009, 2010 Codethink Ltd.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /*
25  * This module contains utility functions for exporting AT-SPI
26  * objects based upon an ATK object.
27  *
28  * It incudes functions for marshalling object references
29  * and supported interfaces to a D-Bus message.
30  */
31
32 #include <atk/atk.h>
33 #include "atspi/atspi.h"
34 #include "spi-dbus.h"
35
36 #include "accessible-register.h"
37 #include "accessible-cache.h"
38 #include "accessible-leasing.h"
39
40 #include "bridge.h"
41
42 /*---------------------------------------------------------------------------*/
43
44 /*
45  * This is the all important function that decides whether an object should
46  * be leased or not.
47  *
48  * The choice of algorithm for this is somewhat vuage. We want ideally to lease
49  * all atk objects that are not owned by their parent.
50  *
51  * The 'cache' object attempts to cache all objects that are owned by their
52  * parent by traversing the tree of accessibles, ignoring the children of
53  * manages-descendants and transient objects.
54  *
55  * This function will simply look for all the accessibles that the cache object
56  * has not found and assume that they need to be leased.
57  */
58 void
59 spi_object_lease_if_needed (GObject *obj)
60 {
61   if (!spi_cache_in (spi_global_cache, obj))
62     {
63       spi_leasing_take (spi_global_leasing, obj);
64     }
65 }
66
67 /*---------------------------------------------------------------------------*/
68
69 /*
70  * It is assumed that all of these functions are returning an accessible
71  * object to the client side.
72  *
73  * All of them will lease the AtkObject if it is deemed neccessary.
74  */
75
76 void
77 spi_object_append_null_reference (DBusMessageIter * iter)
78 {
79   DBusMessageIter iter_struct;
80   const char *name;
81   const char *path = ATSPI_DBUS_PATH_NULL;
82
83   name = dbus_bus_get_unique_name (spi_global_app_data->bus);
84
85   dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
86                                     &iter_struct);
87   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
88   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
89   dbus_message_iter_close_container (iter, &iter_struct);
90 }
91
92 void
93 spi_object_append_reference (DBusMessageIter * iter, AtkObject * obj)
94 {
95   DBusMessageIter iter_struct;
96   const gchar *name;
97   gchar *path;
98
99   if (!obj) {
100     spi_object_append_null_reference (iter);
101     return;
102   }
103
104   spi_object_lease_if_needed (G_OBJECT (obj));
105
106   name = dbus_bus_get_unique_name (spi_global_app_data->bus);
107   path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj));
108
109   if (!path)
110     path = g_strdup (SPI_DBUS_PATH_NULL);
111
112   dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
113                                     &iter_struct);
114   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
115   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
116   dbus_message_iter_close_container (iter, &iter_struct);
117
118   g_free (path);
119 }
120
121 /* TODO: Perhaps combine with spi_object_append_reference.  Leaving separate
122  * for now in case we want to use a different path for hyperlinks. */
123 void
124 spi_hyperlink_append_reference (DBusMessageIter * iter, AtkHyperlink * obj)
125 {
126   DBusMessageIter iter_struct;
127   const gchar *name;
128   gchar *path;
129
130   if (!obj) {
131     spi_object_append_null_reference (iter);
132     return;
133   }
134
135   spi_object_lease_if_needed (G_OBJECT (obj));
136
137   name = dbus_bus_get_unique_name (spi_global_app_data->bus);
138   path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj));
139
140   if (!path)
141     path = g_strdup (SPI_DBUS_PATH_NULL);
142
143   dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
144                                     &iter_struct);
145   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
146   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
147   dbus_message_iter_close_container (iter, &iter_struct);
148
149   g_free (path);
150 }
151
152 void
153 spi_object_append_v_reference (DBusMessageIter * iter, AtkObject * obj)
154 {
155   DBusMessageIter iter_variant;
156
157   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
158                                     &iter_variant);
159      spi_object_append_reference (&iter_variant, obj);
160   dbus_message_iter_close_container (iter, &iter_variant);
161 }
162
163 void
164 spi_object_append_desktop_reference (DBusMessageIter * iter)
165 {
166   DBusMessageIter iter_struct;
167   const char *name = spi_global_app_data->desktop_name;
168   const char *path = spi_global_app_data->desktop_path;
169
170   dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
171                                     &iter_struct);
172   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
173   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
174   dbus_message_iter_close_container (iter, &iter_struct);
175 }
176
177 DBusMessage *
178 spi_object_return_reference (DBusMessage * msg, AtkObject * obj)
179 {
180   DBusMessage *reply;
181
182   reply = dbus_message_new_method_return (msg);
183   if (reply)
184     {
185       DBusMessageIter iter;
186       dbus_message_iter_init_append (reply, &iter);
187       spi_object_append_reference (&iter, obj);
188     }
189
190   return reply;
191 }
192
193 DBusMessage *
194 spi_object_return_reference_and_recurse_flag (DBusMessage * msg, AtkObject * obj, unsigned char recurse)
195 {
196   DBusMessage *reply;
197
198   reply = dbus_message_new_method_return (msg);
199   if (reply)
200     {
201       DBusMessageIter iter;
202       dbus_message_iter_init_append (reply, &iter);
203       spi_object_append_reference (&iter, obj);
204       dbus_message_iter_append_basic (&iter, DBUS_TYPE_BYTE, &recurse);
205     }
206
207   return reply;
208 }
209
210 DBusMessage *
211 spi_hyperlink_return_reference (DBusMessage * msg, AtkHyperlink * obj)
212 {
213   DBusMessage *reply;
214
215   reply = dbus_message_new_method_return (msg);
216   if (reply)
217     {
218       DBusMessageIter iter;
219       dbus_message_iter_init_append (reply, &iter);
220       spi_hyperlink_append_reference (&iter, obj);
221     }
222   if (obj)
223     g_object_unref (G_OBJECT (obj));
224
225   return reply;
226 }
227
228 /*---------------------------------------------------------------------------*/
229
230 void
231 spi_object_append_interfaces (DBusMessageIter * iter, AtkObject * obj)
232 {
233   const gchar *itf;
234
235   itf = ATSPI_DBUS_INTERFACE_ACCESSIBLE;
236   dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
237
238   if (ATK_IS_ACTION (obj))
239     {
240       itf = ATSPI_DBUS_INTERFACE_ACTION;
241       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
242     }
243
244   if (atk_object_get_role (obj) == ATK_ROLE_APPLICATION)
245     {
246       itf = ATSPI_DBUS_INTERFACE_APPLICATION;
247       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
248     }
249
250   if (ATK_IS_COMPONENT (obj))
251     {
252       itf = ATSPI_DBUS_INTERFACE_COMPONENT;
253       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
254     }
255
256   if (ATK_IS_EDITABLE_TEXT (obj))
257     {
258       itf = ATSPI_DBUS_INTERFACE_EDITABLE_TEXT;
259       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
260     }
261
262   if (ATK_IS_TEXT (obj))
263     {
264       itf = ATSPI_DBUS_INTERFACE_TEXT;
265       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
266     }
267
268   if (ATK_IS_HYPERTEXT (obj))
269     {
270       itf = ATSPI_DBUS_INTERFACE_HYPERTEXT;
271       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
272     }
273
274   if (ATK_IS_IMAGE (obj))
275     {
276       itf = ATSPI_DBUS_INTERFACE_IMAGE;
277       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
278     }
279
280   if (ATK_IS_SELECTION (obj))
281     {
282       itf = ATSPI_DBUS_INTERFACE_SELECTION;
283       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
284     }
285
286   if (ATK_IS_TABLE (obj))
287     {
288       itf = ATSPI_DBUS_INTERFACE_TABLE;
289       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
290     }
291
292   if (ATK_IS_TABLE_CELL (obj))
293     {
294       itf = ATSPI_DBUS_INTERFACE_TABLE_CELL;
295       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
296     }
297
298   if (ATK_IS_VALUE (obj))
299     {
300       itf = ATSPI_DBUS_INTERFACE_VALUE;
301       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
302     }
303
304 #if 0
305   if (ATK_IS_STREAMABLE_CONTENT (obj))
306     {
307       itf = "org.a11y.atspi.StreamableContent";
308       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
309     }
310 #endif
311
312   if (ATK_IS_OBJECT (obj))
313     {
314       itf = "org.a11y.atspi.Collection";
315       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
316     }
317
318   if (ATK_IS_DOCUMENT (obj))
319     {
320       itf = ATSPI_DBUS_INTERFACE_DOCUMENT;
321       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
322     }
323
324   if (ATK_IS_HYPERLINK_IMPL (obj))
325     {
326       itf = ATSPI_DBUS_INTERFACE_HYPERLINK;
327       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
328     }
329 }
330
331 /*---------------------------------------------------------------------------*/
332
333 void
334 spi_object_append_attribute_set (DBusMessageIter * iter, AtkAttributeSet * attr)
335 {
336   DBusMessageIter dictIter;
337
338   dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}", &dictIter);
339   while (attr)
340     {
341       DBusMessageIter dictEntryIter;
342       AtkAttribute *attribute = (AtkAttribute *) attr->data;
343       const char *key = attribute->name;
344       const char *value = attribute->value;
345
346       if (key == NULL)
347         key = "";
348       if (value == NULL)
349         value = "";
350
351       dbus_message_iter_open_container (&dictIter, DBUS_TYPE_DICT_ENTRY, NULL,
352                                         &dictEntryIter);
353       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING,
354                                       &key);
355       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING,
356                                       &value);
357       dbus_message_iter_close_container (&dictIter, &dictEntryIter);
358       attr = g_slist_next (attr);
359     }
360   dbus_message_iter_close_container (iter, &dictIter);
361 }
362
363 /*---------------------------------------------------------------------------*/
364
365 static gboolean
366 init_role_lookup_table (AtspiRole * role_table)
367 {
368   int i;
369   /* if it's not in the list below, dunno what it is */
370   for (i = 0; i < ATK_ROLE_LAST_DEFINED; ++i)
371     {
372       role_table[i] = ATSPI_ROLE_UNKNOWN;
373     }
374
375   role_table[ATK_ROLE_INVALID] = ATSPI_ROLE_INVALID;
376   role_table[ATK_ROLE_ACCEL_LABEL] = ATSPI_ROLE_ACCELERATOR_LABEL;
377   role_table[ATK_ROLE_ALERT] = ATSPI_ROLE_ALERT;
378   role_table[ATK_ROLE_ANIMATION] = ATSPI_ROLE_ANIMATION;
379   role_table[ATK_ROLE_ARROW] = ATSPI_ROLE_ARROW;
380   role_table[ATK_ROLE_CALENDAR] = ATSPI_ROLE_CALENDAR;
381   role_table[ATK_ROLE_CANVAS] = ATSPI_ROLE_CANVAS;
382   role_table[ATK_ROLE_CHECK_BOX] = ATSPI_ROLE_CHECK_BOX;
383   role_table[ATK_ROLE_CHECK_MENU_ITEM] = ATSPI_ROLE_CHECK_MENU_ITEM;
384   role_table[ATK_ROLE_COLOR_CHOOSER] = ATSPI_ROLE_COLOR_CHOOSER;
385   role_table[ATK_ROLE_COLUMN_HEADER] = ATSPI_ROLE_COLUMN_HEADER;
386   role_table[ATK_ROLE_COMBO_BOX] = ATSPI_ROLE_COMBO_BOX;
387   role_table[ATK_ROLE_DATE_EDITOR] = ATSPI_ROLE_DATE_EDITOR;
388   role_table[ATK_ROLE_DESKTOP_ICON] = ATSPI_ROLE_DESKTOP_ICON;
389   role_table[ATK_ROLE_DESKTOP_FRAME] = ATSPI_ROLE_DESKTOP_FRAME;
390   role_table[ATK_ROLE_DIAL] = ATSPI_ROLE_DIAL;
391   role_table[ATK_ROLE_DIALOG] = ATSPI_ROLE_DIALOG;
392   role_table[ATK_ROLE_DIRECTORY_PANE] = ATSPI_ROLE_DIRECTORY_PANE;
393   role_table[ATK_ROLE_DRAWING_AREA] = ATSPI_ROLE_DRAWING_AREA;
394   role_table[ATK_ROLE_FILE_CHOOSER] = ATSPI_ROLE_FILE_CHOOSER;
395   role_table[ATK_ROLE_FILLER] = ATSPI_ROLE_FILLER;
396   role_table[ATK_ROLE_FONT_CHOOSER] = ATSPI_ROLE_FONT_CHOOSER;
397   role_table[ATK_ROLE_FRAME] = ATSPI_ROLE_FRAME;
398   role_table[ATK_ROLE_GLASS_PANE] = ATSPI_ROLE_GLASS_PANE;
399   role_table[ATK_ROLE_HTML_CONTAINER] = ATSPI_ROLE_HTML_CONTAINER;
400   role_table[ATK_ROLE_ICON] = ATSPI_ROLE_ICON;
401   role_table[ATK_ROLE_IMAGE] = ATSPI_ROLE_IMAGE;
402   role_table[ATK_ROLE_INTERNAL_FRAME] = ATSPI_ROLE_INTERNAL_FRAME;
403   role_table[ATK_ROLE_LABEL] = ATSPI_ROLE_LABEL;
404   role_table[ATK_ROLE_LAYERED_PANE] = ATSPI_ROLE_LAYERED_PANE;
405   role_table[ATK_ROLE_LIST] = ATSPI_ROLE_LIST;
406   role_table[ATK_ROLE_LIST_ITEM] = ATSPI_ROLE_LIST_ITEM;
407   role_table[ATK_ROLE_MENU] = ATSPI_ROLE_MENU;
408   role_table[ATK_ROLE_MENU_BAR] = ATSPI_ROLE_MENU_BAR;
409   role_table[ATK_ROLE_MENU_ITEM] = ATSPI_ROLE_MENU_ITEM;
410   role_table[ATK_ROLE_OPTION_PANE] = ATSPI_ROLE_OPTION_PANE;
411   role_table[ATK_ROLE_PAGE_TAB] = ATSPI_ROLE_PAGE_TAB;
412   role_table[ATK_ROLE_PAGE_TAB_LIST] = ATSPI_ROLE_PAGE_TAB_LIST;
413   role_table[ATK_ROLE_PANEL] = ATSPI_ROLE_PANEL;
414   role_table[ATK_ROLE_PASSWORD_TEXT] = ATSPI_ROLE_PASSWORD_TEXT;
415   role_table[ATK_ROLE_POPUP_MENU] = ATSPI_ROLE_POPUP_MENU;
416   role_table[ATK_ROLE_PROGRESS_BAR] = ATSPI_ROLE_PROGRESS_BAR;
417   role_table[ATK_ROLE_PUSH_BUTTON] = ATSPI_ROLE_PUSH_BUTTON;
418   role_table[ATK_ROLE_RADIO_BUTTON] = ATSPI_ROLE_RADIO_BUTTON;
419   role_table[ATK_ROLE_RADIO_MENU_ITEM] = ATSPI_ROLE_RADIO_MENU_ITEM;
420   role_table[ATK_ROLE_ROOT_PANE] = ATSPI_ROLE_ROOT_PANE;
421   role_table[ATK_ROLE_ROW_HEADER] = ATSPI_ROLE_ROW_HEADER;
422   role_table[ATK_ROLE_SCROLL_BAR] = ATSPI_ROLE_SCROLL_BAR;
423   role_table[ATK_ROLE_SCROLL_PANE] = ATSPI_ROLE_SCROLL_PANE;
424   role_table[ATK_ROLE_SEPARATOR] = ATSPI_ROLE_SEPARATOR;
425   role_table[ATK_ROLE_SLIDER] = ATSPI_ROLE_SLIDER;
426   role_table[ATK_ROLE_SPIN_BUTTON] = ATSPI_ROLE_SPIN_BUTTON;
427   role_table[ATK_ROLE_SPLIT_PANE] = ATSPI_ROLE_SPLIT_PANE;
428   role_table[ATK_ROLE_STATUSBAR] = ATSPI_ROLE_STATUS_BAR;
429   role_table[ATK_ROLE_TABLE] = ATSPI_ROLE_TABLE;
430   role_table[ATK_ROLE_TABLE_CELL] = ATSPI_ROLE_TABLE_CELL;
431   role_table[ATK_ROLE_TABLE_COLUMN_HEADER] =
432     ATSPI_ROLE_TABLE_COLUMN_HEADER;
433   role_table[ATK_ROLE_TABLE_ROW_HEADER] = ATSPI_ROLE_TABLE_ROW_HEADER;
434   role_table[ATK_ROLE_TEAR_OFF_MENU_ITEM] =
435     ATSPI_ROLE_TEAROFF_MENU_ITEM;
436   role_table[ATK_ROLE_TERMINAL] = ATSPI_ROLE_TERMINAL;
437   role_table[ATK_ROLE_TEXT] = ATSPI_ROLE_TEXT;
438   role_table[ATK_ROLE_TOGGLE_BUTTON] = ATSPI_ROLE_TOGGLE_BUTTON;
439   role_table[ATK_ROLE_TOOL_BAR] = ATSPI_ROLE_TOOL_BAR;
440   role_table[ATK_ROLE_TOOL_TIP] = ATSPI_ROLE_TOOL_TIP;
441   role_table[ATK_ROLE_TREE] = ATSPI_ROLE_TREE;
442   role_table[ATK_ROLE_TREE_TABLE] = ATSPI_ROLE_TREE_TABLE;
443   role_table[ATK_ROLE_UNKNOWN] = ATSPI_ROLE_UNKNOWN;
444   role_table[ATK_ROLE_VIEWPORT] = ATSPI_ROLE_VIEWPORT;
445   role_table[ATK_ROLE_WINDOW] = ATSPI_ROLE_WINDOW;
446   role_table[ATK_ROLE_HEADER] = ATSPI_ROLE_HEADER;
447   role_table[ATK_ROLE_FOOTER] = ATSPI_ROLE_FOOTER;
448   role_table[ATK_ROLE_PARAGRAPH] = ATSPI_ROLE_PARAGRAPH;
449   role_table[ATK_ROLE_RULER] = ATSPI_ROLE_RULER;
450   role_table[ATK_ROLE_APPLICATION] = ATSPI_ROLE_APPLICATION;
451   role_table[ATK_ROLE_AUTOCOMPLETE] = ATSPI_ROLE_AUTOCOMPLETE;
452   role_table[ATK_ROLE_EDITBAR] = ATSPI_ROLE_EDITBAR;
453   role_table[ATK_ROLE_EMBEDDED] = ATSPI_ROLE_EMBEDDED;
454   role_table[ATK_ROLE_ENTRY] = ATSPI_ROLE_ENTRY;
455   role_table[ATK_ROLE_CHART] = ATSPI_ROLE_CHART;
456   role_table[ATK_ROLE_CAPTION] = ATSPI_ROLE_CAPTION;
457   role_table[ATK_ROLE_DOCUMENT_FRAME] = ATSPI_ROLE_DOCUMENT_FRAME;
458   role_table[ATK_ROLE_HEADING] = ATSPI_ROLE_HEADING;
459   role_table[ATK_ROLE_PAGE] = ATSPI_ROLE_PAGE;
460   role_table[ATK_ROLE_SECTION] = ATSPI_ROLE_SECTION;
461   role_table[ATK_ROLE_FORM] = ATSPI_ROLE_FORM;
462   role_table[ATK_ROLE_REDUNDANT_OBJECT] = ATSPI_ROLE_REDUNDANT_OBJECT;
463   role_table[ATK_ROLE_LINK] = ATSPI_ROLE_LINK;
464   role_table[ATK_ROLE_INPUT_METHOD_WINDOW] =
465     ATSPI_ROLE_INPUT_METHOD_WINDOW;
466   role_table[ATK_ROLE_TABLE_ROW] = ATSPI_ROLE_TABLE_ROW;
467   role_table[ATK_ROLE_TREE_ITEM] = ATSPI_ROLE_TREE_ITEM;
468   role_table[ATK_ROLE_DOCUMENT_SPREADSHEET] =
469     ATSPI_ROLE_DOCUMENT_SPREADSHEET;
470   role_table[ATK_ROLE_DOCUMENT_PRESENTATION] =
471     ATSPI_ROLE_DOCUMENT_PRESENTATION;
472   role_table[ATK_ROLE_DOCUMENT_TEXT] = ATSPI_ROLE_DOCUMENT_TEXT;
473   role_table[ATK_ROLE_DOCUMENT_WEB] = ATSPI_ROLE_DOCUMENT_WEB;
474   role_table[ATK_ROLE_DOCUMENT_EMAIL] = ATSPI_ROLE_DOCUMENT_EMAIL;
475   role_table[ATK_ROLE_COMMENT] = ATSPI_ROLE_COMMENT;
476   role_table[ATK_ROLE_LIST_BOX] = ATSPI_ROLE_LIST_BOX;
477   role_table[ATK_ROLE_GROUPING] = ATSPI_ROLE_GROUPING;
478   role_table[ATK_ROLE_IMAGE_MAP] = ATSPI_ROLE_IMAGE_MAP;
479   role_table[ATK_ROLE_NOTIFICATION] = ATSPI_ROLE_NOTIFICATION;
480   role_table[ATK_ROLE_INFO_BAR] = ATSPI_ROLE_INFO_BAR;
481   role_table[ATK_ROLE_LEVEL_BAR] = ATSPI_ROLE_LEVEL_BAR;
482   role_table[ATK_ROLE_TITLE_BAR] = ATSPI_ROLE_TITLE_BAR;
483   role_table[ATK_ROLE_BLOCK_QUOTE] = ATSPI_ROLE_BLOCK_QUOTE;
484   role_table[ATK_ROLE_AUDIO] = ATSPI_ROLE_AUDIO;
485   role_table[ATK_ROLE_VIDEO] = ATSPI_ROLE_VIDEO;
486   role_table[ATK_ROLE_DEFINITION] = ATSPI_ROLE_DEFINITION;
487   role_table[ATK_ROLE_ARTICLE] = ATSPI_ROLE_ARTICLE;
488   role_table[ATK_ROLE_LANDMARK] = ATSPI_ROLE_LANDMARK;
489   role_table[ATK_ROLE_LOG] = ATSPI_ROLE_LOG;
490   role_table[ATK_ROLE_MARQUEE] = ATSPI_ROLE_MARQUEE;
491   role_table[ATK_ROLE_MATH] = ATSPI_ROLE_MATH;
492   role_table[ATK_ROLE_RATING] = ATSPI_ROLE_RATING;
493   role_table[ATK_ROLE_TIMER] = ATSPI_ROLE_TIMER;
494   role_table[ATK_ROLE_STATIC] = ATSPI_ROLE_STATIC;
495   role_table[ATK_ROLE_MATH_FRACTION] = ATSPI_ROLE_MATH_FRACTION;
496   role_table[ATK_ROLE_MATH_ROOT] = ATSPI_ROLE_MATH_ROOT;
497   role_table[ATK_ROLE_SUBSCRIPT] = ATSPI_ROLE_SUBSCRIPT;
498   role_table[ATK_ROLE_SUPERSCRIPT] = ATSPI_ROLE_SUPERSCRIPT;
499
500   return TRUE;
501 }
502
503 AtspiRole
504 spi_accessible_role_from_atk_role (AtkRole role)
505 {
506   static gboolean is_initialized = FALSE;
507   static AtspiRole spi_role_table[ATK_ROLE_LAST_DEFINED];
508   AtspiRole spi_role;
509
510   if (!is_initialized)
511     {
512       is_initialized = init_role_lookup_table (spi_role_table);
513     }
514
515   if (role >= 0 && role < ATK_ROLE_LAST_DEFINED)
516     {
517       spi_role = spi_role_table[role];
518     }
519   else
520     {
521       spi_role = ATSPI_ROLE_EXTENDED;
522     }
523   return spi_role;
524 }
525
526 /*END------------------------------------------------------------------------*/