1 /*
2 Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "registry_p.h"
22 #include "registry.h"
23
24 #include <qdbusmessage.h>
25 #include <qdbusargument.h>
26 #include <qdbusreply.h>
27 #include <qdbuspendingcall.h>
28 #include <qdbusinterface.h>
29 #include <qdbusargument.h>
30 #include <qdbusmetatype.h>
31
32 #include <qdebug.h>
33 #include <qdbusmessage.h>
34 #include <qstringlist.h>
35 #include <qurl.h>
36
37 #include "atspi/atspi-constants.h"
38 #include "atspi/qt-atspi.h"
39 #include "atspi/dbusconnection.h"
40
41 #include <qstring.h>
42 #include <qhash.h>
43
44 // interface names from at-spi2-core/atspi/atspi-misc-private.h
45 #define ATSPI_DBUS_NAME_REGISTRY "org.a11y.atspi.Registry"
46 #define ATSPI_DBUS_PATH_REGISTRY "/org/a11y/atspi/registry"
47 #define ATSPI_DBUS_INTERFACE_REGISTRY "org.a11y.atspi.Registry"
48
49 #define ATSPI_DBUS_PATH_NULL "/org/a11y/atspi/null"
50 #define ATSPI_DBUS_PATH_ROOT "/org/a11y/atspi/accessible/root"
51
52 #define ATSPI_DBUS_PATH_DEC "/org/a11y/atspi/registry/deviceeventcontroller"
53 #define ATSPI_DBUS_INTERFACE_DEC "org.a11y.atspi.DeviceEventController"
54 #define ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER "org.a11y.atspi.DeviceEventListener"
55
56 #define ATSPI_DBUS_INTERFACE_CACHE "org.a11y.atspi.Cache"
57 #define ATSPI_DBUS_INTERFACE_ACCESSIBLE "org.a11y.atspi.Accessible"
58 #define ATSPI_DBUS_INTERFACE_ACTION "org.a11y.atspi.Action"
59 #define ATSPI_DBUS_INTERFACE_APPLICATION "org.a11y.atspi.Application"
60 #define ATSPI_DBUS_INTERFACE_COLLECTION "org.a11y.atspi.Collection"
61 #define ATSPI_DBUS_INTERFACE_COMPONENT "org.a11y.atspi.Component"
62 #define ATSPI_DBUS_INTERFACE_DOCUMENT "org.a11y.atspi.Document"
63 #define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT "org.a11y.atspi.EditableText"
64 #define ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD "org.a11y.atspi.Event.Keyboard"
65 #define ATSPI_DBUS_INTERFACE_EVENT_MOUSE "org.a11y.atspi.Event.Mouse"
66 #define ATSPI_DBUS_INTERFACE_EVENT_OBJECT "org.a11y.atspi.Event.Object"
67 #define ATSPI_DBUS_INTERFACE_HYPERLINK "org.a11y.atspi.Hyperlink"
68 #define ATSPI_DBUS_INTERFACE_HYPERTEXT "org.a11y.atspi.Hypertext"
69 #define ATSPI_DBUS_INTERFACE_IMAGE "org.a11y.atspi.Image"
70 #define ATSPI_DBUS_INTERFACE_SELECTION "org.a11y.atspi.Selection"
71 #define ATSPI_DBUS_INTERFACE_TABLE "org.a11y.atspi.Table"
72 #define ATSPI_DBUS_INTERFACE_TEXT "org.a11y.atspi.Text"
73 #define ATSPI_DBUS_INTERFACE_VALUE "org.a11y.atspi.Value"
74 #define ATSPI_DBUS_INTERFACE_SOCKET "org.a11y.atspi.Socket"
75
76 // missing from at-spi2-core:
77 #define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
78 #define ATSPI_DBUS_INTERFACE_EVENT_FOCUS "org.a11y.atspi.Event.Focus"
79
80 #define QSPI_OBJECT_PATH_ACCESSIBLE "/org/a11y/atspi/accessible"
81 #define QSPI_OBJECT_PATH_PREFIX "/org/a11y/atspi/accessible/"
82 #define QSPI_OBJECT_PATH_ROOT QSPI_OBJECT_PATH_PREFIX "root"
83
84 #define QSPI_REGISTRY_NAME "org.a11y.atspi.Registry"
85
86 //#define ATSPI_DEBUG
87
88 using namespace QAccessibleClient;
89
90 QString RegistryPrivate::ACCESSIBLE_OBJECT_SCHEME_STRING = QLatin1String("accessibleobject");
91
RegistryPrivate(Registry * qq)92 RegistryPrivate::RegistryPrivate(Registry *qq)
93 :q(qq)
94 , m_subscriptions(Registry::NoEventListeners)
95 , m_cache(nullptr)
96 {
97 qDBusRegisterMetaType<QVector<quint32> >();
98
99 connect(&conn, SIGNAL(connectionFetched()), this, SLOT(connectionFetched()));
100 connect(&m_actionMapper, SIGNAL(mapped(QString)), this, SLOT(actionTriggered(QString)));
101 init();
102 }
103
init()104 void RegistryPrivate::init()
105 {
106 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_CACHE)] = AccessibleObject::CacheInterface;
107 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE)] = AccessibleObject::AccessibleInterface;
108 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_ACTION)] = AccessibleObject::ActionInterface;
109 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION)] = AccessibleObject::ApplicationInterface;
110 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_COLLECTION)] = AccessibleObject::CollectionInterface;
111 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT)] = AccessibleObject::ComponentInterface;
112 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_DOCUMENT)] = AccessibleObject::DocumentInterface;
113 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT)] = AccessibleObject::EditableTextInterface;
114 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD)] = AccessibleObject::EventKeyboardInterface;
115 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_MOUSE)] = AccessibleObject::EventMouseInterface;
116 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT)] = AccessibleObject::EventObjectInterface;
117 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_HYPERLINK)] = AccessibleObject::HyperlinkInterface;
118 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_HYPERTEXT)] = AccessibleObject::HypertextInterface;
119 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_IMAGE)] = AccessibleObject::ImageInterface;
120 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_SELECTION)] = AccessibleObject::SelectionInterface;
121 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_TABLE)] = AccessibleObject::TableInterface;
122 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_TEXT)] = AccessibleObject::TextInterface;
123 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_VALUE)] = AccessibleObject::ValueInterface;
124 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_SOCKET)] = AccessibleObject::SocketInterface;
125 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW)] = AccessibleObject::EventWindowInterface;
126 interfaceHash[QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_FOCUS)] = AccessibleObject::EventFocusInterface;
127 }
128
isEnabled() const129 bool RegistryPrivate::isEnabled() const
130 {
131 if (conn.status() != DBusConnection::Connected)
132 return false;
133 QDBusMessage message = QDBusMessage::createMethodCall(
134 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
135 message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("IsEnabled"));
136 QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(message);
137 if (!reply.isValid())
138 return false;
139 return reply.value().toBool();
140 }
141
setEnabled(bool enable)142 void RegistryPrivate::setEnabled(bool enable)
143 {
144 QDBusMessage message = QDBusMessage::createMethodCall(
145 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Set"));
146 message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("IsEnabled") << QVariant::fromValue(QDBusVariant(enable)));
147 QDBusMessage reply = QDBusConnection::sessionBus().call(message);
148 if (reply.type() == QDBusMessage::ErrorMessage) {
149 qWarning() << "Could not set org.a11y.Status.isEnabled." << reply.errorName() << reply.errorMessage();
150 }
151 }
152
isScreenReaderEnabled() const153 bool RegistryPrivate::isScreenReaderEnabled() const
154 {
155 if (conn.status() != DBusConnection::Connected)
156 return false;
157 QDBusMessage message = QDBusMessage::createMethodCall(
158 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
159 message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("ScreenReaderEnabled"));
160 QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(message);
161 if (!reply.isValid())
162 return false;
163 return reply.value().toBool();
164 }
165
setScreenReaderEnabled(bool enable)166 void RegistryPrivate::setScreenReaderEnabled(bool enable)
167 {
168 QDBusMessage message = QDBusMessage::createMethodCall(
169 QLatin1String("org.a11y.Bus"), QLatin1String("/org/a11y/bus"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Set"));
170 message.setArguments(QVariantList() << QLatin1String("org.a11y.Status") << QLatin1String("ScreenReaderEnabled") << QVariant::fromValue(QDBusVariant(enable)));
171 QDBusMessage reply = QDBusConnection::sessionBus().call(message);
172 if (reply.type() == QDBusMessage::ErrorMessage) {
173 qWarning() << "Could not set org.a11y.Status.ScreenReaderEnabled." << reply.errorName() << reply.errorMessage();
174 }
175 }
176
fromUrl(const QUrl & url) const177 AccessibleObject RegistryPrivate::fromUrl(const QUrl &url) const
178 {
179 Q_ASSERT(url.scheme() == ACCESSIBLE_OBJECT_SCHEME_STRING);
180 if (url.scheme() != ACCESSIBLE_OBJECT_SCHEME_STRING)
181 return AccessibleObject();
182 QString path = url.path();
183 QString service = url.fragment();
184 return accessibleFromPath(service, path);
185 }
186
connectionFetched()187 void RegistryPrivate::connectionFetched()
188 {
189 Q_ASSERT(conn.status() == DBusConnection::Connected);
190
191 QDBusConnection session = QDBusConnection::sessionBus();
192 if (session.isConnected()) {
193 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)));
194 if (!connected)
195 qWarning() << Q_FUNC_INFO << "Failed to connect with signal org.a11y.Status.PropertiesChanged on org.a11y.Bus";
196 }
197
198 if (m_pendingSubscriptions > 0) {
199 subscribeEventListeners(m_pendingSubscriptions);
200 m_pendingSubscriptions = nullptr;
201 }
202 }
203
subscribeEventListeners(const Registry::EventListeners & listeners)204 void RegistryPrivate::subscribeEventListeners(const Registry::EventListeners &listeners)
205 {
206 if (conn.isFetchingConnection()) {
207 m_pendingSubscriptions = listeners;
208 return;
209 }
210
211 Registry::EventListeners addedListeners = listeners & ~m_subscriptions;
212 Registry::EventListeners removedListeners = m_subscriptions & ~listeners;
213
214 QStringList newSubscriptions;
215 QStringList removedSubscriptions;
216
217 if (removedListeners.testFlag(Registry::Window)) {
218 removedSubscriptions << QLatin1String("window:");
219 } else if (addedListeners.testFlag(Registry::Window)) {
220 // subscribe all window events
221 newSubscriptions << QLatin1String("window:");
222
223 bool created = conn.connection().connect(
224 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Create"),
225 this, SLOT(slotWindowCreate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
226 bool destroyed = conn.connection().connect(
227 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Destroy"),
228 this, SLOT(slotWindowDestroy(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
229
230 bool closed = conn.connection().connect(
231 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Close"),
232 this, SLOT(slotWindowClose(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
233 bool reparented = conn.connection().connect(
234 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Reparent"),
235 this, SLOT(slotWindowReparent(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
236
237 bool minimized = conn.connection().connect(
238 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Minimize"),
239 this, SLOT(slotWindowMinimize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
240 bool maximized = conn.connection().connect(
241 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Maximize"),
242 this, SLOT(slotWindowMaximize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
243 bool restored = conn.connection().connect(
244 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Restore"),
245 this, SLOT(slotWindowRestore(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
246
247 bool activated = conn.connection().connect(
248 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Activate"),
249 this, SLOT(slotWindowActivate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
250 bool deactivated = conn.connection().connect(
251 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Deactivate"),
252 this, SLOT(slotWindowDeactivate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
253
254 bool desktopCreated = conn.connection().connect(
255 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("DesktopCreate"),
256 this, SLOT(slotWindowDesktopCreate(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
257 bool desktopDestroyed = conn.connection().connect(
258 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("DesktopDestroy"),
259 this, SLOT(slotWindowDesktopDestroy(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
260 bool raised = conn.connection().connect(
261 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Raise"),
262 this, SLOT(slotWindowRaise(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
263 bool lowered = conn.connection().connect(
264 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Lower"),
265 this, SLOT(slotWindowLower(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
266 bool moved = conn.connection().connect(
267 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Move"),
268 this, SLOT(slotWindowMove(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
269 bool resized = conn.connection().connect(
270 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Resize"),
271 this, SLOT(slotWindowResize(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
272 bool shaded = conn.connection().connect(
273 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Shade"),
274 this, SLOT(slotWindowShade(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
275 bool unshaded = conn.connection().connect(
276 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Window"), QLatin1String("Unshade"),
277 this, SLOT(slotWindowUnshade(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
278
279 if (!created || !destroyed || !closed || !reparented || !minimized || !maximized || !restored ||
280 !activated || !deactivated || !desktopCreated || !desktopDestroyed ||
281 !raised || !lowered || !moved || !resized || !shaded || !unshaded
282 ) {
283 qWarning() << "Could not subscribe to Window event(s)."
284 << "created:" << created << "destroyed:" << destroyed
285 << "closed:" << closed << "reparented:" << reparented
286 << "minimized:" << minimized << "maximized:" << maximized << "restored:" << restored
287 << "activated:" << activated << "deactivated:" << deactivated
288 << "desktopCreated:" << desktopCreated << "desktopDestroyed:" << desktopDestroyed
289 << "raised:" << raised << "lowered:" << lowered
290 << "moved:" << moved << "resized:" << resized
291 << "shaded:" << shaded << "unshaded:" << unshaded
292 ;
293 }
294 }
295
296 if (removedListeners.testFlag(Registry::ChildrenChanged)) {
297 removedSubscriptions << QLatin1String("object:children-changed");
298 } else if (addedListeners.testFlag(Registry::ChildrenChanged)) {
299 newSubscriptions << QLatin1String("object:children-changed");
300 bool success = conn.connection().connect(
301 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("ChildrenChanged"),
302 this, SLOT(slotChildrenChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
303 if (!success) qWarning() << "Could not subscribe to accessibility ChildrenChanged events.";
304 }
305
306 if (removedListeners.testFlag(Registry::VisibleDataChanged)) {
307 removedSubscriptions << QLatin1String("object:visibledata-changed");
308 } else if (addedListeners.testFlag(Registry::VisibleDataChanged)) {
309 newSubscriptions << QLatin1String("object:visibledata-changed");
310 bool success = conn.connection().connect(
311 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("VisibleDataChanged"),
312 this, SLOT(slotVisibleDataChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
313 if (!success) qWarning() << "Could not subscribe to accessibility VisibleDataChanged events.";
314 }
315
316 if (removedListeners.testFlag(Registry::SelectionChanged)) {
317 removedSubscriptions << QLatin1String("object:selection-changed");
318 } else if (addedListeners.testFlag(Registry::SelectionChanged)) {
319 newSubscriptions << QLatin1String("object:selection-changed");
320 bool success = conn.connection().connect(
321 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("SelectionChanged"),
322 this, SLOT(slotSelectionChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
323 if (!success) qWarning() << "Could not subscribe to accessibility SelectionChanged events.";
324 }
325
326
327 if (removedListeners.testFlag(Registry::ModelChanged)) {
328 removedSubscriptions << QLatin1String("object:model-changed");
329 } else if (addedListeners.testFlag(Registry::ModelChanged)) {
330 newSubscriptions << QLatin1String("object:model-changed");
331 bool success = conn.connection().connect(
332 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("ModelChanged"),
333 this, SLOT(slotModelChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
334 if (!success) qWarning() << "Could not subscribe to accessibility ModelChanged events.";
335 }
336
337 // we need state-changed-focus for focus events
338 if ((removedListeners.testFlag(Registry::StateChanged) || removedListeners.testFlag(Registry::Focus))
339 && (!(addedListeners.testFlag(Registry::StateChanged) || addedListeners.testFlag(Registry::Focus)))) {
340 removedSubscriptions << QLatin1String("object:state-changed");
341 } else if (addedListeners.testFlag(Registry::StateChanged) || addedListeners.testFlag(Registry::Focus)) {
342 if (listeners.testFlag(Registry::Focus)) newSubscriptions << QLatin1String("focus:");
343 newSubscriptions << QLatin1String("object:state-changed");
344 bool success = conn.connection().connect(
345 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("StateChanged"),
346 this, SLOT(slotStateChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
347 if (!success) qWarning() << "Could not subscribe to accessibility Focus events.";
348 }
349
350 if (removedListeners.testFlag(Registry::TextChanged)) {
351 removedSubscriptions << QLatin1String("object:text-changed");
352 } else if (addedListeners.testFlag(Registry::TextChanged)) {
353 newSubscriptions << QLatin1String("object:text-changed");
354 bool success = conn.connection().connect(
355 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextChanged"),
356 this, SLOT(slotTextChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
357 if (!success) qWarning() << "Could not subscribe to accessibility TextChanged events.";
358 }
359
360 if (removedListeners.testFlag(Registry::TextCaretMoved)) {
361 removedSubscriptions << QLatin1String("object:text-caret-moved");
362 } else if (addedListeners.testFlag(Registry::TextCaretMoved)) {
363 newSubscriptions << QLatin1String("object:text-caret-moved");
364 bool success = conn.connection().connect(
365 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextCaretMoved"),
366 this, SLOT(slotTextCaretMoved(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
367 if (!success) qWarning() << "Could not subscribe to accessibility TextCaretMoved events.";
368 }
369
370 if (removedListeners.testFlag(Registry::TextSelectionChanged)) {
371 removedSubscriptions << QLatin1String("object:text-selection-changed");
372 } else if (addedListeners.testFlag(Registry::TextSelectionChanged)) {
373 newSubscriptions << QLatin1String("object:text-selection-changed");
374 bool success = conn.connection().connect(
375 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("TextSelectionChanged"),
376 this, SLOT(slotTextSelectionChanged(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
377 if (!success) qWarning() << "Could not subscribe to accessibility TextSelectionChanged events.";
378 }
379
380 if (removedListeners.testFlag(Registry::PropertyChanged)) {
381 removedSubscriptions << QLatin1String("object:property-change");
382 } else if (addedListeners.testFlag(Registry::PropertyChanged )) {
383 newSubscriptions << QLatin1String("object:property-change");
384 bool success = conn.connection().connect(
385 QString(), QLatin1String(""), QLatin1String("org.a11y.atspi.Event.Object"), QLatin1String("PropertyChange"),
386 this, SLOT(slotPropertyChange(QString,int,int,QDBusVariant,QAccessibleClient::QSpiObjectReference)));
387 if (!success) qWarning() << "Could not subscribe to accessibility PropertyChange events.";
388 }
389
390 Q_FOREACH(const QString &subscription, newSubscriptions) {
391 QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
392 QLatin1String("/org/a11y/atspi/registry"),
393 QLatin1String("org.a11y.atspi.Registry"), QLatin1String("RegisterEvent"));
394 m.setArguments(QVariantList() << subscription);
395
396 QDBusPendingCall async = conn.connection().asyncCall(m);
397 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
398 QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(slotSubscribeEventListenerFinished(QDBusPendingCallWatcher*)));
399 }
400
401 Q_FOREACH(const QString &subscription, removedSubscriptions) {
402 QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
403 QLatin1String("/org/a11y/atspi/registry"),
404 QLatin1String("org.a11y.atspi.Registry"), QLatin1String("DeregisterEvent"));
405 m.setArguments(QVariantList() << subscription);
406 conn.connection().asyncCall(m);
407 }
408
409 m_subscriptions = listeners;
410
411 // accerciser
412 // (u':1.7', u'Object:StateChanged:'),
413 // (u':1.7', u'Object:BoundsChanged:'),
414 // (u':1.7', u'Object:VisibleDataChanged:'),
415 // (u':1.7', u'Object:StateChanged:'),
416 // orca
417 // [(u':1.8', u'Object:ChildrenChanged:'),
418 // (u':1.8', u'Mouse:Button:'),
419 // (u':1.8', u'Mouse:Abs:'),
420 // (u':1.8', u'Object:StateChanged:Selected'),
421 // (u':1.8', u'Object:StateChanged:Expanded'),
422 // (u':1.8', u'Object:ValueChanged:'),
423 // (u':1.8', u'Object:StateChanged:Focused'),
424 // (u':1.8', u'Object:StateChanged:Active'),
425 // (u':1.8', u'Window:Create:'),
426 // (u':1.8', u'Object:TextAttributesChanged:'),
427 // (u':1.8', u'Object:TextCaretMoved:'),
428 // (u':1.8', u'Object:SelectionChanged:'),
429 // (u':1.8', u'Focus::'),
430 // (u':1.8', u'Object:ActiveDescendantChanged:'),
431 // (u':1.8', u'Object:PropertyChange:AccessibleName'),
432 // (u':1.8', u'Window:Activate:'),
433 // (u':1.8', u'Window:Deactivate:'),
434 // (u':1.8', u'Mouse:Button:'),
435 // (u':1.8', u'Object:StateChanged:Indeterminate'),
436 // (u':1.8', u'Object:LinkSelected:'),
437 // (u':1.8', u'Object:TextChanged:Insert'),
438 // (u':1.8', u'Object:PropertyChange:AccessibleValue'),
439 // (u':1.8', u'Object:TextSelectionChanged:'),
440 // // (u':1.8', u'Object:StateChanged:Showing'),
441 // (u':1.8', u'Object:TextChanged:Delete'),
442 // (u':1.8', u'Object:StateChanged:Pressed'),
443 // (u':1.8', u'Object:StateChanged:Checked'),
444 // (u':1.8', u'Object:ChildrenChanged:Remove')]
445
446 }
447
eventListeners() const448 Registry::EventListeners RegistryPrivate::eventListeners() const
449 {
450 return m_subscriptions | m_pendingSubscriptions;
451 }
452
slotSubscribeEventListenerFinished(QDBusPendingCallWatcher * call)453 void RegistryPrivate::slotSubscribeEventListenerFinished(QDBusPendingCallWatcher *call)
454 {
455 if (call->isError()) {
456 qWarning() << "Could not subscribe to accessibility event: " << call->error().type() << call->error().message();
457 }
458 call->deleteLater();
459 }
460
a11yConnectionChanged(const QString & interface,const QVariantMap & changedProperties,const QStringList & invalidatedProperties)461 void RegistryPrivate::a11yConnectionChanged(const QString &interface,const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
462 {
463 //qDebug() << Q_FUNC_INFO << "interface=" << interface << "changedProperties=" << changedProperties << "invalidatedProperties=" << invalidatedProperties;
464 if (conn.status() != DBusConnection::Connected)
465 return;
466 if (interface == QLatin1String("org.a11y.Status")) {
467 QVariantMap::ConstIterator IsEnabledIt = changedProperties.constFind(QLatin1String("IsEnabled"));
468 if (IsEnabledIt != changedProperties.constEnd())
469 emit q->enabledChanged(IsEnabledIt.value().toBool());
470 else if (invalidatedProperties.contains(QLatin1String("IsEnabled")))
471 emit q->enabledChanged(isEnabled());
472
473 QVariantMap::ConstIterator ScreenReaderEnabledIt = changedProperties.constFind(QLatin1String("ScreenReaderEnabled"));
474 if (ScreenReaderEnabledIt != changedProperties.constEnd())
475 emit q->screenReaderEnabledChanged(ScreenReaderEnabledIt.value().toBool());
476 else if (invalidatedProperties.contains(QLatin1String("ScreenReaderEnabled")))
477 emit q->screenReaderEnabledChanged(isScreenReaderEnabled());
478 }
479 }
480
parentAccessible(const AccessibleObject & object) const481 AccessibleObject RegistryPrivate::parentAccessible(const AccessibleObject &object) const
482 {
483 QVariant parent = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Parent"));
484 if (!parent.isValid())
485 return AccessibleObject();
486 const QDBusArgument arg = parent.value<QDBusArgument>();
487 QSpiObjectReference ref;
488 arg >> ref;
489
490 if (ref.path.path() == object.d->path) {
491 qWarning() << "WARNING: Accessible claims to be its own parent: " << object;
492 return AccessibleObject();
493 }
494
495 if (ref.service.isEmpty() || ref.path.path().isEmpty())
496 return AccessibleObject();
497
498 return AccessibleObject(const_cast<RegistryPrivate*>(this), ref.service, ref.path.path());
499 }
500
childCount(const AccessibleObject & object) const501 int RegistryPrivate::childCount(const AccessibleObject &object) const
502 {
503 QVariant childCount = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("ChildCount"));
504 return childCount.toInt();
505 }
506
indexInParent(const AccessibleObject & object) const507 int RegistryPrivate::indexInParent(const AccessibleObject &object) const
508 {
509 QDBusMessage message = QDBusMessage::createMethodCall (
510 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetIndexInParent"));
511
512 QDBusReply<int> reply = conn.connection().call(message);
513 if (!reply.isValid()) {
514 QDBusReply<uint> reply2 = conn.connection().call(message);
515 if (reply2.isValid()) {
516 qWarning() << "Found old api returning uint in GetIndexInParent." << reply.error().message();
517 return static_cast<int>(reply.value());
518 }
519 qWarning() << "Could not access index in parent." << reply.error().message();
520 return -1;
521 }
522 return reply.value();
523 }
524
child(const AccessibleObject & object,int index) const525 AccessibleObject RegistryPrivate::child(const AccessibleObject &object, int index) const
526 {
527 QDBusMessage message = QDBusMessage::createMethodCall (
528 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetChildAtIndex"));
529 QVariantList args;
530 args << index;
531 message.setArguments(args);
532
533 QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
534 if (!reply.isValid()) {
535 qWarning() << "Could not access child." << reply.error().message();
536 return AccessibleObject();
537 }
538 const QSpiObjectReference child = reply.value();
539 return AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path());
540 }
541
children(const AccessibleObject & object) const542 QList<AccessibleObject> RegistryPrivate::children(const AccessibleObject &object) const
543 {
544 QList<AccessibleObject> accs;
545
546 QDBusMessage message = QDBusMessage::createMethodCall (
547 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetChildren"));
548
549 QDBusReply<QSpiObjectReferenceList> reply = conn.connection().call(message, QDBus::Block, 500);
550 if (!reply.isValid()) {
551 qWarning() << "Could not access children." << reply.error().message();
552 return accs;
553 }
554
555 const QSpiObjectReferenceList children = reply.value();
556 Q_FOREACH(const QSpiObjectReference &child, children) {
557 accs.append(AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path()));
558 }
559
560 return accs;
561 }
562
topLevelAccessibles() const563 QList<AccessibleObject> RegistryPrivate::topLevelAccessibles() const
564 {
565 QString service = QLatin1String("org.a11y.atspi.Registry");
566 QString path = QLatin1String("/org/a11y/atspi/accessible/root");
567 return children(AccessibleObject(const_cast<RegistryPrivate*>(this), service, path));
568 }
569
name(const AccessibleObject & object) const570 QString RegistryPrivate::name(const AccessibleObject &object) const
571 {
572 if (!object.isValid())
573 return QString();
574 return getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Name")).toString();
575 }
576
description(const AccessibleObject & object) const577 QString RegistryPrivate::description(const AccessibleObject &object) const
578 {
579 if (!object.isValid())
580 return QString();
581 return getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("Description")).toString();
582 }
583
role(const AccessibleObject & object) const584 AccessibleObject::Role RegistryPrivate::role(const AccessibleObject &object) const
585 {
586 if (!object.isValid())
587 return AccessibleObject::NoRole;
588
589 QDBusMessage message = QDBusMessage::createMethodCall (
590 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetRole"));
591
592 QDBusReply<uint> reply = conn.connection().call(message);
593 if (!reply.isValid()) {
594 qWarning() << "Could not access role." << reply.error().message();
595 return AccessibleObject::NoRole;
596 }
597 return atspiRoleToRole(static_cast<AtspiRole>(reply.value()));
598 }
599
atspiRoleToRole(AtspiRole role)600 AccessibleObject::Role RegistryPrivate::atspiRoleToRole(AtspiRole role)
601 {
602 switch (role) {
603 case ATSPI_ROLE_INVALID: return AccessibleObject::NoRole;
604 // case ATSPI_ROLE_ACCELERATOR_LABEL: return AccessibleObject::;
605 // case ATSPI_ROLE_ALERT: return AccessibleObject::;
606 // case ATSPI_ROLE_ANIMATION: return AccessibleObject::;
607 // case ATSPI_ROLE_ARROW: return AccessibleObject::;
608 // case ATSPI_ROLE_CALENDAR: return AccessibleObject::;
609 // case ATSPI_ROLE_CANVAS: return AccessibleObject::;
610 case ATSPI_ROLE_CHECK_BOX: return AccessibleObject::CheckBox;
611 case ATSPI_ROLE_CHECK_MENU_ITEM: return AccessibleObject::CheckableMenuItem;
612 // case ATSPI_ROLE_COLOR_CHOOSER: return AccessibleObject::;
613 case ATSPI_ROLE_COLUMN_HEADER: return AccessibleObject::ColumnHeader;
614 case ATSPI_ROLE_COMBO_BOX: return AccessibleObject::ComboBox;
615 // case ATSPI_ROLE_DATE_EDITOR: return AccessibleObject::;
616 // case ATSPI_ROLE_DESKTOP_ICON: return AccessibleObject::;
617 case ATSPI_ROLE_DESKTOP_FRAME: return AccessibleObject::DesktopFrame;
618 // case ATSPI_ROLE_DIAL: return AccessibleObject::;
619 case ATSPI_ROLE_DIALOG: return AccessibleObject::Dialog;
620 // case ATSPI_ROLE_DIRECTORY_PANE: return AccessibleObject::;
621 // case ATSPI_ROLE_DRAWING_AREA: return AccessibleObject::;
622 // case ATSPI_ROLE_FILE_CHOOSER: return AccessibleObject::;
623 case ATSPI_ROLE_FILLER: return AccessibleObject::Filler;
624 // case ATSPI_ROLE_FOCUS_TRAVERSABLE: return AccessibleObject::;
625 // case ATSPI_ROLE_FONT_CHOOSER: return AccessibleObject::;
626 case ATSPI_ROLE_FRAME: return AccessibleObject::Frame;
627 // case ATSPI_ROLE_GLASS_PANE: return AccessibleObject::;
628 // case ATSPI_ROLE_HTML_CONTAINER: return AccessibleObject::;
629 case ATSPI_ROLE_ICON: return AccessibleObject::Icon;
630 // case ATSPI_ROLE_IMAGE: return AccessibleObject::;
631 // case ATSPI_ROLE_INTERNAL_FRAME: return AccessibleObject::;
632 case ATSPI_ROLE_LABEL: return AccessibleObject::Label;
633 // case ATSPI_ROLE_LAYERED_PANE: return AccessibleObject::;
634 case ATSPI_ROLE_LIST: return AccessibleObject::ListView;
635 case ATSPI_ROLE_LIST_ITEM: return AccessibleObject::ListItem;
636 case ATSPI_ROLE_MENU: return AccessibleObject::Menu;
637 case ATSPI_ROLE_MENU_BAR: return AccessibleObject::MenuBar;
638 case ATSPI_ROLE_MENU_ITEM: return AccessibleObject::MenuItem;
639 // case ATSPI_ROLE_OPTION_PANE: return AccessibleObject::;
640 case ATSPI_ROLE_PAGE_TAB: return AccessibleObject::Tab;
641 case ATSPI_ROLE_PAGE_TAB_LIST: return AccessibleObject::TabContainer;
642 // case ATSPI_ROLE_PANEL: return AccessibleObject::;
643 case ATSPI_ROLE_PASSWORD_TEXT: return AccessibleObject::PasswordText;
644 case ATSPI_ROLE_POPUP_MENU: return AccessibleObject::PopupMenu;
645 case ATSPI_ROLE_PROGRESS_BAR: return AccessibleObject::ProgressBar;
646 case ATSPI_ROLE_PUSH_BUTTON: return AccessibleObject::Button;
647 case ATSPI_ROLE_RADIO_BUTTON: return AccessibleObject::RadioButton;
648 case ATSPI_ROLE_RADIO_MENU_ITEM: return AccessibleObject::RadioMenuItem;
649 // case ATSPI_ROLE_ROOT_PANE: return AccessibleObject::;
650 case ATSPI_ROLE_ROW_HEADER: return AccessibleObject::RowHeader;
651 case ATSPI_ROLE_SCROLL_BAR: return AccessibleObject::ScrollBar;
652 case ATSPI_ROLE_SCROLL_PANE: return AccessibleObject::ScrollArea;
653 case ATSPI_ROLE_SEPARATOR: return AccessibleObject::Separator;
654 case ATSPI_ROLE_SLIDER: return AccessibleObject::Slider;
655 case ATSPI_ROLE_SPIN_BUTTON: return AccessibleObject::SpinButton;
656 // case ATSPI_ROLE_SPLIT_PANE: return AccessibleObject::;
657 case ATSPI_ROLE_STATUS_BAR: return AccessibleObject::StatusBar;
658 case ATSPI_ROLE_TABLE: return AccessibleObject::TableView;
659 case ATSPI_ROLE_TABLE_CELL: return AccessibleObject::TableCell;
660 case ATSPI_ROLE_TABLE_COLUMN_HEADER: return AccessibleObject::TableColumnHeader;
661 case ATSPI_ROLE_TABLE_ROW_HEADER: return AccessibleObject::TableRowHeader;
662 // case ATSPI_ROLE_TEAROFF_MENU_ITEM: return AccessibleObject::;
663 case ATSPI_ROLE_TERMINAL: return AccessibleObject::Terminal;
664 case ATSPI_ROLE_TEXT: return AccessibleObject::Text;
665 case ATSPI_ROLE_TOGGLE_BUTTON: return AccessibleObject::ToggleButton;
666 case ATSPI_ROLE_TOOL_BAR: return AccessibleObject::ToolBar;
667 case ATSPI_ROLE_TOOL_TIP: return AccessibleObject::ToolTip;
668 case ATSPI_ROLE_TREE: return AccessibleObject::TreeView;
669 case ATSPI_ROLE_TREE_TABLE: return AccessibleObject::TreeView;
670 case ATSPI_ROLE_UNKNOWN: return AccessibleObject::NoRole;
671 // case ATSPI_ROLE_VIEWPORT: return AccessibleObject::;
672 case ATSPI_ROLE_WINDOW: return AccessibleObject::Window;
673 // case ATSPI_ROLE_EXTENDED: return AccessibleObject::;
674 // case ATSPI_ROLE_HEADER: return AccessibleObject::;
675 // case ATSPI_ROLE_FOOTER: return AccessibleObject::;
676 // case ATSPI_ROLE_PARAGRAPH: return AccessibleObject::;
677 // case ATSPI_ROLE_RULER: return AccessibleObject::;
678 // case ATSPI_ROLE_APPLICATION: return AccessibleObject::;
679 // case ATSPI_ROLE_AUTOCOMPLETE: return AccessibleObject::;
680 // case ATSPI_ROLE_EDITBAR: return AccessibleObject::;
681 // case ATSPI_ROLE_EMBEDDED: return AccessibleObject::;
682 // case ATSPI_ROLE_ENTRY: return AccessibleObject::;
683 // case ATSPI_ROLE_CHART: return AccessibleObject::;
684 // case ATSPI_ROLE_CAPTION: return AccessibleObject::;
685 // case ATSPI_ROLE_DOCUMENT_FRAME: return AccessibleObject::;
686 // case ATSPI_ROLE_HEADING: return AccessibleObject::;
687 // case ATSPI_ROLE_PAGE: return AccessibleObject::;
688 // case ATSPI_ROLE_SECTION: return AccessibleObject::;
689 // case ATSPI_ROLE_REDUNDANT_OBJECT: return AccessibleObject::;
690 // case ATSPI_ROLE_FORM: return AccessibleObject::;
691 // case ATSPI_ROLE_LINK: return AccessibleObject::;
692 // case ATSPI_ROLE_INPUT_METHOD_WINDOW: return AccessibleObject::;
693 case ATSPI_ROLE_TABLE_ROW: return AccessibleObject::TableRow;
694 case ATSPI_ROLE_TREE_ITEM: return AccessibleObject::TreeItem;
695 // case ATSPI_ROLE_DOCUMENT_SPREADSHEET: return AccessibleObject::;
696 // case ATSPI_ROLE_DOCUMENT_PRESENTATION: return AccessibleObject::;
697 // case ATSPI_ROLE_DOCUMENT_TEXT: return AccessibleObject::;
698 // case ATSPI_ROLE_DOCUMENT_WEB: return AccessibleObject::;
699 // case ATSPI_ROLE_DOCUMENT_EMAIL: return AccessibleObject::;
700 // case ATSPI_ROLE_COMMENT: return AccessibleObject::;
701 // case ATSPI_ROLE_LIST_BOX: return AccessibleObject::;
702 // case ATSPI_ROLE_GROUPING: return AccessibleObject::;
703 // case ATSPI_ROLE_IMAGE_MAP: return AccessibleObject::;
704 // case ATSPI_ROLE_NOTIFICATION: return AccessibleObject::;
705 // case ATSPI_ROLE_INFO_BAR: return AccessibleObject::;
706 // case ATSPI_ROLE_LAST_DEFINED: return AccessibleObject::;
707 }
708 return AccessibleObject::NoRole;
709 }
710
roleName(const AccessibleObject & object) const711 QString RegistryPrivate::roleName(const AccessibleObject &object) const
712 {
713 QDBusMessage message = QDBusMessage::createMethodCall (
714 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetRoleName"));
715
716 QDBusReply<QString> reply = conn.connection().call(message);
717 if (!reply.isValid()) {
718 qWarning() << "Could not access roleName." << reply.error().message();
719 return QString();
720 }
721 return reply.value();
722 }
723
localizedRoleName(const AccessibleObject & object) const724 QString RegistryPrivate::localizedRoleName(const AccessibleObject &object) const
725 {
726 QDBusMessage message = QDBusMessage::createMethodCall (
727 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetLocalizedRoleName"));
728
729 QDBusReply<QString> reply = conn.connection().call(message);
730 if (!reply.isValid()) {
731 qWarning() << "Could not access localizedRoleName." << reply.error().message();\
732 return QString();
733 }
734 return reply.value();
735 }
736
state(const AccessibleObject & object) const737 quint64 RegistryPrivate::state(const AccessibleObject &object) const
738 {
739 if (m_cache) {
740 quint64 cachedValue = m_cache->state(object);
741 if (cachedValue != QAccessibleClient::ObjectCache::StateNotFound)
742 return cachedValue;
743 }
744
745 QDBusMessage message = QDBusMessage::createMethodCall (
746 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetState"));
747
748 QDBusReply<QVector<quint32> > reply = conn.connection().call(message);
749 if (!reply.isValid()) {
750 qWarning() << "Could not access state." << reply.error().message();
751 return 0;
752 }
753 if (reply.value().size() < 2) {
754 qWarning() << "Did not receive expected reply.";
755 return 0;
756 }
757 quint32 low = reply.value().at(0);
758 quint32 high = reply.value().at(1);
759 quint64 state = low + (static_cast<quint64>(high) << 32);
760
761 if (m_cache) {
762 m_cache->setState(object, state);
763 }
764
765 return state;
766 }
767
layer(const AccessibleObject & object) const768 int RegistryPrivate::layer(const AccessibleObject &object) const
769 {
770 QDBusMessage message = QDBusMessage::createMethodCall (
771 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetLayer"));
772 QDBusReply<uint> reply = conn.connection().call(message);
773 if (!reply.isValid()) {
774 qWarning() << "Could not access layer." << reply.error().message();
775 return 1;
776 }
777 return reply.value();
778 }
779
mdiZOrder(const AccessibleObject & object) const780 int RegistryPrivate::mdiZOrder(const AccessibleObject &object) const
781 {
782 QDBusMessage message = QDBusMessage::createMethodCall (
783 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetMDIZOrder"));
784 QDBusReply<short> reply = conn.connection().call(message);
785 if (!reply.isValid()) {
786 qWarning() << "Could not access mdiZOrder." << reply.error().message();
787 return 0;
788 }
789 return reply.value();
790 }
791
alpha(const AccessibleObject & object) const792 double RegistryPrivate::alpha(const AccessibleObject &object) const
793 {
794 QDBusMessage message = QDBusMessage::createMethodCall (
795 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetAlpha"));
796 QDBusReply<double> reply = conn.connection().call(message);
797 if (!reply.isValid()) {
798 qWarning() << "Could not access alpha." << reply.error().message();
799 return 1.0;
800 }
801 return reply.value();
802 }
803
boundingRect(const AccessibleObject & object) const804 QRect RegistryPrivate::boundingRect(const AccessibleObject &object) const
805 {
806 QDBusMessage message = QDBusMessage::createMethodCall(
807 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Component"), QLatin1String("GetExtents") );
808 QVariantList args;
809 quint32 coords = ATSPI_COORD_TYPE_SCREEN;
810 args << coords;
811 message.setArguments(args);
812
813 QDBusReply< QRect > reply = conn.connection().call(message);
814 if(!reply.isValid()){
815 qWarning() << "Could not get extents." << reply.error().message();
816 return QRect();
817 }
818
819 return QRect( reply.value() );
820 }
821
characterRect(const AccessibleObject & object,int offset) const822 QRect RegistryPrivate::characterRect(const AccessibleObject &object, int offset) const
823 {
824 QDBusMessage message = QDBusMessage::createMethodCall(
825 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"),
826 QLatin1String("GetCharacterExtents"));
827
828 QVariantList args;
829 quint32 coords = ATSPI_COORD_TYPE_SCREEN;
830 args << offset;
831 args << coords;
832 message.setArguments(args);
833
834
835 QDBusReply< QRect > reply = conn.connection().call(message);
836 if(!reply.isValid()){
837 if (reply.error().type() == QDBusError::InvalidSignature) {
838 QDBusMessage reply2 = conn.connection().call(message);
839 if (reply2.signature() != QLatin1String("iiii")) {
840 qWarning() << "Could not get Character Extents. " << reply.error().message();
841 return QRect();
842 }
843 QList<QVariant> args = reply2.arguments();
844 QRect rect(args.at(0).toInt(), args.at(1).toInt(), args.at(2).toInt(), args.at(3).toInt());
845 return rect;
846 }
847 }
848
849 return reply.value();
850 }
851
supportedInterfaces(const AccessibleObject & object) const852 AccessibleObject::Interfaces RegistryPrivate::supportedInterfaces(const AccessibleObject &object) const
853 {
854 if (m_cache) {
855 AccessibleObject::Interfaces interfaces = m_cache->interfaces(object);
856 if (!(interfaces & AccessibleObject::InvalidInterface))
857 return interfaces;
858 }
859
860 QDBusMessage message = QDBusMessage::createMethodCall(
861 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"),
862 QLatin1String("GetInterfaces"));
863
864 QDBusReply<QStringList > reply = conn.connection().call(message);
865 if(!reply.isValid()){
866 qWarning() << "Could not get Interfaces. " << reply.error().message();
867 return AccessibleObject::NoInterface;
868 }
869
870 AccessibleObject::Interfaces interfaces = AccessibleObject::NoInterface;
871 Q_FOREACH(const QString &interface, reply.value()){
872 interfaces |= interfaceHash[interface];
873 }
874
875 if (m_cache) {
876 m_cache->setInterfaces(object, interfaces);
877 }
878
879 return interfaces;
880 }
881
caretOffset(const AccessibleObject & object) const882 int RegistryPrivate::caretOffset(const AccessibleObject &object) const
883 {
884 QVariant offset= getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("CaretOffset"));
885 if (offset.isNull()) qWarning() << "Could not get caret offset";
886 return offset.toInt();
887 }
888
characterCount(const AccessibleObject & object) const889 int RegistryPrivate::characterCount(const AccessibleObject &object) const
890 {
891 QVariant count = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("CharacterCount"));
892 if (count.isNull()) qWarning() << "Could not get character count";
893 return count.toInt();
894 }
895
textSelections(const AccessibleObject & object) const896 QList< QPair<int,int> > RegistryPrivate::textSelections(const AccessibleObject &object) const
897 {
898 QList< QPair<int,int> > result;
899 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetNSelections"));
900 QDBusReply<int> reply = conn.connection().call(message);
901 if (!reply.isValid()) {
902 qWarning() << "Could not access GetNSelections." << reply.error().message();
903 return result;
904 }
905 int count = reply.value();
906 for(int i = 0; i < count; ++i) {
907 QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetSelection"));
908 m.setArguments(QVariantList() << i);
909 m = conn.connection().call(m);
910 QList<QVariant> args = m.arguments();
911 if (args.count() < 2) {
912 qWarning() << "Invalid number of arguments. Expected=2 Actual=" << args.count();
913 continue;
914 }
915 int startOffset = args[0].toInt();
916 int endOffset = args[1].toInt();
917 if (startOffset > endOffset)
918 qSwap(startOffset, endOffset);
919 result.append(qMakePair(startOffset, endOffset));
920 }
921 return result;
922 }
923
setTextSelections(const AccessibleObject & object,const QList<QPair<int,int>> & selections)924 void RegistryPrivate::setTextSelections(const AccessibleObject &object, const QList< QPair<int,int> > &selections)
925 {
926 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetNSelections"));
927 QDBusReply<int> reply = conn.connection().call(message);
928 if (!reply.isValid()) {
929 qWarning() << "Could not access GetNSelections." << reply.error().message();
930 return;
931 }
932 int count = reply.value();
933 int setSel = qMin(selections.count(), count);
934 for(int i = 0; i < setSel; ++i) {
935 Q_ASSERT(i < selections.count());
936 QPair<int,int> p = selections[i];
937 QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("SetSelection"));
938 m.setArguments(QVariantList() << i << p.first << p.second);
939 QDBusReply<bool> r = conn.connection().call(m);
940 if (!r.isValid()) {
941 qWarning() << "Failed call text.SetSelection." << r.error().message();
942 continue;
943 }
944 }
945 int removeSel = qMax(0, count - selections.count());
946 for(int i = 0, k = selections.count(); i < removeSel; ++i, ++k) {
947 QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("RemoveSelection"));
948 m.setArguments(QVariantList() << k);
949 QDBusReply<bool> r = conn.connection().call(m);
950 if (!r.isValid()) {
951 qWarning() << "Failed call text.RemoveSelection." << r.error().message();
952 continue;
953 }
954 }
955 int addSel = qMax(0, selections.count() - count);
956 for(int i = 0, k = count; i < addSel; ++i, ++k) {
957 Q_ASSERT(k < selections.count());
958 QPair<int,int> p = selections[k];
959 QDBusMessage m = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("AddSelection"));
960 m.setArguments(QVariantList() << p.first << p.second);
961 QDBusReply<bool> r = conn.connection().call(m);
962 if (!r.isValid()) {
963 qWarning() << "Failed call text.AddSelection." << r.error().message();
964 continue;
965 }
966 }
967 }
968
text(const AccessibleObject & object,int startOffset,int endOffset) const969 QString RegistryPrivate::text(const AccessibleObject &object, int startOffset, int endOffset) const
970 {
971 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetText"));
972 message.setArguments(QVariantList() << startOffset << endOffset);
973 QDBusReply<QString> reply = conn.connection().call(message);
974 if (!reply.isValid()) {
975 qWarning() << "Could not access text." << reply.error().message();
976 return QString();
977 }
978 return reply.value();
979 }
980
textWithBoundary(const AccessibleObject & object,int offset,AccessibleObject::TextBoundary boundary,int * startOffset,int * endOffset) const981 QString RegistryPrivate::textWithBoundary(const AccessibleObject &object, int offset, AccessibleObject::TextBoundary boundary, int *startOffset, int *endOffset) const
982 {
983 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Text"), QLatin1String("GetTextAtOffset"));
984 message.setArguments(QVariantList() << offset << static_cast<AtspiTextBoundaryType>(boundary));
985 QDBusMessage reply = conn.connection().call(message);
986 if (reply.type() != QDBusMessage::ReplyMessage || reply.signature() != QStringLiteral("sii")) {
987 qWarning() << "Could not access text." << reply.errorMessage();
988 if (startOffset)
989 *startOffset = 0;
990 if (endOffset)
991 *endOffset = 0;
992 return QString();
993 }
994 if (startOffset)
995 *startOffset = reply.arguments().at(1).toInt();
996 if (endOffset)
997 *endOffset = reply.arguments().at(2).toInt();
998 return reply.arguments().first().toString();;
999 }
1000
setText(const AccessibleObject & object,const QString & text)1001 bool RegistryPrivate::setText(const AccessibleObject &object, const QString &text)
1002 {
1003 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("SetTextContents"));
1004 message.setArguments(QVariantList() << text);
1005 QDBusReply<bool> reply = conn.connection().call(message);
1006 if (!reply.isValid()) {
1007 qWarning() << "Could not set text." << reply.error().message();
1008 return false;
1009 }
1010 return reply.value();
1011 }
1012
insertText(const AccessibleObject & object,const QString & text,int position,int length)1013 bool RegistryPrivate::insertText(const AccessibleObject &object, const QString &text, int position, int length)
1014 {
1015 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("InsertText"));
1016 message.setArguments(QVariantList() << position << text << length);
1017 QDBusReply<bool> reply = conn.connection().call(message);
1018 if (!reply.isValid()) {
1019 qWarning() << "Could not insert text." << reply.error().message();
1020 return false;
1021 }
1022 return reply.value();
1023 }
1024
copyText(const AccessibleObject & object,int startPos,int endPos)1025 bool RegistryPrivate::copyText(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("CopyText"));
1028 message.setArguments(QVariantList() << startPos << endPos);
1029 conn.connection().call(message);
1030 return true;
1031 }
1032
cutText(const AccessibleObject & object,int startPos,int endPos)1033 bool RegistryPrivate::cutText(const AccessibleObject &object, int startPos, int endPos)
1034 {
1035 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("CutText"));
1036 message.setArguments(QVariantList() << startPos << endPos);
1037 QDBusReply<bool> reply = conn.connection().call(message);
1038 if (!reply.isValid()) {
1039 qWarning() << "Could not cut text." << reply.error().message();
1040 return false;
1041 }
1042 return reply.value();
1043 }
1044
deleteText(const AccessibleObject & object,int startPos,int endPos)1045 bool RegistryPrivate::deleteText(const AccessibleObject &object, int startPos, int endPos)
1046 {
1047 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("DeleteText"));
1048 message.setArguments(QVariantList() << startPos << endPos);
1049 QDBusReply<bool> reply = conn.connection().call(message);
1050 if (!reply.isValid()) {
1051 qWarning() << "Could not delete text." << reply.error().message();
1052 return false;
1053 }
1054 return reply.value();
1055 }
1056
pasteText(const AccessibleObject & object,int position)1057 bool RegistryPrivate::pasteText(const AccessibleObject &object, int position)
1058 {
1059 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.EditableText"), QLatin1String("PasteText"));
1060 message.setArguments(QVariantList() << position);
1061 QDBusReply<bool> reply = conn.connection().call(message);
1062 if (!reply.isValid()) {
1063 qWarning() << "Could not paste text." << reply.error().message();
1064 return false;
1065 }
1066 return reply.value();
1067 }
1068
application(const AccessibleObject & object) const1069 AccessibleObject RegistryPrivate::application(const AccessibleObject &object) const
1070 {
1071 QDBusMessage message = QDBusMessage::createMethodCall(
1072 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Accessible"), QLatin1String("GetApplication"));
1073 QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
1074 if (!reply.isValid()) {
1075 qWarning() << "Could not access application." << reply.error().message();
1076 return AccessibleObject();
1077 }
1078 const QSpiObjectReference child = reply.value();
1079 return AccessibleObject(const_cast<RegistryPrivate*>(this), child.service, child.path.path());
1080 }
1081
appToolkitName(const AccessibleObject & object) const1082 QString RegistryPrivate::appToolkitName(const AccessibleObject &object) const
1083 {
1084 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("ToolkitName"));
1085 return v.toString();
1086 }
1087
appVersion(const AccessibleObject & object) const1088 QString RegistryPrivate::appVersion(const AccessibleObject &object) const
1089 {
1090 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("Version"));
1091 return v.toString();
1092 }
1093
appId(const AccessibleObject & object) const1094 int RegistryPrivate::appId(const AccessibleObject &object) const
1095 {
1096 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("Id"));
1097 return v.toInt();
1098 }
1099
appLocale(const AccessibleObject & object,uint lctype) const1100 QString RegistryPrivate::appLocale(const AccessibleObject &object, uint lctype) const
1101 {
1102 // 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
1103 if (object.d->service == QLatin1String(":1.0"))
1104 return QString();
1105
1106 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("GetLocale"));
1107
1108 QVariantList args;
1109 args.append(lctype);
1110 message.setArguments(args);
1111
1112 QDBusReply<QString> reply = conn.connection().call(message, QDBus::Block, 500);
1113 if (!reply.isValid()) {
1114 qWarning() << "Could not access appLocale." << reply.error().message();
1115 return QString();
1116 }
1117 return reply.value();
1118 }
1119
appBusAddress(const AccessibleObject & object) const1120 QString RegistryPrivate::appBusAddress(const AccessibleObject &object) const
1121 {
1122 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Application"), QLatin1String("GetApplicationBusAddress"));
1123 QDBusReply<QString> reply = conn.connection().call(message);
1124 if (!reply.isValid()) {
1125 qWarning() << Q_FUNC_INFO << "Could not access application bus address. Error: " << reply.error().message() << " in response to: " << message;
1126 return QString();
1127 }
1128 return reply.value();
1129 }
1130
minimumValue(const AccessibleObject & object) const1131 double RegistryPrivate::minimumValue(const AccessibleObject &object) const
1132 {
1133 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MinimumValue"));
1134 return v.toDouble();
1135 }
1136
maximumValue(const AccessibleObject & object) const1137 double RegistryPrivate::maximumValue(const AccessibleObject &object) const
1138 {
1139 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MaximumValue"));
1140 return v.toDouble();
1141 }
1142
minimumValueIncrement(const AccessibleObject & object) const1143 double RegistryPrivate::minimumValueIncrement(const AccessibleObject &object) const
1144 {
1145 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("MinimumIncrement"));
1146 return v.toDouble();
1147 }
1148
currentValue(const AccessibleObject & object) const1149 double RegistryPrivate::currentValue(const AccessibleObject &object) const
1150 {
1151 QVariant v = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("CurrentValue"));
1152 return v.toDouble();
1153 }
1154
setCurrentValue(const AccessibleObject & object,double value)1155 bool RegistryPrivate::setCurrentValue(const AccessibleObject &object, double value)
1156 {
1157 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Value"), QLatin1String("SetCurrentValue"));
1158
1159 QVariantList arguments;
1160 arguments << QLatin1String("org.a11y.atspi.Value") << QLatin1String("CurrentValue");
1161 arguments << QVariant::fromValue(QDBusVariant(value));
1162 message.setArguments(arguments);
1163
1164 QDBusReply<bool> reply = conn.connection().call(message);
1165 if (!reply.isValid()) {
1166 qWarning() << "Could not set text." << reply.error().message();
1167 return false;
1168 }
1169 return reply.value();
1170 }
1171
selection(const AccessibleObject & object) const1172 QList<AccessibleObject> RegistryPrivate::selection(const AccessibleObject &object) const
1173 {
1174 QList<AccessibleObject> result;
1175 int count = getProperty(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Selection"), QLatin1String("CurrentValue")).toInt();
1176 for(int i = 0; i < count; ++i) {
1177 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Selection"), QLatin1String("GetSelectedChild"));
1178 QDBusReply<QSpiObjectReference> reply = conn.connection().call(message);
1179 if (!reply.isValid()) {
1180 qWarning() << "Could not access selection." << reply.error().message();
1181 return QList<AccessibleObject>();
1182 }
1183 const QSpiObjectReference ref = reply.value();
1184 result.append(AccessibleObject(const_cast<RegistryPrivate*>(this), ref.service, ref.path.path()));
1185 }
1186 return result;
1187 }
1188
imageDescription(const AccessibleObject & object) const1189 QString RegistryPrivate::imageDescription(const AccessibleObject &object) const
1190 {
1191 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("ImageDescription"));
1192 QDBusReply<QString> reply = conn.connection().call(message);
1193 if (!reply.isValid()) {
1194 qWarning() << "Could not access imageDescription." << reply.error().message();
1195 return QString();
1196 }
1197 return reply.value();
1198 }
1199
imageLocale(const AccessibleObject & object) const1200 QString RegistryPrivate::imageLocale(const AccessibleObject &object) const
1201 {
1202 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("ImageLocale"));
1203 QDBusReply<QString> reply = conn.connection().call(message, QDBus::Block, 500);
1204 if (!reply.isValid()) {
1205 qWarning() << "Could not access imageLocale." << reply.error().message();
1206 return QString();
1207 }
1208 return reply.value();
1209 }
1210
imageRect(const AccessibleObject & object) const1211 QRect RegistryPrivate::imageRect(const AccessibleObject &object) const
1212 {
1213 QDBusMessage message = QDBusMessage::createMethodCall(object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Image"), QLatin1String("GetImageExtents"));
1214 QVariantList args;
1215 quint32 coords = ATSPI_COORD_TYPE_SCREEN;
1216 args << coords;
1217 message.setArguments(args);
1218 QDBusReply<QRect> reply = conn.connection().call(message);
1219 if (!reply.isValid()) {
1220 qWarning() << "Could not access imageRect." << reply.error().message();
1221 return QRect();
1222 }
1223 return QRect( reply.value() );
1224 }
1225
actions(const AccessibleObject & object)1226 QVector< QSharedPointer<QAction> > RegistryPrivate::actions(const AccessibleObject &object)
1227 {
1228 QDBusMessage message = QDBusMessage::createMethodCall (
1229 object.d->service, object.d->path, QLatin1String("org.a11y.atspi.Action"), QLatin1String("GetActions"));
1230
1231 QDBusReply<QSpiActionArray> reply = conn.connection().call(message, QDBus::Block, 500);
1232 if (!reply.isValid()) {
1233 qWarning() << "Could not access actions." << reply.error().message();
1234 return QVector< QSharedPointer<QAction> >();
1235 }
1236
1237 QSpiActionArray actionArray = reply.value();
1238 QVector< QSharedPointer<QAction> > list;
1239 for(int i = 0; i < actionArray.count(); ++i) {
1240 const QSpiAction &a = actionArray[i];
1241 QAction *action = new QAction();
1242 QString id = QString(QLatin1String("%1;%2;%3")).arg(object.d->service).arg(object.d->path).arg(i);
1243 action->setObjectName(id);
1244 action->setText(a.name);
1245 action->setWhatsThis(a.description);
1246 QKeySequence shortcut(a.keyBinding);
1247 action->setShortcut(shortcut);
1248 m_actionMapper.setMapping(action, id);
1249 connect(action, SIGNAL(triggered()), &m_actionMapper, SLOT(map()));
1250 list.append(QSharedPointer<QAction>(action));
1251 }
1252 return list;
1253 }
1254
actionTriggered(const QString & action)1255 void RegistryPrivate::actionTriggered(const QString &action)
1256 {
1257 QStringList actionParts = action.split(QLatin1Char(';'));
1258 Q_ASSERT(actionParts.count() == 3);
1259 QString service = actionParts[0];
1260 QString path = actionParts[1];
1261 int index = actionParts[2].toInt();
1262
1263 QDBusMessage message = QDBusMessage::createMethodCall (
1264 service, path, QLatin1String("org.a11y.atspi.Action"), QLatin1String("DoAction"));
1265
1266 QVariantList args;
1267 args << index;
1268 message.setArguments(args);
1269
1270 QDBusReply<bool> reply = conn.connection().call(message, QDBus::Block, 500);
1271 if (!reply.isValid()) {
1272 qWarning() << "Could not execute action=" << action << reply.error().message();
1273 return;
1274 }
1275
1276 if (reply.value()) {
1277 qDebug() << "Successful executed action=" << action;
1278 } else {
1279 qWarning() << "Failed to execute action=" << action;
1280 }
1281 }
1282
getProperty(const QString & service,const QString & path,const QString & interface,const QString & name) const1283 QVariant RegistryPrivate::getProperty(const QString &service, const QString &path, const QString &interface, const QString &name) const
1284 {
1285 QVariantList args;
1286 args.append(interface);
1287 args.append(name);
1288
1289 QDBusMessage message = QDBusMessage::createMethodCall (
1290 service, path, QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
1291
1292 message.setArguments(args);
1293 QDBusMessage reply = conn.connection().call(message, QDBus::Block, 500);
1294 if (reply.arguments().isEmpty())
1295 return QVariant();
1296
1297 QDBusVariant v = reply.arguments().at(0).value<QDBusVariant>();
1298 return v.variant();
1299 }
1300
accessibleFromPath(const QString & service,const QString & path) const1301 AccessibleObject RegistryPrivate::accessibleFromPath(const QString &service, const QString &path) const
1302 {
1303 return AccessibleObject(const_cast<RegistryPrivate*>(this), service, path);
1304 }
1305
accessibleFromReference(const QSpiObjectReference & reference) const1306 AccessibleObject RegistryPrivate::accessibleFromReference(const QSpiObjectReference &reference) const
1307 {
1308 return accessibleFromPath(reference.service, reference.path.path());
1309 }
1310
accessibleFromContext() const1311 AccessibleObject RegistryPrivate::accessibleFromContext() const
1312 {
1313 return accessibleFromPath(QDBusContext::message().service(), QDBusContext::message().path());
1314 }
1315
slotWindowCreate(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference &)1316 void RegistryPrivate::slotWindowCreate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &)
1317 {
1318 emit q->windowCreated(accessibleFromContext());
1319 }
1320
slotWindowDestroy(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1321 void RegistryPrivate::slotWindowDestroy(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1322 {
1323 emit q->windowDestroyed(accessibleFromContext());
1324 }
1325
slotWindowClose(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1326 void RegistryPrivate::slotWindowClose(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1327 {
1328 emit q->windowClosed(accessibleFromContext());
1329 }
1330
slotWindowReparent(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1331 void RegistryPrivate::slotWindowReparent(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1332 {
1333 emit q->windowReparented(accessibleFromContext());
1334 }
1335
slotWindowMinimize(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1336 void RegistryPrivate::slotWindowMinimize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1337 {
1338 emit q->windowMinimized(accessibleFromContext());
1339 }
1340
slotWindowMaximize(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1341 void RegistryPrivate::slotWindowMaximize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1342 {
1343 emit q->windowMaximized(accessibleFromContext());
1344 }
1345
slotWindowRestore(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1346 void RegistryPrivate::slotWindowRestore(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1347 {
1348 emit q->windowRestored(accessibleFromContext());
1349 }
1350
slotWindowActivate(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1351 void RegistryPrivate::slotWindowActivate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1352 {
1353 emit q->windowActivated(accessibleFromContext());
1354 }
1355
slotWindowDeactivate(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1356 void RegistryPrivate::slotWindowDeactivate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1357 {
1358 emit q->windowDeactivated(accessibleFromContext());
1359 }
1360
slotWindowDesktopCreate(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1361 void RegistryPrivate::slotWindowDesktopCreate(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1362 {
1363 emit q->windowDesktopCreated(accessibleFromContext());
1364 }
1365
slotWindowDesktopDestroy(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1366 void RegistryPrivate::slotWindowDesktopDestroy(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1367 {
1368 emit q->windowDesktopDestroyed(accessibleFromContext());
1369 }
1370
slotWindowRaise(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1371 void RegistryPrivate::slotWindowRaise(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1372 {
1373 emit q->windowRaised(accessibleFromContext());
1374 }
1375
slotWindowLower(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1376 void RegistryPrivate::slotWindowLower(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1377 {
1378 emit q->windowLowered(accessibleFromContext());
1379 }
1380
slotWindowMove(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1381 void RegistryPrivate::slotWindowMove(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1382 {
1383 emit q->windowMoved(accessibleFromContext());
1384 }
1385
slotWindowResize(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1386 void RegistryPrivate::slotWindowResize(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1387 {
1388 emit q->windowResized(accessibleFromContext());
1389 }
1390
slotWindowShade(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1391 void RegistryPrivate::slotWindowShade(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1392 {
1393 emit q->windowShaded(accessibleFromContext());
1394 }
1395
slotWindowUnshade(const QString & state,int detail1,int detail2,const QDBusVariant &,const QAccessibleClient::QSpiObjectReference & reference)1396 void RegistryPrivate::slotWindowUnshade(const QString &state, int detail1, int detail2, const QDBusVariant &/*args*/, const QAccessibleClient::QSpiObjectReference &reference)
1397 {
1398 emit q->windowUnshaded(accessibleFromContext());
1399 }
1400
slotPropertyChange(const QString & property,int detail1,int detail2,const QDBusVariant & args,const QSpiObjectReference & reference)1401 void RegistryPrivate::slotPropertyChange(const QString &property, int detail1, int detail2, const QDBusVariant &args, const QSpiObjectReference &reference)
1402 {
1403 #ifdef ATSPI_DEBUG
1404 qDebug() << Q_FUNC_INFO << property << detail1 << detail2 << args.variant() << reference.path.path();
1405 #endif
1406 if (property == QLatin1String("accessible-name")) {
1407 emit q->accessibleNameChanged(accessibleFromContext());
1408 } else if (property == QLatin1String("accessible-description")) {
1409 emit q->accessibleDescriptionChanged(accessibleFromContext());
1410 }
1411 }
1412
slotStateChanged(const QString & state,int detail1,int detail2,const QDBusVariant & object,const QSpiObjectReference & reference)1413 void RegistryPrivate::slotStateChanged(const QString &state, int detail1, int detail2, const QDBusVariant &object, const QSpiObjectReference &reference)
1414 {
1415 //qDebug() << Q_FUNC_INFO << state << detail1 << detail2 << reference.service << reference.path.path() << QDBusContext::message();
1416
1417 if (state == QLatin1String("defunct") && (detail1 == 1)) {
1418 QSpiObjectReference removed;
1419 removed.service = QDBusContext::message().service();
1420 removed.path = QDBusObjectPath(QDBusContext::message().path());
1421 removeAccessibleObject(removed);
1422 return;
1423 }
1424
1425 AccessibleObject accessible = accessibleFromContext();
1426 if (m_cache) {
1427 m_cache->cleanState(accessible);
1428 }
1429
1430 if (state == QLatin1String("focused") && (detail1 == 1) &&
1431 (q->subscribedEventListeners().testFlag(Registry::Focus))) {
1432 emit q->focusChanged(accessible);
1433 }
1434
1435 if (q->subscribedEventListeners().testFlag(Registry::StateChanged)) {
1436 emit q->stateChanged(accessible, state, detail1 == 1);
1437 }
1438 }
1439
1440 // void RegistryPrivate::slotLinkSelected(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1441 // {
1442 // emit q->linkSelected(accessibleFromContext());
1443 // }
1444
removeAccessibleObject(const QAccessibleClient::AccessibleObject & accessible)1445 bool RegistryPrivate::removeAccessibleObject(const QAccessibleClient::AccessibleObject &accessible)
1446 {
1447 Q_ASSERT(accessible.isValid());
1448 if (m_cache) {
1449 const QString id = accessible.id();
1450 if (m_cache->remove(id)) {
1451 emit q->removed(accessible);
1452 }
1453 } else {
1454 emit q->removed(accessible);
1455 }
1456 if (accessible.d)
1457 accessible.d->setDefunct();
1458 return true;
1459 }
1460
removeAccessibleObject(const QAccessibleClient::QSpiObjectReference & reference)1461 bool RegistryPrivate::removeAccessibleObject(const QAccessibleClient::QSpiObjectReference &reference)
1462 {
1463 QAccessibleClient::AccessibleObject acc = accessibleFromReference(reference);
1464 if (acc.isValid()) {
1465 if (removeAccessibleObject(acc))
1466 return true;
1467 }
1468 return false;
1469 }
1470
slotChildrenChanged(const QString & state,int detail1,int detail2,const QDBusVariant & args,const QAccessibleClient::QSpiObjectReference & reference)1471 void RegistryPrivate::slotChildrenChanged(const QString &state, int detail1, int detail2, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1472 {
1473 // qDebug() << Q_FUNC_INFO << state << detail1 << detail2 << args.variant() << reference.path.path();
1474 QAccessibleClient::AccessibleObject parentAccessible = accessibleFromContext();
1475 if (!parentAccessible.isValid()) {
1476 qWarning() << Q_FUNC_INFO << "Children change with invalid parent." << reference.path.path();
1477 return;
1478 }
1479
1480 int index = detail1;
1481 if (state == QLatin1String("add")) {
1482 emit q->childAdded(parentAccessible, index);
1483 } else if (state == QLatin1String("remove")) {
1484 emit q->childRemoved(parentAccessible, index);
1485 } else {
1486 qWarning() << "Invalid state in ChildrenChanged." << state;
1487 }
1488 }
1489
slotVisibleDataChanged(const QString &,int,int,const QDBusVariant & args,const QAccessibleClient::QSpiObjectReference & reference)1490 void RegistryPrivate::slotVisibleDataChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1491 {
1492 emit q->visibleDataChanged(accessibleFromContext());
1493 }
1494
slotSelectionChanged(const QString &,int,int,const QDBusVariant & args,const QAccessibleClient::QSpiObjectReference & reference)1495 void RegistryPrivate::slotSelectionChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1496 {
1497 emit q->selectionChanged(accessibleFromContext());
1498 }
1499
slotModelChanged(const QString &,int,int,const QDBusVariant & args,const QAccessibleClient::QSpiObjectReference & reference)1500 void RegistryPrivate::slotModelChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &args, const QAccessibleClient::QSpiObjectReference &reference)
1501 {
1502 emit q->modelChanged(accessibleFromContext());
1503 }
1504
slotTextCaretMoved(const QString &,int detail1,int,const QDBusVariant &,const QSpiObjectReference & reference)1505 void RegistryPrivate::slotTextCaretMoved(const QString &/*state*/, int detail1, int /*detail2*/, const QDBusVariant &/*args*/, const QSpiObjectReference &reference)
1506 {
1507 emit q->textCaretMoved(accessibleFromContext(), detail1);
1508 }
1509
slotTextSelectionChanged(const QString &,int,int,const QDBusVariant &,const QSpiObjectReference & reference)1510 void RegistryPrivate::slotTextSelectionChanged(const QString &/*state*/, int /*detail1*/, int /*detail2*/, const QDBusVariant &/*args*/, const QSpiObjectReference &reference)
1511 {
1512 emit q->textSelectionChanged(accessibleFromContext());
1513 }
1514
slotTextChanged(const QString & change,int start,int end,const QDBusVariant & textVariant,const QSpiObjectReference & reference)1515 void RegistryPrivate::slotTextChanged(const QString &change, int start, int end, const QDBusVariant &textVariant, const QSpiObjectReference &reference)
1516 {
1517 AccessibleObject object(accessibleFromContext());
1518 QString text = textVariant.variant().toString();
1519
1520 if (change == QLatin1String("insert")) {
1521 emit q->textInserted(object, text, start, end);
1522 } else if (change == QLatin1String("remove")) {
1523 emit q->textRemoved(object, text, start, end);
1524 } else {
1525 emit q->textChanged(object, text, start, end);
1526 }
1527 }
1528
1529 #include "moc_registry_p.cpp"
1530