Warning, file /libraries/libqaccessibilityclient/src/qaccessibilityclient/registry_p.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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