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