| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <com/sun/star/uno/Any.hxx> |
| #include <com/sun/star/uno/Type.hxx> |
| #include <com/sun/star/uno/Sequence.hxx> |
| #include <com/sun/star/accessibility/AccessibleRole.hpp> |
| #include <com/sun/star/accessibility/AccessibleRelation.hpp> |
| #include <com/sun/star/accessibility/AccessibleRelationType.hpp> |
| #include <com/sun/star/accessibility/AccessibleStateType.hpp> |
| #include <com/sun/star/accessibility/XAccessible.hpp> |
| #include <com/sun/star/accessibility/XAccessibleText.hpp> |
| #include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp> |
| #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp> |
| #include <com/sun/star/accessibility/XAccessibleValue.hpp> |
| #include <com/sun/star/accessibility/XAccessibleAction.hpp> |
| #include <com/sun/star/accessibility/XAccessibleContext.hpp> |
| #include <com/sun/star/accessibility/XAccessibleComponent.hpp> |
| #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> |
| #include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp> |
| #include <com/sun/star/accessibility/XAccessibleStateSet.hpp> |
| #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> |
| #include <com/sun/star/accessibility/XAccessibleTable.hpp> |
| #include <com/sun/star/accessibility/XAccessibleEditableText.hpp> |
| #include <com/sun/star/accessibility/XAccessibleImage.hpp> |
| #include <com/sun/star/accessibility/XAccessibleHyperlink.hpp> |
| #include <com/sun/star/accessibility/XAccessibleHypertext.hpp> |
| #include <com/sun/star/accessibility/XAccessibleSelection.hpp> |
| #include <com/sun/star/awt/XExtendedToolkit.hpp> |
| #include <com/sun/star/awt/XTopWindow.hpp> |
| #include <com/sun/star/awt/XTopWindowListener.hpp> |
| #include <com/sun/star/awt/XWindow.hpp> |
| #include <com/sun/star/lang/XComponent.hpp> |
| #include <com/sun/star/lang/XServiceInfo.hpp> |
| #include <com/sun/star/lang/XInitialization.hpp> |
| #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
| #include <com/sun/star/lang/XSingleServiceFactory.hpp> |
| #include <com/sun/star/beans/Property.hpp> |
| |
| #include <rtl/ref.hxx> |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/queryinterface.hxx> |
| |
| #include "atkwrapper.hxx" |
| #include "atkregistry.hxx" |
| #include "atklistener.hxx" |
| |
| #ifdef ENABLE_TRACING |
| #include <stdio.h> |
| #endif |
| |
| #include <string.h> |
| |
| using namespace ::com::sun::star; |
| |
| static GObjectClass *parent_class = NULL; |
| |
| static AtkRelationType mapRelationType( sal_Int16 nRelation ) |
| { |
| AtkRelationType type = ATK_RELATION_NULL; |
| |
| switch( nRelation ) |
| { |
| case accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM: |
| type = ATK_RELATION_FLOWS_FROM; |
| break; |
| |
| case accessibility::AccessibleRelationType::CONTENT_FLOWS_TO: |
| type = ATK_RELATION_FLOWS_TO; |
| break; |
| |
| case accessibility::AccessibleRelationType::CONTROLLED_BY: |
| type = ATK_RELATION_CONTROLLED_BY; |
| break; |
| |
| case accessibility::AccessibleRelationType::CONTROLLER_FOR: |
| type = ATK_RELATION_CONTROLLER_FOR; |
| break; |
| |
| case accessibility::AccessibleRelationType::LABEL_FOR: |
| type = ATK_RELATION_LABEL_FOR; |
| break; |
| |
| case accessibility::AccessibleRelationType::LABELED_BY: |
| type = ATK_RELATION_LABELLED_BY; |
| break; |
| |
| case accessibility::AccessibleRelationType::MEMBER_OF: |
| type = ATK_RELATION_MEMBER_OF; |
| break; |
| |
| case accessibility::AccessibleRelationType::SUB_WINDOW_OF: |
| type = ATK_RELATION_SUBWINDOW_OF; |
| break; |
| |
| case accessibility::AccessibleRelationType::NODE_CHILD_OF: |
| type = ATK_RELATION_NODE_CHILD_OF; |
| break; |
| |
| default: |
| break; |
| } |
| #if 0 |
| ATK_RELATION_NODE_CHILD_OF, |
| ATK_RELATION_EMBEDS, |
| ATK_RELATION_EMBEDDED_BY, |
| ATK_RELATION_POPUP_FOR, |
| #endif |
| return type; |
| } |
| |
| |
| AtkStateType mapAtkState( sal_Int16 nState ) |
| { |
| AtkStateType type = ATK_STATE_INVALID; |
| |
| // A perfect / complete mapping ... |
| switch( nState ) |
| { |
| #define MAP_DIRECT( a ) \ |
| case accessibility::AccessibleStateType::a: \ |
| type = ATK_STATE_##a; break |
| |
| MAP_DIRECT( INVALID ); |
| MAP_DIRECT( ACTIVE ); |
| MAP_DIRECT( ARMED ); |
| MAP_DIRECT( BUSY ); |
| MAP_DIRECT( CHECKED ); |
| MAP_DIRECT( EDITABLE ); |
| MAP_DIRECT( ENABLED ); |
| MAP_DIRECT( EXPANDABLE ); |
| MAP_DIRECT( EXPANDED ); |
| MAP_DIRECT( FOCUSABLE ); |
| MAP_DIRECT( FOCUSED ); |
| MAP_DIRECT( HORIZONTAL ); |
| MAP_DIRECT( ICONIFIED ); |
| MAP_DIRECT( INDETERMINATE ); |
| MAP_DIRECT( MANAGES_DESCENDANTS ); |
| MAP_DIRECT( MODAL ); |
| MAP_DIRECT( MULTI_LINE ); |
| MAP_DIRECT( OPAQUE ); |
| MAP_DIRECT( PRESSED ); |
| MAP_DIRECT( RESIZABLE ); |
| MAP_DIRECT( SELECTABLE ); |
| MAP_DIRECT( SELECTED ); |
| MAP_DIRECT( SENSITIVE ); |
| MAP_DIRECT( SHOWING ); |
| MAP_DIRECT( SINGLE_LINE ); |
| MAP_DIRECT( STALE ); |
| MAP_DIRECT( TRANSIENT ); |
| MAP_DIRECT( VERTICAL ); |
| MAP_DIRECT( VISIBLE ); |
| // a spelling error ... |
| case accessibility::AccessibleStateType::DEFUNC: |
| type = ATK_STATE_DEFUNCT; break; |
| case accessibility::AccessibleStateType::MULTI_SELECTABLE: |
| type = ATK_STATE_MULTISELECTABLE; break; |
| default: |
| break; |
| } |
| |
| return type; |
| } |
| |
| static inline AtkRole registerRole( const gchar * name ) |
| { |
| AtkRole ret = atk_role_for_name( name ); |
| if( ATK_ROLE_INVALID == ret ) |
| ret = atk_role_register( name ); |
| |
| return ret; |
| } |
| |
| static AtkRole mapToAtkRole( sal_Int16 nRole ) |
| { |
| AtkRole role = ATK_ROLE_UNKNOWN; |
| |
| static AtkRole roleMap[] = { |
| ATK_ROLE_UNKNOWN, |
| ATK_ROLE_ALERT, |
| ATK_ROLE_COLUMN_HEADER, |
| ATK_ROLE_CANVAS, |
| ATK_ROLE_CHECK_BOX, |
| ATK_ROLE_CHECK_MENU_ITEM, |
| ATK_ROLE_COLOR_CHOOSER, |
| ATK_ROLE_COMBO_BOX, |
| ATK_ROLE_DATE_EDITOR, |
| ATK_ROLE_DESKTOP_ICON, |
| ATK_ROLE_DESKTOP_FRAME, // ? pane |
| ATK_ROLE_DIRECTORY_PANE, |
| ATK_ROLE_DIALOG, |
| ATK_ROLE_UNKNOWN, // DOCUMENT - registered below |
| ATK_ROLE_UNKNOWN, // EMBEDDED_OBJECT - registered below |
| ATK_ROLE_UNKNOWN, // END_NOTE - registered below |
| ATK_ROLE_FILE_CHOOSER, |
| ATK_ROLE_FILLER, |
| ATK_ROLE_FONT_CHOOSER, |
| ATK_ROLE_FOOTER, |
| ATK_ROLE_TEXT, // FOOTNOTE - registered below |
| ATK_ROLE_FRAME, |
| ATK_ROLE_GLASS_PANE, |
| ATK_ROLE_IMAGE, // GRAPHIC |
| ATK_ROLE_UNKNOWN, // GROUP_BOX - registered below |
| ATK_ROLE_HEADER, |
| ATK_ROLE_PARAGRAPH, // HEADING - registered below |
| ATK_ROLE_TEXT, // HYPER_LINK - registered below |
| ATK_ROLE_ICON, |
| ATK_ROLE_INTERNAL_FRAME, |
| ATK_ROLE_LABEL, |
| ATK_ROLE_LAYERED_PANE, |
| ATK_ROLE_LIST, |
| ATK_ROLE_LIST_ITEM, |
| ATK_ROLE_MENU, |
| ATK_ROLE_MENU_BAR, |
| ATK_ROLE_MENU_ITEM, |
| ATK_ROLE_OPTION_PANE, |
| ATK_ROLE_PAGE_TAB, |
| ATK_ROLE_PAGE_TAB_LIST, |
| ATK_ROLE_PANEL, |
| ATK_ROLE_PARAGRAPH, |
| ATK_ROLE_PASSWORD_TEXT, |
| ATK_ROLE_POPUP_MENU, |
| ATK_ROLE_PUSH_BUTTON, |
| ATK_ROLE_PROGRESS_BAR, |
| ATK_ROLE_RADIO_BUTTON, |
| ATK_ROLE_RADIO_MENU_ITEM, |
| ATK_ROLE_ROW_HEADER, |
| ATK_ROLE_ROOT_PANE, |
| ATK_ROLE_SCROLL_BAR, |
| ATK_ROLE_SCROLL_PANE, |
| ATK_ROLE_UNKNOWN, // SHAPE - registered below |
| ATK_ROLE_SEPARATOR, |
| ATK_ROLE_SLIDER, |
| ATK_ROLE_SPIN_BUTTON, // SPIN_BOX ? |
| ATK_ROLE_SPLIT_PANE, |
| ATK_ROLE_STATUSBAR, |
| ATK_ROLE_TABLE, |
| ATK_ROLE_TABLE_CELL, |
| ATK_ROLE_TEXT, |
| ATK_ROLE_INTERNAL_FRAME, // TEXT_FRAME - registered below |
| ATK_ROLE_TOGGLE_BUTTON, |
| ATK_ROLE_TOOL_BAR, |
| ATK_ROLE_TOOL_TIP, |
| ATK_ROLE_TREE, |
| ATK_ROLE_VIEWPORT, |
| ATK_ROLE_WINDOW, |
| ATK_ROLE_PUSH_BUTTON, // BUTTON_DROPDOWN |
| ATK_ROLE_PUSH_BUTTON, // BUTTON_MENU |
| ATK_ROLE_UNKNOWN, // CAPTION - registered below |
| ATK_ROLE_UNKNOWN, // CHART - registered below |
| ATK_ROLE_UNKNOWN, // EDIT_BAR - registered below |
| ATK_ROLE_UNKNOWN, // FORM - registered below |
| ATK_ROLE_UNKNOWN, // IMAGE_MAP - registered below |
| ATK_ROLE_UNKNOWN, // NOTE - registered below |
| ATK_ROLE_UNKNOWN, // PAGE - registered below |
| ATK_ROLE_RULER, |
| ATK_ROLE_UNKNOWN, // SECTION - registered below |
| ATK_ROLE_UNKNOWN, // TREE_ITEM - registered below |
| ATK_ROLE_TREE_TABLE, |
| ATK_ROLE_SCROLL_PANE, // COMMENT - mapped to atk_role_scroll_pane |
| ATK_ROLE_UNKNOWN // COMMENT_END - mapped to atk_role_unknown |
| }; |
| |
| static bool initialized = false; |
| |
| if( ! initialized ) |
| { |
| // re-use strings from ATK library |
| roleMap[accessibility::AccessibleRole::EDIT_BAR] = registerRole("edit bar"); |
| roleMap[accessibility::AccessibleRole::EMBEDDED_OBJECT] = registerRole("embedded component"); |
| roleMap[accessibility::AccessibleRole::CHART] = registerRole("chart"); |
| roleMap[accessibility::AccessibleRole::CAPTION] = registerRole("caption"); |
| roleMap[accessibility::AccessibleRole::DOCUMENT] = registerRole("document frame"); |
| roleMap[accessibility::AccessibleRole::HEADING] = registerRole("heading"); |
| roleMap[accessibility::AccessibleRole::PAGE] = registerRole("page"); |
| roleMap[accessibility::AccessibleRole::SECTION] = registerRole("section"); |
| roleMap[accessibility::AccessibleRole::FORM] = registerRole("form"); |
| |
| // these don't exist in ATK yet |
| roleMap[accessibility::AccessibleRole::END_NOTE] = registerRole("end note"); |
| roleMap[accessibility::AccessibleRole::FOOTNOTE] = registerRole("foot note"); |
| roleMap[accessibility::AccessibleRole::GROUP_BOX] = registerRole("group box"); |
| roleMap[accessibility::AccessibleRole::HYPER_LINK] = registerRole("hyper link"); |
| roleMap[accessibility::AccessibleRole::SHAPE] = registerRole("shape"); |
| roleMap[accessibility::AccessibleRole::TEXT_FRAME] = registerRole("text frame"); |
| roleMap[accessibility::AccessibleRole::IMAGE_MAP] = registerRole("image map"); |
| roleMap[accessibility::AccessibleRole::NOTE] = registerRole("note"); |
| roleMap[accessibility::AccessibleRole::TREE_ITEM] = registerRole("tree item"); |
| |
| initialized = true; |
| } |
| |
| static const sal_Int32 nMapSize = sizeof(roleMap)/sizeof(roleMap[0]); |
| if( 0 <= nRole && nMapSize > nRole ) |
| role = roleMap[nRole]; |
| |
| return role; |
| } |
| |
| |
| /*****************************************************************************/ |
| |
| extern "C" { |
| |
| /*****************************************************************************/ |
| |
| static G_CONST_RETURN gchar* |
| wrapper_get_name( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| |
| if( obj->mpContext ) |
| { |
| try { |
| rtl::OString aName = |
| rtl::OUStringToOString( |
| obj->mpContext->getAccessibleName(), |
| RTL_TEXTENCODING_UTF8); |
| |
| int nCmp = atk_obj->name ? rtl_str_compare( atk_obj->name, aName.getStr() ) : -1; |
| if( nCmp != 0 ) |
| { |
| if( atk_obj->name ) |
| g_free(atk_obj->name); |
| atk_obj->name = g_strdup(aName.getStr()); |
| } |
| } |
| catch(const uno::Exception& e) { |
| g_warning( "Exception in getAccessibleName()" ); |
| } |
| } |
| |
| return ATK_OBJECT_CLASS (parent_class)->get_name(atk_obj); |
| } |
| |
| /*****************************************************************************/ |
| |
| static G_CONST_RETURN gchar* |
| wrapper_get_description( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| |
| if( obj->mpContext ) |
| { |
| try { |
| rtl::OString aDescription = |
| rtl::OUStringToOString( |
| obj->mpContext->getAccessibleDescription(), |
| RTL_TEXTENCODING_UTF8); |
| |
| g_free(atk_obj->description); |
| atk_obj->description = g_strdup(aDescription.getStr()); |
| } |
| catch(const uno::Exception& e) { |
| g_warning( "Exception in getAccessibleDescription()" ); |
| } |
| } |
| |
| return ATK_OBJECT_CLASS (parent_class)->get_description(atk_obj); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| static gint |
| wrapper_get_n_children( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| gint n = 0; |
| |
| if( obj->mpContext ) |
| { |
| try { |
| n = obj->mpContext->getAccessibleChildCount(); |
| } |
| catch(const uno::Exception& e) { |
| OSL_ENSURE(0, "Exception in getAccessibleChildCount()" ); |
| } |
| } |
| |
| return n; |
| } |
| |
| /*****************************************************************************/ |
| |
| static AtkObject * |
| wrapper_ref_child( AtkObject *atk_obj, |
| gint i ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| AtkObject* child = NULL; |
| |
| // see comments above atk_object_wrapper_remove_child |
| if( -1 < i && obj->index_of_child_about_to_be_removed == i ) |
| { |
| g_object_ref( obj->child_about_to_be_removed ); |
| return obj->child_about_to_be_removed; |
| } |
| |
| if( obj->mpContext ) |
| { |
| try { |
| uno::Reference< accessibility::XAccessible > xAccessible = |
| obj->mpContext->getAccessibleChild( i ); |
| |
| child = atk_object_wrapper_ref( xAccessible ); |
| } |
| catch(const uno::Exception& e) { |
| OSL_ENSURE(0, "Exception in getAccessibleChild"); |
| } |
| } |
| |
| return child; |
| } |
| |
| /*****************************************************************************/ |
| |
| static gint |
| wrapper_get_index_in_parent( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| gint i = -1; |
| |
| if( obj->mpContext ) |
| { |
| try { |
| i = obj->mpContext->getAccessibleIndexInParent(); |
| |
| #ifdef ENABLE_TRACING |
| fprintf(stderr, "%p->getAccessibleIndexInParent() returned: %u\n", |
| obj->mpAccessible, i); |
| #endif |
| } |
| catch(const uno::Exception& e) { |
| g_warning( "Exception in getAccessibleIndexInParent()" ); |
| } |
| } |
| return i; |
| } |
| |
| /*****************************************************************************/ |
| |
| static AtkRelationSet * |
| wrapper_ref_relation_set( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| AtkRelationSet *pSet = atk_relation_set_new(); |
| |
| if( obj->mpContext ) |
| { |
| try { |
| uno::Reference< accessibility::XAccessibleRelationSet > xRelationSet( |
| obj->mpContext->getAccessibleRelationSet() |
| ); |
| |
| sal_Int32 nRelations = xRelationSet.is() ? xRelationSet->getRelationCount() : 0; |
| for( sal_Int32 n = 0; n < nRelations; n++ ) |
| { |
| accessibility::AccessibleRelation aRelation = xRelationSet->getRelation( n ); |
| sal_uInt32 nTargetCount = aRelation.TargetSet.getLength(); |
| AtkObject **pTargets = (AtkObject **) alloca( nTargetCount * sizeof(AtkObject *) ); |
| |
| for( sal_uInt32 i = 0; i < nTargetCount; i++ ) |
| { |
| uno::Reference< accessibility::XAccessible > xAccessible( |
| aRelation.TargetSet[i], uno::UNO_QUERY ); |
| pTargets[i] = atk_object_wrapper_ref( xAccessible ); |
| } |
| |
| AtkRelation *pRel = |
| atk_relation_new( |
| pTargets, nTargetCount, |
| mapRelationType( aRelation.RelationType ) |
| ); |
| atk_relation_set_add( pSet, pRel ); |
| g_object_unref( G_OBJECT( pRel ) ); |
| } |
| } |
| catch(const uno::Exception &e) { |
| g_object_unref( G_OBJECT( pSet ) ); |
| pSet = NULL; |
| } |
| } |
| |
| return pSet; |
| } |
| |
| /*****************************************************************************/ |
| |
| #if 0 |
| struct { |
| sal_Int16 value; |
| const sal_Char* name; |
| } aStateTypeTable[] = { |
| { accessibility::AccessibleStateType::INVALID, "INVALID" }, |
| { accessibility::AccessibleStateType::ACTIVE, "ACTIVE" }, |
| { accessibility::AccessibleStateType::ARMED, "ARMED" }, |
| { accessibility::AccessibleStateType::BUSY, "BUSY" }, |
| { accessibility::AccessibleStateType::CHECKED, "CHECKED" }, |
| { accessibility::AccessibleStateType::DEFUNC, "DEFUNC" }, |
| { accessibility::AccessibleStateType::EDITABLE, "EDITABLE" }, |
| { accessibility::AccessibleStateType::ENABLED, "ENABLED" }, |
| { accessibility::AccessibleStateType::EXPANDABLE, "EXPANDABLE" }, |
| { accessibility::AccessibleStateType::EXPANDED, "EXPANDED" }, |
| { accessibility::AccessibleStateType::FOCUSABLE, "FOCUSABLE" }, |
| { accessibility::AccessibleStateType::FOCUSED, "FOCUSED" }, |
| { accessibility::AccessibleStateType::HORIZONTAL, "HORIZONTAL" }, |
| { accessibility::AccessibleStateType::ICONIFIED, "ICONIFIED" }, |
| { accessibility::AccessibleStateType::INDETERMINATE, "INDETERMINATE" }, |
| { accessibility::AccessibleStateType::MANAGES_DESCENDANTS, "MANAGES_DESCENDANTS" }, |
| { accessibility::AccessibleStateType::MODAL, "MODAL" }, |
| { accessibility::AccessibleStateType::MULTI_LINE, "MULTI_LINE" }, |
| { accessibility::AccessibleStateType::MULTI_SELECTABLE, "MULTI_SELECTABLE" }, |
| { accessibility::AccessibleStateType::OPAQUE, "OPAQUE" }, |
| { accessibility::AccessibleStateType::PRESSED, "PRESSED" }, |
| { accessibility::AccessibleStateType::RESIZABLE, "RESIZABLE" }, |
| { accessibility::AccessibleStateType::SELECTABLE, "SELECTABLE" }, |
| { accessibility::AccessibleStateType::SELECTED, "SELECTED" }, |
| { accessibility::AccessibleStateType::SENSITIVE, "SENSITIVE" }, |
| { accessibility::AccessibleStateType::SHOWING, "SHOWING" }, |
| { accessibility::AccessibleStateType::SINGLE_LINE, "SINGLE_LINE" }, |
| { accessibility::AccessibleStateType::STALE, "STALE" }, |
| { accessibility::AccessibleStateType::TRANSIENT, "TRANSIENT" }, |
| { accessibility::AccessibleStateType::VERTICAL, "VERTICAL" }, |
| { accessibility::AccessibleStateType::VISIBLE, "VISIBLE" } |
| }; |
| |
| static void printStates(const uno::Sequence<sal_Int16>& rStates) |
| { |
| sal_Int32 n = rStates.getLength(); |
| size_t nTypes = sizeof(aStateTypeTable)/sizeof(aStateTypeTable[0]); |
| for (sal_Int32 i = 0; i < n; ++i) |
| { |
| for (size_t j = 0; j < nTypes; ++j) |
| { |
| if (aStateTypeTable[j].value == rStates[i]) |
| printf("%s ", aStateTypeTable[j].name); |
| } |
| } |
| printf("\n"); |
| } |
| #endif |
| |
| static AtkStateSet * |
| wrapper_ref_state_set( AtkObject *atk_obj ) |
| { |
| AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj); |
| AtkStateSet *pSet = atk_state_set_new(); |
| |
| if( obj->mpContext ) |
| { |
| try { |
| uno::Reference< accessibility::XAccessibleStateSet > xStateSet( |
| obj->mpContext->getAccessibleStateSet()); |
| |
| if( xStateSet.is() ) |
| { |
| uno::Sequence< sal_Int16 > aStates = xStateSet->getStates(); |
| |
| for( sal_Int32 n = 0; n < aStates.getLength(); n++ ) |
| atk_state_set_add_state( pSet, mapAtkState( aStates[n] ) ); |
| |
| // We need to emulate FOCUS state for menus, menu-items etc. |
| if( atk_obj == atk_get_focus_object() ) |
| atk_state_set_add_state( pSet, ATK_STATE_FOCUSED ); |
| /* FIXME - should we do this ? |
| else |
| atk_state_set_remove_state( pSet, ATK_STATE_FOCUSED ); |
| */ |
| } |
| } |
| |
| catch(const uno::Exception &e) { |
| g_warning( "Exception in wrapper_ref_state_set" ); |
| atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT ); |
| } |
| } |
| else |
| atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT ); |
| |
| return pSet; |
| } |
| |
| /*****************************************************************************/ |
| |
| |
| static void |
| atk_object_wrapper_finalize (GObject *obj) |
| { |
| AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER (obj); |
| |
| if( pWrap->mpAccessible ) |
| { |
| ooo_wrapper_registry_remove( pWrap->mpAccessible ); |
| pWrap->mpAccessible->release(); |
| pWrap->mpAccessible = NULL; |
| } |
| |
| atk_object_wrapper_dispose( pWrap ); |
| |
| parent_class->finalize( obj ); |
| } |
| |
| static void |
| atk_object_wrapper_class_init (AtkObjectWrapperClass *klass) |
| { |
| GObjectClass *gobject_class = G_OBJECT_CLASS( klass ); |
| AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass ); |
| |
| parent_class = (GObjectClass *) g_type_class_peek_parent (klass); |
| |
| // GObject methods |
| gobject_class->finalize = atk_object_wrapper_finalize; |
| |
| // AtkObject methods |
| atk_class->get_name = wrapper_get_name; |
| atk_class->get_description = wrapper_get_description; |
| atk_class->get_n_children = wrapper_get_n_children; |
| atk_class->ref_child = wrapper_ref_child; |
| atk_class->get_index_in_parent = wrapper_get_index_in_parent; |
| atk_class->ref_relation_set = wrapper_ref_relation_set; |
| atk_class->ref_state_set = wrapper_ref_state_set; |
| } |
| |
| static void |
| atk_object_wrapper_init (AtkObjectWrapper *wrapper, |
| AtkObjectWrapperClass) |
| { |
| wrapper->mpAction = NULL; |
| wrapper->mpComponent = NULL; |
| wrapper->mpEditableText = NULL; |
| wrapper->mpHypertext = NULL; |
| wrapper->mpImage = NULL; |
| wrapper->mpSelection = NULL; |
| wrapper->mpTable = NULL; |
| wrapper->mpText = NULL; |
| wrapper->mpValue = NULL; |
| } |
| |
| } // extern "C" |
| |
| GType |
| atk_object_wrapper_get_type (void) |
| { |
| static GType type = 0; |
| |
| if (!type) |
| { |
| static const GTypeInfo typeInfo = |
| { |
| sizeof (AtkObjectWrapperClass), |
| (GBaseInitFunc) NULL, |
| (GBaseFinalizeFunc) NULL, |
| (GClassInitFunc) atk_object_wrapper_class_init, |
| (GClassFinalizeFunc) NULL, |
| NULL, |
| sizeof (AtkObjectWrapper), |
| 0, |
| (GInstanceInitFunc) atk_object_wrapper_init, |
| NULL |
| } ; |
| type = g_type_register_static (ATK_TYPE_OBJECT, |
| "OOoAtkObj", |
| &typeInfo, (GTypeFlags)0) ; |
| } |
| return type; |
| } |
| |
| static bool |
| isOfType( uno::XInterface *pInterface, const uno::Type & rType ) |
| { |
| g_return_val_if_fail( pInterface != NULL, false ); |
| |
| bool bIs = false; |
| try { |
| uno::Any aRet = pInterface->queryInterface( rType ); |
| |
| bIs = ( ( typelib_TypeClass_INTERFACE == aRet.pType->eTypeClass ) && |
| ( aRet.pReserved != NULL ) ); |
| } catch( const uno::Exception &e) { } |
| |
| return bIs; |
| } |
| |
| extern "C" { |
| typedef GType (* GetGIfaceType ) (void); |
| } |
| const struct { |
| const char *name; |
| GInterfaceInitFunc aInit; |
| GetGIfaceType aGetGIfaceType; |
| const uno::Type & (*aGetUnoType) (void *); |
| } aTypeTable[] = { |
| // re-location heaven: |
| { |
| "Comp", (GInterfaceInitFunc) componentIfaceInit, |
| atk_component_get_type, |
| accessibility::XAccessibleComponent::static_type |
| }, |
| { |
| "Act", (GInterfaceInitFunc) actionIfaceInit, |
| atk_action_get_type, |
| accessibility::XAccessibleAction::static_type |
| }, |
| { |
| "Txt", (GInterfaceInitFunc) textIfaceInit, |
| atk_text_get_type, |
| accessibility::XAccessibleText::static_type |
| }, |
| { |
| "Val", (GInterfaceInitFunc) valueIfaceInit, |
| atk_value_get_type, |
| accessibility::XAccessibleValue::static_type |
| }, |
| { |
| "Tab", (GInterfaceInitFunc) tableIfaceInit, |
| atk_table_get_type, |
| accessibility::XAccessibleTable::static_type |
| }, |
| { |
| "Edt", (GInterfaceInitFunc) editableTextIfaceInit, |
| atk_editable_text_get_type, |
| accessibility::XAccessibleEditableText::static_type |
| }, |
| { |
| "Img", (GInterfaceInitFunc) imageIfaceInit, |
| atk_image_get_type, |
| accessibility::XAccessibleImage::static_type |
| }, |
| { |
| "Hyp", (GInterfaceInitFunc) hypertextIfaceInit, |
| atk_hypertext_get_type, |
| accessibility::XAccessibleHypertext::static_type |
| }, |
| { |
| "Sel", (GInterfaceInitFunc) selectionIfaceInit, |
| atk_selection_get_type, |
| accessibility::XAccessibleSelection::static_type |
| } |
| // AtkDocument is a nastily broken interface (so far) |
| // we could impl. get_document_type perhaps though. |
| }; |
| |
| const int aTypeTableSize = G_N_ELEMENTS( aTypeTable ); |
| |
| static GType |
| ensureTypeFor( uno::XInterface *pAccessible ) |
| { |
| int i; |
| int bTypes[ aTypeTableSize ] = { 0, }; |
| rtl::OString aTypeName( "OOoAtkObj" ); |
| |
| for( i = 0; i < aTypeTableSize; i++ ) |
| { |
| if( isOfType( pAccessible, aTypeTable[i].aGetUnoType(0) ) ) |
| { |
| aTypeName += aTypeTable[i].name; |
| bTypes[i] = TRUE; |
| } |
| // g_message( "Accessible %p has type '%s' (%d)", |
| // pAccessible, aTypeTable[i].name, bTypes[i] ); |
| } |
| |
| GType nType = g_type_from_name( aTypeName ); |
| if( nType == G_TYPE_INVALID ) |
| { |
| GTypeInfo aTypeInfo = { |
| sizeof( AtkObjectWrapperClass ), |
| NULL, NULL, NULL, NULL, NULL, |
| sizeof( AtkObjectWrapper ), |
| 0, NULL, NULL |
| } ; |
| nType = g_type_register_static( ATK_TYPE_OBJECT_WRAPPER, |
| aTypeName, &aTypeInfo, (GTypeFlags)0 ) ; |
| |
| for( int j = 0; j < aTypeTableSize; j++ ) |
| if( bTypes[j] ) |
| { |
| GInterfaceInfo aIfaceInfo = { NULL, NULL, NULL }; |
| aIfaceInfo.interface_init = aTypeTable[j].aInit; |
| g_type_add_interface_static (nType, aTypeTable[j].aGetGIfaceType(), |
| &aIfaceInfo); |
| } |
| } |
| return nType; |
| } |
| |
| AtkObject * |
| atk_object_wrapper_ref( const uno::Reference< accessibility::XAccessible > &rxAccessible, bool create ) |
| { |
| g_return_val_if_fail( rxAccessible.get() != NULL, NULL ); |
| |
| AtkObject *obj = ooo_wrapper_registry_get(rxAccessible); |
| if( obj ) |
| { |
| g_object_ref( obj ); |
| return obj; |
| } |
| |
| if( create ) |
| return atk_object_wrapper_new( rxAccessible ); |
| |
| return NULL; |
| } |
| |
| |
| AtkObject * |
| atk_object_wrapper_new( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible, |
| AtkObject* parent ) |
| { |
| g_return_val_if_fail( rxAccessible.get() != NULL, NULL ); |
| |
| AtkObjectWrapper *pWrap = NULL; |
| |
| try { |
| uno::Reference< accessibility::XAccessibleContext > xContext(rxAccessible->getAccessibleContext()); |
| |
| g_return_val_if_fail( xContext.get() != NULL, NULL ); |
| |
| GType nType = ensureTypeFor( xContext.get() ); |
| gpointer obj = g_object_new( nType, NULL); |
| |
| pWrap = ATK_OBJECT_WRAPPER( obj ); |
| pWrap->mpAccessible = rxAccessible.get(); |
| rxAccessible->acquire(); |
| |
| pWrap->index_of_child_about_to_be_removed = -1; |
| pWrap->child_about_to_be_removed = NULL; |
| |
| xContext->acquire(); |
| pWrap->mpContext = xContext.get(); |
| |
| AtkObject* atk_obj = ATK_OBJECT(pWrap); |
| atk_obj->role = mapToAtkRole( xContext->getAccessibleRole() ); |
| atk_obj->accessible_parent = parent; |
| |
| ooo_wrapper_registry_add( rxAccessible, atk_obj ); |
| |
| if( parent ) |
| g_object_ref( atk_obj->accessible_parent ); |
| else |
| { |
| /* gail_focus_tracker remembers the focused object at the first |
| * parent in the hierachy that is a Gtk+ widget, but at the time the |
| * event gets processed (at idle), it may be too late to create the |
| * hierachy, so doing it now .. |
| */ |
| uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() ); |
| |
| /* The top-level objects should never be of this class */ |
| OSL_ASSERT( xParent.is() ); |
| |
| if( xParent.is() ) |
| atk_obj->accessible_parent = atk_object_wrapper_ref( xParent ); |
| } |
| |
| // Attach a listener to the UNO object if it's not TRANSIENT |
| uno::Reference< accessibility::XAccessibleStateSet > xStateSet( xContext->getAccessibleStateSet() ); |
| if( xStateSet.is() && ! xStateSet->contains( accessibility::AccessibleStateType::TRANSIENT ) ) |
| { |
| uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY); |
| if( xBroadcaster.is() ) |
| xBroadcaster->addEventListener( static_cast< accessibility::XAccessibleEventListener * > ( new AtkListener(pWrap) ) ); |
| else |
| OSL_ASSERT( false ); |
| } |
| |
| return ATK_OBJECT( pWrap ); |
| } |
| catch (const uno::Exception &e) |
| { |
| if( pWrap ) |
| g_object_unref( pWrap ); |
| |
| return NULL; |
| } |
| } |
| |
| |
| /*****************************************************************************/ |
| |
| void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index) |
| { |
| AtkObject *atk_obj = ATK_OBJECT( wrapper ); |
| |
| atk_object_set_parent( child, atk_obj ); |
| g_signal_emit_by_name( atk_obj, "children_changed::add", index, child, NULL ); |
| } |
| |
| /*****************************************************************************/ |
| |
| void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index) |
| { |
| /* |
| * the atk-bridge GTK+ module get's back to the event source to ref the child just |
| * vanishing, so we keep this reference because the semantic on OOo side is different. |
| */ |
| wrapper->child_about_to_be_removed = child; |
| wrapper->index_of_child_about_to_be_removed = index; |
| |
| g_signal_emit_by_name( ATK_OBJECT( wrapper ), "children_changed::remove", index, child, NULL ); |
| |
| wrapper->index_of_child_about_to_be_removed = -1; |
| wrapper->child_about_to_be_removed = NULL; |
| } |
| |
| /*****************************************************************************/ |
| |
| #define RELEASE(i) if( i ) { i->release(); i = NULL; } |
| |
| void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper) |
| { |
| RELEASE( wrapper->mpContext ) |
| RELEASE( wrapper->mpAction ) |
| RELEASE( wrapper->mpComponent ) |
| RELEASE( wrapper->mpEditableText ) |
| RELEASE( wrapper->mpHypertext ) |
| RELEASE( wrapper->mpImage ) |
| RELEASE( wrapper->mpSelection ) |
| RELEASE( wrapper->mpMultiLineText ) |
| RELEASE( wrapper->mpTable ) |
| RELEASE( wrapper->mpText ) |
| RELEASE( wrapper->mpTextMarkup ) |
| RELEASE( wrapper->mpTextAttributes ) |
| RELEASE( wrapper->mpValue ) |
| } |