Add Linux Accessibility Bridge

This is a plugin that bridges the QAccessible world
to AT-SPI 2 on Linux.

Change-Id: I7af22621ee6a3cefc723b137b7f227a611cf6641
Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
bb10
Frederik Gladhorn 2012-05-10 23:52:05 +02:00 committed by Qt by Nokia
parent 85b624a969
commit 8e1ff45e74
26 changed files with 4917 additions and 8 deletions

26
configure vendored
View File

@ -3012,7 +3012,7 @@ Configure options:
+ -largefile ......... Enables Qt to access files larger than 4 GB.
-no-accessibility .. Do not compile Accessibility support.
* -accessibility ..... Compile Accessibility support.
+ -accessibility ..... Compile Accessibility support.
-no-sql-<driver> ... Disable SQL <driver> entirely.
-qt-sql-<driver> ... Enable a SQL <driver> in the QtSql library, by default
@ -3989,11 +3989,6 @@ if [ "$CFG_LIBPNG" = "auto" ]; then
fi
fi
# detect accessibility
if [ "$CFG_ACCESSIBILITY" = "auto" ]; then
CFG_ACCESSIBILITY=yes
fi
if [ "$CFG_EGLFS" = "yes" ]; then
if [ "$CFG_EGL" = "no" ]; then
echo "The EGLFS plugin requires EGL support and cannot be built"
@ -4842,6 +4837,25 @@ if [ "$CFG_KMS" = "yes" ]; then
fi
fi
# Detect accessibility support
if [ "$CFG_ACCESSIBILITY" != "no" ]; then
if [ "$CFG_XCB" = "no" ]; then
CFG_ACCESSIBILITY=yes
else
# linux/xcb accessibility needs dbus and atspi-2
if [ "$CFG_DBUS" != "no" ] && [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists "atspi-2" 2>/dev/null; then
CFG_ACCESSIBILITY=yes
else
if [ "$CFG_ACCESSIBILITY" = "auto" ]; then
CFG_ACCESSIBILITY=no
else
echo "Accessibility support needs pkg-config and libatspi2."
exit 101
fi
fi
fi
fi
# Determine the default QPA platform
if [ -z "$QT_QPA_DEFAULT_PLATFORM" ]; then
# check the mkspec

6
src/3rdparty/atspi2/atspi2.pri vendored Normal file
View File

@ -0,0 +1,6 @@
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
QDBUSXML2CPP_INTERFACE_HEADER_FLAGS = -i struct_marshallers_p.h

21
src/3rdparty/atspi2/xml/Cache.xml vendored Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/node">
<interface name="org.a11y.atspi.Cache">
<method name="GetItems">
<arg name="nodes" type="a((so)(so)a(so)assusau)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiAccessibleCacheArray"/>
</method>
<signal name="AddAccessible">
<arg name="nodeAdded" type="((so)(so)a(so)assusau)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiAccessibleCacheItem"/>
</signal>
<signal name="RemoveAccessible">
<arg name="nodeRemoved" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/>
</signal>
</interface>
</node>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/node">
<interface name="org.a11y.atspi.DeviceEventController">
<!--
<method name="RegisterKeystrokeListener">
<arg direction="in" name="listener" type="o"/>
<arg direction="in" name="keys" type="a(iisi)">
<annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QSpiKeyTypeArray"/>
</arg>
<arg direction="in" name="mask" type="u"/>
<arg direction="in" name="type" type="au">
<annotation name="com.trolltech.QtDBus.QtTypeName.In3" value="QSpiEventTypeArray"/>
</arg>
<arg direction="in" name="mode" type="(bbb)">
<annotation name="com.trolltech.QtDBus.QtTypeName.In4" value="QSpiEventMode"/>
</arg>
<arg direction="out" type="b"/>
</method>
<method name="DeregisterKeystrokeListener">
<arg direction="in" name="listener" type="o"/>
<arg direction="in" name="keys" type="a(iisi)">
<annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QSpiKeyTypeArray"/>
</arg>
<arg direction="in" name="mask" type="u"/>
<arg direction="in" name="type" type="u"/>
</method>
<method name="RegisterDeviceEventListener">
<arg direction="in" name="listener" type="o"/>
<arg direction="in" name="types" type="u"/>
<arg direction="out" type="b"/>
</method>
<method name="DeregisterDeviceEventListener">
<arg direction="in" name="listener" type="o"/>
<arg direction="in" name="types" type="u"/>
</method>
<method name="GenerateKeyboardEvent">
<arg direction="in" name="keycode" type="i"/>
<arg direction="in" name="keystring" type="s"/>
<arg direction="in" name="type" type="u"/>
</method>
<method name="GenerateMouseEvent">
<arg direction="in" name="x" type="i"/>
<arg direction="in" name="y" type="i"/>
<arg direction="in" name="eventName" type="s"/>
</method>
-->
<method name="NotifyListenersSync">
<arg direction="in" name="event" type="(uinnisb)"/>
<arg direction="out" type="b"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiDeviceEvent"/>
</method>
<method name="NotifyListenersAsync">
<arg direction="in" name="event" type="(uinnisb)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiDeviceEvent"/>
</method>
</interface>
</node>

23
src/3rdparty/atspi2/xml/Socket.xml vendored Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/node">
<interface name="org.a11y.atspi.Socket">
<method name="Embed">
<arg direction="in" name="plug" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/>
<arg direction="out" name="socket" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiObjectReference"/>
</method>
<method name="Unembed">
<arg direction="in" name="plug" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/>
</method>
<signal name="Available">
<arg direction="in" name="socket" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/>
</method>
</interface>
</node>

View File

@ -0,0 +1,219 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "application_p.h"
#include <QtWidgets/qapplication.h>
#include <QtDBus/qdbuspendingreply.h>
#include <qdebug.h>
#include "deviceeventcontroller_adaptor.h"
//#define KEYBOARD_DEBUG
QT_BEGIN_NAMESPACE
/*!
\class QSpiApplicationAdaptor
\brief QSpiApplicationAdaptor
QSpiApplicationAdaptor
*/
QSpiApplicationAdaptor::QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent)
: QObject(parent), dbusConnection(connection)
{
}
enum QSpiKeyEventType {
QSPI_KEY_EVENT_PRESS,
QSPI_KEY_EVENT_RELEASE,
QSPI_KEY_EVENT_LAST_DEFINED
};
void QSpiApplicationAdaptor::sendEvents(bool active)
{
if (active) {
qApp->installEventFilter(this);
} else {
qApp->removeEventFilter(this);
}
}
bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event)
{
if (!event->spontaneous())
return false;
switch (event->type()) {
case QEvent::WindowActivate:
emit windowActivated(target, true);
break;
case QEvent::WindowDeactivate:
emit windowActivated(target, false);
break;
case QEvent::KeyPress:
case QEvent::KeyRelease: {
QKeyEvent *keyEvent = static_cast <QKeyEvent *>(event);
QSpiDeviceEvent de;
if (event->type() == QEvent::KeyPress)
de.type = QSPI_KEY_EVENT_PRESS;
else
de.type = QSPI_KEY_EVENT_RELEASE;
de.id = keyEvent->nativeVirtualKey();
de.hardwareCode = keyEvent->nativeScanCode();
de.modifiers = keyEvent->nativeModifiers();
de.timestamp = QDateTime::currentMSecsSinceEpoch();
if (keyEvent->key() == Qt::Key_Tab)
de.text = QStringLiteral("Tab");
else if (keyEvent->key() == Qt::Key_Backtab)
de.text = QStringLiteral("Backtab");
else if (keyEvent->key() == Qt::Key_Left)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Left") : QStringLiteral("Left");
else if (keyEvent->key() == Qt::Key_Right)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Right") : QStringLiteral("Right");
else if (keyEvent->key() == Qt::Key_Up)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Up") : QStringLiteral("Up");
else if (keyEvent->key() == Qt::Key_Down)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Down") : QStringLiteral("Down");
else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
de.text = QStringLiteral("Return");
else if (keyEvent->key() == Qt::Key_Backspace)
de.text = QStringLiteral("BackSpace");
else if (keyEvent->key() == Qt::Key_Delete)
de.text = QStringLiteral("Delete");
else if (keyEvent->key() == Qt::Key_PageUp)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Up");
else if (keyEvent->key() == Qt::Key_PageDown)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Down");
else if (keyEvent->key() == Qt::Key_Home)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Home") : QStringLiteral("Home");
else if (keyEvent->key() == Qt::Key_End)
de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_End") : QStringLiteral("End");
else if (keyEvent->key() == Qt::Key_Clear && (keyEvent->modifiers() & Qt::KeypadModifier))
de.text = QStringLiteral("KP_Begin"); // Key pad 5
else if (keyEvent->key() == Qt::Key_Escape)
de.text = QStringLiteral("Escape");
else if (keyEvent->key() == Qt::Key_Space)
de.text = QStringLiteral("space");
else if (keyEvent->key() == Qt::Key_CapsLock)
de.text = QStringLiteral("Caps_Lock");
else if (keyEvent->key() == Qt::Key_NumLock)
de.text = QStringLiteral("Num_Lock");
else if (keyEvent->key() == Qt::Key_Insert)
de.text = QStringLiteral("Insert");
else
de.text = keyEvent->text();
// This is a bit dubious, Gnome uses some gtk function here.
// Long term the spec will hopefully change to just use keycodes.
de.isText = !de.text.isEmpty();
#ifdef KEYBOARD_DEBUG
qDebug() << QStringLiteral("Key event text: ") << event->type() << de.isText << QStringLiteral(" ") << de.text
<< QStringLiteral(" hardware code: ") << de.hardwareCode
<< QStringLiteral(" native sc: ") << keyEvent->nativeScanCode()
<< QStringLiteral(" native mod: ") << keyEvent->nativeModifiers()
<< QStringLiteral("native virt: ") << keyEvent->nativeVirtualKey();
#endif
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.a11y.atspi.Registry"),
QStringLiteral("/org/a11y/atspi/registry/deviceeventcontroller"),
QStringLiteral("org.a11y.atspi.DeviceEventController"), QStringLiteral("NotifyListenersSync"));
m.setArguments(QVariantList() <<QVariant::fromValue(de));
// FIXME: this is critical, the timeout should probably be pretty low to allow normal processing
int timeout = 100;
bool sent = dbusConnection.callWithCallback(m, this, SLOT(notifyKeyboardListenerCallback(QDBusMessage)),
SLOT(notifyKeyboardListenerError(QDBusError, QDBusMessage)), timeout);
if (sent) {
//queue the event and send it after callback
keyEvents.enqueue(QPair<QObject*, QKeyEvent*> (target, copyKeyEvent(keyEvent)));
#ifdef KEYBOARD_DEBUG
qDebug() << QStringLiteral("Sent key: ") << de.text;
#endif
return true;
}
}
default:
break;
}
return false;
}
QKeyEvent* QSpiApplicationAdaptor::copyKeyEvent(QKeyEvent* old)
{
return new QKeyEvent(old->type(), old->key(), old->modifiers(), old->text(), old->isAutoRepeat(), old->count());
}
void QSpiApplicationAdaptor::notifyKeyboardListenerCallback(const QDBusMessage& message)
{
if (!keyEvents.length()) {
qWarning() << QStringLiteral("QSpiApplication::notifyKeyboardListenerCallback with no queued key called");
return;
}
Q_ASSERT(message.arguments().length() == 1);
if (message.arguments().at(0).toBool() == true) {
QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue();
delete event.second;
} else {
QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue();
QApplication::postEvent(event.first, event.second);
}
}
void QSpiApplicationAdaptor::notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& /*message*/)
{
qWarning() << QStringLiteral("QSpiApplication::keyEventError ") << error.name() << error.message();
while (!keyEvents.isEmpty()) {
QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue();
QApplication::postEvent(event.first, event.second);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 Q_SPI_APPLICATION_H
#define Q_SPI_APPLICATION_H
#include <QtCore/QQueue>
#include <QtDBus/QDBusConnection>
#include <QtGui/QAccessibleInterface>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
/*
* Used for the root object.
*
* Uses the root object reference and reports its parent as the desktop object.
*/
class QSpiApplicationAdaptor :public QObject
{
Q_OBJECT
public:
QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent);
virtual ~QSpiApplicationAdaptor() {}
void sendEvents(bool active);
Q_SIGNALS:
void windowActivated(QObject* window, bool active);
protected:
bool eventFilter(QObject *obj, QEvent *event);
private Q_SLOTS:
void notifyKeyboardListenerCallback(const QDBusMessage& message);
void notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& message);
private:
static QKeyEvent* copyKeyEvent(QKeyEvent*);
QQueue<QPair<QObject*, QKeyEvent*> > keyEvents;
QDBusConnection dbusConnection;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 ATSPIADAPTOR_H
#define ATSPIADAPTOR_H
#include <atspi/atspi-constants.h>
#include <QtCore/qsharedpointer.h>
#include <QtDBus/qdbusvirtualobject.h>
#include <QtGui/qaccessible.h>
#include <QtGui/qaccessible2.h>
#include "dbusconnection_p.h"
#include "struct_marshallers_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QAccessibleInterface;
class QSpiAccessibleInterface;
class QSpiApplicationAdaptor;
typedef QSharedPointer<QAccessibleInterface> QAIPointer;
class AtSpiAdaptor :public QDBusVirtualObject
{
Q_OBJECT
public:
explicit AtSpiAdaptor(DBusConnection *connection, QObject *parent = 0);
~AtSpiAdaptor();
void registerApplication();
QString introspect(const QString &path) const;
bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection);
void notify(QAccessibleEvent *event);
void setInitialized(bool init);
public Q_SLOTS:
void eventListenerRegistered(const QString &bus, const QString &path);
void eventListenerDeregistered(const QString &bus, const QString &path);
void windowActivated(QObject* window, bool active);
private:
void updateEventListeners();
void setBitFlag(const QString &flag);
// sending messages
QVariantList packDBusSignalArguments(const QString &type, int data1, int data2, const QVariant &variantData) const;
bool sendDBusSignal(const QString &path, const QString &interface, const QString &name, const QVariantList &arguments) const;
QVariant variantForPath(const QString &path) const;
void sendFocusChanged(const QAIPointer &interface) const;
void notifyAboutCreation(const QAIPointer &interface) const;
void notifyAboutDestruction(const QAIPointer &interface) const;
// handlers for the different accessible interfaces
bool applicationInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool accessibleInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool componentInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool actionInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool textInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool editableTextInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool valueInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
bool tableInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
void sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const;
QAIPointer interfaceFromPath(const QString& dbusPath) const;
QString pathForInterface(const QAIPointer &interface, bool inDestructor = false) const;
QString pathForObject(QObject *object) const;
// accessible helper functions
AtspiRole getRole(const QAIPointer &interface) const;
QSpiRelationArray relationSet(const QAIPointer &interface, const QDBusConnection &connection) const;
QStringList accessibleInterfaces(const QAIPointer &interface) const;
// component helper functions
static QRect getExtents(const QAIPointer &interface, uint coordType);
static QRect translateRectToWindowCoordinates(const QAIPointer &interface, const QRect &rect);
// action helper functions
QSpiActionArray getActions(QAccessibleActionInterface* interface) const;
// text helper functions
QVariantList getAttributes(const QAIPointer &, int offset, bool includeDefaults) const;
QVariantList getAttributeValue(const QAIPointer &, int offset, const QString &attributeName) const;
QRect getCharacterExtents(const QAIPointer &, int offset, uint coordType) const;
QRect getRangeExtents(const QAIPointer &, int startOffset, int endOffset, uint coordType) const;
QAccessible2::BoundaryType qAccessibleBoundaryType(int atspiTextBoundaryType) const;
static bool inheritsQAction(QObject *object);
// private vars
QSpiObjectReference accessibilityRegistry;
DBusConnection *m_dbus;
QSpiApplicationAdaptor *m_applicationAdaptor;
/// Assigned from the accessibility registry.
int m_applicationId;
bool initialized;
mutable QHash<quintptr, QPointer<QObject> > m_handledObjects;
// Bit fields - which updates to send
// AT-SPI has some events that we do not care about:
// document
// document-load-complete
// document-load-stopped
// document-reload
uint sendFocus : 1;
// mouse abs/rel/button
// all of object
uint sendObject : 1;
uint sendObject_active_descendant_changed : 1;
uint sendObject_attributes_changed : 1;
uint sendObject_bounds_changed : 1;
uint sendObject_children_changed : 1;
// uint sendObject_children_changed_add : 1;
// uint sendObject_children_changed_remove : 1;
uint sendObject_column_deleted : 1;
uint sendObject_column_inserted : 1;
uint sendObject_column_reordered : 1;
uint sendObject_link_selected : 1;
uint sendObject_model_changed : 1;
uint sendObject_property_change : 1;
uint sendObject_property_change_accessible_description : 1;
uint sendObject_property_change_accessible_name : 1;
uint sendObject_property_change_accessible_parent : 1;
uint sendObject_property_change_accessible_role : 1;
uint sendObject_property_change_accessible_table_caption : 1;
uint sendObject_property_change_accessible_table_column_description : 1;
uint sendObject_property_change_accessible_table_column_header : 1;
uint sendObject_property_change_accessible_table_row_description : 1;
uint sendObject_property_change_accessible_table_row_header : 1;
uint sendObject_property_change_accessible_table_summary : 1;
uint sendObject_property_change_accessible_value : 1;
uint sendObject_row_deleted : 1;
uint sendObject_row_inserted : 1;
uint sendObject_row_reordered : 1;
uint sendObject_selection_changed : 1;
uint sendObject_state_changed : 1;
uint sendObject_text_attributes_changed : 1;
uint sendObject_text_bounds_changed : 1;
uint sendObject_text_caret_moved : 1;
uint sendObject_text_changed : 1;
// uint sendObject_text_changed_delete : 1;
// uint sendObject_text_changed_insert : 1;
uint sendObject_text_selection_changed : 1;
uint sendObject_value_changed : 1;
uint sendObject_visible_data_changed : 1;
// we don't implement terminal
// terminal-application_changed/charwidth_changed/columncount_changed/line_changed/linecount_changed
uint sendWindow : 1;
uint sendWindow_activate : 1;
uint sendWindow_close: 1;
uint sendWindow_create : 1;
uint sendWindow_deactivate : 1;
// uint sendWindow_desktop_create : 1;
// uint sendWindow_desktop_destroy : 1;
uint sendWindow_lower : 1;
uint sendWindow_maximize : 1;
uint sendWindow_minimize : 1;
uint sendWindow_move : 1;
uint sendWindow_raise : 1;
uint sendWindow_reparent : 1;
uint sendWindow_resize : 1;
uint sendWindow_restore : 1;
uint sendWindow_restyle : 1;
uint sendWindow_shade : 1;
uint sendWindow_unshade : 1;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@ -0,0 +1,192 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "bridge_p.h"
#include <atspi/atspi-constants.h>
#include <qstring.h>
#include "atspiadaptor_p.h"
#include "cache_p.h"
#include "constant_mappings_p.h"
#include "dbusconnection_p.h"
#include "struct_marshallers_p.h"
#include "deviceeventcontroller_adaptor.h"
QT_BEGIN_NAMESPACE
/*!
\class QSpiAccessibleBridge
\brief QSpiAccessibleBridge
QSpiAccessibleBridge
*/
QSpiAccessibleBridge::QSpiAccessibleBridge()
: cache(0)
{
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);
bool reg = dBusConnection().registerObject(QLatin1String(ATSPI_DBUS_PATH_DEC), this, QDBusConnection::ExportAdaptors);
qDebug() << "Registered DEC: " << reg;
dbusAdaptor = new AtSpiAdaptor(dbusConnection, this);
dBusConnection().registerVirtualObject(QLatin1String(QSPI_OBJECT_PATH_ACCESSIBLE), dbusAdaptor, QDBusConnection::SubPath);
dbusAdaptor->registerApplication();
}
QSpiAccessibleBridge::~QSpiAccessibleBridge()
{
delete dbusConnection;
} // Qt currently doesn't delete plugins.
QDBusConnection QSpiAccessibleBridge::dBusConnection() const
{
return dbusConnection->connection();
}
void QSpiAccessibleBridge::setRootObject(QAccessibleInterface *interface)
{
// the interface we get will be for the QApplication object.
// we already cache it in the constructor.
Q_ASSERT(interface->object() == qApp);
dbusAdaptor->setInitialized(true);
}
void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
dbusAdaptor->notify(event);
}
struct RoleMapping {
QAccessible::Role role;
AtspiRole spiRole;
const char *name;
const char *localizedName;
};
static RoleMapping map[] = {
{ QAccessible::NoRole, ATSPI_ROLE_INVALID, "invalid", QT_TR_NOOP("invalid role") },
{ QAccessible::TitleBar, ATSPI_ROLE_TEXT, "text", QT_TR_NOOP("title bar") },
{ QAccessible::MenuBar, ATSPI_ROLE_MENU_BAR, "menu bar", QT_TR_NOOP("menu bar") },
{ QAccessible::ScrollBar, ATSPI_ROLE_SCROLL_BAR, "scroll bar", QT_TR_NOOP("scroll bar") },
{ QAccessible::Grip, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("grip") },
{ QAccessible::Sound, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("sound") },
{ QAccessible::Cursor, ATSPI_ROLE_ARROW, "arrow", QT_TR_NOOP("cursor") },
{ QAccessible::Caret, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("caret") },
{ QAccessible::AlertMessage, ATSPI_ROLE_ALERT, "alert", QT_TR_NOOP("alert message") },
{ QAccessible::Window, ATSPI_ROLE_WINDOW, "window", QT_TR_NOOP("window") },
{ QAccessible::Client, ATSPI_ROLE_FILLER, "filler", QT_TR_NOOP("filler") },
{ QAccessible::PopupMenu, ATSPI_ROLE_POPUP_MENU, "popup menu", QT_TR_NOOP("popup menu") },
{ QAccessible::MenuItem, ATSPI_ROLE_MENU_ITEM, "menu item", QT_TR_NOOP("menu item") },
{ QAccessible::ToolTip, ATSPI_ROLE_TOOL_TIP, "tool tip", QT_TR_NOOP("tool tip") },
{ QAccessible::Application, ATSPI_ROLE_APPLICATION, "application", QT_TR_NOOP("application") },
{ QAccessible::Document, ATSPI_ROLE_DOCUMENT_FRAME, "document frame", QT_TR_NOOP("document") },
{ QAccessible::Pane, ATSPI_ROLE_PANEL, "panel", QT_TR_NOOP("pane") },
{ QAccessible::Chart, ATSPI_ROLE_CHART, "chart", QT_TR_NOOP("chart") },
{ QAccessible::Dialog, ATSPI_ROLE_DIALOG, "dialog", QT_TR_NOOP("dialog") },
{ QAccessible::Border, ATSPI_ROLE_FRAME, "frame", QT_TR_NOOP("border") },
{ QAccessible::Grouping, ATSPI_ROLE_PANEL, "panel", QT_TR_NOOP("grouping") },
{ QAccessible::Separator, ATSPI_ROLE_SEPARATOR, "separator", QT_TR_NOOP("separator") },
{ QAccessible::ToolBar, ATSPI_ROLE_TOOL_BAR, "tool bar", QT_TR_NOOP("tool bar") },
{ QAccessible::StatusBar, ATSPI_ROLE_STATUS_BAR, "statusbar", QT_TR_NOOP("status bar") },
{ QAccessible::Table, ATSPI_ROLE_TABLE, "table", QT_TR_NOOP("table") },
{ QAccessible::ColumnHeader, ATSPI_ROLE_TABLE_COLUMN_HEADER, "column header", QT_TR_NOOP("column header") },
{ QAccessible::RowHeader, ATSPI_ROLE_TABLE_ROW_HEADER, "row header", QT_TR_NOOP("row header") },
{ QAccessible::Column, ATSPI_ROLE_TABLE_CELL, "table cell", QT_TR_NOOP("column") },
{ QAccessible::Row, ATSPI_ROLE_TABLE_CELL, "table cell", QT_TR_NOOP("row") },
{ QAccessible::Cell, ATSPI_ROLE_TABLE_CELL, "table cell", QT_TR_NOOP("cell") },
{ QAccessible::Link, ATSPI_ROLE_LINK, "link", QT_TR_NOOP("link") },
{ QAccessible::HelpBalloon, ATSPI_ROLE_DIALOG, "dialog", QT_TR_NOOP("help balloon") },
{ QAccessible::Assistant, ATSPI_ROLE_DIALOG, "dialog", QT_TR_NOOP("assistant") },
{ QAccessible::List, ATSPI_ROLE_LIST, "list", QT_TR_NOOP("list") },
{ QAccessible::ListItem, ATSPI_ROLE_LIST_ITEM, "list item", QT_TR_NOOP("list item") },
{ QAccessible::Tree, ATSPI_ROLE_TREE, "tree", QT_TR_NOOP("tree") },
{ QAccessible::TreeItem, ATSPI_ROLE_TABLE_CELL, "tree item", QT_TR_NOOP("tree item") },
{ QAccessible::PageTab, ATSPI_ROLE_PAGE_TAB, "page tab", QT_TR_NOOP("page tab") },
{ QAccessible::PropertyPage, ATSPI_ROLE_PAGE_TAB, "page tab", QT_TR_NOOP("property page") },
{ QAccessible::Indicator, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("indicator") },
{ QAccessible::Graphic, ATSPI_ROLE_IMAGE, "image", QT_TR_NOOP("graphic") },
{ QAccessible::StaticText, ATSPI_ROLE_LABEL, "label", QT_TR_NOOP("label") },
{ QAccessible::EditableText, ATSPI_ROLE_TEXT, "text", QT_TR_NOOP("text") },
{ QAccessible::PushButton, ATSPI_ROLE_PUSH_BUTTON, "push button", QT_TR_NOOP("push button") },
{ QAccessible::CheckBox, ATSPI_ROLE_CHECK_BOX, "check box", QT_TR_NOOP("check box") },
{ QAccessible::RadioButton, ATSPI_ROLE_RADIO_BUTTON, "radio button", QT_TR_NOOP("radio box") },
{ QAccessible::ComboBox, ATSPI_ROLE_COMBO_BOX, "combo box", QT_TR_NOOP("combo box") },
{ QAccessible::ProgressBar, ATSPI_ROLE_PROGRESS_BAR, "progress bar", QT_TR_NOOP("progress bar") },
{ QAccessible::Dial, ATSPI_ROLE_DIAL, "accelerator label", QT_TR_NOOP("dial") },
{ QAccessible::HotkeyField, ATSPI_ROLE_TEXT, "text", QT_TR_NOOP("hotkey field") }, //FIXME text?
{ QAccessible::Slider, ATSPI_ROLE_SLIDER, "slider", QT_TR_NOOP("slider") },
{ QAccessible::SpinBox, ATSPI_ROLE_SPIN_BUTTON, "spin button", QT_TR_NOOP("spin box") },
{ QAccessible::Canvas, ATSPI_ROLE_CANVAS, "canvas", QT_TR_NOOP("canvas") },
{ QAccessible::Animation, ATSPI_ROLE_ANIMATION, "animation", QT_TR_NOOP("animation") },
{ QAccessible::Equation, ATSPI_ROLE_TEXT, "text", QT_TR_NOOP("equation") },
{ QAccessible::ButtonDropDown, ATSPI_ROLE_PUSH_BUTTON, "push button", QT_TR_NOOP("button drop down") },
{ QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON, "push button", QT_TR_NOOP("button menu") },
{ QAccessible::ButtonDropGrid, ATSPI_ROLE_PUSH_BUTTON, "push button", QT_TR_NOOP("button drop grid") },
{ QAccessible::Whitespace, ATSPI_ROLE_FILLER, "filler", QT_TR_NOOP("whitespace") },
{ QAccessible::PageTabList, ATSPI_ROLE_PAGE_TAB_LIST, "page tab list", QT_TR_NOOP("page tab list") },
{ QAccessible::Clock, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("clock") },
{ QAccessible::Splitter, ATSPI_ROLE_SPLIT_PANE, "split pane", QT_TR_NOOP("splitter") },
{ QAccessible::LayeredPane, ATSPI_ROLE_LAYERED_PANE, "layered pane", QT_TR_NOOP("layered pane") },
{ QAccessible::UserRole, ATSPI_ROLE_UNKNOWN, "unknown", QT_TR_NOOP("user role") }
};
void QSpiAccessibleBridge::initializeConstantMappings()
{
for (uint i = 0; i < sizeof(map) / sizeof(RoleMapping); ++i)
qSpiRoleMapping.insert(map[i].role, RoleNames(map[i].spiRole, QLatin1String(map[i].name), tr(map[i].localizedName)));
}
QT_END_NAMESPACE

View File

@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 QSPIACCESSIBLEBRIDGE_H
#define QSPIACCESSIBLEBRIDGE_H
#include <QtDBus/qdbusconnection.h>
#include <qpa/qplatformaccessibility.h>
class DeviceEventControllerAdaptor;
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class DBusConnection;
class QSpiDBusCache;
class AtSpiAdaptor;
class QSpiAccessibleBridge: public QObject, public QPlatformAccessibility
{
Q_OBJECT
public:
QSpiAccessibleBridge();
virtual ~QSpiAccessibleBridge();
virtual void setRootObject(QAccessibleInterface *obj);
virtual void notifyAccessibilityUpdate(QAccessibleEvent *event);
QDBusConnection dBusConnection() const;
private:
void initializeConstantMappings();
QSpiDBusCache *cache;
DeviceEventControllerAdaptor *dec;
AtSpiAdaptor *dbusAdaptor;
DBusConnection* dbusConnection;
bool initialized;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "cache_p.h"
#include "cache_adaptor.h"
#include "bridge_p.h"
#define QSPI_OBJECT_PATH_CACHE "/org/a11y/atspi/cache"
QT_BEGIN_NAMESPACE
/*!
\class QSpiDBusCache
\brief This class is responsible for the AT-SPI cache interface.
The idea behind the cache is that starting an application would
result in many dbus calls. The way GTK/Gail/ATK work is that
they create accessibles for all objects on startup.
In order to avoid querying all the objects individually via DBus
they get sent by using the GetItems call of the cache.
Additionally the AddAccessible and RemoveAccessible signals
are responsible for adding/removing objects from the cache.
Currently the Qt bridge chooses to ignore these.
*/
QSpiDBusCache::QSpiDBusCache(QDBusConnection c, QObject* parent)
: QObject(parent)
{
new CacheAdaptor(this);
c.registerObject(QLatin1String(QSPI_OBJECT_PATH_CACHE), this, QDBusConnection::ExportAdaptors);
}
void QSpiDBusCache::emitAddAccessible(const QSpiAccessibleCacheItem& item)
{
emit AddAccessible(item);
}
void QSpiDBusCache::emitRemoveAccessible(const QSpiObjectReference& item)
{
emit RemoveAccessible(item);
}
QSpiAccessibleCacheArray QSpiDBusCache::GetItems()
{
QList <QSpiAccessibleCacheItem> cacheArray;
return cacheArray;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 Q_SPI_CACHE_H
#define Q_SPI_CACHE_H
#include <QtCore/QObject>
#include "struct_marshallers_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSpiDBusCache : public QObject
{
Q_OBJECT
public:
QSpiDBusCache(QDBusConnection c, QObject* parent = 0);
void emitAddAccessible(const QSpiAccessibleCacheItem& item);
void emitRemoveAccessible(const QSpiObjectReference& item);
Q_SIGNALS:
void AddAccessible(const QSpiAccessibleCacheItem &nodeAdded);
void RemoveAccessible(const QSpiObjectReference &nodeRemoved);
public Q_SLOTS:
QSpiAccessibleCacheArray GetItems();
};
QT_END_NAMESPACE
QT_END_HEADER
#endif /* Q_SPI_CACHE_H */

View File

@ -0,0 +1,159 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "constant_mappings_p.h"
#include <qobject.h>
#include <qdebug.h>
// FIXME the assignment of roles is quite arbitrary, at some point go through this list and sort and check that it makes sense
// "calendar" "check menu item" "color chooser" "column header" "dateeditor" "desktop icon" "desktop frame"
// "directory pane" "drawing area" "file chooser" "fontchooser" "frame" "glass pane" "html container" "icon"
// "internal frame" "option pane" "password text" "radio menu item" "root pane" "row header" "scroll pane"
// "tear off menu item" "terminal" "toggle button" "tree table" "unknown" "viewport" "header" "footer" "paragraph"
// "ruler" "autocomplete" "edit bar" "embedded component" "entry" "caption"
// "heading" "page" "section" "redundant object" "form" "input method window" "menu"
QT_BEGIN_NAMESPACE
QHash <QAccessible::Role, RoleNames> qSpiRoleMapping;
quint64 spiStatesFromQState(QAccessible::State state)
{
quint64 spiState = 0;
setSpiStateBit(&spiState, ATSPI_STATE_EDITABLE);
setSpiStateBit(&spiState, ATSPI_STATE_ENABLED);
setSpiStateBit(&spiState, ATSPI_STATE_SHOWING);
setSpiStateBit(&spiState, ATSPI_STATE_VISIBLE);
setSpiStateBit(&spiState, ATSPI_STATE_SENSITIVE);
if (state.disabled) {
unsetSpiStateBit(&spiState, ATSPI_STATE_ENABLED);
unsetSpiStateBit(&spiState, ATSPI_STATE_SHOWING);
unsetSpiStateBit(&spiState, ATSPI_STATE_VISIBLE);
unsetSpiStateBit(&spiState, ATSPI_STATE_SENSITIVE);
}
if (state.selected)
setSpiStateBit(&spiState, ATSPI_STATE_SELECTED);
if (state.focused)
setSpiStateBit(&spiState, ATSPI_STATE_FOCUSED);
if (state.pressed)
setSpiStateBit(&spiState, ATSPI_STATE_PRESSED);
if (state.checked)
setSpiStateBit(&spiState, ATSPI_STATE_CHECKED);
if (state.checkStateMixed)
setSpiStateBit(&spiState, ATSPI_STATE_INDETERMINATE);
if (state.readOnly)
unsetSpiStateBit(&spiState, ATSPI_STATE_EDITABLE);
// if (state.HotTracked)
if (state.defaultButton)
setSpiStateBit(&spiState, ATSPI_STATE_IS_DEFAULT);
if (state.expanded)
setSpiStateBit(&spiState, ATSPI_STATE_EXPANDED);
if (state.collapsed)
setSpiStateBit(&spiState, ATSPI_STATE_COLLAPSED);
if (state.busy)
setSpiStateBit(&spiState, ATSPI_STATE_BUSY);
if (state.marqueed || state.animated)
setSpiStateBit(&spiState, ATSPI_STATE_ANIMATED);
if (state.invisible || state.offscreen) {
unsetSpiStateBit(&spiState, ATSPI_STATE_SHOWING);
unsetSpiStateBit(&spiState, ATSPI_STATE_VISIBLE);
}
if (state.sizeable)
setSpiStateBit(&spiState, ATSPI_STATE_RESIZABLE);
// if (state.Movable)
// if (state.SelfVoicing)
if (state.focusable)
setSpiStateBit(&spiState, ATSPI_STATE_FOCUSABLE);
if (state.selectable)
setSpiStateBit(&spiState, ATSPI_STATE_SELECTABLE);
// if (state.Linked)
if (state.traversed)
setSpiStateBit(&spiState, ATSPI_STATE_VISITED);
if (state.multiSelectable)
setSpiStateBit(&spiState, ATSPI_STATE_MULTISELECTABLE);
if (state.extSelectable)
setSpiStateBit(&spiState, ATSPI_STATE_SELECTABLE);
// if (state.Protected)
// if (state.HasPopup)
if (state.modal)
setSpiStateBit(&spiState, ATSPI_STATE_MODAL);
// Not implemented in Qt
// if (state.singleLine)
// setSpiStateBit(&spiState, ATSPI_STATE_SINGLE_LINE);
return spiState;
}
QSpiUIntList spiStateSetFromSpiStates(quint64 states)
{
uint low = states & 0xFFFFFFFF;
uint high = (states >> 32) & 0xFFFFFFFF;
QSpiUIntList stateList;
stateList.append(low);
stateList.append(high);
return stateList;
}
AtspiRelationType qAccessibleRelationToAtSpiRelation(QAccessible::Relation relation)
{
switch (relation) {
case QAccessible::Label:
return ATSPI_RELATION_LABELLED_BY;
case QAccessible::Labelled:
return ATSPI_RELATION_LABEL_FOR;
case QAccessible::Controller:
return ATSPI_RELATION_CONTROLLED_BY;
case QAccessible::Controlled:
return ATSPI_RELATION_CONTROLLER_FOR;
default:
qWarning() << "Cannot return AT-SPI relation for:" << relation;
}
return ATSPI_RELATION_NULL;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,138 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
/*
* This file contains AT-SPI constants and mappings between QAccessible
* and AT-SPI constants such as 'role' and 'state' enumerations.
*/
#ifndef Q_SPI_CONSTANT_MAPPINGS_H
#define Q_SPI_CONSTANT_MAPPINGS_H
#include "struct_marshallers_p.h"
#include <QtGui/QAccessible>
#include <atspi/atspi-constants.h>
// interface names from at-spi2-core/atspi/atspi-misc-private.h
#define ATSPI_DBUS_NAME_REGISTRY "org.a11y.atspi.Registry"
#define ATSPI_DBUS_PATH_REGISTRY "/org/a11y/atspi/registry"
#define ATSPI_DBUS_INTERFACE_REGISTRY "org.a11y.atspi.Registry"
#define ATSPI_DBUS_PATH_ROOT "/org/a11y/atspi/accessible/root"
#define ATSPI_DBUS_PATH_DEC "/org/a11y/atspi/registry/deviceeventcontroller"
#define ATSPI_DBUS_INTERFACE_DEC "org.a11y.atspi.DeviceEventController"
#define ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER "org.a11y.atspi.DeviceEventListener"
#define ATSPI_DBUS_INTERFACE_CACHE "org.a11y.atspi.Cache"
#define ATSPI_DBUS_INTERFACE_ACCESSIBLE "org.a11y.atspi.Accessible"
#define ATSPI_DBUS_INTERFACE_ACTION "org.a11y.atspi.Action"
#define ATSPI_DBUS_INTERFACE_APPLICATION "org.a11y.atspi.Application"
#define ATSPI_DBUS_INTERFACE_COLLECTION "org.a11y.atspi.Collection"
#define ATSPI_DBUS_INTERFACE_COMPONENT "org.a11y.atspi.Component"
#define ATSPI_DBUS_INTERFACE_DOCUMENT "org.a11y.atspi.Document"
#define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT "org.a11y.atspi.EditableText"
#define ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD "org.a11y.atspi.Event.Keyboard"
#define ATSPI_DBUS_INTERFACE_EVENT_MOUSE "org.a11y.atspi.Event.Mouse"
#define ATSPI_DBUS_INTERFACE_EVENT_OBJECT "org.a11y.atspi.Event.Object"
#define ATSPI_DBUS_INTERFACE_HYPERLINK "org.a11y.atspi.Hyperlink"
#define ATSPI_DBUS_INTERFACE_HYPERTEXT "org.a11y.atspi.Hypertext"
#define ATSPI_DBUS_INTERFACE_IMAGE "org.a11y.atspi.Image"
#define ATSPI_DBUS_INTERFACE_SELECTION "org.a11y.atspi.Selection"
#define ATSPI_DBUS_INTERFACE_TABLE "org.a11y.atspi.Table"
#define ATSPI_DBUS_INTERFACE_TEXT "org.a11y.atspi.Text"
#define ATSPI_DBUS_INTERFACE_VALUE "org.a11y.atspi.Value"
#define ATSPI_DBUS_INTERFACE_SOCKET "org.a11y.atspi.Socket"
// missing from at-spi2-core:
#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
#define ATSPI_DBUS_INTERFACE_EVENT_FOCUS "org.a11y.atspi.Event.Focus"
#define QSPI_OBJECT_PATH_ACCESSIBLE "/org/a11y/atspi/accessible"
#define QSPI_OBJECT_PATH_PREFIX "/org/a11y/atspi/accessible/"
#define QSPI_OBJECT_PATH_ROOT QSPI_OBJECT_PATH_PREFIX "root"
#define QSPI_REGISTRY_NAME "org.a11y.atspi.Registry"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
struct RoleNames {
RoleNames() {}
RoleNames(AtspiRole r, const QString& n, const QString& ln)
:m_spiRole(r), m_name(n), m_localizedName(ln)
{}
AtspiRole spiRole() const {return m_spiRole;}
QString name() const {return m_name;}
QString localizedName() const {return m_localizedName;}
private:
AtspiRole m_spiRole;
QString m_name;
QString m_localizedName;
};
extern QHash <QAccessible::Role, RoleNames> qSpiRoleMapping;
extern QHash <int, AtspiStateType> qSpiStateMapping;
inline void setSpiStateBit(quint64* state, AtspiStateType spiState)
{
*state |= quint64(1) << spiState;
}
inline void unsetSpiStateBit(quint64* state, AtspiStateType spiState)
{
*state &= ~(quint64(1) << spiState);
}
quint64 spiStatesFromQState(QAccessible::State state);
QSpiUIntList spiStateSetFromSpiStates(quint64 states);
AtspiRelationType qAccessibleRelationToAtSpiRelation(QAccessible::Relation relation);
QT_END_NAMESPACE
QT_END_HEADER
#endif /* Q_SPI_CONSTANT_MAPPINGS_H */

View File

@ -0,0 +1,116 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "dbusconnection_p.h"
#include <QtDBus/QDBusMessage>
#include <qdebug.h>
/*!
\class DBusConnection
\brief DBusConnection
DBusConnection
*/
QT_BEGIN_NAMESPACE
/*!
Connects to the accessibility dbus.
This is usually a different bus from the session bus.
*/
DBusConnection::DBusConnection()
: dbusConnection(connectDBus())
{}
QDBusConnection DBusConnection::connectDBus()
{
QString address = getAccessibilityBusAddress();
if (!address.isEmpty()) {
QDBusConnection c = QDBusConnection::connectToBus(address, QStringLiteral("a11y"));
if (c.isConnected()) {
qDebug() << "Connected to accessibility bus at: " << address;
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.");
}
QDBusConnection c = QDBusConnection::sessionBus();
if (!c.isConnected()) {
qWarning("Could not connect to DBus.");
}
return QDBusConnection::sessionBus();
}
QString DBusConnection::getAccessibilityBusAddress() const
{
QDBusConnection c = QDBusConnection::sessionBus();
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();
}
QString busAddress = reply.arguments().at(0).toString();
qDebug() << "Got bus address: " << busAddress;
return busAddress;
}
/*!
Returns the DBus connection that got established.
*/
QDBusConnection DBusConnection::connection() const
{
return dbusConnection;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 DBUSCONNECTION_H
#define DBUSCONNECTION_H
#include <QtCore/QString>
#include <QtDBus/QDBusConnection>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class DBusConnection
{
public:
DBusConnection();
QDBusConnection connection() const;
private:
QString getAccessibilityBusAddress() const;
QDBusConnection connectDBus();
QDBusConnection dbusConnection;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // DBUSCONNECTION_H

View File

@ -0,0 +1,27 @@
contains(QT_CONFIG, dbus):contains(QT_CONFIG, xcb):contains(QT_CONFIG, accessibility) {
PKGCONFIG += atspi-2
CONFIG += link_pkgconfig
QT += dbus
include(../../3rdparty/atspi2/atspi2.pri)
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/application_p.h \
$$PWD/bridge_p.h \
$$PWD/cache_p.h \
$$PWD/struct_marshallers_p.h \
$$PWD/constant_mappings_p.h \
$$PWD/dbusconnection_p.h \
$$PWD/atspiadaptor_p.h
SOURCES += \
$$PWD/application.cpp \
$$PWD/bridge.cpp \
$$PWD/cache.cpp \
$$PWD/struct_marshallers.cpp \
$$PWD/constant_mappings.cpp \
$$PWD/dbusconnection.cpp \
$$PWD/atspiadaptor.cpp
}

View File

@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "bridge.h"
QT_BEGIN_NAMESPACE
/*!
\class QSpiAccessibleBridgePlugin
\brief QSpiAccessibleBridgePlugin
QSpiAccessibleBridgePlugin
*/
class QSpiAccessibleBridgePlugin: public QAccessibleBridgePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QAccessibleBridgeFactoryInterface" FILE "linuxaccessibility.json");
public:
QSpiAccessibleBridgePlugin(QObject *parent = 0);
virtual ~QSpiAccessibleBridgePlugin() {}
virtual QAccessibleBridge* create(const QString &key);
virtual QStringList keys() const;
};
/*!
The contructor of the plugin.
*/
QSpiAccessibleBridgePlugin::QSpiAccessibleBridgePlugin(QObject *parent)
: QAccessibleBridgePlugin(parent)
{
}
/*!
Creates a new instance of the QAccessibleBridge plugin.
*/
QAccessibleBridge* QSpiAccessibleBridgePlugin::create(const QString &key)
{
if (key == "QSPIACCESSIBLEBRIDGE")
return new QSpiAccessibleBridge();
return 0;
}
/*!
*/
QStringList QSpiAccessibleBridgePlugin::keys() const
{
return QStringList() << "QSPIACCESSIBLEBRIDGE";
}
QT_END_NAMESPACE

View File

@ -0,0 +1,234 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include "struct_marshallers_p.h"
#include <atspi/atspi-constants.h>
#include <QtCore/qdebug.h>
#include <QtDBus/qdbusmetatype.h>
#include "bridge_p.h"
QT_BEGIN_NAMESPACE
QSpiObjectReference::QSpiObjectReference()
: path(QDBusObjectPath(ATSPI_DBUS_PATH_NULL))
{}
/* QSpiAccessibleCacheArray */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAccessibleCacheItem &item)
{
argument.beginStructure();
argument << item.path;
argument << item.application;
argument << item.parent;
argument << item.children;
argument << item.supportedInterfaces;
argument << item.name;
argument << item.role;
argument << item.description;
argument << item.state;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAccessibleCacheItem &item)
{
argument.beginStructure();
argument >> item.path;
argument >> item.application;
argument >> item.parent;
argument >> item.children;
argument >> item.supportedInterfaces;
argument >> item.name;
argument >> item.role;
argument >> item.description;
argument >> item.state;
argument.endStructure();
return argument;
}
/* QSpiObjectReference */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiObjectReference &address)
{
argument.beginStructure();
argument << address.service;
argument << address.path;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiObjectReference &address)
{
argument.beginStructure();
argument >> address.service;
argument >> address.path;
argument.endStructure();
return argument;
}
/* QSpiAction */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAction &action)
{
argument.beginStructure();
argument << action.name;
argument << action.description;
argument << action.keyBinding;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAction &action)
{
Q_UNUSED(action)
qWarning() << "QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAction &action): implement me!";
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiEventListener &ev)
{
argument.beginStructure();
argument << ev.listenerAddress;
argument << ev.eventName;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiEventListener &ev)
{
argument.beginStructure();
argument >> ev.listenerAddress;
argument >> ev.eventName;
argument.endStructure();
return argument;
}
/* QSpiAppUpdate */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAppUpdate &update) {
argument.beginStructure();
argument << update.type << update.address;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAppUpdate &update) {
argument.beginStructure();
argument >> update.type >> update.address;
argument.endStructure();
return argument;
}
/* QSpiRelationArrayEntry */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiRelationArrayEntry &entry) {
argument.beginStructure();
argument << entry.first << entry.second;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiRelationArrayEntry &entry) {
argument.beginStructure();
argument >> entry.first >> entry.second;
argument.endStructure();
return argument;
}
/* QSpiDeviceEvent */
/*---------------------------------------------------------------------------*/
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiDeviceEvent &event) {
argument.beginStructure();
argument << event.type
<< event.id
<< event.hardwareCode
<< event.modifiers
<< event.timestamp
<< event.text
<< event.isText;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiDeviceEvent &event) {
argument.beginStructure();
argument >> event.type
>> event.id
>> event.hardwareCode
>> event.modifiers
>> event.timestamp
>> event.text
>> event.isText;
argument.endStructure();
return argument;
}
void qSpiInitializeStructTypes()
{
qDBusRegisterMetaType<QSpiIntList>();
qDBusRegisterMetaType<QSpiUIntList>();
qDBusRegisterMetaType<QSpiAccessibleCacheItem>();
qDBusRegisterMetaType<QSpiAccessibleCacheArray>();
qDBusRegisterMetaType<QSpiObjectReference>();
qDBusRegisterMetaType<QSpiObjectReferenceArray>();
qDBusRegisterMetaType<QSpiAttributeSet>();
qDBusRegisterMetaType<QSpiAction>();
qDBusRegisterMetaType<QSpiActionArray>();
qDBusRegisterMetaType<QSpiEventListener>();
qDBusRegisterMetaType<QSpiEventListenerArray>();
qDBusRegisterMetaType<QSpiDeviceEvent>();
qDBusRegisterMetaType<QSpiAppUpdate>();
qDBusRegisterMetaType<QSpiRelationArrayEntry>();
qDBusRegisterMetaType<QSpiRelationArray>();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,177 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 Q_SPI_STRUCT_MARSHALLERS_H
#define Q_SPI_STRUCT_MARSHALLERS_H
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtDBus/QDBusArgument>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusObjectPath>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
typedef QList <int> QSpiIntList;
typedef QList <uint> QSpiUIntList;
// FIXME: make this copy on write
struct QSpiObjectReference
{
QString service;
QDBusObjectPath path;
QSpiObjectReference();
QSpiObjectReference(const QDBusConnection& connection, const QDBusObjectPath& path)
: service(connection.baseService()), path(path) {}
};
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiObjectReference &address);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiObjectReference &address);
typedef QList <QSpiObjectReference> QSpiObjectReferenceArray;
struct QSpiAccessibleCacheItem
{
QSpiObjectReference path;
QSpiObjectReference application;
QSpiObjectReference parent;
QList <QSpiObjectReference> children;
QStringList supportedInterfaces;
QString name;
uint role;
QString description;
QSpiUIntList state;
};
typedef QList <QSpiAccessibleCacheItem> QSpiAccessibleCacheArray;
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAccessibleCacheItem &item);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAccessibleCacheItem &item);
struct QSpiAction
{
QString name;
QString description;
QString keyBinding;
};
typedef QList <QSpiAction> QSpiActionArray;
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAction &action);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAction &action);
struct QSpiEventListener
{
QString listenerAddress;
QString eventName;
};
typedef QList <QSpiEventListener> QSpiEventListenerArray;
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiEventListener &action);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiEventListener &action);
typedef QPair < unsigned int, QList < QSpiObjectReference > > QSpiRelationArrayEntry;
typedef QList< QSpiRelationArrayEntry > QSpiRelationArray;
//a(iisv)
struct QSpiTextRange {
int startOffset;
int endOffset;
QString contents;
QVariant v;
};
typedef QList <QSpiTextRange> QSpiTextRangeList;
typedef QMap <QString, QString> QSpiAttributeSet;
enum QSpiAppUpdateType {
QSPI_APP_UPDATE_ADDED = 0,
QSPI_APP_UPDATE_REMOVED = 1
};
struct QSpiAppUpdate {
int type; /* Is an application added or removed */
QString address; /* D-Bus address of application added or removed */
};
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAppUpdate &update);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAppUpdate &update);
struct QSpiDeviceEvent {
unsigned int type;
int id;
int hardwareCode;
int modifiers;
int timestamp;
QString text;
bool isText;
};
QDBusArgument &operator<<(QDBusArgument &argument, const QSpiDeviceEvent &event);
const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiDeviceEvent &event);
void qSpiInitializeStructTypes();
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QSpiIntList)
Q_DECLARE_METATYPE(QSpiUIntList)
Q_DECLARE_METATYPE(QSpiObjectReference)
Q_DECLARE_METATYPE(QSpiObjectReferenceArray)
Q_DECLARE_METATYPE(QSpiAccessibleCacheItem)
Q_DECLARE_METATYPE(QSpiAccessibleCacheArray)
Q_DECLARE_METATYPE(QSpiAction)
Q_DECLARE_METATYPE(QSpiActionArray)
Q_DECLARE_METATYPE(QSpiEventListener)
Q_DECLARE_METATYPE(QSpiEventListenerArray)
Q_DECLARE_METATYPE(QSpiRelationArrayEntry)
Q_DECLARE_METATYPE(QSpiRelationArray)
Q_DECLARE_METATYPE(QSpiTextRange)
Q_DECLARE_METATYPE(QSpiTextRangeList)
Q_DECLARE_METATYPE(QSpiAttributeSet)
Q_DECLARE_METATYPE(QSpiAppUpdate)
Q_DECLARE_METATYPE(QSpiDeviceEvent)
QT_END_HEADER
#endif /* Q_SPI_STRUCT_MARSHALLERS_H */

View File

@ -21,3 +21,4 @@ include(input/input.pri)
include(devicediscovery/devicediscovery.pri)
include(services/services.pri)
include(themes/themes.pri)
include(linuxaccessibility/linuxaccessibility.pri)

View File

@ -85,6 +85,7 @@
#include <QtGui/QScreen>
#ifndef QT_NO_ACCESSIBILITY
#include <qpa/qplatformaccessibility.h>
#include "../../../platformsupport/linuxaccessibility/bridge_p.h"
#endif
QT_BEGIN_NAMESPACE
@ -117,7 +118,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters)
m_fontDatabase.reset(new QGenericUnixFontDatabase());
m_inputContext.reset(QPlatformInputContextFactory::create());
#ifndef QT_NO_ACCESSIBILITY
m_accessibility.reset(new QPlatformAccessibility());
m_accessibility.reset(new QSpiAccessibleBridge());
#endif
}

View File

@ -16,6 +16,7 @@ SUBDIRS=\
modeltest \
networkselftest \
qaccessibility \
qaccessibilitylinux \
qcomplextext \
qfocusevent \
qnetworkaccessmanager_and_qprogressdialog \
@ -45,7 +46,9 @@ cross_compile: SUBDIRS -= \
atwrapper \
compiler
wince*|!contains(QT_CONFIG, accessibility):SUBDIRS -= qaccessibility
wince*|!contains(QT_CONFIG, accessibility): SUBDIRS -= qaccessibility
!contains(QT_CONFIG, accessibility)|!contains(QT_CONFIG, xcb): SUBDIRS -= qaccessibilitylinux
!mac: SUBDIRS -= \
macgui \

View File

@ -0,0 +1,12 @@
CONFIG += testcase
TARGET = tst_qaccessibilitylinux
SOURCES += tst_qaccessibilitylinux.cpp \
../../../../src/platformsupport/linuxaccessibility/dbusconnection.cpp \
../../../../src/platformsupport/linuxaccessibility/struct_marshallers.cpp
CONFIG += gui
CONFIG += link_pkgconfig
QT += gui widgets dbus testlib
PKGCONFIG += atspi-2

View File

@ -0,0 +1,467 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtGui>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QTextEdit>
#include <QDBusArgument>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusInterface>
#include <QDBusReply>
#include <atspi/atspi-constants.h>
#include "../../../../src/plugins/platforms/linuxaccessibility/dbusconnection.h"
#include "../../../../src/plugins/platforms/linuxaccessibility/struct_marshallers.h"
#define COMPARE3(v1, v2, v3) QCOMPARE(v1, v3); QCOMPARE(v2, v3);
class AccessibleTestWindow : public QWidget
{
Q_OBJECT
public:
AccessibleTestWindow()
{
DBusConnection c;
m_address = c.connection().baseService().toLatin1().data();
new QHBoxLayout(this);
}
QString dbusAddress() const { return m_address; }
void addWidget(QWidget* widget)
{
layout()->addWidget(widget);
widget->show();
QTest::qWaitForWindowShown(widget);
}
void clearChildren()
{
qDeleteAll(children());
new QHBoxLayout(this);
}
private:
QString m_address;
QString m_bus;
};
class tst_QtAtSpi : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testLabel();
void testLineEdit();
void testListWidget();
void testTreeWidget();
void testTextEdit();
void testSlider();
void cleanupTestCase();
private:
void registerDbus();
static QString getParent(QDBusInterface *interface);
static QStringList getChildren(QDBusInterface *interface);
QDBusInterface *getInterface(const QString &path, const QString &interfaceName);
AccessibleTestWindow *m_window;
QString bus;
QString address;
QDBusInterface *root; // the root object on dbus (for the app)
QDBusInterface *rootApplication;
QDBusInterface *mainWindow;
DBusConnection dbus;
};
// helper to find children of a dbus object
QStringList tst_QtAtSpi::getChildren(QDBusInterface *interface)
{
QSpiObjectReferenceArray list;
interface->call(QDBus::Block, "GetChildren").arguments().first().value<QDBusArgument>() >> list;
Q_ASSERT(interface->property("ChildCount").toInt() == list.count());
QStringList children;
Q_FOREACH (const QSpiObjectReference &ref, list)
children << ref.path.path();
return children;
}
QString tst_QtAtSpi::getParent(QDBusInterface *interface)
{
if (!interface->isValid())
return QString();
QVariant var = interface->property("Parent");
if (!var.canConvert<QSpiObjectReference>()) {
qWarning() << "Invalid parent";
return QString();
}
QSpiObjectReference parent = var.value<QSpiObjectReference>();
return parent.path.path();
}
// helper to get dbus object
QDBusInterface *tst_QtAtSpi::getInterface(const QString &path, const QString &interfaceName)
{
return new QDBusInterface(address, path, interfaceName, dbus.connection(), this);
}
void tst_QtAtSpi::initTestCase()
{
// Oxygen style creates many extra items, it's simply unusable here
qDebug() << "Using plastique style...";
qApp->setStyle("plastique");
qApp->setApplicationName("tst_QtAtSpi app");
dbus = DBusConnection();
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::qWaitForWindowShown(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_QtAtSpi::cleanupTestCase()
{
delete mainWindow;
delete rootApplication;
delete root;
delete m_window;
}
void tst_QtAtSpi::registerDbus()
{
QVERIFY(dbus.connection().isConnected());
root = getInterface("/org/a11y/atspi/accessible/root",
"org.a11y.atspi.Accessible");
rootApplication = getInterface("/org/a11y/atspi/accessible/root",
"org.a11y.atspi.Application");
QVERIFY(root->isValid());
QVERIFY(rootApplication->isValid());
QStringList appChildren = getChildren(root);
QString window = appChildren.at(0);
mainWindow = getInterface(window, "org.a11y.atspi.Accessible");
}
#define ROOTPATH "/org/a11y/atspi/accessible"
void tst_QtAtSpi::testLabel()
{
QLabel *l = new QLabel(m_window);
l->setText("Hello A11y");
m_window->addWidget(l);
// Application
QCOMPARE(getParent(mainWindow), QLatin1String(ATSPI_DBUS_PATH_ROOT));
QStringList children = getChildren(mainWindow);
QDBusInterface *labelInterface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QVERIFY(labelInterface->isValid());
QCOMPARE(labelInterface->property("Name").toString(), QLatin1String("Hello A11y"));
QCOMPARE(getChildren(labelInterface).count(), 0);
QCOMPARE(labelInterface->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("label"));
QCOMPARE(labelInterface->call(QDBus::Block, "GetRole").arguments().first().toUInt(), 29u);
QCOMPARE(getParent(labelInterface), mainWindow->path());
l->setText("New text");
QCOMPARE(labelInterface->property("Name").toString(), l->text());
m_window->clearChildren();
delete labelInterface;
}
void tst_QtAtSpi::testLineEdit()
{
QLineEdit *lineEdit = new QLineEdit(m_window);
lineEdit->setText("a11y test QLineEdit");
m_window->addWidget(lineEdit);
QStringList children = getChildren(mainWindow);
QDBusInterface *accessibleInterface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QDBusInterface *editableTextInterface = getInterface(children.at(0), "org.a11y.atspi.EditableText");
QDBusInterface *textInterface = getInterface(children.at(0), "org.a11y.atspi.Text");
QVERIFY(accessibleInterface->isValid());
QVERIFY(editableTextInterface->isValid());
QVERIFY(textInterface->isValid());
QCOMPARE(accessibleInterface->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("text"));
QCOMPARE(textInterface->call(QDBus::Block,"GetText", 5, -1).arguments().first().toString(), QLatin1String("test QLineEdit"));
QString newText = "Text has changed!";
editableTextInterface->call(QDBus::Block, "SetTextContents", newText);
COMPARE3(lineEdit->text(), textInterface->call(QDBus::Block, "GetText", 0, -1).arguments().first().toString(), newText);
QCOMPARE(textInterface->call(QDBus::Block, "GetText", 0, 4).arguments().first().toString(), QLatin1String("Text"));
editableTextInterface->call(QDBus::Block, "DeleteText", 4, 8);
COMPARE3(lineEdit->text(), "Te" + textInterface->call(QDBus::Block, "GetText", 2, 10).arguments().first().toString() + "ed!", QLatin1String("Text changed!"));
editableTextInterface->call(QDBus::Block, "InsertText", 12, " again ", 6);
QCOMPARE(lineEdit->text(), QLatin1String("Text changed again!"));
COMPARE3(lineEdit->text().length(), textInterface->property("CharacterCount").toInt(), 19);
textInterface->call(QDBus::Block, "SetCaretOffset", 4);
COMPARE3(lineEdit->cursorPosition(), textInterface->property("CaretOffset").toInt(), 4);
textInterface->call(QDBus::Block, "AddSelection", 1, 4);
QList<QVariant> data = textInterface->call(QDBus::Block, "GetSelection", 0).arguments();
COMPARE3(data.at(0).toInt(), lineEdit->selectionStart(), 1);
QCOMPARE(data.at(1).toInt(), 4);
QCOMPARE(lineEdit->selectedText().length(), 3);
QCOMPARE(textInterface->call(QDBus::Block, "GetNSelections").arguments().first().toInt(), 1);
textInterface->call(QDBus::Block, "SetSelection", 0, 0, 5);
data = textInterface->call(QDBus::Block, "GetSelection", 0).arguments();
COMPARE3(data.at(0).toInt(), lineEdit->selectionStart(), 0);
COMPARE3(data.at(1).toInt(), lineEdit->selectedText().length(), 5);
textInterface->call(QDBus::Block, "RemoveSelection", 0);
QCOMPARE(lineEdit->selectionStart(), -1);
QCOMPARE(textInterface->call(QDBus::Block, "GetNSelections").arguments().first().toInt(), 0);
m_window->clearChildren();
delete accessibleInterface;
delete textInterface;
delete editableTextInterface;
}
void tst_QtAtSpi::testListWidget()
{
QListWidget *lw = new QListWidget;
lw->addItem("Hello");
lw->addItem("Good morning");
lw->addItem("Good bye");
m_window->addWidget(lw);
QStringList children = getChildren(mainWindow);
QDBusInterface *listIface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QCOMPARE(listIface->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("list"));
QStringList tableChildren = getChildren(listIface);
QCOMPARE(tableChildren.size(), 3);
QDBusInterface *cell1 = getInterface(tableChildren.at(0), "org.a11y.atspi.Accessible");
QCOMPARE(cell1->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("list item"));
QCOMPARE(cell1->property("Name").toString(), QLatin1String("Hello"));
QDBusInterface *cell2 = getInterface(tableChildren.at(1), "org.a11y.atspi.Accessible");
QCOMPARE(cell2->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("list item"));
QCOMPARE(cell2->property("Name").toString(), QLatin1String("Good morning"));
QDBusInterface *cell3 = getInterface(tableChildren.at(2), "org.a11y.atspi.Accessible");
QCOMPARE(cell3->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("list item"));
QCOMPARE(cell3->property("Name").toString(), QLatin1String("Good bye"));
delete cell1; delete cell2; delete cell3;
m_window->clearChildren();
delete listIface;
}
void tst_QtAtSpi::testTreeWidget()
{
QTreeWidget *tree = new QTreeWidget;
tree->setColumnCount(2);
tree->setHeaderLabels(QStringList() << "Header 1" << "Header 2");
QTreeWidgetItem *top1 = new QTreeWidgetItem(QStringList() << "0.0" << "0.1");
tree->addTopLevelItem(top1);
QTreeWidgetItem *top2 = new QTreeWidgetItem(QStringList() << "1.0" << "1.1");
tree->addTopLevelItem(top2);
QTreeWidgetItem *child1 = new QTreeWidgetItem(QStringList() << "1.0 0.0" << "1.0 0.1");
top2->addChild(child1);
m_window->addWidget(tree);
QStringList children = getChildren(mainWindow);
QDBusInterface *treeIface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QCOMPARE(treeIface->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("tree"));
QStringList tableChildren = getChildren(treeIface);
QCOMPARE(tableChildren.size(), 6);
QDBusInterface *cell1 = getInterface(tableChildren.at(0), "org.a11y.atspi.Accessible");
QCOMPARE(cell1->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("column header"));
QCOMPARE(cell1->property("Name").toString(), QLatin1String("Header 1"));
QDBusInterface *cell2 = getInterface(tableChildren.at(1), "org.a11y.atspi.Accessible");
QCOMPARE(cell2->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("column header"));
QCOMPARE(cell2->property("Name").toString(), QLatin1String("Header 2"));
QDBusInterface *cell3 = getInterface(tableChildren.at(2), "org.a11y.atspi.Accessible");
QCOMPARE(cell3->property("Name").toString(), QLatin1String("0.0"));
QDBusInterface *cell4 = getInterface(tableChildren.at(3), "org.a11y.atspi.Accessible");
QCOMPARE(cell4->property("Name").toString(), QLatin1String("0.1"));
tree->expandItem(top2);
tableChildren = getChildren(treeIface);
QCOMPARE(tableChildren.size(), 8);
QDBusInterface *cell5 = getInterface(tableChildren.at(6), "org.a11y.atspi.Accessible");
QCOMPARE(cell5->property("Name").toString(), QLatin1String("1.0 0.0"));
QDBusInterface *cell6 = getInterface(tableChildren.at(7), "org.a11y.atspi.Accessible");
QCOMPARE(cell6->property("Name").toString(), QLatin1String("1.0 0.1"));
QDBusInterface *treeTableIface = getInterface(children.at(0), "org.a11y.atspi.Table");
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 0).arguments().first().toInt(), -1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 1).arguments().first().toInt(), -1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 2).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 3).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 4).arguments().first().toInt(), 1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 5).arguments().first().toInt(), 1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 6).arguments().first().toInt(), 2);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetRowAtIndex", 7).arguments().first().toInt(), 2);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 0).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 1).arguments().first().toInt(), 1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 2).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 3).arguments().first().toInt(), 1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 4).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 5).arguments().first().toInt(), 1);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 6).arguments().first().toInt(), 0);
QCOMPARE(treeTableIface->call(QDBus::Block, "GetColumnAtIndex", 7).arguments().first().toInt(), 1);
delete treeTableIface;
delete cell1; delete cell2; delete cell3; delete cell4; delete cell5; delete cell6;
m_window->clearChildren();
delete treeIface;
}
void tst_QtAtSpi::testTextEdit()
{
QTextEdit *textEdit = new QTextEdit(m_window);
textEdit->setText("<html><head></head><body>This is a <b>sample</b> text.<br />"
"How are you today</body></html>");
textEdit->show();
m_window->addWidget(textEdit);
QStringList children = getChildren(mainWindow);
QDBusInterface *accessibleInterface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QDBusInterface *editableTextInterface = getInterface(children.at(0), "org.a11y.atspi.EditableText");
QDBusInterface *textInterface = getInterface(children.at(0), "org.a11y.atspi.Text");
QVERIFY(accessibleInterface->isValid());
QVERIFY(editableTextInterface->isValid());
QVERIFY(textInterface->isValid());
QList<QVariant> callResult;
QDBusMessage msg = textInterface->call(QDBus::Block, "GetText", 0, 5);
callResult = msg.arguments();
QCOMPARE(callResult.at(0).toString(), QLatin1String("This "));
msg = textInterface->call(QDBus::Block, "GetTextAtOffset", 12, (uint) ATSPI_TEXT_BOUNDARY_WORD_START);
callResult = msg.arguments();
QEXPECT_FAIL("", "Word should contain space at end according to atspi.", Continue);
QCOMPARE(callResult.at(0).toString(), QLatin1String("sample "));
QCOMPARE(callResult.at(1).toInt(), 10);
QEXPECT_FAIL("", "Due to missing space the count is off by one.", Continue);
QCOMPARE(callResult.at(2).toInt(), 17);
// Check if at least CharacterExtents and RangeExtents give a consistent result
QDBusReply<QRect> replyRect20 = textInterface->call(QDBus::Block, "GetCharacterExtents", 20, ATSPI_COORD_TYPE_SCREEN);
QVERIFY(replyRect20.isValid());
QRect r1 = replyRect20.value();
QDBusReply<QRect> replyRect21 = textInterface->call(QDBus::Block, "GetCharacterExtents", 21, ATSPI_COORD_TYPE_SCREEN);
QRect r2 = replyRect21.value();
QDBusReply<QRect> reply = textInterface->call(QDBus::Block, "GetRangeExtents", 20, 21, ATSPI_COORD_TYPE_SCREEN);
QRect rect = reply.value();
QCOMPARE(rect, r1|r2);
m_window->clearChildren();
delete textInterface;
}
void tst_QtAtSpi::testSlider()
{
QSlider *slider = new QSlider(m_window);
slider->setMinimum(2);
slider->setMaximum(5);
slider->setValue(3);
m_window->addWidget(slider);
QStringList children = getChildren(mainWindow);
QDBusInterface *accessibleInterface = getInterface(children.at(0), "org.a11y.atspi.Accessible");
QDBusInterface *valueInterface = getInterface(children.at(0), "org.a11y.atspi.Value");
QVERIFY(accessibleInterface->isValid());
QVERIFY(valueInterface->isValid());
QCOMPARE(valueInterface->property("CurrentValue").toInt(), 3);
QCOMPARE(valueInterface->property("MinimumValue").toInt(), 2);
QCOMPARE(valueInterface->property("MaximumValue").toInt(), 5);
valueInterface->setProperty("CurrentValue", 4);
QCOMPARE(valueInterface->property("CurrentValue").toInt(), 4);
}
QTEST_MAIN(tst_QtAtSpi)
#include "tst_qaccessibilitylinux.moc"