Let platform plugin decide if accessibility is active
Change-Id: I881a8ff3fedf3db73ee37046a4363c70960a92a6 Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
This commit is contained in:
parent
c2059ac80d
commit
0d57da067b
2
src/3rdparty/atspi2/atspi2.pri
vendored
2
src/3rdparty/atspi2/atspi2.pri
vendored
@ -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
|
||||
|
17
src/3rdparty/atspi2/xml/Bus.xml
vendored
Normal file
17
src/3rdparty/atspi2/xml/Bus.xml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.a11y.Status">
|
||||
<property type="b" name="IsEnabled" access="readwrite">
|
||||
</property>
|
||||
<property type="b" name="ScreenReaderEnabled" access="readwrite">
|
||||
</property>
|
||||
</interface>
|
||||
<interface name="org.a11y.Bus">
|
||||
<method name="GetAddress">
|
||||
<arg type="s" name="address" direction="out">
|
||||
</arg>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
@ -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
|
||||
|
@ -73,6 +73,7 @@ Q_GLOBAL_STATIC(QVector<QAccessibleBridge *>, bridges)
|
||||
\sa QAccessible
|
||||
*/
|
||||
QPlatformAccessibility::QPlatformAccessibility()
|
||||
: m_active(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,6 @@ private:
|
||||
DeviceEventControllerAdaptor *dec;
|
||||
AtSpiAdaptor *dbusAdaptor;
|
||||
DBusConnection* dbusConnection;
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <qdebug.h>
|
||||
|
||||
#include <QDBusConnectionInterface>
|
||||
#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.";
|
||||
OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this);
|
||||
|
||||
// check if it's enabled right away
|
||||
QDBusMessage enabledMessage = QDBusMessage::createMethodCall(A11Y_SERVICE, A11Y_PATH, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("Get"));
|
||||
QList<QVariant> args;
|
||||
args << QStringLiteral("org.a11y.Status") << QStringLiteral("IsEnabled");
|
||||
enabledMessage.setArguments(args);
|
||||
c.callWithCallback(enabledMessage, this, SLOT(enabledStateCallback(QDBusVariant)), SLOT(dbusError(QDBusError)));
|
||||
}
|
||||
// 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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaaccessibility.h"
|
||||
#include "qcocoaaccessibilityelement.h"
|
||||
#include <qpa/qplatformintegration.h>
|
||||
|
||||
#include <QtGui/private/qaccessible2_p.h>
|
||||
#include <QtCore/QDebug>
|
||||
@ -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];
|
||||
|
@ -52,7 +52,9 @@
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtGui/qaccessible.h>
|
||||
#include <QtGui/private/qaccessible2_p.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
|
||||
@ -245,6 +247,8 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W
|
||||
if (static_cast<long>(lParam) == static_cast<long>(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???
|
||||
|
@ -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
|
||||
|
@ -63,6 +63,9 @@
|
||||
#include <QtWidgets/private/qaccessiblewidget_p.h>
|
||||
#include <math.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <qpa/qplatformaccessibility.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
|
||||
#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()
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <QDBusReply>
|
||||
|
||||
#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();
|
||||
|
Loading…
Reference in New Issue
Block a user