summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2012-12-13 18:12:40 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-01-22 14:11:14 +0100
commit15a32435561a668e69764d12edfa2b5c564c6505 (patch)
treef56d1306f6fbd95a63fc5d9396c0798d3029d2b5
parentffeaff9a267f31f202578457d0fae96634a4ec2b (diff)
Accessibility Linux: Make dbus registration async
Change-Id: I74043be04f4ee17089353304fdc007a7f22cdea0 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor.cpp40
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor_p.h5
-rw-r--r--src/platformsupport/linuxaccessibility/bridge.cpp45
-rw-r--r--src/platformsupport/linuxaccessibility/bridge_p.h9
-rw-r--r--src/platformsupport/linuxaccessibility/dbusconnection.cpp94
-rw-r--r--src/platformsupport/linuxaccessibility/dbusconnection_p.h28
-rw-r--r--tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp30
7 files changed, 141 insertions, 110 deletions
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
index 895a5183a0..3d91f883f9 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
@@ -69,7 +69,7 @@ static bool isDebugging = false;
#define qAtspiDebug if (!::isDebugging); else qDebug
AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
- : QDBusVirtualObject(parent), m_dbus(connection), initialized(false)
+ : QDBusVirtualObject(parent), m_dbus(connection)
, sendFocus(0)
, sendObject(0)
, sendObject_active_descendant_changed(0)
@@ -132,6 +132,17 @@ AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
m_applicationAdaptor = new QSpiApplicationAdaptor(m_dbus->connection(), this);
connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,bool)), this, SLOT(windowActivated(QObject*,bool)));
+
+ updateEventListeners();
+ bool success = m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
+ QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerRegistered"), this,
+ SLOT(eventListenerRegistered(QString,QString)));
+ success = success && m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
+ QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerDeregistered"), this,
+ SLOT(eventListenerDeregistered(QString,QString)));
+#ifdef QT_ATSPI_DEBUG
+ qAtspiDebug() << "Registered event listener change listener: " << success;
+#endif
}
AtSpiAdaptor::~AtSpiAdaptor()
@@ -605,30 +616,6 @@ QString AtSpiAdaptor::introspect(const QString &path) const
return xml;
}
-/*!
- When initialized we will send updates, not before this.
-
- This function also checks which event listeners are registered in the at-spi registry.
- */
-void AtSpiAdaptor::setInitialized(bool init)
-{
- initialized = init;
-
- if (!initialized)
- return;
-
- updateEventListeners();
- bool success = m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
- QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerRegistered"), this,
- SLOT(eventListenerRegistered(QString,QString)));
- success = success && m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
- QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerDeregistered"), this,
- SLOT(eventListenerDeregistered(QString,QString)));
-#ifdef QT_ATSPI_DEBUG
- qAtspiDebug() << "Registered event listener change listener: " << success;
-#endif
-}
-
void AtSpiAdaptor::setBitFlag(const QString &flag)
{
Q_ASSERT(flag.size());
@@ -918,9 +905,6 @@ void AtSpiAdaptor::notifyStateChange(const QAIPointer &interface, const QString
*/
void AtSpiAdaptor::notify(QAccessibleEvent *event)
{
- if (!initialized)
- return;
-
switch (event->type()) {
case QAccessible::ObjectCreated:
if (sendObject || sendObject_children_changed)
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
index d282a1ed2e..b7a29fdc15 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
@@ -75,8 +75,8 @@ public:
bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection);
void notify(QAccessibleEvent *event);
- void setInitialized(bool init);
-
+ void init();
+ void checkInitializedAndEnabled();
public Q_SLOTS:
void eventListenerRegistered(const QString &bus, const QString &path);
void eventListenerDeregistered(const QString &bus, const QString &path);
@@ -140,7 +140,6 @@ private:
/// Assigned from the accessibility registry.
int m_applicationId;
- bool initialized;
mutable QHash<quintptr, QPointer<QObject> > m_handledObjects;
diff --git a/src/platformsupport/linuxaccessibility/bridge.cpp b/src/platformsupport/linuxaccessibility/bridge.cpp
index 39560d9509..d42ce8b064 100644
--- a/src/platformsupport/linuxaccessibility/bridge.cpp
+++ b/src/platformsupport/linuxaccessibility/bridge.cpp
@@ -62,24 +62,16 @@ QT_BEGIN_NAMESPACE
*/
QSpiAccessibleBridge::QSpiAccessibleBridge()
- : cache(0)
+ : cache(0), dec(0), dbusAdaptor(0), m_enabled(false)
{
dbusConnection = new DBusConnection();
- if (!dBusConnection().isConnected())
- qWarning() << "Could not connect to dbus.";
-
- qSpiInitializeStructTypes();
- initializeConstantMappings();
-
- /* Create the cache of accessible objects */
- cache = new QSpiDBusCache(dBusConnection(), this);
- dec = new DeviceEventControllerAdaptor(this);
-
- dBusConnection().registerObject(QLatin1String(ATSPI_DBUS_PATH_DEC), this, QDBusConnection::ExportAdaptors);
+ connect(dbusConnection, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool)));
+}
- dbusAdaptor = new AtSpiAdaptor(dbusConnection, this);
- dBusConnection().registerVirtualObject(QLatin1String(QSPI_OBJECT_PATH_ACCESSIBLE), dbusAdaptor, QDBusConnection::SubPath);
- dbusAdaptor->registerApplication();
+void QSpiAccessibleBridge::enabledChanged(bool enabled)
+{
+ m_enabled = enabled;
+ updateStatus();
}
QSpiAccessibleBridge::~QSpiAccessibleBridge()
@@ -92,15 +84,30 @@ QDBusConnection QSpiAccessibleBridge::dBusConnection() const
return dbusConnection->connection();
}
-void QSpiAccessibleBridge::setRootObject(QObject *obj)
+void QSpiAccessibleBridge::updateStatus()
{
- Q_UNUSED(obj);
- dbusAdaptor->setInitialized(true);
+ // create the adaptor to handle everything if we are in enabled state
+ if (!dbusAdaptor && m_enabled) {
+ qSpiInitializeStructTypes();
+ initializeConstantMappings();
+
+ cache = new QSpiDBusCache(dbusConnection->connection(), this);
+ dec = new DeviceEventControllerAdaptor(this);
+
+ dbusConnection->connection().registerObject(QLatin1String(ATSPI_DBUS_PATH_DEC), this, QDBusConnection::ExportAdaptors);
+
+ dbusAdaptor = new AtSpiAdaptor(dbusConnection, this);
+ dbusConnection->connection().registerVirtualObject(QLatin1String(QSPI_OBJECT_PATH_ACCESSIBLE), dbusAdaptor, QDBusConnection::SubPath);
+ dbusAdaptor->registerApplication();
+ }
}
void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- dbusAdaptor->notify(event);
+ if (!dbusAdaptor)
+ return;
+ if (m_enabled)
+ dbusAdaptor->notify(event);
}
struct RoleMapping {
diff --git a/src/platformsupport/linuxaccessibility/bridge_p.h b/src/platformsupport/linuxaccessibility/bridge_p.h
index afc32ac49c..aed437b1e2 100644
--- a/src/platformsupport/linuxaccessibility/bridge_p.h
+++ b/src/platformsupport/linuxaccessibility/bridge_p.h
@@ -62,21 +62,22 @@ public:
QSpiAccessibleBridge();
virtual ~QSpiAccessibleBridge();
- virtual void setRootObject(QObject *obj);
virtual void notifyAccessibilityUpdate(QAccessibleEvent *event);
QDBusConnection dBusConnection() const;
+public Q_SLOTS:
+ void enabledChanged(bool enabled);
+
private:
void initializeConstantMappings();
+ void updateStatus();
QSpiDBusCache *cache;
DeviceEventControllerAdaptor *dec;
-
AtSpiAdaptor *dbusAdaptor;
-
DBusConnection* dbusConnection;
- bool initialized;
+ bool m_enabled;
};
QT_END_NAMESPACE
diff --git a/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/src/platformsupport/linuxaccessibility/dbusconnection.cpp
index c91ad1da39..a37b99c105 100644
--- a/src/platformsupport/linuxaccessibility/dbusconnection.cpp
+++ b/src/platformsupport/linuxaccessibility/dbusconnection.cpp
@@ -44,10 +44,16 @@
#include "dbusconnection_p.h"
#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusServiceWatcher>
#include <qdebug.h>
+#include <QDBusConnectionInterface>
+
QT_BEGIN_NAMESPACE
+QString A11Y_SERVICE = QStringLiteral("org.a11y.Bus");
+QString A11Y_PATH = QStringLiteral("/org/a11y/bus");
+
/*!
\class DBusConnection
\internal
@@ -55,53 +61,81 @@ QT_BEGIN_NAMESPACE
This is usually a different bus from the session bus.
*/
-DBusConnection::DBusConnection()
- : dbusConnection(connectDBus())
-{}
-
-QDBusConnection DBusConnection::connectDBus()
+DBusConnection::DBusConnection(QObject *parent)
+ : QObject(parent), m_a11yConnection(QString()), m_enabled(false)
{
- QString address = getAccessibilityBusAddress();
+ // Start monitoring if "org.a11y.Bus" is registered as DBus service.
+ QDBusConnection c = QDBusConnection::sessionBus();
+ dbusWatcher = new QDBusServiceWatcher(A11Y_SERVICE, c, QDBusServiceWatcher::WatchForRegistration, this);
+ connect(dbusWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(serviceRegistered()));
- if (!address.isEmpty()) {
- QDBusConnection c = QDBusConnection::connectToBus(address, QStringLiteral("a11y"));
- if (c.isConnected())
- return c;
- qWarning("Found Accessibility DBus address but cannot connect. Falling back to session bus.");
- } else {
- qWarning("Accessibility DBus not found. Falling back to session bus.");
- }
+ // If it is registered already, setup a11y right away
+ if (c.interface()->isServiceRegistered(A11Y_SERVICE))
+ serviceRegistered();
+}
+// We have the a11y registry on the session bus.
+// Subscribe to updates about a11y enabled state.
+// Find out the bus address
+void DBusConnection::serviceRegistered()
+{
+ // listen to enabled changes
QDBusConnection c = QDBusConnection::sessionBus();
- if (!c.isConnected()) {
- qWarning("Could not connect to DBus.");
- }
- return 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<QVariant> args;
+ args << QStringLiteral("org.a11y.Status") << QStringLiteral("IsEnabled");
+ enabledMessage.setArguments(args);
+ c.callWithCallback(enabledMessage, this, SLOT(enabledStateCallback(QDBusVariant)), SLOT(dbusError(QDBusError)));
}
-QString DBusConnection::getAccessibilityBusAddress() const
+void DBusConnection::dbusError(const QDBusError &error)
{
- QDBusConnection c = QDBusConnection::sessionBus();
+ qWarning() << "Accessibility encountered a DBus error:" << error;
+}
+
+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)));
+ }
+}
- QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.Bus"),
- QLatin1String("/org/a11y/bus"),
- QLatin1String("org.a11y.Bus"), QLatin1String("GetAddress"));
- QDBusMessage reply = c.call(m);
- if (reply.type() == QDBusMessage::ErrorMessage) {
- qWarning() << "Qt at-spi: error getting the accessibility dbus address: " << reply.errorMessage();
- return QString();
+void DBusConnection::connectA11yBus(const QString &address)
+{
+ if (address.isEmpty()) {
+ qWarning("Could not find Accessibility DBus address.");
+ return;
}
+ m_a11yConnection = QDBusConnection(QDBusConnection::connectToBus(address, QStringLiteral("a11y")));
- QString busAddress = reply.arguments().at(0).toString();
- return busAddress;
+ if (m_enabled)
+ emit enabledChanged(true);
}
/*!
Returns the DBus connection that got established.
+ Or an invalid connection if not yet connected.
*/
QDBusConnection DBusConnection::connection() const
{
- return dbusConnection;
+ return m_a11yConnection;
}
QT_END_NAMESPACE
diff --git a/src/platformsupport/linuxaccessibility/dbusconnection_p.h b/src/platformsupport/linuxaccessibility/dbusconnection_p.h
index 4fb75bf41f..2875dd89d8 100644
--- a/src/platformsupport/linuxaccessibility/dbusconnection_p.h
+++ b/src/platformsupport/linuxaccessibility/dbusconnection_p.h
@@ -45,21 +45,41 @@
#include <QtCore/QString>
#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusVariant>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class DBusConnection
+class QDBusServiceWatcher;
+
+class DBusConnection : public QObject
{
+ Q_OBJECT
+
public:
- DBusConnection();
+ DBusConnection(QObject *parent = 0);
QDBusConnection connection() const;
+ bool isEnabled() const { return m_enabled; }
+
+Q_SIGNALS:
+ // Emitted when the global accessibility status changes to enabled
+ void enabledChanged(bool enabled);
+
+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);
private:
QString getAccessibilityBusAddress() const;
- QDBusConnection connectDBus();
- QDBusConnection dbusConnection;
+ QDBusServiceWatcher *dbusWatcher;
+ QDBusConnection m_a11yConnection;
+ bool m_enabled;
};
QT_END_NAMESPACE
diff --git a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
index fd157dd834..15b8089525 100644
--- a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
+++ b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
@@ -67,11 +67,8 @@ class AccessibleTestWindow : public QWidget
public:
AccessibleTestWindow()
{
- DBusConnection c;
- m_address = c.connection().baseService().toLatin1().data();
new QHBoxLayout(this);
}
- QString dbusAddress() const { return m_address; }
void addWidget(QWidget* widget)
{
@@ -85,10 +82,6 @@ public:
qDeleteAll(children());
new QHBoxLayout(this);
}
-
-private:
- QString m_address;
- QString m_bus;
};
@@ -116,7 +109,6 @@ private:
AccessibleTestWindow *m_window;
- QString bus;
QString address;
QDBusInterface *root; // the root object on dbus (for the app)
QDBusInterface *rootApplication;
@@ -129,10 +121,12 @@ private:
QStringList tst_QAccessibilityLinux::getChildren(QDBusInterface *interface)
{
QSpiObjectReferenceArray list;
- interface->call(QDBus::Block, "GetChildren").arguments().first().value<QDBusArgument>() >> list;
+ const QList<QVariant> args = interface->call(QDBus::Block, "GetChildren").arguments();
+ Q_ASSERT(args.size() == 1);
+ Q_ASSERT(args.first().isValid());
+ args.first().value<QDBusArgument>() >> list;
Q_ASSERT(interface->property("ChildCount").toInt() == list.count());
-
QStringList children;
Q_FOREACH (const QSpiObjectReference &ref, list)
children << ref.path.path();
@@ -164,26 +158,18 @@ QDBusInterface *tst_QAccessibilityLinux::getInterface(const QString &path, const
void tst_QAccessibilityLinux::initTestCase()
{
// Oxygen style creates many extra items, it's simply unusable here
- qDebug() << "Using fusion style...";
qApp->setStyle("fusion");
qApp->setApplicationName("tst_QAccessibilityLinux app");
- dbus = DBusConnection();
+
+ QTRY_VERIFY(dbus.isEnabled());
+ QTRY_VERIFY(dbus.connection().isConnected());
+ address = dbus.connection().baseService().toLatin1().data();
m_window = new AccessibleTestWindow();
m_window->show();
- // this has the side-effect of immediately activating accessibility
- qDebug() << "Explicitly activating accessibility...";
- delete QAccessible::queryAccessibleInterface(m_window);
-
QTest::qWaitForWindowExposed(m_window);
-
- address = m_window->dbusAddress();
registerDbus();
-
- QStringList appChildren = getChildren(root);
- QString window = appChildren.at(0);
- mainWindow = getInterface(window, "org.a11y.atspi.Accessible");
}
void tst_QAccessibilityLinux::cleanupTestCase()