From 946805f07f9f8270d60df58f07bd8836b76d7258 Mon Sep 17 00:00:00 2001 From: Morten Sorvig Date: Tue, 11 Oct 2011 11:04:59 +0200 Subject: Cocoa: Add initial accessibility implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See qcocoaaccessiblity.h for details. For now only the first level of the hierarchy is made accessible. Also add tools/accessibilityinspector which is an utility for inspecting and debugging the Qt accessibility tree. Change-Id: Iff520bec26b3761feb0c2e00471feb379daaa735 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/cocoa.pro | 9 + src/plugins/platforms/cocoa/qcocoaaccessibility.h | 68 +++++++ src/plugins/platforms/cocoa/qcocoaaccessibility.mm | 113 ++++++++++++ .../platforms/cocoa/qcocoaaccessibilityelement.h | 65 +++++++ .../platforms/cocoa/qcocoaaccessibilityelement.mm | 197 +++++++++++++++++++++ src/plugins/platforms/cocoa/qnsview.h | 2 + src/plugins/platforms/cocoa/qnsview.mm | 32 +++- .../platforms/cocoa/qnsviewaccessibility.mm | 117 ++++++++++++ 8 files changed, 599 insertions(+), 4 deletions(-) create mode 100644 src/plugins/platforms/cocoa/qcocoaaccessibility.h create mode 100644 src/plugins/platforms/cocoa/qcocoaaccessibility.mm create mode 100644 src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h create mode 100644 src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm create mode 100644 src/plugins/platforms/cocoa/qnsviewaccessibility.mm (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 40d3323819..80149ae8d2 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -7,6 +7,7 @@ OBJECTIVE_SOURCES += main.mm \ qcocoabackingstore.mm \ qcocoawindow.mm \ qnsview.mm \ + qnsviewaccessibility.mm \ qcocoaautoreleasepool.mm \ qnswindowdelegate.mm \ qcocoaglcontext.mm \ @@ -19,6 +20,8 @@ OBJECTIVE_SOURCES += main.mm \ qmenu_mac.mm \ qcocoahelpers.mm \ qmultitouch_mac.mm \ + qcocoaaccessibilityelement.mm \ + qcocoaaccessibility.mm \ HEADERS += qcocoaintegration.h \ qcocoabackingstore.h \ @@ -36,6 +39,8 @@ HEADERS += qcocoaintegration.h \ qmenu_mac.h \ qcocoahelpers.h \ qmultitouch_mac_p.h \ + qcocoaaccessibilityelement.h \ + qcocoaaccessibility.h \ RESOURCES += qcocoaresources.qrc @@ -47,3 +52,7 @@ QT += core-private gui-private widgets-private platformsupport-private CONFIG += qpa/basicunixfontdatabase target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target + +# Acccessibility debug support +# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR +# include ($$PWD/../../../../tools/accessibilityinspector/accessibilityinspector.pri) diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h new file mode 100644 index 0000000000..7f4a840b15 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 plugins 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$ +** +****************************************************************************/ +#ifndef QCOCOAACCESIBILITY_H +#define QCOCOAACCESIBILITY_H + +#include + +#include + +/* + Qt Cocoa Accessibility Overview + + Cocoa accessibility is implemented in the following files: + + - qnsviewaccessibility : Root accessibility implementation for QNSView + - qcocoaaccessibilityelement : Cocoa accessibility protocol wrapper for QAccessibleInterface + - qcocoaaccessibility (this file) : Conversion and helper functions. + + The accessibility implementation wraps QAccessibleInterfaces in QCocoaAccessibleElements, which + implements the cocoa accessibility protocol. The root QAccessibleInterface (the one returned + by QWindow::accessibleRoot), is anchored to the QNSView in qnsviewaccessibility.mm. + + Cocoa explores the accessibility tree by walking the tree using the parent/child + relationships or hit testing. When this happens we create QCocoaAccessibleElements on + demand. +*/ + +NSString *macRole(QAccessible::Role); + +#endif diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm new file mode 100644 index 0000000000..a2ce743804 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -0,0 +1,113 @@ +/**************************************************************************** + ** + ** 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 plugins 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 "qcocoaaccessibility.h" + +typedef QMap QMacAccessibiltyRoleMap; +Q_GLOBAL_STATIC(QMacAccessibiltyRoleMap, qMacAccessibiltyRoleMap); + +static void populateRoleMap() +{ + QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap(); + roleMap[QAccessible::MenuItem] = NSAccessibilityMenuItemRole; + roleMap[QAccessible::MenuBar] = NSAccessibilityMenuBarRole; + roleMap[QAccessible::ScrollBar] = NSAccessibilityScrollBarRole; + roleMap[QAccessible::Grip] = NSAccessibilityGrowAreaRole; + roleMap[QAccessible::Window] = NSAccessibilityWindowRole; + roleMap[QAccessible::Dialog] = NSAccessibilityWindowRole; + roleMap[QAccessible::AlertMessage] = NSAccessibilityWindowRole; + roleMap[QAccessible::ToolTip] = NSAccessibilityWindowRole; + roleMap[QAccessible::HelpBalloon] = NSAccessibilityWindowRole; + roleMap[QAccessible::PopupMenu] = NSAccessibilityMenuRole; + roleMap[QAccessible::Application] = NSAccessibilityApplicationRole; + roleMap[QAccessible::Pane] = NSAccessibilityGroupRole; + roleMap[QAccessible::Grouping] = NSAccessibilityGroupRole; + roleMap[QAccessible::Separator] = NSAccessibilitySplitterRole; + roleMap[QAccessible::ToolBar] = NSAccessibilityToolbarRole; + roleMap[QAccessible::PageTab] = NSAccessibilityRadioButtonRole; + roleMap[QAccessible::ButtonMenu] = NSAccessibilityMenuButtonRole; + roleMap[QAccessible::ButtonDropDown] = NSAccessibilityPopUpButtonRole; + roleMap[QAccessible::SpinBox] = NSAccessibilityIncrementorRole; + roleMap[QAccessible::Slider] = NSAccessibilitySliderRole; + roleMap[QAccessible::ProgressBar] = NSAccessibilityProgressIndicatorRole; + roleMap[QAccessible::ComboBox] = NSAccessibilityPopUpButtonRole; + roleMap[QAccessible::RadioButton] = NSAccessibilityRadioButtonRole; + roleMap[QAccessible::CheckBox] = NSAccessibilityCheckBoxRole; + roleMap[QAccessible::StaticText] = NSAccessibilityStaticTextRole; + roleMap[QAccessible::Table] = NSAccessibilityTableRole; + roleMap[QAccessible::StatusBar] = NSAccessibilityStaticTextRole; + roleMap[QAccessible::Column] = NSAccessibilityColumnRole; + roleMap[QAccessible::ColumnHeader] = NSAccessibilityColumnRole; + roleMap[QAccessible::Row] = NSAccessibilityRowRole; + roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole; + roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole; + roleMap[QAccessible::PushButton] = NSAccessibilityButtonRole; + roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole; + roleMap[QAccessible::Link] = NSAccessibilityTextFieldRole; + roleMap[QAccessible::Indicator] = NSAccessibilityValueIndicatorRole; + roleMap[QAccessible::Splitter] = NSAccessibilitySplitGroupRole; + roleMap[QAccessible::List] = NSAccessibilityListRole; + roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole; + roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole; + roleMap[QAccessible::Client] = NSAccessibilityGroupRole; +} + +/* + Returns a Mac accessibility role for the given interface, or + NSAccessibilityUnknownRole if no role mapping is found. +*/ +NSString *macRole(QAccessible::Role qtRole) +{ + QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap(); + + if (roleMap.isEmpty()) + populateRoleMap(); + + // MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << hex << qtRole; + + if (roleMap.contains(qtRole)) { + // MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole]; + return roleMap[qtRole]; + } + + // MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityUnknownRole"; + return NSAccessibilityUnknownRole; +} + diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h new file mode 100644 index 0000000000..76509f9e43 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 plugins 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$ +** +****************************************************************************/ +#ifndef QCOCOAACCESIBILITYELEMENT_H +#define QCOCOAACCESIBILITYELEMENT_H + + +#import +#import + +@class QCocoaAccessibleElement; + +@interface QCocoaAccessibleElement : NSObject { + NSUInteger index; + NSString *role; + NSObject * parent; + void *accessibleInterface; + +} + +- (id)initWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface; ++ (QCocoaAccessibleElement *)elementWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface; +- (NSUInteger)index; + +@end + +#endif + diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm new file mode 100644 index 0000000000..4ce41307e7 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -0,0 +1,197 @@ +/**************************************************************************** + ** + ** 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 plugins 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 "qcocoaaccessibilityelement.h" +#include "qcocoaaccessibility.h" +#include "qcocoahelpers.h" + +#include +#include "QAccessibleActionInterface" + +#import + +static QAccessibleInterface *acast(void *ptr) +{ + return reinterpret_cast(ptr); +} + +@implementation QCocoaAccessibleElement + +- (id)initWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface +{ + self = [super init]; + if (self) { + index = aIndex; + accessibleInterface = anQAccessibleInterface; + role = macRole(acast(accessibleInterface)->role()); + parent = aParent; + + } + + return self; +} + ++ (QCocoaAccessibleElement *)elementWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface +{ + return [[[self alloc] initWithIndex:aIndex parent:aParent accessibleInterface:anQAccessibleInterface] autorelease]; +} + +- (void)dealloc { + [super dealloc]; +} + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[QCocoaAccessibleElement class]]) { + QCocoaAccessibleElement *other = object; + return (index == other->index) && [role isEqualToString:other->role] && [parent isEqual:other->parent]; + } else + return NO; +} + +- (NSUInteger)hash { + return [parent hash] + index; +} + +- (NSUInteger)index { + return index; +} + +// +// accessibility protocol +// + +// attributes + +- (NSArray *)accessibilityAttributeNames { + static NSArray *attributes = nil; + if (attributes == nil) { + attributes = [[NSArray alloc] initWithObjects: + NSAccessibilityRoleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityFocusedAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityWindowAttribute, + NSAccessibilityTopLevelUIElementAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilitySizeAttribute, + NSAccessibilityDescriptionAttribute, + nil]; + } + return attributes; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { + return role; + } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { + return NSAccessibilityRoleDescription(role, nil); + } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + // Just check if the app thinks we're focused. + id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute]; + return [NSNumber numberWithBool:[focusedElement isEqual:self]]; + } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) { + return NSAccessibilityUnignoredAncestor(parent); + } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) { + // We're in the same window as our parent. + return [parent accessibilityAttributeValue:NSAccessibilityWindowAttribute]; + } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) { + // We're in the same top level element as our parent. + return [parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; + } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { + QPoint qtPosition = acast(accessibleInterface)->rect().topLeft(); + QSize qtSize = acast(accessibleInterface)->rect().size(); + return [NSValue valueWithPoint: NSMakePoint(qtPosition.x(), qt_mac_flipYCoordinate(qtPosition.y() + qtSize.height()))]; + } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { + QSize qtSize = acast(accessibleInterface)->rect().size(); + return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())]; + } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) { + return qt_mac_QStringToNSString(acast(accessibleInterface)->text(QAccessible::Name)); + } + + return nil; +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + return NO; // YES to handle keyboard input + } else { + return NO; + } +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { + Q_UNUSED(value); + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + + } +} + +// actions + +- (NSArray *)accessibilityActionNames { + return [NSArray arrayWithObject:NSAccessibilityPressAction]; +} + +- (NSString *)accessibilityActionDescription:(NSString *)action { + return NSAccessibilityActionDescription(action); +} + +- (void)accessibilityPerformAction:(NSString *)action { + Q_UNUSED(action); + if (acast(accessibleInterface)->actionInterface()) + acast(accessibleInterface)->actionInterface()->doAction(0); +} + +// misc + +- (BOOL)accessibilityIsIgnored { + return NO; +} + +- (id)accessibilityHitTest:(NSPoint)point { + Q_UNUSED(point); + return NSAccessibilityUnignoredAncestor(self); +} + +- (id)accessibilityFocusedUIElement { + return NSAccessibilityUnignoredAncestor(self); +} + +@end diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 0b96928d5b..eddc1aa7e9 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -45,11 +45,13 @@ #include #include +#include @interface QNSView : NSView { CGImageRef m_cgImage; QWindow *m_window; Qt::MouseButtons m_buttons; + QAccessibleInterface *m_accessibleRoot; } - (id)init; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 67bc61c63b..664b87607a 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -48,6 +48,10 @@ #include #include +#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR +#include +#endif + @interface NSEvent (Qt_Compile_Leopard_DeviceDelta) - (CGFloat)deviceDeltaX; - (CGFloat)deviceDeltaY; @@ -58,7 +62,7 @@ - (id) init { - self = [super init]; + self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; if (self) { m_cgImage = 0; m_window = 0; @@ -67,11 +71,31 @@ return self; } -- (id)initWithQWindow:(QWindow *)widget { +- (id)initWithQWindow:(QWindow *)window { self = [self init]; - if (self) { - m_window = widget; + if (!self) + return 0; + + m_window = window; + m_accessibleRoot = 0; + +#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR + // prevent rift in space-time continuum, disable + // accessibility for the accessibility inspector's windows. + static bool skipAccessibilityForInspectorWindows = false; + if (!skipAccessibilityForInspectorWindows) { + + m_accessibleRoot = window->accessibleRoot(); + + AccessibilityInspector *inspector = new AccessibilityInspector(window); + skipAccessibilityForInspectorWindows = true; + inspector->inspectWindow(window); + skipAccessibilityForInspectorWindows = false; } +#else + m_accessibleRoot = window->accessibleRoot(); +#endif + return self; } diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm new file mode 100644 index 0000000000..327bace123 --- /dev/null +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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 plugins 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 + +#include "qnsview.h" +#include "qcocoahelpers.h" +#include "qcocoaaccessibility.h" +#include "qcocoaaccessibilityelement.h" + +#include "QAccessibleActionInterface" +#include + +#import + +@implementation QNSView (QNSViewAccessibility) + +- (BOOL)accessibilityIsIgnored { + return NO; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { + if (m_accessibleRoot) + return macRole(m_accessibleRoot->role()); + return NSAccessibilityUnknownRole; + } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { + return NSAccessibilityRoleDescriptionForUIElement(self); + } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + if (!m_accessibleRoot) + return [super accessibilityAttributeValue:attribute]; + + // Create QCocoaAccessibleElements for each child if the + // root accessible interface. + int numKids = m_accessibleRoot->childCount(); + NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids]; + for (int i = 0; i < numKids; ++i) { + [kids addObject:[QCocoaAccessibleElement elementWithIndex:i parent:self accessibleInterface:(void*)m_accessibleRoot->child(i)]]; + } + + return NSAccessibilityUnignoredChildren(kids); + } else { + return [super accessibilityAttributeValue:attribute]; + } +} + +- (id)accessibilityHitTest:(NSPoint)point { + NSPoint windowPoint = [[self window] convertScreenToBase:point]; + NSPoint localPoint = [self convertPoint:windowPoint fromView:nil]; + + int index = -1; + if (m_accessibleRoot) { + index = m_accessibleRoot->childAt(point.x, qt_mac_flipYCoordinate(point.y)); + + // qDebug() << "root rect" << m_accessibleRoot->rect(); + // qDebug() << "hit screen" << point.x << qt_mac_flipYCoordinate(point.y) << index; + // if (index > 0) { + // qDebug() << "child name" << m_accessibleRoot->child(index - 1)->text(QAccessible::Name); + // qDebug() << "child rect" << m_accessibleRoot->child(index - 1)->rect(); + // } + } + + // hit outside + if (index == -1) { + return [super accessibilityHitTest:point]; + } + + // hit the NSView / top-level window + if (index == 0) { + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithIndex:index parent:self accessibleInterface:(void*)m_accessibleRoot]; + return [accessibleElement accessibilityHitTest:point]; + } + + // hit a child, forward to child accessible interface. + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithIndex:index - 1 parent:self accessibleInterface:(void*)m_accessibleRoot->child(index -1)]; + return [accessibleElement accessibilityHitTest:point]; +} + +@end -- cgit v1.2.3