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