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