File indexing completed on 2024-04-21 04:42:46

0001 /*
0002     SPDX-FileCopyrightText: 2012 Frederik Gladhorn <gladhorn@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "registry_p.h"
0008 #include "registry.h"
0009 #include "qaccessibilityclient_debug.h"
0010 
0011 #include <QDBusMessage>
0012 #include <QDBusArgument>
0013 #include <QDBusReply>
0014 #include <QDBusPendingCall>
0015 #include <QDBusArgument>
0016 #include <QDBusMetaType>
0017 
0018 #include <QDBusMessage>
0019 #include <QStringList>
0020 #include <qurl.h>
0021 
0022 #include "atspi/atspi-constants.h"
0023 
0024 #include <QString>
0025 
0026 // interface names from at-spi2-core/atspi/atspi-misc-private.h
0027 #define ATSPI_DBUS_NAME_REGISTRY "org.a11y.atspi.Registry"
0028 #define ATSPI_DBUS_PATH_REGISTRY "/org/a11y/atspi/registry"
0029 #define ATSPI_DBUS_INTERFACE_REGISTRY "org.a11y.atspi.Registry"
0030 
0031 #define ATSPI_DBUS_PATH_NULL "/org/a11y/atspi/null"
0032 #define ATSPI_DBUS_PATH_ROOT "/org/a11y/atspi/accessible/root"
0033 
0034 #define ATSPI_DBUS_PATH_DEC "/org/a11y/atspi/registry/deviceeventcontroller"
0035 #define ATSPI_DBUS_INTERFACE_DEC "org.a11y.atspi.DeviceEventController"
0036 #define ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER "org.a11y.atspi.DeviceEventListener"
0037 
0038 #define ATSPI_DBUS_INTERFACE_CACHE "org.a11y.atspi.Cache"
0039 #define ATSPI_DBUS_INTERFACE_ACCESSIBLE "org.a11y.atspi.Accessible"
0040 #define ATSPI_DBUS_INTERFACE_ACTION "org.a11y.atspi.Action"
0041 #define ATSPI_DBUS_INTERFACE_APPLICATION "org.a11y.atspi.Application"
0042 #define ATSPI_DBUS_INTERFACE_COLLECTION "org.a11y.atspi.Collection"
0043 #define ATSPI_DBUS_INTERFACE_COMPONENT "org.a11y.atspi.Component"
0044 #define ATSPI_DBUS_INTERFACE_DOCUMENT "org.a11y.atspi.Document"
0045 #define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT "org.a11y.atspi.EditableText"
0046 #define ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD "org.a11y.atspi.Event.Keyboard"
0047 #define ATSPI_DBUS_INTERFACE_EVENT_MOUSE "org.a11y.atspi.Event.Mouse"
0048 #define ATSPI_DBUS_INTERFACE_EVENT_OBJECT "org.a11y.atspi.Event.Object"
0049 #define ATSPI_DBUS_INTERFACE_HYPERLINK "org.a11y.atspi.Hyperlink"
0050 #define ATSPI_DBUS_INTERFACE_HYPERTEXT "org.a11y.atspi.Hypertext"
0051 #define ATSPI_DBUS_INTERFACE_IMAGE "org.a11y.atspi.Image"
0052 #define ATSPI_DBUS_INTERFACE_SELECTION "org.a11y.atspi.Selection"
0053 #define ATSPI_DBUS_INTERFACE_TABLE "org.a11y.atspi.Table"
0054 #define ATSPI_DBUS_INTERFACE_TEXT "org.a11y.atspi.Text"
0055 #define ATSPI_DBUS_INTERFACE_VALUE "org.a11y.atspi.Value"
0056 #define ATSPI_DBUS_INTERFACE_SOCKET "org.a11y.atspi.Socket"
0057 
0058 // missing from at-spi2-core:
0059 #define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
0060 #define ATSPI_DBUS_INTERFACE_EVENT_FOCUS  "org.a11y.atspi.Event.Focus"
0061 
0062 #define QSPI_OBJECT_PATH_ACCESSIBLE  "/org/a11y/atspi/accessible"
0063 #define QSPI_OBJECT_PATH_PREFIX      "/org/a11y/atspi/accessible/"
0064 #define QSPI_OBJECT_PATH_ROOT    QSPI_OBJECT_PATH_PREFIX "root"
0065 
0066 #define QSPI_REGISTRY_NAME "org.a11y.atspi.Registry"
0067 
0068 //#define ATSPI_DEBUG
0069 
0070 using namespace QAccessibleClient;
0071 
0072 QString RegistryPrivate::ACCESSIBLE_OBJECT_SCHEME_STRING = QLatin1String("accessibleobject");
0073 
0074 RegistryPrivate::RegistryPrivate(Registry *qq)
0075     :q(qq)
0076     , m_subscriptions(Registry::NoEventListeners)
0077 {
0078     qDBusRegisterMetaType<QVector<quint32> >();
0079 
0080     connect(&conn, SIGNAL(connectionFetched()), this, SLOT(connectionFetched()));
0081     connect(&m_actionMapper, SIGNAL(mappedString(QString)), this, SLOT(actionTriggered(QString)));
0082     init();
0083 }
0084 
0085 RegistryPrivate::~RegistryPrivate()
0086 {
0087     delete m_cache;
0088 }
0089 
0090 void RegistryPrivate::init()
0091 {
0092     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_CACHE)] = AccessibleObject::CacheInterface;
0093     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE)] = AccessibleObject::AccessibleInterface;
0094     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_ACTION)] = AccessibleObject::ActionInterface;
0095     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION)] = AccessibleObject::ApplicationInterface;
0096     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_COLLECTION)] = AccessibleObject::CollectionInterface;
0097     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT)] = AccessibleObject::ComponentInterface;
0098     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_DOCUMENT)] = AccessibleObject::DocumentInterface;
0099     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT)] = AccessibleObject::EditableTextInterface;
0100     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD)] = AccessibleObject::EventKeyboardInterface;
0101     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_MOUSE)] = AccessibleObject::EventMouseInterface;
0102     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT)] = AccessibleObject::EventObjectInterface;
0103     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_HYPERLINK)] = AccessibleObject::HyperlinkInterface;
0104     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_HYPERTEXT)] = AccessibleObject::HypertextInterface;
0105     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_IMAGE)] = AccessibleObject::ImageInterface;
0106     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_SELECTION)] = AccessibleObject::SelectionInterface;
0107     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_TABLE)] = AccessibleObject::TableInterface;
0108     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_TEXT)] = AccessibleObject::TextInterface;
0109     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_VALUE)] = AccessibleObject::ValueInterface;
0110     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_SOCKET)] = AccessibleObject::SocketInterface;
0111     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW)] = AccessibleObject::EventWindowInterface;
0112     interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_FOCUS)] = AccessibleObject::EventFocusInterface;
0113 }
0114 
0115 bool RegistryPrivate::isEnabled() const
0116 {
0117     if (conn.status() != DBusConnection::Connected)
0118         return false;
0119     QDBusMessage message = QDBusMessage::createMethodCall(
0120                 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
0121     message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("IsEnabled"));
0122     QDBusReply<QVariant> reply  = QDBusConnection::sessionBus().call(message);
0123     if (!reply.isValid())
0124         return false;
0125     return reply.value().toBool();
0126 }
0127 
0128 void RegistryPrivate::setEnabled(bool enable)
0129 {
0130     QDBusMessage message = QDBusMessage::createMethodCall(
0131                 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Set"));
0132     message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("IsEnabled") << QVariant::fromValue(QDBusVariant(enable)));
0133     QDBusMessage reply = QDBusConnection::sessionBus().call(message);
0134     if (reply.type() == QDBusMessage::ErrorMessage) {
0135         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not set org.a11y.Status.isEnabled." << reply.errorName() << reply.errorMessage();
0136     }
0137 }
0138 
0139 bool RegistryPrivate::isScreenReaderEnabled() const
0140 {
0141     if (conn.status() != DBusConnection::Connected)
0142         return false;
0143     QDBusMessage message = QDBusMessage::createMethodCall(
0144                 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
0145     message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("ScreenReaderEnabled"));
0146     QDBusReply<QVariant> reply  = QDBusConnection::sessionBus().call(message);
0147     if (!reply.isValid())
0148         return false;
0149     return reply.value().toBool();
0150 }
0151 
0152 void RegistryPrivate::setScreenReaderEnabled(bool enable)
0153 {
0154     QDBusMessage message = QDBusMessage::createMethodCall(
0155                 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Set"));
0156     message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("ScreenReaderEnabled") << QVariant::fromValue(QDBusVariant(enable)));
0157     QDBusMessage reply = QDBusConnection::sessionBus().call(message);
0158     if (reply.type() == QDBusMessage::ErrorMessage) {
0159         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not set org.a11y.Status.ScreenReaderEnabled." << reply.errorName() << reply.errorMessage();
0160     }
0161 }
0162 
0163 AccessibleObject RegistryPrivate::fromUrl(const QUrl &url) const
0164 {
0165     Q_ASSERT(url.scheme() == ACCESSIBLE_OBJECT_SCHEME_STRING);
0166     if (url.scheme() != ACCESSIBLE_OBJECT_SCHEME_STRING)
0167         return AccessibleObject();
0168     QString path = url.path();
0169     QString service = url.fragment();
0170     return accessibleFromPath(service, path);
0171 }
0172 
0173 void RegistryPrivate::connectionFetched()
0174 {
0175     Q_ASSERT(conn.status() == DBusConnection::Connected);
0176 
0177     QDBusConnection session = QDBusConnection::sessionBus();
0178     if (session.isConnected()) {
0179         bool connected = session.connect(QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("PropertiesChanged"), this, SLOT(a11yConnectionChanged(QString,QVariantMap,QStringList)));
0180         if (!connected)
0181             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << Q_FUNC_INFO << "Failed to connect with signal org.a11y.Status.PropertiesChanged on org.a11y.Bus";
0182     }
0183 
0184     if (m_pendingSubscriptions > 0) {
0185         subscribeEventListeners(m_pendingSubscriptions);
0186         m_pendingSubscriptions = {};
0187     }
0188 }
0189 
0190 void RegistryPrivate::subscribeEventListeners(const Registry::EventListeners &listeners)
0191 {
0192     if (conn.isFetchingConnection()) {
0193         m_pendingSubscriptions = listeners;
0194         return;
0195     }
0196 
0197     Registry::EventListeners addedListeners = listeners & ~m_subscriptions;
0198     Registry::EventListeners removedListeners = m_subscriptions & ~listeners;
0199 
0200     QStringList newSubscriptions;
0201     QStringList removedSubscriptions;
0202 
0203     if (removedListeners.testFlag(Registry::Window)) {
0204         removedSubscriptions << QLatin1String("window:");
0205     } else if (addedListeners.testFlag(Registry::Window)) {
0206         // subscribe all window events
0207         newSubscriptions << QLatin1String("window:");
0208 
0209         bool created = conn.connection().connect(
0210                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Create"),
0211                     this, SLOT(slotWindowCreate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0212         bool destroyed = conn.connection().connect(
0213                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Destroy"),
0214                     this, SLOT(slotWindowDestroy(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0215 
0216         bool closed = conn.connection().connect(
0217                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Close"),
0218                     this, SLOT(slotWindowClose(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0219         bool reparented = conn.connection().connect(
0220                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Reparent"),
0221                     this, SLOT(slotWindowReparent(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0222 
0223         bool minimized = conn.connection().connect(
0224                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Minimize"),
0225                     this, SLOT(slotWindowMinimize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0226         bool maximized = conn.connection().connect(
0227                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Maximize"),
0228                     this, SLOT(slotWindowMaximize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0229         bool restored = conn.connection().connect(
0230                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Restore"),
0231                     this, SLOT(slotWindowRestore(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0232 
0233         bool activated = conn.connection().connect(
0234                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Activate"),
0235                     this, SLOT(slotWindowActivate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0236         bool deactivated = conn.connection().connect(
0237                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Deactivate"),
0238                     this, SLOT(slotWindowDeactivate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0239 
0240         bool desktopCreated = conn.connection().connect(
0241                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("DesktopCreate"),
0242                     this, SLOT(slotWindowDesktopCreate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0243         bool desktopDestroyed = conn.connection().connect(
0244                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("DesktopDestroy"),
0245                     this, SLOT(slotWindowDesktopDestroy(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0246         bool raised = conn.connection().connect(
0247                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Raise"),
0248                     this, SLOT(slotWindowRaise(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0249         bool lowered = conn.connection().connect(
0250                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Lower"),
0251                     this, SLOT(slotWindowLower(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0252         bool moved = conn.connection().connect(
0253                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Move"),
0254                     this, SLOT(slotWindowMove(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0255         bool resized = conn.connection().connect(
0256                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Resize"),
0257                     this, SLOT(slotWindowResize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0258         bool shaded = conn.connection().connect(
0259                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Shade"),
0260                     this, SLOT(slotWindowShade(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0261         bool unshaded = conn.connection().connect(
0262                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Unshade"),
0263                     this, SLOT(slotWindowUnshade(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0264 
0265         if (!created || !destroyed || !closed || !reparented || !minimized || !maximized || !restored || 
0266             !activated || !deactivated || !desktopCreated || !desktopDestroyed ||
0267             !raised || !lowered || !moved || !resized || !shaded || !unshaded
0268         ) {
0269             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to Window event(s)."
0270                        << "created:" << created << "destroyed:" << destroyed
0271                        << "closed:" << closed << "reparented:" << reparented
0272                        << "minimized:" << minimized << "maximized:" << maximized << "restored:" << restored
0273                        << "activated:" << activated << "deactivated:" << deactivated
0274                        << "desktopCreated:" << desktopCreated << "desktopDestroyed:" << desktopDestroyed
0275                        << "raised:" << raised << "lowered:" << lowered
0276                        << "moved:" << moved << "resized:" << resized
0277                        << "shaded:" << shaded << "unshaded:" << unshaded
0278                        ;
0279         }
0280     }
0281 
0282     if (removedListeners.testFlag(Registry::ChildrenChanged)) {
0283         removedSubscriptions << QLatin1String("object:children-changed");
0284     } else if (addedListeners.testFlag(Registry::ChildrenChanged)) {
0285         newSubscriptions << QLatin1String("object:children-changed");
0286         bool success = conn.connection().connect(
0287                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("ChildrenChanged"),
0288                     this, SLOT(slotChildrenChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0289         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility ChildrenChanged events.";
0290     }
0291 
0292     if (removedListeners.testFlag(Registry::VisibleDataChanged)) {
0293         removedSubscriptions << QLatin1String("object:visibledata-changed");
0294     } else if (addedListeners.testFlag(Registry::VisibleDataChanged)) {
0295         newSubscriptions << QLatin1String("object:visibledata-changed");
0296         bool success = conn.connection().connect(
0297                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("VisibleDataChanged"),
0298                     this, SLOT(slotVisibleDataChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0299         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility VisibleDataChanged events.";
0300     }
0301 
0302     if (removedListeners.testFlag(Registry::SelectionChanged)) {
0303         removedSubscriptions << QLatin1String("object:selection-changed");
0304     } else if (addedListeners.testFlag(Registry::SelectionChanged)) {
0305         newSubscriptions << QLatin1String("object:selection-changed");
0306         bool success = conn.connection().connect(
0307                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("SelectionChanged"),
0308                     this, SLOT(slotSelectionChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0309         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility SelectionChanged events.";
0310     }
0311 
0312 
0313     if (removedListeners.testFlag(Registry::ModelChanged)) {
0314         removedSubscriptions << QLatin1String("object:model-changed");
0315     } else if (addedListeners.testFlag(Registry::ModelChanged)) {
0316         newSubscriptions << QLatin1String("object:model-changed");
0317         bool success = conn.connection().connect(
0318                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("ModelChanged"),
0319                     this, SLOT(slotModelChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0320         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility ModelChanged events.";
0321     }
0322 
0323     // we need state-changed-focus for focus events
0324     if ((removedListeners.testFlag(Registry::StateChanged) || removedListeners.testFlag(Registry::Focus))
0325             && (!(addedListeners.testFlag(Registry::StateChanged) || addedListeners.testFlag(Registry::Focus)))) {
0326         removedSubscriptions << QLatin1String("object:state-changed");
0327     } else if (addedListeners.testFlag(Registry::StateChanged) || addedListeners.testFlag(Registry::Focus)) {
0328         if (listeners.testFlag(Registry::Focus)) newSubscriptions << QLatin1String("focus:");
0329         newSubscriptions << QLatin1String("object:state-changed");
0330         bool success = conn.connection().connect(
0331                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("StateChanged"),
0332                     this, SLOT(slotStateChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0333         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility Focus events.";
0334     }
0335 
0336     if (removedListeners.testFlag(Registry::TextChanged)) {
0337         removedSubscriptions << QLatin1String("object:text-changed");
0338     } else if (addedListeners.testFlag(Registry::TextChanged)) {
0339         newSubscriptions << QLatin1String("object:text-changed");
0340         bool success = conn.connection().connect(
0341                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextChanged"),
0342                     this, SLOT(slotTextChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0343         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility TextChanged events.";
0344     }
0345 
0346     if (removedListeners.testFlag(Registry::TextCaretMoved)) {
0347         removedSubscriptions << QLatin1String("object:text-caret-moved");
0348     } else if (addedListeners.testFlag(Registry::TextCaretMoved)) {
0349         newSubscriptions << QLatin1String("object:text-caret-moved");
0350         bool success = conn.connection().connect(
0351                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextCaretMoved"),
0352                     this, SLOT(slotTextCaretMoved(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0353         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility TextCaretMoved events.";
0354     }
0355 
0356     if (removedListeners.testFlag(Registry::TextSelectionChanged)) {
0357         removedSubscriptions << QLatin1String("object:text-selection-changed");
0358     } else if (addedListeners.testFlag(Registry::TextSelectionChanged)) {
0359         newSubscriptions << QLatin1String("object:text-selection-changed");
0360         bool success = conn.connection().connect(
0361                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextSelectionChanged"),
0362                     this, SLOT(slotTextSelectionChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0363         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility TextSelectionChanged events.";
0364     }
0365 
0366     if (removedListeners.testFlag(Registry::PropertyChanged)) {
0367         removedSubscriptions << QLatin1String("object:property-change");
0368     } else if (addedListeners.testFlag(Registry::PropertyChanged )) {
0369         newSubscriptions << QLatin1String("object:property-change");
0370         bool success = conn.connection().connect(
0371                     QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("PropertyChange"),
0372                     this, SLOT(slotPropertyChange(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
0373         if (!success) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility PropertyChange events.";
0374     }
0375 
0376     for (const QString &subscription : std::as_const(newSubscriptions)) {
0377         QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
0378                                                         QLatin1String("/org/a11y/atspi/registry"),
0379                                                         QLatin1String("org.a11y.atspi.Registry"), QLatin1String("RegisterEvent"));
0380         m.setArguments(QVariantList() << subscription);
0381 
0382         QDBusPendingCall async = conn.connection().asyncCall(m);
0383         QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
0384         QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(slotSubscribeEventListenerFinished(QDBusPendingCallWatcher*)));
0385     }
0386 
0387     for (const QString &subscription : std::as_const(removedSubscriptions)) {
0388         QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
0389                                                         QLatin1String("/org/a11y/atspi/registry"),
0390                                                         QLatin1String("org.a11y.atspi.Registry"), QLatin1String("DeregisterEvent"));
0391         m.setArguments(QVariantList() << subscription);
0392         conn.connection().asyncCall(m);
0393     }
0394 
0395     m_subscriptions = listeners;
0396 
0397 // accerciser
0398 //     (u':1.7', u'Object:StateChanged:'),
0399 //     (u':1.7', u'Object:BoundsChanged:'),
0400 //     (u':1.7', u'Object:VisibleDataChanged:'),
0401 //     (u':1.7', u'Object:StateChanged:'),
0402 // orca
0403 //    [(u':1.8', u'Object:ChildrenChanged:'),
0404 //     (u':1.8', u'Mouse:Button:'),
0405 //     (u':1.8', u'Mouse:Abs:'),
0406 //     (u':1.8', u'Object:StateChanged:Selected'),
0407 //     (u':1.8', u'Object:StateChanged:Expanded'),
0408 //     (u':1.8', u'Object:ValueChanged:'),
0409 //     (u':1.8', u'Object:StateChanged:Focused'),
0410 //     (u':1.8', u'Object:StateChanged:Active'),
0411 //     (u':1.8', u'Window:Create:'),
0412 //     (u':1.8', u'Object:TextAttributesChanged:'),
0413 //     (u':1.8', u'Object:TextCaretMoved:'),
0414 //     (u':1.8', u'Object:SelectionChanged:'),
0415 //     (u':1.8', u'Focus::'),
0416 //     (u':1.8', u'Object:ActiveDescendantChanged:'),
0417 //     (u':1.8', u'Object:PropertyChange:AccessibleName'),
0418 //     (u':1.8', u'Window:Activate:'),
0419 //     (u':1.8', u'Window:Deactivate:'),
0420 //     (u':1.8', u'Mouse:Button:'),
0421 //     (u':1.8', u'Object:StateChanged:Indeterminate'),
0422 //     (u':1.8', u'Object:LinkSelected:'),
0423 //     (u':1.8', u'Object:TextChanged:Insert'),
0424 //     (u':1.8', u'Object:PropertyChange:AccessibleValue'),
0425 //     (u':1.8', u'Object:TextSelectionChanged:'),
0426 // //     (u':1.8', u'Object:StateChanged:Showing'),
0427 //     (u':1.8', u'Object:TextChanged:Delete'),
0428 //     (u':1.8', u'Object:StateChanged:Pressed'),
0429 //     (u':1.8', u'Object:StateChanged:Checked'),
0430 //     (u':1.8', u'Object:ChildrenChanged:Remove')]
0431 
0432 }
0433 
0434 Registry::EventListeners RegistryPrivate::eventListeners() const
0435 {
0436     return m_subscriptions | m_pendingSubscriptions;
0437 }
0438 
0439 void RegistryPrivate::slotSubscribeEventListenerFinished(QDBusPendingCallWatcher *call)
0440 {
0441     if (call->isError()) {
0442         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not subscribe to accessibility event: " << call->error().type() << call->error().message();
0443     }
0444     call->deleteLater();
0445 }
0446 
0447 void RegistryPrivate::a11yConnectionChanged(const QString &interface,const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
0448 {
0449     //qDebug() << Q_FUNC_INFO << "interface=" << interface << "changedProperties=" << changedProperties << "invalidatedProperties=" << invalidatedProperties;
0450     if (conn.status() != DBusConnection::Connected)
0451         return;
0452     if (interface == QLatin1String("org.a11y.Status")) {
0453         QVariantMap::ConstIterator IsEnabledIt = changedProperties.constFind(QLatin1String("IsEnabled"));
0454         if (IsEnabledIt != changedProperties.constEnd())
0455             Q_EMIT q->enabledChanged(IsEnabledIt.value().toBool());
0456         else if (invalidatedProperties.contains(QLatin1String("IsEnabled")))
0457             Q_EMIT q->enabledChanged(isEnabled());
0458 
0459         QVariantMap::ConstIterator ScreenReaderEnabledIt = changedProperties.constFind(QLatin1String("ScreenReaderEnabled"));
0460         if (ScreenReaderEnabledIt != changedProperties.constEnd())
0461             Q_EMIT q->screenReaderEnabledChanged(ScreenReaderEnabledIt.value().toBool());
0462         else if (invalidatedProperties.contains(QLatin1String("ScreenReaderEnabled")))
0463             Q_EMIT q->screenReaderEnabledChanged(isScreenReaderEnabled());
0464     }
0465 }
0466 
0467 AccessibleObject RegistryPrivate::parentAccessible(const AccessibleObject &object) const
0468 {
0469     QVariant parent = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Parent"));
0470     if (!parent.isValid())
0471         return AccessibleObject();
0472     const QDBusArgument arg = parent.value<QDBusArgument>();
0473     QSpiObjectReference ref;
0474     arg >> ref;
0475 
0476     if (ref.path.path() == object.d->path) {
0477         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "WARNING: Accessible claims to be its own parent: " << object;
0478         return AccessibleObject();
0479     }
0480 
0481     if (ref.service.isEmpty() || ref.path.path().isEmpty())
0482         return AccessibleObject();
0483 
0484     return AccessibleObject(const_cast<RegistryPrivate*>(this), ref.service, ref.path.path());
0485 }
0486 
0487 int RegistryPrivate::childCount(const AccessibleObject &object) const
0488 {
0489     QVariant childCount = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("ChildCount"));
0490     return childCount.toInt();
0491 }
0492 
0493 int RegistryPrivate::indexInParent(const AccessibleObject &object) const
0494 {
0495     QDBusMessage message = QDBusMessage::createMethodCall (
0496                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetIndexInParent"));
0497 
0498     QDBusReply<int> reply = conn.connection().call(message);
0499     if (!reply.isValid()) {
0500         QDBusReply<uint> reply2 = conn.connection().call(message);
0501         if (reply2.isValid()) {
0502             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Found old api returning uint in GetIndexInParent." << reply.error().message();
0503             return static_cast<int>(reply.value());
0504         }
0505         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access index in parent." << reply.error().message();
0506         return -1;
0507     }
0508     return reply.value();
0509 }
0510 
0511 AccessibleObject RegistryPrivate::child(const AccessibleObject &object, int index) const
0512 {
0513     QDBusMessage message = QDBusMessage::createMethodCall (
0514                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetChildAtIndex"));
0515     QVariantList args;
0516     args << index;
0517     message.setArguments(args);
0518 
0519     QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
0520     if (!reply.isValid()) {
0521         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access child." << reply.error().message();
0522         return AccessibleObject();
0523     }
0524     const QSpiObjectReference child = reply.value();
0525     return AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path());
0526 }
0527 
0528 QList<AccessibleObject> RegistryPrivate::children(const AccessibleObject &object) const
0529 {
0530     QList<AccessibleObject> accs;
0531 
0532     QDBusMessage message = QDBusMessage::createMethodCall (
0533                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetChildren"));
0534 
0535     QDBusReply<QSpiObjectReferenceList> reply = conn.connection().call(message, QDBus::Block, 500);
0536     if (!reply.isValid()) {
0537         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access children." << reply.error().message();
0538         return accs;
0539     }
0540 
0541     const QSpiObjectReferenceList children = reply.value();
0542     for (const QSpiObjectReference &child : children) {
0543         accs.append(AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path()));
0544     }
0545 
0546     return accs;
0547 }
0548 
0549 QList<AccessibleObject> RegistryPrivate::topLevelAccessibles() const
0550 {
0551     QString service = QLatin1String("org.a11y.atspi.Registry");
0552     QString path = QLatin1String("/org/a11y/atspi/accessible/root");
0553     return children(AccessibleObject(const_cast<RegistryPrivate*>(this), service, path));
0554 }
0555 
0556 QString RegistryPrivate::accessibleId(const AccessibleObject &object) const
0557 {
0558     if (!object.isValid())
0559         return QString();
0560     return getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("AccessibleId")).toString();
0561 }
0562 
0563 QString RegistryPrivate::name(const AccessibleObject &object) const
0564 {
0565     if (!object.isValid())
0566         return QString();
0567     return getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Name")).toString();
0568 }
0569 
0570 QString RegistryPrivate::description(const AccessibleObject &object) const
0571 {
0572     if (!object.isValid())
0573         return QString();
0574     return getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Description")).toString();
0575 }
0576 
0577 AccessibleObject::Role RegistryPrivate::role(const AccessibleObject &object) const
0578 {
0579     if (!object.isValid())
0580         return AccessibleObject::NoRole;
0581 
0582     QDBusMessage message = QDBusMessage::createMethodCall (
0583                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetRole"));
0584 
0585     QDBusReply<uint> reply = conn.connection().call(message);
0586     if (!reply.isValid()) {
0587         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access role." << reply.error().message();
0588         return AccessibleObject::NoRole;
0589     }
0590     return atspiRoleToRole(static_cast<AtspiRole>(reply.value()));
0591 }
0592 
0593 AccessibleObject::Role RegistryPrivate::atspiRoleToRole(AtspiRole role)
0594 {
0595     switch (role) {
0596     case ATSPI_ROLE_INVALID: return AccessibleObject::NoRole;
0597 //    case ATSPI_ROLE_ACCELERATOR_LABEL: return AccessibleObject::;
0598 //    case ATSPI_ROLE_ALERT: return AccessibleObject::;
0599 //    case ATSPI_ROLE_ANIMATION: return AccessibleObject::;
0600 //    case ATSPI_ROLE_ARROW: return AccessibleObject::;
0601 //    case ATSPI_ROLE_CALENDAR: return AccessibleObject::;
0602 //    case ATSPI_ROLE_CANVAS: return AccessibleObject::;
0603     case ATSPI_ROLE_CHECK_BOX: return AccessibleObject::CheckBox;
0604     case ATSPI_ROLE_CHECK_MENU_ITEM: return AccessibleObject::CheckableMenuItem;
0605 //    case ATSPI_ROLE_COLOR_CHOOSER: return AccessibleObject::;
0606     case ATSPI_ROLE_COLUMN_HEADER: return AccessibleObject::ColumnHeader;
0607     case ATSPI_ROLE_COMBO_BOX: return AccessibleObject::ComboBox;
0608 //    case ATSPI_ROLE_DATE_EDITOR: return AccessibleObject::;
0609 //    case ATSPI_ROLE_DESKTOP_ICON: return AccessibleObject::;
0610     case ATSPI_ROLE_DESKTOP_FRAME: return AccessibleObject::DesktopFrame;
0611 //    case ATSPI_ROLE_DIAL: return AccessibleObject::;
0612     case ATSPI_ROLE_DIALOG: return AccessibleObject::Dialog;
0613 //    case ATSPI_ROLE_DIRECTORY_PANE: return AccessibleObject::;
0614 //    case ATSPI_ROLE_DRAWING_AREA: return AccessibleObject::;
0615 //    case ATSPI_ROLE_FILE_CHOOSER: return AccessibleObject::;
0616     case ATSPI_ROLE_FILLER: return AccessibleObject::Filler;
0617 //    case ATSPI_ROLE_FOCUS_TRAVERSABLE: return AccessibleObject::;
0618 //    case ATSPI_ROLE_FONT_CHOOSER: return AccessibleObject::;
0619     case ATSPI_ROLE_FRAME: return AccessibleObject::Frame;
0620 //    case ATSPI_ROLE_GLASS_PANE: return AccessibleObject::;
0621 //    case ATSPI_ROLE_HTML_CONTAINER: return AccessibleObject::;
0622     case ATSPI_ROLE_ICON: return AccessibleObject::Icon;
0623 //    case ATSPI_ROLE_IMAGE: return AccessibleObject::;
0624 //    case ATSPI_ROLE_INTERNAL_FRAME: return AccessibleObject::;
0625     case ATSPI_ROLE_LABEL: return AccessibleObject::Label;
0626 //    case ATSPI_ROLE_LAYERED_PANE: return AccessibleObject::;
0627     case ATSPI_ROLE_LIST: return AccessibleObject::ListView;
0628     case ATSPI_ROLE_LIST_ITEM: return AccessibleObject::ListItem;
0629     case ATSPI_ROLE_MENU: return AccessibleObject::Menu;
0630     case ATSPI_ROLE_MENU_BAR: return AccessibleObject::MenuBar;
0631     case ATSPI_ROLE_MENU_ITEM: return AccessibleObject::MenuItem;
0632 //    case ATSPI_ROLE_OPTION_PANE: return AccessibleObject::;
0633     case ATSPI_ROLE_PAGE_TAB: return AccessibleObject::Tab;
0634     case ATSPI_ROLE_PAGE_TAB_LIST: return AccessibleObject::TabContainer;
0635 //    case ATSPI_ROLE_PANEL: return AccessibleObject::;
0636     case ATSPI_ROLE_PASSWORD_TEXT: return AccessibleObject::PasswordText;
0637     case ATSPI_ROLE_POPUP_MENU: return AccessibleObject::PopupMenu;
0638     case ATSPI_ROLE_PROGRESS_BAR: return AccessibleObject::ProgressBar;
0639     case ATSPI_ROLE_PUSH_BUTTON: return AccessibleObject::Button;
0640     case ATSPI_ROLE_RADIO_BUTTON: return AccessibleObject::RadioButton;
0641     case ATSPI_ROLE_RADIO_MENU_ITEM: return AccessibleObject::RadioMenuItem;
0642 //    case ATSPI_ROLE_ROOT_PANE: return AccessibleObject::;
0643     case ATSPI_ROLE_ROW_HEADER: return AccessibleObject::RowHeader;
0644     case ATSPI_ROLE_SCROLL_BAR: return AccessibleObject::ScrollBar;
0645     case ATSPI_ROLE_SCROLL_PANE: return AccessibleObject::ScrollArea;
0646     case ATSPI_ROLE_SEPARATOR: return AccessibleObject::Separator;
0647     case ATSPI_ROLE_SLIDER: return AccessibleObject::Slider;
0648     case ATSPI_ROLE_SPIN_BUTTON: return AccessibleObject::SpinButton;
0649 //    case ATSPI_ROLE_SPLIT_PANE: return AccessibleObject::;
0650     case ATSPI_ROLE_STATUS_BAR: return AccessibleObject::StatusBar;
0651     case ATSPI_ROLE_TABLE: return AccessibleObject::TableView;
0652     case ATSPI_ROLE_TABLE_CELL: return AccessibleObject::TableCell;
0653     case ATSPI_ROLE_TABLE_COLUMN_HEADER: return AccessibleObject::TableColumnHeader;
0654     case ATSPI_ROLE_TABLE_ROW_HEADER: return AccessibleObject::TableRowHeader;
0655 //    case ATSPI_ROLE_TEAROFF_MENU_ITEM: return AccessibleObject::;
0656     case ATSPI_ROLE_TERMINAL: return AccessibleObject::Terminal;
0657     case ATSPI_ROLE_TEXT: return AccessibleObject::Text;
0658     case ATSPI_ROLE_TOGGLE_BUTTON: return AccessibleObject::ToggleButton;
0659     case ATSPI_ROLE_TOOL_BAR: return AccessibleObject::ToolBar;
0660     case ATSPI_ROLE_TOOL_TIP: return AccessibleObject::ToolTip;
0661     case ATSPI_ROLE_TREE: return AccessibleObject::TreeView;
0662     case ATSPI_ROLE_TREE_TABLE: return AccessibleObject::TreeView;
0663     case ATSPI_ROLE_UNKNOWN: return AccessibleObject::NoRole;
0664 //    case ATSPI_ROLE_VIEWPORT: return AccessibleObject::;
0665     case ATSPI_ROLE_WINDOW: return AccessibleObject::Window;
0666 //    case ATSPI_ROLE_EXTENDED: return AccessibleObject::;
0667 //    case ATSPI_ROLE_HEADER: return AccessibleObject::;
0668 //    case ATSPI_ROLE_FOOTER: return AccessibleObject::;
0669 //    case ATSPI_ROLE_PARAGRAPH: return AccessibleObject::;
0670 //    case ATSPI_ROLE_RULER: return AccessibleObject::;
0671 //    case ATSPI_ROLE_APPLICATION: return AccessibleObject::;
0672 //    case ATSPI_ROLE_AUTOCOMPLETE: return AccessibleObject::;
0673 //    case ATSPI_ROLE_EDITBAR: return AccessibleObject::;
0674 //    case ATSPI_ROLE_EMBEDDED: return AccessibleObject::;
0675 //    case ATSPI_ROLE_ENTRY: return AccessibleObject::;
0676 //    case ATSPI_ROLE_CHART: return AccessibleObject::;
0677 //    case ATSPI_ROLE_CAPTION: return AccessibleObject::;
0678 //    case ATSPI_ROLE_DOCUMENT_FRAME: return AccessibleObject::;
0679 //    case ATSPI_ROLE_HEADING: return AccessibleObject::;
0680 //    case ATSPI_ROLE_PAGE: return AccessibleObject::;
0681 //    case ATSPI_ROLE_SECTION: return AccessibleObject::;
0682 //    case ATSPI_ROLE_REDUNDANT_OBJECT: return AccessibleObject::;
0683 //    case ATSPI_ROLE_FORM: return AccessibleObject::;
0684 //    case ATSPI_ROLE_LINK: return AccessibleObject::;
0685 //    case ATSPI_ROLE_INPUT_METHOD_WINDOW: return AccessibleObject::;
0686     case ATSPI_ROLE_TABLE_ROW: return AccessibleObject::TableRow;
0687     case ATSPI_ROLE_TREE_ITEM: return AccessibleObject::TreeItem;
0688 //    case ATSPI_ROLE_DOCUMENT_SPREADSHEET: return AccessibleObject::;
0689 //    case ATSPI_ROLE_DOCUMENT_PRESENTATION: return AccessibleObject::;
0690 //    case ATSPI_ROLE_DOCUMENT_TEXT: return AccessibleObject::;
0691 //    case ATSPI_ROLE_DOCUMENT_WEB: return AccessibleObject::;
0692 //    case ATSPI_ROLE_DOCUMENT_EMAIL: return AccessibleObject::;
0693 //    case ATSPI_ROLE_COMMENT: return AccessibleObject::;
0694 //    case ATSPI_ROLE_LIST_BOX: return AccessibleObject::;
0695 //    case ATSPI_ROLE_GROUPING: return AccessibleObject::;
0696 //    case ATSPI_ROLE_IMAGE_MAP: return AccessibleObject::;
0697 //    case ATSPI_ROLE_NOTIFICATION: return AccessibleObject::;
0698 //    case ATSPI_ROLE_INFO_BAR: return AccessibleObject::;
0699 //    case ATSPI_ROLE_LAST_DEFINED: return AccessibleObject::;
0700     }
0701     return AccessibleObject::NoRole;
0702 }
0703 
0704 QString RegistryPrivate::roleName(const AccessibleObject &object) const
0705 {
0706     QDBusMessage message = QDBusMessage::createMethodCall (
0707                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetRoleName"));
0708 
0709     QDBusReply<QString> reply = conn.connection().call(message);
0710     if (!reply.isValid()) {
0711         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access roleName." << reply.error().message();
0712         return QString();
0713     }
0714     return reply.value();
0715 }
0716 
0717 QString RegistryPrivate::localizedRoleName(const AccessibleObject &object) const
0718 {
0719     QDBusMessage message = QDBusMessage::createMethodCall (
0720                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetLocalizedRoleName"));
0721 
0722     QDBusReply<QString> reply = conn.connection().call(message);
0723     if (!reply.isValid()) {
0724         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access localizedRoleName." << reply.error().message();\
0725         return QString();
0726     }
0727     return reply.value();
0728 }
0729 
0730 quint64 RegistryPrivate::state(const AccessibleObject &object) const
0731 {
0732     if (m_cache) {
0733         quint64 cachedValue = m_cache->state(object);
0734         if (cachedValue != QAccessibleClient::ObjectCache::StateNotFound)
0735             return cachedValue;
0736     }
0737 
0738     QDBusMessage message = QDBusMessage::createMethodCall (
0739                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetState"));
0740 
0741     QDBusReply<QVector<quint32> > reply = conn.connection().call(message);
0742     if (!reply.isValid()) {
0743         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access state." << reply.error().message();
0744         return 0;
0745     }
0746     if (reply.value().size() < 2) {
0747         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Did not receive expected reply.";
0748         return 0;
0749     }
0750     const quint32 low = reply.value().at(0);
0751     const quint32 high = reply.value().at(1);
0752     const quint64 state = low + (static_cast<quint64>(high) << 32);
0753 
0754     if (m_cache) {
0755         m_cache->setState(object, state);
0756     }
0757 
0758     return state;
0759 }
0760 
0761 int RegistryPrivate::layer(const AccessibleObject &object) const
0762 {
0763     QDBusMessage message = QDBusMessage::createMethodCall (
0764                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetLayer"));
0765     QDBusReply<uint> reply = conn.connection().call(message);
0766     if (!reply.isValid()) {
0767         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access layer." << reply.error().message();
0768         return 1;
0769     }
0770     return reply.value();
0771 }
0772 
0773 int RegistryPrivate::mdiZOrder(const AccessibleObject &object) const
0774 {
0775     QDBusMessage message = QDBusMessage::createMethodCall (
0776                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetMDIZOrder"));
0777     QDBusReply<short> reply = conn.connection().call(message);
0778     if (!reply.isValid()) {
0779         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access mdiZOrder." << reply.error().message();
0780         return 0;
0781     }
0782     return reply.value();
0783 }
0784 
0785 double RegistryPrivate::alpha(const AccessibleObject &object) const
0786 {
0787     QDBusMessage message = QDBusMessage::createMethodCall (
0788                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetAlpha"));
0789     QDBusReply<double> reply = conn.connection().call(message);
0790     if (!reply.isValid()) {
0791         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access alpha." << reply.error().message();
0792         return 1.0;
0793     }
0794     return reply.value();
0795 }
0796 
0797 QRect RegistryPrivate::boundingRect(const AccessibleObject &object) const
0798 {
0799     QDBusMessage message = QDBusMessage::createMethodCall(
0800             object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetExtents") );
0801     QVariantList args;
0802     quint32 coords = ATSPI_COORD_TYPE_SCREEN;
0803     args << coords;
0804     message.setArguments(args);
0805 
0806     QDBusReply< QRect > reply = conn.connection().call(message);
0807     if(!reply.isValid()){
0808         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not get extents." << reply.error().message();
0809         return QRect();
0810     }
0811 
0812     return QRect( reply.value() );
0813 }
0814 
0815 QRect RegistryPrivate::characterRect(const AccessibleObject &object, int offset) const
0816 {
0817     QDBusMessage message = QDBusMessage::createMethodCall(
0818             object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"),
0819                     QLatin1String("GetCharacterExtents"));
0820 
0821     QVariantList args;
0822     quint32 coords = ATSPI_COORD_TYPE_SCREEN;
0823     args << offset;
0824     args << coords;
0825     message.setArguments(args);
0826 
0827 
0828     QDBusReply< QRect > reply = conn.connection().call(message);
0829     if(!reply.isValid()){
0830         if (reply.error().type() == QDBusError::InvalidSignature) {
0831             QDBusMessage reply2 = conn.connection().call(message);
0832             if (reply2.signature() != QLatin1String("iiii")) {
0833                 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not get Character Extents. " << reply.error().message();
0834                 return QRect();
0835             }
0836             QList<QVariant> args = reply2.arguments();
0837             QRect rect(args.at(0).toInt(), args.at(1).toInt(), args.at(2).toInt(), args.at(3).toInt());
0838             return rect;
0839         }
0840     }
0841 
0842     return reply.value();
0843 }
0844 
0845 AccessibleObject::Interfaces RegistryPrivate::supportedInterfaces(const AccessibleObject &object) const
0846 {
0847     if (m_cache) {
0848         AccessibleObject::Interfaces interfaces = m_cache->interfaces(object);
0849         if (!(interfaces & AccessibleObject::InvalidInterface))
0850             return interfaces;
0851     }
0852 
0853     QDBusMessage message = QDBusMessage::createMethodCall(
0854             object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"),
0855                     QLatin1String("GetInterfaces"));
0856 
0857     QDBusReply<QStringList > reply = conn.connection().call(message);
0858     if(!reply.isValid()){
0859         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not get Interfaces. " << reply.error().message();
0860         return AccessibleObject::NoInterface;
0861     }
0862 
0863     AccessibleObject::Interfaces interfaces = AccessibleObject::NoInterface;
0864     const auto values{reply.value()};
0865     for (const QString &interface : values){
0866         interfaces |= interfaceHash[interface];
0867     }
0868 
0869     if (m_cache) {
0870         m_cache->setInterfaces(object, interfaces);
0871     }
0872 
0873     return interfaces;
0874 }
0875 
0876 int RegistryPrivate::caretOffset(const AccessibleObject &object) const
0877 {
0878     QVariant offset= getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("CaretOffset"));
0879     if (offset.isNull()) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not get caret offset";
0880     return offset.toInt();
0881 }
0882 
0883 int RegistryPrivate::characterCount(const AccessibleObject &object) const
0884 {
0885     QVariant count = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("CharacterCount"));
0886     if (count.isNull()) qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not get character count";
0887     return count.toInt();
0888 }
0889 
0890 QList< QPair<int,int> > RegistryPrivate::textSelections(const AccessibleObject &object) const
0891 {
0892     QList< QPair<int,int> > result;
0893     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetNSelections"));
0894     QDBusReply<int> reply = conn.connection().call(message);
0895     if (!reply.isValid()) {
0896         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access GetNSelections." << reply.error().message();
0897         return result;
0898     }
0899     int count = reply.value();
0900     for(int i = 0; i < count; ++i) {
0901         QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetSelection"));
0902         m.setArguments(QVariantList() << i);
0903         m = conn.connection().call(m);
0904         QList<QVariant> args = m.arguments();
0905         if (args.count() < 2) {
0906             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Invalid number of arguments. Expected=2 Actual=" << args.count();
0907             continue;
0908         }
0909         int startOffset = args[0].toInt();
0910         int endOffset = args[1].toInt();
0911         if (startOffset > endOffset)
0912             qSwap(startOffset, endOffset);
0913         result.append(qMakePair(startOffset, endOffset));
0914     }
0915     return result;
0916 }
0917 
0918 void RegistryPrivate::setTextSelections(const AccessibleObject &object, const QList< QPair<int,int> > &selections)
0919 {
0920     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetNSelections"));
0921     QDBusReply<int> reply = conn.connection().call(message);
0922     if (!reply.isValid()) {
0923         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access GetNSelections." << reply.error().message();
0924         return;
0925     }
0926     int count = reply.value();
0927     int setSel = qMin(selections.count(), count);
0928     for(int i = 0; i < setSel; ++i) {
0929         Q_ASSERT(i < selections.count());
0930         QPair<int,int> p = selections[i];
0931         QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("SetSelection"));
0932         m.setArguments(QVariantList() << i << p.first << p.second);
0933         QDBusReply<bool> r = conn.connection().call(m);
0934         if (!r.isValid()) {
0935             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Failed call text.SetSelection." << r.error().message();
0936             continue;
0937         }
0938     }
0939     int removeSel = qMax(0, count - selections.count());
0940     for(int i = 0, k = selections.count(); i < removeSel; ++i, ++k) {
0941         QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("RemoveSelection"));
0942         m.setArguments(QVariantList() << k);
0943         QDBusReply<bool> r = conn.connection().call(m);
0944         if (!r.isValid()) {
0945             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Failed call text.RemoveSelection." << r.error().message();
0946             continue;
0947         }
0948     }
0949     int addSel = qMax(0, selections.count() - count);
0950     for(int i = 0, k = count; i < addSel; ++i, ++k) {
0951         Q_ASSERT(k < selections.count());
0952         QPair<int,int> p = selections[k];
0953         QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("AddSelection"));
0954         m.setArguments(QVariantList() << p.first << p.second);
0955         QDBusReply<bool> r = conn.connection().call(m);
0956         if (!r.isValid()) {
0957             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Failed call text.AddSelection." << r.error().message();
0958             continue;
0959         }
0960     }
0961 }
0962 
0963 QString RegistryPrivate::text(const AccessibleObject &object, int startOffset, int endOffset) const
0964 {
0965     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetText"));
0966     message.setArguments(QVariantList() << startOffset << endOffset);
0967     QDBusReply<QString> reply = conn.connection().call(message);
0968     if (!reply.isValid()) {
0969         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access text." << reply.error().message();
0970         return QString();
0971     }
0972     return reply.value();
0973 }
0974 
0975 QString RegistryPrivate::textWithBoundary(const AccessibleObject &object, int offset, AccessibleObject::TextBoundary boundary, int *startOffset, int *endOffset) const
0976 {
0977     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetTextAtOffset"));
0978     message.setArguments(QVariantList() << offset << static_cast<AtspiTextBoundaryType>(boundary));
0979     QDBusMessage reply = conn.connection().call(message);
0980     if (reply.type() != QDBusMessage::ReplyMessage || reply.signature() != QLatin1String("sii")) {
0981         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access text." << reply.errorMessage();
0982         if (startOffset)
0983             *startOffset = 0;
0984         if (endOffset)
0985             *endOffset = 0;
0986         return QString();
0987     }
0988     if (startOffset)
0989         *startOffset = reply.arguments().at(1).toInt();
0990     if (endOffset)
0991         *endOffset = reply.arguments().at(2).toInt();
0992     return reply.arguments().first().toString();;
0993 }
0994 
0995 bool RegistryPrivate::setText(const AccessibleObject &object, const QString &text)
0996 {
0997     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("SetTextContents"));
0998     message.setArguments(QVariantList() << text);
0999     QDBusReply<bool> reply = conn.connection().call(message);
1000     if (!reply.isValid()) {
1001         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not set text." << reply.error().message();
1002         return false;
1003     }
1004     return reply.value();
1005 }
1006 
1007 bool RegistryPrivate::insertText(const AccessibleObject &object, const QString &text, int position, int length)
1008 {
1009     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("InsertText"));
1010     message.setArguments(QVariantList() << position << text << length);
1011     QDBusReply<bool> reply = conn.connection().call(message);
1012     if (!reply.isValid()) {
1013         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not insert text." << reply.error().message();
1014         return false;
1015     }
1016     return reply.value();
1017 }
1018 
1019 bool RegistryPrivate::copyText(const AccessibleObject &object, int startPos, int endPos)
1020 {
1021     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("CopyText"));
1022     message.setArguments(QVariantList() << startPos << endPos);
1023     conn.connection().call(message);
1024     return true;
1025 }
1026 
1027 bool RegistryPrivate::cutText(const AccessibleObject &object, int startPos, int endPos)
1028 {
1029     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("CutText"));
1030     message.setArguments(QVariantList() << startPos << endPos);
1031     QDBusReply<bool> reply = conn.connection().call(message);
1032     if (!reply.isValid()) {
1033         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not cut text." << reply.error().message();
1034         return false;
1035     }
1036     return reply.value();
1037 }
1038 
1039 bool RegistryPrivate::deleteText(const AccessibleObject &object, int startPos, int endPos)
1040 {
1041     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("DeleteText"));
1042     message.setArguments(QVariantList() << startPos << endPos);
1043     QDBusReply<bool> reply = conn.connection().call(message);
1044     if (!reply.isValid()) {
1045         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not delete text." << reply.error().message();
1046         return false;
1047     }
1048     return reply.value();
1049 }
1050 
1051 bool RegistryPrivate::pasteText(const AccessibleObject &object, int position)
1052 {
1053     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("PasteText"));
1054     message.setArguments(QVariantList() << position);
1055     QDBusReply<bool> reply = conn.connection().call(message);
1056     if (!reply.isValid()) {
1057         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not paste text." << reply.error().message();
1058         return false;
1059     }
1060     return reply.value();
1061 }
1062 
1063 AccessibleObject RegistryPrivate::application(const AccessibleObject &object) const
1064 {
1065     QDBusMessage message = QDBusMessage::createMethodCall(
1066             object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetApplication"));
1067     QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
1068     if (!reply.isValid()) {
1069         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access application." << reply.error().message();
1070         return AccessibleObject();
1071     }
1072     const QSpiObjectReference child = reply.value();
1073     return AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path());
1074 }
1075 
1076 QString RegistryPrivate::appToolkitName(const AccessibleObject &object) const
1077 {
1078     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("ToolkitName"));
1079     return v.toString();
1080 }
1081 
1082 QString RegistryPrivate::appVersion(const AccessibleObject &object) const
1083 {
1084     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("Version"));
1085     return v.toString();
1086 }
1087 
1088 int RegistryPrivate::appId(const AccessibleObject &object) const
1089 {
1090     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("Id"));
1091     return v.toInt();
1092 }
1093 
1094 QString RegistryPrivate::appLocale(const AccessibleObject &object, uint lctype) const
1095 {
1096     // some apps misbehave and claim to be the service, but on :1.0 we have the atspi service which doesn't reply anything sensible here
1097     if (object.d->service == QLatin1String(":1.0"))
1098         return QString();
1099 
1100     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("GetLocale"));
1101 
1102     QVariantList args;
1103     args.append(lctype);
1104     message.setArguments(args);
1105 
1106     QDBusReply<QString> reply = conn.connection().call(message, QDBus::Block, 500);
1107     if (!reply.isValid()) {
1108         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access appLocale." << reply.error().message();
1109         return QString();
1110     }
1111     return reply.value();
1112 }
1113 
1114 QString RegistryPrivate::appBusAddress(const AccessibleObject &object) const
1115 {
1116     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("GetApplicationBusAddress"));
1117     QDBusReply<QString> reply = conn.connection().call(message);
1118     if (!reply.isValid()) {
1119         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << Q_FUNC_INFO << "Could not access application bus address. Error: " << reply.error().message() << " in response to: " << message;
1120         return QString();
1121     }
1122     return reply.value();
1123 }
1124 
1125 double RegistryPrivate::minimumValue(const AccessibleObject &object) const
1126 {
1127     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MinimumValue"));
1128     return v.toDouble();
1129 }
1130 
1131 double RegistryPrivate::maximumValue(const AccessibleObject &object) const
1132 {
1133     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MaximumValue"));
1134     return v.toDouble();
1135 }
1136 
1137 double RegistryPrivate::minimumValueIncrement(const AccessibleObject &object) const
1138 {
1139     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MinimumIncrement"));
1140     return v.toDouble();
1141 }
1142 
1143 double RegistryPrivate::currentValue(const AccessibleObject &object) const
1144 {
1145     const QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("CurrentValue"));
1146     return v.toDouble();
1147 }
1148 
1149 bool RegistryPrivate::setCurrentValue(const AccessibleObject &object, double value)
1150 {
1151     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("SetCurrentValue"));
1152 
1153     QVariantList arguments;
1154     arguments << QLatin1String("org.a11y.atspi.Value") <<  QLatin1String("CurrentValue");
1155     arguments << QVariant::fromValue(QDBusVariant(value));
1156     message.setArguments(arguments);
1157 
1158     QDBusReply<bool> reply = conn.connection().call(message);
1159     if (!reply.isValid()) {
1160         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not set text." << reply.error().message();
1161         return false;
1162     }
1163     return reply.value();
1164 }
1165 
1166 QList<AccessibleObject> RegistryPrivate::selection(const AccessibleObject &object) const
1167 {
1168     QList<AccessibleObject> result;
1169     int count = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Selection"), QLatin1String("CurrentValue")).toInt();
1170     for(int i = 0; i < count; ++i) {
1171         QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Selection"), QLatin1String("GetSelectedChild"));
1172         QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
1173         if (!reply.isValid()) {
1174             qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access selection." << reply.error().message();
1175             return QList<AccessibleObject>();
1176         }
1177         const QSpiObjectReference ref = reply.value();
1178         result.append(AccessibleObject(const_cast<RegistryPrivate*>(this), ref.service, ref.path.path()));
1179     }
1180     return result;
1181 }
1182 
1183 QString RegistryPrivate::imageDescription(const AccessibleObject &object) const
1184 {
1185     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("ImageDescription"));
1186     QDBusReply<QString> reply = conn.connection().call(message);
1187     if (!reply.isValid()) {
1188         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access imageDescription." << reply.error().message();
1189         return QString();
1190     }
1191     return reply.value();
1192 }
1193 
1194 QString RegistryPrivate::imageLocale(const AccessibleObject &object) const
1195 {
1196     const QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("ImageLocale"));
1197     const QDBusReply<QString> reply = conn.connection().call(message, QDBus::Block, 500);
1198     if (!reply.isValid()) {
1199         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access imageLocale." << reply.error().message();
1200         return QString();
1201     }
1202     return reply.value();
1203 }
1204 
1205 QRect RegistryPrivate::imageRect(const AccessibleObject &object) const
1206 {
1207     QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("GetImageExtents"));
1208     QVariantList args;
1209     quint32 coords = ATSPI_COORD_TYPE_SCREEN;
1210     args << coords;
1211     message.setArguments(args);
1212     QDBusReply<QRect> reply = conn.connection().call(message);
1213     if (!reply.isValid()) {
1214         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access imageRect." << reply.error().message();
1215         return QRect();
1216     }
1217     return QRect( reply.value() );
1218 }
1219 
1220 QVector< QSharedPointer<QAction> > RegistryPrivate::actions(const AccessibleObject &object)
1221 {
1222     const QDBusMessage message = QDBusMessage::createMethodCall (
1223                 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Action"), QLatin1String("GetActions"));
1224 
1225     const QDBusReply<QSpiActionArray> reply = conn.connection().call(message, QDBus::Block, 500);
1226     if (!reply.isValid()) {
1227         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not access actions." << reply.error().message();
1228         return QVector< QSharedPointer<QAction> >();
1229     }
1230 
1231     const QSpiActionArray actionArray = reply.value();
1232     QVector< QSharedPointer<QAction> > list;
1233     for(int i = 0, total = actionArray.count(); i < total; ++i) {
1234         const QSpiAction &a = actionArray[i];
1235         QAction *action = new QAction();
1236         const QString id = QStringLiteral("%1;%2;%3").arg(object.d->service).arg(object.d->path).arg(i);
1237         action->setObjectName(id);
1238         action->setText(a.name);
1239         action->setWhatsThis(a.description);
1240         if (!a.keyBinding.isEmpty()) {
1241             const QKeySequence shortcut(a.keyBinding);
1242             action->setShortcut(std::move(shortcut));
1243         }
1244         m_actionMapper.setMapping(action, id);
1245         connect(action, SIGNAL(triggered()), &m_actionMapper, SLOT(map()));
1246         list.append(QSharedPointer<QAction>(action));
1247     }
1248     return list;
1249 }
1250 
1251 void RegistryPrivate::actionTriggered(const QString &action)
1252 {
1253     const QStringList actionParts = action.split(QLatin1Char(';'));
1254     Q_ASSERT(actionParts.count() == 3);
1255     const QString service = actionParts.at(0);
1256     const QString path = actionParts.at(1);
1257     const int index = actionParts.at(2).toInt();
1258 
1259     QDBusMessage message = QDBusMessage::createMethodCall (
1260                 service, path, QLatin1String("org.a11y.atspi.Action"), QLatin1String("DoAction"));
1261 
1262     QVariantList args;
1263     args << index;
1264     message.setArguments(args);
1265 
1266     QDBusReply<bool> reply = conn.connection().call(message, QDBus::Block, 500);
1267     if (!reply.isValid()) {
1268         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Could not execute action=" << action << reply.error().message();
1269         return;
1270     }
1271 
1272     if (reply.value()) {
1273         qDebug() << "Successful executed action=" << action;
1274     } else {
1275         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Failed to execute action=" << action;
1276     }
1277 }
1278 
1279 QVariant RegistryPrivate::getProperty(const QString &service, const QString &path, const QString &interface, const QString &name) const
1280 {
1281     QVariantList args;
1282     args.append(interface);
1283     args.append(name);
1284 
1285     QDBusMessage message = QDBusMessage::createMethodCall (
1286                 service, path, QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
1287 
1288     message.setArguments(args);
1289     const QDBusMessage reply = conn.connection().call(message, QDBus::Block, 500);
1290     if (reply.arguments().isEmpty())
1291         return QVariant();
1292 
1293     const QDBusVariant v = reply.arguments().at(0).value<QDBusVariant>();
1294     return v.variant();
1295 }
1296 
1297 AccessibleObject RegistryPrivate::accessibleFromPath(const QString &service, const QString &path) const
1298 {
1299     return AccessibleObject(const_cast<RegistryPrivate*>(this), service, path);
1300 }
1301 
1302 AccessibleObject RegistryPrivate::accessibleFromReference(const QSpiObjectReference &reference) const
1303 {
1304     return accessibleFromPath(reference.service, reference.path.path());
1305 }
1306 
1307 AccessibleObject RegistryPrivate::accessibleFromContext() const
1308 {
1309     return accessibleFromPath(QDBusContext::message().service(), QDBusContext::message().path());
1310 }
1311 
1312 void RegistryPrivate::slotWindowCreate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &)
1313 {
1314     Q_EMIT q->windowCreated(accessibleFromContext());
1315 }
1316 
1317 void RegistryPrivate::slotWindowDestroy(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1318 {
1319     Q_EMIT q->windowDestroyed(accessibleFromContext());
1320 }
1321 
1322 void RegistryPrivate::slotWindowClose(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1323 {
1324     Q_EMIT q->windowClosed(accessibleFromContext());
1325 }
1326 
1327 void RegistryPrivate::slotWindowReparent(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1328 {
1329     Q_EMIT q->windowReparented(accessibleFromContext());
1330 }
1331 
1332 void RegistryPrivate::slotWindowMinimize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1333 {
1334     Q_EMIT q->windowMinimized(accessibleFromContext());
1335 }
1336 
1337 void RegistryPrivate::slotWindowMaximize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1338 {
1339     Q_EMIT q->windowMaximized(accessibleFromContext());
1340 }
1341 
1342 void RegistryPrivate::slotWindowRestore(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1343 {
1344     Q_EMIT q->windowRestored(accessibleFromContext());
1345 }
1346 
1347 void RegistryPrivate::slotWindowActivate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1348 {
1349     Q_EMIT q->windowActivated(accessibleFromContext());
1350 }
1351 
1352 void RegistryPrivate::slotWindowDeactivate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1353 {
1354     Q_EMIT q->windowDeactivated(accessibleFromContext());
1355 }
1356 
1357 void RegistryPrivate::slotWindowDesktopCreate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1358 {
1359     Q_EMIT q->windowDesktopCreated(accessibleFromContext());
1360 }
1361 
1362 void RegistryPrivate::slotWindowDesktopDestroy(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1363 {
1364     Q_EMIT q->windowDesktopDestroyed(accessibleFromContext());
1365 }
1366 
1367 void RegistryPrivate::slotWindowRaise(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1368 {
1369     Q_EMIT q->windowRaised(accessibleFromContext());
1370 }
1371 
1372 void RegistryPrivate::slotWindowLower(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1373 {
1374     Q_EMIT q->windowLowered(accessibleFromContext());
1375 }
1376 
1377 void RegistryPrivate::slotWindowMove(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1378 {
1379     Q_EMIT q->windowMoved(accessibleFromContext());
1380 }
1381 
1382 void RegistryPrivate::slotWindowResize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1383 {
1384     Q_EMIT q->windowResized(accessibleFromContext());
1385 }
1386 
1387 void RegistryPrivate::slotWindowShade(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1388 {
1389     Q_EMIT q->windowShaded(accessibleFromContext());
1390 }
1391 
1392 void RegistryPrivate::slotWindowUnshade(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1393 {
1394     Q_EMIT q->windowUnshaded(accessibleFromContext());
1395 }
1396 
1397 void RegistryPrivate::slotPropertyChange(const QString &property, int detail1, int detail2, const QDBusVariant &args, const QSpiObjectReference &reference)
1398 {
1399 #ifdef ATSPI_DEBUG
1400     qDebug() << Q_FUNC_INFO << property << detail1 << detail2 << args.variant() << reference.path.path();
1401 #endif
1402     if (property == QLatin1String("accessible-name")) {
1403         Q_EMIT q->accessibleNameChanged(accessibleFromContext());
1404     } else if (property == QLatin1String("accessible-description")) {
1405         Q_EMIT q->accessibleDescriptionChanged(accessibleFromContext());
1406     }
1407 }
1408 
1409 void RegistryPrivate::slotStateChanged(const QString &state, int detail1, int detail2, const QDBusVariant &object, const QSpiObjectReference &reference)
1410 {
1411     //qDebug() << Q_FUNC_INFO << state << detail1 << detail2 << reference.service << reference.path.path() << QDBusContext::message();
1412 
1413     if (state == QLatin1String("defunct") && (detail1 == 1)) {
1414         QSpiObjectReference removed;
1415         removed.service = QDBusContext::message().service();
1416         removed.path = QDBusObjectPath(QDBusContext::message().path());
1417         removeAccessibleObject(removed);
1418         return;
1419     }
1420 
1421     AccessibleObject accessible = accessibleFromContext();
1422     if (m_cache) {
1423         m_cache->cleanState(accessible);
1424     }
1425 
1426     if (state == QLatin1String("focused") && (detail1 == 1) &&
1427             (q->subscribedEventListeners().testFlag(Registry::Focus))) {
1428         Q_EMIT q->focusChanged(accessible);
1429     }
1430 
1431     if (q->subscribedEventListeners().testFlag(Registry::StateChanged)) {
1432         Q_EMIT q->stateChanged(accessible, state, detail1 == 1);
1433     }
1434 }
1435 
1436 // void RegistryPrivate::slotLinkSelected(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1437 // {
1438 //     Q_EMIT q->linkSelected(accessibleFromContext());
1439 // }
1440 
1441 bool RegistryPrivate::removeAccessibleObject(const QAccessibleClient::AccessibleObject &accessible)
1442 {
1443     Q_ASSERT(accessible.isValid());
1444     if (m_cache) {
1445         const QString id = accessible.id();
1446         if (m_cache->remove(id)) {
1447             Q_EMIT q->removed(accessible);
1448         }
1449     } else {
1450         Q_EMIT q->removed(accessible);
1451     }
1452     if (accessible.d)
1453         accessible.d->setDefunct();
1454     return true;
1455 }
1456 
1457 bool RegistryPrivate::removeAccessibleObject(const QAccessibleClient::QSpiObjectReference &reference)
1458 {
1459     QAccessibleClient::AccessibleObject acc = accessibleFromReference(reference);
1460     if (acc.isValid()) {
1461         if (removeAccessibleObject(acc))
1462             return true;
1463     }
1464     return false;
1465 }
1466 
1467 void RegistryPrivate::slotChildrenChanged(const QString &state, int detail1, int detail2, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1468 {
1469 //    qDebug() << Q_FUNC_INFO << state << detail1 << detail2 << args.variant() << reference.path.path();
1470     QAccessibleClient::AccessibleObject parentAccessible = accessibleFromContext();
1471     if (!parentAccessible.isValid()) {
1472         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << Q_FUNC_INFO << "Children change with invalid parent." << reference.path.path();
1473         return;
1474     }
1475 
1476     const int index = detail1;
1477     if (state == QLatin1String("add")) {
1478         Q_EMIT q->childAdded(parentAccessible, index);
1479     } else if (state == QLatin1String("remove")) {
1480         Q_EMIT q->childRemoved(parentAccessible, index);
1481     } else {
1482         qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "Invalid state in ChildrenChanged." << state;
1483     }
1484 }
1485 
1486 void RegistryPrivate::slotVisibleDataChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1487 {
1488     Q_EMIT q->visibleDataChanged(accessibleFromContext());
1489 }
1490 
1491 void RegistryPrivate::slotSelectionChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1492 {
1493     Q_EMIT q->selectionChanged(accessibleFromContext());
1494 }
1495 
1496 void RegistryPrivate::slotModelChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1497 {
1498     Q_EMIT q->modelChanged(accessibleFromContext());
1499 }
1500 
1501 void RegistryPrivate::slotTextCaretMoved(const QString &/*state*/, int detail1, int /*detail2*/, const QDBusVariant &/*args*/, const QSpiObjectReference &reference)
1502 {
1503     Q_EMIT q->textCaretMoved(accessibleFromContext(), detail1);
1504 }
1505 
1506 void RegistryPrivate::slotTextSelectionChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &/*args*/, const QSpiObjectReference &reference)
1507 {
1508     Q_EMIT q->textSelectionChanged(accessibleFromContext());
1509 }
1510 
1511 void RegistryPrivate::slotTextChanged(const QString &change, int start, int end, const QDBusVariant &textVariant, const QSpiObjectReference &reference)
1512 {
1513     const AccessibleObject object(accessibleFromContext());
1514     const QString text = textVariant.variant().toString();
1515 
1516     if (change == QLatin1String("insert")) {
1517         Q_EMIT q->textInserted(object, text, start, end);
1518     } else if (change == QLatin1String("remove")) {
1519         Q_EMIT q->textRemoved(object, text, start, end);
1520     } else {
1521         Q_EMIT q->textChanged(object, text, start, end);
1522     }
1523 }
1524 
1525 #include "moc_registry_p.cpp"