diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-07-02 10:04:34 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-07-06 11:15:08 +0200 |
commit | 9e733622a605c841adf7da7304895758d307c843 (patch) | |
tree | e859f7cf4dee099c49835c65e5c0498bcec6f87c /src/platformsupport/linuxaccessibility/atspiadaptor.cpp | |
parent | 7067b2ca6e08e683bb9c202a7e3c1b10d08622ee (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/platformsupport/linuxaccessibility/atspiadaptor.cpp')
-rw-r--r-- | src/platformsupport/linuxaccessibility/atspiadaptor.cpp | 2482 |
1 files changed, 0 insertions, 2482 deletions
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp deleted file mode 100644 index c4ff9a211b..0000000000 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ /dev/null @@ -1,2482 +0,0 @@ -/**************************************************************************** -** -** 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 "constant_mappings_p.h" -#include <QtGui/private/qaccessiblebridgeutils_p.h> - -#include "application_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 |