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