summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-07-02 10:04:34 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-07-06 11:15:08 +0200
commit9e733622a605c841adf7da7304895758d307c843 (patch)
treee859f7cf4dee099c49835c65e5c0498bcec6f87c /src/gui
parent7067b2ca6e08e683bb9c202a7e3c1b10d08622ee (diff)
Move linuxaccessibility to QtGui
Change some too-generic file names. Task-number: QTBUG-83255 Change-Id: I4497ee2508bc323566f4061d4547707b7bda7a77 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/.prev_CMakeLists.txt25
-rw-r--r--src/gui/CMakeLists.txt31
-rw-r--r--src/gui/accessible/accessible.pri2
-rw-r--r--src/gui/accessible/linux/.prev_CMakeLists.txt40
-rw-r--r--src/gui/accessible/linux/CMakeLists.txt42
-rw-r--r--src/gui/accessible/linux/atspiadaptor.cpp2482
-rw-r--r--src/gui/accessible/linux/atspiadaptor_p.h228
-rw-r--r--src/gui/accessible/linux/dbusconnection.cpp172
-rw-r--r--src/gui/accessible/linux/dbusconnection_p.h95
-rw-r--r--src/gui/accessible/linux/dbusxml/Bus.xml17
-rw-r--r--src/gui/accessible/linux/dbusxml/Cache.xml21
-rw-r--r--src/gui/accessible/linux/dbusxml/DeviceEventController.xml66
-rw-r--r--src/gui/accessible/linux/dbusxml/Socket.xml23
-rw-r--r--src/gui/accessible/linux/linux.pri27
-rw-r--r--src/gui/accessible/linux/qspi_constant_mappings.cpp154
-rw-r--r--src/gui/accessible/linux/qspi_constant_mappings_p.h145
-rw-r--r--src/gui/accessible/linux/qspi_struct_marshallers.cpp237
-rw-r--r--src/gui/accessible/linux/qspi_struct_marshallers_p.h200
-rw-r--r--src/gui/accessible/linux/qspiaccessiblebridge.cpp286
-rw-r--r--src/gui/accessible/linux/qspiaccessiblebridge_p.h95
-rw-r--r--src/gui/accessible/linux/qspiapplicationadaptor.cpp240
-rw-r--r--src/gui/accessible/linux/qspiapplicationadaptor_p.h99
-rw-r--r--src/gui/accessible/linux/qspidbuscache.cpp91
-rw-r--r--src/gui/accessible/linux/qspidbuscache_p.h82
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h6
25 files changed, 4896 insertions, 10 deletions
diff --git a/src/gui/.prev_CMakeLists.txt b/src/gui/.prev_CMakeLists.txt
index 31eb39fb95..a4820965e7 100644
--- a/src/gui/.prev_CMakeLists.txt
+++ b/src/gui/.prev_CMakeLists.txt
@@ -399,6 +399,23 @@ qt_extend_target(Gui CONDITION QT_FEATURE_accessibility AND WIN32
accessible/windows/apisupport/uiatypes_p.h
)
+qt_extend_target(Gui CONDITION QT_FEATURE_accessibility AND QT_FEATURE_accessibility_atspi_bridge
+ SOURCES
+ accessible/linux/atspiadaptor.cpp accessible/linux/atspiadaptor_p.h
+ accessible/linux/dbusconnection.cpp accessible/linux/dbusconnection_p.h
+ accessible/linux/qspi_constant_mappings.cpp accessible/linux/qspi_constant_mappings_p.h
+ accessible/linux/qspi_struct_marshallers.cpp accessible/linux/qspi_struct_marshallers_p.h
+ accessible/linux/qspiaccessiblebridge.cpp accessible/linux/qspiaccessiblebridge_p.h
+ accessible/linux/qspiapplicationadaptor.cpp accessible/linux/qspiapplicationadaptor_p.h
+ accessible/linux/qspidbuscache.cpp accessible/linux/qspidbuscache_p.h
+ DBUS_ADAPTOR_SOURCES
+ accessibility_adaptors
+ DBUS_INTERFACE_SOURCES
+ accessibility_interfaces
+ PUBLIC_LIBRARIES
+ PkgConfig::ATSPI2_nolink
+)
+
qt_extend_target(Gui CONDITION QT_FEATURE_action
SOURCES
kernel/qaction.cpp kernel/qaction.h kernel/qaction_p.h
@@ -433,7 +450,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_png
WrapPNG::WrapPNG
)
-#### Keys ignored in scope 38:.:image:image/image.pri:WIN32 AND MINGW:
+#### Keys ignored in scope 40:.:image:image/image.pri:WIN32 AND MINGW:
# GCC_VERSION = "$${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}"
qt_extend_target(Gui CONDITION ((QT_FEATURE_png) AND (WIN32 AND MINGW)) AND (GCC_VERSION___equals___8.1.0)
@@ -676,7 +693,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_vulkan
Vulkan::Vulkan_nolink
)
-#### Keys ignored in scope 99:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen:
+#### Keys ignored in scope 101:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen:
# QMAKE_EXTRA_COMPILERS = "qvkgen_h" "qvkgen_ph" "qvkgen_pimpl"
# QMAKE_QVKGEN_INPUT = "vulkan/vk.xml"
# QMAKE_QVKGEN_LICENSE_HEADER = "$$QT_SOURCE_TREE/header.LGPL"
@@ -692,10 +709,10 @@ qt_extend_target(Gui CONDITION QT_FEATURE_vulkan
# qvkgen_pimpl.input = "QMAKE_QVKGEN_INPUT"
# qvkgen_pimpl.output = "$$OUT_PWD/vulkan/qvulkanfunctions_p.cpp"
-#### Keys ignored in scope 100:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan:
+#### Keys ignored in scope 102:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan:
# qvkgen_h.variable_out = "HEADERS"
-#### Keys ignored in scope 101:.:vulkan:vulkan/vulkan.pri:else:
+#### Keys ignored in scope 103:.:vulkan:vulkan/vulkan.pri:else:
# qvkgen_h.CONFIG = "target_predeps" "no_link"
qt_extend_target(Gui CONDITION WASM
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index db6f463c0b..21dc18721e 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -487,6 +487,31 @@ qt_extend_target(Gui CONDITION QT_FEATURE_accessibility AND WIN32
accessible/windows/apisupport/uiatypes_p.h
)
+qt_extend_target(Gui CONDITION QT_FEATURE_accessibility AND QT_FEATURE_accessibility_atspi_bridge
+ SOURCES
+ accessible/linux/atspiadaptor.cpp accessible/linux/atspiadaptor_p.h
+ accessible/linux/dbusconnection.cpp accessible/linux/dbusconnection_p.h
+ accessible/linux/qspi_constant_mappings.cpp accessible/linux/qspi_constant_mappings_p.h
+ accessible/linux/qspi_struct_marshallers.cpp accessible/linux/qspi_struct_marshallers_p.h
+ accessible/linux/qspiaccessiblebridge.cpp accessible/linux/qspiaccessiblebridge_p.h
+ accessible/linux/qspiapplicationadaptor.cpp accessible/linux/qspiapplicationadaptor_p.h
+ accessible/linux/qspidbuscache.cpp accessible/linux/qspidbuscache_p.h
+# special case begin
+ DBUS_ADAPTOR_SOURCES
+ accessible/linux/dbusxml/Cache.xml
+ accessible/linux/dbusxml/DeviceEventController.xml
+ DBUS_ADAPTOR_FLAGS
+ "-i" "QtGui/private/qspi_struct_marshallers_p.h"
+ DBUS_INTERFACE_SOURCES
+ accessible/linux/dbusxml/Bus.xml
+ accessible/linux/dbusxml/Socket.xml
+ DBUS_INTERFACE_FLAGS
+ "-i" "QtGui/private/qspi_struct_marshallers_p.h"
+# special case end
+ PUBLIC_LIBRARIES
+ PkgConfig::ATSPI2_nolink
+)
+
qt_extend_target(Gui CONDITION QT_FEATURE_action
SOURCES
kernel/qaction.cpp kernel/qaction.h kernel/qaction_p.h
@@ -521,7 +546,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_png
WrapPNG::WrapPNG
)
-#### Keys ignored in scope 38:.:image:image/image.pri:WIN32 AND MINGW:
+#### Keys ignored in scope 40:.:image:image/image.pri:WIN32 AND MINGW:
# GCC_VERSION = "$${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}"
qt_extend_target(Gui CONDITION ((QT_FEATURE_png) AND (WIN32 AND MINGW)) AND (GCC_VERSION___equals___8.1.0)
@@ -839,10 +864,10 @@ add_custom_command(
# qvkgen_pimpl.input = "QMAKE_QVKGEN_INPUT"
# qvkgen_pimpl.output = "$$OUT_PWD/vulkan/qvulkanfunctions_p.cpp"
-#### Keys ignored in scope 100:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan:
+#### Keys ignored in scope 102:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan:
# qvkgen_h.variable_out = "HEADERS"
-#### Keys ignored in scope 101:.:vulkan:vulkan/vulkan.pri:else:
+#### Keys ignored in scope 103:.:vulkan:vulkan/vulkan.pri:else:
# qvkgen_h.CONFIG = "target_predeps" "no_link"
qt_extend_target(Gui CONDITION WASM
diff --git a/src/gui/accessible/accessible.pri b/src/gui/accessible/accessible.pri
index 471e2fbaea..cc403ba9e9 100644
--- a/src/gui/accessible/accessible.pri
+++ b/src/gui/accessible/accessible.pri
@@ -25,4 +25,6 @@ qtConfig(accessibility) {
}
win32: include(windows/windows.pri)
+
+ qtConfig(accessibility-atspi-bridge): include(linux/linux.pri)
}
diff --git a/src/gui/accessible/linux/.prev_CMakeLists.txt b/src/gui/accessible/linux/.prev_CMakeLists.txt
new file mode 100644
index 0000000000..ffb0ca9610
--- /dev/null
+++ b/src/gui/accessible/linux/.prev_CMakeLists.txt
@@ -0,0 +1,40 @@
+# Generated from linuxaccessibility.pro.
+
+#####################################################################
+## LinuxAccessibilitySupport Module:
+#####################################################################
+
+qt_add_module(LinuxAccessibilitySupport
+ STATIC
+ INTERNAL_MODULE
+ SOURCES
+ application.cpp application_p.h
+ atspiadaptor.cpp atspiadaptor_p.h
+ bridge.cpp bridge_p.h
+ cache.cpp cache_p.h
+ constant_mappings.cpp constant_mappings_p.h
+ dbusconnection.cpp dbusconnection_p.h
+ struct_marshallers.cpp struct_marshallers_p.h
+ DBUS_ADAPTOR_SOURCES
+ dbusxml/Cache.xml
+ dbusxml/DeviceEventController.xml
+ DBUS_ADAPTOR_FLAGS
+ "-i" "struct_marshallers_p.h"
+ DBUS_INTERFACE_SOURCES
+ dbusxml/Bus.xml
+ dbusxml/Socket.xml
+ DBUS_INTERFACE_FLAGS
+ "-i" "struct_marshallers_p.h"
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ PUBLIC_LIBRARIES
+ PkgConfig::ATSPI2_nolink
+ Qt::CorePrivate
+ Qt::DBus
+ Qt::GuiPrivate
+ PRECOMPILED_HEADER
+ "../../corelib/global/qt_pch.h"
+)
+
+#### Keys ignored in scope 1:.:.:linuxaccessibility.pro:<TRUE>:
+# MODULE = "linuxaccessibility_support"
diff --git a/src/gui/accessible/linux/CMakeLists.txt b/src/gui/accessible/linux/CMakeLists.txt
new file mode 100644
index 0000000000..0e1a7a9d16
--- /dev/null
+++ b/src/gui/accessible/linux/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Generated from linuxaccessibility.pro.
+
+qt_find_package(ATSPI2) # special case
+
+#####################################################################
+## LinuxAccessibilitySupport Module:
+#####################################################################
+
+qt_add_module(LinuxAccessibilitySupport
+ STATIC
+ INTERNAL_MODULE
+ SOURCES
+ application.cpp application_p.h
+ atspiadaptor.cpp atspiadaptor_p.h
+ bridge.cpp bridge_p.h
+ cache.cpp cache_p.h
+ constant_mappings.cpp constant_mappings_p.h
+ dbusconnection.cpp dbusconnection_p.h
+ struct_marshallers.cpp struct_marshallers_p.h
+ DBUS_ADAPTOR_SOURCES
+ dbusxml/Cache.xml
+ dbusxml/DeviceEventController.xml
+ DBUS_ADAPTOR_FLAGS
+ "-i" "struct_marshallers_p.h"
+ DBUS_INTERFACE_SOURCES
+ dbusxml/Bus.xml
+ dbusxml/Socket.xml
+ DBUS_INTERFACE_FLAGS
+ "-i" "struct_marshallers_p.h"
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ PUBLIC_LIBRARIES
+ PkgConfig::ATSPI2_nolink
+ Qt::CorePrivate
+ Qt::DBus
+ Qt::GuiPrivate
+ PRECOMPILED_HEADER
+ "../../corelib/global/qt_pch.h"
+)
+
+#### Keys ignored in scope 1:.:.:linuxaccessibility.pro:<TRUE>:
+# MODULE = "linuxaccessibility_support"
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp
new file mode 100644
index 0000000000..65b014c9e1
--- /dev/null
+++ b/src/gui/accessible/linux/atspiadaptor.cpp
@@ -0,0 +1,2482 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "atspiadaptor_p.h"
+
+#include <QtGui/qwindow.h>
+#include <QtGui/qguiapplication.h>
+#include <qdbusmessage.h>
+#include <qdbusreply.h>
+#include <qclipboard.h>
+
+#include <QtCore/qloggingcategory.h>
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "socket_interface.h"
+#include "qspi_constant_mappings_p.h"
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
+
+#include "qspiapplicationadaptor_p.h"
+/*!
+ \class AtSpiAdaptor
+ \internal
+
+ \brief AtSpiAdaptor is the main class to forward between QAccessibleInterface and AT-SPI DBus
+
+ AtSpiAdaptor implements the functions specified in all at-spi interfaces.
+ It sends notifications coming from Qt via dbus and listens to incoming dbus requests.
+*/
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcAccessibilityAtspi, "qt.accessibility.atspi")
+Q_LOGGING_CATEGORY(lcAccessibilityAtspiCreation, "qt.accessibility.atspi.creation")
+
+AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
+ : QDBusVirtualObject(parent), m_dbus(connection)
+ , sendFocus(0)
+ , sendObject(0)
+ , sendObject_active_descendant_changed(0)
+ , sendObject_attributes_changed(0)
+ , sendObject_bounds_changed(0)
+ , sendObject_children_changed(0)
+// , sendObject_children_changed_add(0)
+// , sendObject_children_changed_remove(0)
+ , sendObject_column_deleted(0)
+ , sendObject_column_inserted(0)
+ , sendObject_column_reordered(0)
+ , sendObject_link_selected(0)
+ , sendObject_model_changed(0)
+ , sendObject_property_change(0)
+ , sendObject_property_change_accessible_description(0)
+ , sendObject_property_change_accessible_name(0)
+ , sendObject_property_change_accessible_parent(0)
+ , sendObject_property_change_accessible_role(0)
+ , sendObject_property_change_accessible_table_caption(0)
+ , sendObject_property_change_accessible_table_column_description(0)
+ , sendObject_property_change_accessible_table_column_header(0)
+ , sendObject_property_change_accessible_table_row_description(0)
+ , sendObject_property_change_accessible_table_row_header(0)
+ , sendObject_property_change_accessible_table_summary(0)
+ , sendObject_property_change_accessible_value(0)
+ , sendObject_row_deleted(0)
+ , sendObject_row_inserted(0)
+ , sendObject_row_reordered(0)
+ , sendObject_selection_changed(0)
+ , sendObject_state_changed(0)
+ , sendObject_text_attributes_changed(0)
+ , sendObject_text_bounds_changed(0)
+ , sendObject_text_caret_moved(0)
+ , sendObject_text_changed(0)
+// , sendObject_text_changed_delete(0)
+// , sendObject_text_changed_insert(0)
+ , sendObject_text_selection_changed(0)
+ , sendObject_value_changed(0)
+ , sendObject_visible_data_changed(0)
+ , sendWindow(0)
+ , sendWindow_activate(0)
+ , sendWindow_close(0)
+ , sendWindow_create(0)
+ , sendWindow_deactivate(0)
+// , sendWindow_desktop_create(0)
+// , sendWindow_desktop_destroy(0)
+ , sendWindow_lower(0)
+ , sendWindow_maximize(0)
+ , sendWindow_minimize(0)
+ , sendWindow_move(0)
+ , sendWindow_raise(0)
+ , sendWindow_reparent(0)
+ , sendWindow_resize(0)
+ , sendWindow_restore(0)
+ , sendWindow_restyle(0)
+ , sendWindow_shade(0)
+ , sendWindow_unshade(0)
+{
+ m_applicationAdaptor = new QSpiApplicationAdaptor(m_dbus->connection(), this);
+ connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,bool)), this, SLOT(windowActivated(QObject*,bool)));
+
+ updateEventListeners();
+ bool success = m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
+ QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerRegistered"), this,
+ SLOT(eventListenerRegistered(QString,QString)));
+ success = success && m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
+ QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerDeregistered"), this,
+ SLOT(eventListenerDeregistered(QString,QString)));
+}
+
+AtSpiAdaptor::~AtSpiAdaptor()
+{
+}
+
+/*!
+ Provide DBus introspection.
+ */
+QString AtSpiAdaptor::introspect(const QString &path) const
+{
+ static const QLatin1String accessibleIntrospection(
+ " <interface name=\"org.a11y.atspi.Accessible\">\n"
+ " <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
+ " <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
+ " <property access=\"read\" type=\"(so)\" name=\"Parent\">\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
+ " </property>\n"
+ " <property access=\"read\" type=\"i\" name=\"ChildCount\"/>\n"
+ " <method name=\"GetChildAtIndex\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetChildren\">\n"
+ " <arg direction=\"out\" type=\"a(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetIndexInParent\">\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRelationSet\">\n"
+ " <arg direction=\"out\" type=\"a(ua(so))\"/>\n"
+ " <annotation value=\"QSpiRelationArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRole\">\n"
+ " <arg direction=\"out\" type=\"u\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRoleName\">\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetLocalizedRoleName\">\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetState\">\n"
+ " <arg direction=\"out\" type=\"au\"/>\n"
+ " <annotation value=\"QSpiUIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAttributes\">\n"
+ " <arg direction=\"out\" type=\"a{ss}\"/>\n"
+ " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetApplication\">\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String actionIntrospection(
+ " <interface name=\"org.a11y.atspi.Action\">\n"
+ " <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
+ " <method name=\"GetDescription\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetName\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetKeyBinding\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetActions\">\n"
+ " <arg direction=\"out\" type=\"a(sss)\" name=\"index\"/>\n"
+ " <annotation value=\"QSpiActionArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"DoAction\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String applicationIntrospection(
+ " <interface name=\"org.a11y.atspi.Application\">\n"
+ " <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
+ " <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
+ " <property access=\"readwrite\" type=\"i\" name=\"Id\"/>\n"
+ " <method name=\"GetLocale\">\n"
+ " <arg direction=\"in\" type=\"u\" name=\"lctype\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetApplicationBusAddress\">\n"
+ " <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String componentIntrospection(
+ " <interface name=\"org.a11y.atspi.Component\">\n"
+ " <method name=\"Contains\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAccessibleAtPoint\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetExtents\">\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"(iiii)\"/>\n"
+ " <annotation value=\"QSpiRect\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetPosition\">\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
+ " </method>\n"
+ " <method name=\"GetSize\">\n"
+ " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
+ " </method>\n"
+ " <method name=\"GetLayer\">\n"
+ " <arg direction=\"out\" type=\"u\"/>\n"
+ " </method>\n"
+ " <method name=\"GetMDIZOrder\">\n"
+ " <arg direction=\"out\" type=\"n\"/>\n"
+ " </method>\n"
+ " <method name=\"GrabFocus\">\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAlpha\">\n"
+ " <arg direction=\"out\" type=\"d\"/>\n"
+ " </method>\n"
+ " <method name=\"SetExtents\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"SetPosition\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"SetSize\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String editableTextIntrospection(
+ " <interface name=\"org.a11y.atspi.EditableText\">\n"
+ " <method name=\"SetTextContents\">\n"
+ " <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"InsertText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
+ " <arg direction=\"in\" type=\"s\" name=\"text\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"length\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"CopyText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
+ " </method>\n"
+ " <method name=\"CutText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"DeleteText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"PasteText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String tableIntrospection(
+ " <interface name=\"org.a11y.atspi.Table\">\n"
+ " <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
+ " <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
+ " <property access=\"read\" type=\"(so)\" name=\"Caption\">\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
+ " </property>\n"
+ " <property access=\"read\" type=\"(so)\" name=\"Summary\">\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
+ " </property>\n"
+ " <property access=\"read\" type=\"i\" name=\"NSelectedRows\"/>\n"
+ " <property access=\"read\" type=\"i\" name=\"NSelectedColumns\"/>\n"
+ " <method name=\"GetAccessibleAt\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetIndexAt\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowAtIndex\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetColumnAtIndex\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowDescription\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetColumnDescription\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowExtentAt\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetColumnExtentAt\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowHeader\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetColumnHeader\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetSelectedRows\">\n"
+ " <arg direction=\"out\" type=\"ai\"/>\n"
+ " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetSelectedColumns\">\n"
+ " <arg direction=\"out\" type=\"ai\"/>\n"
+ " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"IsRowSelected\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"IsColumnSelected\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"IsSelected\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"AddRowSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"AddColumnSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"RemoveRowSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"RemoveColumnSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowColumnExtentsAtIndex\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"row\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"col\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"row_extents\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"col_extents\"/>\n"
+ " <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String textIntrospection(
+ " <interface name=\"org.a11y.atspi.Text\">\n"
+ " <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
+ " <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
+ " <method name=\"GetText\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"SetCaretOffset\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"GetTextBeforeOffset\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " </method>\n"
+ " <method name=\"GetTextAtOffset\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " </method>\n"
+ " <method name=\"GetTextAfterOffset\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " </method>\n"
+ " <method name=\"GetCharacterAtOffset\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAttributeValue\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"in\" type=\"s\" name=\"attributeName\"/>\n"
+ " <arg direction=\"out\" type=\"s\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " <arg direction=\"out\" type=\"b\" name=\"defined\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAttributes\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"out\" type=\"a{ss}\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetDefaultAttributes\">\n"
+ " <arg direction=\"out\" type=\"a{ss}\"/>\n"
+ " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetCharacterExtents\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
+ " </method>\n"
+ " <method name=\"GetOffsetAtPoint\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " </method>\n"
+ " <method name=\"GetNSelections\">\n"
+ " <arg direction=\"out\" type=\"i\"/>\n"
+ " <method name=\"GetSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " </method>\n"
+ " <method name=\"AddSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"RemoveSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"SetSelection\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
+ " <arg direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRangeExtents\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
+ " </method>\n"
+ " <method name=\"GetBoundedRanges\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
+ " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"xClipType\"/>\n"
+ " <arg direction=\"in\" type=\"u\" name=\"yClipType\"/>\n"
+ " <arg direction=\"out\" type=\"a(iisv)\"/>\n"
+ " <annotation value=\"QSpiRangeList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAttributeRun\">\n"
+ " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
+ " <arg direction=\"in\" type=\"b\" name=\"includeDefaults\"/>\n"
+ " <arg direction=\"out\" type=\"a{ss}\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
+ " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
+ " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetDefaultAttributeSet\">\n"
+ " <arg direction=\"out\" type=\"a{ss}\"/>\n"
+ " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ static const QLatin1String valueIntrospection(
+ " <interface name=\"org.a11y.atspi.Value\">\n"
+ " <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
+ " <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
+ " <property access=\"read\" type=\"d\" name=\"MinimumIncrement\"/>\n"
+ " <property access=\"readwrite\" type=\"d\" name=\"CurrentValue\"/>\n"
+ " <method name=\"SetCurrentValue\">\n"
+ " <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ );
+
+ QAccessibleInterface * interface = interfaceFromPath(path);
+ if (!interface) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << path;
+ return QString();
+ }
+
+ QStringList interfaces = accessibleInterfaces(interface);
+
+ QString xml;
+ xml.append(accessibleIntrospection);
+
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT)))
+ xml.append(componentIntrospection);
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_TEXT)))
+ xml.append(textIntrospection);
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT)))
+ xml.append(editableTextIntrospection);
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_ACTION)))
+ xml.append(actionIntrospection);
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_TABLE)))
+ xml.append(tableIntrospection);
+ if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_VALUE)))
+ xml.append(valueIntrospection);
+ if (path == QLatin1String(QSPI_OBJECT_PATH_ROOT))
+ xml.append(applicationIntrospection);
+
+ return xml;
+}
+
+void AtSpiAdaptor::setBitFlag(const QString &flag)
+{
+ Q_ASSERT(flag.size());
+
+ // assume we don't get nonsense - look at first letter only
+ switch (flag.at(0).toLower().toLatin1()) {
+ case 'o': {
+ if (flag.size() <= 8) { // Object::
+ sendObject = 1;
+ } else { // Object:Foo:Bar
+ QString right = flag.mid(7);
+ if (false) {
+ } else if (right.startsWith(QLatin1String("ActiveDescendantChanged"))) {
+ sendObject_active_descendant_changed = 1;
+ } else if (right.startsWith(QLatin1String("AttributesChanged"))) {
+ sendObject_attributes_changed = 1;
+ } else if (right.startsWith(QLatin1String("BoundsChanged"))) {
+ sendObject_bounds_changed = 1;
+ } else if (right.startsWith(QLatin1String("ChildrenChanged"))) {
+ sendObject_children_changed = 1;
+ } else if (right.startsWith(QLatin1String("ColumnDeleted"))) {
+ sendObject_column_deleted = 1;
+ } else if (right.startsWith(QLatin1String("ColumnInserted"))) {
+ sendObject_column_inserted = 1;
+ } else if (right.startsWith(QLatin1String("ColumnReordered"))) {
+ sendObject_column_reordered = 1;
+ } else if (right.startsWith(QLatin1String("LinkSelected"))) {
+ sendObject_link_selected = 1;
+ } else if (right.startsWith(QLatin1String("ModelChanged"))) {
+ sendObject_model_changed = 1;
+ } else if (right.startsWith(QLatin1String("PropertyChange"))) {
+ if (right == QLatin1String("PropertyChange:AccessibleDescription")) {
+ sendObject_property_change_accessible_description = 1;
+ } else if (right == QLatin1String("PropertyChange:AccessibleName")) {
+ sendObject_property_change_accessible_name = 1;
+ } else if (right == QLatin1String("PropertyChange:AccessibleParent")) {
+ sendObject_property_change_accessible_parent = 1;
+ } else if (right == QLatin1String("PropertyChange:AccessibleRole")) {
+ sendObject_property_change_accessible_role = 1;
+ } else if (right == QLatin1String("PropertyChange:TableCaption")) {
+ sendObject_property_change_accessible_table_caption = 1;
+ } else if (right == QLatin1String("PropertyChange:TableColumnDescription")) {
+ sendObject_property_change_accessible_table_column_description = 1;
+ } else if (right == QLatin1String("PropertyChange:TableColumnHeader")) {
+ sendObject_property_change_accessible_table_column_header = 1;
+ } else if (right == QLatin1String("PropertyChange:TableRowDescription")) {
+ sendObject_property_change_accessible_table_row_description = 1;
+ } else if (right == QLatin1String("PropertyChange:TableRowHeader")) {
+ sendObject_property_change_accessible_table_row_header = 1;
+ } else if (right == QLatin1String("PropertyChange:TableSummary")) {
+ sendObject_property_change_accessible_table_summary = 1;
+ } else if (right == QLatin1String("PropertyChange:AccessibleValue")) {
+ sendObject_property_change_accessible_value = 1;
+ } else {
+ sendObject_property_change = 1;
+ }
+ } else if (right.startsWith(QLatin1String("RowDeleted"))) {
+ sendObject_row_deleted = 1;
+ } else if (right.startsWith(QLatin1String("RowInserted"))) {
+ sendObject_row_inserted = 1;
+ } else if (right.startsWith(QLatin1String("RowReordered"))) {
+ sendObject_row_reordered = 1;
+ } else if (right.startsWith(QLatin1String("SelectionChanged"))) {
+ sendObject_selection_changed = 1;
+ } else if (right.startsWith(QLatin1String("StateChanged"))) {
+ sendObject_state_changed = 1;
+ } else if (right.startsWith(QLatin1String("TextAttributesChanged"))) {
+ sendObject_text_attributes_changed = 1;
+ } else if (right.startsWith(QLatin1String("TextBoundsChanged"))) {
+ sendObject_text_bounds_changed = 1;
+ } else if (right.startsWith(QLatin1String("TextCaretMoved"))) {
+ sendObject_text_caret_moved = 1;
+ } else if (right.startsWith(QLatin1String("TextChanged"))) {
+ sendObject_text_changed = 1;
+ } else if (right.startsWith(QLatin1String("TextSelectionChanged"))) {
+ sendObject_text_selection_changed = 1;
+ } else if (right.startsWith(QLatin1String("ValueChanged"))) {
+ sendObject_value_changed = 1;
+ } else if (right.startsWith(QLatin1String("VisibleDataChanged"))
+ || right.startsWith(QLatin1String("VisibledataChanged"))) { // typo in libatspi
+ sendObject_visible_data_changed = 1;
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag;
+ }
+ }
+ break;
+ }
+ case 'w': { // window
+ if (flag.size() <= 8) {
+ sendWindow = 1;
+ } else { // object:Foo:Bar
+ QString right = flag.mid(7);
+ if (false) {
+ } else if (right.startsWith(QLatin1String("Activate"))) {
+ sendWindow_activate = 1;
+ } else if (right.startsWith(QLatin1String("Close"))) {
+ sendWindow_close= 1;
+ } else if (right.startsWith(QLatin1String("Create"))) {
+ sendWindow_create = 1;
+ } else if (right.startsWith(QLatin1String("Deactivate"))) {
+ sendWindow_deactivate = 1;
+ } else if (right.startsWith(QLatin1String("Lower"))) {
+ sendWindow_lower = 1;
+ } else if (right.startsWith(QLatin1String("Maximize"))) {
+ sendWindow_maximize = 1;
+ } else if (right.startsWith(QLatin1String("Minimize"))) {
+ sendWindow_minimize = 1;
+ } else if (right.startsWith(QLatin1String("Move"))) {
+ sendWindow_move = 1;
+ } else if (right.startsWith(QLatin1String("Raise"))) {
+ sendWindow_raise = 1;
+ } else if (right.startsWith(QLatin1String("Reparent"))) {
+ sendWindow_reparent = 1;
+ } else if (right.startsWith(QLatin1String("Resize"))) {
+ sendWindow_resize = 1;
+ } else if (right.startsWith(QLatin1String("Restore"))) {
+ sendWindow_restore = 1;
+ } else if (right.startsWith(QLatin1String("Restyle"))) {
+ sendWindow_restyle = 1;
+ } else if (right.startsWith(QLatin1String("Shade"))) {
+ sendWindow_shade = 1;
+ } else if (right.startsWith(QLatin1String("Unshade"))) {
+ sendWindow_unshade = 1;
+ } else if (right.startsWith(QLatin1String("DesktopCreate"))) {
+ // ignore this one
+ } else if (right.startsWith(QLatin1String("DesktopDestroy"))) {
+ // ignore this one
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag;
+ }
+ }
+ break;
+ }
+ case 'f': {
+ sendFocus = 1;
+ break;
+ }
+ case 'd': { // document is not implemented
+ break;
+ }
+ case 't': { // terminal is not implemented
+ break;
+ }
+ case 'm': { // mouse* is handled in a different way by the gnome atspi stack
+ break;
+ }
+ default:
+ qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag;
+ }
+}
+
+/*!
+ Checks via dbus which events should be sent.
+ */
+void AtSpiAdaptor::updateEventListeners()
+{
+ QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
+ QLatin1String("/org/a11y/atspi/registry"),
+ QLatin1String("org.a11y.atspi.Registry"), QLatin1String("GetRegisteredEvents"));
+ QDBusReply<QSpiEventListenerArray> listenersReply = m_dbus->connection().call(m);
+ if (listenersReply.isValid()) {
+ const QSpiEventListenerArray evList = listenersReply.value();
+ for (const QSpiEventListener &ev : evList)
+ setBitFlag(ev.eventName);
+ m_applicationAdaptor->sendEvents(!evList.isEmpty());
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "Could not query active accessibility event listeners.";
+ }
+}
+
+void AtSpiAdaptor::eventListenerDeregistered(const QString &/*bus*/, const QString &/*path*/)
+{
+// qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::eventListenerDeregistered: " << bus << path;
+ updateEventListeners();
+}
+
+void AtSpiAdaptor::eventListenerRegistered(const QString &/*bus*/, const QString &/*path*/)
+{
+// qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::eventListenerRegistered: " << bus << path;
+ updateEventListeners();
+}
+
+/*!
+ This slot needs to get called when a \a window has be activated or deactivated (become focused).
+ When \a active is true, the window just received focus, otherwise it lost the focus.
+ */
+void AtSpiAdaptor::windowActivated(QObject* window, bool active)
+{
+ if (!(sendWindow || sendWindow_activate))
+ return;
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
+ Q_ASSERT(iface);
+ Q_ASSERT(!active || iface->isValid());
+
+ QString windowTitle;
+ // in dtor it may be invalid
+ if (iface->isValid())
+ windowTitle = iface->text(QAccessible::Name);
+
+ QDBusVariant data;
+ data.setVariant(windowTitle);
+
+ QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
+
+ QString status = active ? QLatin1String("Activate") : QLatin1String("Deactivate");
+ QString path = pathForObject(window);
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW), status, args);
+
+ QVariantList stateArgs = packDBusSignalArguments(QLatin1String("active"), active ? 1 : 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("StateChanged"), stateArgs);
+}
+
+QVariantList AtSpiAdaptor::packDBusSignalArguments(const QString &type, int data1, int data2, const QVariant &variantData) const
+{
+ QVariantList arguments;
+ arguments << type << data1 << data2 << variantData
+ << QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT)));
+ return arguments;
+}
+
+QVariant AtSpiAdaptor::variantForPath(const QString &path) const
+{
+ QDBusVariant data;
+ data.setVariant(QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(path))));
+ return QVariant::fromValue(data);
+}
+
+bool AtSpiAdaptor::sendDBusSignal(const QString &path, const QString &interface, const QString &signalName, const QVariantList &arguments) const
+{
+ QDBusMessage message = QDBusMessage::createSignal(path, interface, signalName);
+ message.setArguments(arguments);
+ return m_dbus->connection().send(message);
+}
+
+QAccessibleInterface *AtSpiAdaptor::interfaceFromPath(const QString& dbusPath) const
+{
+ if (dbusPath == QLatin1String(QSPI_OBJECT_PATH_ROOT))
+ return QAccessible::queryAccessibleInterface(qApp);
+
+ QStringList parts = dbusPath.split(QLatin1Char('/'));
+ if (parts.size() != 6) {
+ qCDebug(lcAccessibilityAtspi) << "invalid path: " << dbusPath;
+ return 0;
+ }
+
+ QString objectString = parts.at(5);
+ QAccessible::Id id = objectString.toUInt();
+
+ // The id is always in the range [INT_MAX+1, UINT_MAX]
+ if ((int)id >= 0)
+ qCWarning(lcAccessibilityAtspi) << "No accessible object found for id: " << id;
+
+ return QAccessible::accessibleInterface(id);
+}
+
+void AtSpiAdaptor::notifyStateChange(QAccessibleInterface *interface, const QString &state, int value)
+{
+ QString path = pathForInterface(interface);
+ QVariantList stateArgs = packDBusSignalArguments(state, value, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("StateChanged"), stateArgs);
+}
+
+
+/*!
+ This function gets called when Qt notifies about accessibility updates.
+*/
+void AtSpiAdaptor::notify(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::ObjectCreated:
+ if (sendObject || sendObject_children_changed)
+ notifyAboutCreation(event->accessibleInterface());
+ break;
+ case QAccessible::ObjectShow: {
+ if (sendObject || sendObject_state_changed) {
+ notifyStateChange(event->accessibleInterface(), QLatin1String("showing"), 1);
+ }
+ break;
+ }
+ case QAccessible::ObjectHide: {
+ if (sendObject || sendObject_state_changed) {
+ notifyStateChange(event->accessibleInterface(), QLatin1String("showing"), 0);
+ }
+ break;
+ }
+ case QAccessible::ObjectDestroyed: {
+ if (sendObject || sendObject_state_changed)
+ notifyAboutDestruction(event->accessibleInterface());
+ break;
+ }
+ case QAccessible::ObjectReorder: {
+ if (sendObject || sendObject_children_changed)
+ childrenChanged(event->accessibleInterface());
+ break;
+ }
+ case QAccessible::NameChanged: {
+ if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
+ QString path = pathForInterface(event->accessibleInterface());
+ QVariantList args = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("PropertyChange"), args);
+ }
+ break;
+ }
+ case QAccessible::DescriptionChanged: {
+ if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
+ QString path = pathForInterface(event->accessibleInterface());
+ QVariantList args = packDBusSignalArguments(QLatin1String("accessible-description"), 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("PropertyChange"), args);
+ }
+ break;
+ }
+ case QAccessible::Focus: {
+ if (sendFocus || sendObject || sendObject_state_changed)
+ sendFocusChanged(event->accessibleInterface());
+ break;
+ }
+ case QAccessible::TextInserted:
+ case QAccessible::TextRemoved:
+ case QAccessible::TextUpdated: {
+ if (sendObject || sendObject_text_changed) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface || !iface->textInterface()) {
+ qCDebug(lcAccessibilityAtspi) << "Received text event for invalid interface.";
+ return;
+ }
+ QString path = pathForInterface(iface);
+
+ int changePosition = 0;
+ int cursorPosition = 0;
+ QString textRemoved;
+ QString textInserted;
+
+ if (event->type() == QAccessible::TextInserted) {
+ QAccessibleTextInsertEvent *textEvent = static_cast<QAccessibleTextInsertEvent*>(event);
+ textInserted = textEvent->textInserted();
+ changePosition = textEvent->changePosition();
+ cursorPosition = textEvent->cursorPosition();
+ } else if (event->type() == QAccessible::TextRemoved) {
+ QAccessibleTextRemoveEvent *textEvent = static_cast<QAccessibleTextRemoveEvent*>(event);
+ textRemoved = textEvent->textRemoved();
+ changePosition = textEvent->changePosition();
+ cursorPosition = textEvent->cursorPosition();
+ } else if (event->type() == QAccessible::TextUpdated) {
+ QAccessibleTextUpdateEvent *textEvent = static_cast<QAccessibleTextUpdateEvent*>(event);
+ textInserted = textEvent->textInserted();
+ textRemoved = textEvent->textRemoved();
+ changePosition = textEvent->changePosition();
+ cursorPosition = textEvent->cursorPosition();
+ }
+
+ QDBusVariant data;
+
+ if (!textRemoved.isEmpty()) {
+ data.setVariant(QVariant::fromValue(textRemoved));
+ QVariantList args = packDBusSignalArguments(QLatin1String("delete"), changePosition, textRemoved.length(), QVariant::fromValue(data));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("TextChanged"), args);
+ }
+
+ if (!textInserted.isEmpty()) {
+ data.setVariant(QVariant::fromValue(textInserted));
+ QVariantList args = packDBusSignalArguments(QLatin1String("insert"), changePosition, textInserted.length(), QVariant::fromValue(data));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("TextChanged"), args);
+ }
+
+ // send a cursor update
+ Q_UNUSED(cursorPosition)
+// QDBusVariant cursorData;
+// cursorData.setVariant(QVariant::fromValue(cursorPosition));
+// QVariantList args = packDBusSignalArguments(QString(), cursorPosition, 0, QVariant::fromValue(cursorData));
+// sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+// QLatin1String("TextCaretMoved"), args);
+ }
+ break;
+ }
+ case QAccessible::TextCaretMoved: {
+ if (sendObject || sendObject_text_caret_moved) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface || !iface->textInterface()) {
+ qCWarning(lcAccessibilityAtspi) << "Sending TextCaretMoved from object that does not implement text interface: " << iface;
+ return;
+ }
+
+ QString path = pathForInterface(iface);
+ QDBusVariant cursorData;
+ int pos = iface->textInterface()->cursorPosition();
+ cursorData.setVariant(QVariant::fromValue(pos));
+ QVariantList args = packDBusSignalArguments(QString(), pos, 0, QVariant::fromValue(cursorData));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("TextCaretMoved"), args);
+ }
+ break;
+ }
+ case QAccessible::TextSelectionChanged: {
+ if (sendObject || sendObject_text_selection_changed) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ QString path = pathForInterface(iface);
+ QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("TextSelectionChanged"), args);
+ }
+ break;
+ }
+ case QAccessible::ValueChanged: {
+ if (sendObject || sendObject_value_changed || sendObject_property_change_accessible_value) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface) {
+ qCWarning(lcAccessibilityAtspi) << "ValueChanged event from invalid accessible.";
+ return;
+ }
+ if (iface->valueInterface()) {
+ QString path = pathForInterface(iface);
+ QVariantList args = packDBusSignalArguments(QLatin1String("accessible-value"), 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("PropertyChange"), args);
+ } else if (iface->role() == QAccessible::ComboBox) {
+ // Combo Box with AT-SPI likes to be special
+ // It requires a name-change to update caches and then selection-changed
+ QString path = pathForInterface(iface);
+ QVariantList args1 = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("PropertyChange"), args1);
+ QVariantList args2 = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(0))));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("SelectionChanged"), args2);
+ } else {
+ qCWarning(lcAccessibilityAtspi) << "ValueChanged event and no ValueInterface or ComboBox: " << iface;
+ }
+ }
+ break;
+ }
+ case QAccessible::SelectionAdd:
+ case QAccessible::SelectionRemove:
+ case QAccessible::Selection: {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface) {
+ qCWarning(lcAccessibilityAtspi) << "Selection event from invalid accessible.";
+ return;
+ }
+ QString path = pathForInterface(iface);
+ int selected = iface->state().selected ? 1 : 0;
+ QVariantList stateArgs = packDBusSignalArguments(QLatin1String("selected"), selected, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("StateChanged"), stateArgs);
+ break;
+ }
+
+ case QAccessible::StateChanged: {
+ if (sendObject || sendObject_state_changed || sendWindow || sendWindow_activate) {
+ QAccessible::State stateChange = static_cast<QAccessibleStateChangeEvent*>(event)->changedStates();
+ if (stateChange.checked) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface) {
+ qCWarning(lcAccessibilityAtspi) << "StateChanged event from invalid accessible.";
+ return;
+ }
+ int checked = iface->state().checked;
+ notifyStateChange(iface, QLatin1String("checked"), checked);
+ } else if (stateChange.active) {
+ QAccessibleInterface * iface = event->accessibleInterface();
+ if (!iface || !(iface->role() == QAccessible::Window && (sendWindow || sendWindow_activate)))
+ return;
+ int isActive = iface->state().active;
+ QString windowTitle = iface->text(QAccessible::Name);
+ QDBusVariant data;
+ data.setVariant(windowTitle);
+ QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
+ QString status = isActive ? QLatin1String("Activate") : QLatin1String("Deactivate");
+ QString path = pathForInterface(iface);
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW), status, args);
+ notifyStateChange(iface, QLatin1String("active"), isActive);
+ } else if (stateChange.disabled) {
+ QAccessibleInterface *iface = event->accessibleInterface();
+ QAccessible::State state = iface->state();
+ bool enabled = !state.disabled;
+
+ notifyStateChange(iface, QLatin1String("enabled"), enabled);
+ notifyStateChange(iface, QLatin1String("sensitive"), enabled);
+ }
+ }
+ break;
+ }
+ // For now we ignore these events
+ case QAccessible::TableModelChanged:
+ // For tables, setting manages_descendants should
+ // indicate to the client that it cannot cache these
+ // interfaces.
+ case QAccessible::ParentChanged:
+ case QAccessible::DialogStart:
+ case QAccessible::DialogEnd:
+ case QAccessible::PopupMenuStart:
+ case QAccessible::PopupMenuEnd:
+ case QAccessible::SoundPlayed:
+ case QAccessible::Alert:
+ case QAccessible::ForegroundChanged:
+ case QAccessible::MenuStart:
+ case QAccessible::MenuEnd:
+ case QAccessible::ContextHelpStart:
+ case QAccessible::ContextHelpEnd:
+ case QAccessible::DragDropStart:
+ case QAccessible::DragDropEnd:
+ case QAccessible::ScrollingStart:
+ case QAccessible::ScrollingEnd:
+ case QAccessible::MenuCommand:
+ case QAccessible::ActionChanged:
+ case QAccessible::ActiveDescendantChanged:
+ case QAccessible::AttributeChanged:
+ case QAccessible::DocumentContentChanged:
+ case QAccessible::DocumentLoadComplete:
+ case QAccessible::DocumentLoadStopped:
+ case QAccessible::DocumentReload:
+ case QAccessible::HyperlinkEndIndexChanged:
+ case QAccessible::HyperlinkNumberOfAnchorsChanged:
+ case QAccessible::HyperlinkSelectedLinkChanged:
+ case QAccessible::HypertextLinkActivated:
+ case QAccessible::HypertextLinkSelected:
+ case QAccessible::HyperlinkStartIndexChanged:
+ case QAccessible::HypertextChanged:
+ case QAccessible::HypertextNLinksChanged:
+ case QAccessible::ObjectAttributeChanged:
+ case QAccessible::PageChanged:
+ case QAccessible::SectionChanged:
+ case QAccessible::TableCaptionChanged:
+ case QAccessible::TableColumnDescriptionChanged:
+ case QAccessible::TableColumnHeaderChanged:
+ case QAccessible::TableRowDescriptionChanged:
+ case QAccessible::TableRowHeaderChanged:
+ case QAccessible::TableSummaryChanged:
+ case QAccessible::TextAttributeChanged:
+ case QAccessible::TextColumnChanged:
+ case QAccessible::VisibleDataChanged:
+ case QAccessible::SelectionWithin:
+ case QAccessible::LocationChanged:
+ case QAccessible::HelpChanged:
+ case QAccessible::DefaultActionChanged:
+ case QAccessible::AcceleratorChanged:
+ case QAccessible::InvalidEvent:
+ break;
+ }
+}
+
+void AtSpiAdaptor::sendFocusChanged(QAccessibleInterface *interface) const
+{
+ static QString lastFocusPath;
+ // "remove" old focus
+ if (!lastFocusPath.isEmpty()) {
+ QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 0, 0, variantForPath(lastFocusPath));
+ sendDBusSignal(lastFocusPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("StateChanged"), stateArgs);
+ }
+ // send new focus
+ {
+ QString path = pathForInterface(interface);
+
+ QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 1, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
+ QLatin1String("StateChanged"), stateArgs);
+
+ QVariantList focusArgs = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
+ sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_FOCUS),
+ QLatin1String("Focus"), focusArgs);
+ lastFocusPath = path;
+ }
+}
+
+void AtSpiAdaptor::childrenChanged(QAccessibleInterface *interface) const
+{
+ QString parentPath = pathForInterface(interface);
+ int childCount = interface->childCount();
+ for (int i = 0; i < interface->childCount(); ++i) {
+ QString childPath = pathForInterface(interface->child(i));
+ QVariantList args = packDBusSignalArguments(QLatin1String("add"), childCount, 0, childPath);
+ sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("ChildrenChanged"), args);
+ }
+}
+
+void AtSpiAdaptor::notifyAboutCreation(QAccessibleInterface *interface) const
+{
+// // say hello to d-bus
+// cache->emitAddAccessible(accessible->getCacheItem());
+
+ // notify about the new child of our parent
+ QAccessibleInterface * parent = interface->parent();
+ if (!parent) {
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::notifyAboutCreation: Could not find parent for " << interface->object();
+ return;
+ }
+ QString path = pathForInterface(interface);
+ int childCount = parent->childCount();
+ QString parentPath = pathForInterface(parent);
+ QVariantList args = packDBusSignalArguments(QLatin1String("add"), childCount, 0, variantForPath(path));
+ sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("ChildrenChanged"), args);
+}
+
+void AtSpiAdaptor::notifyAboutDestruction(QAccessibleInterface *interface) const
+{
+ if (!interface || !interface->isValid())
+ return;
+
+ QAccessibleInterface * parent = interface->parent();
+ if (!parent) {
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::notifyAboutDestruction: Could not find parent for " << interface->object();
+ return;
+ }
+ QString path = pathForInterface(interface);
+
+ // this is in the destructor. we have no clue which child we used to be.
+ // FIXME
+ int childIndex = -1;
+ // if (child) {
+ // childIndex = child;
+ // } else {
+ // childIndex = parent->indexOfChild(interface);
+ // }
+
+ QString parentPath = pathForInterface(parent);
+ QVariantList args = packDBusSignalArguments(QLatin1String("remove"), childIndex, 0, variantForPath(path));
+ sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("ChildrenChanged"), args);
+}
+
+/*!
+ Handle incoming DBus message.
+ This function dispatches the dbus message to the right interface handler.
+ */
+bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnection &connection)
+{
+ // get accessible interface
+ QAccessibleInterface * accessible = interfaceFromPath(message.path());
+ if (!accessible) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << message.path();
+ return false;
+ }
+ if (!accessible->isValid()) {
+ qCWarning(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Accessible invalid: " << accessible << message.path();
+ return false;
+ }
+
+ QString interface = message.interface();
+ QString function = message.member();
+
+ // qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::handleMessage: " << interface << function;
+
+ if (function == QLatin1String("Introspect")) {
+ //introspect(message.path());
+ return false;
+ }
+
+ // handle properties like regular functions
+ if (interface == QLatin1String("org.freedesktop.DBus.Properties")) {
+ interface = message.arguments().at(0).toString();
+ // Get/Set + Name
+ function = message.member() + message.arguments().at(1).toString();
+ }
+
+ // switch interface to call
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE))
+ return accessibleInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION))
+ return applicationInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT))
+ return componentInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_ACTION))
+ return actionInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_TEXT))
+ return textInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT))
+ return editableTextInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_VALUE))
+ return valueInterface(accessible, function, message, connection);
+ if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_TABLE))
+ return tableInterface(accessible, function, message, connection);
+
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::handleMessage with unknown interface: " << message.path() << interface << function;
+ return false;
+}
+
+// Application
+bool AtSpiAdaptor::applicationInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (message.path() != QLatin1String(ATSPI_DBUS_PATH_ROOT)) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find application interface for: " << message.path() << interface;
+ return false;
+ }
+
+ if (function == QLatin1String("SetId")) {
+ Q_ASSERT(message.signature() == QLatin1String("ssv"));
+ QVariant value = qvariant_cast<QDBusVariant>(message.arguments().at(2)).variant();
+
+ m_applicationId = value.toInt();
+ return true;
+ }
+ if (function == QLatin1String("GetId")) {
+ Q_ASSERT(message.signature() == QLatin1String("ss"));
+ QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(m_applicationId)));
+ return connection.send(reply);
+ }
+ if (function == QLatin1String("GetToolkitName")) {
+ Q_ASSERT(message.signature() == QLatin1String("ss"));
+ QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QLatin1String("Qt"))));
+ return connection.send(reply);
+ }
+ if (function == QLatin1String("GetVersion")) {
+ Q_ASSERT(message.signature() == QLatin1String("ss"));
+ QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QLatin1String(qVersion()))));
+ return connection.send(reply);
+ }
+ if (function == QLatin1String("GetLocale")) {
+ Q_ASSERT(message.signature() == QLatin1String("u"));
+ QDBusMessage reply = message.createReply(QVariant::fromValue(QLocale().name()));
+ return connection.send(reply);
+ }
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::applicationInterface " << message.path() << interface << function;
+ return false;
+}
+
+/*!
+ Register this application as accessible on the accessibility DBus.
+ */
+void AtSpiAdaptor::registerApplication()
+{
+ OrgA11yAtspiSocketInterface *registry;
+ registry = new OrgA11yAtspiSocketInterface(QLatin1String(QSPI_REGISTRY_NAME),
+ QLatin1String(QSPI_OBJECT_PATH_ROOT), m_dbus->connection());
+
+ QDBusPendingReply<QSpiObjectReference> reply;
+ QSpiObjectReference ref = QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT));
+ reply = registry->Embed(ref);
+ reply.waitForFinished(); // TODO: make this async
+ if (reply.isValid ()) {
+ const QSpiObjectReference &socket = reply.value();
+ accessibilityRegistry = QSpiObjectReference(socket);
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "Error in contacting registry: "
+ << reply.error().name()
+ << reply.error().message();
+ }
+ delete registry;
+}
+
+// Accessible
+bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (function == QLatin1String("GetRole")) {
+ sendReply(connection, message, (uint) getRole(interface));
+ } else if (function == QLatin1String("GetName")) {
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Name))));
+ } else if (function == QLatin1String("GetRoleName")) {
+ sendReply(connection, message, qSpiRoleMapping[interface->role()].name());
+ } else if (function == QLatin1String("GetLocalizedRoleName")) {
+ sendReply(connection, message, QVariant::fromValue(qSpiRoleMapping[interface->role()].localizedName()));
+ } else if (function == QLatin1String("GetChildCount")) {
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->childCount())));
+ } else if (function == QLatin1String("GetIndexInParent")) {
+ int childIndex = -1;
+ QAccessibleInterface * parent = interface->parent();
+ if (parent) {
+ childIndex = parent->indexOfChild(interface);
+ if (childIndex < 0) {
+ qCDebug(lcAccessibilityAtspi) << "GetIndexInParent get invalid index: " << childIndex << interface;
+ }
+ }
+ sendReply(connection, message, childIndex);
+ } else if (function == QLatin1String("GetParent")) {
+ QString path;
+ QAccessibleInterface * parent = interface->parent();
+ if (!parent) {
+ path = QLatin1String(ATSPI_DBUS_PATH_NULL);
+ } else if (parent->role() == QAccessible::Application) {
+ path = QLatin1String(ATSPI_DBUS_PATH_ROOT);
+ } else {
+ path = pathForInterface(parent);
+ }
+ // Parent is a property, so it needs to be wrapped inside an extra variant.
+ sendReply(connection, message, QVariant::fromValue(
+ QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path))))));
+ } else if (function == QLatin1String("GetChildAtIndex")) {
+ const int index = message.arguments().at(0).toInt();
+ if (index < 0) {
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
+ } else {
+ QAccessibleInterface * childInterface = interface->child(index);
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(childInterface)))));
+ }
+ } else if (function == QLatin1String("GetInterfaces")) {
+ sendReply(connection, message, accessibleInterfaces(interface));
+ } else if (function == QLatin1String("GetDescription")) {
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Description))));
+ } else if (function == QLatin1String("GetState")) {
+ quint64 spiState = spiStatesFromQState(interface->state());
+ if (interface->tableInterface()) {
+ setSpiStateBit(&spiState, ATSPI_STATE_MANAGES_DESCENDANTS);
+ }
+ QAccessible::Role role = interface->role();
+ if (role == QAccessible::TreeItem ||
+ role == QAccessible::ListItem) {
+ /* Transient means libatspi2 will not cache items.
+ This is important because when adding/removing an item
+ the cache becomes outdated and we don't change the paths of
+ items in lists/trees/tables. */
+ setSpiStateBit(&spiState, ATSPI_STATE_TRANSIENT);
+ }
+ sendReply(connection, message,
+ QVariant::fromValue(spiStateSetFromSpiStates(spiState)));
+ } else if (function == QLatin1String("GetAttributes")) {
+ sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
+ } else if (function == QLatin1String("GetRelationSet")) {
+ sendReply(connection, message, QVariant::fromValue(relationSet(interface, connection)));
+ } else if (function == QLatin1String("GetApplication")) {
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(QSPI_OBJECT_PATH_ROOT))));
+ } else if (function == QLatin1String("GetChildren")) {
+ QSpiObjectReferenceArray children;
+ const int numChildren = interface->childCount();
+ children.reserve(numChildren);
+ for (int i = 0; i < numChildren; ++i) {
+ QString childPath = pathForInterface(interface->child(i));
+ QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
+ children << ref;
+ }
+ connection.send(message.createReply(QVariant::fromValue(children)));
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::accessibleInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+AtspiRole AtSpiAdaptor::getRole(QAccessibleInterface *interface) const
+{
+ if ((interface->role() == QAccessible::EditableText) && interface->state().passwordEdit)
+ return ATSPI_ROLE_PASSWORD_TEXT;
+ return qSpiRoleMapping[interface->role()].spiRole();
+}
+
+QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface) const
+{
+ QStringList ifaces;
+ qCDebug(lcAccessibilityAtspiCreation) << "AtSpiAdaptor::accessibleInterfaces create: " << interface->object();
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE);
+
+ if ( (!interface->rect().isEmpty()) ||
+ (interface->object() && interface->object()->isWidgetType()) ||
+ (interface->role() == QAccessible::ListItem) ||
+ (interface->role() == QAccessible::Cell) ||
+ (interface->role() == QAccessible::TreeItem) ||
+ (interface->role() == QAccessible::Row) ||
+ (interface->object() && interface->object()->inherits("QSGItem"))
+ ) {
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT);
+ } else {
+ qCDebug(lcAccessibilityAtspiCreation) << " IS NOT a component";
+ }
+ if (interface->role() == QAccessible::Application)
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION);
+
+ if (interface->actionInterface() || interface->valueInterface())
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_ACTION);
+
+ if (interface->textInterface())
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_TEXT);
+
+ if (interface->editableTextInterface())
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT);
+
+ if (interface->valueInterface())
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_VALUE);
+
+ if (interface->tableInterface())
+ ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_TABLE);
+
+ return ifaces;
+}
+
+QSpiRelationArray AtSpiAdaptor::relationSet(QAccessibleInterface *interface, const QDBusConnection &connection) const
+{
+ typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
+ const QVector<RelationPair> relationInterfaces = interface->relations();
+
+ QSpiRelationArray relations;
+ for (const RelationPair &pair : relationInterfaces) {
+// FIXME: this loop seems a bit strange... "related" always have one item when we check.
+//And why is it a list, when it always have one item? And it seems to assume that the QAccessible::Relation enum maps directly to AtSpi
+ QSpiObjectReferenceArray related;
+
+ QDBusObjectPath path = QDBusObjectPath(pathForInterface(pair.first));
+ related.append(QSpiObjectReference(connection, path));
+
+ if (!related.isEmpty())
+ relations.append(QSpiRelationArrayEntry(qAccessibleRelationToAtSpiRelation(pair.second), related));
+ }
+ return relations;
+}
+
+void AtSpiAdaptor::sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const
+{
+ QDBusMessage reply = message.createReply(argument);
+ connection.send(reply);
+}
+
+
+QString AtSpiAdaptor::pathForObject(QObject *object) const
+{
+ Q_ASSERT(object);
+
+ if (inheritsQAction(object)) {
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::pathForObject: warning: creating path with QAction as object.";
+ }
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object);
+ return pathForInterface(iface);
+}
+
+QString AtSpiAdaptor::pathForInterface(QAccessibleInterface *interface) const
+{
+ if (!interface || !interface->isValid())
+ return QLatin1String(ATSPI_DBUS_PATH_NULL);
+ if (interface->role() == QAccessible::Application)
+ return QLatin1String(QSPI_OBJECT_PATH_ROOT);
+
+ QAccessible::Id id = QAccessible::uniqueId(interface);
+ Q_ASSERT((int)id < 0);
+ return QLatin1String(QSPI_OBJECT_PATH_PREFIX) + QString::number(id);
+}
+
+bool AtSpiAdaptor::inheritsQAction(QObject *object)
+{
+ const QMetaObject *mo = object->metaObject();
+ while (mo) {
+ const QLatin1String cn(mo->className());
+ if (cn == QLatin1String("QAction"))
+ return true;
+ mo = mo->superClass();
+ }
+ return false;
+}
+
+// Component
+static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
+{
+ if (interface->role() == QAccessible::Window)
+ return interface;
+
+ QAccessibleInterface * parent = interface->parent();
+ while (parent && parent->role() != QAccessible::Window)
+ parent = parent->parent();
+
+ return parent;
+}
+
+static QRect getRelativeRect(QAccessibleInterface *interface)
+{
+ QAccessibleInterface * window;
+ QRect wr, cr;
+
+ cr = interface->rect();
+
+ window = getWindow(interface);
+ if (window) {
+ wr = window->rect();
+
+ cr.setX(cr.x() - wr.x());
+ cr.setY(cr.x() - wr.y());
+ }
+ return cr;
+}
+
+bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (function == QLatin1String("Contains")) {
+ bool ret = false;
+ int x = message.arguments().at(0).toInt();
+ int y = message.arguments().at(1).toInt();
+ uint coordType = message.arguments().at(2).toUInt();
+ if (coordType == ATSPI_COORD_TYPE_SCREEN)
+ ret = interface->rect().contains(x, y);
+ else
+ ret = getRelativeRect(interface).contains(x, y);
+ sendReply(connection, message, ret);
+ } else if (function == QLatin1String("GetAccessibleAtPoint")) {
+ int x = message.arguments().at(0).toInt();
+ int y = message.arguments().at(1).toInt();
+ uint coordType = message.arguments().at(2).toUInt();
+ if (coordType == ATSPI_COORD_TYPE_WINDOW) {
+ QWindow * window = interface->window();
+ if (window) {
+ x += window->position().x();
+ y += window->position().y();
+ }
+ }
+
+ QAccessibleInterface * childInterface(interface->childAt(x, y));
+ QAccessibleInterface * iface = 0;
+ while (childInterface) {
+ iface = childInterface;
+ childInterface = iface->childAt(x, y);
+ }
+ if (iface) {
+ QString path = pathForInterface(iface);
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(path))));
+ } else {
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
+ }
+ } else if (function == QLatin1String("GetAlpha")) {
+ sendReply(connection, message, (double) 1.0);
+ } else if (function == QLatin1String("GetExtents")) {
+ uint coordType = message.arguments().at(0).toUInt();
+ sendReply(connection, message, QVariant::fromValue(getExtents(interface, coordType)));
+ } else if (function == QLatin1String("GetLayer")) {
+ sendReply(connection, message, QVariant::fromValue((uint)1));
+ } else if (function == QLatin1String("GetMDIZOrder")) {
+ sendReply(connection, message, QVariant::fromValue((short)0));
+ } else if (function == QLatin1String("GetPosition")) {
+ uint coordType = message.arguments().at(0).toUInt();
+ QRect rect;
+ if (coordType == ATSPI_COORD_TYPE_SCREEN)
+ rect = interface->rect();
+ else
+ rect = getRelativeRect(interface);
+ QVariantList pos;
+ pos << rect.x() << rect.y();
+ connection.send(message.createReply(pos));
+ } else if (function == QLatin1String("GetSize")) {
+ QRect rect = interface->rect();
+ QVariantList size;
+ size << rect.width() << rect.height();
+ connection.send(message.createReply(size));
+ } else if (function == QLatin1String("GrabFocus")) {
+ QAccessibleActionInterface *actionIface = interface->actionInterface();
+ if (actionIface && actionIface->actionNames().contains(QAccessibleActionInterface::setFocusAction())) {
+ actionIface->doAction(QAccessibleActionInterface::setFocusAction());
+ sendReply(connection, message, true);
+ } else {
+ sendReply(connection, message, false);
+ }
+ } else if (function == QLatin1String("SetExtents")) {
+// int x = message.arguments().at(0).toInt();
+// int y = message.arguments().at(1).toInt();
+// int width = message.arguments().at(2).toInt();
+// int height = message.arguments().at(3).toInt();
+// uint coordinateType = message.arguments().at(4).toUInt();
+ qCDebug(lcAccessibilityAtspi) << "SetExtents is not implemented.";
+ sendReply(connection, message, false);
+ } else if (function == QLatin1String("SetPosition")) {
+// int x = message.arguments().at(0).toInt();
+// int y = message.arguments().at(1).toInt();
+// uint coordinateType = message.arguments().at(2).toUInt();
+ qCDebug(lcAccessibilityAtspi) << "SetPosition is not implemented.";
+ sendReply(connection, message, false);
+ } else if (function == QLatin1String("SetSize")) {
+// int width = message.arguments().at(0).toInt();
+// int height = message.arguments().at(1).toInt();
+ qCDebug(lcAccessibilityAtspi) << "SetSize is not implemented.";
+ sendReply(connection, message, false);
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::componentInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType)
+{
+ return (coordType == ATSPI_COORD_TYPE_SCREEN) ? interface->rect() : getRelativeRect(interface);
+}
+
+// Action interface
+bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (function == QLatin1String("GetNActions")) {
+ int count = QAccessibleBridgeUtils::effectiveActionNames(interface).count();
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(count))));
+ } else if (function == QLatin1String("DoAction")) {
+ int index = message.arguments().at(0).toInt();
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
+ return false;
+ const QString actionName = actionNames.at(index);
+ bool success = QAccessibleBridgeUtils::performEffectiveAction(interface, actionName);
+ sendReply(connection, message, success);
+ } else if (function == QLatin1String("GetActions")) {
+ sendReply(connection, message, QVariant::fromValue(getActions(interface)));
+ } else if (function == QLatin1String("GetName")) {
+ int index = message.arguments().at(0).toInt();
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
+ return false;
+ sendReply(connection, message, actionNames.at(index));
+ } else if (function == QLatin1String("GetDescription")) {
+ int index = message.arguments().at(0).toInt();
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
+ return false;
+ QString description;
+ if (QAccessibleActionInterface *actionIface = interface->actionInterface())
+ description = actionIface->localizedActionDescription(actionNames.at(index));
+ else
+ description = qAccessibleLocalizedActionDescription(actionNames.at(index));
+ sendReply(connection, message, description);
+ } else if (function == QLatin1String("GetKeyBinding")) {
+ int index = message.arguments().at(0).toInt();
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
+ return false;
+ QStringList keyBindings;
+ if (QAccessibleActionInterface *actionIface = interface->actionInterface())
+ keyBindings = actionIface->keyBindingsForAction(actionNames.at(index));
+ if (keyBindings.isEmpty()) {
+ QString acc = interface->text(QAccessible::Accelerator);
+ if (!acc.isEmpty())
+ keyBindings.append(acc);
+ }
+ if (keyBindings.length() > 0)
+ sendReply(connection, message, keyBindings.join(QLatin1Char(';')));
+ else
+ sendReply(connection, message, QString());
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::actionInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+QSpiActionArray AtSpiAdaptor::getActions(QAccessibleInterface *interface) const
+{
+ QAccessibleActionInterface *actionInterface = interface->actionInterface();
+ QSpiActionArray actions;
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ actions.reserve(actionNames.size());
+ for (const QString &actionName : actionNames) {
+ QSpiAction action;
+
+ action.name = actionName;
+ if (actionInterface) {
+ action.description = actionInterface->localizedActionDescription(actionName);
+ const QStringList keyBindings = actionInterface->keyBindingsForAction(actionName);
+ if (!keyBindings.isEmpty())
+ action.keyBinding = keyBindings.front();
+ } else {
+ action.description = qAccessibleLocalizedActionDescription(actionName);
+ }
+
+ actions.append(std::move(action));
+ }
+ return actions;
+}
+
+// Text interface
+bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (!interface->textInterface())
+ return false;
+
+ // properties
+ if (function == QLatin1String("GetCaretOffset")) {
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->cursorPosition()))));
+ } else if (function == QLatin1String("GetCharacterCount")) {
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->characterCount()))));
+
+ // functions
+ } else if (function == QLatin1String("AddSelection")) {
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ int lastSelection = interface->textInterface()->selectionCount();
+ interface->textInterface()->setSelection(lastSelection, startOffset, endOffset);
+ sendReply(connection, message, (interface->textInterface()->selectionCount() > lastSelection));
+ } else if (function == QLatin1String("GetAttributeRun")) {
+ int offset = message.arguments().at(0).toInt();
+ bool includeDefaults = message.arguments().at(1).toBool();
+ Q_UNUSED(includeDefaults)
+ connection.send(message.createReply(getAttributes(interface, offset, includeDefaults)));
+ } else if (function == QLatin1String("GetAttributeValue")) {
+ int offset = message.arguments().at(0).toInt();
+ QString attributeName = message.arguments().at(1).toString();
+ connection.send(message.createReply(getAttributeValue(interface, offset, attributeName)));
+ } else if (function == QLatin1String("GetAttributes")) {
+ int offset = message.arguments().at(0).toInt();
+ connection.send(message.createReply(getAttributes(interface, offset, true)));
+ } else if (function == QLatin1String("GetBoundedRanges")) {
+ int x = message.arguments().at(0).toInt();
+ int y = message.arguments().at(1).toInt();
+ int width = message.arguments().at(2).toInt();
+ int height = message.arguments().at(3).toInt();
+ uint coordType = message.arguments().at(4).toUInt();
+ uint xClipType = message.arguments().at(5).toUInt();
+ uint yClipType = message.arguments().at(6).toUInt();
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(width);
+ Q_UNUSED(height);
+ Q_UNUSED(coordType);
+ Q_UNUSED(xClipType);
+ Q_UNUSED(yClipType);
+ qCDebug(lcAccessibilityAtspi) << "Not implemented: QSpiAdaptor::GetBoundedRanges";
+ sendReply(connection, message, QVariant::fromValue(QSpiTextRangeList()));
+ } else if (function == QLatin1String("GetCharacterAtOffset")) {
+ int offset = message.arguments().at(0).toInt();
+ int start;
+ int end;
+ QString result = interface->textInterface()->textAtOffset(offset, QAccessible::CharBoundary, &start, &end);
+ sendReply(connection, message, (int) *(qPrintable (result)));
+ } else if (function == QLatin1String("GetCharacterExtents")) {
+ int offset = message.arguments().at(0).toInt();
+ int coordType = message.arguments().at(1).toUInt();
+ connection.send(message.createReply(getCharacterExtents(interface, offset, coordType)));
+ } else if (function == QLatin1String("GetDefaultAttributeSet") || function == QLatin1String("GetDefaultAttributes")) {
+ // GetDefaultAttributes is deprecated in favour of GetDefaultAttributeSet.
+ // Empty set seems reasonable. There is no default attribute set.
+ sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
+ } else if (function == QLatin1String("GetNSelections")) {
+ sendReply(connection, message, interface->textInterface()->selectionCount());
+ } else if (function == QLatin1String("GetOffsetAtPoint")) {
+ qCDebug(lcAccessibilityAtspi) << message.signature();
+ Q_ASSERT(!message.signature().isEmpty());
+ QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
+ uint coordType = message.arguments().at(2).toUInt();
+ if (coordType == ATSPI_COORD_TYPE_WINDOW) {
+ QWindow *win = interface->window();
+ point -= QPoint(win->x(), win->y());
+ }
+ int offset = interface->textInterface()->offsetAtPoint(point);
+ sendReply(connection, message, offset);
+ } else if (function == QLatin1String("GetRangeExtents")) {
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ uint coordType = message.arguments().at(2).toUInt();
+ connection.send(message.createReply(getRangeExtents(interface, startOffset, endOffset, coordType)));
+ } else if (function == QLatin1String("GetSelection")) {
+ int selectionNum = message.arguments().at(0).toInt();
+ int start, end;
+ interface->textInterface()->selection(selectionNum, &start, &end);
+ if (start < 0)
+ start = end = interface->textInterface()->cursorPosition();
+ QVariantList sel;
+ sel << start << end;
+ connection.send(message.createReply(sel));
+ } else if (function == QLatin1String("GetText")) {
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ if (endOffset == -1) // AT-SPI uses -1 to signal all characters
+ endOffset = interface->textInterface()->characterCount();
+ sendReply(connection, message, interface->textInterface()->text(startOffset, endOffset));
+ } else if (function == QLatin1String("GetTextAfterOffset")) {
+ int offset = message.arguments().at(0).toInt();
+ int type = message.arguments().at(1).toUInt();
+ int startOffset, endOffset;
+ QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
+ QVariantList ret;
+ ret << text << startOffset << endOffset;
+ connection.send(message.createReply(ret));
+ } else if (function == QLatin1String("GetTextAtOffset")) {
+ int offset = message.arguments().at(0).toInt();
+ int type = message.arguments().at(1).toUInt();
+ int startOffset, endOffset;
+ QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
+ QVariantList ret;
+ ret << text << startOffset << endOffset;
+ connection.send(message.createReply(ret));
+ } else if (function == QLatin1String("GetTextBeforeOffset")) {
+ int offset = message.arguments().at(0).toInt();
+ int type = message.arguments().at(1).toUInt();
+ int startOffset, endOffset;
+ QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
+ QVariantList ret;
+ ret << text << startOffset << endOffset;
+ connection.send(message.createReply(ret));
+ } else if (function == QLatin1String("RemoveSelection")) {
+ int selectionNum = message.arguments().at(0).toInt();
+ interface->textInterface()->removeSelection(selectionNum);
+ sendReply(connection, message, true);
+ } else if (function == QLatin1String("SetCaretOffset")) {
+ int offset = message.arguments().at(0).toInt();
+ interface->textInterface()->setCursorPosition(offset);
+ sendReply(connection, message, true);
+ } else if (function == QLatin1String("SetSelection")) {
+ int selectionNum = message.arguments().at(0).toInt();
+ int startOffset = message.arguments().at(1).toInt();
+ int endOffset = message.arguments().at(2).toInt();
+ interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
+ sendReply(connection, message, true);
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::textInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTextBoundaryType) const
+{
+ switch (atspiTextBoundaryType) {
+ case ATSPI_TEXT_BOUNDARY_CHAR:
+ return QAccessible::CharBoundary;
+ case ATSPI_TEXT_BOUNDARY_WORD_START:
+ case ATSPI_TEXT_BOUNDARY_WORD_END:
+ return QAccessible::WordBoundary;
+ case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
+ case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
+ return QAccessible::SentenceBoundary;
+ case ATSPI_TEXT_BOUNDARY_LINE_START:
+ case ATSPI_TEXT_BOUNDARY_LINE_END:
+ return QAccessible::LineBoundary;
+ }
+ Q_ASSERT_X(0, "", "Requested invalid boundary type.");
+ return QAccessible::CharBoundary;
+}
+
+namespace
+{
+ struct AtSpiAttribute {
+ QString name;
+ QString value;
+ AtSpiAttribute(const QString &aName, const QString &aValue) : name(aName), value(aValue) {}
+ bool isNull() const { return name.isNull() || value.isNull(); }
+ };
+
+ QString atspiColor(const QString &ia2Color)
+ {
+ // "rgb(%u,%u,%u)" -> "%u,%u,%u"
+ return ia2Color.mid(4, ia2Color.length() - (4+1));
+ }
+
+ QString atspiSize(const QString &ia2Size)
+ {
+ // "%fpt" -> "%f"
+ return ia2Size.left(ia2Size.length() - 2);
+ }
+
+ AtSpiAttribute atspiTextAttribute(const QString &ia2Name, const QString &ia2Value)
+ {
+ QString name = ia2Name;
+ QString value = ia2Value;
+
+ // IAccessible2: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes
+ // ATK attribute names: https://git.gnome.org/browse/orca/tree/src/orca/text_attribute_names.py
+ // ATK attribute values: https://developer.gnome.org/atk/unstable/AtkText.html#AtkTextAttribute
+
+ // https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes"
+ // specifically for "weight", "invalid", "language" and value range for colors
+
+ if (ia2Name == QLatin1String("background-color")) {
+ name = QStringLiteral("bg-color");
+ value = atspiColor(value);
+ } else if (ia2Name == QLatin1String("font-family")) {
+ name = QStringLiteral("family-name");
+ } else if (ia2Name == QLatin1String("color")) {
+ name = QStringLiteral("fg-color");
+ value = atspiColor(value);
+ } else if (ia2Name == QLatin1String("text-align")) {
+ name = QStringLiteral("justification");
+ if (value == QLatin1String("justify")) {
+ value = QStringLiteral("fill");
+ } else {
+ if (value != QLatin1String("left") &&
+ value != QLatin1String("right") &&
+ value != QLatin1String("center")
+ ) {
+ value = QString();
+ qCDebug(lcAccessibilityAtspi) << "Unknown text-align attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ }
+ } else if (ia2Name == QLatin1String("font-size")) {
+ name = QStringLiteral("size");
+ value = atspiSize(value);
+ } else if (ia2Name == QLatin1String("font-style")) {
+ name = QStringLiteral("style");
+ if (value != QLatin1String("normal") &&
+ value != QLatin1String("italic") &&
+ value != QLatin1String("oblique")
+ ) {
+ value = QString();
+ qCDebug(lcAccessibilityAtspi) << "Unknown font-style attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QLatin1String("text-underline-type")) {
+ name = QStringLiteral("underline");
+ if (value != QLatin1String("none") &&
+ value != QLatin1String("single") &&
+ value != QLatin1String("double")
+ ) {
+ value = QString();
+ qCDebug(lcAccessibilityAtspi) << "Unknown text-underline-type attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QLatin1String("font-weight")) {
+ name = QStringLiteral("weight");
+ if (value == QLatin1String("normal"))
+ // Orca seems to accept all IAccessible2 values except for "normal"
+ // (on which it produces traceback and fails to read any following text attributes),
+ // but that is the default value, so omit it anyway
+ value = QString();
+ } else if (ia2Name == QLatin1String("text-position")) {
+ name = QStringLiteral("vertical-align");
+ if (value != QLatin1String("baseline") &&
+ value != QLatin1String("super") &&
+ value != QLatin1String("sub")
+ ) {
+ value = QString();
+ qCDebug(lcAccessibilityAtspi) << "Unknown text-position attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QLatin1String("writing-mode")) {
+ name = QStringLiteral("direction");
+ if (value == QLatin1String("lr"))
+ value = QStringLiteral("ltr");
+ else if (value == QLatin1String("rl"))
+ value = QStringLiteral("rtl");
+ else if (value == QLatin1String("tb")) {
+ // IAccessible2 docs refer to XSL, which specifies "tb" is shorthand for "tb-rl"; so at least give a hint about the horizontal direction (ATK does not support vertical direction in this attribute (yet))
+ value = QStringLiteral("rtl");
+ qCDebug(lcAccessibilityAtspi) << "writing-mode attribute value \"tb\" translated only w.r.t. horizontal direction; vertical direction ignored";
+ } else {
+ value = QString();
+ qCDebug(lcAccessibilityAtspi) << "Unknown writing-mode attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QLatin1String("language")) {
+ // OK - ATK has no docs on the format of the value, IAccessible2 has reasonable format - leave it at that now
+ } else if (ia2Name == QLatin1String("invalid")) {
+ // OK - ATK docs are vague but suggest they support the same range of values as IAccessible2
+ } else {
+ // attribute we know nothing about
+ name = QString();
+ value = QString();
+ }
+ return AtSpiAttribute(name, value);
+ }
+}
+
+// FIXME all attribute methods below should share code
+QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
+{
+ Q_UNUSED(includeDefaults);
+
+ QSpiAttributeSet set;
+ int startOffset;
+ int endOffset;
+
+ QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
+ const QStringList attributes = joined.split (QLatin1Char(';'), Qt::SkipEmptyParts, Qt::CaseSensitive);
+ for (const QString &attr : attributes) {
+ QStringList items;
+ items = attr.split(QLatin1Char(':'), Qt::SkipEmptyParts, Qt::CaseSensitive);
+ AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
+ if (!attribute.isNull())
+ set[attribute.name] = attribute.value;
+ }
+
+ QVariantList list;
+ list << QVariant::fromValue(set) << startOffset << endOffset;
+
+ return list;
+}
+
+QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, int offset, const QString &attributeName) const
+{
+ QString mapped;
+ QString joined;
+ QSpiAttributeSet map;
+ int startOffset;
+ int endOffset;
+
+ joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
+ const QStringList attributes = joined.split (QLatin1Char(';'), Qt::SkipEmptyParts, Qt::CaseSensitive);
+ for (const QString& attr : attributes) {
+ QStringList items;
+ items = attr.split(QLatin1Char(':'), Qt::SkipEmptyParts, Qt::CaseSensitive);
+ AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
+ if (!attribute.isNull())
+ map[attribute.name] = attribute.value;
+ }
+ mapped = map[attributeName];
+ const bool defined = !mapped.isEmpty();
+ QVariantList list;
+ list << mapped << startOffset << endOffset << defined;
+ return list;
+}
+
+QList<QVariant> AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const
+{
+ QRect rect = interface->textInterface()->characterRect(offset);
+
+ if (coordType == ATSPI_COORD_TYPE_WINDOW)
+ rect = translateRectToWindowCoordinates(interface, rect);
+
+ return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
+}
+
+QList<QVariant> AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface,
+ int startOffset, int endOffset, uint coordType) const
+{
+ if (endOffset == -1)
+ endOffset = interface->textInterface()->characterCount();
+
+ QAccessibleTextInterface *textInterface = interface->textInterface();
+ if (endOffset <= startOffset || !textInterface)
+ return QList<QVariant>() << -1 << -1 << 0 << 0;
+
+ QRect rect = textInterface->characterRect(startOffset);
+ for (int i=startOffset + 1; i <= endOffset; i++)
+ rect = rect | textInterface->characterRect(i);
+
+ // relative to window
+ if (coordType == ATSPI_COORD_TYPE_WINDOW)
+ rect = translateRectToWindowCoordinates(interface, rect);
+
+ return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
+}
+
+QRect AtSpiAdaptor::translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect)
+{
+ QAccessibleInterface * window = getWindow(interface);
+ if (window)
+ return rect.translated(-window->rect().x(), -window->rect().y());
+
+ return rect;
+}
+
+
+// Editable Text interface
+static QString textForRange(QAccessibleInterface *accessible, int startOffset, int endOffset)
+{
+ if (QAccessibleTextInterface *textIface = accessible->textInterface()) {
+ if (endOffset == -1)
+ endOffset = textIface->characterCount();
+ return textIface->text(startOffset, endOffset);
+ }
+ QString txt = accessible->text(QAccessible::Value);
+ if (endOffset == -1)
+ endOffset = txt.length();
+ return txt.mid(startOffset, endOffset - startOffset);
+}
+
+static void replaceTextFallback(QAccessibleInterface *accessible, long startOffset, long endOffset, const QString &txt)
+{
+ QString t = textForRange(accessible, 0, -1);
+ if (endOffset == -1)
+ endOffset = t.length();
+ if (endOffset - startOffset == 0)
+ t.insert(startOffset, txt);
+ else
+ t.replace(startOffset, endOffset - startOffset, txt);
+ accessible->setText(QAccessible::Value, t);
+}
+
+bool AtSpiAdaptor::editableTextInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (function == QLatin1String("CopyText")) {
+#ifndef QT_NO_CLIPBOARD
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ const QString t = textForRange(interface, startOffset, endOffset);
+ QGuiApplication::clipboard()->setText(t);
+#endif
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("CutText")) {
+#ifndef QT_NO_CLIPBOARD
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ const QString t = textForRange(interface, startOffset, endOffset);
+ if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
+ editableTextIface->deleteText(startOffset, endOffset);
+ else
+ replaceTextFallback(interface, startOffset, endOffset, QString());
+ QGuiApplication::clipboard()->setText(t);
+#endif
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("DeleteText")) {
+ int startOffset = message.arguments().at(0).toInt();
+ int endOffset = message.arguments().at(1).toInt();
+ if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
+ editableTextIface->deleteText(startOffset, endOffset);
+ else
+ replaceTextFallback(interface, startOffset, endOffset, QString());
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("InsertText")) {
+ int position = message.arguments().at(0).toInt();
+ QString text = message.arguments().at(1).toString();
+ int length = message.arguments().at(2).toInt();
+ text.resize(length);
+ if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
+ editableTextIface->insertText(position, text);
+ else
+ replaceTextFallback(interface, position, position, text);
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("PasteText")) {
+#ifndef QT_NO_CLIPBOARD
+ int position = message.arguments().at(0).toInt();
+ const QString txt = QGuiApplication::clipboard()->text();
+ if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
+ editableTextIface->insertText(position, txt);
+ else
+ replaceTextFallback(interface, position, position, txt);
+#endif
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("SetTextContents")) {
+ QString newContents = message.arguments().at(0).toString();
+ if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
+ editableTextIface->replaceText(0, interface->textInterface()->characterCount(), newContents);
+ else
+ replaceTextFallback(interface, 0, -1, newContents);
+ connection.send(message.createReply(true));
+ } else if (function == QLatin1String("")) {
+ connection.send(message.createReply());
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::editableTextInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+// Value interface
+bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ QAccessibleValueInterface *valueIface = interface->valueInterface();
+ if (!valueIface)
+ return false;
+
+ if (function == QLatin1String("SetCurrentValue")) {
+ QDBusVariant v = qvariant_cast<QDBusVariant>(message.arguments().at(2));
+ double value = v.variant().toDouble();
+ //Temporary fix
+ //See https://bugzilla.gnome.org/show_bug.cgi?id=652596
+ valueIface->setCurrentValue(value);
+ connection.send(message.createReply()); // FIXME is the reply needed?
+ } else {
+ QVariant value;
+ if (function == QLatin1String("GetCurrentValue"))
+ value = valueIface->currentValue();
+ else if (function == QLatin1String("GetMaximumValue"))
+ value = valueIface->maximumValue();
+ else if (function == QLatin1String("GetMinimumIncrement"))
+ value = valueIface->minimumStepSize();
+ else if (function == QLatin1String("GetMinimumValue"))
+ value = valueIface->minimumValue();
+ else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::valueInterface does not implement " << function << message.path();
+ return false;
+ }
+ if (!value.canConvert(QMetaType::Double)) {
+ qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface: Could not convert to double: " << function;
+ }
+
+ // explicitly convert to dbus-variant containing one double since atspi expects that
+ // everything else might fail to convert back on the other end
+ connection.send(message.createReply(
+ QVariant::fromValue(QDBusVariant(QVariant::fromValue(value.toDouble())))));
+ }
+ return true;
+}
+
+// Table interface
+bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
+{
+ if (!(interface->tableInterface() || interface->tableCellInterface())) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find table interface for: " << message.path() << interface;
+ return false;
+ }
+
+ if (0) {
+ // properties
+ } else if (function == QLatin1String("GetCaption")) {
+ QAccessibleInterface * captionInterface= interface->tableInterface()->caption();
+ if (captionInterface) {
+ QSpiObjectReference ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(captionInterface)));
+ sendReply(connection, message, QVariant::fromValue(ref));
+ } else {
+ sendReply(connection, message, QVariant::fromValue(
+ QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
+ }
+ } else if (function == QLatin1String("GetNColumns")) {
+ connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
+ QVariant::fromValue(interface->tableInterface()->columnCount())))));
+ } else if (function == QLatin1String("GetNRows")) {
+ connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
+ QVariant::fromValue(interface->tableInterface()->rowCount())))));
+ } else if (function == QLatin1String("GetNSelectedColumns")) {
+ connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
+ QVariant::fromValue(interface->tableInterface()->selectedColumnCount())))));
+ } else if (function == QLatin1String("GetNSelectedRows")) {
+ connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
+ QVariant::fromValue(interface->tableInterface()->selectedRowCount())))));
+ } else if (function == QLatin1String("GetSummary")) {
+ QAccessibleInterface * summary = interface->tableInterface() ? interface->tableInterface()->summary() : 0;
+ QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(summary)));
+ connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
+ } else if (function == QLatin1String("GetAccessibleAt")) {
+ int row = message.arguments().at(0).toInt();
+ int column = message.arguments().at(1).toInt();
+ if ((row < 0) ||
+ (column < 0) ||
+ (row >= interface->tableInterface()->rowCount()) ||
+ (column >= interface->tableInterface()->columnCount())) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: invalid index for tableInterface GetAccessibleAt (" << row << ", " << column << ')';
+ return false;
+ }
+
+ QSpiObjectReference ref;
+ QAccessibleInterface * cell(interface->tableInterface()->cellAt(row, column));
+ if (cell) {
+ ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell)));
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: no cell interface returned for " << interface->object() << row << column;
+ ref = QSpiObjectReference();
+ }
+ connection.send(message.createReply(QVariant::fromValue(ref)));
+
+ } else if (function == QLatin1String("GetIndexAt")) {
+ int row = message.arguments().at(0).toInt();
+ int column = message.arguments().at(1).toInt();
+ QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column);
+ if (!cell) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::GetIndexAt(" << row << ',' << column << ") did not find a cell. " << interface;
+ return false;
+ }
+ int index = interface->indexOfChild(cell);
+ qCDebug(lcAccessibilityAtspi) << "QSpiAdaptor::GetIndexAt row:" << row << " col:" << column << " logical index:" << index;
+ Q_ASSERT(index > 0);
+ connection.send(message.createReply(index));
+ } else if ((function == QLatin1String("GetColumnAtIndex")) || (function == QLatin1String("GetRowAtIndex"))) {
+ int index = message.arguments().at(0).toInt();
+ int ret = -1;
+ if (index >= 0) {
+ QAccessibleInterface * cell = interface->child(index);
+ if (cell) {
+ if (function == QLatin1String("GetColumnAtIndex")) {
+ if (cell->role() == QAccessible::ColumnHeader) {
+ ret = index;
+ } else if (cell->role() == QAccessible::RowHeader) {
+ ret = -1;
+ } else {
+ if (!cell->tableCellInterface()) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell;
+ return false;
+ }
+ ret = cell->tableCellInterface()->columnIndex();
+ }
+ } else {
+ if (cell->role() == QAccessible::ColumnHeader) {
+ ret = -1;
+ } else if (cell->role() == QAccessible::RowHeader) {
+ ret = index % interface->tableInterface()->columnCount();
+ } else {
+ if (!cell->tableCellInterface()) {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell;
+ return false;
+ }
+ ret = cell->tableCellInterface()->rowIndex();
+ }
+ }
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No cell at index: " << index << interface;
+ return false;
+ }
+ }
+ connection.send(message.createReply(ret));
+
+ } else if (function == QLatin1String("GetColumnDescription")) {
+ int column = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->columnDescription(column)));
+ } else if (function == QLatin1String("GetRowDescription")) {
+ int row = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->rowDescription(row)));
+
+
+
+ } else if (function == QLatin1String("GetRowColumnExtentsAtIndex")) {
+ int index = message.arguments().at(0).toInt();
+ bool success = false;
+
+ int row = -1;
+ int col = -1;
+ int rowExtents = -1;
+ int colExtents = -1;
+ bool isSelected = false;
+
+ int cols = interface->tableInterface()->columnCount();
+ if (cols > 0) {
+ row = index / cols;
+ col = index % cols;
+ QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, col)->tableCellInterface();
+ if (cell) {
+ row = cell->rowIndex();
+ col = cell->columnIndex();
+ rowExtents = cell->rowExtent();
+ colExtents = cell->columnExtent();
+ isSelected = cell->isSelected();
+ success = true;
+ }
+ }
+ QVariantList list;
+ list << success << row << col << rowExtents << colExtents << isSelected;
+ connection.send(message.createReply(list));
+
+ } else if (function == QLatin1String("GetColumnExtentAt")) {
+ int row = message.arguments().at(0).toInt();
+ int column = message.arguments().at(1).toInt();
+ connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->columnExtent()));
+
+ } else if (function == QLatin1String("GetRowExtentAt")) {
+ int row = message.arguments().at(0).toInt();
+ int column = message.arguments().at(1).toInt();
+ connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->rowExtent()));
+
+ } else if (function == QLatin1String("GetColumnHeader")) {
+ int column = message.arguments().at(0).toInt();
+ QSpiObjectReference ref;
+
+ QAccessibleInterface * cell(interface->tableInterface()->cellAt(0, column));
+ if (cell && cell->tableCellInterface()) {
+ QList<QAccessibleInterface*> header = cell->tableCellInterface()->columnHeaderCells();
+ if (header.size() > 0) {
+ ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
+ }
+ }
+ connection.send(message.createReply(QVariant::fromValue(ref)));
+
+ } else if (function == QLatin1String("GetRowHeader")) {
+ int row = message.arguments().at(0).toInt();
+ QSpiObjectReference ref;
+ QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, 0)->tableCellInterface();
+ if (cell) {
+ QList<QAccessibleInterface*> header = cell->rowHeaderCells();
+ if (header.size() > 0) {
+ ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
+ }
+ }
+ connection.send(message.createReply(QVariant::fromValue(ref)));
+
+ } else if (function == QLatin1String("GetSelectedColumns")) {
+ connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedColumns())));
+ } else if (function == QLatin1String("GetSelectedRows")) {
+ connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedRows())));
+ } else if (function == QLatin1String("IsColumnSelected")) {
+ int column = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->isColumnSelected(column)));
+ } else if (function == QLatin1String("IsRowSelected")) {
+ int row = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->isRowSelected(row)));
+ } else if (function == QLatin1String("IsSelected")) {
+ int row = message.arguments().at(0).toInt();
+ int column = message.arguments().at(1).toInt();
+ QAccessibleTableCellInterface* cell = interface->tableInterface()->cellAt(row, column)->tableCellInterface();
+ connection.send(message.createReply(cell->isSelected()));
+ } else if (function == QLatin1String("AddColumnSelection")) {
+ int column = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->selectColumn(column)));
+ } else if (function == QLatin1String("AddRowSelection")) {
+ int row = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->selectRow(row)));
+ } else if (function == QLatin1String("RemoveColumnSelection")) {
+ int column = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->unselectColumn(column)));
+ } else if (function == QLatin1String("RemoveRowSelection")) {
+ int row = message.arguments().at(0).toInt();
+ connection.send(message.createReply(interface->tableInterface()->unselectRow(row)));
+ } else {
+ qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::tableInterface does not implement " << function << message.path();
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/atspiadaptor_p.h b/src/gui/accessible/linux/atspiadaptor_p.h
new file mode 100644
index 0000000000..b9f4011695
--- /dev/null
+++ b/src/gui/accessible/linux/atspiadaptor_p.h
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef ATSPIADAPTOR_H
+#define ATSPIADAPTOR_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <atspi/atspi-constants.h>
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtDBus/qdbusvirtualobject.h>
+#include <QtGui/qaccessible.h>
+
+#include "dbusconnection_p.h"
+#include "qspi_struct_marshallers_p.h"
+
+QT_REQUIRE_CONFIG(accessibility);
+
+QT_BEGIN_NAMESPACE
+
+class QAccessibleInterface;
+class QSpiAccessibleInterface;
+class QSpiApplicationAdaptor;
+
+
+class AtSpiAdaptor :public QDBusVirtualObject
+{
+ Q_OBJECT
+
+public:
+ explicit AtSpiAdaptor(DBusConnection *connection, QObject *parent = nullptr);
+ ~AtSpiAdaptor();
+
+ void registerApplication();
+ QString introspect(const QString &path) const override;
+ bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) override;
+ void notify(QAccessibleEvent *event);
+
+ void init();
+ void checkInitializedAndEnabled();
+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(QAccessibleInterface *interface) const;
+ void notifyAboutCreation(QAccessibleInterface *interface) const;
+ void notifyAboutDestruction(QAccessibleInterface *interface) const;
+ void childrenChanged(QAccessibleInterface *interface) const;
+
+ // handlers for the different accessible interfaces
+ bool applicationInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool accessibleInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool actionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool textInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool editableTextInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool valueInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+ bool tableInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection);
+
+ void sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const;
+
+ QAccessibleInterface *interfaceFromPath(const QString& dbusPath) const;
+ QString pathForInterface(QAccessibleInterface *interface) const;
+ QString pathForObject(QObject *object) const;
+
+ void notifyStateChange(QAccessibleInterface *interface, const QString& state, int value);
+
+ // accessible helper functions
+ AtspiRole getRole(QAccessibleInterface *interface) const;
+ QSpiRelationArray relationSet(QAccessibleInterface *interface, const QDBusConnection &connection) const;
+ QStringList accessibleInterfaces(QAccessibleInterface *interface) const;
+
+ // component helper functions
+ static QRect getExtents(QAccessibleInterface *interface, uint coordType);
+ static QRect translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect);
+
+ // action helper functions
+ QSpiActionArray getActions(QAccessibleInterface *interface) const;
+
+ // text helper functions
+ QVariantList getAttributes(QAccessibleInterface *, int offset, bool includeDefaults) const;
+ QVariantList getAttributeValue(QAccessibleInterface *, int offset, const QString &attributeName) const;
+ QList<QVariant> getCharacterExtents(QAccessibleInterface *, int offset, uint coordType) const;
+ QList<QVariant> getRangeExtents(QAccessibleInterface *, int startOffset, int endOffset, uint coordType) const;
+ QAccessible::TextBoundaryType 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;
+
+ // 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
+
+#endif
diff --git a/src/gui/accessible/linux/dbusconnection.cpp b/src/gui/accessible/linux/dbusconnection.cpp
new file mode 100644
index 0000000000..45ddc8e496
--- /dev/null
+++ b/src/gui/accessible/linux/dbusconnection.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "dbusconnection_p.h"
+
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusServiceWatcher>
+#include <qdebug.h>
+
+#include <QDBusConnectionInterface>
+#include "bus_interface.h"
+
+#include <QtGui/qguiapplication.h>
+#include <qpa/qplatformnativeinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+/* note: do not change these to QStringLiteral;
+ we are unloaded before QtDBus is done using the strings.
+ */
+#define A11Y_SERVICE QLatin1String("org.a11y.Bus")
+#define A11Y_PATH QLatin1String("/org/a11y/bus")
+
+/*!
+ \class DBusConnection
+ \internal
+ \brief Connects to the accessibility dbus.
+
+ This is usually a different bus from the session bus.
+*/
+DBusConnection::DBusConnection(QObject *parent)
+ : QObject(parent), m_a11yConnection(QString()), m_enabled(false)
+{
+ // Start monitoring if "org.a11y.Bus" is registered as DBus service.
+ QDBusConnection c = QDBusConnection::sessionBus();
+ if (!c.isConnected()) {
+ return;
+ }
+
+ dbusWatcher = new QDBusServiceWatcher(A11Y_SERVICE, c, QDBusServiceWatcher::WatchForRegistration, this);
+ connect(dbusWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(serviceRegistered()));
+
+ // If it is registered already, setup a11y right away
+ if (c.interface()->isServiceRegistered(A11Y_SERVICE))
+ serviceRegistered();
+
+ // In addition try if there is an xatom exposing the bus address, this allows applications run as root to work
+ QString address = getAddressFromXCB();
+ if (!address.isEmpty()) {
+ m_enabled = true;
+ connectA11yBus(address);
+ }
+}
+
+QString DBusConnection::getAddressFromXCB()
+{
+ QGuiApplication *app = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
+ if (!app)
+ return QString();
+ QPlatformNativeInterface *platformNativeInterface = app->platformNativeInterface();
+ QByteArray *addressByteArray = reinterpret_cast<QByteArray*>(
+ platformNativeInterface->nativeResourceForIntegration(QByteArrayLiteral("AtspiBus")));
+ if (addressByteArray) {
+ QString address = QString::fromLatin1(*addressByteArray);
+ delete addressByteArray;
+ return address;
+ }
+ return QString();
+}
+
+// We have the a11y registry on the session bus.
+// Subscribe to updates about a11y enabled state.
+// Find out the bus address
+void DBusConnection::serviceRegistered()
+{
+ // listen to enabled changes
+ QDBusConnection c = QDBusConnection::sessionBus();
+ OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this);
+
+ //The variable was introduced because on some embedded platforms there are custom accessibility
+ //clients which don't set Status.ScreenReaderEnabled to true. The variable is also useful for
+ //debugging.
+ static const bool a11yAlwaysOn = qEnvironmentVariableIsSet("QT_LINUX_ACCESSIBILITY_ALWAYS_ON");
+
+ bool enabled = a11yAlwaysOn || a11yStatus->screenReaderEnabled() || a11yStatus->isEnabled();
+
+ if (enabled != m_enabled) {
+ m_enabled = enabled;
+ if (m_a11yConnection.isConnected()) {
+ emit enabledChanged(m_enabled);
+ } else {
+ QDBusConnection c = QDBusConnection::sessionBus();
+ QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.Bus"),
+ QLatin1String("/org/a11y/bus"),
+ QLatin1String("org.a11y.Bus"), QLatin1String("GetAddress"));
+ c.callWithCallback(m, this, SLOT(connectA11yBus(QString)), SLOT(dbusError(QDBusError)));
+ }
+ }
+
+ // connect(a11yStatus, ); QtDbus doesn't support notifications for property changes yet
+}
+
+void DBusConnection::serviceUnregistered()
+{
+ emit enabledChanged(false);
+}
+
+void DBusConnection::connectA11yBus(const QString &address)
+{
+ if (address.isEmpty()) {
+ qWarning("Could not find Accessibility DBus address.");
+ return;
+ }
+ m_a11yConnection = QDBusConnection(QDBusConnection::connectToBus(address, QLatin1String("a11y")));
+
+ if (m_enabled)
+ emit enabledChanged(true);
+}
+
+void DBusConnection::dbusError(const QDBusError &error)
+{
+ qWarning() << "Accessibility encountered a DBus error:" << error;
+}
+
+/*!
+ Returns the DBus connection that got established.
+ Or an invalid connection if not yet connected.
+*/
+QDBusConnection DBusConnection::connection() const
+{
+ return m_a11yConnection;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/accessible/linux/dbusconnection_p.h b/src/gui/accessible/linux/dbusconnection_p.h
new file mode 100644
index 0000000000..826630fddc
--- /dev/null
+++ b/src/gui/accessible/linux/dbusconnection_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DBUSCONNECTION_H
+#define DBUSCONNECTION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QString>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusVariant>
+Q_MOC_INCLUDE(<QtDBus/QDBusError>)
+
+QT_BEGIN_NAMESPACE
+
+class QDBusServiceWatcher;
+
+class DBusConnection : public QObject
+{
+ Q_OBJECT
+
+public:
+ DBusConnection(QObject *parent = nullptr);
+ QDBusConnection connection() const;
+ bool isEnabled() const { return m_enabled; }
+
+Q_SIGNALS:
+ // Emitted when the global accessibility status changes to enabled
+ void enabledChanged(bool enabled);
+
+private Q_SLOTS:
+ QString getAddressFromXCB();
+ void serviceRegistered();
+ void serviceUnregistered();
+ void connectA11yBus(const QString &address);
+
+ void dbusError(const QDBusError &error);
+
+private:
+ QString getAccessibilityBusAddress() const;
+
+ QDBusServiceWatcher *dbusWatcher;
+ QDBusConnection m_a11yConnection;
+ bool m_enabled;
+};
+
+QT_END_NAMESPACE
+
+#endif // DBUSCONNECTION_H
diff --git a/src/gui/accessible/linux/dbusxml/Bus.xml b/src/gui/accessible/linux/dbusxml/Bus.xml
new file mode 100644
index 0000000000..5a33e335a1
--- /dev/null
+++ b/src/gui/accessible/linux/dbusxml/Bus.xml
@@ -0,0 +1,17 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.a11y.Status">
+ <property type="b" name="IsEnabled" access="readwrite">
+ </property>
+ <property type="b" name="ScreenReaderEnabled" access="readwrite">
+ </property>
+ </interface>
+ <interface name="org.a11y.Bus">
+ <method name="GetAddress">
+ <arg type="s" name="address" direction="out">
+ </arg>
+ </method>
+ </interface>
+</node>
+
diff --git a/src/gui/accessible/linux/dbusxml/Cache.xml b/src/gui/accessible/linux/dbusxml/Cache.xml
new file mode 100644
index 0000000000..01c52810ac
--- /dev/null
+++ b/src/gui/accessible/linux/dbusxml/Cache.xml
@@ -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.Out0" value="QSpiAccessibleCacheItem"/>
+ </signal>
+
+ <signal name="RemoveAccessible">
+ <arg name="nodeRemoved" type="(so)"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiObjectReference"/>
+ </signal>
+
+</interface>
+</node>
diff --git a/src/gui/accessible/linux/dbusxml/DeviceEventController.xml b/src/gui/accessible/linux/dbusxml/DeviceEventController.xml
new file mode 100644
index 0000000000..d4c26ef7e7
--- /dev/null
+++ b/src/gui/accessible/linux/dbusxml/DeviceEventController.xml
@@ -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>
diff --git a/src/gui/accessible/linux/dbusxml/Socket.xml b/src/gui/accessible/linux/dbusxml/Socket.xml
new file mode 100644
index 0000000000..75ec99f994
--- /dev/null
+++ b/src/gui/accessible/linux/dbusxml/Socket.xml
@@ -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>
diff --git a/src/gui/accessible/linux/linux.pri b/src/gui/accessible/linux/linux.pri
new file mode 100644
index 0000000000..43e59cb7bc
--- /dev/null
+++ b/src/gui/accessible/linux/linux.pri
@@ -0,0 +1,27 @@
+accessibility_adaptors.files = accessible/linux/dbusxml/Cache.xml accessible/linux/dbusxml/DeviceEventController.xml
+accessibility_adaptors.header_flags = -i QtGui/private/qspi_struct_marshallers_p.h
+DBUS_ADAPTORS += accessibility_adaptors
+
+accessibility_interfaces.files = accessible/linux/dbusxml/Socket.xml accessible/linux/dbusxml/Bus.xml
+accessibility_interfaces.header_flags = -i QtGui/private/qspi_struct_marshallers_p.h
+DBUS_INTERFACES += accessibility_interfaces
+
+HEADERS += \
+ accessible/linux/atspiadaptor_p.h \
+ accessible/linux/dbusconnection_p.h \
+ accessible/linux/qspi_constant_mappings_p.h \
+ accessible/linux/qspi_struct_marshallers_p.h \
+ accessible/linux/qspiaccessiblebridge_p.h \
+ accessible/linux/qspiapplicationadaptor_p.h \
+ accessible/linux/qspidbuscache_p.h
+
+SOURCES += \
+ accessible/linux/atspiadaptor.cpp \
+ accessible/linux/dbusconnection.cpp \
+ accessible/linux/qspi_constant_mappings.cpp \
+ accessible/linux/qspi_struct_marshallers.cpp \
+ accessible/linux/qspiaccessiblebridge.cpp \
+ accessible/linux/qspiapplicationadaptor.cpp \
+ accessible/linux/qspidbuscache.cpp
+
+QMAKE_USE += atspi/nolink
diff --git a/src/gui/accessible/linux/qspi_constant_mappings.cpp b/src/gui/accessible/linux/qspi_constant_mappings.cpp
new file mode 100644
index 0000000000..d4fe3ecd69
--- /dev/null
+++ b/src/gui/accessible/linux/qspi_constant_mappings.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qspi_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"
+
+#ifndef QT_NO_ACCESSIBILITY
+QT_BEGIN_NAMESPACE
+
+QHash <QAccessible::Role, RoleNames> qSpiRoleMapping;
+
+quint64 spiStatesFromQState(QAccessible::State state)
+{
+ quint64 spiState = 0;
+
+ if (state.active)
+ setSpiStateBit(&spiState, ATSPI_STATE_ACTIVE);
+ if (state.editable)
+ setSpiStateBit(&spiState, ATSPI_STATE_EDITABLE);
+ if (!state.disabled) {
+ setSpiStateBit(&spiState, ATSPI_STATE_ENABLED);
+ setSpiStateBit(&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)
+ setSpiStateBit(&spiState, ATSPI_STATE_READ_ONLY);
+ // if (state.HotTracked)
+ if (state.defaultButton)
+ setSpiStateBit(&spiState, ATSPI_STATE_IS_DEFAULT);
+ if (state.expandable)
+ setSpiStateBit(&spiState, ATSPI_STATE_EXPANDABLE);
+ 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) {
+ setSpiStateBit(&spiState, ATSPI_STATE_SHOWING);
+ setSpiStateBit(&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);
+ if (state.multiLine)
+ setSpiStateBit(&spiState, ATSPI_STATE_MULTI_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
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/qspi_constant_mappings_p.h b/src/gui/accessible/linux/qspi_constant_mappings_p.h
new file mode 100644
index 0000000000..292b5e1597
--- /dev/null
+++ b/src/gui/accessible/linux/qspi_constant_mappings_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+/*
+ * 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 "qspi_struct_marshallers_p.h"
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/QAccessible>
+#include <atspi/atspi-constants.h>
+
+QT_REQUIRE_CONFIG(accessibility);
+
+// 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_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 = ATSPI_ROLE_INVALID;
+ QString m_name;
+ QString m_localizedName;
+};
+
+extern QHash <QAccessible::Role, RoleNames> qSpiRoleMapping;
+
+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
+
+#endif /* Q_SPI_CONSTANT_MAPPINGS_H */
diff --git a/src/gui/accessible/linux/qspi_struct_marshallers.cpp b/src/gui/accessible/linux/qspi_struct_marshallers.cpp
new file mode 100644
index 0000000000..1f49d8533f
--- /dev/null
+++ b/src/gui/accessible/linux/qspi_struct_marshallers.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qspi_struct_marshallers_p.h"
+
+#include <atspi/atspi-constants.h>
+#include <QtCore/qdebug.h>
+#include <QtDBus/qdbusmetatype.h>
+
+#include "qspiaccessiblebridge_p.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+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)
+{
+ argument.beginStructure();
+ argument >> action.name;
+ argument >> action.description;
+ argument >> action.keyBinding;
+ argument.endStructure();
+ 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
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/qspi_struct_marshallers_p.h b/src/gui/accessible/linux/qspi_struct_marshallers_p.h
new file mode 100644
index 0000000000..876c2bf700
--- /dev/null
+++ b/src/gui/accessible/linux/qspi_struct_marshallers_p.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef Q_SPI_STRUCT_MARSHALLERS_H
+#define Q_SPI_STRUCT_MARSHALLERS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qpair.h>
+#include <QtDBus/QDBusArgument>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusObjectPath>
+
+QT_REQUIRE_CONFIG(accessibility);
+
+QT_BEGIN_NAMESPACE
+
+typedef QVector<int> QSpiIntList;
+typedef QVector<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) {}
+};
+Q_DECLARE_TYPEINFO(QSpiObjectReference, Q_MOVABLE_TYPE); // QDBusObjectPath is movable, even though it
+ // cannot be marked that way until Qt 6
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QSpiObjectReference &address);
+const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiObjectReference &address);
+
+typedef QVector<QSpiObjectReference> QSpiObjectReferenceArray;
+
+struct QSpiAccessibleCacheItem
+{
+ QSpiObjectReference path;
+ QSpiObjectReference application;
+ QSpiObjectReference parent;
+ QSpiObjectReferenceArray children;
+ QStringList supportedInterfaces;
+ QString name;
+ uint role;
+ QString description;
+ QSpiUIntList state;
+};
+Q_DECLARE_TYPEINFO(QSpiAccessibleCacheItem, Q_MOVABLE_TYPE);
+
+typedef QVector<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;
+};
+Q_DECLARE_TYPEINFO(QSpiAction, Q_MOVABLE_TYPE);
+
+typedef QVector<QSpiAction> QSpiActionArray;
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAction &action);
+const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAction &action);
+
+struct QSpiEventListener
+{
+ QString listenerAddress;
+ QString eventName;
+};
+Q_DECLARE_TYPEINFO(QSpiEventListener, Q_MOVABLE_TYPE);
+
+typedef QVector<QSpiEventListener> QSpiEventListenerArray;
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QSpiEventListener &action);
+const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiEventListener &action);
+
+typedef QPair<unsigned int, QSpiObjectReferenceArray> QSpiRelationArrayEntry;
+typedef QVector<QSpiRelationArrayEntry> QSpiRelationArray;
+
+//a(iisv)
+struct QSpiTextRange {
+ int startOffset;
+ int endOffset;
+ QString contents;
+ QVariant v;
+};
+Q_DECLARE_TYPEINFO(QSpiTextRange, Q_MOVABLE_TYPE);
+
+typedef QVector<QSpiTextRange> QSpiTextRangeList;
+typedef QMap <QString, QString> QSpiAttributeSet;
+
+enum QSpiAppUpdateType {
+ QSPI_APP_UPDATE_ADDED = 0,
+ QSPI_APP_UPDATE_REMOVED = 1
+};
+Q_DECLARE_TYPEINFO(QSpiAppUpdateType, Q_PRIMITIVE_TYPE);
+
+struct QSpiAppUpdate {
+ int type; /* Is an application added or removed */
+ QString address; /* D-Bus address of application added or removed */
+};
+Q_DECLARE_TYPEINFO(QSpiAppUpdate, Q_MOVABLE_TYPE);
+
+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;
+};
+Q_DECLARE_TYPEINFO(QSpiDeviceEvent, Q_MOVABLE_TYPE);
+
+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)
+
+// For qdbusxml2cpp-generated code
+QT_USE_NAMESPACE
+
+#endif /* Q_SPI_STRUCT_MARSHALLERS_H */
diff --git a/src/gui/accessible/linux/qspiaccessiblebridge.cpp b/src/gui/accessible/linux/qspiaccessiblebridge.cpp
new file mode 100644
index 0000000000..9ae8767b66
--- /dev/null
+++ b/src/gui/accessible/linux/qspiaccessiblebridge.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qspiaccessiblebridge_p.h"
+
+#include <atspi/atspi-constants.h>
+#include <qstring.h>
+
+#include "atspiadaptor_p.h"
+
+#include "qspidbuscache_p.h"
+#include "qspi_constant_mappings_p.h"
+#include "dbusconnection_p.h"
+#include "qspi_struct_marshallers_p.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "deviceeventcontroller_adaptor.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSpiAccessibleBridge
+ \internal
+*/
+
+QSpiAccessibleBridge::QSpiAccessibleBridge()
+ : cache(0), dec(0), dbusAdaptor(0)
+{
+ dbusConnection = new DBusConnection();
+ connect(dbusConnection, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool)));
+}
+
+void QSpiAccessibleBridge::enabledChanged(bool enabled)
+{
+ setActive(enabled);
+ updateStatus();
+}
+
+QSpiAccessibleBridge::~QSpiAccessibleBridge()
+{
+ delete dbusConnection;
+} // Qt currently doesn't delete plugins.
+
+QDBusConnection QSpiAccessibleBridge::dBusConnection() const
+{
+ return dbusConnection->connection();
+}
+
+void QSpiAccessibleBridge::updateStatus()
+{
+ // create the adaptor to handle everything if we are in enabled state
+ if (!dbusAdaptor && isActive()) {
+ qSpiInitializeStructTypes();
+ initializeConstantMappings();
+
+ cache = new QSpiDBusCache(dbusConnection->connection(), this);
+ dec = new DeviceEventControllerAdaptor(this);
+
+ dbusConnection->connection().registerObject(QLatin1String(ATSPI_DBUS_PATH_DEC), this, QDBusConnection::ExportAdaptors);
+
+ dbusAdaptor = new AtSpiAdaptor(dbusConnection, this);
+ dbusConnection->connection().registerVirtualObject(QLatin1String(QSPI_OBJECT_PATH_ACCESSIBLE), dbusAdaptor, QDBusConnection::SubPath);
+ dbusAdaptor->registerApplication();
+ }
+}
+
+void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event)
+{
+ if (!dbusAdaptor)
+ return;
+ if (isActive() && event->accessibleInterface())
+ dbusAdaptor->notify(event);
+}
+
+struct RoleMapping {
+ QAccessible::Role role;
+ AtspiRole spiRole;
+ const char *name;
+};
+
+static RoleMapping map[] = {
+ //: Role of an accessible object - the object is in an invalid state or could not be constructed
+ { QAccessible::NoRole, ATSPI_ROLE_INVALID, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "invalid role") },
+ //: Role of an accessible object
+ { QAccessible::TitleBar, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "title bar") },
+ //: Role of an accessible object
+ { QAccessible::MenuBar, ATSPI_ROLE_MENU_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "menu bar") },
+ //: Role of an accessible object
+ { QAccessible::ScrollBar, ATSPI_ROLE_SCROLL_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "scroll bar") },
+ //: Role of an accessible object - the grip is usually used for resizing another object
+ { QAccessible::Grip, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "grip") },
+ //: Role of an accessible object
+ { QAccessible::Sound, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "sound") },
+ //: Role of an accessible object
+ { QAccessible::Cursor, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "cursor") },
+ //: Role of an accessible object
+ { QAccessible::Caret, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "text caret") },
+ //: Role of an accessible object
+ { QAccessible::AlertMessage, ATSPI_ROLE_ALERT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "alert message") },
+ //: Role of an accessible object: a window with frame and title
+ { QAccessible::Window, ATSPI_ROLE_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "frame") },
+ //: Role of an accessible object
+ { QAccessible::Client, ATSPI_ROLE_FILLER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "filler") },
+ //: Role of an accessible object
+ { QAccessible::PopupMenu, ATSPI_ROLE_POPUP_MENU, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "popup menu") },
+ //: Role of an accessible object
+ { QAccessible::MenuItem, ATSPI_ROLE_MENU_ITEM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "menu item") },
+ //: Role of an accessible object
+ { QAccessible::ToolTip, ATSPI_ROLE_TOOL_TIP, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tool tip") },
+ //: Role of an accessible object
+ { QAccessible::Application, ATSPI_ROLE_APPLICATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "application") },
+ //: Role of an accessible object
+ { QAccessible::Document, ATSPI_ROLE_DOCUMENT_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "document") },
+ //: Role of an accessible object
+ { QAccessible::Pane, ATSPI_ROLE_PANEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "panel") },
+ //: Role of an accessible object
+ { QAccessible::Chart, ATSPI_ROLE_CHART, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "chart") },
+ //: Role of an accessible object
+ { QAccessible::Dialog, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "dialog") },
+ //: Role of an accessible object
+ { QAccessible::Border, ATSPI_ROLE_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "frame") },
+ //: Role of an accessible object
+ { QAccessible::Grouping, ATSPI_ROLE_PANEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "panel") },
+ //: Role of an accessible object
+ { QAccessible::Separator, ATSPI_ROLE_SEPARATOR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "separator") },
+ //: Role of an accessible object
+ { QAccessible::ToolBar, ATSPI_ROLE_TOOL_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tool bar") },
+ //: Role of an accessible object
+ { QAccessible::StatusBar, ATSPI_ROLE_STATUS_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "status bar") },
+ //: Role of an accessible object
+ { QAccessible::Table, ATSPI_ROLE_TABLE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "table") },
+ //: Role of an accessible object - part of a table
+ { QAccessible::ColumnHeader, ATSPI_ROLE_TABLE_COLUMN_HEADER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "column header") },
+ //: Role of an accessible object - part of a table
+ { QAccessible::RowHeader, ATSPI_ROLE_TABLE_ROW_HEADER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "row header") },
+ //: Role of an accessible object - part of a table
+ { QAccessible::Column, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "column") },
+ //: Role of an accessible object - part of a table
+ { QAccessible::Row, ATSPI_ROLE_TABLE_ROW, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "row") },
+ //: Role of an accessible object - part of a table
+ { QAccessible::Cell, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "cell") },
+ //: Role of an accessible object
+ { QAccessible::Link, ATSPI_ROLE_LINK, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "link") },
+ //: Role of an accessible object
+ { QAccessible::HelpBalloon, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "help balloon") },
+ //: Role of an accessible object - a helper dialog
+ { QAccessible::Assistant, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "assistant") },
+ //: Role of an accessible object
+ { QAccessible::List, ATSPI_ROLE_LIST, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "list") },
+ //: Role of an accessible object
+ { QAccessible::ListItem, ATSPI_ROLE_LIST_ITEM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "list item") },
+ //: Role of an accessible object
+ { QAccessible::Tree, ATSPI_ROLE_TREE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tree") },
+ //: Role of an accessible object
+ { QAccessible::TreeItem, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tree item") },
+ //: Role of an accessible object
+ { QAccessible::PageTab, ATSPI_ROLE_PAGE_TAB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "page tab") },
+ //: Role of an accessible object
+ { QAccessible::PropertyPage, ATSPI_ROLE_PAGE_TAB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "property page") },
+ //: Role of an accessible object
+ { QAccessible::Indicator, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "indicator") },
+ //: Role of an accessible object
+ { QAccessible::Graphic, ATSPI_ROLE_IMAGE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "graphic") },
+ //: Role of an accessible object
+ { QAccessible::StaticText, ATSPI_ROLE_LABEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "label") },
+ //: Role of an accessible object
+ { QAccessible::EditableText, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "text") },
+ //: Role of an accessible object
+ { QAccessible::PushButton, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "push button") },
+ //: Role of an accessible object
+ { QAccessible::CheckBox, ATSPI_ROLE_CHECK_BOX, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "check box") },
+ //: Role of an accessible object
+ { QAccessible::RadioButton, ATSPI_ROLE_RADIO_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "radio button") },
+ //: Role of an accessible object
+ { QAccessible::ComboBox, ATSPI_ROLE_COMBO_BOX, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "combo box") },
+ //: Role of an accessible object
+ { QAccessible::ProgressBar, ATSPI_ROLE_PROGRESS_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "progress bar") },
+ //: Role of an accessible object
+ { QAccessible::Dial, ATSPI_ROLE_DIAL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "dial") },
+ //: Role of an accessible object
+ { QAccessible::HotkeyField, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "hotkey field") },
+ //: Role of an accessible object
+ { QAccessible::Slider, ATSPI_ROLE_SLIDER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "slider") },
+ //: Role of an accessible object
+ { QAccessible::SpinBox, ATSPI_ROLE_SPIN_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "spin box") },
+ //: Role of an accessible object
+ { QAccessible::Canvas, ATSPI_ROLE_CANVAS, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "canvas") },
+ //: Role of an accessible object
+ { QAccessible::Animation, ATSPI_ROLE_ANIMATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "animation") },
+ //: Role of an accessible object
+ { QAccessible::Equation, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "equation") },
+ //: Role of an accessible object
+ { QAccessible::ButtonDropDown, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down") },
+ //: Role of an accessible object
+ { QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button menu") },
+ //: Role of an accessible object - a button that expands a grid.
+ { QAccessible::ButtonDropGrid, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down grid") },
+ //: Role of an accessible object - blank space between other objects.
+ { QAccessible::Whitespace, ATSPI_ROLE_FILLER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "space") },
+ //: Role of an accessible object
+ { QAccessible::PageTabList, ATSPI_ROLE_PAGE_TAB_LIST, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "page tab list") },
+ //: Role of an accessible object
+ { QAccessible::Clock, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "clock") },
+ //: Role of an accessible object
+ { QAccessible::Splitter, ATSPI_ROLE_SPLIT_PANE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "splitter") },
+ //: Role of an accessible object
+ { QAccessible::LayeredPane, ATSPI_ROLE_LAYERED_PANE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "layered pane") },
+ //: Role of an accessible object
+ { QAccessible::WebDocument, ATSPI_ROLE_DOCUMENT_WEB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "web document") },
+ //: Role of an accessible object
+ { QAccessible::Paragraph, ATSPI_ROLE_PARAGRAPH, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "paragraph") },
+ //: Role of an accessible object
+ { QAccessible::Section, ATSPI_ROLE_SECTION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "section") },
+ //: Role of an accessible object
+ { QAccessible::ColorChooser, ATSPI_ROLE_COLOR_CHOOSER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "color chooser") },
+ //: Role of an accessible object
+ { QAccessible::Footer, ATSPI_ROLE_FOOTER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "footer") },
+ //: Role of an accessible object
+ { QAccessible::Form, ATSPI_ROLE_FORM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "form") },
+ //: Role of an accessible object
+ { QAccessible::Heading, ATSPI_ROLE_HEADING, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "heading") },
+ //: Role of an accessible object
+ { QAccessible::Note, ATSPI_ROLE_COMMENT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "note") },
+ //: Role of an accessible object
+ { QAccessible::ComplementaryContent, ATSPI_ROLE_SECTION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "complementary content") },
+ //: Role of an accessible object
+ { QAccessible::Terminal, ATSPI_ROLE_TERMINAL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "terminal") },
+ //: Role of an accessible object
+ { QAccessible::Desktop, ATSPI_ROLE_DESKTOP_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "desktop") },
+ //: Role of an accessible object
+ { QAccessible::Notification, ATSPI_ROLE_NOTIFICATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "notification") },
+ //: Role of an accessible object
+ { QAccessible::UserRole, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "unknown") }
+};
+
+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].name)));
+
+ // -1 because we have button duplicated, as PushButton and Button.
+ Q_ASSERT_X(qSpiRoleMapping.size() ==
+ QAccessible::staticMetaObject.enumerator(
+ QAccessible::staticMetaObject.indexOfEnumerator("Role")).keyCount() - 1,
+ "", "Handle all QAccessible::Role members in qSpiRoleMapping");
+}
+
+QT_END_NAMESPACE
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/qspiaccessiblebridge_p.h b/src/gui/accessible/linux/qspiaccessiblebridge_p.h
new file mode 100644
index 0000000000..ce1b755826
--- /dev/null
+++ b/src/gui/accessible/linux/qspiaccessiblebridge_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSPIACCESSIBLEBRIDGE_H
+#define QSPIACCESSIBLEBRIDGE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtDBus/qdbusconnection.h>
+#include <qpa/qplatformaccessibility.h>
+
+class DeviceEventControllerAdaptor;
+
+QT_REQUIRE_CONFIG(accessibility);
+
+QT_BEGIN_NAMESPACE
+
+class DBusConnection;
+class QSpiDBusCache;
+class AtSpiAdaptor;
+
+class Q_GUI_EXPORT QSpiAccessibleBridge: public QObject, public QPlatformAccessibility
+{
+ Q_OBJECT
+public:
+ QSpiAccessibleBridge();
+
+ virtual ~QSpiAccessibleBridge();
+
+ void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+ QDBusConnection dBusConnection() const;
+
+public Q_SLOTS:
+ void enabledChanged(bool enabled);
+
+private:
+ void initializeConstantMappings();
+ void updateStatus();
+
+ QSpiDBusCache *cache;
+ DeviceEventControllerAdaptor *dec;
+ AtSpiAdaptor *dbusAdaptor;
+ DBusConnection* dbusConnection;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/accessible/linux/qspiapplicationadaptor.cpp b/src/gui/accessible/linux/qspiapplicationadaptor.cpp
new file mode 100644
index 0000000000..430dc13b00
--- /dev/null
+++ b/src/gui/accessible/linux/qspiapplicationadaptor.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qspiapplicationadaptor_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtDBus/qdbuspendingreply.h>
+#include <qdebug.h>
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "deviceeventcontroller_adaptor.h"
+#include "atspi/atspi-constants.h"
+
+//#define KEYBOARD_DEBUG
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSpiApplicationAdaptor
+ \internal
+
+ \brief QSpiApplicationAdaptor
+
+ QSpiApplicationAdaptor
+*/
+
+QSpiApplicationAdaptor::QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent)
+ : QObject(parent), dbusConnection(connection), inCapsLock(false)
+{
+}
+
+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.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_Control)
+ de.text = QStringLiteral("Control_L");
+ 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");
+ if (event->type() == QEvent::KeyPress)
+ inCapsLock = true;
+ else
+ inCapsLock = false;
+ } 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();
+
+ de.modifiers = 0;
+ if (!inCapsLock && keyEvent->modifiers() & Qt::ShiftModifier)
+ de.modifiers |= 1 << ATSPI_MODIFIER_SHIFT;
+ if (inCapsLock && (keyEvent->key() != Qt::Key_CapsLock))
+ de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK;
+ if ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->key() != Qt::Key_Control))
+ de.modifiers |= 1 << ATSPI_MODIFIER_CONTROL;
+ if ((keyEvent->modifiers() & Qt::AltModifier) && (keyEvent->key() != Qt::Key_Alt))
+ de.modifiers |= 1 << ATSPI_MODIFIER_ALT;
+ if ((keyEvent->modifiers() & Qt::MetaModifier) && (keyEvent->key() != Qt::Key_Meta))
+ de.modifiers |= 1 << ATSPI_MODIFIER_META;
+
+#ifdef KEYBOARD_DEBUG
+ qDebug() << "Key event text:" << event->type() << de.text
+ << "native virtual key:" << de.id
+ << "hardware code/scancode:" << de.hardwareCode
+ << "modifiers:" << de.modifiers
+ << "text:" << de.text;
+#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<QPointer<QObject>, QKeyEvent*> (QPointer<QObject>(target), copyKeyEvent(keyEvent)));
+ return true;
+ }
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+QKeyEvent* QSpiApplicationAdaptor::copyKeyEvent(QKeyEvent* old)
+{
+ return new QKeyEvent(old->type(), old->key(), old->modifiers(),
+ old->nativeScanCode(), old->nativeVirtualKey(), old->nativeModifiers(),
+ old->text(), old->isAutoRepeat(), old->count());
+}
+
+void QSpiApplicationAdaptor::notifyKeyboardListenerCallback(const QDBusMessage& message)
+{
+ if (!keyEvents.length()) {
+ qWarning("QSpiApplication::notifyKeyboardListenerCallback with no queued key called");
+ return;
+ }
+ Q_ASSERT(message.arguments().length() == 1);
+ if (message.arguments().at(0).toBool() == true) {
+ QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
+ delete event.second;
+ } else {
+ QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
+ if (event.first)
+ QCoreApplication::postEvent(event.first.data(), event.second);
+ }
+}
+
+void QSpiApplicationAdaptor::notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& /*message*/)
+{
+ qWarning() << "QSpiApplication::keyEventError " << error.name() << error.message();
+ while (!keyEvents.isEmpty()) {
+ QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
+ if (event.first)
+ QCoreApplication::postEvent(event.first.data(), event.second);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/qspiapplicationadaptor_p.h b/src/gui/accessible/linux/qspiapplicationadaptor_p.h
new file mode 100644
index 0000000000..ca206edcd4
--- /dev/null
+++ b/src/gui/accessible/linux/qspiapplicationadaptor_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q_SPI_APPLICATION_H
+#define Q_SPI_APPLICATION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/QPointer>
+#include <QtCore/QQueue>
+#include <QtDBus/QDBusConnection>
+#include <QtGui/QAccessibleInterface>
+Q_MOC_INCLUDE(<QtDBus/QDBusMessage>)
+
+QT_REQUIRE_CONFIG(accessibility);
+
+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) override;
+
+private Q_SLOTS:
+ void notifyKeyboardListenerCallback(const QDBusMessage& message);
+ void notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& message);
+
+private:
+ static QKeyEvent* copyKeyEvent(QKeyEvent*);
+
+ QQueue<QPair<QPointer<QObject>, QKeyEvent*> > keyEvents;
+ QDBusConnection dbusConnection;
+ bool inCapsLock;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/accessible/linux/qspidbuscache.cpp b/src/gui/accessible/linux/qspidbuscache.cpp
new file mode 100644
index 0000000000..189cd2adf8
--- /dev/null
+++ b/src/gui/accessible/linux/qspidbuscache.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qspidbuscache_p.h"
+#include "qspiaccessiblebridge_p.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "cache_adaptor.h"
+
+#define QSPI_OBJECT_PATH_CACHE "/org/a11y/atspi/cache"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSpiDBusCache
+ \internal
+ \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()
+{
+ return QSpiAccessibleCacheArray();
+}
+
+QT_END_NAMESPACE
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/linux/qspidbuscache_p.h b/src/gui/accessible/linux/qspidbuscache_p.h
new file mode 100644
index 0000000000..89bee59d3a
--- /dev/null
+++ b/src/gui/accessible/linux/qspidbuscache_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef Q_SPI_CACHE_H
+#define Q_SPI_CACHE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/QObject>
+#include "qspi_struct_marshallers_p.h"
+
+QT_REQUIRE_CONFIG(accessibility);
+
+QT_BEGIN_NAMESPACE
+
+class QSpiDBusCache : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QSpiDBusCache(QDBusConnection c, QObject* parent = nullptr);
+ 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
+
+#endif /* Q_SPI_CACHE_H */
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
index bbdaad1e89..acd34c20ac 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef DBUSCONNECTION_H
-#define DBUSCONNECTION_H
+#ifndef QDBUSMENUCONNECTION_H
+#define QDBUSMENUCONNECTION_H
//
// W A R N I N G
@@ -98,4 +98,4 @@ private:
QT_END_NAMESPACE
-#endif // DBUSCONNECTION_H
+#endif // QDBUSMENUCONNECTION_H