From 0d57da067b47eac51ea725d267069d6e616cf586 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 25 Mar 2013 18:07:17 +0100 Subject: Let platform plugin decide if accessibility is active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I881a8ff3fedf3db73ee37046a4363c70960a92a6 Reviewed-by: Jan Arve Sæther --- src/3rdparty/atspi2/atspi2.pri | 2 +- src/3rdparty/atspi2/xml/Bus.xml | 17 ++++++++ src/gui/accessible/qaccessible.cpp | 21 +++++---- src/gui/accessible/qplatformaccessibility.cpp | 1 + src/gui/accessible/qplatformaccessibility.h | 5 +++ src/platformsupport/linuxaccessibility/bridge.cpp | 8 ++-- src/platformsupport/linuxaccessibility/bridge_p.h | 1 - .../linuxaccessibility/dbusconnection.cpp | 51 ++++++++++------------ .../linuxaccessibility/dbusconnection_p.h | 2 - src/plugins/platforms/cocoa/qnsview.h | 1 - src/plugins/platforms/cocoa/qnsview.mm | 5 +-- .../platforms/cocoa/qnsviewaccessibility.mm | 19 +++++--- .../windows/accessible/qwindowsaccessibility.cpp | 4 ++ tests/auto/other/qaccessibility/qaccessibility.pro | 2 +- .../other/qaccessibility/tst_qaccessibility.cpp | 5 +++ .../tst_qaccessibilitylinux.cpp | 8 +++- 16 files changed, 94 insertions(+), 58 deletions(-) create mode 100644 src/3rdparty/atspi2/xml/Bus.xml diff --git a/src/3rdparty/atspi2/atspi2.pri b/src/3rdparty/atspi2/atspi2.pri index 1b2ac51b85..5a6dc6d839 100644 --- a/src/3rdparty/atspi2/atspi2.pri +++ b/src/3rdparty/atspi2/atspi2.pri @@ -2,7 +2,7 @@ DBUS_ADAPTORS = $$PWD/xml/Cache.xml $$PWD/xml/DeviceEventController.xml QDBUSXML2CPP_ADAPTOR_HEADER_FLAGS = -i struct_marshallers_p.h -DBUS_INTERFACES = $$PWD/xml/Socket.xml +DBUS_INTERFACES = $$PWD/xml/Socket.xml $$PWD/xml/Bus.xml QDBUSXML2CPP_INTERFACE_HEADER_FLAGS = -i struct_marshallers_p.h INCLUDEPATH += $$PWD diff --git a/src/3rdparty/atspi2/xml/Bus.xml b/src/3rdparty/atspi2/xml/Bus.xml new file mode 100644 index 0000000000..5a33e335a1 --- /dev/null +++ b/src/3rdparty/atspi2/xml/Bus.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 4fd595ed5a..18157f8e2f 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -441,7 +441,6 @@ Q_GLOBAL_STATIC(QAccessiblePluginsHash, qAccessiblePlugins); QAccessible::UpdateHandler QAccessible::updateHandler = 0; QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0; -static bool accessibility_active = false; static bool cleanupAdded = false; #ifndef QT_NO_ACCESSIBILITY @@ -584,7 +583,6 @@ Q_GLOBAL_STATIC(QAccessibleCache, qAccessibleCache) */ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) { - accessibility_active = true; if (!object) return 0; @@ -699,19 +697,26 @@ QAccessibleInterface *QAccessible::accessibleInterface(Id id) /*! - Returns true if an accessibility implementation has been requested - during the runtime of the application; otherwise returns false. + Returns true if the platform requested accessibility information. - Use this function to prevent potentially expensive notifications via - updateAccessibility(). + This function will return false until a tool such as a screen reader + accessed the accessibility framework. It is still possible to use + \l QAccessible::queryAccessibleInterface even if accessibility is not + active. But there will be no notifications sent to the platform. + + It is recommended to use this function to prevent expensive notifications + via updateAccessibility() when they are not needed. */ bool QAccessible::isActive() { - return accessibility_active; +#ifndef QT_NO_ACCESSIBILITY + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + return pfAccessibility->isActive(); +#endif + return false; } - /*! Sets the root object of the accessible objects of this application to \a object. All other accessible objects are reachable using object diff --git a/src/gui/accessible/qplatformaccessibility.cpp b/src/gui/accessible/qplatformaccessibility.cpp index 2e36e5ac71..490fb7a407 100644 --- a/src/gui/accessible/qplatformaccessibility.cpp +++ b/src/gui/accessible/qplatformaccessibility.cpp @@ -73,6 +73,7 @@ Q_GLOBAL_STATIC(QVector, bridges) \sa QAccessible */ QPlatformAccessibility::QPlatformAccessibility() + : m_active(false) { } diff --git a/src/gui/accessible/qplatformaccessibility.h b/src/gui/accessible/qplatformaccessibility.h index 26a22e492d..f86a9b6157 100644 --- a/src/gui/accessible/qplatformaccessibility.h +++ b/src/gui/accessible/qplatformaccessibility.h @@ -69,6 +69,11 @@ public: virtual void initialize(); virtual void cleanup(); + inline bool isActive() const { return m_active; } + inline void setActive(bool active) { m_active = active; } + +private: + bool m_active; }; QT_END_NAMESPACE diff --git a/src/platformsupport/linuxaccessibility/bridge.cpp b/src/platformsupport/linuxaccessibility/bridge.cpp index 181feeba6a..350c67f1ed 100644 --- a/src/platformsupport/linuxaccessibility/bridge.cpp +++ b/src/platformsupport/linuxaccessibility/bridge.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE */ QSpiAccessibleBridge::QSpiAccessibleBridge() - : cache(0), dec(0), dbusAdaptor(0), m_enabled(false) + : cache(0), dec(0), dbusAdaptor(0) { dbusConnection = new DBusConnection(); connect(dbusConnection, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool))); @@ -70,7 +70,7 @@ QSpiAccessibleBridge::QSpiAccessibleBridge() void QSpiAccessibleBridge::enabledChanged(bool enabled) { - m_enabled = enabled; + setActive(enabled); updateStatus(); } @@ -87,7 +87,7 @@ QDBusConnection QSpiAccessibleBridge::dBusConnection() const void QSpiAccessibleBridge::updateStatus() { // create the adaptor to handle everything if we are in enabled state - if (!dbusAdaptor && m_enabled) { + if (!dbusAdaptor && isActive()) { qSpiInitializeStructTypes(); initializeConstantMappings(); @@ -106,7 +106,7 @@ void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event) { if (!dbusAdaptor) return; - if (m_enabled) + if (isActive()) dbusAdaptor->notify(event); } diff --git a/src/platformsupport/linuxaccessibility/bridge_p.h b/src/platformsupport/linuxaccessibility/bridge_p.h index 8a02847d3d..0e1624c522 100644 --- a/src/platformsupport/linuxaccessibility/bridge_p.h +++ b/src/platformsupport/linuxaccessibility/bridge_p.h @@ -76,7 +76,6 @@ private: DeviceEventControllerAdaptor *dec; AtSpiAdaptor *dbusAdaptor; DBusConnection* dbusConnection; - bool m_enabled; }; QT_END_NAMESPACE diff --git a/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/src/platformsupport/linuxaccessibility/dbusconnection.cpp index a37b99c105..18915f8e08 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection.cpp +++ b/src/platformsupport/linuxaccessibility/dbusconnection.cpp @@ -48,6 +48,7 @@ #include #include +#include "bus_interface.h" QT_BEGIN_NAMESPACE @@ -81,21 +82,24 @@ void DBusConnection::serviceRegistered() { // listen to enabled changes QDBusConnection c = QDBusConnection::sessionBus(); - // FXIME check for changes of enabled state -// if (!c.connect(A11Y_SERVICE, A11Y_PATH, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"), this, SLOT(enabledStateChanged(QDBusVariant)))) -// qWarning() << "Could not listen to accessibility enabled state changes."; - - // check if it's enabled right away - QDBusMessage enabledMessage = QDBusMessage::createMethodCall(A11Y_SERVICE, A11Y_PATH, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("Get")); - QList args; - args << QStringLiteral("org.a11y.Status") << QStringLiteral("IsEnabled"); - enabledMessage.setArguments(args); - c.callWithCallback(enabledMessage, this, SLOT(enabledStateCallback(QDBusVariant)), SLOT(dbusError(QDBusError))); -} + OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this); + + // a11yStatus->isEnabled() returns always true (since Gnome 3.6) + bool enabled = a11yStatus->screenReaderEnabled(); + if (enabled != m_enabled) { + m_enabled = enabled; + if (m_a11yConnection.isConnected()) { + emit enabledChanged(m_enabled); + } else { + QDBusConnection c = QDBusConnection::sessionBus(); + QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.Bus"), + QLatin1String("/org/a11y/bus"), + QLatin1String("org.a11y.Bus"), QLatin1String("GetAddress")); + c.callWithCallback(m, this, SLOT(connectA11yBus(QString)), SLOT(dbusError(QDBusError))); + } + } -void DBusConnection::dbusError(const QDBusError &error) -{ - qWarning() << "Accessibility encountered a DBus error:" << error; + // connect(a11yStatus, ); QtDbus doesn't support notifications for property changes yet } void DBusConnection::serviceUnregistered() @@ -103,20 +107,6 @@ void DBusConnection::serviceUnregistered() emit enabledChanged(false); } -void DBusConnection::enabledStateCallback(const QDBusVariant &enabled) -{ - m_enabled = enabled.variant().toBool(); - if (m_a11yConnection.isConnected()) { - emit enabledChanged(m_enabled); - } else { - QDBusConnection c = QDBusConnection::sessionBus(); - QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.Bus"), - QLatin1String("/org/a11y/bus"), - QLatin1String("org.a11y.Bus"), QLatin1String("GetAddress")); - c.callWithCallback(m, this, SLOT(connectA11yBus(QString)), SLOT(dbusError(QDBusError))); - } -} - void DBusConnection::connectA11yBus(const QString &address) { if (address.isEmpty()) { @@ -129,6 +119,11 @@ void DBusConnection::connectA11yBus(const QString &address) emit enabledChanged(true); } +void DBusConnection::dbusError(const QDBusError &error) +{ + qWarning() << "Accessibility encountered a DBus error:" << error; +} + /*! Returns the DBus connection that got established. Or an invalid connection if not yet connected. diff --git a/src/platformsupport/linuxaccessibility/dbusconnection_p.h b/src/platformsupport/linuxaccessibility/dbusconnection_p.h index 2d55ccb547..70f6fb80ac 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection_p.h +++ b/src/platformsupport/linuxaccessibility/dbusconnection_p.h @@ -67,8 +67,6 @@ Q_SIGNALS: private Q_SLOTS: void serviceRegistered(); void serviceUnregistered(); - void enabledStateCallback(const QDBusVariant &enabled); -// void enabledStateChanged(const QDBusVariant &); void connectA11yBus(const QString &address); void dbusError(const QDBusError &error); diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index e7ea3d8f8d..68145ec914 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -63,7 +63,6 @@ QT_END_NAMESPACE QWindow *m_window; QCocoaWindow *m_platformWindow; Qt::MouseButtons m_buttons; - QAccessibleInterface *m_accessibleRoot; QString m_composingText; bool m_sendKeyEvent; QStringList *currentCustomDragTypes; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 568cc4bebf..52e2d781ee 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -121,7 +121,6 @@ static QTouchDevice *touchDevice = 0; m_window = window; m_platformWindow = platformWindow; - m_accessibleRoot = 0; m_sendKeyEvent = false; #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR @@ -130,15 +129,13 @@ static QTouchDevice *touchDevice = 0; static bool skipAccessibilityForInspectorWindows = false; if (!skipAccessibilityForInspectorWindows) { - m_accessibleRoot = window->accessibleRoot(); + // m_accessibleRoot = window->accessibleRoot(); AccessibilityInspector *inspector = new AccessibilityInspector(window); skipAccessibilityForInspectorWindows = true; inspector->inspectWindow(window); skipAccessibilityForInspectorWindows = false; } -#else - m_accessibleRoot = window->accessibleRoot(); #endif [self registerDragTypes]; diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index e3b8cf6532..c43c0b5068 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -45,6 +45,7 @@ #include "qcocoahelpers.h" #include "qcocoaaccessibility.h" #include "qcocoaaccessibilityelement.h" +#include #include #include @@ -60,22 +61,26 @@ } - (id)accessibilityAttributeValue:(NSString *)attribute { + + // activate accessibility updates + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { - if (m_accessibleRoot) - return QCocoaAccessible::macRole(m_accessibleRoot); + if (m_window->accessibleRoot()) + return QCocoaAccessible::macRole(m_window->accessibleRoot()); return NSAccessibilityUnknownRole; } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { return NSAccessibilityRoleDescriptionForUIElement(self); } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { - if (!m_accessibleRoot) + if (!m_window->accessibleRoot()) return [super accessibilityAttributeValue:attribute]; // Create QCocoaAccessibleElements for each child if the // root accessible interface. - int numKids = m_accessibleRoot->childCount(); + int numKids = m_window->accessibleRoot()->childCount(); NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids]; for (int i = 0; i < numKids; ++i) { - QAccessibleInterface *child = m_accessibleRoot->child(i); + QAccessibleInterface *child = m_window->accessibleRoot()->child(i); Q_ASSERT(child); QAccessible::Id childAxid = QAccessible::uniqueId(child); QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; @@ -90,10 +95,10 @@ } - (id)accessibilityHitTest:(NSPoint)point { - if (!m_accessibleRoot) + if (!m_window->accessibleRoot()) return [super accessibilityHitTest:point]; - QAccessibleInterface *childInterface = m_accessibleRoot->childAt(point.x, qt_mac_flipYCoordinate(point.y)); + QAccessibleInterface *childInterface = m_window->accessibleRoot()->childAt(point.x, qt_mac_flipYCoordinate(point.y)); // No child found, meaning we hit the NSView if (!childInterface) { return [super accessibilityHitTest:point]; diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index f222deeeac..63b4370dc2 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -52,7 +52,9 @@ #include #include #include +#include #include +#include #include #include @@ -245,6 +247,8 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W if (static_cast(lParam) == static_cast(UiaRootObjectId)) { /* For UI Automation */ } else if ((DWORD)lParam == DWORD(OBJID_CLIENT)) { + // Start handling accessibility internally + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); #if 1 // Ignoring all requests while starting up // ### Maybe QPA takes care of this??? diff --git a/tests/auto/other/qaccessibility/qaccessibility.pro b/tests/auto/other/qaccessibility/qaccessibility.pro index 071b0bb66c..70f6633195 100644 --- a/tests/auto/other/qaccessibility/qaccessibility.pro +++ b/tests/auto/other/qaccessibility/qaccessibility.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qaccessibility requires(contains(QT_CONFIG,accessibility)) -QT += testlib gui-private widgets-private +QT += testlib core-private gui-private widgets-private SOURCES += tst_qaccessibility.cpp unix:!mac:LIBS+=-lm diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 4e0b3298fc..af8e4472ed 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -63,6 +63,9 @@ #include #include #include +#include +#include +#include #if defined(Q_OS_WIN) && defined(interface) # undef interface @@ -311,6 +314,8 @@ void tst_QAccessibility::onClicked() void tst_QAccessibility::initTestCase() { QTestAccessibility::initialize(); + QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration(); + pfIntegration->accessibility()->setActive(true); } void tst_QAccessibility::cleanupTestCase() diff --git a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp index 15b8089525..79fd29f2a1 100644 --- a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp +++ b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp @@ -55,6 +55,7 @@ #include #include "atspi/atspi-constants.h" +#include "bus_interface.h" #include "dbusconnection_p.h" #include "struct_marshallers_p.h" @@ -154,16 +155,21 @@ QDBusInterface *tst_QAccessibilityLinux::getInterface(const QString &path, const return new QDBusInterface(address, path, interfaceName, dbus.connection(), this); } - void tst_QAccessibilityLinux::initTestCase() { // Oxygen style creates many extra items, it's simply unusable here qApp->setStyle("fusion"); qApp->setApplicationName("tst_QAccessibilityLinux app"); + // Pretend we are a screen reader + QDBusConnection c = QDBusConnection::sessionBus(); + OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(QStringLiteral("org.a11y.Bus"), QStringLiteral("/org/a11y/bus"), c, this); + a11yStatus->setScreenReaderEnabled(true); + QTRY_VERIFY(dbus.isEnabled()); QTRY_VERIFY(dbus.connection().isConnected()); address = dbus.connection().baseService().toLatin1().data(); + QVERIFY(!address.isEmpty()); m_window = new AccessibleTestWindow(); m_window->show(); -- cgit v1.2.3