Warning: That file was not part of the compilation database. It may have many parsing errors.

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

Warning: That file was not part of the compilation database. It may have many parsing errors.