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