| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com)
|
|---|
| 5 | **
|
|---|
| 6 | ** This file is part of the QtGui module of the Qt Toolkit.
|
|---|
| 7 | **
|
|---|
| 8 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 9 | ** Commercial Usage
|
|---|
| 10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 11 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 12 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 13 | ** a written agreement between you and Nokia.
|
|---|
| 14 | **
|
|---|
| 15 | ** GNU Lesser General Public License Usage
|
|---|
| 16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 17 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 19 | ** packaging of this file. Please review the following information to
|
|---|
| 20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 22 | **
|
|---|
| 23 | ** In addition, as a special exception, Nokia gives you certain
|
|---|
| 24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
|---|
| 25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|---|
| 26 | ** package.
|
|---|
| 27 | **
|
|---|
| 28 | ** GNU General Public License Usage
|
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 32 | ** packaging of this file. Please review the following information to
|
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 35 | **
|
|---|
| 36 | ** If you are unsure which license is appropriate for your use, please
|
|---|
| 37 | ** contact the sales department at qt-sales@nokia.com.
|
|---|
| 38 | ** $QT_END_LICENSE$
|
|---|
| 39 | **
|
|---|
| 40 | ****************************************************************************/
|
|---|
| 41 |
|
|---|
| 42 | #include "qaccessible.h"
|
|---|
| 43 |
|
|---|
| 44 | #ifndef QT_NO_ACCESSIBILITY
|
|---|
| 45 | #include "qaccessible_mac_p.h"
|
|---|
| 46 | #include "qhash.h"
|
|---|
| 47 | #include "qset.h"
|
|---|
| 48 | #include "qpointer.h"
|
|---|
| 49 | #include "qapplication.h"
|
|---|
| 50 | #include "qmainwindow.h"
|
|---|
| 51 | #include "qtextdocument.h"
|
|---|
| 52 | #include "qdebug.h"
|
|---|
| 53 | #include "qabstractslider.h"
|
|---|
| 54 | #include "qsplitter.h"
|
|---|
| 55 | #include "qtabwidget.h"
|
|---|
| 56 | #include "qlistview.h"
|
|---|
| 57 | #include "qtableview.h"
|
|---|
| 58 | #include "qdockwidget.h"
|
|---|
| 59 |
|
|---|
| 60 | #include <private/qt_mac_p.h>
|
|---|
| 61 | #include <private/qwidget_p.h>
|
|---|
| 62 | #include <CoreFoundation/CoreFoundation.h>
|
|---|
| 63 |
|
|---|
| 64 | QT_BEGIN_NAMESPACE
|
|---|
| 65 |
|
|---|
| 66 | /*
|
|---|
| 67 | Set up platform defines. There is a one-to-one correspondence between the
|
|---|
| 68 | Carbon and Cocoa roles and attributes, but the prefix and type changes.
|
|---|
| 69 | */
|
|---|
| 70 | #ifdef QT_MAC_USE_COCOA
|
|---|
| 71 | typedef NSString * const QAXRoleType;
|
|---|
| 72 | #define QAXApplicationRole NSAccessibilityApplicationRole
|
|---|
| 73 | #define QAXButtonRole NSAccessibilityButtonRole
|
|---|
| 74 | #define QAXCancelAction NSAccessibilityCancelAction
|
|---|
| 75 | #define QAXCheckBoxRole NSAccessibilityCheckBoxRole
|
|---|
| 76 | #define QAXChildrenAttribute NSAccessibilityChildrenAttribute
|
|---|
| 77 | #define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
|
|---|
| 78 | #define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
|
|---|
| 79 | #define QAXColumnRole NSAccessibilityColumnRole
|
|---|
| 80 | #define QAXConfirmAction NSAccessibilityConfirmAction
|
|---|
| 81 | #define QAXContentsAttribute NSAccessibilityContentsAttribute
|
|---|
| 82 | #define QAXDecrementAction NSAccessibilityDecrementAction
|
|---|
| 83 | #define QAXDecrementArrowSubrole NSAccessibilityDecrementArrowSubrole
|
|---|
| 84 | #define QAXDecrementPageSubrole NSAccessibilityDecrementPageSubrole
|
|---|
| 85 | #define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute
|
|---|
| 86 | #define QAXEnabledAttribute NSAccessibilityEnabledAttribute
|
|---|
| 87 | #define QAXExpandedAttribute NSAccessibilityExpandedAttribute
|
|---|
| 88 | #define QAXFocusedAttribute NSAccessibilityFocusedAttribute
|
|---|
| 89 | #define QAXFocusedUIElementChangedNotification NSAccessibilityFocusedUIElementChangedNotification
|
|---|
| 90 | #define QAXFocusedWindowChangedNotification NSAccessibilityFocusedWindowChangedNotification
|
|---|
| 91 | #define QAXGroupRole NSAccessibilityGroupRole
|
|---|
| 92 | #define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute
|
|---|
| 93 | #define QAXGrowAreaRole NSAccessibilityGrowAreaRole
|
|---|
| 94 | #define QAXHelpAttribute NSAccessibilityHelpAttribute
|
|---|
| 95 | #define QAXHorizontalOrientationValue NSAccessibilityHorizontalOrientationValue
|
|---|
| 96 | #define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute
|
|---|
| 97 | #define QAXIncrementAction NSAccessibilityIncrementAction
|
|---|
| 98 | #define QAXIncrementArrowSubrole NSAccessibilityIncrementArrowSubrole
|
|---|
| 99 | #define QAXIncrementPageSubrole NSAccessibilityIncrementPageSubrole
|
|---|
| 100 | #define QAXIncrementorRole NSAccessibilityIncrementorRole
|
|---|
| 101 | #define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute
|
|---|
| 102 | #define QAXListRole NSAccessibilityListRole
|
|---|
| 103 | #define QAXMainAttribute NSAccessibilityMainAttribute
|
|---|
| 104 | #define QAXMaxValueAttribute NSAccessibilityMaxValueAttribute
|
|---|
| 105 | #define QAXMenuBarRole NSAccessibilityMenuBarRole
|
|---|
| 106 | #define QAXMenuButtonRole NSAccessibilityMenuButtonRole
|
|---|
| 107 | #define QAXMenuClosedNotification NSAccessibilityMenuClosedNotification
|
|---|
| 108 | #define QAXMenuItemRole NSAccessibilityMenuItemRole
|
|---|
| 109 | #define QAXMenuOpenedNotification NSAccessibilityMenuOpenedNotification
|
|---|
| 110 | #define QAXMenuRole NSAccessibilityMenuRole
|
|---|
| 111 | #define QAXMinValueAttribute NSAccessibilityMinValueAttribute
|
|---|
| 112 | #define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute
|
|---|
| 113 | #define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute
|
|---|
| 114 | #define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute
|
|---|
| 115 | #define QAXOrientationAttribute NSAccessibilityOrientationAttribute
|
|---|
| 116 | #define QAXParentAttribute NSAccessibilityParentAttribute
|
|---|
| 117 | #define QAXPickAction NSAccessibilityPickAction
|
|---|
| 118 | #define QAXPopUpButtonRole NSAccessibilityPopUpButtonRole
|
|---|
| 119 | #define QAXPositionAttribute NSAccessibilityPositionAttribute
|
|---|
| 120 | #define QAXPressAction NSAccessibilityPressAction
|
|---|
| 121 | #define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute
|
|---|
| 122 | #define QAXProgressIndicatorRole NSAccessibilityProgressIndicatorRole
|
|---|
| 123 | #define QAXRadioButtonRole NSAccessibilityRadioButtonRole
|
|---|
| 124 | #define QAXRoleAttribute NSAccessibilityRoleAttribute
|
|---|
| 125 | #define QAXRoleDescriptionAttribute NSAccessibilityRoleDescriptionAttribute
|
|---|
| 126 | #define QAXRowRole NSAccessibilityRowRole
|
|---|
| 127 | #define QAXRowsAttribute NSAccessibilityRowsAttribute
|
|---|
| 128 | #define QAXScrollAreaRole NSAccessibilityScrollAreaRole
|
|---|
| 129 | #define QAXScrollBarRole NSAccessibilityScrollBarRole
|
|---|
| 130 | #define QAXSelectedAttribute NSAccessibilitySelectedAttribute
|
|---|
| 131 | #define QAXSelectedChildrenAttribute NSAccessibilitySelectedChildrenAttribute
|
|---|
| 132 | #define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute
|
|---|
| 133 | #define QAXSizeAttribute NSAccessibilitySizeAttribute
|
|---|
| 134 | #define QAXSliderRole NSAccessibilitySliderRole
|
|---|
| 135 | #define QAXSplitGroupRole NSAccessibilitySplitGroupRole
|
|---|
| 136 | #define QAXSplitterRole NSAccessibilitySplitterRole
|
|---|
| 137 | #define QAXSplittersAttribute NSAccessibilitySplittersAttribute
|
|---|
| 138 | #define QAXStaticTextRole NSAccessibilityStaticTextRole
|
|---|
| 139 | #define QAXSubroleAttribute NSAccessibilitySubroleAttribute
|
|---|
| 140 | #define QAXSubroleAttribute NSAccessibilitySubroleAttribute
|
|---|
| 141 | #define QAXTabGroupRole NSAccessibilityTabGroupRole
|
|---|
| 142 | #define QAXTableRole NSAccessibilityTableRole
|
|---|
| 143 | #define QAXTabsAttribute NSAccessibilityTabsAttribute
|
|---|
| 144 | #define QAXTextFieldRole NSAccessibilityTextFieldRole
|
|---|
| 145 | #define QAXTitleAttribute NSAccessibilityTitleAttribute
|
|---|
| 146 | #define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute
|
|---|
| 147 | #define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute
|
|---|
| 148 | #define QAXToolbarRole NSAccessibilityToolbarRole
|
|---|
| 149 | #define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute
|
|---|
| 150 | #define QAXUnknownRole NSAccessibilityUnknownRole
|
|---|
| 151 | #define QAXValueAttribute NSAccessibilityValueAttribute
|
|---|
| 152 | #define QAXValueChangedNotification NSAccessibilityValueChangedNotification
|
|---|
| 153 | #define QAXValueIndicatorRole NSAccessibilityValueIndicatorRole
|
|---|
| 154 | #define QAXVerticalOrientationValue NSAccessibilityVerticalOrientationValue
|
|---|
| 155 | #define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute
|
|---|
| 156 | #define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute
|
|---|
| 157 | #define QAXWindowAttribute NSAccessibilityWindowAttribute
|
|---|
| 158 | #define QAXWindowCreatedNotification NSAccessibilityWindowCreatedNotification
|
|---|
| 159 | #define QAXWindowMovedNotification NSAccessibilityWindowMovedNotification
|
|---|
| 160 | #define QAXWindowRole NSAccessibilityWindowRole
|
|---|
| 161 | #define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute
|
|---|
| 162 | #else
|
|---|
| 163 | typedef CFStringRef const QAXRoleType;
|
|---|
| 164 | #define QAXApplicationRole kAXApplicationRole
|
|---|
| 165 | #define QAXButtonRole kAXButtonRole
|
|---|
| 166 | #define QAXCancelAction kAXCancelAction
|
|---|
| 167 | #define QAXCheckBoxRole kAXCheckBoxRole
|
|---|
| 168 | #define QAXChildrenAttribute kAXChildrenAttribute
|
|---|
| 169 | #define QAXCloseButtonAttribute kAXCloseButtonAttribute
|
|---|
| 170 | #define QAXColumnRole kAXColumnRole
|
|---|
| 171 | #define QAXConfirmAction kAXConfirmAction
|
|---|
| 172 | #define QAXContentsAttribute kAXContentsAttribute
|
|---|
| 173 | #define QAXDecrementAction kAXDecrementAction
|
|---|
| 174 | #define QAXDecrementArrowSubrole kAXDecrementArrowSubrole
|
|---|
| 175 | #define QAXDecrementPageSubrole kAXDecrementPageSubrole
|
|---|
| 176 | #define QAXDescriptionAttribute kAXDescriptionAttribute
|
|---|
| 177 | #define QAXEnabledAttribute kAXEnabledAttribute
|
|---|
| 178 | #define QAXExpandedAttribute kAXExpandedAttribute
|
|---|
| 179 | #define QAXFocusedAttribute kAXFocusedAttribute
|
|---|
| 180 | #define QAXFocusedUIElementChangedNotification kAXFocusedUIElementChangedNotification
|
|---|
| 181 | #define QAXFocusedWindowChangedNotification kAXFocusedWindowChangedNotification
|
|---|
| 182 | #define QAXGroupRole kAXGroupRole
|
|---|
| 183 | #define QAXGrowAreaAttribute kAXGrowAreaAttribute
|
|---|
| 184 | #define QAXGrowAreaRole kAXGrowAreaRole
|
|---|
| 185 | #define QAXHelpAttribute kAXHelpAttribute
|
|---|
| 186 | #define QAXHorizontalOrientationValue kAXHorizontalOrientationValue
|
|---|
| 187 | #define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute
|
|---|
| 188 | #define QAXIncrementAction kAXIncrementAction
|
|---|
| 189 | #define QAXIncrementArrowSubrole kAXIncrementArrowSubrole
|
|---|
| 190 | #define QAXIncrementPageSubrole kAXIncrementPageSubrole
|
|---|
| 191 | #define QAXIncrementorRole kAXIncrementorRole
|
|---|
| 192 | #define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute
|
|---|
| 193 | #define QAXListRole kAXListRole
|
|---|
| 194 | #define QAXMainAttribute kAXMainAttribute
|
|---|
| 195 | #define QAXMaxValueAttribute kAXMaxValueAttribute
|
|---|
| 196 | #define QAXMenuBarRole kAXMenuBarRole
|
|---|
| 197 | #define QAXMenuButtonRole kAXMenuButtonRole
|
|---|
| 198 | #define QAXMenuClosedNotification kAXMenuClosedNotification
|
|---|
| 199 | #define QAXMenuItemRole kAXMenuItemRole
|
|---|
| 200 | #define QAXMenuOpenedNotification kAXMenuOpenedNotification
|
|---|
| 201 | #define QAXMenuRole kAXMenuRole
|
|---|
| 202 | #define QAXMinValueAttribute kAXMinValueAttribute
|
|---|
| 203 | #define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute
|
|---|
| 204 | #define QAXMinimizedAttribute kAXMinimizedAttribute
|
|---|
| 205 | #define QAXNextContentsAttribute kAXNextContentsAttribute
|
|---|
| 206 | #define QAXOrientationAttribute kAXOrientationAttribute
|
|---|
| 207 | #define QAXParentAttribute kAXParentAttribute
|
|---|
| 208 | #define QAXPickAction kAXPickAction
|
|---|
| 209 | #define QAXPopUpButtonRole kAXPopUpButtonRole
|
|---|
| 210 | #define QAXPositionAttribute kAXPositionAttribute
|
|---|
| 211 | #define QAXPressAction kAXPressAction
|
|---|
| 212 | #define QAXPreviousContentsAttribute kAXPreviousContentsAttribute
|
|---|
| 213 | #define QAXProgressIndicatorRole kAXProgressIndicatorRole
|
|---|
| 214 | #define QAXRadioButtonRole kAXRadioButtonRole
|
|---|
| 215 | #define QAXRoleAttribute kAXRoleAttribute
|
|---|
| 216 | #define QAXRoleDescriptionAttribute kAXRoleDescriptionAttribute
|
|---|
| 217 | #define QAXRowRole kAXRowRole
|
|---|
| 218 | #define QAXRowsAttribute kAXRowsAttribute
|
|---|
| 219 | #define QAXScrollAreaRole kAXScrollAreaRole
|
|---|
| 220 | #define QAXScrollBarRole kAXScrollBarRole
|
|---|
| 221 | #define QAXSelectedAttribute kAXSelectedAttribute
|
|---|
| 222 | #define QAXSelectedChildrenAttribute kAXSelectedChildrenAttribute
|
|---|
| 223 | #define QAXSelectedRowsAttribute kAXSelectedRowsAttribute
|
|---|
| 224 | #define QAXSizeAttribute kAXSizeAttribute
|
|---|
| 225 | #define QAXSliderRole kAXSliderRole
|
|---|
| 226 | #define QAXSplitGroupRole kAXSplitGroupRole
|
|---|
| 227 | #define QAXSplitterRole kAXSplitterRole
|
|---|
| 228 | #define QAXSplittersAttribute kAXSplittersAttribute
|
|---|
| 229 | #define QAXStaticTextRole kAXStaticTextRole
|
|---|
| 230 | #define QAXSubroleAttribute kAXSubroleAttribute
|
|---|
| 231 | #define QAXTabGroupRole kAXTabGroupRole
|
|---|
| 232 | #define QAXTableRole kAXTableRole
|
|---|
| 233 | #define QAXTabsAttribute kAXTabsAttribute
|
|---|
| 234 | #define QAXTextFieldRole kAXTextFieldRole
|
|---|
| 235 | #define QAXTitleAttribute kAXTitleAttribute
|
|---|
| 236 | #define QAXTitleUIElementAttribute kAXTitleUIElementAttribute
|
|---|
| 237 | #define QAXToolbarButtonAttribute kAXToolbarButtonAttribute
|
|---|
| 238 | #define QAXToolbarRole kAXToolbarRole
|
|---|
| 239 | #define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute
|
|---|
| 240 | #define QAXUnknownRole kAXUnknownRole
|
|---|
| 241 | #define QAXValueAttribute kAXValueAttribute
|
|---|
| 242 | #define QAXValueChangedNotification kAXValueChangedNotification
|
|---|
| 243 | #define QAXValueIndicatorRole kAXValueIndicatorRole
|
|---|
| 244 | #define QAXVerticalOrientationValue kAXVerticalOrientationValue
|
|---|
| 245 | #define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute
|
|---|
| 246 | #define QAXVisibleRowsAttribute kAXVisibleRowsAttribute
|
|---|
| 247 | #define QAXWindowAttribute kAXWindowAttribute
|
|---|
| 248 | #define QAXWindowCreatedNotification kAXWindowCreatedNotification
|
|---|
| 249 | #define QAXWindowMovedNotification kAXWindowMovedNotification
|
|---|
| 250 | #define QAXWindowRole kAXWindowRole
|
|---|
| 251 | #define QAXZoomButtonAttribute kAXZoomButtonAttribute
|
|---|
| 252 | #endif
|
|---|
| 253 |
|
|---|
| 254 |
|
|---|
| 255 | /*****************************************************************************
|
|---|
| 256 | Externals
|
|---|
| 257 | *****************************************************************************/
|
|---|
| 258 | extern bool qt_mac_is_macsheet(const QWidget *w); //qwidget_mac.cpp
|
|---|
| 259 | extern bool qt_mac_is_macdrawer(const QWidget *w); //qwidget_mac.cpp
|
|---|
| 260 |
|
|---|
| 261 | /*****************************************************************************
|
|---|
| 262 | QAccessible Bindings
|
|---|
| 263 | *****************************************************************************/
|
|---|
| 264 | //hardcoded bindings between control info and (known) QWidgets
|
|---|
| 265 | struct QAccessibleTextBinding {
|
|---|
| 266 | int qt;
|
|---|
| 267 | QAXRoleType mac;
|
|---|
| 268 | bool settable;
|
|---|
| 269 | } text_bindings[][10] = {
|
|---|
| 270 | { { QAccessible::MenuItem, QAXMenuItemRole, false },
|
|---|
| 271 | { -1, 0, false }
|
|---|
| 272 | },
|
|---|
| 273 | { { QAccessible::MenuBar, QAXMenuBarRole, false },
|
|---|
| 274 | { -1, 0, false }
|
|---|
| 275 | },
|
|---|
| 276 | { { QAccessible::ScrollBar, QAXScrollBarRole, false },
|
|---|
| 277 | { -1, 0, false }
|
|---|
| 278 | },
|
|---|
| 279 | { { QAccessible::Grip, QAXGrowAreaRole, false },
|
|---|
| 280 | { -1, 0, false }
|
|---|
| 281 | },
|
|---|
| 282 | { { QAccessible::Window, QAXWindowRole, false },
|
|---|
| 283 | { -1, 0, false }
|
|---|
| 284 | },
|
|---|
| 285 | { { QAccessible::Dialog, QAXWindowRole, false },
|
|---|
| 286 | { -1, 0, false }
|
|---|
| 287 | },
|
|---|
| 288 | { { QAccessible::AlertMessage, QAXWindowRole, false },
|
|---|
| 289 | { -1, 0, false }
|
|---|
| 290 | },
|
|---|
| 291 | { { QAccessible::ToolTip, QAXWindowRole, false },
|
|---|
| 292 | { -1, 0, false }
|
|---|
| 293 | },
|
|---|
| 294 | { { QAccessible::HelpBalloon, QAXWindowRole, false },
|
|---|
| 295 | { -1, 0, false }
|
|---|
| 296 | },
|
|---|
| 297 | { { QAccessible::PopupMenu, QAXMenuRole, false },
|
|---|
| 298 | { -1, 0, false }
|
|---|
| 299 | },
|
|---|
| 300 | { { QAccessible::Application, QAXApplicationRole, false },
|
|---|
| 301 | { -1, 0, false }
|
|---|
| 302 | },
|
|---|
| 303 | { { QAccessible::Pane, QAXGroupRole, false },
|
|---|
| 304 | { -1, 0, false }
|
|---|
| 305 | },
|
|---|
| 306 | { { QAccessible::Grouping, QAXGroupRole, false },
|
|---|
| 307 | { -1, 0, false }
|
|---|
| 308 | },
|
|---|
| 309 | { { QAccessible::Separator, QAXSplitterRole, false },
|
|---|
| 310 | { -1, 0, false }
|
|---|
| 311 | },
|
|---|
| 312 | { { QAccessible::ToolBar, QAXToolbarRole, false },
|
|---|
| 313 | { -1, 0, false }
|
|---|
| 314 | },
|
|---|
| 315 | { { QAccessible::PageTab, QAXRadioButtonRole, false },
|
|---|
| 316 | { -1, 0, false }
|
|---|
| 317 | },
|
|---|
| 318 | { { QAccessible::ButtonMenu, QAXMenuButtonRole, false },
|
|---|
| 319 | { -1, 0, false }
|
|---|
| 320 | },
|
|---|
| 321 | { { QAccessible::ButtonDropDown, QAXPopUpButtonRole, false },
|
|---|
| 322 | { -1, 0, false }
|
|---|
| 323 | },
|
|---|
| 324 | { { QAccessible::SpinBox, QAXIncrementorRole, false },
|
|---|
| 325 | { -1, 0, false }
|
|---|
| 326 | },
|
|---|
| 327 | { { QAccessible::Slider, QAXSliderRole, false },
|
|---|
| 328 | { -1, 0, false }
|
|---|
| 329 | },
|
|---|
| 330 | { { QAccessible::ProgressBar, QAXProgressIndicatorRole, false },
|
|---|
| 331 | { -1, 0, false }
|
|---|
| 332 | },
|
|---|
| 333 | { { QAccessible::ComboBox, QAXPopUpButtonRole, false },
|
|---|
| 334 | { -1, 0, false }
|
|---|
| 335 | },
|
|---|
| 336 | { { QAccessible::RadioButton, QAXRadioButtonRole, false },
|
|---|
| 337 | { -1, 0, false }
|
|---|
| 338 | },
|
|---|
| 339 | { { QAccessible::CheckBox, QAXCheckBoxRole, false },
|
|---|
| 340 | { -1, 0, false }
|
|---|
| 341 | },
|
|---|
| 342 | { { QAccessible::StaticText, QAXStaticTextRole, false },
|
|---|
| 343 | { QAccessible::Name, QAXValueAttribute, false },
|
|---|
| 344 | { -1, 0, false }
|
|---|
| 345 | },
|
|---|
| 346 | { { QAccessible::Table, QAXTableRole, false },
|
|---|
| 347 | { -1, 0, false }
|
|---|
| 348 | },
|
|---|
| 349 | { { QAccessible::StatusBar, QAXStaticTextRole, false },
|
|---|
| 350 | { -1, 0, false }
|
|---|
| 351 | },
|
|---|
| 352 | { { QAccessible::Column, QAXColumnRole, false },
|
|---|
| 353 | { -1, 0, false }
|
|---|
| 354 | },
|
|---|
| 355 | { { QAccessible::ColumnHeader, QAXColumnRole, false },
|
|---|
| 356 | { -1, 0, false }
|
|---|
| 357 | },
|
|---|
| 358 | { { QAccessible::Row, QAXRowRole, false },
|
|---|
| 359 | { -1, 0, false }
|
|---|
| 360 | },
|
|---|
| 361 | { { QAccessible::RowHeader, QAXRowRole, false },
|
|---|
| 362 | { -1, 0, false }
|
|---|
| 363 | },
|
|---|
| 364 | { { QAccessible::Cell, QAXTextFieldRole, false },
|
|---|
| 365 | { -1, 0, false }
|
|---|
| 366 | },
|
|---|
| 367 | { { QAccessible::PushButton, QAXButtonRole, false },
|
|---|
| 368 | { -1, 0, false }
|
|---|
| 369 | },
|
|---|
| 370 | { { QAccessible::EditableText, QAXTextFieldRole, true },
|
|---|
| 371 | { -1, 0, false }
|
|---|
| 372 | },
|
|---|
| 373 | { { QAccessible::Link, QAXTextFieldRole, false },
|
|---|
| 374 | { -1, 0, false }
|
|---|
| 375 | },
|
|---|
| 376 | { { QAccessible::Indicator, QAXValueIndicatorRole, false },
|
|---|
| 377 | { -1, 0, false }
|
|---|
| 378 | },
|
|---|
| 379 | { { QAccessible::Splitter, QAXSplitGroupRole, false },
|
|---|
| 380 | { -1, 0, false }
|
|---|
| 381 | },
|
|---|
| 382 | { { QAccessible::List, QAXListRole, false },
|
|---|
| 383 | { -1, 0, false }
|
|---|
| 384 | },
|
|---|
| 385 | { { QAccessible::ListItem, QAXStaticTextRole, false },
|
|---|
| 386 | { -1, 0, false }
|
|---|
| 387 | },
|
|---|
| 388 | { { QAccessible::Cell, QAXStaticTextRole, false },
|
|---|
| 389 | { -1, 0, false }
|
|---|
| 390 | },
|
|---|
| 391 | { { -1, 0, false } }
|
|---|
| 392 | };
|
|---|
| 393 |
|
|---|
| 394 | class QAInterface;
|
|---|
| 395 | static CFStringRef macRole(const QAInterface &interface);
|
|---|
| 396 |
|
|---|
| 397 | QDebug operator<<(QDebug debug, const QAInterface &interface)
|
|---|
| 398 | {
|
|---|
| 399 | if (interface.isValid() == false)
|
|---|
| 400 | debug << "invalid interface";
|
|---|
| 401 | else
|
|---|
| 402 | debug << interface.object() << "id" << interface.id() << "role" << hex << interface.role();
|
|---|
| 403 | return debug;
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | // The root of the Qt accessible hiearchy.
|
|---|
| 407 | static QObject *rootObject = 0;
|
|---|
| 408 |
|
|---|
| 409 |
|
|---|
| 410 | bool QAInterface::operator==(const QAInterface &other) const
|
|---|
| 411 | {
|
|---|
| 412 | if (isValid() == false || other.isValid() == false)
|
|---|
| 413 | return (isValid() && other.isValid());
|
|---|
| 414 |
|
|---|
| 415 | // walk up the parent chain, comparing child indexes, until we reach
|
|---|
| 416 | // an interface that has a QObject.
|
|---|
| 417 | QAInterface currentThis = *this;
|
|---|
| 418 | QAInterface currentOther = other;
|
|---|
| 419 |
|
|---|
| 420 | while (currentThis.object() == 0) {
|
|---|
| 421 | if (currentOther.object() != 0)
|
|---|
| 422 | return false;
|
|---|
| 423 |
|
|---|
| 424 | // fail if the child indexes in the two hirearchies don't match.
|
|---|
| 425 | if (currentThis.parent().indexOfChild(currentThis) !=
|
|---|
| 426 | currentOther.parent().indexOfChild(currentOther))
|
|---|
| 427 | return false;
|
|---|
| 428 |
|
|---|
| 429 | currentThis = currentThis.parent();
|
|---|
| 430 | currentOther = currentOther.parent();
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | return (currentThis.object() == currentOther.object() && currentThis.id() == currentOther.id());
|
|---|
| 434 | }
|
|---|
| 435 |
|
|---|
| 436 | bool QAInterface::operator!=(const QAInterface &other) const
|
|---|
| 437 | {
|
|---|
| 438 | return !operator==(other);
|
|---|
| 439 | }
|
|---|
| 440 |
|
|---|
| 441 | uint qHash(const QAInterface &item)
|
|---|
| 442 | {
|
|---|
| 443 | if (item.isValid())
|
|---|
| 444 | return qHash(item.object()) + qHash(item.id());
|
|---|
| 445 | else
|
|---|
| 446 | return qHash(item.cachedObject()) + qHash(item.id());
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | QAInterface QAInterface::navigate(RelationFlag relation, int entry) const
|
|---|
| 450 | {
|
|---|
| 451 | if (!checkValid())
|
|---|
| 452 | return QAInterface();
|
|---|
| 453 |
|
|---|
| 454 | // On a QAccessibleInterface that handles its own children we can short-circut
|
|---|
| 455 | // the navigation if this QAInterface refers to one of the children:
|
|---|
| 456 | if (child != 0) {
|
|---|
| 457 | // The Ancestor interface will always be the same QAccessibleInterface with
|
|---|
| 458 | // a child value of 0.
|
|---|
| 459 | if (relation == QAccessible::Ancestor)
|
|---|
| 460 | return QAInterface(*this, 0);
|
|---|
| 461 |
|
|---|
| 462 | // The child hiearchy is only one level deep, so navigating to a child
|
|---|
| 463 | // of a child is not possible.
|
|---|
| 464 | if (relation == QAccessible::Child) {
|
|---|
| 465 | return QAInterface();
|
|---|
| 466 | }
|
|---|
| 467 | }
|
|---|
| 468 | QAccessibleInterface *child_iface = 0;
|
|---|
| 469 |
|
|---|
| 470 | const int status = base.interface->navigate(relation, entry, &child_iface);
|
|---|
| 471 |
|
|---|
| 472 | if (status == -1)
|
|---|
| 473 | return QAInterface(); // not found;
|
|---|
| 474 |
|
|---|
| 475 | // Check if target is a child of this interface.
|
|---|
| 476 | if (!child_iface) {
|
|---|
| 477 | return QAInterface(*this, status);
|
|---|
| 478 | } else {
|
|---|
| 479 | // Target is child_iface or a child of that (status decides).
|
|---|
| 480 | return QAInterface(child_iface, status);
|
|---|
| 481 | }
|
|---|
| 482 | }
|
|---|
| 483 |
|
|---|
| 484 | QAElement::QAElement()
|
|---|
| 485 | :elementRef(0)
|
|---|
| 486 | {}
|
|---|
| 487 |
|
|---|
| 488 | QAElement::QAElement(AXUIElementRef elementRef)
|
|---|
| 489 | :elementRef(elementRef)
|
|---|
| 490 | {
|
|---|
| 491 | if (elementRef != 0) {
|
|---|
| 492 | CFRetain(elementRef);
|
|---|
| 493 | CFRetain(object());
|
|---|
| 494 | }
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | QAElement::QAElement(const QAElement &element)
|
|---|
| 498 | :elementRef(element.elementRef)
|
|---|
| 499 | {
|
|---|
| 500 | if (elementRef != 0) {
|
|---|
| 501 | CFRetain(elementRef);
|
|---|
| 502 | CFRetain(object());
|
|---|
| 503 | }
|
|---|
| 504 | }
|
|---|
| 505 |
|
|---|
| 506 | QAElement::QAElement(HIObjectRef object, int child)
|
|---|
| 507 | :elementRef(
|
|---|
| 508 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 509 | AXUIElementCreateWithHIObjectAndIdentifier(object, child)
|
|---|
| 510 | #endif
|
|---|
| 511 | )
|
|---|
| 512 | {
|
|---|
| 513 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 514 | if (object == 0) {
|
|---|
| 515 | elementRef = 0; // Create invalid QAElement.
|
|---|
| 516 | } else {
|
|---|
| 517 | elementRef = AXUIElementCreateWithHIObjectAndIdentifier(object, child);
|
|---|
| 518 | CFRetain(object);
|
|---|
| 519 | }
|
|---|
| 520 | #else
|
|---|
| 521 | Q_UNUSED(object);
|
|---|
| 522 | Q_UNUSED(child);
|
|---|
| 523 | #endif
|
|---|
| 524 | }
|
|---|
| 525 |
|
|---|
| 526 | QAElement::~QAElement()
|
|---|
| 527 | {
|
|---|
| 528 | if (elementRef != 0) {
|
|---|
| 529 | CFRelease(object());
|
|---|
| 530 | CFRelease(elementRef);
|
|---|
| 531 | }
|
|---|
| 532 | }
|
|---|
| 533 |
|
|---|
| 534 | void QAElement::operator=(const QAElement &other)
|
|---|
| 535 | {
|
|---|
| 536 | if (*this == other)
|
|---|
| 537 | return;
|
|---|
| 538 |
|
|---|
| 539 | if (elementRef != 0) {
|
|---|
| 540 | CFRelease(object());
|
|---|
| 541 | CFRelease(elementRef);
|
|---|
| 542 | }
|
|---|
| 543 |
|
|---|
| 544 | elementRef = other.elementRef;
|
|---|
| 545 |
|
|---|
| 546 | if (elementRef != 0) {
|
|---|
| 547 | CFRetain(elementRef);
|
|---|
| 548 | CFRetain(object());
|
|---|
| 549 | }
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | bool QAElement::operator==(const QAElement &other) const
|
|---|
| 553 | {
|
|---|
| 554 | if (elementRef == 0 || other.elementRef == 0)
|
|---|
| 555 | return (elementRef == other.elementRef);
|
|---|
| 556 |
|
|---|
| 557 | return CFEqual(elementRef, other.elementRef);
|
|---|
| 558 | }
|
|---|
| 559 |
|
|---|
| 560 | uint qHash(QAElement element)
|
|---|
| 561 | {
|
|---|
| 562 | return qHash(element.object()) + qHash(element.id());
|
|---|
| 563 | }
|
|---|
| 564 |
|
|---|
| 565 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 566 | static QInterfaceFactory *createFactory(const QAInterface &interface);
|
|---|
| 567 | #endif
|
|---|
| 568 | Q_GLOBAL_STATIC(QAccessibleHierarchyManager, accessibleHierarchyManager);
|
|---|
| 569 |
|
|---|
| 570 | /*
|
|---|
| 571 | Reomves all accessibility info accosiated with the sender object.
|
|---|
| 572 | */
|
|---|
| 573 | void QAccessibleHierarchyManager::objectDestroyed(QObject *object)
|
|---|
| 574 | {
|
|---|
| 575 | HIObjectRef hiObject = qobjectHiobjectHash.value(object);
|
|---|
| 576 | delete qobjectElementHash.value(object);
|
|---|
| 577 | qobjectElementHash.remove(object);
|
|---|
| 578 | hiobjectInterfaceHash.remove(hiObject);
|
|---|
| 579 | }
|
|---|
| 580 |
|
|---|
| 581 | /*
|
|---|
| 582 | Removes all stored items.
|
|---|
| 583 | */
|
|---|
| 584 | void QAccessibleHierarchyManager::reset()
|
|---|
| 585 | {
|
|---|
| 586 | qDeleteAll(qobjectElementHash);
|
|---|
| 587 | qobjectElementHash.clear();
|
|---|
| 588 | hiobjectInterfaceHash.clear();
|
|---|
| 589 | qobjectHiobjectHash.clear();
|
|---|
| 590 | }
|
|---|
| 591 |
|
|---|
| 592 | QAccessibleHierarchyManager *QAccessibleHierarchyManager::instance()
|
|---|
| 593 | {
|
|---|
| 594 | return accessibleHierarchyManager();
|
|---|
| 595 | }
|
|---|
| 596 |
|
|---|
| 597 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 598 | static bool isItemView(const QAInterface &interface)
|
|---|
| 599 | {
|
|---|
| 600 | QObject *object = interface.object();
|
|---|
| 601 | return (interface.role() == QAccessible::List || interface.role() == QAccessible::Table
|
|---|
| 602 | || (object && qobject_cast<QAbstractItemView *>(interface.object()))
|
|---|
| 603 | || (object && object->objectName() == QLatin1String("qt_scrollarea_viewport")
|
|---|
| 604 | && qobject_cast<QAbstractItemView *>(object->parent())));
|
|---|
| 605 | }
|
|---|
| 606 | #endif
|
|---|
| 607 |
|
|---|
| 608 | static bool isTabWidget(const QAInterface &interface)
|
|---|
| 609 | {
|
|---|
| 610 | if (QObject *object = interface.object())
|
|---|
| 611 | return (object->inherits("QTabWidget") && interface.id() == 0);
|
|---|
| 612 | return false;
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 | static bool isStandaloneTabBar(const QAInterface &interface)
|
|---|
| 616 | {
|
|---|
| 617 | QObject *object = interface.object();
|
|---|
| 618 | if (interface.role() == QAccessible::PageTabList && object)
|
|---|
| 619 | return (qobject_cast<QTabWidget *>(object->parent()) == 0);
|
|---|
| 620 |
|
|---|
| 621 | return false;
|
|---|
| 622 | }
|
|---|
| 623 |
|
|---|
| 624 | static bool isEmbeddedTabBar(const QAInterface &interface)
|
|---|
| 625 | {
|
|---|
| 626 | QObject *object = interface.object();
|
|---|
| 627 | if (interface.role() == QAccessible::PageTabList && object)
|
|---|
| 628 | return (qobject_cast<QTabWidget *>(object->parent()));
|
|---|
| 629 |
|
|---|
| 630 | return false;
|
|---|
| 631 | }
|
|---|
| 632 |
|
|---|
| 633 | /*
|
|---|
| 634 | Decides if a QAInterface is interesting from an accessibility users point of view.
|
|---|
| 635 | */
|
|---|
| 636 | bool isItInteresting(const QAInterface &interface)
|
|---|
| 637 | {
|
|---|
| 638 | // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen
|
|---|
| 639 | // state, so we disable the interface here.
|
|---|
| 640 | const QAccessible::State state = interface.state();
|
|---|
| 641 | if (state & QAccessible::Invisible ||
|
|---|
| 642 | state & QAccessible::Offscreen )
|
|---|
| 643 | return false;
|
|---|
| 644 |
|
|---|
| 645 | const QAccessible::Role role = interface.role();
|
|---|
| 646 |
|
|---|
| 647 | if (QObject * const object = interface.object()) {
|
|---|
| 648 | const QString className = QLatin1String(object->metaObject()->className());
|
|---|
| 649 |
|
|---|
| 650 | // VoiceOver focusing on tool tips can be confusing. The contents of the
|
|---|
| 651 | // tool tip is avalible through the description attribute anyway, so
|
|---|
| 652 | // we disable accessibility for tool tips.
|
|---|
| 653 | if (className == QLatin1String("QTipLabel"))
|
|---|
| 654 | return false;
|
|---|
| 655 |
|
|---|
| 656 | // Hide TabBars that has a QTabWidget parent (the tab widget handles the accessibility)
|
|---|
| 657 | if (isEmbeddedTabBar(interface))
|
|---|
| 658 | return false;
|
|---|
| 659 |
|
|---|
| 660 | // Hide docked dockwidgets. ### causes infinitie loop in the apple accessibility code.
|
|---|
| 661 | /* if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) {
|
|---|
| 662 | if (dockWidget->isFloating() == false)
|
|---|
| 663 | return false;
|
|---|
| 664 | }
|
|---|
| 665 | */
|
|---|
| 666 | }
|
|---|
| 667 |
|
|---|
| 668 | // Client is a generic role returned by plain QWidgets or other
|
|---|
| 669 | // widgets that does not have separate QAccessible interface, such
|
|---|
| 670 | // as the TabWidget. Return false unless macRole gives the interface
|
|---|
| 671 | // a special role.
|
|---|
| 672 | if (role == QAccessible::Client && macRole(interface) == CFStringRef(QAXUnknownRole))
|
|---|
| 673 | return false;
|
|---|
| 674 |
|
|---|
| 675 | // Some roles are not interesting:
|
|---|
| 676 | if (role == QAccessible::Border || // QFrame
|
|---|
| 677 | role == QAccessible::Application || // We use the system-provided application element.
|
|---|
| 678 | role == QAccessible::MenuItem) // The system also provides the menu items.
|
|---|
| 679 | return false;
|
|---|
| 680 |
|
|---|
| 681 | // It is probably better to access the toolbar buttons directly than having
|
|---|
| 682 | // to navigate through the toolbar.
|
|---|
| 683 | if (role == QAccessible::ToolBar)
|
|---|
| 684 | return false;
|
|---|
| 685 |
|
|---|
| 686 | return true;
|
|---|
| 687 | }
|
|---|
| 688 |
|
|---|
| 689 | QAElement QAccessibleHierarchyManager::registerInterface(QObject *object, int child)
|
|---|
| 690 | {
|
|---|
| 691 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 692 | return registerInterface(QAInterface(QAccessible::queryAccessibleInterface(object), child));
|
|---|
| 693 | #else
|
|---|
| 694 | Q_UNUSED(object);
|
|---|
| 695 | Q_UNUSED(child);
|
|---|
| 696 | return QAElement();
|
|---|
| 697 | #endif
|
|---|
| 698 | }
|
|---|
| 699 |
|
|---|
| 700 | /*
|
|---|
| 701 | Creates a QAXUIelement that corresponds to the given QAInterface.
|
|---|
| 702 | */
|
|---|
| 703 | QAElement QAccessibleHierarchyManager::registerInterface(const QAInterface &interface)
|
|---|
| 704 | {
|
|---|
| 705 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 706 | if (interface.isValid() == false)
|
|---|
| 707 | return QAElement();
|
|---|
| 708 | QAInterface objectInterface = interface.objectInterface();
|
|---|
| 709 |
|
|---|
| 710 | QObject * qobject = objectInterface.object();
|
|---|
| 711 | HIObjectRef hiobject = objectInterface.hiObject();
|
|---|
| 712 | if (qobject == 0 || hiobject == 0)
|
|---|
| 713 | return QAElement();
|
|---|
| 714 |
|
|---|
| 715 | if (qobjectElementHash.contains(qobject) == false) {
|
|---|
| 716 | registerInterface(qobject, hiobject, createFactory(interface));
|
|---|
| 717 | HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(interface));
|
|---|
| 718 | }
|
|---|
| 719 |
|
|---|
| 720 | return QAElement(hiobject, interface.id());
|
|---|
| 721 | #else
|
|---|
| 722 | Q_UNUSED(interface);
|
|---|
| 723 | return QAElement();
|
|---|
| 724 | #endif
|
|---|
| 725 | }
|
|---|
| 726 |
|
|---|
| 727 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 728 | #include "qaccessible_mac_carbon.cpp"
|
|---|
| 729 | #endif
|
|---|
| 730 |
|
|---|
| 731 | void QAccessibleHierarchyManager::registerInterface(QObject * qobject, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory)
|
|---|
| 732 | {
|
|---|
| 733 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 734 | if (qobjectElementHash.contains(qobject) == false) {
|
|---|
| 735 | qobjectElementHash.insert(qobject, interfaceFactory);
|
|---|
| 736 | qobjectHiobjectHash.insert(qobject, hiobject);
|
|---|
| 737 | connect(qobject, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *)));
|
|---|
| 738 | }
|
|---|
| 739 |
|
|---|
| 740 | if (hiobjectInterfaceHash.contains(hiobject) == false) {
|
|---|
| 741 | hiobjectInterfaceHash.insert(hiobject, interfaceFactory);
|
|---|
| 742 | installAcessibilityEventHandler(hiobject);
|
|---|
| 743 | }
|
|---|
| 744 | #else
|
|---|
| 745 | Q_UNUSED(qobject);
|
|---|
| 746 | Q_UNUSED(hiobject);
|
|---|
| 747 | Q_UNUSED(interfaceFactory);
|
|---|
| 748 | #endif
|
|---|
| 749 | }
|
|---|
| 750 |
|
|---|
| 751 | void QAccessibleHierarchyManager::registerChildren(const QAInterface &interface)
|
|---|
| 752 | {
|
|---|
| 753 | QObject * const object = interface.object();
|
|---|
| 754 | if (object == 0)
|
|---|
| 755 | return;
|
|---|
| 756 |
|
|---|
| 757 | QInterfaceFactory *interfaceFactory = qobjectElementHash.value(object);
|
|---|
| 758 |
|
|---|
| 759 | if (interfaceFactory == 0)
|
|---|
| 760 | return;
|
|---|
| 761 |
|
|---|
| 762 | interfaceFactory->registerChildren();
|
|---|
| 763 | }
|
|---|
| 764 |
|
|---|
| 765 | QAInterface QAccessibleHierarchyManager::lookup(const AXUIElementRef &element)
|
|---|
| 766 | {
|
|---|
| 767 | if (element == 0)
|
|---|
| 768 | return QAInterface();
|
|---|
| 769 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 770 | HIObjectRef hiObject = AXUIElementGetHIObject(element);
|
|---|
| 771 |
|
|---|
| 772 | QInterfaceFactory *factory = hiobjectInterfaceHash.value(hiObject);
|
|---|
| 773 | if (factory == 0) {
|
|---|
| 774 | return QAInterface();
|
|---|
| 775 | }
|
|---|
| 776 |
|
|---|
| 777 | UInt64 id;
|
|---|
| 778 | AXUIElementGetIdentifier(element, &id);
|
|---|
| 779 | return factory->interface(id);
|
|---|
| 780 | #else
|
|---|
| 781 | return QAInterface();
|
|---|
| 782 | #endif;
|
|---|
| 783 | }
|
|---|
| 784 |
|
|---|
| 785 | QAInterface QAccessibleHierarchyManager::lookup(const QAElement &element)
|
|---|
| 786 | {
|
|---|
| 787 | return lookup(element.element());
|
|---|
| 788 | }
|
|---|
| 789 |
|
|---|
| 790 | QAElement QAccessibleHierarchyManager::lookup(const QAInterface &interface)
|
|---|
| 791 | {
|
|---|
| 792 | if (interface.isValid() == false)
|
|---|
| 793 | return QAElement();
|
|---|
| 794 |
|
|---|
| 795 | QInterfaceFactory *factory = qobjectElementHash.value(interface.objectInterface().object());
|
|---|
| 796 | if (factory == 0)
|
|---|
| 797 | return QAElement();
|
|---|
| 798 |
|
|---|
| 799 | return factory->element(interface);
|
|---|
| 800 | }
|
|---|
| 801 |
|
|---|
| 802 | QAElement QAccessibleHierarchyManager::lookup(QObject * const object, int id)
|
|---|
| 803 | {
|
|---|
| 804 | QInterfaceFactory *factory = qobjectElementHash.value(object);
|
|---|
| 805 | if (factory == 0)
|
|---|
| 806 | return QAElement();
|
|---|
| 807 |
|
|---|
| 808 | return factory->element(id);
|
|---|
| 809 | }
|
|---|
| 810 |
|
|---|
| 811 | /*
|
|---|
| 812 | Standard interface mapping, return the stored interface
|
|---|
| 813 | or HIObjectRef, and there is an one-to-one mapping between
|
|---|
| 814 | the identifier and child.
|
|---|
| 815 | */
|
|---|
| 816 | class QStandardInterfaceFactory : public QInterfaceFactory
|
|---|
| 817 | {
|
|---|
| 818 | public:
|
|---|
| 819 | QStandardInterfaceFactory(const QAInterface &interface)
|
|---|
| 820 | : m_interface(interface), object(interface.hiObject())
|
|---|
| 821 | {
|
|---|
| 822 | CFRetain(object);
|
|---|
| 823 | }
|
|---|
| 824 |
|
|---|
| 825 | ~QStandardInterfaceFactory()
|
|---|
| 826 | {
|
|---|
| 827 | CFRelease(object);
|
|---|
| 828 | }
|
|---|
| 829 |
|
|---|
| 830 |
|
|---|
| 831 | QAInterface interface(UInt64 identifier)
|
|---|
| 832 | {
|
|---|
| 833 | const int child = identifier;
|
|---|
| 834 | return QAInterface(m_interface, child);
|
|---|
| 835 | }
|
|---|
| 836 |
|
|---|
| 837 | QAElement element(int id)
|
|---|
| 838 | {
|
|---|
| 839 | return QAElement(object, id);
|
|---|
| 840 | }
|
|---|
| 841 |
|
|---|
| 842 | QAElement element(const QAInterface &interface)
|
|---|
| 843 | {
|
|---|
| 844 | if (interface.object() == 0)
|
|---|
| 845 | return QAElement();
|
|---|
| 846 | return QAElement(object, interface.id());
|
|---|
| 847 | }
|
|---|
| 848 |
|
|---|
| 849 | void registerChildren()
|
|---|
| 850 | {
|
|---|
| 851 | const int childCount = m_interface.childCount();
|
|---|
| 852 | for (int i = 1; i <= childCount; ++i) {
|
|---|
| 853 | accessibleHierarchyManager()->registerInterface(m_interface.navigate(QAccessible::Child, i));
|
|---|
| 854 | }
|
|---|
| 855 | }
|
|---|
| 856 |
|
|---|
| 857 | private:
|
|---|
| 858 | QAInterface m_interface;
|
|---|
| 859 | HIObjectRef object;
|
|---|
| 860 | };
|
|---|
| 861 |
|
|---|
| 862 | /*
|
|---|
| 863 | Interface mapping where that creates one HIObject for each interface child.
|
|---|
| 864 | */
|
|---|
| 865 | class QMultipleHIObjectFactory : public QInterfaceFactory
|
|---|
| 866 | {
|
|---|
| 867 | public:
|
|---|
| 868 | QMultipleHIObjectFactory(const QAInterface &interface)
|
|---|
| 869 | : m_interface(interface)
|
|---|
| 870 | { }
|
|---|
| 871 |
|
|---|
| 872 | ~QMultipleHIObjectFactory()
|
|---|
| 873 | {
|
|---|
| 874 | foreach (HIObjectRef object, objects) {
|
|---|
| 875 | CFRelease(object);
|
|---|
| 876 | }
|
|---|
| 877 | }
|
|---|
| 878 |
|
|---|
| 879 | QAInterface interface(UInt64 identifier)
|
|---|
| 880 | {
|
|---|
| 881 | const int child = identifier;
|
|---|
| 882 | return QAInterface(m_interface, child);
|
|---|
| 883 | }
|
|---|
| 884 |
|
|---|
| 885 | QAElement element(int child)
|
|---|
| 886 | {
|
|---|
| 887 | if (child == 0)
|
|---|
| 888 | return QAElement(m_interface.hiObject(), 0);
|
|---|
| 889 |
|
|---|
| 890 | if (child > objects.count())
|
|---|
| 891 | return QAElement();
|
|---|
| 892 |
|
|---|
| 893 | return QAElement(objects.at(child - 1), child);
|
|---|
| 894 | }
|
|---|
| 895 |
|
|---|
| 896 | void registerChildren()
|
|---|
| 897 | {
|
|---|
| 898 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 899 | const int childCount = m_interface.childCount();
|
|---|
| 900 | for (int i = 1; i <= childCount; ++i) {
|
|---|
| 901 | HIObjectRef hiobject;
|
|---|
| 902 | HIObjectCreate(kObjectQtAccessibility, 0, &hiobject);
|
|---|
| 903 | objects.append(hiobject);
|
|---|
| 904 | accessibleHierarchyManager()->registerInterface(m_interface.object(), hiobject, this);
|
|---|
| 905 | HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(m_interface.navigate(QAccessible::Child, i)));
|
|---|
| 906 | }
|
|---|
| 907 | #endif
|
|---|
| 908 | }
|
|---|
| 909 |
|
|---|
| 910 | private:
|
|---|
| 911 | QAInterface m_interface;
|
|---|
| 912 | QList<HIObjectRef> objects;
|
|---|
| 913 | };
|
|---|
| 914 |
|
|---|
| 915 | class QItemViewInterfaceFactory : public QInterfaceFactory
|
|---|
| 916 | {
|
|---|
| 917 | public:
|
|---|
| 918 | QItemViewInterfaceFactory(const QAInterface &interface)
|
|---|
| 919 | : m_interface(interface), object(interface.hiObject())
|
|---|
| 920 | {
|
|---|
| 921 | CFRetain(object);
|
|---|
| 922 | columnCount = 0;
|
|---|
| 923 | if (QTableView * tableView = qobject_cast<QTableView *>(interface.parent().object())) {
|
|---|
| 924 | if (tableView->model())
|
|---|
| 925 | columnCount = tableView->model()->columnCount();
|
|---|
| 926 | if (tableView->verticalHeader())
|
|---|
| 927 | ++columnCount;
|
|---|
| 928 | }
|
|---|
| 929 | }
|
|---|
| 930 |
|
|---|
| 931 | ~QItemViewInterfaceFactory()
|
|---|
| 932 | {
|
|---|
| 933 | CFRelease(object);
|
|---|
| 934 | }
|
|---|
| 935 |
|
|---|
| 936 | QAInterface interface(UInt64 identifier)
|
|---|
| 937 | {
|
|---|
| 938 | if (identifier == 0)
|
|---|
| 939 | return m_interface;
|
|---|
| 940 |
|
|---|
| 941 | if (m_interface.role() == QAccessible::List)
|
|---|
| 942 | return m_interface.childAt(identifier);
|
|---|
| 943 |
|
|---|
| 944 | if (m_interface.role() == QAccessible::Table) {
|
|---|
| 945 | const int index = identifier;
|
|---|
| 946 | if (index == 0)
|
|---|
| 947 | return m_interface; // return the item view interface.
|
|---|
| 948 |
|
|---|
| 949 | const int rowIndex = (index - 1) / (columnCount + 1);
|
|---|
| 950 | const int cellIndex = (index - 1) % (columnCount + 1);
|
|---|
| 951 | /*
|
|---|
| 952 | qDebug() << "index" << index;
|
|---|
| 953 | qDebug() << "rowIndex" << rowIndex;
|
|---|
| 954 | qDebug() << "cellIndex" << cellIndex;
|
|---|
| 955 | */
|
|---|
| 956 | const QAInterface rowInterface = m_interface.childAt(rowIndex + 1);
|
|---|
| 957 |
|
|---|
| 958 | if ((cellIndex) == 0) // Is it a row?
|
|---|
| 959 | return rowInterface;
|
|---|
| 960 | else {
|
|---|
| 961 | return rowInterface.childAt(cellIndex);
|
|---|
| 962 | }
|
|---|
| 963 | }
|
|---|
| 964 |
|
|---|
| 965 | return QAInterface();
|
|---|
| 966 | }
|
|---|
| 967 |
|
|---|
| 968 | QAElement element(int id)
|
|---|
| 969 | {
|
|---|
| 970 | if (id != 0) {
|
|---|
| 971 | return QAElement();
|
|---|
| 972 | }
|
|---|
| 973 | return QAElement(object, 0);
|
|---|
| 974 | }
|
|---|
| 975 |
|
|---|
| 976 | QAElement element(const QAInterface &interface)
|
|---|
| 977 | {
|
|---|
| 978 | if (interface.object() && interface.object() == m_interface.object()) {
|
|---|
| 979 | return QAElement(object, 0);
|
|---|
| 980 | } else if (m_interface.role() == QAccessible::List) {
|
|---|
| 981 | if (interface.parent().object() && interface.parent().object() == m_interface.object())
|
|---|
| 982 | return QAElement(object, m_interface.indexOfChild(interface));
|
|---|
| 983 | } else if (m_interface.role() == QAccessible::Table) {
|
|---|
| 984 | QAInterface currentInterface = interface;
|
|---|
| 985 | int index = 0;
|
|---|
| 986 |
|
|---|
| 987 | while (currentInterface.isValid() && currentInterface.object() == 0) {
|
|---|
| 988 | const QAInterface parentInterface = currentInterface.parent();
|
|---|
| 989 | /*
|
|---|
| 990 | qDebug() << "current index" << index;
|
|---|
| 991 | qDebug() << "current interface" << interface;
|
|---|
| 992 |
|
|---|
| 993 | qDebug() << "parent interface" << parentInterface;
|
|---|
| 994 | qDebug() << "grandparent interface" << parentInterface.parent();
|
|---|
| 995 | qDebug() << "childCount" << interface.childCount();
|
|---|
| 996 | qDebug() << "index of child" << parentInterface.indexOfChild(currentInterface);
|
|---|
| 997 | */
|
|---|
| 998 | index += ((parentInterface.indexOfChild(currentInterface) - 1) * (currentInterface.childCount() + 1)) + 1;
|
|---|
| 999 | currentInterface = parentInterface;
|
|---|
| 1000 | // qDebug() << "new current interface" << currentInterface;
|
|---|
| 1001 | }
|
|---|
| 1002 | if (currentInterface.object() == m_interface.object())
|
|---|
| 1003 | return QAElement(object, index);
|
|---|
| 1004 |
|
|---|
| 1005 |
|
|---|
| 1006 | }
|
|---|
| 1007 | return QAElement();
|
|---|
| 1008 | }
|
|---|
| 1009 |
|
|---|
| 1010 | void registerChildren()
|
|---|
| 1011 | {
|
|---|
| 1012 | // Item view child interfraces don't have their own qobjects, so there is nothing to register here.
|
|---|
| 1013 | }
|
|---|
| 1014 |
|
|---|
| 1015 | private:
|
|---|
| 1016 | QAInterface m_interface;
|
|---|
| 1017 | HIObjectRef object;
|
|---|
| 1018 | int columnCount; // for table views;
|
|---|
| 1019 | };
|
|---|
| 1020 |
|
|---|
| 1021 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1022 | static bool managesChildren(const QAInterface &interface)
|
|---|
| 1023 | {
|
|---|
| 1024 | return (interface.childCount() > 0 && interface.childAt(1).id() > 0);
|
|---|
| 1025 | }
|
|---|
| 1026 |
|
|---|
| 1027 | static QInterfaceFactory *createFactory(const QAInterface &interface)
|
|---|
| 1028 | {
|
|---|
| 1029 | if (isItemView(interface)) {
|
|---|
| 1030 | return new QItemViewInterfaceFactory(interface);
|
|---|
| 1031 | } if (managesChildren(interface)) {
|
|---|
| 1032 | return new QMultipleHIObjectFactory(interface);
|
|---|
| 1033 | }
|
|---|
| 1034 |
|
|---|
| 1035 | return new QStandardInterfaceFactory(interface);
|
|---|
| 1036 | }
|
|---|
| 1037 | #endif
|
|---|
| 1038 |
|
|---|
| 1039 | QList<QAElement> lookup(const QList<QAInterface> &interfaces)
|
|---|
| 1040 | {
|
|---|
| 1041 | QList<QAElement> elements;
|
|---|
| 1042 | foreach (const QAInterface &interface, interfaces)
|
|---|
| 1043 | if (interface.isValid()) {
|
|---|
| 1044 | const QAElement element = accessibleHierarchyManager()->lookup(interface);
|
|---|
| 1045 | if (element.isValid())
|
|---|
| 1046 | elements.append(element);
|
|---|
| 1047 | }
|
|---|
| 1048 | return elements;
|
|---|
| 1049 | }
|
|---|
| 1050 |
|
|---|
| 1051 | // Debug output helpers:
|
|---|
| 1052 | /*
|
|---|
| 1053 | static QString nameForEventKind(UInt32 kind)
|
|---|
| 1054 | {
|
|---|
| 1055 | switch(kind) {
|
|---|
| 1056 | case kEventAccessibleGetChildAtPoint: return QString("GetChildAtPoint"); break;
|
|---|
| 1057 | case kEventAccessibleGetAllAttributeNames: return QString("GetAllAttributeNames"); break;
|
|---|
| 1058 | case kEventAccessibleGetNamedAttribute: return QString("GetNamedAttribute"); break;
|
|---|
| 1059 | case kEventAccessibleSetNamedAttribute: return QString("SetNamedAttribute"); break;
|
|---|
| 1060 | case kEventAccessibleGetAllActionNames: return QString("GetAllActionNames"); break;
|
|---|
| 1061 | case kEventAccessibleGetFocusedChild: return QString("GetFocusedChild"); break;
|
|---|
| 1062 | default:
|
|---|
| 1063 | return QString("Unknown accessibility event type: %1").arg(kind);
|
|---|
| 1064 | break;
|
|---|
| 1065 | };
|
|---|
| 1066 | }
|
|---|
| 1067 | */
|
|---|
| 1068 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1069 | static bool qt_mac_append_cf_uniq(CFMutableArrayRef array, CFTypeRef value)
|
|---|
| 1070 | {
|
|---|
| 1071 | if (value == 0)
|
|---|
| 1072 | return false;
|
|---|
| 1073 |
|
|---|
| 1074 | CFRange range;
|
|---|
| 1075 | range.location = 0;
|
|---|
| 1076 | range.length = CFArrayGetCount(array);
|
|---|
| 1077 | if(!CFArrayContainsValue(array, range, value)) {
|
|---|
| 1078 | CFArrayAppendValue(array, value);
|
|---|
| 1079 | return true;
|
|---|
| 1080 | }
|
|---|
| 1081 | return false;
|
|---|
| 1082 | }
|
|---|
| 1083 |
|
|---|
| 1084 | static OSStatus setAttributeValue(EventRef event, const QList<QAElement> &elements)
|
|---|
| 1085 | {
|
|---|
| 1086 | CFMutableArrayRef array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
|
|---|
| 1087 | foreach (const QAElement &element, elements) {
|
|---|
| 1088 | if (element.isValid())
|
|---|
| 1089 | CFArrayAppendValue(array, element.element());
|
|---|
| 1090 | }
|
|---|
| 1091 |
|
|---|
| 1092 | const OSStatus err = SetEventParameter(event, kEventParamAccessibleAttributeValue,
|
|---|
| 1093 | typeCFTypeRef, sizeof(array), &array);
|
|---|
| 1094 | CFRelease(array);
|
|---|
| 1095 | return err;
|
|---|
| 1096 | }
|
|---|
| 1097 | #endif //QT_MAC_USE_COCOA
|
|---|
| 1098 |
|
|---|
| 1099 | /*
|
|---|
| 1100 | Gets the AccessibleObject parameter from an event.
|
|---|
| 1101 | */
|
|---|
| 1102 | static inline AXUIElementRef getAccessibleObjectParameter(EventRef event)
|
|---|
| 1103 | {
|
|---|
| 1104 | AXUIElementRef element;
|
|---|
| 1105 | GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0,
|
|---|
| 1106 | sizeof(element), 0, &element);
|
|---|
| 1107 | return element;
|
|---|
| 1108 | }
|
|---|
| 1109 |
|
|---|
| 1110 | /*
|
|---|
| 1111 | The application event handler makes sure that all top-level qt windows are registered
|
|---|
| 1112 | before any accessibility events are handeled.
|
|---|
| 1113 | */
|
|---|
| 1114 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1115 | static OSStatus applicationEventHandler(EventHandlerCallRef next_ref, EventRef event, void *)
|
|---|
| 1116 | {
|
|---|
| 1117 | QAInterface rootInterface(QAccessible::queryAccessibleInterface(rootObject ? rootObject : qApp), 0);
|
|---|
| 1118 | accessibleHierarchyManager()->registerChildren(rootInterface);
|
|---|
| 1119 |
|
|---|
| 1120 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1121 | }
|
|---|
| 1122 |
|
|---|
| 1123 | /*
|
|---|
| 1124 | Returns the value for element by combining the QAccessibility::Checked and
|
|---|
| 1125 | QAccessibility::Mixed flags into an int value that the Mac accessibilty
|
|---|
| 1126 | system understands. This works for check boxes, radio buttons, and the like.
|
|---|
| 1127 | The return values are:
|
|---|
| 1128 | 0: unchecked
|
|---|
| 1129 | 1: checked
|
|---|
| 1130 | 2: undecided
|
|---|
| 1131 | */
|
|---|
| 1132 | static int buttonValue(QAInterface element)
|
|---|
| 1133 | {
|
|---|
| 1134 | const QAccessible::State state = element.state();
|
|---|
| 1135 | if (state & QAccessible::Mixed)
|
|---|
| 1136 | return 2;
|
|---|
| 1137 | else if(state & QAccessible::Checked)
|
|---|
| 1138 | return 1;
|
|---|
| 1139 | else
|
|---|
| 1140 | return 0;
|
|---|
| 1141 | }
|
|---|
| 1142 |
|
|---|
| 1143 | static QString getValue(const QAInterface &interface)
|
|---|
| 1144 | {
|
|---|
| 1145 | const QAccessible::Role role = interface.role();
|
|---|
| 1146 | if (role == QAccessible::RadioButton || role == QAccessible::CheckBox)
|
|---|
| 1147 | return QString::number(buttonValue(interface));
|
|---|
| 1148 | else
|
|---|
| 1149 | return interface.text(QAccessible::Value);
|
|---|
| 1150 | }
|
|---|
| 1151 | #endif //QT_MAC_USE_COCOA
|
|---|
| 1152 |
|
|---|
| 1153 | /*
|
|---|
| 1154 | Translates a QAccessible::Role into a mac accessibility role.
|
|---|
| 1155 | */
|
|---|
| 1156 | static CFStringRef macRole(const QAInterface &interface)
|
|---|
| 1157 | {
|
|---|
| 1158 | const QAccessible::Role qtRole = interface.role();
|
|---|
| 1159 |
|
|---|
| 1160 | // qDebug() << "role for" << interface.object() << "interface role" << hex << qtRole;
|
|---|
| 1161 |
|
|---|
| 1162 | // Qt accessibility: QAccessible::Splitter contains QAccessible::Grip.
|
|---|
| 1163 | // Mac accessibility: AXSplitGroup contains AXSplitter.
|
|---|
| 1164 | if (qtRole == QAccessible::Grip) {
|
|---|
| 1165 | const QAInterface parent = interface.parent();
|
|---|
| 1166 | if (parent.isValid() && parent.role() == QAccessible::Splitter)
|
|---|
| 1167 | return CFStringRef(QAXSplitterRole);
|
|---|
| 1168 | }
|
|---|
| 1169 |
|
|---|
| 1170 | // Tab widgets and standalone tab bars get the kAXTabGroupRole. Accessibility
|
|---|
| 1171 | // for tab bars emebedded in a tab widget is handled by the tab widget.
|
|---|
| 1172 | if (isTabWidget(interface) || isStandaloneTabBar(interface))
|
|---|
| 1173 | return kAXTabGroupRole;
|
|---|
| 1174 |
|
|---|
| 1175 | if (QObject *object = interface.object()) {
|
|---|
| 1176 | // ### The interface for an abstract scroll area returns the generic "Client"
|
|---|
| 1177 | // role, so we have to to an extra detect on the QObject here.
|
|---|
| 1178 | if (object->inherits("QAbstractScrollArea") && interface.id() == 0)
|
|---|
| 1179 | return CFStringRef(QAXScrollAreaRole);
|
|---|
| 1180 |
|
|---|
| 1181 | if (object->inherits("QDockWidget"))
|
|---|
| 1182 | return CFStringRef(QAXUnknownRole);
|
|---|
| 1183 | }
|
|---|
| 1184 |
|
|---|
| 1185 | int i = 0;
|
|---|
| 1186 | int testRole = text_bindings[i][0].qt;
|
|---|
| 1187 | while (testRole != -1) {
|
|---|
| 1188 | if (testRole == qtRole)
|
|---|
| 1189 | return CFStringRef(text_bindings[i][0].mac);
|
|---|
| 1190 | ++i;
|
|---|
| 1191 | testRole = text_bindings[i][0].qt;
|
|---|
| 1192 | }
|
|---|
| 1193 |
|
|---|
| 1194 | // qDebug() << "got unknown role!" << interface << interface.parent();
|
|---|
| 1195 |
|
|---|
| 1196 | return CFStringRef(QAXUnknownRole);
|
|---|
| 1197 | }
|
|---|
| 1198 |
|
|---|
| 1199 | /*
|
|---|
| 1200 | Translates a QAccessible::Role and an attribute name into a QAccessible::Text, taking into
|
|---|
| 1201 | account execptions listed in text_bindings.
|
|---|
| 1202 | */
|
|---|
| 1203 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1204 | static int textForRoleAndAttribute(QAccessible::Role role, CFStringRef attribute)
|
|---|
| 1205 | {
|
|---|
| 1206 | // Search for exception, return it if found.
|
|---|
| 1207 | int testRole = text_bindings[0][0].qt;
|
|---|
| 1208 | int i = 0;
|
|---|
| 1209 | while (testRole != -1) {
|
|---|
| 1210 | if (testRole == role) {
|
|---|
| 1211 | int j = 1;
|
|---|
| 1212 | int qtRole = text_bindings[i][j].qt;
|
|---|
| 1213 | CFStringRef testAttribute = CFStringRef(text_bindings[i][j].mac);
|
|---|
| 1214 | while (qtRole != -1) {
|
|---|
| 1215 | if (CFStringCompare(attribute, testAttribute, 0) == kCFCompareEqualTo) {
|
|---|
| 1216 | return (QAccessible::Text)qtRole;
|
|---|
| 1217 | }
|
|---|
| 1218 | ++j;
|
|---|
| 1219 | testAttribute = CFStringRef(text_bindings[i][j].mac); /// ### custom compare
|
|---|
| 1220 | qtRole = text_bindings[i][j].qt; /// ### custom compare
|
|---|
| 1221 | }
|
|---|
| 1222 | break;
|
|---|
| 1223 | }
|
|---|
| 1224 | ++i;
|
|---|
| 1225 | testRole = text_bindings[i][0].qt;
|
|---|
| 1226 | }
|
|---|
| 1227 |
|
|---|
| 1228 | // Return default mappping
|
|---|
| 1229 | if (CFStringCompare(attribute, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo)
|
|---|
| 1230 | return QAccessible::Name;
|
|---|
| 1231 | else if (CFStringCompare(attribute, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo)
|
|---|
| 1232 | return QAccessible::Value;
|
|---|
| 1233 | else if (CFStringCompare(attribute, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo)
|
|---|
| 1234 | return QAccessible::Help;
|
|---|
| 1235 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 1236 | else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo)
|
|---|
| 1237 | return QAccessible::Description;
|
|---|
| 1238 | #endif
|
|---|
| 1239 | else
|
|---|
| 1240 | return -1;
|
|---|
| 1241 | }
|
|---|
| 1242 |
|
|---|
| 1243 | /*
|
|---|
| 1244 | Returns the subrole string constant for the interface if it has one,
|
|---|
| 1245 | else returns an empty string.
|
|---|
| 1246 | */
|
|---|
| 1247 | static QCFString subrole(const QAInterface &interface)
|
|---|
| 1248 | {
|
|---|
| 1249 | const QAInterface parent = interface.parent();
|
|---|
| 1250 | if (parent.isValid() == false)
|
|---|
| 1251 | return QCFString();
|
|---|
| 1252 |
|
|---|
| 1253 | if (parent.role() == QAccessible::ScrollBar) {
|
|---|
| 1254 | QCFString subrole;
|
|---|
| 1255 | switch(interface.id()) {
|
|---|
| 1256 | case 1: subrole = CFStringRef(QAXDecrementArrowSubrole); break;
|
|---|
| 1257 | case 2: subrole = CFStringRef(QAXDecrementPageSubrole); break;
|
|---|
| 1258 | case 4: subrole = CFStringRef(QAXIncrementPageSubrole); break;
|
|---|
| 1259 | case 5: subrole = CFStringRef(QAXIncrementArrowSubrole); break;
|
|---|
| 1260 | default:
|
|---|
| 1261 | break;
|
|---|
| 1262 | }
|
|---|
| 1263 | return subrole;
|
|---|
| 1264 | }
|
|---|
| 1265 | return QCFString();
|
|---|
| 1266 | }
|
|---|
| 1267 |
|
|---|
| 1268 | // Gets the scroll bar orientation by asking the QAbstractSlider object directly.
|
|---|
| 1269 | static Qt::Orientation scrollBarOrientation(const QAInterface &scrollBar)
|
|---|
| 1270 | {
|
|---|
| 1271 | QObject *const object = scrollBar.object();
|
|---|
| 1272 | if (QAbstractSlider * const sliderObject = qobject_cast<QAbstractSlider * const>(object))
|
|---|
| 1273 | return sliderObject->orientation();
|
|---|
| 1274 |
|
|---|
| 1275 | return Qt::Vertical; // D'oh! The interface wasn't a scroll bar.
|
|---|
| 1276 | }
|
|---|
| 1277 |
|
|---|
| 1278 | static QAInterface scrollAreaGetScrollBarInterface(const QAInterface &scrollArea, Qt::Orientation orientation)
|
|---|
| 1279 | {
|
|---|
| 1280 | if (macRole(scrollArea) != CFStringRef(CFStringRef(QAXScrollAreaRole)))
|
|---|
| 1281 | return QAInterface();
|
|---|
| 1282 |
|
|---|
| 1283 | // Child 1 is the contents widget, 2 and 3 are the scroll bar containers wich contains possible scroll bars.
|
|---|
| 1284 | for (int i = 2; i <= 3; ++i) {
|
|---|
| 1285 | QAInterface scrollBarContainer = scrollArea.childAt(i);
|
|---|
| 1286 | for (int i = 1; i <= scrollBarContainer.childCount(); ++i) {
|
|---|
| 1287 | QAInterface scrollBar = scrollBarContainer.childAt(i);
|
|---|
| 1288 | if (scrollBar.isValid() &&
|
|---|
| 1289 | scrollBar.role() == QAccessible::ScrollBar &&
|
|---|
| 1290 | scrollBarOrientation(scrollBar) == orientation)
|
|---|
| 1291 | return scrollBar;
|
|---|
| 1292 | }
|
|---|
| 1293 | }
|
|---|
| 1294 |
|
|---|
| 1295 | return QAInterface();
|
|---|
| 1296 | }
|
|---|
| 1297 |
|
|---|
| 1298 | static bool scrollAreaHasScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
|
|---|
| 1299 | {
|
|---|
| 1300 | return scrollAreaGetScrollBarInterface(scrollArea, orientation).isValid();
|
|---|
| 1301 | }
|
|---|
| 1302 |
|
|---|
| 1303 | static QAElement scrollAreaGetScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
|
|---|
| 1304 | {
|
|---|
| 1305 | return accessibleHierarchyManager()->lookup(scrollAreaGetScrollBarInterface(scrollArea, orientation));
|
|---|
| 1306 | }
|
|---|
| 1307 |
|
|---|
| 1308 | static QAElement scrollAreaGetContents(const QAInterface &scrollArea)
|
|---|
| 1309 | {
|
|---|
| 1310 | // Child 1 is the contents widget,
|
|---|
| 1311 | return accessibleHierarchyManager()->lookup(scrollArea.navigate(QAccessible::Child, 1));
|
|---|
| 1312 | }
|
|---|
| 1313 |
|
|---|
| 1314 | static QAElement tabWidgetGetContents(const QAInterface &interface)
|
|---|
| 1315 | {
|
|---|
| 1316 | // A kAXTabGroup has a kAXContents attribute, which consists of the
|
|---|
| 1317 | // ui elements for the current tab page. Get the current tab page
|
|---|
| 1318 | // from the QStackedWidget, where the current visible page can
|
|---|
| 1319 | // be found at index 1.
|
|---|
| 1320 | QAInterface stackedWidget = interface.childAt(1);
|
|---|
| 1321 | accessibleHierarchyManager()->registerChildren(stackedWidget);
|
|---|
| 1322 | QAInterface tabPageInterface = stackedWidget.childAt(1);
|
|---|
| 1323 | return accessibleHierarchyManager()->lookup(tabPageInterface);
|
|---|
| 1324 | }
|
|---|
| 1325 |
|
|---|
| 1326 | static QList<QAElement> tabBarGetTabs(const QAInterface &interface)
|
|---|
| 1327 | {
|
|---|
| 1328 | // Get the tabs by searching for children with the "PageTab" role.
|
|---|
| 1329 | // This filters out the left/right navigation buttons.
|
|---|
| 1330 | accessibleHierarchyManager()->registerChildren(interface);
|
|---|
| 1331 | QList<QAElement> tabs;
|
|---|
| 1332 | const int numChildren = interface.childCount();
|
|---|
| 1333 | for (int i = 1; i < numChildren + 1; ++i) {
|
|---|
| 1334 | QAInterface child = interface.navigate(QAccessible::Child, i);
|
|---|
| 1335 | if (child.isValid() && child.role() == QAccessible::PageTab) {
|
|---|
| 1336 | tabs.append(accessibleHierarchyManager()->lookup(child));
|
|---|
| 1337 | }
|
|---|
| 1338 | }
|
|---|
| 1339 | return tabs;
|
|---|
| 1340 | }
|
|---|
| 1341 |
|
|---|
| 1342 | static QList<QAElement> tabWidgetGetTabs(const QAInterface &interface)
|
|---|
| 1343 | {
|
|---|
| 1344 | // Each QTabWidget has two children, a QStackedWidget and a QTabBar.
|
|---|
| 1345 | // Get the tabs from the QTabBar.
|
|---|
| 1346 | return tabBarGetTabs(interface.childAt(2));
|
|---|
| 1347 | }
|
|---|
| 1348 |
|
|---|
| 1349 | static QList<QAElement> tabWidgetGetChildren(const QAInterface &interface)
|
|---|
| 1350 | {
|
|---|
| 1351 | // The children for a kAXTabGroup should consist of the tabs and the
|
|---|
| 1352 | // contents of the current open tab page.
|
|---|
| 1353 | QList<QAElement> children = tabWidgetGetTabs(interface);
|
|---|
| 1354 | children += tabWidgetGetContents(interface);
|
|---|
| 1355 | return children;
|
|---|
| 1356 | }
|
|---|
| 1357 | #endif //QT_MAC_USE_COCOA
|
|---|
| 1358 |
|
|---|
| 1359 | /*
|
|---|
| 1360 | Returns the label (buddy) interface for interface, or 0 if it has none.
|
|---|
| 1361 | */
|
|---|
| 1362 | /*
|
|---|
| 1363 | static QAInterface findLabel(const QAInterface &interface)
|
|---|
| 1364 | {
|
|---|
| 1365 | return interface.navigate(QAccessible::Label, 1);
|
|---|
| 1366 | }
|
|---|
| 1367 | */
|
|---|
| 1368 | /*
|
|---|
| 1369 | Returns a list of interfaces this interface labels, or an empty list if it doesn't label any.
|
|---|
| 1370 | */
|
|---|
| 1371 | /*
|
|---|
| 1372 | static QList<QAInterface> findLabelled(const QAInterface &interface)
|
|---|
| 1373 | {
|
|---|
| 1374 | QList<QAInterface> interfaceList;
|
|---|
| 1375 |
|
|---|
| 1376 | int count = 1;
|
|---|
| 1377 | const QAInterface labelled = interface.navigate(QAccessible::Labelled, count);
|
|---|
| 1378 | while (labelled.isValid()) {
|
|---|
| 1379 | interfaceList.append(labelled);
|
|---|
| 1380 | ++count;
|
|---|
| 1381 | }
|
|---|
| 1382 | return interfaceList;
|
|---|
| 1383 | }
|
|---|
| 1384 | */
|
|---|
| 1385 | /*
|
|---|
| 1386 | Tests if the given QAInterface has data for a mac attribute.
|
|---|
| 1387 | */
|
|---|
| 1388 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1389 | static bool supportsAttribute(CFStringRef attribute, const QAInterface &interface)
|
|---|
| 1390 | {
|
|---|
| 1391 | const int text = textForRoleAndAttribute(interface.role(), attribute);
|
|---|
| 1392 |
|
|---|
| 1393 | // Special case: Static texts don't have a title.
|
|---|
| 1394 | if (interface.role() == QAccessible::StaticText && attribute == CFStringRef(QAXTitleAttribute))
|
|---|
| 1395 | return false;
|
|---|
| 1396 |
|
|---|
| 1397 | // Return true if we the attribute matched a QAccessible::Role and we get text for that role from the interface.
|
|---|
| 1398 | if (text != -1) {
|
|---|
| 1399 | if (text == QAccessible::Value) // Special case for Value, see getValue()
|
|---|
| 1400 | return !getValue(interface).isEmpty();
|
|---|
| 1401 | else
|
|---|
| 1402 | return !interface.text((QAccessible::Text)text).isEmpty();
|
|---|
| 1403 | }
|
|---|
| 1404 |
|
|---|
| 1405 | if (CFStringCompare(attribute, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1406 | if (interface.childCount() > 0)
|
|---|
| 1407 | return true;
|
|---|
| 1408 | }
|
|---|
| 1409 |
|
|---|
| 1410 | if (CFStringCompare(attribute, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1411 | return (subrole(interface) != QCFString());
|
|---|
| 1412 | }
|
|---|
| 1413 |
|
|---|
| 1414 | return false;
|
|---|
| 1415 | }
|
|---|
| 1416 |
|
|---|
| 1417 | static void appendIfSupported(CFMutableArrayRef array, CFStringRef attribute, const QAInterface &interface)
|
|---|
| 1418 | {
|
|---|
| 1419 | if (supportsAttribute(attribute, interface))
|
|---|
| 1420 | qt_mac_append_cf_uniq(array, attribute);
|
|---|
| 1421 | }
|
|---|
| 1422 |
|
|---|
| 1423 | /*
|
|---|
| 1424 | Returns the names of the attributes the give QAInterface supports.
|
|---|
| 1425 | */
|
|---|
| 1426 | static OSStatus getAllAttributeNames(EventRef event, const QAInterface &interface, EventHandlerCallRef next_ref)
|
|---|
| 1427 | {
|
|---|
| 1428 | // Call system event handler.
|
|---|
| 1429 | OSStatus err = CallNextEventHandler(next_ref, event);
|
|---|
| 1430 | if(err != noErr && err != eventNotHandledErr)
|
|---|
| 1431 | return err;
|
|---|
| 1432 | CFMutableArrayRef attrs = 0;
|
|---|
| 1433 | GetEventParameter(event, kEventParamAccessibleAttributeNames, typeCFMutableArrayRef, 0,
|
|---|
| 1434 | sizeof(attrs), 0, &attrs);
|
|---|
| 1435 |
|
|---|
| 1436 | if (!attrs)
|
|---|
| 1437 | return eventNotHandledErr;
|
|---|
| 1438 |
|
|---|
| 1439 | // Append attribute names that are always supported.
|
|---|
| 1440 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPositionAttribute));
|
|---|
| 1441 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSizeAttribute));
|
|---|
| 1442 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRoleAttribute));
|
|---|
| 1443 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXEnabledAttribute));
|
|---|
| 1444 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXWindowAttribute));
|
|---|
| 1445 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 1446 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute));
|
|---|
| 1447 | #endif
|
|---|
| 1448 |
|
|---|
| 1449 | // Append these names if the QInterafceItem returns any data for them.
|
|---|
| 1450 | appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface);
|
|---|
| 1451 | appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface);
|
|---|
| 1452 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 1453 | appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface);
|
|---|
| 1454 | appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface);
|
|---|
| 1455 | #endif
|
|---|
| 1456 | appendIfSupported(attrs, CFStringRef(QAXHelpAttribute), interface);
|
|---|
| 1457 | appendIfSupported(attrs, CFStringRef(QAXTitleUIElementAttribute), interface);
|
|---|
| 1458 | appendIfSupported(attrs, CFStringRef(QAXChildrenAttribute), interface);
|
|---|
| 1459 | appendIfSupported(attrs, CFStringRef(QAXSubroleAttribute), interface);
|
|---|
| 1460 |
|
|---|
| 1461 | // Append attribute names based on the interaface role.
|
|---|
| 1462 | switch (interface.role()) {
|
|---|
| 1463 | case QAccessible::Window:
|
|---|
| 1464 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMainAttribute));
|
|---|
| 1465 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizedAttribute));
|
|---|
| 1466 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXCloseButtonAttribute));
|
|---|
| 1467 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXZoomButtonAttribute));
|
|---|
| 1468 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizeButtonAttribute));
|
|---|
| 1469 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXToolbarButtonAttribute));
|
|---|
| 1470 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXGrowAreaAttribute));
|
|---|
| 1471 | break;
|
|---|
| 1472 | case QAccessible::RadioButton:
|
|---|
| 1473 | case QAccessible::CheckBox:
|
|---|
| 1474 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinValueAttribute));
|
|---|
| 1475 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMaxValueAttribute));
|
|---|
| 1476 | break;
|
|---|
| 1477 | case QAccessible::ScrollBar:
|
|---|
| 1478 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
|
|---|
| 1479 | break;
|
|---|
| 1480 | case QAccessible::Splitter:
|
|---|
| 1481 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSplittersAttribute));
|
|---|
| 1482 | break;
|
|---|
| 1483 | case QAccessible::Table:
|
|---|
| 1484 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRowsAttribute));
|
|---|
| 1485 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVisibleRowsAttribute));
|
|---|
| 1486 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSelectedRowsAttribute));
|
|---|
| 1487 | break;
|
|---|
| 1488 | default:
|
|---|
| 1489 | break;
|
|---|
| 1490 | }
|
|---|
| 1491 |
|
|---|
| 1492 | // Append attribute names based on the mac accessibility role.
|
|---|
| 1493 | const QCFString mac_role = macRole(interface);
|
|---|
| 1494 | if (mac_role == CFStringRef(QAXSplitterRole)) {
|
|---|
| 1495 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPreviousContentsAttribute));
|
|---|
| 1496 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXNextContentsAttribute));
|
|---|
| 1497 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
|
|---|
| 1498 | } else if (mac_role == CFStringRef(QAXScrollAreaRole)) {
|
|---|
| 1499 | if (scrollAreaHasScrollBar(interface, Qt::Horizontal))
|
|---|
| 1500 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXHorizontalScrollBarAttribute));
|
|---|
| 1501 | if (scrollAreaHasScrollBar(interface, Qt::Vertical))
|
|---|
| 1502 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVerticalScrollBarAttribute));
|
|---|
| 1503 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
|
|---|
| 1504 | } else if (mac_role == CFStringRef(QAXTabGroupRole)) {
|
|---|
| 1505 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTabsAttribute));
|
|---|
| 1506 | // Only tab widgets can have the contents attribute, there is no way of getting
|
|---|
| 1507 | // the contents from a QTabBar.
|
|---|
| 1508 | if (isTabWidget(interface))
|
|---|
| 1509 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
|
|---|
| 1510 | }
|
|---|
| 1511 |
|
|---|
| 1512 | return noErr;
|
|---|
| 1513 | }
|
|---|
| 1514 |
|
|---|
| 1515 | static void handleStringAttribute(EventRef event, QAccessible::Text text, const QAInterface &interface)
|
|---|
| 1516 | {
|
|---|
| 1517 | QString str = interface.text(text);
|
|---|
| 1518 | if (str.isEmpty())
|
|---|
| 1519 | return;
|
|---|
| 1520 |
|
|---|
| 1521 | // Remove any html markup from the text string, or VoiceOver will read the html tags.
|
|---|
| 1522 | static QTextDocument document;
|
|---|
| 1523 | document.setHtml(str);
|
|---|
| 1524 | str = document.toPlainText();
|
|---|
| 1525 |
|
|---|
| 1526 | CFStringRef cfstr = QCFString::toCFStringRef(str);
|
|---|
| 1527 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(cfstr), &cfstr);
|
|---|
| 1528 | }
|
|---|
| 1529 |
|
|---|
| 1530 | /*
|
|---|
| 1531 | Handles the parent attribute for a interface.
|
|---|
| 1532 | There are basically three cases here:
|
|---|
| 1533 | 1. interface is a HIView and has only HIView children.
|
|---|
| 1534 | 2. interface is a HIView but has children that is not a HIView
|
|---|
| 1535 | 3. interface is not a HIView.
|
|---|
| 1536 | */
|
|---|
| 1537 | static OSStatus handleChildrenAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 1538 | {
|
|---|
| 1539 | // Add the children for this interface to the global QAccessibelHierachyManager.
|
|---|
| 1540 | accessibleHierarchyManager()->registerChildren(interface);
|
|---|
| 1541 |
|
|---|
| 1542 | if (isTabWidget(interface)) {
|
|---|
| 1543 | QList<QAElement> children = tabWidgetGetChildren(interface);
|
|---|
| 1544 | const int childCount = children.count();
|
|---|
| 1545 |
|
|---|
| 1546 | CFMutableArrayRef array = 0;
|
|---|
| 1547 | array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
|
|---|
| 1548 | for (int i = 0; i < childCount; ++i) {
|
|---|
| 1549 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
|---|
| 1550 | }
|
|---|
| 1551 |
|
|---|
| 1552 | OSStatus err;
|
|---|
| 1553 | err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
|
|---|
| 1554 | if (err != noErr)
|
|---|
| 1555 | qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
|
|---|
| 1556 |
|
|---|
| 1557 | return noErr;
|
|---|
| 1558 | }
|
|---|
| 1559 |
|
|---|
| 1560 | const QList<QAElement> children = lookup(interface.children());
|
|---|
| 1561 | const int childCount = children.count();
|
|---|
| 1562 |
|
|---|
| 1563 | OSStatus err = eventNotHandledErr;
|
|---|
| 1564 | if (interface.isHIView())
|
|---|
| 1565 | err = CallNextEventHandler(next_ref, event);
|
|---|
| 1566 |
|
|---|
| 1567 | CFMutableArrayRef array = 0;
|
|---|
| 1568 | int arraySize = 0;
|
|---|
| 1569 | if (err == noErr) {
|
|---|
| 1570 | CFTypeRef obj = 0;
|
|---|
| 1571 | err = GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, NULL , sizeof(obj), NULL, &obj);
|
|---|
| 1572 | if (err == noErr && obj != 0) {
|
|---|
| 1573 | array = (CFMutableArrayRef)obj;
|
|---|
| 1574 | arraySize = CFArrayGetCount(array);
|
|---|
| 1575 | }
|
|---|
| 1576 | }
|
|---|
| 1577 |
|
|---|
| 1578 | if (array) {
|
|---|
| 1579 | CFArrayRemoveAllValues(array);
|
|---|
| 1580 | for (int i = 0; i < childCount; ++i) {
|
|---|
| 1581 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
|---|
| 1582 | }
|
|---|
| 1583 | } else {
|
|---|
| 1584 | array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
|
|---|
| 1585 | for (int i = 0; i < childCount; ++i) {
|
|---|
| 1586 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
|---|
| 1587 | }
|
|---|
| 1588 |
|
|---|
| 1589 | err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
|
|---|
| 1590 | if (err != noErr)
|
|---|
| 1591 | qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
|
|---|
| 1592 | }
|
|---|
| 1593 |
|
|---|
| 1594 | return noErr;
|
|---|
| 1595 | }
|
|---|
| 1596 |
|
|---|
| 1597 | /*
|
|---|
| 1598 |
|
|---|
| 1599 | */
|
|---|
| 1600 | static OSStatus handleParentAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 1601 | {
|
|---|
| 1602 | OSStatus err = eventNotHandledErr;
|
|---|
| 1603 | if (interface.isHIView()) {
|
|---|
| 1604 | err = CallNextEventHandler(next_ref, event);
|
|---|
| 1605 | }
|
|---|
| 1606 | if (err == noErr)
|
|---|
| 1607 | return err;
|
|---|
| 1608 |
|
|---|
| 1609 | const QAInterface parentInterface = interface.navigate(QAccessible::Ancestor, 1);
|
|---|
| 1610 | const QAElement parentElement = accessibleHierarchyManager()->lookup(parentInterface);
|
|---|
| 1611 |
|
|---|
| 1612 | if (parentElement.isValid() == false)
|
|---|
| 1613 | return eventNotHandledErr;
|
|---|
| 1614 |
|
|---|
| 1615 | AXUIElementRef elementRef = parentElement.element();
|
|---|
| 1616 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
|
|---|
| 1617 | return noErr;
|
|---|
| 1618 | }
|
|---|
| 1619 | #endif
|
|---|
| 1620 |
|
|---|
| 1621 | struct IsWindowTest
|
|---|
| 1622 | {
|
|---|
| 1623 | static inline bool test(const QAInterface &interface)
|
|---|
| 1624 | {
|
|---|
| 1625 | return (interface.role() == QAccessible::Window);
|
|---|
| 1626 | }
|
|---|
| 1627 | };
|
|---|
| 1628 |
|
|---|
| 1629 | struct IsWindowAndNotDrawerOrSheetTest
|
|---|
| 1630 | {
|
|---|
| 1631 | static inline bool test(const QAInterface &interface)
|
|---|
| 1632 | {
|
|---|
| 1633 | QWidget * const widget = qobject_cast<QWidget*>(interface.object());
|
|---|
| 1634 | return (interface.role() == QAccessible::Window &&
|
|---|
| 1635 | widget && widget->isWindow() &&
|
|---|
| 1636 | !qt_mac_is_macdrawer(widget) &&
|
|---|
| 1637 | !qt_mac_is_macsheet(widget));
|
|---|
| 1638 | }
|
|---|
| 1639 | };
|
|---|
| 1640 |
|
|---|
| 1641 | /*
|
|---|
| 1642 | Navigates up the iterfaces ancestor hierachy until a QAccessibleInterface that
|
|---|
| 1643 | passes the Test is found. If we reach a interface that is a HIView we stop the
|
|---|
| 1644 | search and call AXUIElementCopyAttributeValue.
|
|---|
| 1645 | */
|
|---|
| 1646 | template <typename TestType>
|
|---|
| 1647 | OSStatus navigateAncestors(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, CFStringRef attribute)
|
|---|
| 1648 | {
|
|---|
| 1649 | if (interface.isHIView())
|
|---|
| 1650 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1651 |
|
|---|
| 1652 | QAInterface current = interface;
|
|---|
| 1653 | QAElement element;
|
|---|
| 1654 | while (current.isValid()) {
|
|---|
| 1655 | if (TestType::test(interface)) {
|
|---|
| 1656 | element = accessibleHierarchyManager()->lookup(current);
|
|---|
| 1657 | break;
|
|---|
| 1658 | }
|
|---|
| 1659 |
|
|---|
| 1660 | // If we reach an InterfaceItem that is a HiView we can hand of the search to
|
|---|
| 1661 | // the system event handler. This is the common case.
|
|---|
| 1662 | if (current.isHIView()) {
|
|---|
| 1663 | CFTypeRef value = 0;
|
|---|
| 1664 | const QAElement currentElement = accessibleHierarchyManager()->lookup(current);
|
|---|
| 1665 | AXError err = AXUIElementCopyAttributeValue(currentElement.element(), attribute, &value);
|
|---|
| 1666 | AXUIElementRef newElement = (AXUIElementRef)value;
|
|---|
| 1667 |
|
|---|
| 1668 | if (err == noErr)
|
|---|
| 1669 | element = QAElement(newElement);
|
|---|
| 1670 |
|
|---|
| 1671 | if (newElement != 0)
|
|---|
| 1672 | CFRelease(newElement);
|
|---|
| 1673 | break;
|
|---|
| 1674 | }
|
|---|
| 1675 |
|
|---|
| 1676 | QAInterface next = current.parent();
|
|---|
| 1677 | if (next.isValid() == false)
|
|---|
| 1678 | break;
|
|---|
| 1679 | if (next == current)
|
|---|
| 1680 | break;
|
|---|
| 1681 | current = next;
|
|---|
| 1682 | }
|
|---|
| 1683 |
|
|---|
| 1684 | if (element.isValid() == false)
|
|---|
| 1685 | return eventNotHandledErr;
|
|---|
| 1686 |
|
|---|
| 1687 |
|
|---|
| 1688 | AXUIElementRef elementRef = element.element();
|
|---|
| 1689 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef,
|
|---|
| 1690 | sizeof(elementRef), &elementRef);
|
|---|
| 1691 | return noErr;
|
|---|
| 1692 | }
|
|---|
| 1693 |
|
|---|
| 1694 | /*
|
|---|
| 1695 | Returns the top-level window for an interface, which is the closest ancestor interface that
|
|---|
| 1696 | has the Window role, but is not a sheet or a drawer.
|
|---|
| 1697 | */
|
|---|
| 1698 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 1699 | static OSStatus handleWindowAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 1700 | {
|
|---|
| 1701 | return navigateAncestors<IsWindowAndNotDrawerOrSheetTest>(next_ref, event, interface, CFStringRef(QAXWindowAttribute));
|
|---|
| 1702 | }
|
|---|
| 1703 |
|
|---|
| 1704 | /*
|
|---|
| 1705 | Returns the top-level window for an interface, which is the closest ancestor interface that
|
|---|
| 1706 | has the Window role. (Can also be a sheet or a drawer)
|
|---|
| 1707 | */
|
|---|
| 1708 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 1709 | static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 1710 | {
|
|---|
| 1711 | return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute));
|
|---|
| 1712 | }
|
|---|
| 1713 | #endif
|
|---|
| 1714 |
|
|---|
| 1715 | /*
|
|---|
| 1716 | Returns the tab buttons for an interface.
|
|---|
| 1717 | */
|
|---|
| 1718 | static OSStatus handleTabsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 1719 | {
|
|---|
| 1720 | Q_UNUSED(next_ref);
|
|---|
| 1721 | if (isTabWidget(interface))
|
|---|
| 1722 | return setAttributeValue(event, tabWidgetGetTabs(interface));
|
|---|
| 1723 | else
|
|---|
| 1724 | return setAttributeValue(event, tabBarGetTabs(interface));
|
|---|
| 1725 | }
|
|---|
| 1726 |
|
|---|
| 1727 | static OSStatus handlePositionAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
|---|
| 1728 | {
|
|---|
| 1729 | QPoint qpoint(interface.rect().topLeft());
|
|---|
| 1730 | HIPoint point;
|
|---|
| 1731 | point.x = qpoint.x();
|
|---|
| 1732 | point.y = qpoint.y();
|
|---|
| 1733 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHIPoint, sizeof(point), &point);
|
|---|
| 1734 | return noErr;
|
|---|
| 1735 | }
|
|---|
| 1736 |
|
|---|
| 1737 | static OSStatus handleSizeAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
|---|
| 1738 | {
|
|---|
| 1739 | QSize qSize(interface.rect().size());
|
|---|
| 1740 | HISize size;
|
|---|
| 1741 | size.width = qSize.width();
|
|---|
| 1742 | size.height = qSize.height();
|
|---|
| 1743 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHISize, sizeof(size), &size);
|
|---|
| 1744 | return noErr;
|
|---|
| 1745 | }
|
|---|
| 1746 |
|
|---|
| 1747 | static OSStatus handleSubroleAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
|---|
| 1748 | {
|
|---|
| 1749 | const QCFString role = subrole(interface);
|
|---|
| 1750 | CFStringRef rolestr = (CFStringRef)role;
|
|---|
| 1751 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(rolestr), &rolestr);
|
|---|
| 1752 | return noErr;
|
|---|
| 1753 | }
|
|---|
| 1754 |
|
|---|
| 1755 | static OSStatus handleOrientationAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 1756 | {
|
|---|
| 1757 | QObject *const object = interface.object();
|
|---|
| 1758 | Qt::Orientation orientation;
|
|---|
| 1759 | if (interface.role() == QAccessible::ScrollBar) {
|
|---|
| 1760 | orientation = scrollBarOrientation(interface);
|
|---|
| 1761 | } else if (QSplitterHandle * const splitter = qobject_cast<QSplitterHandle * const>(object)) {
|
|---|
| 1762 | // Qt reports the layout orientation, but we want the splitter handle orientation.
|
|---|
| 1763 | orientation = (splitter->orientation() == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal;
|
|---|
| 1764 | } else {
|
|---|
| 1765 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1766 | }
|
|---|
| 1767 | const CFStringRef orientationString = (orientation == Qt::Vertical)
|
|---|
| 1768 | ? CFStringRef(QAXVerticalOrientationValue) : CFStringRef(QAXHorizontalOrientationValue);
|
|---|
| 1769 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(orientationString), &orientationString);
|
|---|
| 1770 | return noErr;
|
|---|
| 1771 | }
|
|---|
| 1772 |
|
|---|
| 1773 | /*
|
|---|
| 1774 | Figures out the next or previous contents for a splitter.
|
|---|
| 1775 | */
|
|---|
| 1776 | static OSStatus handleSplitterContentsAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, QCFString nextOrPrev)
|
|---|
| 1777 | {
|
|---|
| 1778 | if (interface.isValid() == false || interface.role() != QAccessible::Grip)
|
|---|
| 1779 | return eventNotHandledErr;
|
|---|
| 1780 |
|
|---|
| 1781 | const QAInterface parent = interface.parent();
|
|---|
| 1782 | if (parent.isValid() == false)
|
|---|
| 1783 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1784 |
|
|---|
| 1785 | if (parent.role() != QAccessible::Splitter)
|
|---|
| 1786 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1787 |
|
|---|
| 1788 | const QSplitter * const splitter = qobject_cast<const QSplitter * const>(parent.object());
|
|---|
| 1789 | if (splitter == 0)
|
|---|
| 1790 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1791 |
|
|---|
| 1792 | QWidget * const splitterHandle = qobject_cast<QWidget * const>(interface.object());
|
|---|
| 1793 | const int splitterHandleIndex = splitter->indexOf(splitterHandle);
|
|---|
| 1794 | const int widgetIndex = (nextOrPrev == QCFString(CFStringRef(QAXPreviousContentsAttribute))) ? splitterHandleIndex - 1 : splitterHandleIndex;
|
|---|
| 1795 | const QAElement contentsElement = accessibleHierarchyManager()->lookup(splitter->widget(widgetIndex), 0);
|
|---|
| 1796 | return setAttributeValue(event, QList<QAElement>() << contentsElement);
|
|---|
| 1797 | }
|
|---|
| 1798 |
|
|---|
| 1799 | /*
|
|---|
| 1800 | Creates a list of all splitter handles the splitter contains.
|
|---|
| 1801 | */
|
|---|
| 1802 | static OSStatus handleSplittersAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 1803 | {
|
|---|
| 1804 | const QSplitter * const splitter = qobject_cast<const QSplitter * const>(interface.object());
|
|---|
| 1805 | if (splitter == 0)
|
|---|
| 1806 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1807 |
|
|---|
| 1808 | accessibleHierarchyManager()->registerChildren(interface);
|
|---|
| 1809 |
|
|---|
| 1810 | QList<QAElement> handles;
|
|---|
| 1811 | const int visibleSplitterCount = splitter->count() -1; // skip first handle, it's always invisible.
|
|---|
| 1812 | for (int i = 0; i < visibleSplitterCount; ++i)
|
|---|
| 1813 | handles.append(accessibleHierarchyManager()->lookup(splitter->handle(i + 1), 0));
|
|---|
| 1814 |
|
|---|
| 1815 | return setAttributeValue(event, handles);
|
|---|
| 1816 | }
|
|---|
| 1817 |
|
|---|
| 1818 | // This handler gets the scroll bars for a scroll area
|
|---|
| 1819 | static OSStatus handleScrollBarAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &scrollArea, Qt::Orientation orientation)
|
|---|
| 1820 | {
|
|---|
| 1821 | QAElement scrollBar = scrollAreaGetScrollBar(scrollArea, orientation);
|
|---|
| 1822 | if (scrollBar.isValid() == false)
|
|---|
| 1823 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1824 |
|
|---|
| 1825 | AXUIElementRef elementRef = scrollBar.element();
|
|---|
| 1826 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
|
|---|
| 1827 | return noErr;
|
|---|
| 1828 | }
|
|---|
| 1829 |
|
|---|
| 1830 | // This handler gets the contents for a scroll area or tab widget.
|
|---|
| 1831 | static OSStatus handleContentsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 1832 | {
|
|---|
| 1833 | const QCFString mac_role = macRole(interface);
|
|---|
| 1834 |
|
|---|
| 1835 | QAElement contents;
|
|---|
| 1836 |
|
|---|
| 1837 | if (mac_role == kAXTabGroupRole) {
|
|---|
| 1838 | contents = tabWidgetGetContents(interface);
|
|---|
| 1839 | } else {
|
|---|
| 1840 | contents = scrollAreaGetContents(interface);
|
|---|
| 1841 | if (contents.isValid() == false)
|
|---|
| 1842 | return CallNextEventHandler(next_ref, event);
|
|---|
| 1843 | }
|
|---|
| 1844 |
|
|---|
| 1845 | return setAttributeValue(event, QList<QAElement>() << contents);
|
|---|
| 1846 | }
|
|---|
| 1847 |
|
|---|
| 1848 | static OSStatus handleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
|---|
| 1849 | {
|
|---|
| 1850 | QList<QAElement> rows = lookup(tableView.children());
|
|---|
| 1851 |
|
|---|
| 1852 | // kill the first row which is the horizontal header.
|
|---|
| 1853 | rows.removeAt(0);
|
|---|
| 1854 |
|
|---|
| 1855 | return setAttributeValue(event, rows);
|
|---|
| 1856 | }
|
|---|
| 1857 |
|
|---|
| 1858 | static OSStatus handleVisibleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
|---|
| 1859 | {
|
|---|
| 1860 | QList<QAElement> visibleRows;
|
|---|
| 1861 |
|
|---|
| 1862 | QList<QAInterface> rows = tableView.children();
|
|---|
| 1863 | // kill the first row which is the horizontal header.
|
|---|
| 1864 | rows.removeAt(0);
|
|---|
| 1865 |
|
|---|
| 1866 | foreach (const QAInterface &interface, rows)
|
|---|
| 1867 | if ((interface.state() & QAccessible::Invisible) == false)
|
|---|
| 1868 | visibleRows.append(accessibleHierarchyManager()->lookup(interface));
|
|---|
| 1869 |
|
|---|
| 1870 | return setAttributeValue(event, visibleRows);
|
|---|
| 1871 | }
|
|---|
| 1872 |
|
|---|
| 1873 | static OSStatus handleSelectedRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
|---|
| 1874 | {
|
|---|
| 1875 | QList<QAElement> selectedRows;
|
|---|
| 1876 | foreach (const QAInterface &interface, tableView.children())
|
|---|
| 1877 | if ((interface.state() & QAccessible::Selected))
|
|---|
| 1878 | selectedRows.append(accessibleHierarchyManager()->lookup(interface));
|
|---|
| 1879 |
|
|---|
| 1880 | return setAttributeValue(event, selectedRows);
|
|---|
| 1881 | }
|
|---|
| 1882 |
|
|---|
| 1883 | static OSStatus getNamedAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 1884 | {
|
|---|
| 1885 | CFStringRef var;
|
|---|
| 1886 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
|---|
| 1887 | sizeof(var), 0, &var);
|
|---|
| 1888 |
|
|---|
| 1889 | if (CFStringCompare(var, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1890 | return handleChildrenAttribute(next_ref, event, interface);
|
|---|
| 1891 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 1892 | } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1893 | return handleTopLevelUIElementAttribute(next_ref, event, interface);
|
|---|
| 1894 | #endif
|
|---|
| 1895 | } else if(CFStringCompare(var, CFStringRef(QAXWindowAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1896 | return handleWindowAttribute(next_ref, event, interface);
|
|---|
| 1897 | } else if(CFStringCompare(var, CFStringRef(QAXParentAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1898 | return handleParentAttribute(next_ref, event, interface);
|
|---|
| 1899 | } else if (CFStringCompare(var, CFStringRef(QAXPositionAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1900 | return handlePositionAttribute(next_ref, event, interface);
|
|---|
| 1901 | } else if (CFStringCompare(var, CFStringRef(QAXSizeAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1902 | return handleSizeAttribute(next_ref, event, interface);
|
|---|
| 1903 | } else if (CFStringCompare(var, CFStringRef(QAXRoleAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1904 | CFStringRef role = macRole(interface);
|
|---|
| 1905 | // ###
|
|---|
| 1906 | // QWidget * const widget = qobject_cast<QWidget *>(interface.object());
|
|---|
| 1907 | // if (role == CFStringRef(QAXUnknownRole) && widget && widget->isWindow())
|
|---|
| 1908 | // role = CFStringRef(QAXWindowRole);
|
|---|
| 1909 |
|
|---|
| 1910 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
|
|---|
| 1911 | sizeof(role), &role);
|
|---|
| 1912 |
|
|---|
| 1913 | } else if (CFStringCompare(var, CFStringRef(QAXEnabledAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1914 | Boolean val = !((interface.state() & QAccessible::Unavailable))
|
|---|
| 1915 | && !((interface.state() & QAccessible::Invisible));
|
|---|
| 1916 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1917 | sizeof(val), &val);
|
|---|
| 1918 | } else if (CFStringCompare(var, CFStringRef(QAXExpandedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1919 | Boolean val = (interface.state() & QAccessible::Expanded);
|
|---|
| 1920 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1921 | sizeof(val), &val);
|
|---|
| 1922 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1923 | Boolean val = (interface.state() & QAccessible::Selection);
|
|---|
| 1924 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1925 | sizeof(val), &val);
|
|---|
| 1926 | } else if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1927 | Boolean val = (interface.state() & QAccessible::Focus);
|
|---|
| 1928 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1929 | sizeof(val), &val);
|
|---|
| 1930 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedChildrenAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1931 | const int cc = interface.childCount();
|
|---|
| 1932 | QList<QAElement> selected;
|
|---|
| 1933 | for (int i = 1; i <= cc; ++i) {
|
|---|
| 1934 | const QAInterface child_iface = interface.navigate(QAccessible::Child, i);
|
|---|
| 1935 | if (child_iface.isValid() && child_iface.state() & QAccessible::Selected)
|
|---|
| 1936 | selected.append(accessibleHierarchyManager()->lookup(child_iface));
|
|---|
| 1937 | }
|
|---|
| 1938 |
|
|---|
| 1939 | return setAttributeValue(event, selected);
|
|---|
| 1940 |
|
|---|
| 1941 | } else if (CFStringCompare(var, CFStringRef(QAXCloseButtonAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1942 | if(interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1943 | Boolean val = true; //do we want to add a WState for this?
|
|---|
| 1944 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1945 | sizeof(val), &val);
|
|---|
| 1946 | }
|
|---|
| 1947 | } else if (CFStringCompare(var, CFStringRef(QAXZoomButtonAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1948 | if(interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1949 | QWidget *widget = (QWidget*)interface.object();
|
|---|
| 1950 | Boolean val = (widget->windowFlags() & Qt::WindowMaximizeButtonHint);
|
|---|
| 1951 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1952 | sizeof(val), &val);
|
|---|
| 1953 | }
|
|---|
| 1954 | } else if (CFStringCompare(var, CFStringRef(QAXMinimizeButtonAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1955 | if(interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1956 | QWidget *widget = (QWidget*)interface.object();
|
|---|
| 1957 | Boolean val = (widget->windowFlags() & Qt::WindowMinimizeButtonHint);
|
|---|
| 1958 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1959 | sizeof(val), &val);
|
|---|
| 1960 | }
|
|---|
| 1961 | } else if (CFStringCompare(var, CFStringRef(QAXToolbarButtonAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1962 | if(interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1963 | QWidget *widget = (QWidget*)interface.object();
|
|---|
| 1964 | Boolean val = qobject_cast<QMainWindow *>(widget) != 0;
|
|---|
| 1965 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1966 | sizeof(val), &val);
|
|---|
| 1967 | }
|
|---|
| 1968 | } else if (CFStringCompare(var, CFStringRef(QAXGrowAreaAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1969 | if(interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1970 | Boolean val = true; //do we want to add a WState for this?
|
|---|
| 1971 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1972 | sizeof(val), &val);
|
|---|
| 1973 | }
|
|---|
| 1974 | } else if (CFStringCompare(var, CFStringRef(QAXMinimizedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1975 | if (interface.object() && interface.object()->isWidgetType()) {
|
|---|
| 1976 | QWidget *widget = (QWidget*)interface.object();
|
|---|
| 1977 | Boolean val = (widget->windowState() & Qt::WindowMinimized);
|
|---|
| 1978 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
|---|
| 1979 | sizeof(val), &val);
|
|---|
| 1980 | }
|
|---|
| 1981 | } else if (CFStringCompare(var, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1982 | return handleSubroleAttribute(next_ref, event, interface);
|
|---|
| 1983 | } else if (CFStringCompare(var, CFStringRef(QAXRoleDescriptionAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1984 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) && !defined(QT_MAC_USE_COCOA)
|
|---|
| 1985 | if (HICopyAccessibilityRoleDescription) {
|
|---|
| 1986 | const CFStringRef roleDescription = HICopyAccessibilityRoleDescription(macRole(interface), 0);
|
|---|
| 1987 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
|
|---|
| 1988 | sizeof(roleDescription), &roleDescription);
|
|---|
| 1989 | } else
|
|---|
| 1990 | #endif
|
|---|
| 1991 | {
|
|---|
| 1992 | // Just use Qt::Description on 10.3
|
|---|
| 1993 | handleStringAttribute(event, QAccessible::Description, interface);
|
|---|
| 1994 | }
|
|---|
| 1995 | } else if (CFStringCompare(var, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 1996 | const QAccessible::Role role = interface.role();
|
|---|
| 1997 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
|---|
| 1998 | handleStringAttribute(event, text, interface);
|
|---|
| 1999 | } else if (CFStringCompare(var, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2000 | const QAccessible::Role role = interface.role();
|
|---|
| 2001 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
|---|
| 2002 | if (role == QAccessible::CheckBox || role == QAccessible::RadioButton) {
|
|---|
| 2003 | int value = buttonValue(interface);
|
|---|
| 2004 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
|---|
| 2005 | } else {
|
|---|
| 2006 | handleStringAttribute(event, text, interface);
|
|---|
| 2007 | }
|
|---|
| 2008 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|---|
| 2009 | } else if (CFStringCompare(var, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2010 | const QAccessible::Role role = interface.role();
|
|---|
| 2011 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
|---|
| 2012 | handleStringAttribute(event, text, interface);
|
|---|
| 2013 | } else if (CFStringCompare(var, CFStringRef(QAXLinkedUIElementsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2014 | return CallNextEventHandler(next_ref, event);
|
|---|
| 2015 | #endif
|
|---|
| 2016 | } else if (CFStringCompare(var, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2017 | const QAccessible::Role role = interface.role();
|
|---|
| 2018 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
|---|
| 2019 | handleStringAttribute(event, text, interface);
|
|---|
| 2020 | } else if (CFStringCompare(var, kAXTitleUIElementAttribute, 0) == kCFCompareEqualTo) {
|
|---|
| 2021 | return CallNextEventHandler(next_ref, event);
|
|---|
| 2022 | } else if (CFStringCompare(var, CFStringRef(QAXTabsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2023 | return handleTabsAttribute(next_ref, event, interface);
|
|---|
| 2024 | } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2025 | // tabs we first go to the tab bar which is child #2.
|
|---|
| 2026 | QAInterface tabBarInterface = interface.childAt(2);
|
|---|
| 2027 | return handleTabsAttribute(next_ref, event, tabBarInterface);
|
|---|
| 2028 | } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2029 | if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
|
|---|
| 2030 | uint value = 0;
|
|---|
| 2031 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
|---|
| 2032 | } else {
|
|---|
| 2033 | return CallNextEventHandler(next_ref, event);
|
|---|
| 2034 | }
|
|---|
| 2035 | } else if (CFStringCompare(var, CFStringRef(QAXMaxValueAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2036 | if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
|
|---|
| 2037 | uint value = 2;
|
|---|
| 2038 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
|---|
| 2039 | } else {
|
|---|
| 2040 | return CallNextEventHandler(next_ref, event);
|
|---|
| 2041 | }
|
|---|
| 2042 | } else if (CFStringCompare(var, CFStringRef(QAXOrientationAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2043 | return handleOrientationAttribute(next_ref, event, interface);
|
|---|
| 2044 | } else if (CFStringCompare(var, CFStringRef(QAXPreviousContentsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2045 | return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXPreviousContentsAttribute));
|
|---|
| 2046 | } else if (CFStringCompare(var, CFStringRef(QAXNextContentsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2047 | return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXNextContentsAttribute));
|
|---|
| 2048 | } else if (CFStringCompare(var, CFStringRef(QAXSplittersAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2049 | return handleSplittersAttribute(next_ref, event, interface);
|
|---|
| 2050 | } else if (CFStringCompare(var, CFStringRef(QAXHorizontalScrollBarAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2051 | return handleScrollBarAttribute(next_ref, event, interface, Qt::Horizontal);
|
|---|
| 2052 | } else if (CFStringCompare(var, CFStringRef(QAXVerticalScrollBarAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2053 | return handleScrollBarAttribute(next_ref, event, interface, Qt::Vertical);
|
|---|
| 2054 | } else if (CFStringCompare(var, CFStringRef(QAXContentsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2055 | return handleContentsAttribute(next_ref, event, interface);
|
|---|
| 2056 | } else if (CFStringCompare(var, CFStringRef(QAXRowsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2057 | return handleRowsAttribute(next_ref, event, interface);
|
|---|
| 2058 | } else if (CFStringCompare(var, CFStringRef(QAXVisibleRowsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2059 | return handleVisibleRowsAttribute(next_ref, event, interface);
|
|---|
| 2060 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedRowsAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2061 | return handleSelectedRowsAttribute(next_ref, event, interface);
|
|---|
| 2062 | } else {
|
|---|
| 2063 | return CallNextEventHandler(next_ref, event);
|
|---|
| 2064 | }
|
|---|
| 2065 | return noErr;
|
|---|
| 2066 | }
|
|---|
| 2067 |
|
|---|
| 2068 | static OSStatus isNamedAttributeSettable(EventRef event, const QAInterface &interface)
|
|---|
| 2069 | {
|
|---|
| 2070 | CFStringRef var;
|
|---|
| 2071 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
|---|
| 2072 | sizeof(var), 0, &var);
|
|---|
| 2073 | Boolean settable = false;
|
|---|
| 2074 | if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2075 | settable = true;
|
|---|
| 2076 | } else {
|
|---|
| 2077 | for (int r = 0; text_bindings[r][0].qt != -1; r++) {
|
|---|
| 2078 | if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
|
|---|
| 2079 | for (int a = 1; text_bindings[r][a].qt != -1; a++) {
|
|---|
| 2080 | if (CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
|
|---|
| 2081 | settable = text_bindings[r][a].settable;
|
|---|
| 2082 | break;
|
|---|
| 2083 | }
|
|---|
| 2084 | }
|
|---|
| 2085 | }
|
|---|
| 2086 | }
|
|---|
| 2087 | }
|
|---|
| 2088 | SetEventParameter(event, kEventParamAccessibleAttributeSettable, typeBoolean,
|
|---|
| 2089 | sizeof(settable), &settable);
|
|---|
| 2090 | return noErr;
|
|---|
| 2091 | }
|
|---|
| 2092 |
|
|---|
| 2093 | static OSStatus getChildAtPoint(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
|---|
| 2094 | {
|
|---|
| 2095 | Q_UNUSED(next_ref);
|
|---|
| 2096 | if (interface.isValid() == false)
|
|---|
| 2097 | return eventNotHandledErr;
|
|---|
| 2098 |
|
|---|
| 2099 | // Add the children for this interface to the global QAccessibelHierachyManager.
|
|---|
| 2100 | accessibleHierarchyManager()->registerChildren(interface);
|
|---|
| 2101 |
|
|---|
| 2102 | Point where;
|
|---|
| 2103 | GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where);
|
|---|
| 2104 | const QAInterface childInterface = interface.childAt(where.h, where.v);
|
|---|
| 2105 |
|
|---|
| 2106 | if (childInterface.isValid() == false || childInterface == interface)
|
|---|
| 2107 | return eventNotHandledErr;
|
|---|
| 2108 |
|
|---|
| 2109 | const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
|
|---|
| 2110 | if (element.isValid() == false)
|
|---|
| 2111 | return eventNotHandledErr;
|
|---|
| 2112 |
|
|---|
| 2113 | AXUIElementRef elementRef = element.element();
|
|---|
| 2114 | CFRetain(elementRef);
|
|---|
| 2115 | SetEventParameter(event, kEventParamAccessibleChild, typeCFTypeRef,
|
|---|
| 2116 | sizeof(elementRef), &elementRef);
|
|---|
| 2117 |
|
|---|
| 2118 | return noErr;
|
|---|
| 2119 | }
|
|---|
| 2120 |
|
|---|
| 2121 | /*
|
|---|
| 2122 | Returns a list of actions the given interface supports.
|
|---|
| 2123 | Currently implemented by getting the interface role and deciding based on that.
|
|---|
| 2124 | */
|
|---|
| 2125 | static QList<QAccessible::Action> supportedPredefinedActions(const QAInterface &interface)
|
|---|
| 2126 | {
|
|---|
| 2127 | QList<QAccessible::Action> actions;
|
|---|
| 2128 | switch (interface.role()) {
|
|---|
| 2129 | default:
|
|---|
| 2130 | // Most things can be pressed.
|
|---|
| 2131 | actions.append(QAccessible::Press);
|
|---|
| 2132 | break;
|
|---|
| 2133 | }
|
|---|
| 2134 |
|
|---|
| 2135 | return actions;
|
|---|
| 2136 | }
|
|---|
| 2137 |
|
|---|
| 2138 | /*
|
|---|
| 2139 | Translates a predefined QAccessible::Action to a Mac action constant.
|
|---|
| 2140 | Returns an empty string if the Qt Action has no mac equivalent.
|
|---|
| 2141 | */
|
|---|
| 2142 | static QCFString translateAction(const QAccessible::Action action)
|
|---|
| 2143 | {
|
|---|
| 2144 | switch (action) {
|
|---|
| 2145 | case QAccessible::Press:
|
|---|
| 2146 | return CFStringRef(QAXPressAction);
|
|---|
| 2147 | break;
|
|---|
| 2148 | case QAccessible::Increase:
|
|---|
| 2149 | return CFStringRef(QAXIncrementAction);
|
|---|
| 2150 | break;
|
|---|
| 2151 | case QAccessible::Decrease:
|
|---|
| 2152 | return CFStringRef(QAXDecrementAction);
|
|---|
| 2153 | break;
|
|---|
| 2154 | case QAccessible::Accept:
|
|---|
| 2155 | return CFStringRef(QAXConfirmAction);
|
|---|
| 2156 | break;
|
|---|
| 2157 | case QAccessible::Select:
|
|---|
| 2158 | return CFStringRef(QAXPickAction);
|
|---|
| 2159 | break;
|
|---|
| 2160 | case QAccessible::Cancel:
|
|---|
| 2161 | return CFStringRef(QAXCancelAction);
|
|---|
| 2162 | break;
|
|---|
| 2163 | default:
|
|---|
| 2164 | return QCFString();
|
|---|
| 2165 | break;
|
|---|
| 2166 | }
|
|---|
| 2167 | }
|
|---|
| 2168 |
|
|---|
| 2169 | /*
|
|---|
| 2170 | Translates between a Mac action constant and a QAccessible::Action.
|
|---|
| 2171 | Returns QAccessible::Default action if there is no Qt predefined equivalent.
|
|---|
| 2172 | */
|
|---|
| 2173 | static QAccessible::Action translateAction(const CFStringRef actionName)
|
|---|
| 2174 | {
|
|---|
| 2175 | if(CFStringCompare(actionName, CFStringRef(QAXPressAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2176 | return QAccessible::Press;
|
|---|
| 2177 | } else if(CFStringCompare(actionName, CFStringRef(QAXIncrementAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2178 | return QAccessible::Increase;
|
|---|
| 2179 | } else if(CFStringCompare(actionName, CFStringRef(QAXDecrementAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2180 | return QAccessible::Decrease;
|
|---|
| 2181 | } else if(CFStringCompare(actionName, CFStringRef(QAXConfirmAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2182 | return QAccessible::Accept;
|
|---|
| 2183 | } else if(CFStringCompare(actionName, CFStringRef(QAXPickAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2184 | return QAccessible::Select;
|
|---|
| 2185 | } else if(CFStringCompare(actionName, CFStringRef(QAXCancelAction), 0) == kCFCompareEqualTo) {
|
|---|
| 2186 | return QAccessible::Cancel;
|
|---|
| 2187 | } else {
|
|---|
| 2188 | return QAccessible::DefaultAction;
|
|---|
| 2189 | }
|
|---|
| 2190 | }
|
|---|
| 2191 | #endif // QT_MAC_USE_COCOA
|
|---|
| 2192 |
|
|---|
| 2193 | /*
|
|---|
| 2194 | Copies the translated names all supported actions for an interface into the kEventParamAccessibleActionNames
|
|---|
| 2195 | event parameter.
|
|---|
| 2196 | */
|
|---|
| 2197 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 2198 | static OSStatus getAllActionNames(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 2199 | {
|
|---|
| 2200 | Q_UNUSED(next_ref);
|
|---|
| 2201 |
|
|---|
| 2202 | CFMutableArrayRef actions = 0;
|
|---|
| 2203 | GetEventParameter(event, kEventParamAccessibleActionNames, typeCFMutableArrayRef, 0,
|
|---|
| 2204 | sizeof(actions), 0, &actions);
|
|---|
| 2205 |
|
|---|
| 2206 | // Add supported predefined actions.
|
|---|
| 2207 | const QList<QAccessible::Action> predefinedActions = supportedPredefinedActions(interface);
|
|---|
| 2208 | for (int i = 0; i < predefinedActions.count(); ++i) {
|
|---|
| 2209 | const QCFString action = translateAction(predefinedActions.at(i));
|
|---|
| 2210 | if (action != QCFString())
|
|---|
| 2211 | qt_mac_append_cf_uniq(actions, action);
|
|---|
| 2212 | }
|
|---|
| 2213 |
|
|---|
| 2214 | // Add user actions
|
|---|
| 2215 | const int actionCount = interface.userActionCount();
|
|---|
| 2216 | for (int i = 0; i < actionCount; ++i) {
|
|---|
| 2217 | const QString actionName = interface.actionText(i, QAccessible::Name);
|
|---|
| 2218 | qt_mac_append_cf_uniq(actions, QCFString::toCFStringRef(actionName));
|
|---|
| 2219 | }
|
|---|
| 2220 |
|
|---|
| 2221 | return noErr;
|
|---|
| 2222 | }
|
|---|
| 2223 | #endif
|
|---|
| 2224 |
|
|---|
| 2225 | /*
|
|---|
| 2226 | Handles the perforNamedAction event.
|
|---|
| 2227 | */
|
|---|
| 2228 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 2229 | static OSStatus performNamedAction(EventHandlerCallRef next_ref, EventRef event, const QAInterface& interface)
|
|---|
| 2230 | {
|
|---|
| 2231 | Q_UNUSED(next_ref);
|
|---|
| 2232 |
|
|---|
| 2233 | CFStringRef act;
|
|---|
| 2234 | GetEventParameter(event, kEventParamAccessibleActionName, typeCFStringRef, 0,
|
|---|
| 2235 | sizeof(act), 0, &act);
|
|---|
| 2236 |
|
|---|
| 2237 | const QAccessible::Action action = translateAction(act);
|
|---|
| 2238 |
|
|---|
| 2239 | // Perform built-in action
|
|---|
| 2240 | if (action != QAccessible::DefaultAction) {
|
|---|
| 2241 | interface.doAction(action, QVariantList());
|
|---|
| 2242 | return noErr;
|
|---|
| 2243 | }
|
|---|
| 2244 |
|
|---|
| 2245 | // Search for user-defined actions and perform it if found.
|
|---|
| 2246 | const int actCount = interface.userActionCount();
|
|---|
| 2247 | const QString qAct = QCFString::toQString(act);
|
|---|
| 2248 | for(int i = 0; i < actCount; i++) {
|
|---|
| 2249 | if(interface.actionText(i, QAccessible::Name) == qAct) {
|
|---|
| 2250 | interface.doAction(i, QVariantList());
|
|---|
| 2251 | break;
|
|---|
| 2252 | }
|
|---|
| 2253 | }
|
|---|
| 2254 | return noErr;
|
|---|
| 2255 | }
|
|---|
| 2256 |
|
|---|
| 2257 | static OSStatus setNamedAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
|---|
| 2258 | {
|
|---|
| 2259 | Q_UNUSED(next_ref);
|
|---|
| 2260 | Q_UNUSED(event);
|
|---|
| 2261 |
|
|---|
| 2262 | CFStringRef var;
|
|---|
| 2263 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
|---|
| 2264 | sizeof(var), 0, &var);
|
|---|
| 2265 | if(CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
|---|
| 2266 | CFTypeRef val;
|
|---|
| 2267 | if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
|
|---|
| 2268 | sizeof(val), 0, &val) == noErr) {
|
|---|
| 2269 | if(CFGetTypeID(val) == CFBooleanGetTypeID() &&
|
|---|
| 2270 | CFEqual(static_cast<CFBooleanRef>(val), kCFBooleanTrue)) {
|
|---|
| 2271 | interface.doAction(QAccessible::SetFocus);
|
|---|
| 2272 | }
|
|---|
| 2273 | }
|
|---|
| 2274 | } else {
|
|---|
| 2275 | bool found = false;
|
|---|
| 2276 | for(int r = 0; text_bindings[r][0].qt != -1; r++) {
|
|---|
| 2277 | if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
|
|---|
| 2278 | for(int a = 1; text_bindings[r][a].qt != -1; a++) {
|
|---|
| 2279 | if(CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
|
|---|
| 2280 | if(!text_bindings[r][a].settable) {
|
|---|
| 2281 | } else {
|
|---|
| 2282 | CFTypeRef val;
|
|---|
| 2283 | if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
|
|---|
| 2284 | sizeof(val), 0, &val) == noErr) {
|
|---|
| 2285 | if(CFGetTypeID(val) == CFStringGetTypeID())
|
|---|
| 2286 | interface.setText((QAccessible::Text)text_bindings[r][a].qt,
|
|---|
| 2287 | QCFString::toQString(static_cast<CFStringRef>(val)));
|
|---|
| 2288 |
|
|---|
| 2289 | }
|
|---|
| 2290 | }
|
|---|
| 2291 | found = true;
|
|---|
| 2292 | break;
|
|---|
| 2293 | }
|
|---|
| 2294 | }
|
|---|
| 2295 | break;
|
|---|
| 2296 | }
|
|---|
| 2297 | }
|
|---|
| 2298 | }
|
|---|
| 2299 | return noErr;
|
|---|
| 2300 | }
|
|---|
| 2301 |
|
|---|
| 2302 | /*
|
|---|
| 2303 | This is the main accessibility event handler.
|
|---|
| 2304 | */
|
|---|
| 2305 | static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data)
|
|---|
| 2306 | {
|
|---|
| 2307 | Q_UNUSED(data)
|
|---|
| 2308 |
|
|---|
| 2309 | // Return if this event is not a AccessibleGetNamedAttribute event.
|
|---|
| 2310 | const UInt32 eclass = GetEventClass(event);
|
|---|
| 2311 | if (eclass != kEventClassAccessibility)
|
|---|
| 2312 | return eventNotHandledErr;
|
|---|
| 2313 |
|
|---|
| 2314 | // Get the AXUIElementRef and QAInterface pointer
|
|---|
| 2315 | AXUIElementRef element = 0;
|
|---|
| 2316 | GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, sizeof(element), 0, &element);
|
|---|
| 2317 | QAInterface interface = accessibleHierarchyManager()->lookup(element);
|
|---|
| 2318 | if (interface.isValid() == false)
|
|---|
| 2319 | return eventNotHandledErr;
|
|---|
| 2320 |
|
|---|
| 2321 | const UInt32 ekind = GetEventKind(event);
|
|---|
| 2322 | OSStatus status = noErr;
|
|---|
| 2323 | switch (ekind) {
|
|---|
| 2324 | case kEventAccessibleGetAllAttributeNames:
|
|---|
| 2325 | status = getAllAttributeNames(event, interface, next_ref);
|
|---|
| 2326 | break;
|
|---|
| 2327 | case kEventAccessibleGetNamedAttribute:
|
|---|
| 2328 | status = getNamedAttribute(next_ref, event, interface);
|
|---|
| 2329 | break;
|
|---|
| 2330 | case kEventAccessibleIsNamedAttributeSettable:
|
|---|
| 2331 | status = isNamedAttributeSettable(event, interface);
|
|---|
| 2332 | break;
|
|---|
| 2333 | case kEventAccessibleGetChildAtPoint:
|
|---|
| 2334 | status = getChildAtPoint(next_ref, event, interface);
|
|---|
| 2335 | break;
|
|---|
| 2336 | case kEventAccessibleGetAllActionNames:
|
|---|
| 2337 | status = getAllActionNames(next_ref, event, interface);
|
|---|
| 2338 | break;
|
|---|
| 2339 | case kEventAccessibleGetFocusedChild:
|
|---|
| 2340 | status = CallNextEventHandler(next_ref, event);
|
|---|
| 2341 | break;
|
|---|
| 2342 | case kEventAccessibleSetNamedAttribute:
|
|---|
| 2343 | status = setNamedAttribute(next_ref, event, interface);
|
|---|
| 2344 | break;
|
|---|
| 2345 | case kEventAccessiblePerformNamedAction:
|
|---|
| 2346 | status = performNamedAction(next_ref, event, interface);
|
|---|
| 2347 | break;
|
|---|
| 2348 | default:
|
|---|
| 2349 | status = CallNextEventHandler(next_ref, event);
|
|---|
| 2350 | break;
|
|---|
| 2351 | };
|
|---|
| 2352 | return status;
|
|---|
| 2353 | }
|
|---|
| 2354 | #endif
|
|---|
| 2355 |
|
|---|
| 2356 | void QAccessible::initialize()
|
|---|
| 2357 | {
|
|---|
| 2358 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 2359 | registerQtAccessibilityHIObjectSubclass();
|
|---|
| 2360 | installApplicationEventhandler();
|
|---|
| 2361 | #endif
|
|---|
| 2362 | }
|
|---|
| 2363 |
|
|---|
| 2364 | // Sets thre root object for the application
|
|---|
| 2365 | void QAccessible::setRootObject(QObject *object)
|
|---|
| 2366 | {
|
|---|
| 2367 | // Call installed root object handler if we have one
|
|---|
| 2368 | if (rootObjectHandler) {
|
|---|
| 2369 | rootObjectHandler(object);
|
|---|
| 2370 | return;
|
|---|
| 2371 | }
|
|---|
| 2372 |
|
|---|
| 2373 | rootObject = object;
|
|---|
| 2374 | }
|
|---|
| 2375 |
|
|---|
| 2376 | void QAccessible::cleanup()
|
|---|
| 2377 | {
|
|---|
| 2378 | accessibleHierarchyManager()->reset();
|
|---|
| 2379 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 2380 | removeEventhandler(applicationEventHandlerUPP);
|
|---|
| 2381 | removeEventhandler(objectCreateEventHandlerUPP);
|
|---|
| 2382 | removeEventhandler(accessibilityEventHandlerUPP);
|
|---|
| 2383 | #endif
|
|---|
| 2384 | }
|
|---|
| 2385 |
|
|---|
| 2386 | void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
|
|---|
| 2387 | {
|
|---|
| 2388 | // Call installed update handler if we have one.
|
|---|
| 2389 | if (updateHandler) {
|
|---|
| 2390 | updateHandler(object, child, reason);
|
|---|
| 2391 | return;
|
|---|
| 2392 | }
|
|---|
| 2393 |
|
|---|
| 2394 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 2395 | // Return if the mac accessibility is not enabled.
|
|---|
| 2396 | if(!AXAPIEnabled())
|
|---|
| 2397 | return;
|
|---|
| 2398 |
|
|---|
| 2399 | // Work around crash, disable accessiblity for focus frames.
|
|---|
| 2400 | if (qstrcmp(object->metaObject()->className(), "QFocusFrame") == 0)
|
|---|
| 2401 | return;
|
|---|
| 2402 |
|
|---|
| 2403 | // qDebug() << "updateAccessibility" << object << child << hex << reason;
|
|---|
| 2404 |
|
|---|
| 2405 | if (reason == ObjectShow) {
|
|---|
| 2406 | QAInterface interface = QAInterface(QAccessible::queryAccessibleInterface(object), child);
|
|---|
| 2407 | accessibleHierarchyManager()->registerInterface(interface);
|
|---|
| 2408 | }
|
|---|
| 2409 |
|
|---|
| 2410 | const QAElement element = accessibleHierarchyManager()->lookup(object, child);
|
|---|
| 2411 | if (element.isValid() == false)
|
|---|
| 2412 | return;
|
|---|
| 2413 |
|
|---|
| 2414 |
|
|---|
| 2415 | CFStringRef notification = 0;
|
|---|
| 2416 | if(object && object->isWidgetType() && reason == ObjectCreated) {
|
|---|
| 2417 | notification = CFStringRef(QAXWindowCreatedNotification);
|
|---|
| 2418 | } else if(reason == ValueChanged) {
|
|---|
| 2419 | notification = CFStringRef(QAXValueChangedNotification);
|
|---|
| 2420 | } else if(reason == MenuStart) {
|
|---|
| 2421 | notification = CFStringRef(QAXMenuOpenedNotification);
|
|---|
| 2422 | } else if(reason == MenuEnd) {
|
|---|
| 2423 | notification = CFStringRef(QAXMenuClosedNotification);
|
|---|
| 2424 | } else if(reason == LocationChanged) {
|
|---|
| 2425 | notification = CFStringRef(QAXWindowMovedNotification);
|
|---|
| 2426 | } else if(reason == ObjectShow || reason == ObjectHide ) {
|
|---|
| 2427 | // When a widget is deleted we get a ObjectHide before the destroyed(QObject *)
|
|---|
| 2428 | // signal is emitted (which makes sense). However, at this point we are in the
|
|---|
| 2429 | // middle of the QWidget destructor which means that we have to be careful when
|
|---|
| 2430 | // using the widget pointer. Since we can't control what the accessibilty interfaces
|
|---|
| 2431 | // does when navigate() is called below we ignore the hide update in this case.
|
|---|
| 2432 | // (the widget will be deleted soon anyway.)
|
|---|
| 2433 | extern QWidgetPrivate * qt_widget_private(QWidget *);
|
|---|
| 2434 | if (QWidget *widget = qobject_cast<QWidget*>(object)) {
|
|---|
| 2435 | if (qt_widget_private(widget)->data.in_destructor)
|
|---|
| 2436 | return;
|
|---|
| 2437 |
|
|---|
| 2438 | // Check widget parent as well, special case for preventing crash
|
|---|
| 2439 | // when the viewport() of an abstract scroll area is hidden when
|
|---|
| 2440 | // the QWidget destructor hides all its children.
|
|---|
| 2441 | QWidget *parentWidget = widget->parentWidget();
|
|---|
| 2442 | if (parentWidget && qt_widget_private(parentWidget)->data.in_destructor)
|
|---|
| 2443 | return;
|
|---|
| 2444 | }
|
|---|
| 2445 |
|
|---|
| 2446 | // There is no equivalent Mac notification for ObjectShow/Hide, so we call HIObjectSetAccessibilityIgnored
|
|---|
| 2447 | // and isItIntersting which will mark the HIObject accociated with the element as ignored if the
|
|---|
| 2448 | // QAccessible::Invisible state bit is set.
|
|---|
| 2449 | QAInterface interface = accessibleHierarchyManager()->lookup(element);
|
|---|
| 2450 | if (interface.isValid()) {
|
|---|
| 2451 | HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(interface));
|
|---|
| 2452 | }
|
|---|
| 2453 |
|
|---|
| 2454 | // If the interface manages its own children, also check if we should ignore those.
|
|---|
| 2455 | if (isItemView(interface) == false && managesChildren(interface)) {
|
|---|
| 2456 | for (int i = 1; i <= interface.childCount(); ++i) {
|
|---|
| 2457 | QAInterface childInterface = interface.navigate(QAccessible::Child, i);
|
|---|
| 2458 | if (childInterface.isValid() && childInterface.isHIView() == false) {
|
|---|
| 2459 | const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
|
|---|
| 2460 | if (element.isValid()) {
|
|---|
| 2461 | HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(childInterface));
|
|---|
| 2462 | }
|
|---|
| 2463 | }
|
|---|
| 2464 | }
|
|---|
| 2465 | }
|
|---|
| 2466 |
|
|---|
| 2467 | } else if(reason == Focus) {
|
|---|
| 2468 | if(object && object->isWidgetType()) {
|
|---|
| 2469 | QWidget *w = static_cast<QWidget*>(object);
|
|---|
| 2470 | if(w->isWindow())
|
|---|
| 2471 | notification = CFStringRef(QAXFocusedWindowChangedNotification);
|
|---|
| 2472 | else
|
|---|
| 2473 | notification = CFStringRef(QAXFocusedUIElementChangedNotification);
|
|---|
| 2474 | }
|
|---|
| 2475 | }
|
|---|
| 2476 |
|
|---|
| 2477 | if (!notification)
|
|---|
| 2478 | return;
|
|---|
| 2479 |
|
|---|
| 2480 | AXNotificationHIObjectNotify(notification, element.object(), element.id());
|
|---|
| 2481 | #endif
|
|---|
| 2482 | }
|
|---|
| 2483 |
|
|---|
| 2484 | QT_END_NAMESPACE
|
|---|
| 2485 |
|
|---|
| 2486 | #endif // QT_NO_ACCESSIBILITY
|
|---|