From 87ae97c11ab9b298c0ce6701873b45fc3992b385 Mon Sep 17 00:00:00 2001 From: Jan-Arve Saether Date: Fri, 16 Sep 2011 06:56:48 +0200 Subject: [PATCH] Refactor accessibility for Qt5 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * Moved most stuff to gui\accessible * Moved widget-specific stuff to widgets\accessible * Moved platform-specific code to either the bridge plugin (this was already the case) or to the platform plugin. * Added several classes and functions. These have not yet gone through an API review. The plan is to do that in a later commit. Classes: - QPlatformAccessibility - QWindowsAccessibility Functions: - QWindow *QAccessibleInterface::window(); - QPlatformAccessibility *QPlatformIntegration::accessibility() * The bridge code can now either be a plugin or integrated into the platform plugin * Mac accessibility is left out for now. Unix "should still work" (tm). These platforms should be fixed soon. Change-Id: Ib49ffa73b647ee0af90864544c2769440157f562 Reviewed-on: http://codereview.qt-project.org/5330 Reviewed-by: Frederik Gladhorn Reviewed-by: Jan-Arve Sæther --- src/gui/accessible/accessible.pri | 31 ++ src/{widgets => gui}/accessible/qaccessible.cpp | 107 +++-- src/{widgets => gui}/accessible/qaccessible.h | 12 +- src/{widgets => gui}/accessible/qaccessible2.cpp | 14 +- src/{widgets => gui}/accessible/qaccessible2.h | 22 +- src/{widgets => gui}/accessible/qaccessible_mac.mm | 0 .../accessible/qaccessible_mac_carbon.cpp | 0 .../accessible/qaccessible_mac_cocoa.mm | 0 .../accessible/qaccessible_mac_p.h | 0 .../accessible/qaccessiblebridge.cpp | 0 .../accessible/qaccessiblebridge.h | 4 +- .../accessible/qaccessibleobject.cpp | 104 +++-- .../accessible/qaccessibleobject.h | 27 +- .../accessible/qaccessibleplugin.cpp | 3 +- .../accessible/qaccessibleplugin.h | 6 +- .../accessible/qplatformaccessibility_qpa.cpp} | 105 ++--- src/gui/accessible/qplatformaccessibility_qpa.h | 74 +++ src/gui/gui.pro | 1 + src/gui/kernel/qplatformintegration_qpa.cpp | 11 + src/gui/kernel/qplatformintegration_qpa.h | 2 + src/gui/kernel/qwindow.cpp | 2 + src/plugins/accessible/widgets/complexwidgets.h | 2 +- src/plugins/accessible/widgets/itemviews.h | 4 +- src/plugins/accessible/widgets/main.cpp | 3 + .../accessible/widgets/qaccessiblewidgets.h | 2 +- src/plugins/accessible/widgets/rangecontrols.h | 2 +- src/plugins/accessible/widgets/simplewidgets.h | 2 +- src/plugins/platforms/windows/qtwindowsglobal.h | 3 + .../platforms/windows/qwindowsaccessibility.cpp} | 495 ++++++++++----------- .../platforms/windows/qwindowsaccessibility.h | 61 +++ src/plugins/platforms/windows/qwindowscontext.cpp | 3 + .../platforms/windows/qwindowsintegration.cpp | 7 + .../platforms/windows/qwindowsintegration.h | 1 + src/plugins/platforms/windows/windows.pro | 8 +- src/testlib/qtestaccessible.h | 8 +- src/widgets/accessible/accessible.pri | 23 +- src/widgets/accessible/qaccessiblewidget.cpp | 5 + src/widgets/accessible/qaccessiblewidget.h | 17 +- src/widgets/dialogs/qmessagebox.cpp | 2 +- src/widgets/graphicsview/qgraphicsscene.cpp | 2 +- src/widgets/kernel/qwidgetwindow_qpa.cpp | 8 + src/widgets/kernel/qwidgetwindow_qpa_p.h | 1 + src/widgets/widgets/qwidgetlinecontrol_p.h | 1 - tests/auto/qaccessibility/tst_qaccessibility.cpp | 2 +- 44 files changed, 703 insertions(+), 484 deletions(-) create mode 100644 src/gui/accessible/accessible.pri rename src/{widgets => gui}/accessible/qaccessible.cpp (95%) rename src/{widgets => gui}/accessible/qaccessible.h (98%) rename src/{widgets => gui}/accessible/qaccessible2.cpp (94%) rename src/{widgets => gui}/accessible/qaccessible2.h (94%) rename src/{widgets => gui}/accessible/qaccessible_mac.mm (100%) rename src/{widgets => gui}/accessible/qaccessible_mac_carbon.cpp (100%) rename src/{widgets => gui}/accessible/qaccessible_mac_cocoa.mm (100%) rename src/{widgets => gui}/accessible/qaccessible_mac_p.h (100%) rename src/{widgets => gui}/accessible/qaccessiblebridge.cpp (100%) rename src/{widgets => gui}/accessible/qaccessiblebridge.h (93%) rename src/{widgets => gui}/accessible/qaccessibleobject.cpp (80%) rename src/{widgets => gui}/accessible/qaccessibleobject.h (78%) rename src/{widgets => gui}/accessible/qaccessibleplugin.cpp (99%) rename src/{widgets => gui}/accessible/qaccessibleplugin.h (92%) rename src/{widgets/accessible/qaccessible_unix.cpp => gui/accessible/qplatformaccessibility_qpa.cpp} (73%) create mode 100644 src/gui/accessible/qplatformaccessibility_qpa.h rename src/{widgets/accessible/qaccessible_win.cpp => plugins/platforms/windows/qwindowsaccessibility.cpp} (84%) create mode 100644 src/plugins/platforms/windows/qwindowsaccessibility.h diff --git a/src/gui/accessible/accessible.pri b/src/gui/accessible/accessible.pri new file mode 100644 index 0000000..be2fe1a --- /dev/null +++ b/src/gui/accessible/accessible.pri @@ -0,0 +1,31 @@ +# Qt accessibility module + +contains(QT_CONFIG, accessibility) { + HEADERS += \ + accessible/qaccessible.h \ + accessible/qaccessible2.h \ + accessible/qaccessibleobject.h \ + accessible/qaccessibleplugin.h \ + accessible/qplatformaccessibility_qpa.h + + SOURCES += accessible/qaccessible.cpp \ + accessible/qaccessible2.cpp \ + accessible/qaccessibleobject.cpp \ + accessible/qaccessibleplugin.cpp \ + accessible/qplatformaccessibility_qpa.cpp + + HEADERS += accessible/qaccessiblebridge.h + SOURCES += accessible/qaccessiblebridge.cpp + +### FIXME +# mac:!qpa { +# HEADERS += accessible/qaccessible_mac_p.h +# OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \ +# accessible/qaccessible_mac_cocoa.mm +# } else:win32:!qpa { +# SOURCES += accessible/qaccessible_win.cpp +# } else { +# HEADERS += accessible/qaccessiblebridge.h +# SOURCES += accessible/qaccessible_unix.cpp accessible/qaccessiblebridge.cpp +# } +} diff --git a/src/widgets/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp similarity index 95% rename from src/widgets/accessible/qaccessible.cpp rename to src/gui/accessible/qaccessible.cpp index a61034a..2497e37 100644 --- a/src/widgets/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -44,15 +44,17 @@ #ifndef QT_NO_ACCESSIBILITY #include "qaccessibleplugin.h" -#include "qaccessiblewidget.h" -#include "qapplication.h" -#include "qhash.h" -#include "qmetaobject.h" -#include "qmutex.h" +#include "qaccessibleobject.h" +#include "qaccessiblebridge.h" +#include +#include +#include "qplatformaccessibility_qpa.h" + +#include +#include +#include #include -#include "qwidget.h" - QT_BEGIN_NAMESPACE /*! @@ -438,16 +440,10 @@ QT_BEGIN_NAMESPACE Destroys the object. */ -/*! - \fn void QAccessible::initialize() - \internal -*/ -/*! - \fn void QAccessible::cleanup() - \internal -*/ + +/* accessible widgets plugin discovery stuff */ #ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QAccessibleFactoryInterface_iid, QLatin1String("/accessible"))) @@ -460,6 +456,22 @@ QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0; static bool accessibility_active = false; static bool cleanupAdded = false; + +static QPlatformAccessibility *platformAccessibility() +{ + QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration(); + return pfIntegration ? pfIntegration->accessibility() : 0; +} + +/*! + \internal +*/ +void QAccessible::cleanup() +{ + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + pfAccessibility->cleanup(); +} + static void qAccessibleCleanup() { qAccessibleFactories()->clear(); @@ -507,6 +519,7 @@ static void qAccessibleCleanup() The function is called by setRootObject(). */ + /*! Installs the InterfaceFactory \a factory. The last factory added is the first one used by queryAccessibleInterface(). @@ -585,7 +598,8 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) return 0; QEvent e(QEvent::AccessibilityPrepare); - QApplication::sendEvent(object, &e); + + QCoreApplication::sendEvent(object, &e); const QMetaObject *mo = object->metaObject(); while (mo) { @@ -607,13 +621,11 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) mo = mo->superClass(); } - QWidget *widget = qobject_cast(object); - if (widget) - return new QAccessibleWidget(widget); - else if (object == qApp) - return new QAccessibleApplication(); - - return 0; + if (!iface) { + if (object == qApp) + iface = new QAccessibleApplication; + } + return iface; } /*! @@ -628,9 +640,9 @@ bool QAccessible::isActive() return accessibility_active; } -/*! - \fn void QAccessible::setRootObject(QObject *object) + +/*! Sets the root accessible object of this application to \a object. All other accessible objects in the application can be reached by the client using object navigation. @@ -644,10 +656,18 @@ bool QAccessible::isActive() \sa queryAccessibleInterface() */ +void QAccessible::setRootObject(QObject *o) +{ + if (rootObjectHandler) { + rootObjectHandler(o); + return; + } -/*! - \fn void QAccessible::updateAccessibility(QObject *object, int child, Event reason) + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + pfAccessibility->setRootObject(o); +} +/*! Notifies accessibility clients about a change in \a object's accessibility information. @@ -665,6 +685,21 @@ bool QAccessible::isActive() the parameters of the call is expensive you can test isActive() to avoid unnecessary computations. */ +void QAccessible::updateAccessibility(QObject *o, int who, Event reason) +{ + Q_ASSERT(o); + + if (updateHandler) { + updateHandler(o, who, reason); + return; + } + + if (!isActive()) + return; + + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + pfAccessibility->notifyAccessibilityUpdate(o, who, reason); +} /*! @@ -1161,6 +1196,24 @@ QVector > QAccessibleInterfa \sa value() */ +/*! + Returns the window associated with the underlying object. + For instance, QAccessibleWidget reimplements this and returns + the windowHandle() of the QWidget. + + The default implementation returns the window() of the parent interface. + + It is used on some platforms to be able to notify the AT client about + state changes. + \preliminary + */ +QWindow *QAccessibleInterface::window() const +{ + QAccessibleInterface *par = parent(); + QWindow *w = par ? par->window() : 0; + delete par; + return w; +} /*! \since 4.2 diff --git a/src/widgets/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h similarity index 98% rename from src/widgets/accessible/qaccessible.h rename to src/gui/accessible/qaccessible.h index e6a0f0d..a5e9945 100644 --- a/src/widgets/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -51,6 +51,8 @@ #include #include +class QWindow; + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -61,7 +63,7 @@ QT_MODULE(Gui) class QAccessibleInterface; -class Q_WIDGETS_EXPORT QAccessible +class Q_GUI_EXPORT QAccessible { public: enum Event { @@ -294,7 +296,7 @@ public: Increase = -3, Decrease = -4, Accept = -5, - Cancel = -6, + Cancel = -6, Select = -7, ClearSelection = -8, RemoveSelection = -9, @@ -325,7 +327,6 @@ public: static bool isActive(); static void setRootObject(QObject*); - static void initialize(); static void cleanup(); private: @@ -362,13 +363,14 @@ class QAccessibleActionInterface; class QAccessibleImageInterface; class QAccessibleTable2Interface; -class Q_WIDGETS_EXPORT QAccessibleInterface : public QAccessible +class Q_GUI_EXPORT QAccessibleInterface : public QAccessible { public: virtual ~QAccessibleInterface() {} // check for valid pointers virtual bool isValid() const = 0; virtual QObject *object() const = 0; + virtual QWindow *window() const; // hierarchy virtual int childCount() const = 0; @@ -440,7 +442,7 @@ private: QAccessible2Interface *cast_helper(QAccessible2::InterfaceType); }; -class Q_WIDGETS_EXPORT QAccessibleEvent : public QEvent +class QAccessibleEvent : public QEvent { public: inline QAccessibleEvent(Type type, int child); diff --git a/src/widgets/accessible/qaccessible2.cpp b/src/gui/accessible/qaccessible2.cpp similarity index 94% rename from src/widgets/accessible/qaccessible2.cpp rename to src/gui/accessible/qaccessible2.cpp index 896c2c8..aef7e1a 100644 --- a/src/widgets/accessible/qaccessible2.cpp +++ b/src/gui/accessible/qaccessible2.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qaccessible2.h" -#include "qapplication.h" +#include #include "qclipboard.h" #include "qtextboundaryfinder.h" @@ -137,7 +137,7 @@ QT_BEGIN_NAMESPACE /*! \internal */ -QString Q_WIDGETS_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, +QString Q_GUI_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, int *startOffset, int *endOffset, const QString& text) { QTextBoundaryFinder::BoundaryType type; @@ -175,7 +175,7 @@ QString Q_WIDGETS_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::B /*! \internal */ -QString Q_WIDGETS_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, +QString Q_GUI_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, int *startOffset, int *endOffset, const QString& text) { QTextBoundaryFinder::BoundaryType type; @@ -210,7 +210,7 @@ QString Q_WIDGETS_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::Bo /*! \internal */ -QString Q_WIDGETS_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, +QString Q_GUI_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, int *startOffset, int *endOffset, const QString& text) { QTextBoundaryFinder::BoundaryType type; @@ -264,7 +264,7 @@ void QAccessibleSimpleEditableTextInterface::copyText(int startOffset, int endOf Q_UNUSED(startOffset); Q_UNUSED(endOffset); #else - QApplication::clipboard()->setText(textForRange(iface, startOffset, endOffset)); + QGuiApplication::clipboard()->setText(textForRange(iface, startOffset, endOffset)); #endif } @@ -290,7 +290,7 @@ void QAccessibleSimpleEditableTextInterface::cutText(int startOffset, int endOff #else QString sub = textForRange(iface, startOffset, endOffset); deleteText(startOffset, endOffset); - QApplication::clipboard()->setText(sub); + QGuiApplication::clipboard()->setText(sub); #endif } @@ -300,7 +300,7 @@ void QAccessibleSimpleEditableTextInterface::pasteText(int offset) Q_UNUSED(offset); #else QString txt = iface->text(QAccessible::Value, 0); - txt.insert(offset, QApplication::clipboard()->text()); + txt.insert(offset, QGuiApplication::clipboard()->text()); iface->setText(QAccessible::Value, 0, txt); #endif } diff --git a/src/widgets/accessible/qaccessible2.h b/src/gui/accessible/qaccessible2.h similarity index 94% rename from src/widgets/accessible/qaccessible2.h rename to src/gui/accessible/qaccessible2.h index 69c1949..5ac877e 100644 --- a/src/widgets/accessible/qaccessible2.h +++ b/src/gui/accessible/qaccessible2.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLE2_H #define QACCESSIBLE2_H -#include +#include "qaccessible.h" QT_BEGIN_HEADER @@ -90,7 +90,7 @@ namespace QAccessible2 }; } -class Q_WIDGETS_EXPORT QAccessible2Interface +class Q_GUI_EXPORT QAccessible2Interface { public: virtual ~QAccessible2Interface() {} @@ -129,7 +129,7 @@ inline QAccessible2Interface *qAccessibleTable2CastHelper() { return 0; } } \ private: -class Q_WIDGETS_EXPORT QAccessibleTextInterface: public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleTextInterface: public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleTextCastHelper() { return this; } @@ -157,7 +157,7 @@ public: virtual void scrollToSubstring(int startIndex, int endIndex) = 0; }; -class Q_WIDGETS_EXPORT QAccessibleEditableTextInterface: public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleEditableTextInterface: public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleEditableTextCastHelper() { return this; } @@ -173,7 +173,7 @@ public: virtual void setAttributes(int startOffset, int endOffset, const QString &attributes) = 0; }; -class Q_WIDGETS_EXPORT QAccessibleSimpleEditableTextInterface: public QAccessibleEditableTextInterface +class Q_GUI_EXPORT QAccessibleSimpleEditableTextInterface: public QAccessibleEditableTextInterface { public: QAccessibleSimpleEditableTextInterface(QAccessibleInterface *accessibleInterface); @@ -190,7 +190,7 @@ private: QAccessibleInterface *iface; }; -class Q_WIDGETS_EXPORT QAccessibleValueInterface: public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleValueInterface: public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleValueCastHelper() { return this; } @@ -203,7 +203,7 @@ public: virtual QVariant minimumValue() = 0; }; -class Q_WIDGETS_EXPORT QAccessibleTableInterface: public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleTableInterface: public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleTableCastHelper() { return this; } @@ -237,7 +237,7 @@ public: int *columnSpan, bool *isSelected) = 0; }; -class Q_WIDGETS_EXPORT QAccessibleTable2CellInterface: public QAccessibleInterface +class Q_GUI_EXPORT QAccessibleTable2CellInterface: public QAccessibleInterface { public: // Returns the number of columns occupied by this cell accessible. @@ -266,7 +266,7 @@ public: virtual bool isExpandable() const = 0; }; -class Q_WIDGETS_EXPORT QAccessibleTable2Interface: public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleTable2Interface: public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleTable2CastHelper() { return this; } @@ -326,7 +326,7 @@ friend class QAbstractItemView; friend class QAbstractItemViewPrivate; }; -class Q_WIDGETS_EXPORT QAccessibleActionInterface : public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleActionInterface : public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleActionCastHelper() { return this; } @@ -339,7 +339,7 @@ public: virtual QStringList keyBindings(int actionIndex) = 0; }; -class Q_WIDGETS_EXPORT QAccessibleImageInterface : public QAccessible2Interface +class Q_GUI_EXPORT QAccessibleImageInterface : public QAccessible2Interface { public: inline QAccessible2Interface *qAccessibleImageCastHelper() { return this; } diff --git a/src/widgets/accessible/qaccessible_mac.mm b/src/gui/accessible/qaccessible_mac.mm similarity index 100% rename from src/widgets/accessible/qaccessible_mac.mm rename to src/gui/accessible/qaccessible_mac.mm diff --git a/src/widgets/accessible/qaccessible_mac_carbon.cpp b/src/gui/accessible/qaccessible_mac_carbon.cpp similarity index 100% rename from src/widgets/accessible/qaccessible_mac_carbon.cpp rename to src/gui/accessible/qaccessible_mac_carbon.cpp diff --git a/src/widgets/accessible/qaccessible_mac_cocoa.mm b/src/gui/accessible/qaccessible_mac_cocoa.mm similarity index 100% rename from src/widgets/accessible/qaccessible_mac_cocoa.mm rename to src/gui/accessible/qaccessible_mac_cocoa.mm diff --git a/src/widgets/accessible/qaccessible_mac_p.h b/src/gui/accessible/qaccessible_mac_p.h similarity index 100% rename from src/widgets/accessible/qaccessible_mac_p.h rename to src/gui/accessible/qaccessible_mac_p.h diff --git a/src/widgets/accessible/qaccessiblebridge.cpp b/src/gui/accessible/qaccessiblebridge.cpp similarity index 100% rename from src/widgets/accessible/qaccessiblebridge.cpp rename to src/gui/accessible/qaccessiblebridge.cpp diff --git a/src/widgets/accessible/qaccessiblebridge.h b/src/gui/accessible/qaccessiblebridge.h similarity index 93% rename from src/widgets/accessible/qaccessiblebridge.h rename to src/gui/accessible/qaccessiblebridge.h index 0ea0450..73edf51 100644 --- a/src/widgets/accessible/qaccessiblebridge.h +++ b/src/gui/accessible/qaccessiblebridge.h @@ -63,7 +63,7 @@ public: virtual void notifyAccessibilityUpdate(int, QAccessibleInterface*, int) = 0; }; -struct Q_WIDGETS_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface +struct Q_GUI_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface { virtual QAccessibleBridge *create(const QString& name) = 0; }; @@ -71,7 +71,7 @@ struct Q_WIDGETS_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInter #define QAccessibleBridgeFactoryInterface_iid "com.trolltech.Qt.QAccessibleBridgeFactoryInterface" Q_DECLARE_INTERFACE(QAccessibleBridgeFactoryInterface, QAccessibleBridgeFactoryInterface_iid) -class Q_WIDGETS_EXPORT QAccessibleBridgePlugin : public QObject, public QAccessibleBridgeFactoryInterface +class Q_GUI_EXPORT QAccessibleBridgePlugin : public QObject, public QAccessibleBridgeFactoryInterface { Q_OBJECT Q_INTERFACES(QAccessibleBridgeFactoryInterface:QFactoryInterface) diff --git a/src/widgets/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp similarity index 80% rename from src/widgets/accessible/qaccessibleobject.cpp rename to src/gui/accessible/qaccessibleobject.cpp index f1c5e13..af32943 100644 --- a/src/widgets/accessible/qaccessibleobject.cpp +++ b/src/gui/accessible/qaccessibleobject.cpp @@ -43,11 +43,11 @@ #ifndef QT_NO_ACCESSIBILITY -#include "qapplication.h" -#include "qwidget.h" +#include +#include + #include "qpointer.h" #include "qmetaobject.h" -#include "qvarlengtharray.h" QT_BEGIN_NAMESPACE @@ -208,15 +208,27 @@ QAccessibleApplication::QAccessibleApplication() { } -// all toplevel widgets except popups and the desktop -static QWidgetList topLevelWidgets() +QWindow *QAccessibleApplication::window() const +{ + // an application can have several windows, and AFAIK we don't need + // to notify about changes on the application. + return 0; +} + +// all toplevel windows except popups and the desktop +static QObjectList topLevelObjects() { - QWidgetList list; - const QWidgetList tlw(QApplication::topLevelWidgets()); + QObjectList list; + const QWindowList tlw(QGuiApplication::topLevelWindows()); for (int i = 0; i < tlw.count(); ++i) { - QWidget *w = tlw.at(i); - if (!(w->windowType() == Qt::Popup) && !(w->windowType() == Qt::Desktop)) - list.append(w); + QWindow *w = tlw.at(i); + if (w->windowType() != Qt::Popup && w->windowType() != Qt::Desktop) { + if (QAccessibleInterface *root = w->accessibleRoot()) { + if (root->object()) + list.append(w->accessibleRoot()->object()); + delete root; + } + } } return list; @@ -225,17 +237,14 @@ static QWidgetList topLevelWidgets() /*! \reimp */ int QAccessibleApplication::childCount() const { - return topLevelWidgets().count(); + return topLevelObjects().count(); } /*! \reimp */ int QAccessibleApplication::indexOfChild(const QAccessibleInterface *child) const { - if (!child->object()->isWidgetType()) - return -1; - - const QWidgetList tlw(topLevelWidgets()); - int index = tlw.indexOf(static_cast(child->object())); + const QObjectList tlw(topLevelObjects()); + int index = tlw.indexOf(child->object()); if (index != -1) ++index; return index; @@ -244,13 +253,14 @@ int QAccessibleApplication::indexOfChild(const QAccessibleInterface *child) cons /*! \reimp */ int QAccessibleApplication::childAt(int x, int y) const { - const QWidgetList tlw(topLevelWidgets()); - for (int i = 0; i < tlw.count(); ++i) { - QWidget *w = tlw.at(i); - if (w->frameGeometry().contains(x,y)) + for (int i = 0; i < childCount(); ++i) { + QAccessibleInterface *childIface = child(i); + QRect geom = childIface->rect(); + if (geom.contains(x,y)) return i+1; + delete childIface; } - return -1; + return rect().contains(x,y) ? 0 : -1; } /*! \reimp */ @@ -270,17 +280,6 @@ QAccessible::Relation QAccessibleApplication::relationTo(int child, const return Self; } - QWidgetList tlw(topLevelWidgets()); - if (tlw.contains(qobject_cast(o))) - return Ancestor; - - for (int i = 0; i < tlw.count(); ++i) { - QWidget *w = tlw.at(i); - QObjectList cl = w->findChildren(QString()); - if (cl.contains(o)) - return Ancestor; - } - return Unrelated; } @@ -292,9 +291,9 @@ QAccessibleInterface *QAccessibleApplication::parent() const QAccessibleInterface *QAccessibleApplication::child(int index) const { Q_ASSERT(index >= 0); - const QWidgetList tlw(topLevelWidgets()); - if (index >= 0 && index < tlw.count()) - return QAccessible::queryAccessibleInterface(tlw.at(index)); + const QObjectList tlo(topLevelObjects()); + if (index >= 0 && index < tlo.count()) + return QAccessible::queryAccessibleInterface(tlo.at(index)); return 0; } @@ -312,18 +311,12 @@ int QAccessibleApplication::navigate(RelationFlag relation, int entry, case Self: targetObject = object(); break; - case Child: - if (entry > 0 && entry <= childCount()) { - const QWidgetList tlw(topLevelWidgets()); - if (tlw.count() >= entry) - targetObject = tlw.at(entry-1); - } else { - return -1; - } - break; case FocusChild: - targetObject = QApplication::activeWindow(); + targetObject = QGuiApplication::activeWindow(); break; + case Ancestor: + *target = parent(); + return 0; default: break; } @@ -336,9 +329,9 @@ QString QAccessibleApplication::text(Text t, int) const { switch (t) { case Name: - return QApplication::applicationName(); + return QGuiApplication::applicationName(); case Description: - return QApplication::applicationFilePath(); + return QGuiApplication::applicationFilePath(); default: break; } @@ -354,7 +347,7 @@ QAccessible::Role QAccessibleApplication::role(int) const /*! \reimp */ QAccessible::State QAccessibleApplication::state(int) const { - return QApplication::activeWindow() ? Focused : Normal; + return QGuiApplication::activeWindow() ? Focused : Normal; } /*! \reimp */ @@ -366,16 +359,19 @@ int QAccessibleApplication::userActionCount(int) const /*! \reimp */ bool QAccessibleApplication::doAction(int action, int child, const QVariantList ¶m) { + //###Move to IA2 action interface at some point to get rid of the ambiguity. + /* //### what is action == 0 and action == 1 ????? if (action == 0 || action == 1) { - QWidget *w = 0; - w = QApplication::activeWindow(); + QWindow *w = 0; + w = QGuiApplication::activeWindow(); if (!w) - w = topLevelWidgets().at(0); + w = topLevelWindows().at(0); if (!w) return false; - w->activateWindow(); + w->requestActivateWindow(); return true; } + */ return QAccessibleObject::doAction(action, child, param); } @@ -385,9 +381,9 @@ QString QAccessibleApplication::actionText(int action, Text text, int child) con QString str; if ((action == 0 || action == 1) && !child) switch (text) { case Name: - return QApplication::tr("Activate"); + return QGuiApplication::tr("Activate"); case Description: - return QApplication::tr("Activates the program's main window"); + return QGuiApplication::tr("Activates the program's main window"); default: break; } diff --git a/src/widgets/accessible/qaccessibleobject.h b/src/gui/accessible/qaccessibleobject.h similarity index 78% rename from src/widgets/accessible/qaccessibleobject.h rename to src/gui/accessible/qaccessibleobject.h index 7d31b6e..0252a43 100644 --- a/src/widgets/accessible/qaccessibleobject.h +++ b/src/gui/accessible/qaccessibleobject.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLEOBJECT_H #define QACCESSIBLEOBJECT_H -#include +#include "qaccessible.h" QT_BEGIN_HEADER @@ -55,7 +55,7 @@ QT_MODULE(Gui) class QAccessibleObjectPrivate; class QObject; -class Q_WIDGETS_EXPORT QAccessibleObject : public QAccessibleInterface +class Q_GUI_EXPORT QAccessibleObject : public QAccessibleInterface { public: explicit QAccessibleObject(QObject *object); @@ -64,13 +64,13 @@ public: QObject *object() const; // properties - QRect rect(int child) const; + QRect rect(int child = 0) const; void setText(Text t, int child, const QString &text); // actions - int userActionCount(int child) const; - bool doAction(int action, int child, const QVariantList ¶ms); - QString actionText(int action, Text t, int child) const; + int userActionCount(int child = 0) const; + bool doAction(int action, int child = 0, const QVariantList ¶ms = QVariantList()); + QString actionText(int action, Text t, int child = 0) const; protected: virtual ~QAccessibleObject(); @@ -80,11 +80,12 @@ private: Q_DISABLE_COPY(QAccessibleObject) }; -class Q_WIDGETS_EXPORT QAccessibleApplication : public QAccessibleObject +class Q_GUI_EXPORT QAccessibleApplication : public QAccessibleObject { public: QAccessibleApplication(); + QWindow *window() const; // relations int childCount() const; int indexOfChild(const QAccessibleInterface*) const; @@ -97,14 +98,14 @@ public: int navigate(RelationFlag, int, QAccessibleInterface **) const; // properties and state - QString text(Text t, int child) const; - Role role(int child) const; - State state(int child) const; + QString text(Text t, int child = 0) const; + Role role(int child = 0) const; + State state(int child = 0) const; // actions - int userActionCount(int child) const; - bool doAction(int action, int child, const QVariantList ¶ms); - QString actionText(int action, Text t, int child) const; + int userActionCount(int child = 0) const; + bool doAction(int action, int child = 0, const QVariantList ¶ms = QVariantList()); + QString actionText(int action, Text t, int child = 0) const; }; #endif // QT_NO_ACCESSIBILITY diff --git a/src/widgets/accessible/qaccessibleplugin.cpp b/src/gui/accessible/qaccessibleplugin.cpp similarity index 99% rename from src/widgets/accessible/qaccessibleplugin.cpp rename to src/gui/accessible/qaccessibleplugin.cpp index 509463b..618a31a 100644 --- a/src/widgets/accessible/qaccessibleplugin.cpp +++ b/src/gui/accessible/qaccessibleplugin.cpp @@ -39,10 +39,11 @@ ** ****************************************************************************/ -#include "qaccessibleplugin.h" +#include #ifndef QT_NO_ACCESSIBILITY +#include "qaccessibleplugin.h" #include "qaccessible.h" QT_BEGIN_NAMESPACE diff --git a/src/widgets/accessible/qaccessibleplugin.h b/src/gui/accessible/qaccessibleplugin.h similarity index 92% rename from src/widgets/accessible/qaccessibleplugin.h rename to src/gui/accessible/qaccessibleplugin.h index a71a143..4a92094 100644 --- a/src/widgets/accessible/qaccessibleplugin.h +++ b/src/gui/accessible/qaccessibleplugin.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLEPLUGIN_H #define QACCESSIBLEPLUGIN_H -#include +#include "qaccessible.h" #include QT_BEGIN_HEADER @@ -56,7 +56,7 @@ QT_MODULE(Gui) class QStringList; class QAccessibleInterface; -struct Q_WIDGETS_EXPORT QAccessibleFactoryInterface : public QAccessible, public QFactoryInterface +struct Q_GUI_EXPORT QAccessibleFactoryInterface : public QAccessible, public QFactoryInterface { virtual QAccessibleInterface* create(const QString &key, QObject *object) = 0; }; @@ -66,7 +66,7 @@ Q_DECLARE_INTERFACE(QAccessibleFactoryInterface, QAccessibleFactoryInterface_iid class QAccessiblePluginPrivate; -class Q_WIDGETS_EXPORT QAccessiblePlugin : public QObject, public QAccessibleFactoryInterface +class Q_GUI_EXPORT QAccessiblePlugin : public QObject, public QAccessibleFactoryInterface { Q_OBJECT Q_INTERFACES(QAccessibleFactoryInterface:QFactoryInterface) diff --git a/src/widgets/accessible/qaccessible_unix.cpp b/src/gui/accessible/qplatformaccessibility_qpa.cpp similarity index 73% rename from src/widgets/accessible/qaccessible_unix.cpp rename to src/gui/accessible/qplatformaccessibility_qpa.cpp index 1c1eb2a..f912907 100644 --- a/src/widgets/accessible/qaccessible_unix.cpp +++ b/src/gui/accessible/qplatformaccessibility_qpa.cpp @@ -38,64 +38,45 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - -#include "qaccessible.h" +#include "qplatformaccessibility_qpa.h" +#include +#include "qaccessibleplugin.h" +#include "qaccessibleobject.h" #include "qaccessiblebridge.h" +#include -#ifndef QT_NO_ACCESSIBILITY - -#include "qcoreapplication.h" -#include "qmutex.h" -#include "qvector.h" -#include "private/qfactoryloader_p.h" - -#include - -QT_BEGIN_NAMESPACE - +/* accessiblebridge plugin discovery stuff */ #ifndef QT_NO_LIBRARY -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, bridgeloader, (QAccessibleBridgeFactoryInterface_iid, QLatin1String("/accessiblebridge"))) #endif + Q_GLOBAL_STATIC(QVector, bridges) -static bool isInit = false; -void QAccessible::initialize() -{ - if (isInit) - return; - isInit = true; +/*! + \class QPlatformAccessibility + \brief The QPlatformAccessibility class is the base class for + integrating accessibility backends - if (qgetenv("QT_ACCESSIBILITY") != "1") - return; -#ifndef QT_NO_LIBRARY - const QStringList l = loader()->keys(); - for (int i = 0; i < l.count(); ++i) { - if (QAccessibleBridgeFactoryInterface *factory = - qobject_cast(loader()->instance(l.at(i)))) { - QAccessibleBridge * bridge = factory->create(l.at(i)); - if (bridge) - bridges()->append(bridge); - } - } -#endif -} + \preliminary + \ingroup accessibility -void QAccessible::cleanup() + \sa QAccessible +*/ +QPlatformAccessibility::QPlatformAccessibility() { - qDeleteAll(*bridges()); } -void QAccessible::updateAccessibility(QObject *o, int who, Event reason) +QPlatformAccessibility::~QPlatformAccessibility() { - Q_ASSERT(o); - - if (updateHandler) { - updateHandler(o, who, reason); - return; - } +} +void QPlatformAccessibility::notifyAccessibilityUpdate(QObject *o, + int who, + QAccessible::Event reason) +{ initialize(); + if (!bridges() || bridges()->isEmpty()) return; @@ -117,15 +98,11 @@ void QAccessible::updateAccessibility(QObject *o, int who, Event reason) for (int i = 0; i < bridges()->count(); ++i) bridges()->at(i)->notifyAccessibilityUpdate(reason, iface, who); delete iface; + } -void QAccessible::setRootObject(QObject *o) +void QPlatformAccessibility::setRootObject(QObject *o) { - if (rootObjectHandler) { - rootObjectHandler(o); - return; - } - initialize(); if (bridges()->isEmpty()) return; @@ -139,7 +116,33 @@ void QAccessible::setRootObject(QObject *o) } } -QT_END_NAMESPACE +void QPlatformAccessibility::initialize() +{ + static bool isInit = false; + if (isInit) + return; + isInit = true; // ### not atomic +#ifdef Q_OS_UNIX + if (qgetenv("QT_ACCESSIBILITY") != "1") + return; +#endif +#ifndef QT_NO_LIBRARY + const QStringList l = bridgeloader()->keys(); + for (int i = 0; i < l.count(); ++i) { + if (QAccessibleBridgeFactoryInterface *factory = + qobject_cast(bridgeloader()->instance(l.at(i)))) { + QAccessibleBridge * bridge = factory->create(l.at(i)); + if (bridge) { + bridges()->append(bridge); +# + } + } + } +#endif +} -#endif // QT_NO_ACCESSIBILITY +void QPlatformAccessibility::cleanup() +{ + qDeleteAll(*bridges()); +} diff --git a/src/gui/accessible/qplatformaccessibility_qpa.h b/src/gui/accessible/qplatformaccessibility_qpa.h new file mode 100644 index 0000000..c12f1c0 --- /dev/null +++ b/src/gui/accessible/qplatformaccessibility_qpa.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QPLATFORMACCESSIBILITY_H +#define QPLATFORMACCESSIBILITY_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qaccessible.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class Q_GUI_EXPORT QPlatformAccessibility +{ +public: + QPlatformAccessibility(); + + virtual ~QPlatformAccessibility(); + virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason); + virtual void setRootObject(QObject *o); + virtual void initialize(); + virtual void cleanup(); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_ACCESSIBILITY + +#endif // QPLATFORMACCESSIBILITY_H diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 4ee9d76..aafc477 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -15,6 +15,7 @@ load(qt_module_config) HEADERS += $$QT_SOURCE_TREE/src/gui/qtguiversion.h +include(accessible/accessible.pri) include(kernel/kernel.pri) include(image/image.pri) include(text/text.pri) diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index 856ceab..f3acf43 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -209,6 +210,16 @@ QPlatformInputContext *QPlatformIntegration::inputContext() const return 0; } +/*! + Returns the platforms accessibility. + + The default implementation returns 0, implying no accessibility support. +*/ +QPlatformAccessibility *QPlatformIntegration::accessibility() const +{ + return new QPlatformAccessibility; +} + QVariant QPlatformIntegration::styleHint(StyleHint hint) const { switch (hint) { diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index b9e1d02..0ccd9f9 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -67,6 +67,7 @@ class QMenu; class QMenuBar; class QPlatformMenu; class QPlatformMenuBar; +class QPlatformAccessibility; class Q_GUI_EXPORT QPlatformIntegration { @@ -101,6 +102,7 @@ public: virtual QPlatformMenu *createPlatformMenu(QMenu *menu = 0) const; virtual QPlatformMenuBar *createPlatformMenuBar(QMenuBar *menuBar = 0) const; + virtual QPlatformAccessibility *accessibility() const; // Access native handles. The window handle is already available from Wid; virtual QPlatformNativeInterface *nativeInterface() const; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 118844a..d17ff9e 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -559,6 +559,8 @@ void QWindow::setScreen(QScreen *newScreen) /*! Returns the accessibility interface for the object that the window represents + \preliminary + \sa QAccessible */ QAccessibleInterface *QWindow::accessibleRoot() const { diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h index 8566fe6..81f79fd 100644 --- a/src/plugins/accessible/widgets/complexwidgets.h +++ b/src/plugins/accessible/widgets/complexwidgets.h @@ -45,7 +45,7 @@ #include #include #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h index c2b255b..41d2b6c 100644 --- a/src/plugins/accessible/widgets/itemviews.h +++ b/src/plugins/accessible/widgets/itemviews.h @@ -44,8 +44,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp index a7b3a95..fb6bd1e 100644 --- a/src/plugins/accessible/widgets/main.cpp +++ b/src/plugins/accessible/widgets/main.cpp @@ -153,6 +153,7 @@ QStringList AccessibleFactory::keys() const #ifndef QT_NO_DOCKWIDGET list << QLatin1String("QDockWidget"); #endif + list << QLatin1String("QAccessibleWidget"); return list; } @@ -348,6 +349,8 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec } else if (classname == QLatin1String("QDockWidget")) { iface = new QAccessibleDockWidget(widget); #endif + } else { + iface = new QAccessibleWidget(widget); } return iface; diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h index bf3c769..2a595d7 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.h +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLEWIDGETS_H #define QACCESSIBLEWIDGETS_H -#include +#include #include #ifndef QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h index 30d8f00..39916a7 100644 --- a/src/plugins/accessible/widgets/rangecontrols.h +++ b/src/plugins/accessible/widgets/rangecontrols.h @@ -43,7 +43,7 @@ #define RANGECONTROLS_H #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index aa68cf3..122d086 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -43,7 +43,7 @@ #define SIMPLEWIDGETS_H #include -#include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 66d1858..254463e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -88,6 +88,7 @@ enum WindowsEventType // Simplify event types ClipboardEvent = ClipboardEventFlag + 1, ActivateApplicationEvent = ApplicationEventFlag + 1, DeactivateApplicationEvent = ApplicationEventFlag + 2, + AccessibleObjectFromWindowRequest = ApplicationEventFlag + 3, InputMethodStartCompositionEvent = InputMethodEventFlag + 1, InputMethodCompositionEvent = InputMethodEventFlag + 2, InputMethodEndCompositionEvent = InputMethodEventFlag + 3, @@ -166,6 +167,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI default: break; } + case WM_GETOBJECT: + return QtWindows::AccessibleObjectFromWindowRequest; default: break; } diff --git a/src/widgets/accessible/qaccessible_win.cpp b/src/plugins/platforms/windows/qwindowsaccessibility.cpp similarity index 84% rename from src/widgets/accessible/qaccessible_win.cpp rename to src/plugins/platforms/windows/qwindowsaccessibility.cpp index f09f4bb..fdc3273 100644 --- a/src/widgets/accessible/qaccessible_win.cpp +++ b/src/plugins/platforms/windows/qwindowsaccessibility.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -38,20 +38,32 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "qaccessible.h" + +#include #ifndef QT_NO_ACCESSIBILITY -#include "qapplication.h" + +#include "qwindowsaccessibility.h" +#include "qwindowscontext.h" + #include -#include "qmessagebox.h" // ### dependency -#include "qt_windows.h" -#include "qwidget.h" -#include "qsettings.h" + #include +#include #include +#include +#include #include -#include #include +#include +#include +#include +#include "qt_windows.h" + +//#include +#ifndef UiaRootObjectId +#define UiaRootObjectId -25 +#endif #include #if !defined(WINABLEAPI) @@ -255,9 +267,9 @@ static const char *eventString(QAccessible::Event ev) void showDebug(const char* funcName, const QAccessibleInterface *iface) { - qDebug() << "Role:" << roleString(iface->role(0)) - << "Name:" << iface->text(QAccessible::Name, 0) - << "State:" << QString::number(int(iface->state(0)), 16) + qDebug() << "Role:" << roleString(iface->role(0)) + << "Name:" << iface->text(QAccessible::Name, 0) + << "State:" << QString::number(int(iface->state(0)), 16) << QLatin1String(funcName); } #else @@ -269,229 +281,6 @@ typedef QMap > NotifyMap; Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents) static int eventNum = 0; - -void QAccessible::initialize() -{ - -} -void QAccessible::cleanup() -{ - -} - -void QAccessible::updateAccessibility(QObject *o, int who, Event reason) -{ - Q_ASSERT(o); - - if (updateHandler) { - updateHandler(o, who, reason); - return; - } - - QString soundName; - switch (reason) { - case PopupMenuStart: - soundName = QLatin1String("MenuPopup"); - break; - - case MenuCommand: - soundName = QLatin1String("MenuCommand"); - break; - - case Alert: - { -#ifndef QT_NO_MESSAGEBOX - QMessageBox *mb = qobject_cast(o); - if (mb) { - switch (mb->icon()) { - case QMessageBox::Warning: - soundName = QLatin1String("SystemExclamation"); - break; - case QMessageBox::Critical: - soundName = QLatin1String("SystemHand"); - break; - case QMessageBox::Information: - soundName = QLatin1String("SystemAsterisk"); - break; - default: - break; - } - } else -#endif // QT_NO_MESSAGEBOX - { - soundName = QLatin1String("SystemAsterisk"); - } - - } - break; - default: - break; - } - - if (soundName.size()) { -#ifndef QT_NO_SETTINGS - QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName, - QSettings::NativeFormat); - QString file = settings.value(QLatin1String(".Current/.")).toString(); -#else - QString file; -#endif - if (!file.isEmpty()) { - PlaySound(reinterpret_cast(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT); - } - } - - if (!isActive()) - return; - - typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG); - -#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0 - // There is no user32.lib nor NotifyWinEvent for CE - return; -#else - static PtrNotifyWinEvent ptrNotifyWinEvent = 0; - static bool resolvedNWE = false; - if (!resolvedNWE) { - resolvedNWE = true; - ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent"); - } - if (!ptrNotifyWinEvent) - return; - - // An event has to be associated with a window, - // so find the first parent that is a widget. - QWidget *w = 0; - QObject *p = o; - do { - if (p->isWidgetType()) { - w = static_cast(p); - if (w->internalWinId()) - break; - } - if (QGraphicsObject *gfxObj = qobject_cast(p)) { - QGraphicsItem *parentItem = gfxObj->parentItem(); - if (parentItem) { - p = parentItem->toGraphicsObject(); - } else { - QGraphicsView *view = 0; - if (QGraphicsScene *scene = gfxObj->scene()) { - QWidget *fw = QApplication::focusWidget(); - const QList views = scene->views(); - for (int i = 0 ; i < views.count() && view != fw; ++i) { - view = views.at(i); - } - } - p = view; - } - } else { - p = p->parent(); - } - - } while (p); - - //qDebug() << "updateAccessibility(), hwnd:" << w << ", object:" << o << "," << eventString(reason); - if (!w) { - if (reason != QAccessible::ContextHelpStart && - reason != QAccessible::ContextHelpEnd) - w = QApplication::focusWidget(); - if (!w) { - w = QApplication::activeWindow(); - - if (!w) - return; - -// ### Fixme -// if (!w) { -// w = qApp->mainWidget(); -// if (!w) -// return; -// } - } - } - - WId wid = w->internalWinId(); - if (reason != MenuCommand) { // MenuCommand is faked - if (w != o) { - // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE" - eventNum %= 50; //[0..49] - int eventId = - eventNum - 1; - - qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o,who)); - ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, eventId ); - - ++eventNum; - } else { - ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, who); - } - } -#endif // Q_WS_WINCE -} - -/* == SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE == - - If the user requested to send the event to a widget with no window, - we need to send an event to an object with no hwnd. - The way we do that is to send it to the *first* ancestor widget - with a window. - Then we'll need a way of identifying the child: - We'll just keep a list of the most recent events that we have sent, - where each entry in the list is identified by a negative value - between [-50,-1]. This negative value we will pass on to - NotifyWinEvent() as the child id. When the negative value have - reached -50, it will wrap around to -1. This seems to be enough - - Now, when the client receives that event, he will first call - AccessibleObjectFromEvent() where dwChildID is the special - negative value. AccessibleObjectFromEvent does two steps: - 1. It will first sent a WM_GETOBJECT to the server, asking - for the IAccessible interface for the HWND. - 2. With the IAccessible interface it got hold of it will call - acc_getChild where the child id argument is the special - negative identifier. In our reimplementation of get_accChild - we check for this if the child id is negative. If it is, then - we'll look up in our table for the entry that is associated - with that value. - The entry will then contain a pointer to the QObject /QWidget - that we can use to call queryAccessibleInterface() on. - - - The following figure shows how the interaction between server and - client is in the case when the server is sending an event. - -SERVER (Qt) | CLIENT | ---------------------------------------------+---------------------------------------+ - | -acc->updateAccessibility(obj, childIndex) | - | -recentEvents()->insert(- 1 - eventNum, | - qMakePair(obj, childIndex) | -NotifyWinEvent(hwnd, childId) => | - | AccessibleObjectFromEvent(event, hwnd, OBJID_CLIENT, childId ) - | will do: - <=== 1. send WM_GETOBJECT(hwnd, OBJID_CLIENT) -widget ~= hwnd -iface = queryAccessibleInteface(widget) -(create IAccessible interface wrapper for - iface) - return iface ===> IAccessible* iface; (for hwnd) - | - <=== call iface->get_accChild(childId) -get_accChild() { | - if (varChildID.lVal < 0) { - QPair ref = recentEvents().value(varChildID.lVal); - [...] - } -*/ - - -void QAccessible::setRootObject(QObject *o) -{ - if (rootObjectHandler) { - rootObjectHandler(o); - } -} - class QWindowsEnumerate : public IEnumVARIANT { public: @@ -674,14 +463,6 @@ static inline BSTR QStringToBSTR(const QString &str) /* */ -IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access) -{ - QWindowsAccessible *acc = new QWindowsAccessible(access); - IAccessible *iface; - acc->QueryInterface(IID_IAccessible, (void**)&iface); - - return iface; -} /* IUnknown @@ -742,45 +523,45 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar // PROPERTIES: Hierarchical if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent")) rgdispid[0] = DISPID_ACC_PARENT; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount")) rgdispid[0] = DISPID_ACC_CHILDCOUNT; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChild")) rgdispid[0] = DISPID_ACC_CHILD; // PROPERTIES: Descriptional - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName(")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accName(")) rgdispid[0] = DISPID_ACC_NAME; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accValue")) rgdispid[0] = DISPID_ACC_VALUE; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription")) rgdispid[0] = DISPID_ACC_DESCRIPTION; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accRole")) rgdispid[0] = DISPID_ACC_ROLE; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accState")) rgdispid[0] = DISPID_ACC_STATE; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp")) rgdispid[0] = DISPID_ACC_HELP; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic")) rgdispid[0] = DISPID_ACC_HELPTOPIC; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut")) rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus")) rgdispid[0] = DISPID_ACC_FOCUS; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection")) rgdispid[0] = DISPID_ACC_SELECTION; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction")) rgdispid[0] = DISPID_ACC_DEFAULTACTION; // METHODS - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect")) rgdispid[0] = DISPID_ACC_SELECT; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation")) rgdispid[0] = DISPID_ACC_LOCATION; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate")) rgdispid[0] = DISPID_ACC_NAVIGATE; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest")) rgdispid[0] = DISPID_ACC_HITTEST; - else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction")) + else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction")) rgdispid[0] = DISPID_ACC_DODEFAULTACTION; else return DISP_E_UNKNOWNINTERFACE; @@ -798,7 +579,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _G { HRESULT hr = DISP_E_MEMBERNOTFOUND; - switch(dispIdMember) + switch (dispIdMember) { case DISPID_ACC_PARENT: if (wFlags == DISPATCH_PROPERTYGET) { @@ -1021,7 +802,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT v QAccessibleInterface *acc = 0; int control = -1; - switch(navDir) { + switch (navDir) { case NAVDIR_FIRSTCHILD: control = accessible->navigate(Child, 1, &acc); break; @@ -1422,11 +1203,27 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd) return E_UNEXPECTED; QObject *o = accessible->object(); - if (!o || !o->isWidgetType()) + QWindow *window = qobject_cast(o); + if (!window) + window = QGuiApplication::topLevelWindows().first(); + + + Q_ASSERT(window); + if (!o || !window) return E_FAIL; + +#ifdef Q_WS_QPA + //QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface(); + //Q_ASSERT(platform); + //*phwnd = (HWND)platform->nativeResourceForWindow("handle", window); + + + return S_OK; +#else *phwnd = static_cast(o)->effectiveWinId(); return S_OK; +#endif } HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL) @@ -1434,6 +1231,176 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL) return S_OK; } + +QWindowsAccessibility::QWindowsAccessibility() +{ +} + + +void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason) +{ + QString soundName; + switch (reason) { + case QAccessible::PopupMenuStart: + soundName = QLatin1String("MenuPopup"); + break; + + case QAccessible::MenuCommand: + soundName = QLatin1String("MenuCommand"); + break; + + case QAccessible::Alert: + { + /* ### FIXME +#ifndef QT_NO_MESSAGEBOX + QMessageBox *mb = qobject_cast(o); + if (mb) { + switch (mb->icon()) { + case QMessageBox::Warning: + soundName = QLatin1String("SystemExclamation"); + break; + case QMessageBox::Critical: + soundName = QLatin1String("SystemHand"); + break; + case QMessageBox::Information: + soundName = QLatin1String("SystemAsterisk"); + break; + default: + break; + } + } else +#endif // QT_NO_MESSAGEBOX +*/ + { + soundName = QLatin1String("SystemAsterisk"); + } + + } + break; + default: + break; + } + + if (!soundName.isEmpty()) { +#ifndef QT_NO_SETTINGS + QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName, + QSettings::NativeFormat); + QString file = settings.value(QLatin1String(".Current/.")).toString(); +#else + QString file; +#endif + if (!file.isEmpty()) { + PlaySound(reinterpret_cast(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT); + } + } + + typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG); + +#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0 + // There is no user32.lib nor NotifyWinEvent for CE + return; +#else + static PtrNotifyWinEvent ptrNotifyWinEvent = 0; + static bool resolvedNWE = false; + if (!resolvedNWE) { + resolvedNWE = true; + ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent"); + } + if (!ptrNotifyWinEvent) + return; + + // An event has to be associated with a window, + // so find the first parent that is a widget and that has a WId + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o); + QWindow *window = iface->window(); + + if (!window) { + window = QGuiApplication::activeWindow(); + if (!window) + return; + } + + QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface(); + HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window); + + if (reason != QAccessible::MenuCommand) { // MenuCommand is faked + // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE" + eventNum %= 50; //[0..49] + int eventId = - eventNum - 1; + + qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o, who)); + ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId ); + + ++eventNum; + } +#endif // Q_WS_WINCE + +} + +/* +void QWindowsAccessibility::setRootObject(QObject *o) +{ + +} + +void QWindowsAccessibility::initialize() +{ + +} + +void QWindowsAccessibility::cleanup() +{ + +} + +*/ + +bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult) +{ + if (static_cast(lParam) == static_cast(UiaRootObjectId)) { + /* For UI Automation + */ + } else if ((DWORD)lParam == OBJID_CLIENT) { +#if 1 + // Ignoring all requests while starting up + // ### Maybe QPA takes care of this??? + if (QApplication::startingUp() || QApplication::closingDown()) + return false; +#endif + + typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN); + static PtrLresultFromObject ptrLresultFromObject = 0; + static bool oleaccChecked = false; + + if (!oleaccChecked) { + oleaccChecked = true; +#if !defined(Q_OS_WINCE) + ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject"); +#endif + } + + if (ptrLresultFromObject) { + QWindow *window = QWindowsContext::instance()->findWindow(hwnd); + if (window) { + QAccessibleInterface *acc = window->accessibleRoot(); + if (acc) { + QWindowsAccessible *winacc = new QWindowsAccessible(acc); + IAccessible *iface; + HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface); + if (SUCCEEDED(hr)) { + *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2 + if (*lResult) { + iface->Release(); // the client will release the object again, and then it will destroy itself + } + return true; + } + } + } + } + } + return false; +} + QT_END_NAMESPACE -#endif // QT_NO_ACCESSIBILITY +#endif //QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.h b/src/plugins/platforms/windows/qwindowsaccessibility.h new file mode 100644 index 0000000..d27b28c --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsaccessibility.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSACCESSIBILITY_H +#define QWINDOWSACCESSIBILITY_H + +#include +#include + +class QWindowsAccessibility : public QPlatformAccessibility +{ +public: + QWindowsAccessibility(); + static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult); + virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason); + /* + virtual void setRootObject(QObject *o); + virtual void initialize(); + virtual void cleanup(); +*/ +}; + +#endif // QWINDOWSACCESSIBILITY_H diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3dae732..3da1281 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -47,6 +47,7 @@ #include "qtwindowsglobal.h" #include "qwindowsmime.h" #include "qwindowsinputcontext.h" +#include "qwindowsaccessibility.h" #include #include @@ -623,6 +624,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::UnknownEvent: return false; + case QtWindows::AccessibleObjectFromWindowRequest: + return QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(hwnd, wParam, lParam, result); default: break; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 048ca13..7bd4e2a 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -50,6 +50,7 @@ #include "qwindowsclipboard.h" #include "qwindowsdrag.h" #include "qwindowsinputcontext.h" +#include "qwindowsaccessibility.h" #include #include @@ -138,6 +139,7 @@ struct QWindowsIntegrationPrivate QWindowsGuiEventDispatcher *m_eventDispatcher; QOpenGLStaticContextPtr m_staticOpenGLContext; QWindowsInputContext m_inputContext; + QWindowsAccessibility m_accessibility; }; QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(bool openGL) @@ -258,6 +260,11 @@ QPlatformInputContext * QWindowsIntegration::inputContext() const return &d->m_inputContext; } +QPlatformAccessibility *QWindowsIntegration::accessibility() const +{ + return &d->m_accessibility; +} + QWindowsIntegration *QWindowsIntegration::instance() { return static_cast(QGuiApplicationPrivate::platformIntegration()); diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 1fe2301..8202e03 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -66,6 +66,7 @@ public: virtual QPlatformClipboard *clipboard() const; virtual QPlatformDrag *drag() const; virtual QPlatformInputContext *inputContext() const; + virtual QPlatformAccessibility *accessibility() const; virtual QPlatformNativeInterface *nativeInterface() const; virtual QPlatformFontDatabase *fontDatabase() const; diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index e5627ae..f188ef5 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -8,7 +8,7 @@ INCLUDEPATH += ../../../3rdparty/harfbuzz/src QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms # Note: OpenGL32 must precede Gdi32 as it overwrites some functions. -LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32 +LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32 -lWinmm win32-g++: LIBS *= -luuid contains(QT_CONFIG, directwrite) { @@ -39,7 +39,8 @@ SOURCES += \ qwindowsdrag.cpp \ qwindowscursor.cpp \ pixmaputils.cpp \ - qwindowsinputcontext.cpp + qwindowsinputcontext.cpp \ + qwindowsaccessibility.cpp HEADERS += \ qwindowsnativeimage.h \ @@ -64,7 +65,8 @@ HEADERS += \ qwindowscursor.h \ pixmaputils.h \ array.h \ - qwindowsinputcontext.h + qwindowsinputcontext.h \ + qwindowsaccessibility.h target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h index a58ed2f..90ed883 100644 --- a/src/testlib/qtestaccessible.h +++ b/src/testlib/qtestaccessible.h @@ -53,8 +53,8 @@ QVERIFY(QTestAccessibility::verifyEvent(object, child, (int)event)) #include -#include -#include +#include +#include QT_BEGIN_HEADER @@ -127,9 +127,9 @@ private: { // qDebug("rootObjectHandler called %p", object); if (object) { - QApplication* app = qobject_cast(object); + QGuiApplication* app = qobject_cast(object); if ( !app ) - qWarning("%s: root Object is not a QApplication!", Q_FUNC_INFO); + qWarning("%s: root Object is not a QGuiApplication!", Q_FUNC_INFO); } else { qWarning("%s: root Object called with 0 pointer", Q_FUNC_INFO); } diff --git a/src/widgets/accessible/accessible.pri b/src/widgets/accessible/accessible.pri index ff75563..9fb2f18 100644 --- a/src/widgets/accessible/accessible.pri +++ b/src/widgets/accessible/accessible.pri @@ -1,25 +1,6 @@ # Qt accessibility module contains(QT_CONFIG, accessibility) { - HEADERS += accessible/qaccessible.h \ - accessible/qaccessible2.h \ - accessible/qaccessibleobject.h \ - accessible/qaccessiblewidget.h \ - accessible/qaccessibleplugin.h - SOURCES += accessible/qaccessible.cpp \ - accessible/qaccessible2.cpp \ - accessible/qaccessibleobject.cpp \ - accessible/qaccessiblewidget.cpp \ - accessible/qaccessibleplugin.cpp - - mac:!qpa { - HEADERS += accessible/qaccessible_mac_p.h - OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \ - accessible/qaccessible_mac_cocoa.mm - } else:win32:!qpa { - SOURCES += accessible/qaccessible_win.cpp - } else { - HEADERS += accessible/qaccessiblebridge.h - SOURCES += accessible/qaccessible_unix.cpp accessible/qaccessiblebridge.cpp - } + HEADERS += accessible/qaccessiblewidget.h + SOURCES += accessible/qaccessiblewidget.cpp } diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp index ec52c4b..c1a4d1b 100644 --- a/src/widgets/accessible/qaccessiblewidget.cpp +++ b/src/widgets/accessible/qaccessiblewidget.cpp @@ -187,6 +187,11 @@ QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name) d->asking = 0; } +QWindow *QAccessibleWidget::window() const +{ + return widget()->windowHandle(); +} + /*! Destroys this object. */ diff --git a/src/widgets/accessible/qaccessiblewidget.h b/src/widgets/accessible/qaccessiblewidget.h index acf900e..3c63d5d 100644 --- a/src/widgets/accessible/qaccessiblewidget.h +++ b/src/widgets/accessible/qaccessiblewidget.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLEWIDGET_H #define QACCESSIBLEWIDGET_H -#include +#include QT_BEGIN_HEADER @@ -59,25 +59,26 @@ class Q_WIDGETS_EXPORT QAccessibleWidget : public QAccessibleObject public: explicit QAccessibleWidget(QWidget *o, Role r = Client, const QString& name = QString()); + QWindow *window() const; int childCount() const; int indexOfChild(const QAccessibleInterface *child) const; Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; int childAt(int x, int y) const; - QRect rect(int child) const; + QRect rect(int child = 0) const; QAccessibleInterface *parent() const; QAccessibleInterface *child(int index) const; int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const; - QString text(Text t, int child) const; - Role role(int child) const; - State state(int child) const; + QString text(Text t, int child = 0) const; + Role role(int child = 0) const; + State state(int child = 0) const; #ifndef QT_NO_ACTION - int userActionCount(int child) const; - QString actionText(int action, Text t, int child) const; - bool doAction(int action, int child, const QVariantList ¶ms); + int userActionCount(int child = 0) const; + QString actionText(int action, Text t, int child = 0) const; + bool doAction(int action, int child = 0, const QVariantList ¶ms = QVariantList()); #endif QVariant invokeMethod(Method method, int child, const QVariantList ¶ms); diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index 63c4f88..8b6073d 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 2c2acc8..76e60f9 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -246,7 +246,7 @@ #include #include #ifndef QT_NO_ACCESSIBILITY -# include +# include #endif #include #include diff --git a/src/widgets/kernel/qwidgetwindow_qpa.cpp b/src/widgets/kernel/qwidgetwindow_qpa.cpp index 32878bf..4488015 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa.cpp +++ b/src/widgets/kernel/qwidgetwindow_qpa.cpp @@ -43,6 +43,7 @@ #include "private/qwidget_p.h" #include "private/qapplication_p.h" +#include QT_BEGIN_NAMESPACE @@ -59,6 +60,13 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) { } +QAccessibleInterface *QWidgetWindow::accessibleRoot() const +{ + if (m_widget) + return QAccessible::queryAccessibleInterface(m_widget); + return 0; +} + bool QWidgetWindow::event(QEvent *event) { switch (event->type()) { diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index 86290c6..9f31d0e 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -63,6 +63,7 @@ public: QWidgetWindow(QWidget *widget); QWidget *widget() const { return m_widget; } + QAccessibleInterface *accessibleRoot() const; protected: bool event(QEvent *); diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index 4169d2d..5fcb852 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -64,7 +64,6 @@ #include "QtGui/qclipboard.h" #include "QtCore/qpoint.h" #include "QtWidgets/qcompleter.h" -#include "QtWidgets/qaccessible.h" #include "QtCore/qthread.h" #include "qplatformdefs.h" diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 4fb2106..b5b9ec7 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -353,7 +353,7 @@ class QtTestAccessibleWidgetIface: public QAccessibleWidget { public: QtTestAccessibleWidgetIface(QtTestAccessibleWidget *w): QAccessibleWidget(w) {} - QString text(Text t, int control) const + QString text(Text t, int control = 0) const { if (t == Help) return QString::fromLatin1("Help yourself"); -- 2.7.4