Reverted Value interface since the new union was more complicated than necessary.
[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 2001 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /* accessible.c: the core of the accessibility implementation */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <bonobo/bonobo-exception.h>
28 #include <atk/atk.h>
29 #include <libspi/libspi.h>
30
31 /* Our parent Gtk object type  */
32 #define PARENT_TYPE SPI_TYPE_BASE
33
34 static Accessibility_Role
35 spi_role_from_atk_role (AtkRole role)
36 {
37   Accessibility_Role spi_role;
38
39   /* TODO: finish and/or make efficient! */
40   switch (role)
41   {
42     case ATK_ROLE_INVALID:
43       spi_role = Accessibility_ROLE_INVALID;
44       break;
45     case ATK_ROLE_ACCEL_LABEL:
46     case ATK_ROLE_ALERT:
47     case ATK_ROLE_ANIMATION: 
48     case ATK_ROLE_ARROW: 
49     case ATK_ROLE_CALENDAR: 
50     case ATK_ROLE_CANVAS:
51     case ATK_ROLE_CHECK_BOX:
52     case ATK_ROLE_CHECK_MENU_ITEM:
53     case ATK_ROLE_COLOR_CHOOSER:
54     case ATK_ROLE_COLUMN_HEADER:
55     case ATK_ROLE_COMBO_BOX:
56     case ATK_ROLE_DATE_EDITOR:
57     case ATK_ROLE_DESKTOP_ICON:
58     case ATK_ROLE_DESKTOP_FRAME:
59     case ATK_ROLE_DIAL:
60     case ATK_ROLE_DIALOG:
61     case ATK_ROLE_DIRECTORY_PANE:
62     case ATK_ROLE_DRAWING_AREA:
63     case ATK_ROLE_FILE_CHOOSER:
64     case ATK_ROLE_FILLER:
65     case ATK_ROLE_FONT_CHOOSER:
66     case ATK_ROLE_FRAME:
67     case ATK_ROLE_GLASS_PANE: 
68     case ATK_ROLE_HTML_CONTAINER: 
69     case ATK_ROLE_ICON: 
70     case ATK_ROLE_IMAGE:
71     case ATK_ROLE_INTERNAL_FRAME:
72     case ATK_ROLE_LABEL:
73     case ATK_ROLE_LAYERED_PANE:
74     case ATK_ROLE_LIST:
75     case ATK_ROLE_LIST_ITEM:
76     case ATK_ROLE_MENU:
77     case ATK_ROLE_MENU_BAR:
78     case ATK_ROLE_MENU_ITEM:
79     case ATK_ROLE_OPTION_PANE:
80     case ATK_ROLE_PAGE_TAB:
81     case ATK_ROLE_PAGE_TAB_LIST:
82     case ATK_ROLE_PANEL:
83     case ATK_ROLE_PASSWORD_TEXT:
84     case ATK_ROLE_POPUP_MENU:
85     case ATK_ROLE_PROGRESS_BAR:
86     case ATK_ROLE_PUSH_BUTTON:
87     case ATK_ROLE_RADIO_BUTTON:
88     case ATK_ROLE_RADIO_MENU_ITEM:
89     case ATK_ROLE_ROOT_PANE:
90     case ATK_ROLE_ROW_HEADER:
91     case ATK_ROLE_SCROLL_BAR:
92     case ATK_ROLE_SCROLL_PANE:
93     case ATK_ROLE_SEPARATOR:
94     case ATK_ROLE_SLIDER:
95     case ATK_ROLE_SPLIT_PANE:
96     case ATK_ROLE_SPIN_BUTTON:
97     case ATK_ROLE_STATUSBAR:
98     case ATK_ROLE_TABLE:
99     case ATK_ROLE_TABLE_CELL:
100     case ATK_ROLE_TABLE_COLUMN_HEADER:
101     case ATK_ROLE_TABLE_ROW_HEADER:
102     case ATK_ROLE_TEAR_OFF_MENU_ITEM:
103     case ATK_ROLE_TERMINAL:
104     case ATK_ROLE_TEXT:
105     case ATK_ROLE_TOGGLE_BUTTON:
106     case ATK_ROLE_TOOL_BAR:
107     case ATK_ROLE_TOOL_TIP:
108     case ATK_ROLE_TREE:
109     case ATK_ROLE_TREE_TABLE:
110     case ATK_ROLE_UNKNOWN:
111     case ATK_ROLE_VIEWPORT:
112     case ATK_ROLE_WINDOW:
113     case ATK_ROLE_LAST_DEFINED:
114     default:
115       spi_role = Accessibility_ROLE_EXTENDED;       
116   }
117   return spi_role;
118 }
119
120 static AtkObject *
121 get_accessible_from_servant (PortableServer_Servant servant)
122 {
123   SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
124
125   if (!object)
126     {
127       return NULL;
128     }
129
130   return object->atko;
131 }
132
133 /*
134  * CORBA Accessibility::Accessible::get_name method implementation
135  */
136 static CORBA_char *
137 impl_accessibility_accessible_get_name (PortableServer_Servant servant,
138                                         CORBA_Environment     *ev)
139 {
140   const gchar *name;
141   CORBA_char  *retval;
142   AtkObject   *object = get_accessible_from_servant (servant);
143
144   g_return_val_if_fail (object != NULL, CORBA_string_dup (""));
145
146   name = atk_object_get_name (object);
147
148   if (name)
149     {
150       retval = CORBA_string_dup (name);
151     }
152   else
153     {
154       retval = CORBA_string_dup ("");
155     }
156
157   return retval;
158 }
159
160 /*
161  * CORBA Accessibility::Accessible::set_name method implementation
162  */
163 static void
164 impl_accessibility_accessible_set_name (PortableServer_Servant servant,
165                                         const CORBA_char      *name,
166                                         CORBA_Environment     *ev)
167 {
168   AtkObject *object = get_accessible_from_servant (servant);
169
170   g_return_if_fail (object != NULL);
171
172   atk_object_set_name (object, name);
173 }
174
175 /*
176  * CORBA Accessibility::Accessible::get_description method implementation
177  */
178 static CORBA_char *
179 impl_accessibility_accessible_get_description (PortableServer_Servant servant,
180                                                CORBA_Environment     *ev)
181 {
182   const gchar *descr;
183   CORBA_char  *retval;
184   AtkObject   *object = get_accessible_from_servant (servant);
185
186   g_return_val_if_fail (object != NULL, CORBA_string_dup (""));
187
188   descr = atk_object_get_description (object);
189
190   if (descr)
191     {
192       retval = CORBA_string_dup (descr);
193     }
194   else
195     {
196       retval = CORBA_string_dup ("");
197     }
198
199   return retval;
200 }
201
202 /*
203  * CORBA Accessibility::Accessible::set_description method implementation
204  */
205 static void
206 impl_accessibility_accessible_set_description (PortableServer_Servant servant,
207                                                const CORBA_char      *descr,
208                                                CORBA_Environment     *ev)
209 {
210   AtkObject *object = get_accessible_from_servant (servant);
211
212   g_return_if_fail (object != NULL);
213
214   atk_object_set_description (object, descr);
215 }
216
217 /*
218  * CORBA Accessibility::Accessible::get_parent method implementation
219  */
220 static Accessibility_Accessible
221 impl_accessibility_accessible_get_parent (PortableServer_Servant servant,
222                                           CORBA_Environment     *ev)
223 {
224   AtkObject *parent;
225   AtkObject *object = get_accessible_from_servant (servant);
226
227   g_return_val_if_fail (object != NULL, CORBA_OBJECT_NIL);
228
229   parent = atk_object_get_parent (object);
230
231   return spi_accessible_new_return (parent, FALSE, ev);
232 }
233
234 /*
235  * CORBA Accessibility::Accessible::get_IndexInParent method implementation
236  */
237 static CORBA_long
238 impl_accessibility_accessible_get_index_in_parent (PortableServer_Servant servant,
239                                                    CORBA_Environment     *ev)
240 {
241   AtkObject *object = get_accessible_from_servant (servant);
242
243   g_return_val_if_fail (object != NULL, -1);
244
245   return atk_object_get_index_in_parent (object);
246 }
247
248 /*
249  * CORBA Accessibility::Accessible::get_childCount method implementation
250  */
251 static CORBA_long
252 impl_accessibility_accessible_get_child_count (PortableServer_Servant servant,
253                                                CORBA_Environment     *ev)
254 {
255   AtkObject *object = get_accessible_from_servant (servant);
256
257   g_return_val_if_fail (object != NULL, 0);
258
259   return atk_object_get_n_accessible_children (object);
260 }
261
262 /*
263  * CORBA Accessibility::Accessible::getChildAtIndex method implementation
264  */
265 static Accessibility_Accessible
266 impl_accessibility_accessible_get_child_at_index (PortableServer_Servant servant,
267                                                   const CORBA_long      index,
268                                                   CORBA_Environment     *ev)
269 {
270   AtkObject *child;
271   AtkObject *object = get_accessible_from_servant (servant);
272
273   g_return_val_if_fail (object != NULL, 0);
274
275   child = atk_object_ref_accessible_child (object, index);
276
277   return spi_accessible_new_return (child, TRUE, ev);
278 }
279
280 /*
281  * CORBA Accessibility::Accessible::getState method implementation
282  */
283 static Accessibility_StateSet
284 impl_accessibility_accessible_get_state (PortableServer_Servant servant,
285                                          CORBA_Environment     *ev)
286 {
287   AtkObject *object = get_accessible_from_servant (servant);
288
289   bonobo_return_val_if_fail (object != NULL, NULL, ev);
290
291   printf ("SpiAccessible get_state.\n");
292
293   /* TODO: implement the bonobo stateset class */
294   return (Accessibility_StateSet) NULL;
295 }
296
297 /*
298  * CORBA Accessibility::Accessible::getRelationSet method implementation
299  */
300 static Accessibility_RelationSet *
301 impl_accessibility_accessible_get_relation_set (PortableServer_Servant servant,
302                                                 CORBA_Environment     *ev)
303 {
304   Accessibility_RelationSet *retval;
305   gint n_relations;
306   gint i;
307   AtkRelationSet *relation_set;
308   AtkObject      *object = get_accessible_from_servant (servant);
309
310   bonobo_return_val_if_fail (object != NULL, NULL, ev);
311
312   relation_set = atk_object_ref_relation_set (object);
313
314   n_relations = atk_relation_set_get_n_relations (relation_set);
315   retval = CORBA_sequence_Accessibility_Relation__alloc ();
316   CORBA_sequence_Accessibility_Relation_allocbuf (n_relations);
317           
318   for (i = 0; i < n_relations; ++i)
319     {
320       retval->_buffer[i] =
321         bonobo_object_dup_ref (
322           BONOBO_OBJREF (
323             spi_relation_new (atk_relation_set_get_relation (relation_set, i))),
324           ev);
325     }
326   
327   printf ("SpiAccessible get_relation_set.\n");
328   return retval;
329 }
330
331 /*
332  * CORBA Accessibility::Accessible::getRole method implementation
333  */
334 static Accessibility_Role
335 impl_accessibility_accessible_get_role (PortableServer_Servant servant,
336                                         CORBA_Environment     *ev)
337 {
338   AtkRole            role;
339   Accessibility_Role retval;
340   AtkObject         *object = get_accessible_from_servant (servant);
341
342   g_return_val_if_fail (object != NULL, 0);
343
344   role = atk_object_get_role (object);
345   retval = spi_role_from_atk_role (role);
346
347   return retval;
348 }
349
350 /*
351  * CORBA Accessibility::Accessible::getRole method implementation
352  */
353 static CORBA_char *
354 impl_accessibility_accessible_get_role_name (PortableServer_Servant servant,
355                                              CORBA_Environment     *ev)
356 {
357   AtkRole            role;
358   Accessibility_Role retval;
359   AtkObject         *object = get_accessible_from_servant (servant);
360
361   g_return_val_if_fail (object != NULL, 0);
362
363   role = atk_object_get_role (object);
364
365   return CORBA_string_dup (atk_role_get_name (role));
366 }
367
368 static void
369 spi_accessible_class_init (SpiAccessibleClass *klass)
370 {
371         POA_Accessibility_Accessible__epv *epv = &klass->epv;
372
373         epv->_get_name = impl_accessibility_accessible_get_name;
374         epv->_set_name = impl_accessibility_accessible_set_name;
375         epv->_get_description = impl_accessibility_accessible_get_description;
376         epv->_set_description = impl_accessibility_accessible_set_description;
377
378         epv->_get_parent = impl_accessibility_accessible_get_parent;
379         epv->_get_childCount = impl_accessibility_accessible_get_child_count;
380         epv->getChildAtIndex = impl_accessibility_accessible_get_child_at_index;
381         epv->getIndexInParent = impl_accessibility_accessible_get_index_in_parent;
382
383         epv->getRelationSet = impl_accessibility_accessible_get_relation_set;
384         epv->getState = impl_accessibility_accessible_get_state;
385         epv->getRole = impl_accessibility_accessible_get_role;
386         epv->getRoleName = impl_accessibility_accessible_get_role_name;
387 }
388
389 static void
390 spi_accessible_init (SpiAccessible *accessible)
391 {
392 }
393
394 BONOBO_TYPE_FUNC_FULL (SpiAccessible,
395                        Accessibility_Accessible,
396                        PARENT_TYPE,
397                        spi_accessible);
398
399 static GHashTable *public_corba_refs = NULL;
400
401 static GHashTable *
402 get_public_refs (void)
403 {
404   if (!public_corba_refs)
405     {
406       public_corba_refs = g_hash_table_new (NULL, NULL);
407     }
408   return public_corba_refs;
409 }
410
411 static void
412 de_register_public_ref (SpiBase *object)
413 {
414   g_hash_table_remove (get_public_refs (), object->atko);
415 }
416
417 SpiAccessible *
418 spi_accessible_new (AtkObject *o)
419 {
420     SpiAccessible *retval;
421     CORBA_Environment ev;
422
423     CORBA_exception_init (&ev);
424
425     g_assert (o);
426
427     if ((retval = g_hash_table_lookup (get_public_refs (), o)))
428       {
429         bonobo_object_ref (BONOBO_OBJECT (retval));
430         return retval;
431       }
432
433     retval = g_object_new (SPI_ACCESSIBLE_TYPE, NULL);
434
435     spi_base_construct (SPI_BASE (retval), o);
436
437     g_hash_table_insert (get_public_refs (), o, retval);
438     g_signal_connect (G_OBJECT (retval), "destroy",
439                       G_CALLBACK (de_register_public_ref),
440                       NULL);
441
442     /* aggregate appropriate SPI interfaces based on ATK interfaces */
443
444     if (ATK_IS_ACTION (o))
445       {
446         bonobo_object_add_interface (bonobo_object (retval),
447                                      BONOBO_OBJECT (spi_action_interface_new (o)));
448       }
449
450     if (ATK_IS_COMPONENT (o))
451       {
452         bonobo_object_add_interface (bonobo_object (retval),
453                                      BONOBO_OBJECT (spi_component_interface_new (o)));
454       }
455
456     if (ATK_IS_EDITABLE_TEXT (o))
457       {
458         bonobo_object_add_interface (bonobo_object (retval),
459                                      BONOBO_OBJECT(spi_editable_text_interface_new (o)));
460       }
461
462     else if (ATK_IS_HYPERTEXT (o))
463       {
464         bonobo_object_add_interface (bonobo_object (retval),
465                                      BONOBO_OBJECT (spi_hypertext_interface_new (o)));
466       }
467
468     else if (ATK_IS_TEXT (o))
469       {
470         bonobo_object_add_interface (bonobo_object (retval),
471                                      BONOBO_OBJECT (spi_text_interface_new (o)));
472       }
473
474     if (ATK_IS_IMAGE (o))
475       {
476         bonobo_object_add_interface (bonobo_object (retval),
477                                      BONOBO_OBJECT (spi_image_interface_new (o)));
478       }
479
480     if (ATK_IS_SELECTION (o))
481       {
482         bonobo_object_add_interface (bonobo_object (retval),
483                                      BONOBO_OBJECT (spi_selection_interface_new (o)));
484       }
485
486     if (ATK_IS_TABLE (o))
487       {
488         bonobo_object_add_interface (bonobo_object (retval),
489                                      BONOBO_OBJECT (spi_table_interface_new (o)));
490       }
491
492     if (ATK_IS_VALUE (o))
493       {
494         bonobo_object_add_interface (bonobo_object (retval),
495                                      BONOBO_OBJECT (spi_value_interface_new (o)));
496       }
497
498     return retval;
499 }
500
501 /**
502  * spi_accessible_new_return:
503  * @o: an AtkObject or NULL
504  * @release_ref: whether to unref this AtkObject before return
505  * @ev: a CORBA environment
506  * 
507  * A helper function to instantiate a CORBA accessiblility
508  * proxy from an AtkObject.
509  * 
510  * Return value: the proxy or CORBA_OBJECT_NIL
511  **/
512 Accessibility_Accessible
513 spi_accessible_new_return (AtkObject         *o,
514                            gboolean           release_ref,
515                            CORBA_Environment *ev)
516 {
517   SpiAccessible *accessible;
518
519   if (!o)
520     {
521       return CORBA_OBJECT_NIL;
522     }
523
524   accessible = spi_accessible_new (o);
525
526   if (release_ref)
527     {
528       g_object_unref (G_OBJECT (o));
529     }
530
531   return CORBA_Object_duplicate (BONOBO_OBJREF (accessible), ev);
532 }