xref: /AOO41X/main/vcl/unx/gtk/a11y/atkwrapper.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <com/sun/star/uno/Any.hxx>
32 #include <com/sun/star/uno/Type.hxx>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <com/sun/star/accessibility/AccessibleRole.hpp>
35 #include <com/sun/star/accessibility/AccessibleRelation.hpp>
36 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <com/sun/star/accessibility/XAccessible.hpp>
39 #include <com/sun/star/accessibility/XAccessibleText.hpp>
40 #include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
41 #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
42 #include <com/sun/star/accessibility/XAccessibleValue.hpp>
43 #include <com/sun/star/accessibility/XAccessibleAction.hpp>
44 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
45 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
46 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
47 #include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
48 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
49 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
50 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
51 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
52 #include <com/sun/star/accessibility/XAccessibleImage.hpp>
53 #include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
54 #include <com/sun/star/accessibility/XAccessibleHypertext.hpp>
55 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
56 #include <com/sun/star/awt/XExtendedToolkit.hpp>
57 #include <com/sun/star/awt/XTopWindow.hpp>
58 #include <com/sun/star/awt/XTopWindowListener.hpp>
59 #include <com/sun/star/awt/XWindow.hpp>
60 #include <com/sun/star/lang/XComponent.hpp>
61 #include <com/sun/star/lang/XServiceInfo.hpp>
62 #include <com/sun/star/lang/XInitialization.hpp>
63 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
64 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
65 #include <com/sun/star/beans/Property.hpp>
66 
67 #include <rtl/ref.hxx>
68 #include <cppuhelper/factory.hxx>
69 #include <cppuhelper/queryinterface.hxx>
70 
71 #include "atkwrapper.hxx"
72 #include "atkregistry.hxx"
73 #include "atklistener.hxx"
74 
75 #ifdef ENABLE_TRACING
76 #include <stdio.h>
77 #endif
78 
79 #include <string.h>
80 
81 using namespace ::com::sun::star;
82 
83 static GObjectClass *parent_class = NULL;
84 
85 static AtkRelationType mapRelationType( sal_Int16 nRelation )
86 {
87     AtkRelationType type = ATK_RELATION_NULL;
88 
89     switch( nRelation )
90     {
91         case accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM:
92             type = ATK_RELATION_FLOWS_FROM;
93             break;
94 
95         case accessibility::AccessibleRelationType::CONTENT_FLOWS_TO:
96             type = ATK_RELATION_FLOWS_TO;
97             break;
98 
99         case accessibility::AccessibleRelationType::CONTROLLED_BY:
100             type = ATK_RELATION_CONTROLLED_BY;
101             break;
102 
103         case accessibility::AccessibleRelationType::CONTROLLER_FOR:
104             type = ATK_RELATION_CONTROLLER_FOR;
105             break;
106 
107         case accessibility::AccessibleRelationType::LABEL_FOR:
108             type = ATK_RELATION_LABEL_FOR;
109             break;
110 
111         case accessibility::AccessibleRelationType::LABELED_BY:
112             type = ATK_RELATION_LABELLED_BY;
113             break;
114 
115         case accessibility::AccessibleRelationType::MEMBER_OF:
116             type = ATK_RELATION_MEMBER_OF;
117             break;
118 
119         case accessibility::AccessibleRelationType::SUB_WINDOW_OF:
120             type = ATK_RELATION_SUBWINDOW_OF;
121             break;
122 
123         case accessibility::AccessibleRelationType::NODE_CHILD_OF:
124             type = ATK_RELATION_NODE_CHILD_OF;
125             break;
126 
127         default:
128             break;
129     }
130 #if 0
131   ATK_RELATION_NODE_CHILD_OF,
132   ATK_RELATION_EMBEDS,
133   ATK_RELATION_EMBEDDED_BY,
134   ATK_RELATION_POPUP_FOR,
135 #endif
136     return type;
137 }
138 
139 
140 AtkStateType mapAtkState( sal_Int16 nState )
141 {
142     AtkStateType type = ATK_STATE_INVALID;
143 
144     // A perfect / complete mapping ...
145     switch( nState )
146     {
147 #define MAP_DIRECT( a ) \
148         case accessibility::AccessibleStateType::a: \
149             type = ATK_STATE_##a; break
150 
151         MAP_DIRECT( INVALID );
152         MAP_DIRECT( ACTIVE );
153         MAP_DIRECT( ARMED );
154         MAP_DIRECT( BUSY );
155         MAP_DIRECT( CHECKED );
156         MAP_DIRECT( EDITABLE );
157         MAP_DIRECT( ENABLED );
158         MAP_DIRECT( EXPANDABLE );
159         MAP_DIRECT( EXPANDED );
160         MAP_DIRECT( FOCUSABLE );
161         MAP_DIRECT( FOCUSED );
162         MAP_DIRECT( HORIZONTAL );
163         MAP_DIRECT( ICONIFIED );
164         MAP_DIRECT( INDETERMINATE );
165         MAP_DIRECT( MANAGES_DESCENDANTS );
166         MAP_DIRECT( MODAL );
167         MAP_DIRECT( MULTI_LINE );
168         MAP_DIRECT( OPAQUE );
169         MAP_DIRECT( PRESSED );
170         MAP_DIRECT( RESIZABLE );
171         MAP_DIRECT( SELECTABLE );
172         MAP_DIRECT( SELECTED );
173         MAP_DIRECT( SENSITIVE );
174         MAP_DIRECT( SHOWING );
175         MAP_DIRECT( SINGLE_LINE );
176         MAP_DIRECT( STALE );
177         MAP_DIRECT( TRANSIENT );
178         MAP_DIRECT( VERTICAL );
179         MAP_DIRECT( VISIBLE );
180         // a spelling error ...
181         case accessibility::AccessibleStateType::DEFUNC:
182             type = ATK_STATE_DEFUNCT; break;
183         case accessibility::AccessibleStateType::MULTI_SELECTABLE:
184             type = ATK_STATE_MULTISELECTABLE; break;
185     default:
186         break;
187     }
188 
189     return type;
190 }
191 
192 static inline AtkRole registerRole( const gchar * name )
193 {
194     AtkRole ret = atk_role_for_name( name );
195     if( ATK_ROLE_INVALID == ret )
196         ret = atk_role_register( name );
197 
198     return ret;
199 }
200 
201 static AtkRole mapToAtkRole( sal_Int16 nRole )
202 {
203     AtkRole role = ATK_ROLE_UNKNOWN;
204 
205     static AtkRole roleMap[] = {
206         ATK_ROLE_UNKNOWN,
207         ATK_ROLE_ALERT,
208         ATK_ROLE_COLUMN_HEADER,
209         ATK_ROLE_CANVAS,
210         ATK_ROLE_CHECK_BOX,
211         ATK_ROLE_CHECK_MENU_ITEM,
212         ATK_ROLE_COLOR_CHOOSER,
213         ATK_ROLE_COMBO_BOX,
214         ATK_ROLE_DATE_EDITOR,
215         ATK_ROLE_DESKTOP_ICON,
216         ATK_ROLE_DESKTOP_FRAME,   // ? pane
217         ATK_ROLE_DIRECTORY_PANE,
218         ATK_ROLE_DIALOG,
219         ATK_ROLE_UNKNOWN,         // DOCUMENT - registered below
220         ATK_ROLE_UNKNOWN,         // EMBEDDED_OBJECT - registered below
221         ATK_ROLE_UNKNOWN,         // END_NOTE - registered below
222         ATK_ROLE_FILE_CHOOSER,
223         ATK_ROLE_FILLER,
224         ATK_ROLE_FONT_CHOOSER,
225         ATK_ROLE_FOOTER,
226         ATK_ROLE_TEXT,            // FOOTNOTE - registered below
227         ATK_ROLE_FRAME,
228         ATK_ROLE_GLASS_PANE,
229         ATK_ROLE_IMAGE,           // GRAPHIC
230         ATK_ROLE_UNKNOWN,         // GROUP_BOX - registered below
231         ATK_ROLE_HEADER,
232         ATK_ROLE_PARAGRAPH,       // HEADING - registered below
233         ATK_ROLE_TEXT,            // HYPER_LINK - registered below
234         ATK_ROLE_ICON,
235         ATK_ROLE_INTERNAL_FRAME,
236         ATK_ROLE_LABEL,
237         ATK_ROLE_LAYERED_PANE,
238         ATK_ROLE_LIST,
239         ATK_ROLE_LIST_ITEM,
240         ATK_ROLE_MENU,
241         ATK_ROLE_MENU_BAR,
242         ATK_ROLE_MENU_ITEM,
243         ATK_ROLE_OPTION_PANE,
244         ATK_ROLE_PAGE_TAB,
245         ATK_ROLE_PAGE_TAB_LIST,
246         ATK_ROLE_PANEL,
247         ATK_ROLE_PARAGRAPH,
248         ATK_ROLE_PASSWORD_TEXT,
249         ATK_ROLE_POPUP_MENU,
250         ATK_ROLE_PUSH_BUTTON,
251         ATK_ROLE_PROGRESS_BAR,
252         ATK_ROLE_RADIO_BUTTON,
253         ATK_ROLE_RADIO_MENU_ITEM,
254         ATK_ROLE_ROW_HEADER,
255         ATK_ROLE_ROOT_PANE,
256         ATK_ROLE_SCROLL_BAR,
257         ATK_ROLE_SCROLL_PANE,
258         ATK_ROLE_UNKNOWN,        // SHAPE - registered below
259         ATK_ROLE_SEPARATOR,
260         ATK_ROLE_SLIDER,
261         ATK_ROLE_SPIN_BUTTON,    // SPIN_BOX ?
262         ATK_ROLE_SPLIT_PANE,
263         ATK_ROLE_STATUSBAR,
264         ATK_ROLE_TABLE,
265         ATK_ROLE_TABLE_CELL,
266         ATK_ROLE_TEXT,
267         ATK_ROLE_INTERNAL_FRAME, // TEXT_FRAME - registered below
268         ATK_ROLE_TOGGLE_BUTTON,
269         ATK_ROLE_TOOL_BAR,
270         ATK_ROLE_TOOL_TIP,
271         ATK_ROLE_TREE,
272         ATK_ROLE_VIEWPORT,
273         ATK_ROLE_WINDOW,
274         ATK_ROLE_PUSH_BUTTON,   // BUTTON_DROPDOWN
275         ATK_ROLE_PUSH_BUTTON,   // BUTTON_MENU
276         ATK_ROLE_UNKNOWN,       // CAPTION - registered below
277         ATK_ROLE_UNKNOWN,       // CHART - registered below
278         ATK_ROLE_UNKNOWN,       // EDIT_BAR - registered below
279         ATK_ROLE_UNKNOWN,       // FORM - registered below
280         ATK_ROLE_UNKNOWN,       // IMAGE_MAP - registered below
281         ATK_ROLE_UNKNOWN,       // NOTE - registered below
282         ATK_ROLE_UNKNOWN,       // PAGE - registered below
283         ATK_ROLE_RULER,
284         ATK_ROLE_UNKNOWN,       // SECTION - registered below
285         ATK_ROLE_UNKNOWN,       // TREE_ITEM - registered below
286         ATK_ROLE_TREE_TABLE,
287         ATK_ROLE_SCROLL_PANE,   // COMMENT - mapped to atk_role_scroll_pane
288         ATK_ROLE_UNKNOWN        // COMMENT_END - mapped to atk_role_unknown
289     };
290 
291     static bool initialized = false;
292 
293     if( ! initialized )
294     {
295         // re-use strings from ATK library
296         roleMap[accessibility::AccessibleRole::EDIT_BAR] = registerRole("edit bar");
297         roleMap[accessibility::AccessibleRole::EMBEDDED_OBJECT] = registerRole("embedded component");
298         roleMap[accessibility::AccessibleRole::CHART] = registerRole("chart");
299         roleMap[accessibility::AccessibleRole::CAPTION] = registerRole("caption");
300         roleMap[accessibility::AccessibleRole::DOCUMENT] = registerRole("document frame");
301         roleMap[accessibility::AccessibleRole::HEADING] = registerRole("heading");
302         roleMap[accessibility::AccessibleRole::PAGE] = registerRole("page");
303         roleMap[accessibility::AccessibleRole::SECTION] = registerRole("section");
304         roleMap[accessibility::AccessibleRole::FORM] = registerRole("form");
305 
306         // these don't exist in ATK yet
307         roleMap[accessibility::AccessibleRole::END_NOTE] = registerRole("end note");
308         roleMap[accessibility::AccessibleRole::FOOTNOTE] = registerRole("foot note");
309         roleMap[accessibility::AccessibleRole::GROUP_BOX] = registerRole("group box");
310         roleMap[accessibility::AccessibleRole::HYPER_LINK] = registerRole("hyper link");
311         roleMap[accessibility::AccessibleRole::SHAPE] = registerRole("shape");
312         roleMap[accessibility::AccessibleRole::TEXT_FRAME] = registerRole("text frame");
313         roleMap[accessibility::AccessibleRole::IMAGE_MAP] = registerRole("image map");
314         roleMap[accessibility::AccessibleRole::NOTE] = registerRole("note");
315         roleMap[accessibility::AccessibleRole::TREE_ITEM] = registerRole("tree item");
316 
317         initialized = true;
318     }
319 
320     static const sal_Int32 nMapSize = sizeof(roleMap)/sizeof(sal_Int16);
321     if( 0 <= nRole &&  nMapSize > nRole )
322         role = roleMap[nRole];
323 
324     return role;
325 }
326 
327 
328 /*****************************************************************************/
329 
330 extern "C" {
331 
332 /*****************************************************************************/
333 
334 static G_CONST_RETURN gchar*
335 wrapper_get_name( AtkObject *atk_obj )
336 {
337     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
338 
339     if( obj->mpContext )
340     {
341         try {
342             rtl::OString aName =
343                 rtl::OUStringToOString(
344                     obj->mpContext->getAccessibleName(),
345                     RTL_TEXTENCODING_UTF8);
346 
347             int nCmp = atk_obj->name ? rtl_str_compare( atk_obj->name, aName.getStr() ) : -1;
348             if( nCmp != 0 )
349             {
350                 if( atk_obj->name )
351                     g_free(atk_obj->name);
352                 atk_obj->name = g_strdup(aName.getStr());
353             }
354         }
355         catch(const uno::Exception& e) {
356             g_warning( "Exception in getAccessibleName()" );
357         }
358     }
359 
360     return ATK_OBJECT_CLASS (parent_class)->get_name(atk_obj);
361 }
362 
363 /*****************************************************************************/
364 
365 static G_CONST_RETURN gchar*
366 wrapper_get_description( AtkObject *atk_obj )
367 {
368     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
369 
370     if( obj->mpContext )
371     {
372         try {
373             rtl::OString aDescription =
374                 rtl::OUStringToOString(
375                     obj->mpContext->getAccessibleDescription(),
376                     RTL_TEXTENCODING_UTF8);
377 
378             g_free(atk_obj->description);
379             atk_obj->description = g_strdup(aDescription.getStr());
380         }
381         catch(const uno::Exception& e) {
382             g_warning( "Exception in getAccessibleDescription()" );
383         }
384     }
385 
386     return ATK_OBJECT_CLASS (parent_class)->get_description(atk_obj);
387 
388 }
389 
390 /*****************************************************************************/
391 
392 static gint
393 wrapper_get_n_children( AtkObject *atk_obj )
394 {
395     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
396     gint n = 0;
397 
398     if( obj->mpContext )
399     {
400         try {
401             n = obj->mpContext->getAccessibleChildCount();
402         }
403         catch(const uno::Exception& e) {
404             OSL_ENSURE(0, "Exception in getAccessibleChildCount()" );
405         }
406     }
407 
408     return n;
409 }
410 
411 /*****************************************************************************/
412 
413 static AtkObject *
414 wrapper_ref_child( AtkObject *atk_obj,
415                    gint       i )
416 {
417     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
418     AtkObject* child = NULL;
419 
420     // see comments above atk_object_wrapper_remove_child
421     if( -1 < i && obj->index_of_child_about_to_be_removed == i )
422     {
423         g_object_ref( obj->child_about_to_be_removed );
424         return obj->child_about_to_be_removed;
425     }
426 
427     if( obj->mpContext )
428     {
429         try {
430             uno::Reference< accessibility::XAccessible > xAccessible =
431                 obj->mpContext->getAccessibleChild( i );
432 
433             child = atk_object_wrapper_ref( xAccessible );
434         }
435         catch(const uno::Exception& e) {
436             OSL_ENSURE(0, "Exception in getAccessibleChild");
437         }
438     }
439 
440     return child;
441 }
442 
443 /*****************************************************************************/
444 
445 static gint
446 wrapper_get_index_in_parent( AtkObject *atk_obj )
447 {
448     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
449     gint i = -1;
450 
451     if( obj->mpContext )
452     {
453         try {
454             i = obj->mpContext->getAccessibleIndexInParent();
455 
456 #ifdef ENABLE_TRACING
457             fprintf(stderr, "%p->getAccessibleIndexInParent() returned: %u\n",
458                 obj->mpAccessible, i);
459 #endif
460         }
461         catch(const uno::Exception& e) {
462             g_warning( "Exception in getAccessibleIndexInParent()" );
463         }
464     }
465     return i;
466 }
467 
468 /*****************************************************************************/
469 
470 static AtkRelationSet *
471 wrapper_ref_relation_set( AtkObject *atk_obj )
472 {
473     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
474     AtkRelationSet *pSet = atk_relation_set_new();
475 
476     if( obj->mpContext )
477     {
478         try {
479             uno::Reference< accessibility::XAccessibleRelationSet > xRelationSet(
480                     obj->mpContext->getAccessibleRelationSet()
481             );
482 
483             sal_Int32 nRelations = xRelationSet.is() ? xRelationSet->getRelationCount() : 0;
484             for( sal_Int32 n = 0; n < nRelations; n++ )
485             {
486                 accessibility::AccessibleRelation aRelation = xRelationSet->getRelation( n );
487                 sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
488                 AtkObject **pTargets = (AtkObject **) alloca( nTargetCount * sizeof(AtkObject *) );
489 
490                 for( sal_uInt32 i = 0; i < nTargetCount; i++ )
491                 {
492                     uno::Reference< accessibility::XAccessible > xAccessible(
493                             aRelation.TargetSet[i], uno::UNO_QUERY );
494                     pTargets[i] = atk_object_wrapper_ref( xAccessible );
495                 }
496 
497                 AtkRelation *pRel =
498                     atk_relation_new(
499                         pTargets, nTargetCount,
500                         mapRelationType( aRelation.RelationType )
501                     );
502                 atk_relation_set_add( pSet, pRel );
503                 g_object_unref( G_OBJECT( pRel ) );
504             }
505         }
506         catch(const uno::Exception &e) {
507             g_object_unref( G_OBJECT( pSet ) );
508             pSet = NULL;
509         }
510     }
511 
512     return pSet;
513 }
514 
515 /*****************************************************************************/
516 
517 #if 0
518 struct {
519     sal_Int16       value;
520     const sal_Char* name;
521 } aStateTypeTable[] = {
522     { accessibility::AccessibleStateType::INVALID, "INVALID" },
523     { accessibility::AccessibleStateType::ACTIVE, "ACTIVE" },
524     { accessibility::AccessibleStateType::ARMED, "ARMED" },
525     { accessibility::AccessibleStateType::BUSY, "BUSY" },
526     { accessibility::AccessibleStateType::CHECKED, "CHECKED" },
527     { accessibility::AccessibleStateType::DEFUNC, "DEFUNC" },
528     { accessibility::AccessibleStateType::EDITABLE, "EDITABLE" },
529     { accessibility::AccessibleStateType::ENABLED, "ENABLED" },
530     { accessibility::AccessibleStateType::EXPANDABLE, "EXPANDABLE" },
531     { accessibility::AccessibleStateType::EXPANDED, "EXPANDED" },
532     { accessibility::AccessibleStateType::FOCUSABLE, "FOCUSABLE" },
533     { accessibility::AccessibleStateType::FOCUSED, "FOCUSED" },
534     { accessibility::AccessibleStateType::HORIZONTAL, "HORIZONTAL" },
535     { accessibility::AccessibleStateType::ICONIFIED, "ICONIFIED" },
536     { accessibility::AccessibleStateType::INDETERMINATE, "INDETERMINATE" },
537     { accessibility::AccessibleStateType::MANAGES_DESCENDANTS, "MANAGES_DESCENDANTS" },
538     { accessibility::AccessibleStateType::MODAL, "MODAL" },
539     { accessibility::AccessibleStateType::MULTI_LINE, "MULTI_LINE" },
540     { accessibility::AccessibleStateType::MULTI_SELECTABLE, "MULTI_SELECTABLE" },
541     { accessibility::AccessibleStateType::OPAQUE, "OPAQUE" },
542     { accessibility::AccessibleStateType::PRESSED, "PRESSED" },
543     { accessibility::AccessibleStateType::RESIZABLE, "RESIZABLE" },
544     { accessibility::AccessibleStateType::SELECTABLE, "SELECTABLE" },
545     { accessibility::AccessibleStateType::SELECTED, "SELECTED" },
546     { accessibility::AccessibleStateType::SENSITIVE, "SENSITIVE" },
547     { accessibility::AccessibleStateType::SHOWING, "SHOWING" },
548     { accessibility::AccessibleStateType::SINGLE_LINE, "SINGLE_LINE" },
549     { accessibility::AccessibleStateType::STALE, "STALE" },
550     { accessibility::AccessibleStateType::TRANSIENT, "TRANSIENT" },
551     { accessibility::AccessibleStateType::VERTICAL, "VERTICAL" },
552     { accessibility::AccessibleStateType::VISIBLE, "VISIBLE" }
553 };
554 
555 static void printStates(const uno::Sequence<sal_Int16>& rStates)
556 {
557     sal_Int32 n = rStates.getLength();
558     size_t nTypes = sizeof(aStateTypeTable)/sizeof(aStateTypeTable[0]);
559     for (sal_Int32 i = 0; i < n; ++i)
560     {
561         for (size_t j = 0; j < nTypes; ++j)
562         {
563             if (aStateTypeTable[j].value == rStates[i])
564                 printf("%s ", aStateTypeTable[j].name);
565         }
566     }
567     printf("\n");
568 }
569 #endif
570 
571 static AtkStateSet *
572 wrapper_ref_state_set( AtkObject *atk_obj )
573 {
574     AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
575     AtkStateSet *pSet = atk_state_set_new();
576 
577     if( obj->mpContext )
578     {
579         try {
580             uno::Reference< accessibility::XAccessibleStateSet > xStateSet(
581                 obj->mpContext->getAccessibleStateSet());
582 
583             if( xStateSet.is() )
584             {
585                 uno::Sequence< sal_Int16 > aStates = xStateSet->getStates();
586 
587                 for( sal_Int32 n = 0; n < aStates.getLength(); n++ )
588                     atk_state_set_add_state( pSet, mapAtkState( aStates[n] ) );
589 
590                 // We need to emulate FOCUS state for menus, menu-items etc.
591                 if( atk_obj == atk_get_focus_object() )
592                     atk_state_set_add_state( pSet, ATK_STATE_FOCUSED );
593 /* FIXME - should we do this ?
594                 else
595                     atk_state_set_remove_state( pSet, ATK_STATE_FOCUSED );
596 */
597             }
598         }
599 
600         catch(const uno::Exception &e) {
601             g_warning( "Exception in wrapper_ref_state_set" );
602             atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
603         }
604     }
605     else
606         atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
607 
608     return pSet;
609 }
610 
611 /*****************************************************************************/
612 
613 
614 static void
615 atk_object_wrapper_finalize (GObject *obj)
616 {
617     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER (obj);
618 
619     if( pWrap->mpAccessible )
620     {
621         ooo_wrapper_registry_remove( pWrap->mpAccessible );
622         pWrap->mpAccessible->release();
623         pWrap->mpAccessible = NULL;
624     }
625 
626     atk_object_wrapper_dispose( pWrap );
627 
628     parent_class->finalize( obj );
629 }
630 
631 static void
632 atk_object_wrapper_class_init (AtkObjectWrapperClass *klass)
633 {
634   GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
635   AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass );
636 
637   parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
638 
639   // GObject methods
640   gobject_class->finalize = atk_object_wrapper_finalize;
641 
642   // AtkObject methods
643   atk_class->get_name = wrapper_get_name;
644   atk_class->get_description = wrapper_get_description;
645   atk_class->get_n_children = wrapper_get_n_children;
646   atk_class->ref_child = wrapper_ref_child;
647   atk_class->get_index_in_parent = wrapper_get_index_in_parent;
648   atk_class->ref_relation_set = wrapper_ref_relation_set;
649   atk_class->ref_state_set = wrapper_ref_state_set;
650 }
651 
652 static void
653 atk_object_wrapper_init (AtkObjectWrapper      *wrapper,
654                          AtkObjectWrapperClass)
655 {
656    wrapper->mpAction = NULL;
657    wrapper->mpComponent = NULL;
658    wrapper->mpEditableText = NULL;
659    wrapper->mpHypertext = NULL;
660    wrapper->mpImage = NULL;
661    wrapper->mpSelection = NULL;
662    wrapper->mpTable = NULL;
663    wrapper->mpText = NULL;
664    wrapper->mpValue = NULL;
665 }
666 
667 } // extern "C"
668 
669 GType
670 atk_object_wrapper_get_type (void)
671 {
672   static GType type = 0;
673 
674   if (!type)
675     {
676       static const GTypeInfo typeInfo =
677       {
678         sizeof (AtkObjectWrapperClass),
679         (GBaseInitFunc) NULL,
680         (GBaseFinalizeFunc) NULL,
681         (GClassInitFunc) atk_object_wrapper_class_init,
682         (GClassFinalizeFunc) NULL,
683         NULL,
684         sizeof (AtkObjectWrapper),
685         0,
686         (GInstanceInitFunc) atk_object_wrapper_init,
687         NULL
688       } ;
689       type = g_type_register_static (ATK_TYPE_OBJECT,
690                                      "OOoAtkObj",
691                                      &typeInfo, (GTypeFlags)0) ;
692     }
693   return type;
694 }
695 
696 static bool
697 isOfType( uno::XInterface *pInterface, const uno::Type & rType )
698 {
699     g_return_val_if_fail( pInterface != NULL, false );
700 
701     bool bIs = false;
702     try {
703         uno::Any aRet = pInterface->queryInterface( rType );
704 
705         bIs = ( ( typelib_TypeClass_INTERFACE == aRet.pType->eTypeClass ) &&
706                 ( aRet.pReserved != NULL ) );
707     } catch( const uno::Exception &e) { }
708 
709     return bIs;
710 }
711 
712 extern "C" {
713 typedef  GType (* GetGIfaceType ) (void);
714 }
715 const struct {
716         const char          *name;
717         GInterfaceInitFunc   aInit;
718         GetGIfaceType        aGetGIfaceType;
719         const uno::Type &  (*aGetUnoType) (void *);
720 } aTypeTable[] = {
721 // re-location heaven:
722     {
723         "Comp", (GInterfaceInitFunc) componentIfaceInit,
724         atk_component_get_type,
725         accessibility::XAccessibleComponent::static_type
726     },
727     {
728         "Act",  (GInterfaceInitFunc) actionIfaceInit,
729         atk_action_get_type,
730         accessibility::XAccessibleAction::static_type
731     },
732     {
733         "Txt",  (GInterfaceInitFunc) textIfaceInit,
734         atk_text_get_type,
735         accessibility::XAccessibleText::static_type
736     },
737     {
738         "Val",  (GInterfaceInitFunc) valueIfaceInit,
739         atk_value_get_type,
740         accessibility::XAccessibleValue::static_type
741     },
742     {
743         "Tab",  (GInterfaceInitFunc) tableIfaceInit,
744         atk_table_get_type,
745         accessibility::XAccessibleTable::static_type
746     },
747     {
748         "Edt",  (GInterfaceInitFunc) editableTextIfaceInit,
749         atk_editable_text_get_type,
750         accessibility::XAccessibleEditableText::static_type
751     },
752     {
753         "Img",  (GInterfaceInitFunc) imageIfaceInit,
754         atk_image_get_type,
755         accessibility::XAccessibleImage::static_type
756     },
757     {
758         "Hyp",  (GInterfaceInitFunc) hypertextIfaceInit,
759         atk_hypertext_get_type,
760         accessibility::XAccessibleHypertext::static_type
761     },
762     {
763         "Sel",  (GInterfaceInitFunc) selectionIfaceInit,
764         atk_selection_get_type,
765         accessibility::XAccessibleSelection::static_type
766     }
767     // AtkDocument is a nastily broken interface (so far)
768     //  we could impl. get_document_type perhaps though.
769 };
770 
771 const int aTypeTableSize = G_N_ELEMENTS( aTypeTable );
772 
773 static GType
774 ensureTypeFor( uno::XInterface *pAccessible )
775 {
776     int i;
777     int bTypes[ aTypeTableSize ] = { 0, };
778     rtl::OString aTypeName( "OOoAtkObj" );
779 
780     for( i = 0; i < aTypeTableSize; i++ )
781     {
782         if( isOfType( pAccessible, aTypeTable[i].aGetUnoType(0) ) )
783         {
784             aTypeName += aTypeTable[i].name;
785             bTypes[i] = TRUE;
786         }
787 //      g_message( "Accessible %p has type '%s' (%d)",
788 //                 pAccessible, aTypeTable[i].name, bTypes[i] );
789     }
790 
791     GType nType = g_type_from_name( aTypeName );
792     if( nType == G_TYPE_INVALID )
793     {
794         GTypeInfo aTypeInfo = {
795             sizeof( AtkObjectWrapperClass ),
796             NULL, NULL, NULL, NULL, NULL,
797             sizeof( AtkObjectWrapper ),
798             0, NULL, NULL
799         } ;
800         nType = g_type_register_static( ATK_TYPE_OBJECT_WRAPPER,
801                                         aTypeName, &aTypeInfo, (GTypeFlags)0 ) ;
802 
803         for( int j = 0; j < aTypeTableSize; j++ )
804             if( bTypes[j] )
805             {
806                 GInterfaceInfo aIfaceInfo = { NULL, NULL, NULL };
807                 aIfaceInfo.interface_init = aTypeTable[j].aInit;
808                 g_type_add_interface_static (nType, aTypeTable[j].aGetGIfaceType(),
809                                              &aIfaceInfo);
810             }
811     }
812     return nType;
813 }
814 
815 AtkObject *
816 atk_object_wrapper_ref( const uno::Reference< accessibility::XAccessible > &rxAccessible, bool create )
817 {
818     g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
819 
820     AtkObject *obj = ooo_wrapper_registry_get(rxAccessible);
821     if( obj )
822     {
823         g_object_ref( obj );
824         return obj;
825     }
826 
827     if( create )
828         return atk_object_wrapper_new( rxAccessible );
829 
830     return NULL;
831 }
832 
833 
834 AtkObject *
835 atk_object_wrapper_new( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
836                         AtkObject* parent )
837 {
838     g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
839 
840     AtkObjectWrapper *pWrap = NULL;
841 
842     try {
843         uno::Reference< accessibility::XAccessibleContext > xContext(rxAccessible->getAccessibleContext());
844 
845         g_return_val_if_fail( xContext.get() != NULL, NULL );
846 
847         GType nType = ensureTypeFor( xContext.get() );
848         gpointer obj = g_object_new( nType, NULL);
849 
850         pWrap = ATK_OBJECT_WRAPPER( obj );
851         pWrap->mpAccessible = rxAccessible.get();
852         rxAccessible->acquire();
853 
854         pWrap->index_of_child_about_to_be_removed = -1;
855         pWrap->child_about_to_be_removed = NULL;
856 
857         xContext->acquire();
858         pWrap->mpContext = xContext.get();
859 
860         AtkObject* atk_obj = ATK_OBJECT(pWrap);
861         atk_obj->role = mapToAtkRole( xContext->getAccessibleRole() );
862         atk_obj->accessible_parent = parent;
863 
864         ooo_wrapper_registry_add( rxAccessible, atk_obj );
865 
866         if( parent )
867             g_object_ref( atk_obj->accessible_parent );
868         else
869         {
870             /* gail_focus_tracker remembers the focused object at the first
871              * parent in the hierachy that is a Gtk+ widget, but at the time the
872              * event gets processed (at idle), it may be too late to create the
873              * hierachy, so doing it now ..
874              */
875             uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
876 
877             /* The top-level objects should never be of this class */
878             OSL_ASSERT( xParent.is() );
879 
880             if( xParent.is() )
881                 atk_obj->accessible_parent = atk_object_wrapper_ref( xParent );
882         }
883 
884         // Attach a listener to the UNO object if it's not TRANSIENT
885         uno::Reference< accessibility::XAccessibleStateSet > xStateSet( xContext->getAccessibleStateSet() );
886         if( xStateSet.is() && ! xStateSet->contains( accessibility::AccessibleStateType::TRANSIENT ) )
887         {
888             uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
889             if( xBroadcaster.is() )
890                 xBroadcaster->addEventListener( static_cast< accessibility::XAccessibleEventListener * > ( new AtkListener(pWrap) ) );
891 	    else
892                 OSL_ASSERT( false );
893         }
894 
895         return ATK_OBJECT( pWrap );
896     }
897     catch (const uno::Exception &e)
898     {
899         if( pWrap )
900             g_object_unref( pWrap );
901 
902         return NULL;
903     }
904 }
905 
906 
907 /*****************************************************************************/
908 
909 void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
910 {
911     AtkObject *atk_obj = ATK_OBJECT( wrapper );
912 
913     atk_object_set_parent( child, atk_obj );
914     g_signal_emit_by_name( atk_obj, "children_changed::add", index, child, NULL );
915 }
916 
917 /*****************************************************************************/
918 
919 void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
920 {
921     /*
922      * the atk-bridge GTK+ module get's back to the event source to ref the child just
923      * vanishing, so we keep this reference because the semantic on OOo side is different.
924      */
925     wrapper->child_about_to_be_removed = child;
926     wrapper->index_of_child_about_to_be_removed = index;
927 
928     g_signal_emit_by_name( ATK_OBJECT( wrapper ), "children_changed::remove", index, child, NULL );
929 
930     wrapper->index_of_child_about_to_be_removed = -1;
931     wrapper->child_about_to_be_removed = NULL;
932 }
933 
934 /*****************************************************************************/
935 
936 #define RELEASE(i) if( i ) { i->release(); i = NULL; }
937 
938 void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper)
939 {
940     RELEASE( wrapper->mpContext )
941     RELEASE( wrapper->mpAction )
942     RELEASE( wrapper->mpComponent )
943     RELEASE( wrapper->mpEditableText )
944     RELEASE( wrapper->mpHypertext )
945     RELEASE( wrapper->mpImage )
946     RELEASE( wrapper->mpSelection )
947     RELEASE( wrapper->mpMultiLineText )
948     RELEASE( wrapper->mpTable )
949     RELEASE( wrapper->mpText )
950     RELEASE( wrapper->mpTextMarkup )
951     RELEASE( wrapper->mpTextAttributes )
952     RELEASE( wrapper->mpValue )
953 }
954