diff options
Diffstat (limited to 'src/gui/accessible/qaccessible_mac.mm')
-rw-r--r-- | src/gui/accessible/qaccessible_mac.mm | 2469 |
1 files changed, 0 insertions, 2469 deletions
diff --git a/src/gui/accessible/qaccessible_mac.mm b/src/gui/accessible/qaccessible_mac.mm deleted file mode 100644 index 432b536577..0000000000 --- a/src/gui/accessible/qaccessible_mac.mm +++ /dev/null @@ -1,2469 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qaccessible.h" - -#ifndef QT_NO_ACCESSIBILITY -#include "qaccessible_mac_p.h" -#include "qhash.h" -#include "qset.h" -#include "qpointer.h" -#include "qapplication.h" -#include "qmainwindow.h" -#include "qtextdocument.h" -#include "qdebug.h" -#include "qabstractslider.h" -#include "qsplitter.h" -#include "qtabwidget.h" -#include "qlistview.h" -#include "qtableview.h" -#include "qdockwidget.h" - -#include <private/qt_mac_p.h> -#include <private/qwidget_p.h> -#include <CoreFoundation/CoreFoundation.h> - -QT_BEGIN_NAMESPACE - -/* - Set up platform defines. There is a one-to-one correspondence between the - Carbon and Cocoa roles and attributes, but the prefix and type changes. -*/ -#ifdef QT_MAC_USE_COCOA -typedef NSString * const QAXRoleType; -#define QAXApplicationRole NSAccessibilityApplicationRole -#define QAXButtonRole NSAccessibilityButtonRole -#define QAXCancelAction NSAccessibilityCancelAction -#define QAXCheckBoxRole NSAccessibilityCheckBoxRole -#define QAXChildrenAttribute NSAccessibilityChildrenAttribute -#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute -#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute -#define QAXColumnRole NSAccessibilityColumnRole -#define QAXConfirmAction NSAccessibilityConfirmAction -#define QAXContentsAttribute NSAccessibilityContentsAttribute -#define QAXDecrementAction NSAccessibilityDecrementAction -#define QAXDecrementArrowSubrole NSAccessibilityDecrementArrowSubrole -#define QAXDecrementPageSubrole NSAccessibilityDecrementPageSubrole -#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute -#define QAXEnabledAttribute NSAccessibilityEnabledAttribute -#define QAXExpandedAttribute NSAccessibilityExpandedAttribute -#define QAXFocusedAttribute NSAccessibilityFocusedAttribute -#define QAXFocusedUIElementChangedNotification NSAccessibilityFocusedUIElementChangedNotification -#define QAXFocusedWindowChangedNotification NSAccessibilityFocusedWindowChangedNotification -#define QAXGroupRole NSAccessibilityGroupRole -#define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute -#define QAXGrowAreaRole NSAccessibilityGrowAreaRole -#define QAXHelpAttribute NSAccessibilityHelpAttribute -#define QAXHorizontalOrientationValue NSAccessibilityHorizontalOrientationValue -#define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute -#define QAXIncrementAction NSAccessibilityIncrementAction -#define QAXIncrementArrowSubrole NSAccessibilityIncrementArrowSubrole -#define QAXIncrementPageSubrole NSAccessibilityIncrementPageSubrole -#define QAXIncrementorRole NSAccessibilityIncrementorRole -#define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute -#define QAXListRole NSAccessibilityListRole -#define QAXMainAttribute NSAccessibilityMainAttribute -#define QAXMaxValueAttribute NSAccessibilityMaxValueAttribute -#define QAXMenuBarRole NSAccessibilityMenuBarRole -#define QAXMenuButtonRole NSAccessibilityMenuButtonRole -#define QAXMenuClosedNotification NSAccessibilityMenuClosedNotification -#define QAXMenuItemRole NSAccessibilityMenuItemRole -#define QAXMenuOpenedNotification NSAccessibilityMenuOpenedNotification -#define QAXMenuRole NSAccessibilityMenuRole -#define QAXMinValueAttribute NSAccessibilityMinValueAttribute -#define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute -#define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute -#define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute -#define QAXOrientationAttribute NSAccessibilityOrientationAttribute -#define QAXParentAttribute NSAccessibilityParentAttribute -#define QAXPickAction NSAccessibilityPickAction -#define QAXPopUpButtonRole NSAccessibilityPopUpButtonRole -#define QAXPositionAttribute NSAccessibilityPositionAttribute -#define QAXPressAction NSAccessibilityPressAction -#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute -#define QAXProgressIndicatorRole NSAccessibilityProgressIndicatorRole -#define QAXRadioButtonRole NSAccessibilityRadioButtonRole -#define QAXRoleAttribute NSAccessibilityRoleAttribute -#define QAXRoleDescriptionAttribute NSAccessibilityRoleDescriptionAttribute -#define QAXRowRole NSAccessibilityRowRole -#define QAXRowsAttribute NSAccessibilityRowsAttribute -#define QAXScrollAreaRole NSAccessibilityScrollAreaRole -#define QAXScrollBarRole NSAccessibilityScrollBarRole -#define QAXSelectedAttribute NSAccessibilitySelectedAttribute -#define QAXSelectedChildrenAttribute NSAccessibilitySelectedChildrenAttribute -#define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute -#define QAXSizeAttribute NSAccessibilitySizeAttribute -#define QAXSliderRole NSAccessibilitySliderRole -#define QAXSplitGroupRole NSAccessibilitySplitGroupRole -#define QAXSplitterRole NSAccessibilitySplitterRole -#define QAXSplittersAttribute NSAccessibilitySplittersAttribute -#define QAXStaticTextRole NSAccessibilityStaticTextRole -#define QAXSubroleAttribute NSAccessibilitySubroleAttribute -#define QAXSubroleAttribute NSAccessibilitySubroleAttribute -#define QAXTabGroupRole NSAccessibilityTabGroupRole -#define QAXTableRole NSAccessibilityTableRole -#define QAXTabsAttribute NSAccessibilityTabsAttribute -#define QAXTextFieldRole NSAccessibilityTextFieldRole -#define QAXTitleAttribute NSAccessibilityTitleAttribute -#define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute -#define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute -#define QAXToolbarRole NSAccessibilityToolbarRole -#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute -#define QAXUnknownRole NSAccessibilityUnknownRole -#define QAXValueAttribute NSAccessibilityValueAttribute -#define QAXValueChangedNotification NSAccessibilityValueChangedNotification -#define QAXValueIndicatorRole NSAccessibilityValueIndicatorRole -#define QAXVerticalOrientationValue NSAccessibilityVerticalOrientationValue -#define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute -#define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute -#define QAXWindowAttribute NSAccessibilityWindowAttribute -#define QAXWindowCreatedNotification NSAccessibilityWindowCreatedNotification -#define QAXWindowMovedNotification NSAccessibilityWindowMovedNotification -#define QAXWindowRole NSAccessibilityWindowRole -#define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute -#else -typedef CFStringRef const QAXRoleType; -#define QAXApplicationRole kAXApplicationRole -#define QAXButtonRole kAXButtonRole -#define QAXCancelAction kAXCancelAction -#define QAXCheckBoxRole kAXCheckBoxRole -#define QAXChildrenAttribute kAXChildrenAttribute -#define QAXCloseButtonAttribute kAXCloseButtonAttribute -#define QAXColumnRole kAXColumnRole -#define QAXConfirmAction kAXConfirmAction -#define QAXContentsAttribute kAXContentsAttribute -#define QAXDecrementAction kAXDecrementAction -#define QAXDecrementArrowSubrole kAXDecrementArrowSubrole -#define QAXDecrementPageSubrole kAXDecrementPageSubrole -#define QAXDescriptionAttribute kAXDescriptionAttribute -#define QAXEnabledAttribute kAXEnabledAttribute -#define QAXExpandedAttribute kAXExpandedAttribute -#define QAXFocusedAttribute kAXFocusedAttribute -#define QAXFocusedUIElementChangedNotification kAXFocusedUIElementChangedNotification -#define QAXFocusedWindowChangedNotification kAXFocusedWindowChangedNotification -#define QAXGroupRole kAXGroupRole -#define QAXGrowAreaAttribute kAXGrowAreaAttribute -#define QAXGrowAreaRole kAXGrowAreaRole -#define QAXHelpAttribute kAXHelpAttribute -#define QAXHorizontalOrientationValue kAXHorizontalOrientationValue -#define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute -#define QAXIncrementAction kAXIncrementAction -#define QAXIncrementArrowSubrole kAXIncrementArrowSubrole -#define QAXIncrementPageSubrole kAXIncrementPageSubrole -#define QAXIncrementorRole kAXIncrementorRole -#define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute -#define QAXListRole kAXListRole -#define QAXMainAttribute kAXMainAttribute -#define QAXMaxValueAttribute kAXMaxValueAttribute -#define QAXMenuBarRole kAXMenuBarRole -#define QAXMenuButtonRole kAXMenuButtonRole -#define QAXMenuClosedNotification kAXMenuClosedNotification -#define QAXMenuItemRole kAXMenuItemRole -#define QAXMenuOpenedNotification kAXMenuOpenedNotification -#define QAXMenuRole kAXMenuRole -#define QAXMinValueAttribute kAXMinValueAttribute -#define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute -#define QAXMinimizedAttribute kAXMinimizedAttribute -#define QAXNextContentsAttribute kAXNextContentsAttribute -#define QAXOrientationAttribute kAXOrientationAttribute -#define QAXParentAttribute kAXParentAttribute -#define QAXPickAction kAXPickAction -#define QAXPopUpButtonRole kAXPopUpButtonRole -#define QAXPositionAttribute kAXPositionAttribute -#define QAXPressAction kAXPressAction -#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute -#define QAXProgressIndicatorRole kAXProgressIndicatorRole -#define QAXRadioButtonRole kAXRadioButtonRole -#define QAXRoleAttribute kAXRoleAttribute -#define QAXRoleDescriptionAttribute kAXRoleDescriptionAttribute -#define QAXRowRole kAXRowRole -#define QAXRowsAttribute kAXRowsAttribute -#define QAXScrollAreaRole kAXScrollAreaRole -#define QAXScrollBarRole kAXScrollBarRole -#define QAXSelectedAttribute kAXSelectedAttribute -#define QAXSelectedChildrenAttribute kAXSelectedChildrenAttribute -#define QAXSelectedRowsAttribute kAXSelectedRowsAttribute -#define QAXSizeAttribute kAXSizeAttribute -#define QAXSliderRole kAXSliderRole -#define QAXSplitGroupRole kAXSplitGroupRole -#define QAXSplitterRole kAXSplitterRole -#define QAXSplittersAttribute kAXSplittersAttribute -#define QAXStaticTextRole kAXStaticTextRole -#define QAXSubroleAttribute kAXSubroleAttribute -#define QAXTabGroupRole kAXTabGroupRole -#define QAXTableRole kAXTableRole -#define QAXTabsAttribute kAXTabsAttribute -#define QAXTextFieldRole kAXTextFieldRole -#define QAXTitleAttribute kAXTitleAttribute -#define QAXTitleUIElementAttribute kAXTitleUIElementAttribute -#define QAXToolbarButtonAttribute kAXToolbarButtonAttribute -#define QAXToolbarRole kAXToolbarRole -#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute -#define QAXUnknownRole kAXUnknownRole -#define QAXValueAttribute kAXValueAttribute -#define QAXValueChangedNotification kAXValueChangedNotification -#define QAXValueIndicatorRole kAXValueIndicatorRole -#define QAXVerticalOrientationValue kAXVerticalOrientationValue -#define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute -#define QAXVisibleRowsAttribute kAXVisibleRowsAttribute -#define QAXWindowAttribute kAXWindowAttribute -#define QAXWindowCreatedNotification kAXWindowCreatedNotification -#define QAXWindowMovedNotification kAXWindowMovedNotification -#define QAXWindowRole kAXWindowRole -#define QAXZoomButtonAttribute kAXZoomButtonAttribute -#endif - - -/***************************************************************************** - Externals - *****************************************************************************/ -extern bool qt_mac_is_macsheet(const QWidget *w); //qwidget_mac.cpp -extern bool qt_mac_is_macdrawer(const QWidget *w); //qwidget_mac.cpp - -/***************************************************************************** - QAccessible Bindings - *****************************************************************************/ -//hardcoded bindings between control info and (known) QWidgets -struct QAccessibleTextBinding { - int qt; - QAXRoleType mac; - bool settable; -} text_bindings[][10] = { - { { QAccessible::MenuItem, QAXMenuItemRole, false }, - { -1, 0, false } - }, - { { QAccessible::MenuBar, QAXMenuBarRole, false }, - { -1, 0, false } - }, - { { QAccessible::ScrollBar, QAXScrollBarRole, false }, - { -1, 0, false } - }, - { { QAccessible::Grip, QAXGrowAreaRole, false }, - { -1, 0, false } - }, - { { QAccessible::Window, QAXWindowRole, false }, - { -1, 0, false } - }, - { { QAccessible::Dialog, QAXWindowRole, false }, - { -1, 0, false } - }, - { { QAccessible::AlertMessage, QAXWindowRole, false }, - { -1, 0, false } - }, - { { QAccessible::ToolTip, QAXWindowRole, false }, - { -1, 0, false } - }, - { { QAccessible::HelpBalloon, QAXWindowRole, false }, - { -1, 0, false } - }, - { { QAccessible::PopupMenu, QAXMenuRole, false }, - { -1, 0, false } - }, - { { QAccessible::Application, QAXApplicationRole, false }, - { -1, 0, false } - }, - { { QAccessible::Pane, QAXGroupRole, false }, - { -1, 0, false } - }, - { { QAccessible::Grouping, QAXGroupRole, false }, - { -1, 0, false } - }, - { { QAccessible::Separator, QAXSplitterRole, false }, - { -1, 0, false } - }, - { { QAccessible::ToolBar, QAXToolbarRole, false }, - { -1, 0, false } - }, - { { QAccessible::PageTab, QAXRadioButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::ButtonMenu, QAXMenuButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::ButtonDropDown, QAXPopUpButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::SpinBox, QAXIncrementorRole, false }, - { -1, 0, false } - }, - { { QAccessible::Slider, QAXSliderRole, false }, - { -1, 0, false } - }, - { { QAccessible::ProgressBar, QAXProgressIndicatorRole, false }, - { -1, 0, false } - }, - { { QAccessible::ComboBox, QAXPopUpButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::RadioButton, QAXRadioButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::CheckBox, QAXCheckBoxRole, false }, - { -1, 0, false } - }, - { { QAccessible::StaticText, QAXStaticTextRole, false }, - { QAccessible::Name, QAXValueAttribute, false }, - { -1, 0, false } - }, - { { QAccessible::Table, QAXTableRole, false }, - { -1, 0, false } - }, - { { QAccessible::StatusBar, QAXStaticTextRole, false }, - { -1, 0, false } - }, - { { QAccessible::Column, QAXColumnRole, false }, - { -1, 0, false } - }, - { { QAccessible::ColumnHeader, QAXColumnRole, false }, - { -1, 0, false } - }, - { { QAccessible::Row, QAXRowRole, false }, - { -1, 0, false } - }, - { { QAccessible::RowHeader, QAXRowRole, false }, - { -1, 0, false } - }, - { { QAccessible::Cell, QAXTextFieldRole, false }, - { -1, 0, false } - }, - { { QAccessible::PushButton, QAXButtonRole, false }, - { -1, 0, false } - }, - { { QAccessible::EditableText, QAXTextFieldRole, true }, - { -1, 0, false } - }, - { { QAccessible::Link, QAXTextFieldRole, false }, - { -1, 0, false } - }, - { { QAccessible::Indicator, QAXValueIndicatorRole, false }, - { -1, 0, false } - }, - { { QAccessible::Splitter, QAXSplitGroupRole, false }, - { -1, 0, false } - }, - { { QAccessible::List, QAXListRole, false }, - { -1, 0, false } - }, - { { QAccessible::ListItem, QAXStaticTextRole, false }, - { -1, 0, false } - }, - { { QAccessible::Cell, QAXStaticTextRole, false }, - { -1, 0, false } - }, - { { -1, 0, false } } -}; - -class QAInterface; -static CFStringRef macRole(const QAInterface &interface); - -QDebug operator<<(QDebug debug, const QAInterface &interface) -{ - if (interface.isValid() == false) - debug << "invalid interface"; - else - debug << interface.object() << "id" << interface.id() << "role" << hex << interface.role(); - return debug; -} - -// The root of the Qt accessible hiearchy. -static QObject *rootObject = 0; - - -bool QAInterface::operator==(const QAInterface &other) const -{ - if (isValid() == false || other.isValid() == false) - return (isValid() && other.isValid()); - - // walk up the parent chain, comparing child indexes, until we reach - // an interface that has a QObject. - QAInterface currentThis = *this; - QAInterface currentOther = other; - - while (currentThis.object() == 0) { - if (currentOther.object() != 0) - return false; - - // fail if the child indexes in the two hirearchies don't match. - if (currentThis.parent().indexOfChild(currentThis) != - currentOther.parent().indexOfChild(currentOther)) - return false; - - currentThis = currentThis.parent(); - currentOther = currentOther.parent(); - } - - return (currentThis.object() == currentOther.object() && currentThis.id() == currentOther.id()); -} - -bool QAInterface::operator!=(const QAInterface &other) const -{ - return !operator==(other); -} - -uint qHash(const QAInterface &item) -{ - if (item.isValid()) - return qHash(item.object()) + qHash(item.id()); - else - return qHash(item.cachedObject()) + qHash(item.id()); -} - -QAInterface QAInterface::navigate(RelationFlag relation, int entry) const -{ - if (!checkValid()) - return QAInterface(); - - // On a QAccessibleInterface that handles its own children we can short-circut - // the navigation if this QAInterface refers to one of the children: - if (child != 0) { - // The Ancestor interface will always be the same QAccessibleInterface with - // a child value of 0. - if (relation == QAccessible::Ancestor) - return QAInterface(*this, 0); - - // The child hiearchy is only one level deep, so navigating to a child - // of a child is not possible. - if (relation == QAccessible::Child) { - return QAInterface(); - } - } - QAccessibleInterface *child_iface = 0; - - const int status = base.interface->navigate(relation, entry, &child_iface); - - if (status == -1) - return QAInterface(); // not found; - - // Check if target is a child of this interface. - if (!child_iface) { - return QAInterface(*this, status); - } else { - // Target is child_iface or a child of that (status decides). - return QAInterface(child_iface, status); - } -} - -QAElement::QAElement() -:elementRef(0) -{} - -QAElement::QAElement(AXUIElementRef elementRef) -:elementRef(elementRef) -{ - if (elementRef != 0) { - CFRetain(elementRef); - CFRetain(object()); - } -} - -QAElement::QAElement(const QAElement &element) -:elementRef(element.elementRef) -{ - if (elementRef != 0) { - CFRetain(elementRef); - CFRetain(object()); - } -} - -QAElement::QAElement(HIObjectRef object, int child) -{ -#ifndef QT_MAC_USE_COCOA - if (object == 0) { - elementRef = 0; // Create invalid QAElement. - } else { - elementRef = AXUIElementCreateWithHIObjectAndIdentifier(object, child); - CFRetain(object); - } -#else - Q_UNUSED(object); - Q_UNUSED(child); -#endif -} - -QAElement::~QAElement() -{ - if (elementRef != 0) { - CFRelease(object()); - CFRelease(elementRef); - } -} - -void QAElement::operator=(const QAElement &other) -{ - if (*this == other) - return; - - if (elementRef != 0) { - CFRelease(object()); - CFRelease(elementRef); - } - - elementRef = other.elementRef; - - if (elementRef != 0) { - CFRetain(elementRef); - CFRetain(object()); - } -} - -bool QAElement::operator==(const QAElement &other) const -{ - if (elementRef == 0 || other.elementRef == 0) - return (elementRef == other.elementRef); - - return CFEqual(elementRef, other.elementRef); -} - -uint qHash(QAElement element) -{ - return qHash(element.object()) + qHash(element.id()); -} - -#ifndef QT_MAC_USE_COCOA -static QInterfaceFactory *createFactory(const QAInterface &interface); -#endif -Q_GLOBAL_STATIC(QAccessibleHierarchyManager, accessibleHierarchyManager); - -/* - Reomves all accessibility info accosiated with the sender object. -*/ -void QAccessibleHierarchyManager::objectDestroyed(QObject *object) -{ - HIObjectRef hiObject = qobjectHiobjectHash.value(object); - delete qobjectElementHash.value(object); - qobjectElementHash.remove(object); - hiobjectInterfaceHash.remove(hiObject); -} - -/* - Removes all stored items. -*/ -void QAccessibleHierarchyManager::reset() -{ - qDeleteAll(qobjectElementHash); - qobjectElementHash.clear(); - hiobjectInterfaceHash.clear(); - qobjectHiobjectHash.clear(); -} - -QAccessibleHierarchyManager *QAccessibleHierarchyManager::instance() -{ - return accessibleHierarchyManager(); -} - -#ifndef QT_MAC_USE_COCOA -static bool isItemView(const QAInterface &interface) -{ - QObject *object = interface.object(); - return (interface.role() == QAccessible::List || interface.role() == QAccessible::Table - || (object && qobject_cast<QAbstractItemView *>(interface.object())) - || (object && object->objectName() == QLatin1String("qt_scrollarea_viewport") - && qobject_cast<QAbstractItemView *>(object->parent()))); -} -#endif - -static bool isTabWidget(const QAInterface &interface) -{ - if (QObject *object = interface.object()) - return (object->inherits("QTabWidget") && interface.id() == 0); - return false; -} - -static bool isStandaloneTabBar(const QAInterface &interface) -{ - QObject *object = interface.object(); - if (interface.role() == QAccessible::PageTabList && object) - return (qobject_cast<QTabWidget *>(object->parent()) == 0); - - return false; -} - -static bool isEmbeddedTabBar(const QAInterface &interface) -{ - QObject *object = interface.object(); - if (interface.role() == QAccessible::PageTabList && object) - return (qobject_cast<QTabWidget *>(object->parent())); - - return false; -} - -/* - Decides if a QAInterface is interesting from an accessibility users point of view. -*/ -bool isItInteresting(const QAInterface &interface) -{ - // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen - // state, so we disable the interface here. - const QAccessible::State state = interface.state(); - if (state & QAccessible::Invisible || - state & QAccessible::Offscreen ) - return false; - - const QAccessible::Role role = interface.role(); - - if (QObject * const object = interface.object()) { - const QString className = QLatin1String(object->metaObject()->className()); - - // VoiceOver focusing on tool tips can be confusing. The contents of the - // tool tip is avalible through the description attribute anyway, so - // we disable accessibility for tool tips. - if (className == QLatin1String("QTipLabel")) - return false; - - // Hide TabBars that has a QTabWidget parent (the tab widget handles the accessibility) - if (isEmbeddedTabBar(interface)) - return false; - - // Hide docked dockwidgets. ### causes infinitie loop in the apple accessibility code. - /* if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) { - if (dockWidget->isFloating() == false) - return false; - } - */ - } - - // Client is a generic role returned by plain QWidgets or other - // widgets that does not have separate QAccessible interface, such - // as the TabWidget. Return false unless macRole gives the interface - // a special role. - if (role == QAccessible::Client && macRole(interface) == CFStringRef(QAXUnknownRole)) - return false; - - // Some roles are not interesting: - if (role == QAccessible::Border || // QFrame - role == QAccessible::Application || // We use the system-provided application element. - role == QAccessible::MenuItem) // The system also provides the menu items. - return false; - - // It is probably better to access the toolbar buttons directly than having - // to navigate through the toolbar. - if (role == QAccessible::ToolBar) - return false; - - return true; -} - -QAElement QAccessibleHierarchyManager::registerInterface(QObject *object, int child) -{ -#ifndef QT_MAC_USE_COCOA - return registerInterface(QAInterface(QAccessible::queryAccessibleInterface(object), child)); -#else - Q_UNUSED(object); - Q_UNUSED(child); - return QAElement(); -#endif -} - -/* - Creates a QAXUIelement that corresponds to the given QAInterface. -*/ -QAElement QAccessibleHierarchyManager::registerInterface(const QAInterface &interface) -{ -#ifndef QT_MAC_USE_COCOA - if (interface.isValid() == false) - return QAElement(); - QAInterface objectInterface = interface.objectInterface(); - - QObject * qobject = objectInterface.object(); - HIObjectRef hiobject = objectInterface.hiObject(); - if (qobject == 0 || hiobject == 0) - return QAElement(); - - if (qobjectElementHash.contains(qobject) == false) { - registerInterface(qobject, hiobject, createFactory(interface)); - HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(interface)); - } - - return QAElement(hiobject, interface.id()); -#else - Q_UNUSED(interface); - return QAElement(); -#endif -} - -#ifndef QT_MAC_USE_COCOA -#include "qaccessible_mac_carbon.cpp" -#endif - -void QAccessibleHierarchyManager::registerInterface(QObject * qobject, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory) -{ -#ifndef QT_MAC_USE_COCOA - if (qobjectElementHash.contains(qobject) == false) { - qobjectElementHash.insert(qobject, interfaceFactory); - qobjectHiobjectHash.insert(qobject, hiobject); - connect(qobject, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *))); - } - - if (hiobjectInterfaceHash.contains(hiobject) == false) { - hiobjectInterfaceHash.insert(hiobject, interfaceFactory); - installAcessibilityEventHandler(hiobject); - } -#else - Q_UNUSED(qobject); - Q_UNUSED(hiobject); - Q_UNUSED(interfaceFactory); -#endif -} - -void QAccessibleHierarchyManager::registerChildren(const QAInterface &interface) -{ - QObject * const object = interface.object(); - if (object == 0) - return; - - QInterfaceFactory *interfaceFactory = qobjectElementHash.value(object); - - if (interfaceFactory == 0) - return; - - interfaceFactory->registerChildren(); -} - -QAInterface QAccessibleHierarchyManager::lookup(const AXUIElementRef &element) -{ - if (element == 0) - return QAInterface(); -#ifndef QT_MAC_USE_COCOA - HIObjectRef hiObject = AXUIElementGetHIObject(element); - - QInterfaceFactory *factory = hiobjectInterfaceHash.value(hiObject); - if (factory == 0) { - return QAInterface(); - } - - UInt64 id; - AXUIElementGetIdentifier(element, &id); - return factory->interface(id); -#else - return QAInterface(); -#endif -} - -QAInterface QAccessibleHierarchyManager::lookup(const QAElement &element) -{ - return lookup(element.element()); -} - -QAElement QAccessibleHierarchyManager::lookup(const QAInterface &interface) -{ - if (interface.isValid() == false) - return QAElement(); - - QInterfaceFactory *factory = qobjectElementHash.value(interface.objectInterface().object()); - if (factory == 0) - return QAElement(); - - return factory->element(interface); -} - -QAElement QAccessibleHierarchyManager::lookup(QObject * const object, int id) -{ - QInterfaceFactory *factory = qobjectElementHash.value(object); - if (factory == 0) - return QAElement(); - - return factory->element(id); -} - -/* - Standard interface mapping, return the stored interface - or HIObjectRef, and there is an one-to-one mapping between - the identifier and child. -*/ -class QStandardInterfaceFactory : public QInterfaceFactory -{ -public: - QStandardInterfaceFactory(const QAInterface &interface) - : m_interface(interface), object(interface.hiObject()) - { - CFRetain(object); - } - - ~QStandardInterfaceFactory() - { - CFRelease(object); - } - - - QAInterface interface(UInt64 identifier) - { - const int child = identifier; - return QAInterface(m_interface, child); - } - - QAElement element(int id) - { - return QAElement(object, id); - } - - QAElement element(const QAInterface &interface) - { - if (interface.object() == 0) - return QAElement(); - return QAElement(object, interface.id()); - } - - void registerChildren() - { - const int childCount = m_interface.childCount(); - for (int i = 1; i <= childCount; ++i) { - accessibleHierarchyManager()->registerInterface(m_interface.navigate(QAccessible::Child, i)); - } - } - -private: - QAInterface m_interface; - HIObjectRef object; -}; - -/* - Interface mapping where that creates one HIObject for each interface child. -*/ -class QMultipleHIObjectFactory : public QInterfaceFactory -{ -public: - QMultipleHIObjectFactory(const QAInterface &interface) - : m_interface(interface) - { } - - ~QMultipleHIObjectFactory() - { - foreach (HIObjectRef object, objects) { - CFRelease(object); - } - } - - QAInterface interface(UInt64 identifier) - { - const int child = identifier; - return QAInterface(m_interface, child); - } - - QAElement element(int child) - { - if (child == 0) - return QAElement(m_interface.hiObject(), 0); - - if (child > objects.count()) - return QAElement(); - - return QAElement(objects.at(child - 1), child); - } - - void registerChildren() - { -#ifndef QT_MAC_USE_COCOA - const int childCount = m_interface.childCount(); - for (int i = 1; i <= childCount; ++i) { - HIObjectRef hiobject; - HIObjectCreate(kObjectQtAccessibility, 0, &hiobject); - objects.append(hiobject); - accessibleHierarchyManager()->registerInterface(m_interface.object(), hiobject, this); - HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(m_interface.navigate(QAccessible::Child, i))); - } -#endif - } - -private: - QAInterface m_interface; - QList<HIObjectRef> objects; -}; - -class QItemViewInterfaceFactory : public QInterfaceFactory -{ -public: - QItemViewInterfaceFactory(const QAInterface &interface) - : m_interface(interface), object(interface.hiObject()) - { - CFRetain(object); - columnCount = 0; - if (QTableView * tableView = qobject_cast<QTableView *>(interface.parent().object())) { - if (tableView->model()) - columnCount = tableView->model()->columnCount(); - if (tableView->verticalHeader()) - ++columnCount; - } - } - - ~QItemViewInterfaceFactory() - { - CFRelease(object); - } - - QAInterface interface(UInt64 identifier) - { - if (identifier == 0) - return m_interface; - - if (m_interface.role() == QAccessible::List) - return m_interface.childAt(identifier); - - if (m_interface.role() == QAccessible::Table) { - const int index = identifier; - if (index == 0) - return m_interface; // return the item view interface. - - const int rowIndex = (index - 1) / (columnCount + 1); - const int cellIndex = (index - 1) % (columnCount + 1); -/* - qDebug() << "index" << index; - qDebug() << "rowIndex" << rowIndex; - qDebug() << "cellIndex" << cellIndex; -*/ - const QAInterface rowInterface = m_interface.childAt(rowIndex + 1); - - if ((cellIndex) == 0) // Is it a row? - return rowInterface; - else { - return rowInterface.childAt(cellIndex); - } - } - - return QAInterface(); - } - - QAElement element(int id) - { - if (id != 0) { - return QAElement(); - } - return QAElement(object, 0); - } - - QAElement element(const QAInterface &interface) - { - if (interface.object() && interface.object() == m_interface.object()) { - return QAElement(object, 0); - } else if (m_interface.role() == QAccessible::List) { - if (interface.parent().object() && interface.parent().object() == m_interface.object()) - return QAElement(object, m_interface.indexOfChild(interface)); - } else if (m_interface.role() == QAccessible::Table) { - QAInterface currentInterface = interface; - int index = 0; - - while (currentInterface.isValid() && currentInterface.object() == 0) { - const QAInterface parentInterface = currentInterface.parent(); -/* - qDebug() << "current index" << index; - qDebug() << "current interface" << interface; - - qDebug() << "parent interface" << parentInterface; - qDebug() << "grandparent interface" << parentInterface.parent(); - qDebug() << "childCount" << interface.childCount(); - qDebug() << "index of child" << parentInterface.indexOfChild(currentInterface); -*/ - index += ((parentInterface.indexOfChild(currentInterface) - 1) * (currentInterface.childCount() + 1)) + 1; - currentInterface = parentInterface; -// qDebug() << "new current interface" << currentInterface; - } - if (currentInterface.object() == m_interface.object()) - return QAElement(object, index); - - - } - return QAElement(); - } - - void registerChildren() - { - // Item view child interfraces don't have their own qobjects, so there is nothing to register here. - } - -private: - QAInterface m_interface; - HIObjectRef object; - int columnCount; // for table views; -}; - -#ifndef QT_MAC_USE_COCOA -static bool managesChildren(const QAInterface &interface) -{ - return (interface.childCount() > 0 && interface.childAt(1).id() > 0); -} - -static QInterfaceFactory *createFactory(const QAInterface &interface) -{ - if (isItemView(interface)) { - return new QItemViewInterfaceFactory(interface); - } if (managesChildren(interface)) { - return new QMultipleHIObjectFactory(interface); - } - - return new QStandardInterfaceFactory(interface); -} -#endif - -QList<QAElement> lookup(const QList<QAInterface> &interfaces) -{ - QList<QAElement> elements; - foreach (const QAInterface &interface, interfaces) - if (interface.isValid()) { - const QAElement element = accessibleHierarchyManager()->lookup(interface); - if (element.isValid()) - elements.append(element); - } - return elements; -} - -// Debug output helpers: -/* -static QString nameForEventKind(UInt32 kind) -{ - switch(kind) { - case kEventAccessibleGetChildAtPoint: return QString("GetChildAtPoint"); break; - case kEventAccessibleGetAllAttributeNames: return QString("GetAllAttributeNames"); break; - case kEventAccessibleGetNamedAttribute: return QString("GetNamedAttribute"); break; - case kEventAccessibleSetNamedAttribute: return QString("SetNamedAttribute"); break; - case kEventAccessibleGetAllActionNames: return QString("GetAllActionNames"); break; - case kEventAccessibleGetFocusedChild: return QString("GetFocusedChild"); break; - default: - return QString("Unknown accessibility event type: %1").arg(kind); - break; - }; -} -*/ -#ifndef QT_MAC_USE_COCOA -static bool qt_mac_append_cf_uniq(CFMutableArrayRef array, CFTypeRef value) -{ - if (value == 0) - return false; - - CFRange range; - range.location = 0; - range.length = CFArrayGetCount(array); - if(!CFArrayContainsValue(array, range, value)) { - CFArrayAppendValue(array, value); - return true; - } - return false; -} - -static OSStatus setAttributeValue(EventRef event, const QList<QAElement> &elements) -{ - CFMutableArrayRef array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); - foreach (const QAElement &element, elements) { - if (element.isValid()) - CFArrayAppendValue(array, element.element()); - } - - const OSStatus err = SetEventParameter(event, kEventParamAccessibleAttributeValue, - typeCFTypeRef, sizeof(array), &array); - CFRelease(array); - return err; -} -#endif //QT_MAC_USE_COCOA - -/* - Gets the AccessibleObject parameter from an event. -*/ -static inline AXUIElementRef getAccessibleObjectParameter(EventRef event) -{ - AXUIElementRef element; - GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, - sizeof(element), 0, &element); - return element; -} - -/* - The application event handler makes sure that all top-level qt windows are registered - before any accessibility events are handeled. -*/ -#ifndef QT_MAC_USE_COCOA -static OSStatus applicationEventHandler(EventHandlerCallRef next_ref, EventRef event, void *) -{ - QAInterface rootInterface(QAccessible::queryAccessibleInterface(rootObject ? rootObject : qApp), 0); - accessibleHierarchyManager()->registerChildren(rootInterface); - - return CallNextEventHandler(next_ref, event); -} - -/* - Returns the value for element by combining the QAccessibility::Checked and - QAccessibility::Mixed flags into an int value that the Mac accessibilty - system understands. This works for check boxes, radio buttons, and the like. - The return values are: - 0: unchecked - 1: checked - 2: undecided -*/ -static int buttonValue(QAInterface element) -{ - const QAccessible::State state = element.state(); - if (state & QAccessible::Mixed) - return 2; - else if(state & QAccessible::Checked) - return 1; - else - return 0; -} - -static QString getValue(const QAInterface &interface) -{ - const QAccessible::Role role = interface.role(); - if (role == QAccessible::RadioButton || role == QAccessible::CheckBox) - return QString::number(buttonValue(interface)); - else - return interface.text(QAccessible::Value); -} -#endif //QT_MAC_USE_COCOA - -/* - Translates a QAccessible::Role into a mac accessibility role. -*/ -static CFStringRef macRole(const QAInterface &interface) -{ - const QAccessible::Role qtRole = interface.role(); - -// qDebug() << "role for" << interface.object() << "interface role" << hex << qtRole; - - // Qt accessibility: QAccessible::Splitter contains QAccessible::Grip. - // Mac accessibility: AXSplitGroup contains AXSplitter. - if (qtRole == QAccessible::Grip) { - const QAInterface parent = interface.parent(); - if (parent.isValid() && parent.role() == QAccessible::Splitter) - return CFStringRef(QAXSplitterRole); - } - - // Tab widgets and standalone tab bars get the kAXTabGroupRole. Accessibility - // for tab bars emebedded in a tab widget is handled by the tab widget. - if (isTabWidget(interface) || isStandaloneTabBar(interface)) - return kAXTabGroupRole; - - if (QObject *object = interface.object()) { - // ### The interface for an abstract scroll area returns the generic "Client" - // role, so we have to to an extra detect on the QObject here. - if (object->inherits("QAbstractScrollArea") && interface.id() == 0) - return CFStringRef(QAXScrollAreaRole); - - if (object->inherits("QDockWidget")) - return CFStringRef(QAXUnknownRole); - } - - int i = 0; - int testRole = text_bindings[i][0].qt; - while (testRole != -1) { - if (testRole == qtRole) - return CFStringRef(text_bindings[i][0].mac); - ++i; - testRole = text_bindings[i][0].qt; - } - -// qDebug() << "got unknown role!" << interface << interface.parent(); - - return CFStringRef(QAXUnknownRole); -} - -/* - Translates a QAccessible::Role and an attribute name into a QAccessible::Text, taking into - account execptions listed in text_bindings. -*/ -#ifndef QT_MAC_USE_COCOA -static int textForRoleAndAttribute(QAccessible::Role role, CFStringRef attribute) -{ - // Search for exception, return it if found. - int testRole = text_bindings[0][0].qt; - int i = 0; - while (testRole != -1) { - if (testRole == role) { - int j = 1; - int qtRole = text_bindings[i][j].qt; - CFStringRef testAttribute = CFStringRef(text_bindings[i][j].mac); - while (qtRole != -1) { - if (CFStringCompare(attribute, testAttribute, 0) == kCFCompareEqualTo) { - return (QAccessible::Text)qtRole; - } - ++j; - testAttribute = CFStringRef(text_bindings[i][j].mac); /// ### custom compare - qtRole = text_bindings[i][j].qt; /// ### custom compare - } - break; - } - ++i; - testRole = text_bindings[i][0].qt; - } - - // Return default mappping - if (CFStringCompare(attribute, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) - return QAccessible::Name; - else if (CFStringCompare(attribute, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) - return QAccessible::Value; - else if (CFStringCompare(attribute, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) - return QAccessible::Help; - else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) - return QAccessible::Description; - else - return -1; -} - -/* - Returns the subrole string constant for the interface if it has one, - else returns an empty string. -*/ -static QCFString subrole(const QAInterface &interface) -{ - const QAInterface parent = interface.parent(); - if (parent.isValid() == false) - return QCFString(); - - if (parent.role() == QAccessible::ScrollBar) { - QCFString subrole; - switch(interface.id()) { - case 1: subrole = CFStringRef(QAXDecrementArrowSubrole); break; - case 2: subrole = CFStringRef(QAXDecrementPageSubrole); break; - case 4: subrole = CFStringRef(QAXIncrementPageSubrole); break; - case 5: subrole = CFStringRef(QAXIncrementArrowSubrole); break; - default: - break; - } - return subrole; - } - return QCFString(); -} - -// Gets the scroll bar orientation by asking the QAbstractSlider object directly. -static Qt::Orientation scrollBarOrientation(const QAInterface &scrollBar) -{ - QObject *const object = scrollBar.object(); - if (QAbstractSlider * const sliderObject = qobject_cast<QAbstractSlider * const>(object)) - return sliderObject->orientation(); - - return Qt::Vertical; // D'oh! The interface wasn't a scroll bar. -} - -static QAInterface scrollAreaGetScrollBarInterface(const QAInterface &scrollArea, Qt::Orientation orientation) -{ - if (macRole(scrollArea) != CFStringRef(CFStringRef(QAXScrollAreaRole))) - return QAInterface(); - - // Child 1 is the contents widget, 2 and 3 are the scroll bar containers wich contains possible scroll bars. - for (int i = 2; i <= 3; ++i) { - QAInterface scrollBarContainer = scrollArea.childAt(i); - for (int i = 1; i <= scrollBarContainer.childCount(); ++i) { - QAInterface scrollBar = scrollBarContainer.childAt(i); - if (scrollBar.isValid() && - scrollBar.role() == QAccessible::ScrollBar && - scrollBarOrientation(scrollBar) == orientation) - return scrollBar; - } - } - - return QAInterface(); -} - -static bool scrollAreaHasScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation) -{ - return scrollAreaGetScrollBarInterface(scrollArea, orientation).isValid(); -} - -static QAElement scrollAreaGetScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation) -{ - return accessibleHierarchyManager()->lookup(scrollAreaGetScrollBarInterface(scrollArea, orientation)); -} - -static QAElement scrollAreaGetContents(const QAInterface &scrollArea) -{ - // Child 1 is the contents widget, - return accessibleHierarchyManager()->lookup(scrollArea.navigate(QAccessible::Child, 1)); -} - -static QAElement tabWidgetGetContents(const QAInterface &interface) -{ - // A kAXTabGroup has a kAXContents attribute, which consists of the - // ui elements for the current tab page. Get the current tab page - // from the QStackedWidget, where the current visible page can - // be found at index 1. - QAInterface stackedWidget = interface.childAt(1); - accessibleHierarchyManager()->registerChildren(stackedWidget); - QAInterface tabPageInterface = stackedWidget.childAt(1); - return accessibleHierarchyManager()->lookup(tabPageInterface); -} - -static QList<QAElement> tabBarGetTabs(const QAInterface &interface) -{ - // Get the tabs by searching for children with the "PageTab" role. - // This filters out the left/right navigation buttons. - accessibleHierarchyManager()->registerChildren(interface); - QList<QAElement> tabs; - const int numChildren = interface.childCount(); - for (int i = 1; i < numChildren + 1; ++i) { - QAInterface child = interface.navigate(QAccessible::Child, i); - if (child.isValid() && child.role() == QAccessible::PageTab) { - tabs.append(accessibleHierarchyManager()->lookup(child)); - } - } - return tabs; -} - -static QList<QAElement> tabWidgetGetTabs(const QAInterface &interface) -{ - // Each QTabWidget has two children, a QStackedWidget and a QTabBar. - // Get the tabs from the QTabBar. - return tabBarGetTabs(interface.childAt(2)); -} - -static QList<QAElement> tabWidgetGetChildren(const QAInterface &interface) -{ - // The children for a kAXTabGroup should consist of the tabs and the - // contents of the current open tab page. - QList<QAElement> children = tabWidgetGetTabs(interface); - children += tabWidgetGetContents(interface); - return children; -} -#endif //QT_MAC_USE_COCOA - -/* - Returns the label (buddy) interface for interface, or 0 if it has none. -*/ -/* -static QAInterface findLabel(const QAInterface &interface) -{ - return interface.navigate(QAccessible::Label, 1); -} -*/ -/* - Returns a list of interfaces this interface labels, or an empty list if it doesn't label any. -*/ -/* -static QList<QAInterface> findLabelled(const QAInterface &interface) -{ - QList<QAInterface> interfaceList; - - int count = 1; - const QAInterface labelled = interface.navigate(QAccessible::Labelled, count); - while (labelled.isValid()) { - interfaceList.append(labelled); - ++count; - } - return interfaceList; -} -*/ -/* - Tests if the given QAInterface has data for a mac attribute. -*/ -#ifndef QT_MAC_USE_COCOA -static bool supportsAttribute(CFStringRef attribute, const QAInterface &interface) -{ - const int text = textForRoleAndAttribute(interface.role(), attribute); - - // Special case: Static texts don't have a title. - if (interface.role() == QAccessible::StaticText && attribute == CFStringRef(QAXTitleAttribute)) - return false; - - // Return true if we the attribute matched a QAccessible::Role and we get text for that role from the interface. - if (text != -1) { - if (text == QAccessible::Value) // Special case for Value, see getValue() - return !getValue(interface).isEmpty(); - else - return !interface.text((QAccessible::Text)text).isEmpty(); - } - - if (CFStringCompare(attribute, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) { - if (interface.childCount() > 0) - return true; - } - - if (CFStringCompare(attribute, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) { - return (subrole(interface) != QCFString()); - } - - return false; -} - -static void appendIfSupported(CFMutableArrayRef array, CFStringRef attribute, const QAInterface &interface) -{ - if (supportsAttribute(attribute, interface)) - qt_mac_append_cf_uniq(array, attribute); -} - -/* - Returns the names of the attributes the give QAInterface supports. -*/ -static OSStatus getAllAttributeNames(EventRef event, const QAInterface &interface, EventHandlerCallRef next_ref) -{ - // Call system event handler. - OSStatus err = CallNextEventHandler(next_ref, event); - if(err != noErr && err != eventNotHandledErr) - return err; - CFMutableArrayRef attrs = 0; - GetEventParameter(event, kEventParamAccessibleAttributeNames, typeCFMutableArrayRef, 0, - sizeof(attrs), 0, &attrs); - - if (!attrs) - return eventNotHandledErr; - - // Append attribute names that are always supported. - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPositionAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSizeAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRoleAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXEnabledAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXWindowAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute)); - - // Append these names if the QInterafceItem returns any data for them. - appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXHelpAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXTitleUIElementAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXChildrenAttribute), interface); - appendIfSupported(attrs, CFStringRef(QAXSubroleAttribute), interface); - - // Append attribute names based on the interaface role. - switch (interface.role()) { - case QAccessible::Window: - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMainAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizedAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXCloseButtonAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXZoomButtonAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizeButtonAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXToolbarButtonAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXGrowAreaAttribute)); - break; - case QAccessible::RadioButton: - case QAccessible::CheckBox: - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinValueAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMaxValueAttribute)); - break; - case QAccessible::ScrollBar: - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute)); - break; - case QAccessible::Splitter: - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSplittersAttribute)); - break; - case QAccessible::Table: - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRowsAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVisibleRowsAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSelectedRowsAttribute)); - break; - default: - break; - } - - // Append attribute names based on the mac accessibility role. - const QCFString mac_role = macRole(interface); - if (mac_role == CFStringRef(QAXSplitterRole)) { - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPreviousContentsAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXNextContentsAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute)); - } else if (mac_role == CFStringRef(QAXScrollAreaRole)) { - if (scrollAreaHasScrollBar(interface, Qt::Horizontal)) - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXHorizontalScrollBarAttribute)); - if (scrollAreaHasScrollBar(interface, Qt::Vertical)) - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVerticalScrollBarAttribute)); - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute)); - } else if (mac_role == CFStringRef(QAXTabGroupRole)) { - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTabsAttribute)); - // Only tab widgets can have the contents attribute, there is no way of getting - // the contents from a QTabBar. - if (isTabWidget(interface)) - qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute)); - } - - return noErr; -} - -static void handleStringAttribute(EventRef event, QAccessible::Text text, const QAInterface &interface) -{ - QString str = interface.text(text); - if (str.isEmpty()) - return; - - // Remove any html markup from the text string, or VoiceOver will read the html tags. - static QTextDocument document; - document.setHtml(str); - str = document.toPlainText(); - - CFStringRef cfstr = QCFString::toCFStringRef(str); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(cfstr), &cfstr); -} - -/* - Handles the parent attribute for a interface. - There are basically three cases here: - 1. interface is a HIView and has only HIView children. - 2. interface is a HIView but has children that is not a HIView - 3. interface is not a HIView. -*/ -static OSStatus handleChildrenAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - // Add the children for this interface to the global QAccessibelHierachyManager. - accessibleHierarchyManager()->registerChildren(interface); - - if (isTabWidget(interface)) { - QList<QAElement> children = tabWidgetGetChildren(interface); - const int childCount = children.count(); - - CFMutableArrayRef array = 0; - array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); - for (int i = 0; i < childCount; ++i) { - qt_mac_append_cf_uniq(array, children.at(i).element()); - } - - OSStatus err; - err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array); - if (err != noErr) - qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); - - return noErr; - } - - const QList<QAElement> children = lookup(interface.children()); - const int childCount = children.count(); - - OSStatus err = eventNotHandledErr; - if (interface.isHIView()) - err = CallNextEventHandler(next_ref, event); - - CFMutableArrayRef array = 0; - int arraySize = 0; - if (err == noErr) { - CFTypeRef obj = 0; - err = GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, NULL , sizeof(obj), NULL, &obj); - if (err == noErr && obj != 0) { - array = (CFMutableArrayRef)obj; - arraySize = CFArrayGetCount(array); - } - } - - if (array) { - CFArrayRemoveAllValues(array); - for (int i = 0; i < childCount; ++i) { - qt_mac_append_cf_uniq(array, children.at(i).element()); - } - } else { - array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); - for (int i = 0; i < childCount; ++i) { - qt_mac_append_cf_uniq(array, children.at(i).element()); - } - - err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array); - if (err != noErr) - qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); - } - - return noErr; -} - -/* - -*/ -static OSStatus handleParentAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - OSStatus err = eventNotHandledErr; - if (interface.isHIView()) { - err = CallNextEventHandler(next_ref, event); - } - if (err == noErr) - return err; - - const QAInterface parentInterface = interface.navigate(QAccessible::Ancestor, 1); - const QAElement parentElement = accessibleHierarchyManager()->lookup(parentInterface); - - if (parentElement.isValid() == false) - return eventNotHandledErr; - - AXUIElementRef elementRef = parentElement.element(); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef); - return noErr; -} -#endif - -struct IsWindowTest -{ - static inline bool test(const QAInterface &interface) - { - return (interface.role() == QAccessible::Window); - } -}; - -struct IsWindowAndNotDrawerOrSheetTest -{ - static inline bool test(const QAInterface &interface) - { - QWidget * const widget = qobject_cast<QWidget*>(interface.object()); - return (interface.role() == QAccessible::Window && - widget && widget->isWindow() && - !qt_mac_is_macdrawer(widget) && - !qt_mac_is_macsheet(widget)); - } -}; - -/* - Navigates up the iterfaces ancestor hierachy until a QAccessibleInterface that - passes the Test is found. If we reach a interface that is a HIView we stop the - search and call AXUIElementCopyAttributeValue. -*/ -template <typename TestType> -OSStatus navigateAncestors(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, CFStringRef attribute) -{ - if (interface.isHIView()) - return CallNextEventHandler(next_ref, event); - - QAInterface current = interface; - QAElement element; - while (current.isValid()) { - if (TestType::test(interface)) { - element = accessibleHierarchyManager()->lookup(current); - break; - } - - // If we reach an InterfaceItem that is a HiView we can hand of the search to - // the system event handler. This is the common case. - if (current.isHIView()) { - CFTypeRef value = 0; - const QAElement currentElement = accessibleHierarchyManager()->lookup(current); - AXError err = AXUIElementCopyAttributeValue(currentElement.element(), attribute, &value); - AXUIElementRef newElement = (AXUIElementRef)value; - - if (err == noErr) - element = QAElement(newElement); - - if (newElement != 0) - CFRelease(newElement); - break; - } - - QAInterface next = current.parent(); - if (next.isValid() == false) - break; - if (next == current) - break; - current = next; - } - - if (element.isValid() == false) - return eventNotHandledErr; - - - AXUIElementRef elementRef = element.element(); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, - sizeof(elementRef), &elementRef); - return noErr; -} - -/* - Returns the top-level window for an interface, which is the closest ancestor interface that - has the Window role, but is not a sheet or a drawer. -*/ -#ifndef QT_MAC_USE_COCOA -static OSStatus handleWindowAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - return navigateAncestors<IsWindowAndNotDrawerOrSheetTest>(next_ref, event, interface, CFStringRef(QAXWindowAttribute)); -} - -/* - Returns the top-level window for an interface, which is the closest ancestor interface that - has the Window role. (Can also be a sheet or a drawer) -*/ -static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute)); -} - -/* - Returns the tab buttons for an interface. -*/ -static OSStatus handleTabsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - Q_UNUSED(next_ref); - if (isTabWidget(interface)) - return setAttributeValue(event, tabWidgetGetTabs(interface)); - else - return setAttributeValue(event, tabBarGetTabs(interface)); -} - -static OSStatus handlePositionAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) -{ - QPoint qpoint(interface.rect().topLeft()); - HIPoint point; - point.x = qpoint.x(); - point.y = qpoint.y(); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHIPoint, sizeof(point), &point); - return noErr; -} - -static OSStatus handleSizeAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) -{ - QSize qSize(interface.rect().size()); - HISize size; - size.width = qSize.width(); - size.height = qSize.height(); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHISize, sizeof(size), &size); - return noErr; -} - -static OSStatus handleSubroleAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) -{ - const QCFString role = subrole(interface); - CFStringRef rolestr = (CFStringRef)role; - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(rolestr), &rolestr); - return noErr; -} - -static OSStatus handleOrientationAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - QObject *const object = interface.object(); - Qt::Orientation orientation; - if (interface.role() == QAccessible::ScrollBar) { - orientation = scrollBarOrientation(interface); - } else if (QSplitterHandle * const splitter = qobject_cast<QSplitterHandle * const>(object)) { - // Qt reports the layout orientation, but we want the splitter handle orientation. - orientation = (splitter->orientation() == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; - } else { - return CallNextEventHandler(next_ref, event); - } - const CFStringRef orientationString = (orientation == Qt::Vertical) - ? CFStringRef(QAXVerticalOrientationValue) : CFStringRef(QAXHorizontalOrientationValue); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(orientationString), &orientationString); - return noErr; -} - -/* - Figures out the next or previous contents for a splitter. -*/ -static OSStatus handleSplitterContentsAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, QCFString nextOrPrev) -{ - if (interface.isValid() == false || interface.role() != QAccessible::Grip) - return eventNotHandledErr; - - const QAInterface parent = interface.parent(); - if (parent.isValid() == false) - return CallNextEventHandler(next_ref, event); - - if (parent.role() != QAccessible::Splitter) - return CallNextEventHandler(next_ref, event); - - const QSplitter * const splitter = qobject_cast<const QSplitter * const>(parent.object()); - if (splitter == 0) - return CallNextEventHandler(next_ref, event); - - QWidget * const splitterHandle = qobject_cast<QWidget * const>(interface.object()); - const int splitterHandleIndex = splitter->indexOf(splitterHandle); - const int widgetIndex = (nextOrPrev == QCFString(CFStringRef(QAXPreviousContentsAttribute))) ? splitterHandleIndex - 1 : splitterHandleIndex; - const QAElement contentsElement = accessibleHierarchyManager()->lookup(splitter->widget(widgetIndex), 0); - return setAttributeValue(event, QList<QAElement>() << contentsElement); -} - -/* - Creates a list of all splitter handles the splitter contains. -*/ -static OSStatus handleSplittersAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - const QSplitter * const splitter = qobject_cast<const QSplitter * const>(interface.object()); - if (splitter == 0) - return CallNextEventHandler(next_ref, event); - - accessibleHierarchyManager()->registerChildren(interface); - - QList<QAElement> handles; - const int visibleSplitterCount = splitter->count() -1; // skip first handle, it's always invisible. - for (int i = 0; i < visibleSplitterCount; ++i) - handles.append(accessibleHierarchyManager()->lookup(splitter->handle(i + 1), 0)); - - return setAttributeValue(event, handles); -} - -// This handler gets the scroll bars for a scroll area -static OSStatus handleScrollBarAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &scrollArea, Qt::Orientation orientation) -{ - QAElement scrollBar = scrollAreaGetScrollBar(scrollArea, orientation); - if (scrollBar.isValid() == false) - return CallNextEventHandler(next_ref, event); - - AXUIElementRef elementRef = scrollBar.element(); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef); - return noErr; -} - -// This handler gets the contents for a scroll area or tab widget. -static OSStatus handleContentsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - const QCFString mac_role = macRole(interface); - - QAElement contents; - - if (mac_role == kAXTabGroupRole) { - contents = tabWidgetGetContents(interface); - } else { - contents = scrollAreaGetContents(interface); - if (contents.isValid() == false) - return CallNextEventHandler(next_ref, event); - } - - return setAttributeValue(event, QList<QAElement>() << contents); -} - -static OSStatus handleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) -{ - QList<QAElement> rows = lookup(tableView.children()); - - // kill the first row which is the horizontal header. - rows.removeAt(0); - - return setAttributeValue(event, rows); -} - -static OSStatus handleVisibleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) -{ - QList<QAElement> visibleRows; - - QList<QAInterface> rows = tableView.children(); - // kill the first row which is the horizontal header. - rows.removeAt(0); - - foreach (const QAInterface &interface, rows) - if ((interface.state() & QAccessible::Invisible) == false) - visibleRows.append(accessibleHierarchyManager()->lookup(interface)); - - return setAttributeValue(event, visibleRows); -} - -static OSStatus handleSelectedRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) -{ - QList<QAElement> selectedRows; - foreach (const QAInterface &interface, tableView.children()) - if ((interface.state() & QAccessible::Selected)) - selectedRows.append(accessibleHierarchyManager()->lookup(interface)); - - return setAttributeValue(event, selectedRows); -} - -static OSStatus getNamedAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - CFStringRef var; - GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, - sizeof(var), 0, &var); - - if (CFStringCompare(var, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) { - return handleChildrenAttribute(next_ref, event, interface); - } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) { - return handleTopLevelUIElementAttribute(next_ref, event, interface); - } else if(CFStringCompare(var, CFStringRef(QAXWindowAttribute), 0) == kCFCompareEqualTo) { - return handleWindowAttribute(next_ref, event, interface); - } else if(CFStringCompare(var, CFStringRef(QAXParentAttribute), 0) == kCFCompareEqualTo) { - return handleParentAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXPositionAttribute), 0) == kCFCompareEqualTo) { - return handlePositionAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXSizeAttribute), 0) == kCFCompareEqualTo) { - return handleSizeAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXRoleAttribute), 0) == kCFCompareEqualTo) { - CFStringRef role = macRole(interface); -// ### -// QWidget * const widget = qobject_cast<QWidget *>(interface.object()); -// if (role == CFStringRef(QAXUnknownRole) && widget && widget->isWindow()) -// role = CFStringRef(QAXWindowRole); - - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, - sizeof(role), &role); - - } else if (CFStringCompare(var, CFStringRef(QAXEnabledAttribute), 0) == kCFCompareEqualTo) { - Boolean val = !((interface.state() & QAccessible::Unavailable)) - && !((interface.state() & QAccessible::Invisible)); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } else if (CFStringCompare(var, CFStringRef(QAXExpandedAttribute), 0) == kCFCompareEqualTo) { - Boolean val = (interface.state() & QAccessible::Expanded); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } else if (CFStringCompare(var, CFStringRef(QAXSelectedAttribute), 0) == kCFCompareEqualTo) { - Boolean val = (interface.state() & QAccessible::Selection); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } else if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { - Boolean val = (interface.state() & QAccessible::Focus); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } else if (CFStringCompare(var, CFStringRef(QAXSelectedChildrenAttribute), 0) == kCFCompareEqualTo) { - const int cc = interface.childCount(); - QList<QAElement> selected; - for (int i = 1; i <= cc; ++i) { - const QAInterface child_iface = interface.navigate(QAccessible::Child, i); - if (child_iface.isValid() && child_iface.state() & QAccessible::Selected) - selected.append(accessibleHierarchyManager()->lookup(child_iface)); - } - - return setAttributeValue(event, selected); - - } else if (CFStringCompare(var, CFStringRef(QAXCloseButtonAttribute), 0) == kCFCompareEqualTo) { - if(interface.object() && interface.object()->isWidgetType()) { - Boolean val = true; //do we want to add a WState for this? - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXZoomButtonAttribute), 0) == kCFCompareEqualTo) { - if(interface.object() && interface.object()->isWidgetType()) { - QWidget *widget = (QWidget*)interface.object(); - Boolean val = (widget->windowFlags() & Qt::WindowMaximizeButtonHint); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXMinimizeButtonAttribute), 0) == kCFCompareEqualTo) { - if(interface.object() && interface.object()->isWidgetType()) { - QWidget *widget = (QWidget*)interface.object(); - Boolean val = (widget->windowFlags() & Qt::WindowMinimizeButtonHint); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXToolbarButtonAttribute), 0) == kCFCompareEqualTo) { - if(interface.object() && interface.object()->isWidgetType()) { - QWidget *widget = (QWidget*)interface.object(); - Boolean val = qobject_cast<QMainWindow *>(widget) != 0; - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXGrowAreaAttribute), 0) == kCFCompareEqualTo) { - if(interface.object() && interface.object()->isWidgetType()) { - Boolean val = true; //do we want to add a WState for this? - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXMinimizedAttribute), 0) == kCFCompareEqualTo) { - if (interface.object() && interface.object()->isWidgetType()) { - QWidget *widget = (QWidget*)interface.object(); - Boolean val = (widget->windowState() & Qt::WindowMinimized); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, - sizeof(val), &val); - } - } else if (CFStringCompare(var, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) { - return handleSubroleAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXRoleDescriptionAttribute), 0) == kCFCompareEqualTo) { -#if !defined(QT_MAC_USE_COCOA) - if (HICopyAccessibilityRoleDescription) { - const CFStringRef roleDescription = HICopyAccessibilityRoleDescription(macRole(interface), 0); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, - sizeof(roleDescription), &roleDescription); - } else -#endif - { - // Just use Qt::Description on 10.3 - handleStringAttribute(event, QAccessible::Description, interface); - } - } else if (CFStringCompare(var, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) { - const QAccessible::Role role = interface.role(); - const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); - handleStringAttribute(event, text, interface); - } else if (CFStringCompare(var, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) { - const QAccessible::Role role = interface.role(); - const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); - if (role == QAccessible::CheckBox || role == QAccessible::RadioButton) { - int value = buttonValue(interface); - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); - } else { - handleStringAttribute(event, text, interface); - } - } else if (CFStringCompare(var, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) { - const QAccessible::Role role = interface.role(); - const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); - handleStringAttribute(event, text, interface); - } else if (CFStringCompare(var, CFStringRef(QAXLinkedUIElementsAttribute), 0) == kCFCompareEqualTo) { - return CallNextEventHandler(next_ref, event); - } else if (CFStringCompare(var, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) { - const QAccessible::Role role = interface.role(); - const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); - handleStringAttribute(event, text, interface); - } else if (CFStringCompare(var, kAXTitleUIElementAttribute, 0) == kCFCompareEqualTo) { - return CallNextEventHandler(next_ref, event); - } else if (CFStringCompare(var, CFStringRef(QAXTabsAttribute), 0) == kCFCompareEqualTo) { - return handleTabsAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) { - // tabs we first go to the tab bar which is child #2. - QAInterface tabBarInterface = interface.childAt(2); - return handleTabsAttribute(next_ref, event, tabBarInterface); - } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) { - if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) { - uint value = 0; - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); - } else { - return CallNextEventHandler(next_ref, event); - } - } else if (CFStringCompare(var, CFStringRef(QAXMaxValueAttribute), 0) == kCFCompareEqualTo) { - if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) { - uint value = 2; - SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); - } else { - return CallNextEventHandler(next_ref, event); - } - } else if (CFStringCompare(var, CFStringRef(QAXOrientationAttribute), 0) == kCFCompareEqualTo) { - return handleOrientationAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXPreviousContentsAttribute), 0) == kCFCompareEqualTo) { - return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXPreviousContentsAttribute)); - } else if (CFStringCompare(var, CFStringRef(QAXNextContentsAttribute), 0) == kCFCompareEqualTo) { - return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXNextContentsAttribute)); - } else if (CFStringCompare(var, CFStringRef(QAXSplittersAttribute), 0) == kCFCompareEqualTo) { - return handleSplittersAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXHorizontalScrollBarAttribute), 0) == kCFCompareEqualTo) { - return handleScrollBarAttribute(next_ref, event, interface, Qt::Horizontal); - } else if (CFStringCompare(var, CFStringRef(QAXVerticalScrollBarAttribute), 0) == kCFCompareEqualTo) { - return handleScrollBarAttribute(next_ref, event, interface, Qt::Vertical); - } else if (CFStringCompare(var, CFStringRef(QAXContentsAttribute), 0) == kCFCompareEqualTo) { - return handleContentsAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXRowsAttribute), 0) == kCFCompareEqualTo) { - return handleRowsAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXVisibleRowsAttribute), 0) == kCFCompareEqualTo) { - return handleVisibleRowsAttribute(next_ref, event, interface); - } else if (CFStringCompare(var, CFStringRef(QAXSelectedRowsAttribute), 0) == kCFCompareEqualTo) { - return handleSelectedRowsAttribute(next_ref, event, interface); - } else { - return CallNextEventHandler(next_ref, event); - } - return noErr; -} - -static OSStatus isNamedAttributeSettable(EventRef event, const QAInterface &interface) -{ - CFStringRef var; - GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, - sizeof(var), 0, &var); - Boolean settable = false; - if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { - settable = true; - } else { - for (int r = 0; text_bindings[r][0].qt != -1; r++) { - if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) { - for (int a = 1; text_bindings[r][a].qt != -1; a++) { - if (CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) { - settable = text_bindings[r][a].settable; - break; - } - } - } - } - } - SetEventParameter(event, kEventParamAccessibleAttributeSettable, typeBoolean, - sizeof(settable), &settable); - return noErr; -} - -static OSStatus getChildAtPoint(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) -{ - Q_UNUSED(next_ref); - if (interface.isValid() == false) - return eventNotHandledErr; - - // Add the children for this interface to the global QAccessibelHierachyManager. - accessibleHierarchyManager()->registerChildren(interface); - - Point where; - GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where); - const QAInterface childInterface = interface.childAt(where.h, where.v); - - if (childInterface.isValid() == false || childInterface == interface) - return eventNotHandledErr; - - const QAElement element = accessibleHierarchyManager()->lookup(childInterface); - if (element.isValid() == false) - return eventNotHandledErr; - - AXUIElementRef elementRef = element.element(); - CFRetain(elementRef); - SetEventParameter(event, kEventParamAccessibleChild, typeCFTypeRef, - sizeof(elementRef), &elementRef); - - return noErr; -} - -/* - Returns a list of actions the given interface supports. - Currently implemented by getting the interface role and deciding based on that. -*/ -static QList<QAccessible::Action> supportedPredefinedActions(const QAInterface &interface) -{ - QList<QAccessible::Action> actions; - switch (interface.role()) { - default: - // Most things can be pressed. - actions.append(QAccessible::Press); - break; - } - - return actions; -} - -/* - Translates a predefined QAccessible::Action to a Mac action constant. - Returns an empty string if the Qt Action has no mac equivalent. -*/ -static QCFString translateAction(const QAccessible::Action action) -{ - switch (action) { - case QAccessible::Press: - return CFStringRef(QAXPressAction); - break; - case QAccessible::Increase: - return CFStringRef(QAXIncrementAction); - break; - case QAccessible::Decrease: - return CFStringRef(QAXDecrementAction); - break; - case QAccessible::Accept: - return CFStringRef(QAXConfirmAction); - break; - case QAccessible::Select: - return CFStringRef(QAXPickAction); - break; - case QAccessible::Cancel: - return CFStringRef(QAXCancelAction); - break; - default: - return QCFString(); - break; - } -} - -/* - Translates between a Mac action constant and a QAccessible::Action. - Returns QAccessible::Default action if there is no Qt predefined equivalent. -*/ -static QAccessible::Action translateAction(const CFStringRef actionName) -{ - if(CFStringCompare(actionName, CFStringRef(QAXPressAction), 0) == kCFCompareEqualTo) { - return QAccessible::Press; - } else if(CFStringCompare(actionName, CFStringRef(QAXIncrementAction), 0) == kCFCompareEqualTo) { - return QAccessible::Increase; - } else if(CFStringCompare(actionName, CFStringRef(QAXDecrementAction), 0) == kCFCompareEqualTo) { - return QAccessible::Decrease; - } else if(CFStringCompare(actionName, CFStringRef(QAXConfirmAction), 0) == kCFCompareEqualTo) { - return QAccessible::Accept; - } else if(CFStringCompare(actionName, CFStringRef(QAXPickAction), 0) == kCFCompareEqualTo) { - return QAccessible::Select; - } else if(CFStringCompare(actionName, CFStringRef(QAXCancelAction), 0) == kCFCompareEqualTo) { - return QAccessible::Cancel; - } else { - return QAccessible::DefaultAction; - } -} -#endif // QT_MAC_USE_COCOA - -/* - Copies the translated names all supported actions for an interface into the kEventParamAccessibleActionNames - event parameter. -*/ -#ifndef QT_MAC_USE_COCOA -static OSStatus getAllActionNames(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - Q_UNUSED(next_ref); - - CFMutableArrayRef actions = 0; - GetEventParameter(event, kEventParamAccessibleActionNames, typeCFMutableArrayRef, 0, - sizeof(actions), 0, &actions); - - // Add supported predefined actions. - const QList<QAccessible::Action> predefinedActions = supportedPredefinedActions(interface); - for (int i = 0; i < predefinedActions.count(); ++i) { - const QCFString action = translateAction(predefinedActions.at(i)); - if (action != QCFString()) - qt_mac_append_cf_uniq(actions, action); - } - - // Add user actions - const int actionCount = interface.userActionCount(); - for (int i = 0; i < actionCount; ++i) { - const QString actionName = interface.actionText(i, QAccessible::Name); - qt_mac_append_cf_uniq(actions, QCFString::toCFStringRef(actionName)); - } - - return noErr; -} -#endif - -/* - Handles the perforNamedAction event. -*/ -#ifndef QT_MAC_USE_COCOA -static OSStatus performNamedAction(EventHandlerCallRef next_ref, EventRef event, const QAInterface& interface) -{ - Q_UNUSED(next_ref); - - CFStringRef act; - GetEventParameter(event, kEventParamAccessibleActionName, typeCFStringRef, 0, - sizeof(act), 0, &act); - - const QAccessible::Action action = translateAction(act); - - // Perform built-in action - if (action != QAccessible::DefaultAction) { - interface.doAction(action, QVariantList()); - return noErr; - } - - // Search for user-defined actions and perform it if found. - const int actCount = interface.userActionCount(); - const QString qAct = QCFString::toQString(act); - for(int i = 0; i < actCount; i++) { - if(interface.actionText(i, QAccessible::Name) == qAct) { - interface.doAction(i, QVariantList()); - break; - } - } - return noErr; -} - -static OSStatus setNamedAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) -{ - Q_UNUSED(next_ref); - Q_UNUSED(event); - - CFStringRef var; - GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, - sizeof(var), 0, &var); - if(CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { - CFTypeRef val; - if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0, - sizeof(val), 0, &val) == noErr) { - if(CFGetTypeID(val) == CFBooleanGetTypeID() && - CFEqual(static_cast<CFBooleanRef>(val), kCFBooleanTrue)) { - interface.doAction(QAccessible::SetFocus); - } - } - } else { - bool found = false; - for(int r = 0; text_bindings[r][0].qt != -1; r++) { - if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) { - for(int a = 1; text_bindings[r][a].qt != -1; a++) { - if(CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) { - if(!text_bindings[r][a].settable) { - } else { - CFTypeRef val; - if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0, - sizeof(val), 0, &val) == noErr) { - if(CFGetTypeID(val) == CFStringGetTypeID()) - interface.setText((QAccessible::Text)text_bindings[r][a].qt, - QCFString::toQString(static_cast<CFStringRef>(val))); - - } - } - found = true; - break; - } - } - break; - } - } - } - return noErr; -} - -/* - This is the main accessibility event handler. -*/ -static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data) -{ - Q_UNUSED(data) - - // Return if this event is not a AccessibleGetNamedAttribute event. - const UInt32 eclass = GetEventClass(event); - if (eclass != kEventClassAccessibility) - return eventNotHandledErr; - - // Get the AXUIElementRef and QAInterface pointer - AXUIElementRef element = 0; - GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, sizeof(element), 0, &element); - QAInterface interface = accessibleHierarchyManager()->lookup(element); - if (interface.isValid() == false) - return eventNotHandledErr; - - const UInt32 ekind = GetEventKind(event); - OSStatus status = noErr; - switch (ekind) { - case kEventAccessibleGetAllAttributeNames: - status = getAllAttributeNames(event, interface, next_ref); - break; - case kEventAccessibleGetNamedAttribute: - status = getNamedAttribute(next_ref, event, interface); - break; - case kEventAccessibleIsNamedAttributeSettable: - status = isNamedAttributeSettable(event, interface); - break; - case kEventAccessibleGetChildAtPoint: - status = getChildAtPoint(next_ref, event, interface); - break; - case kEventAccessibleGetAllActionNames: - status = getAllActionNames(next_ref, event, interface); - break; - case kEventAccessibleGetFocusedChild: - status = CallNextEventHandler(next_ref, event); - break; - case kEventAccessibleSetNamedAttribute: - status = setNamedAttribute(next_ref, event, interface); - break; - case kEventAccessiblePerformNamedAction: - status = performNamedAction(next_ref, event, interface); - break; - default: - status = CallNextEventHandler(next_ref, event); - break; - }; - return status; -} -#endif - -void QAccessible::initialize() -{ -#ifndef QT_MAC_USE_COCOA - registerQtAccessibilityHIObjectSubclass(); - installApplicationEventhandler(); -#endif -} - -// Sets thre root object for the application -void QAccessible::setRootObject(QObject *object) -{ - // Call installed root object handler if we have one - if (rootObjectHandler) { - rootObjectHandler(object); - return; - } - - rootObject = object; -} - -void QAccessible::cleanup() -{ - accessibleHierarchyManager()->reset(); -#ifndef QT_MAC_USE_COCOA - removeEventhandler(applicationEventHandlerUPP); - removeEventhandler(objectCreateEventHandlerUPP); - removeEventhandler(accessibilityEventHandlerUPP); -#endif -} - -void QAccessible::updateAccessibility(QObject *object, int child, Event reason) -{ - // Call installed update handler if we have one. - if (updateHandler) { - updateHandler(object, child, reason); - return; - } - -#ifndef QT_MAC_USE_COCOA - // Return if the mac accessibility is not enabled. - if(!AXAPIEnabled()) - return; - - // Work around crash, disable accessiblity for focus frames. - if (qstrcmp(object->metaObject()->className(), "QFocusFrame") == 0) - return; - -// qDebug() << "updateAccessibility" << object << child << hex << reason; - - if (reason == ObjectShow) { - QAInterface interface = QAInterface(QAccessible::queryAccessibleInterface(object), child); - accessibleHierarchyManager()->registerInterface(interface); - } - - const QAElement element = accessibleHierarchyManager()->lookup(object, child); - if (element.isValid() == false) - return; - - - CFStringRef notification = 0; - if(object && object->isWidgetType() && reason == ObjectCreated) { - notification = CFStringRef(QAXWindowCreatedNotification); - } else if(reason == ValueChanged) { - notification = CFStringRef(QAXValueChangedNotification); - } else if(reason == MenuStart) { - notification = CFStringRef(QAXMenuOpenedNotification); - } else if(reason == MenuEnd) { - notification = CFStringRef(QAXMenuClosedNotification); - } else if(reason == LocationChanged) { - notification = CFStringRef(QAXWindowMovedNotification); - } else if(reason == ObjectShow || reason == ObjectHide ) { - // When a widget is deleted we get a ObjectHide before the destroyed(QObject *) - // signal is emitted (which makes sense). However, at this point we are in the - // middle of the QWidget destructor which means that we have to be careful when - // using the widget pointer. Since we can't control what the accessibilty interfaces - // does when navigate() is called below we ignore the hide update in this case. - // (the widget will be deleted soon anyway.) - extern QWidgetPrivate * qt_widget_private(QWidget *); - if (QWidget *widget = qobject_cast<QWidget*>(object)) { - if (qt_widget_private(widget)->data.in_destructor) - return; - - // Check widget parent as well, special case for preventing crash - // when the viewport() of an abstract scroll area is hidden when - // the QWidget destructor hides all its children. - QWidget *parentWidget = widget->parentWidget(); - if (parentWidget && qt_widget_private(parentWidget)->data.in_destructor) - return; - } - - // There is no equivalent Mac notification for ObjectShow/Hide, so we call HIObjectSetAccessibilityIgnored - // and isItIntersting which will mark the HIObject accociated with the element as ignored if the - // QAccessible::Invisible state bit is set. - QAInterface interface = accessibleHierarchyManager()->lookup(element); - if (interface.isValid()) { - HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(interface)); - } - - // If the interface manages its own children, also check if we should ignore those. - if (isItemView(interface) == false && managesChildren(interface)) { - for (int i = 1; i <= interface.childCount(); ++i) { - QAInterface childInterface = interface.navigate(QAccessible::Child, i); - if (childInterface.isValid() && childInterface.isHIView() == false) { - const QAElement element = accessibleHierarchyManager()->lookup(childInterface); - if (element.isValid()) { - HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(childInterface)); - } - } - } - } - - } else if(reason == Focus) { - if(object && object->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(object); - if(w->isWindow()) - notification = CFStringRef(QAXFocusedWindowChangedNotification); - else - notification = CFStringRef(QAXFocusedUIElementChangedNotification); - } - } - - if (!notification) - return; - - AXNotificationHIObjectNotify(notification, element.object(), element.id()); -#endif -} - -QT_END_NAMESPACE - -#endif // QT_NO_ACCESSIBILITY |