Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
atspiadaptor.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "atspiadaptor_p.h"
6
7#include <QtGui/qwindow.h>
8#include <QtGui/qguiapplication.h>
9#include <qdbusmessage.h>
10#include <qdbusreply.h>
11#include <qclipboard.h>
12
13#include <QtCore/qloggingcategory.h>
14#include <QtCore/qtversion.h>
15
16#if QT_CONFIG(accessibility)
17#include "socket_interface.h"
19#include <QtCore/private/qstringiterator_p.h>
20#include <QtGui/private/qaccessiblebridgeutils_p.h>
21
33// ATSPI_COORD_TYPE_PARENT was added in at-spi 2.30, define here for older versions
34#if ATSPI_COORD_TYPE_COUNT < 3
35#define ATSPI_COORD_TYPE_PARENT 2
36#endif
37
38// ATSPI_*_VERSION defines were added in libatspi 2.50,
39// as was the AtspiLive enum; define values here for older versions
40#if !defined(ATSPI_MAJOR_VERSION) || !defined(ATSPI_MINOR_VERSION) || ATSPI_MAJOR_VERSION < 2 || ATSPI_MINOR_VERSION < 50
41#define ATSPI_LIVE_POLITE 1
42#define ATSPI_LIVE_ASSERTIVE 2
43#endif
44
46
47using namespace Qt::StringLiterals;
48
49Q_LOGGING_CATEGORY(lcAccessibilityAtspi, "qt.accessibility.atspi")
50Q_LOGGING_CATEGORY(lcAccessibilityAtspiCreation, "qt.accessibility.atspi.creation")
51
53 : QDBusVirtualObject(parent), m_dbus(connection)
54 , sendFocus(0)
55 , sendObject(0)
56 , sendObject_active_descendant_changed(0)
57 , sendObject_announcement(0)
58 , sendObject_attributes_changed(0)
59 , sendObject_bounds_changed(0)
60 , sendObject_children_changed(0)
61// , sendObject_children_changed_add(0)
62// , sendObject_children_changed_remove(0)
63 , sendObject_column_deleted(0)
64 , sendObject_column_inserted(0)
65 , sendObject_column_reordered(0)
66 , sendObject_link_selected(0)
67 , sendObject_model_changed(0)
68 , sendObject_property_change(0)
69 , sendObject_property_change_accessible_description(0)
70 , sendObject_property_change_accessible_name(0)
71 , sendObject_property_change_accessible_parent(0)
72 , sendObject_property_change_accessible_role(0)
73 , sendObject_property_change_accessible_table_caption(0)
74 , sendObject_property_change_accessible_table_column_description(0)
75 , sendObject_property_change_accessible_table_column_header(0)
76 , sendObject_property_change_accessible_table_row_description(0)
77 , sendObject_property_change_accessible_table_row_header(0)
78 , sendObject_property_change_accessible_table_summary(0)
79 , sendObject_property_change_accessible_value(0)
80 , sendObject_row_deleted(0)
81 , sendObject_row_inserted(0)
82 , sendObject_row_reordered(0)
83 , sendObject_selection_changed(0)
84 , sendObject_state_changed(0)
85 , sendObject_text_attributes_changed(0)
86 , sendObject_text_bounds_changed(0)
87 , sendObject_text_caret_moved(0)
88 , sendObject_text_changed(0)
89// , sendObject_text_changed_delete(0)
90// , sendObject_text_changed_insert(0)
91 , sendObject_text_selection_changed(0)
92 , sendObject_value_changed(0)
93 , sendObject_visible_data_changed(0)
94 , sendWindow(0)
95 , sendWindow_activate(0)
96 , sendWindow_close(0)
97 , sendWindow_create(0)
98 , sendWindow_deactivate(0)
99// , sendWindow_desktop_create(0)
100// , sendWindow_desktop_destroy(0)
101 , sendWindow_lower(0)
102 , sendWindow_maximize(0)
103 , sendWindow_minimize(0)
104 , sendWindow_move(0)
105 , sendWindow_raise(0)
106 , sendWindow_reparent(0)
107 , sendWindow_resize(0)
108 , sendWindow_restore(0)
109 , sendWindow_restyle(0)
110 , sendWindow_shade(0)
111 , sendWindow_unshade(0)
112{
113 m_applicationAdaptor = new QSpiApplicationAdaptor(m_dbus->connection(), this);
114 connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,bool)), this, SLOT(windowActivated(QObject*,bool)));
115
116 updateEventListeners();
117 bool success = m_dbus->connection().connect("org.a11y.atspi.Registry"_L1, "/org/a11y/atspi/registry"_L1,
118 "org.a11y.atspi.Registry"_L1, "EventListenerRegistered"_L1, this,
119 SLOT(eventListenerRegistered(QString,QString)));
120 success = success && m_dbus->connection().connect("org.a11y.atspi.Registry"_L1, "/org/a11y/atspi/registry"_L1,
121 "org.a11y.atspi.Registry"_L1, "EventListenerDeregistered"_L1, this,
122 SLOT(eventListenerDeregistered(QString,QString)));
123}
124
126{
127}
128
133{
134 static const QLatin1StringView accessibleIntrospection(
135 " <interface name=\"org.a11y.atspi.Accessible\">\n"
136 " <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
137 " <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
138 " <property access=\"read\" type=\"(so)\" name=\"Parent\">\n"
139 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
140 " </property>\n"
141 " <property access=\"read\" type=\"i\" name=\"ChildCount\"/>\n"
142 " <method name=\"GetChildAtIndex\">\n"
143 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
144 " <arg direction=\"out\" type=\"(so)\"/>\n"
145 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
146 " </method>\n"
147 " <method name=\"GetChildren\">\n"
148 " <arg direction=\"out\" type=\"a(so)\"/>\n"
149 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
150 " </method>\n"
151 " <method name=\"GetIndexInParent\">\n"
152 " <arg direction=\"out\" type=\"i\"/>\n"
153 " </method>\n"
154 " <method name=\"GetRelationSet\">\n"
155 " <arg direction=\"out\" type=\"a(ua(so))\"/>\n"
156 " <annotation value=\"QSpiRelationArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
157 " </method>\n"
158 " <method name=\"GetRole\">\n"
159 " <arg direction=\"out\" type=\"u\"/>\n"
160 " </method>\n"
161 " <method name=\"GetRoleName\">\n"
162 " <arg direction=\"out\" type=\"s\"/>\n"
163 " </method>\n"
164 " <method name=\"GetLocalizedRoleName\">\n"
165 " <arg direction=\"out\" type=\"s\"/>\n"
166 " </method>\n"
167 " <method name=\"GetState\">\n"
168 " <arg direction=\"out\" type=\"au\"/>\n"
169 " <annotation value=\"QSpiUIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
170 " </method>\n"
171 " <method name=\"GetAttributes\">\n"
172 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
173 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
174 " </method>\n"
175 " <method name=\"GetApplication\">\n"
176 " <arg direction=\"out\" type=\"(so)\"/>\n"
177 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
178 " </method>\n"
179 " <method name=\"GetAccessibleId\">\n"
180 " <arg direction=\"out\" type=\"s\"/>\n"
181 " </method>\n"
182 " </interface>\n"
183 );
184
185 static const QLatin1StringView actionIntrospection(
186 " <interface name=\"org.a11y.atspi.Action\">\n"
187 " <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
188 " <method name=\"GetDescription\">\n"
189 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
190 " <arg direction=\"out\" type=\"s\"/>\n"
191 " </method>\n"
192 " <method name=\"GetName\">\n"
193 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
194 " <arg direction=\"out\" type=\"s\"/>\n"
195 " </method>\n"
196 " <method name=\"GetKeyBinding\">\n"
197 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
198 " <arg direction=\"out\" type=\"s\"/>\n"
199 " </method>\n"
200 " <method name=\"GetActions\">\n"
201 " <arg direction=\"out\" type=\"a(sss)\" name=\"index\"/>\n"
202 " <annotation value=\"QSpiActionArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
203 " </method>\n"
204 " <method name=\"DoAction\">\n"
205 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
206 " <arg direction=\"out\" type=\"b\"/>\n"
207 " </method>\n"
208 " </interface>\n"
209 );
210
211 static const QLatin1StringView applicationIntrospection(
212 " <interface name=\"org.a11y.atspi.Application\">\n"
213 " <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
214 " <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
215 " <property access=\"readwrite\" type=\"i\" name=\"Id\"/>\n"
216 " <method name=\"GetLocale\">\n"
217 " <arg direction=\"in\" type=\"u\" name=\"lctype\"/>\n"
218 " <arg direction=\"out\" type=\"s\"/>\n"
219 " </method>\n"
220 " <method name=\"GetApplicationBusAddress\">\n"
221 " <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
222 " </method>\n"
223 " </interface>\n"
224 );
225
226 static const QLatin1StringView componentIntrospection(
227 " <interface name=\"org.a11y.atspi.Component\">\n"
228 " <method name=\"Contains\">\n"
229 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
230 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
231 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
232 " <arg direction=\"out\" type=\"b\"/>\n"
233 " </method>\n"
234 " <method name=\"GetAccessibleAtPoint\">\n"
235 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
236 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
237 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
238 " <arg direction=\"out\" type=\"(so)\"/>\n"
239 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
240 " </method>\n"
241 " <method name=\"GetExtents\">\n"
242 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
243 " <arg direction=\"out\" type=\"(iiii)\"/>\n"
244 " <annotation value=\"QSpiRect\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
245 " </method>\n"
246 " <method name=\"GetPosition\">\n"
247 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
248 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
249 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
250 " </method>\n"
251 " <method name=\"GetSize\">\n"
252 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
253 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
254 " </method>\n"
255 " <method name=\"GetLayer\">\n"
256 " <arg direction=\"out\" type=\"u\"/>\n"
257 " </method>\n"
258 " <method name=\"GetMDIZOrder\">\n"
259 " <arg direction=\"out\" type=\"n\"/>\n"
260 " </method>\n"
261 " <method name=\"GrabFocus\">\n"
262 " <arg direction=\"out\" type=\"b\"/>\n"
263 " </method>\n"
264 " <method name=\"GetAlpha\">\n"
265 " <arg direction=\"out\" type=\"d\"/>\n"
266 " </method>\n"
267 " <method name=\"SetExtents\">\n"
268 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
269 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
270 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
271 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
272 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
273 " <arg direction=\"out\" type=\"b\"/>\n"
274 " </method>\n"
275 " <method name=\"SetPosition\">\n"
276 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
277 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
278 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
279 " <arg direction=\"out\" type=\"b\"/>\n"
280 " </method>\n"
281 " <method name=\"SetSize\">\n"
282 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
283 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
284 " <arg direction=\"out\" type=\"b\"/>\n"
285 " </method>\n"
286 " </interface>\n"
287 );
288
289 static const QLatin1StringView editableTextIntrospection(
290 " <interface name=\"org.a11y.atspi.EditableText\">\n"
291 " <method name=\"SetTextContents\">\n"
292 " <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
293 " <arg direction=\"out\" type=\"b\"/>\n"
294 " </method>\n"
295 " <method name=\"InsertText\">\n"
296 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
297 " <arg direction=\"in\" type=\"s\" name=\"text\"/>\n"
298 " <arg direction=\"in\" type=\"i\" name=\"length\"/>\n"
299 " <arg direction=\"out\" type=\"b\"/>\n"
300 " </method>\n"
301 " <method name=\"CopyText\">\n"
302 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
303 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
304 " </method>\n"
305 " <method name=\"CutText\">\n"
306 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
307 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
308 " <arg direction=\"out\" type=\"b\"/>\n"
309 " </method>\n"
310 " <method name=\"DeleteText\">\n"
311 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
312 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
313 " <arg direction=\"out\" type=\"b\"/>\n"
314 " </method>\n"
315 " <method name=\"PasteText\">\n"
316 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
317 " <arg direction=\"out\" type=\"b\"/>\n"
318 " </method>\n"
319 " </interface>\n"
320 );
321
322 static const QLatin1StringView selectionIntrospection(
323 " <interface name=\"org.a11y.atspi.Selection\">\n"
324 " <property name=\"NSelectedChildren\" type=\"i\" access=\"read\"/>\n"
325 " <method name=\"GetSelectedChild\">\n"
326 " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n"
327 " <arg direction=\"out\" type=\"(so)\"/>\n"
328 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiObjectReference\"/>\n"
329 " </method>\n"
330 " <method name=\"SelectChild\">\n"
331 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
332 " <arg direction=\"out\" type=\"b\"/>\n"
333 " </method>\n"
334 " <method name=\"DeselectSelectedChild\">\n"
335 " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n"
336 " <arg direction=\"out\" type=\"b\"/>\n"
337 " </method>\n"
338 " <method name=\"IsChildSelected\">\n"
339 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
340 " <arg direction=\"out\" type=\"b\"/>\n"
341 " </method>\n"
342 " <method name=\"SelectAll\">\n"
343 " <arg direction=\"out\" type=\"b\"/>\n"
344 " </method>\n"
345 " <method name=\"ClearSelection\">\n"
346 " <arg direction=\"out\" type=\"b\"/>\n"
347 " </method>\n"
348 " <method name=\"DeselectChild\">\n"
349 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
350 " <arg direction=\"out\" type=\"b\"/>\n"
351 " </method>\n"
352 " </interface>\n"
353 );
354
355 static const QLatin1StringView tableIntrospection(
356 " <interface name=\"org.a11y.atspi.Table\">\n"
357 " <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
358 " <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
359 " <property access=\"read\" type=\"(so)\" name=\"Caption\">\n"
360 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
361 " </property>\n"
362 " <property access=\"read\" type=\"(so)\" name=\"Summary\">\n"
363 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
364 " </property>\n"
365 " <property access=\"read\" type=\"i\" name=\"NSelectedRows\"/>\n"
366 " <property access=\"read\" type=\"i\" name=\"NSelectedColumns\"/>\n"
367 " <method name=\"GetAccessibleAt\">\n"
368 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
369 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
370 " <arg direction=\"out\" type=\"(so)\"/>\n"
371 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
372 " </method>\n"
373 " <method name=\"GetIndexAt\">\n"
374 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
375 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
376 " <arg direction=\"out\" type=\"i\"/>\n"
377 " </method>\n"
378 " <method name=\"GetRowAtIndex\">\n"
379 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
380 " <arg direction=\"out\" type=\"i\"/>\n"
381 " </method>\n"
382 " <method name=\"GetColumnAtIndex\">\n"
383 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
384 " <arg direction=\"out\" type=\"i\"/>\n"
385 " </method>\n"
386 " <method name=\"GetRowDescription\">\n"
387 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
388 " <arg direction=\"out\" type=\"s\"/>\n"
389 " </method>\n"
390 " <method name=\"GetColumnDescription\">\n"
391 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
392 " <arg direction=\"out\" type=\"s\"/>\n"
393 " </method>\n"
394 " <method name=\"GetRowExtentAt\">\n"
395 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
396 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
397 " <arg direction=\"out\" type=\"i\"/>\n"
398 " </method>\n"
399 " <method name=\"GetColumnExtentAt\">\n"
400 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
401 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
402 " <arg direction=\"out\" type=\"i\"/>\n"
403 " </method>\n"
404 " <method name=\"GetRowHeader\">\n"
405 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
406 " <arg direction=\"out\" type=\"(so)\"/>\n"
407 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
408 " </method>\n"
409 " <method name=\"GetColumnHeader\">\n"
410 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
411 " <arg direction=\"out\" type=\"(so)\"/>\n"
412 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
413 " </method>\n"
414 " <method name=\"GetSelectedRows\">\n"
415 " <arg direction=\"out\" type=\"ai\"/>\n"
416 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
417 " </method>\n"
418 " <method name=\"GetSelectedColumns\">\n"
419 " <arg direction=\"out\" type=\"ai\"/>\n"
420 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
421 " </method>\n"
422 " <method name=\"IsRowSelected\">\n"
423 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
424 " <arg direction=\"out\" type=\"b\"/>\n"
425 " </method>\n"
426 " <method name=\"IsColumnSelected\">\n"
427 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
428 " <arg direction=\"out\" type=\"b\"/>\n"
429 " </method>\n"
430 " <method name=\"IsSelected\">\n"
431 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
432 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
433 " <arg direction=\"out\" type=\"b\"/>\n"
434 " </method>\n"
435 " <method name=\"AddRowSelection\">\n"
436 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
437 " <arg direction=\"out\" type=\"b\"/>\n"
438 " </method>\n"
439 " <method name=\"AddColumnSelection\">\n"
440 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
441 " <arg direction=\"out\" type=\"b\"/>\n"
442 " </method>\n"
443 " <method name=\"RemoveRowSelection\">\n"
444 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
445 " <arg direction=\"out\" type=\"b\"/>\n"
446 " </method>\n"
447 " <method name=\"RemoveColumnSelection\">\n"
448 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
449 " <arg direction=\"out\" type=\"b\"/>\n"
450 " </method>\n"
451 " <method name=\"GetRowColumnExtentsAtIndex\">\n"
452 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
453 " <arg direction=\"out\" type=\"b\"/>\n"
454 " <arg direction=\"out\" type=\"i\" name=\"row\"/>\n"
455 " <arg direction=\"out\" type=\"i\" name=\"col\"/>\n"
456 " <arg direction=\"out\" type=\"i\" name=\"row_extents\"/>\n"
457 " <arg direction=\"out\" type=\"i\" name=\"col_extents\"/>\n"
458 " <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
459 " </method>\n"
460 " </interface>\n"
461 );
462
463 static const QLatin1StringView tableCellIntrospection(
464 " <interface name=\"org.a11y.atspi.TableCell\">\n"
465 " <property access=\"read\" name=\"ColumnSpan\" type=\"i\" />\n"
466 " <property access=\"read\" name=\"Position\" type=\"(ii)\">\n"
467 " <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QPoint\"/>\n"
468 " </property>\n"
469 " <property access=\"read\" name=\"RowSpan\" type=\"i\" />\n"
470 " <property access=\"read\" name=\"Table\" type=\"(so)\" >\n"
471 " <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QSpiObjectReference\"/>\n"
472 " </property>\n"
473 " <method name=\"GetRowColumnSpan\">\n"
474 " <arg direction=\"out\" type=\"b\" />\n"
475 " <arg direction=\"out\" name=\"row\" type=\"i\" />\n"
476 " <arg direction=\"out\" name=\"col\" type=\"i\" />\n"
477 " <arg direction=\"out\" name=\"row_extents\" type=\"i\" />\n"
478 " <arg direction=\"out\" name=\"col_extents\" type=\"i\" />\n"
479 " </method>\n"
480 " <method name=\"GetColumnHeaderCells\">\n"
481 " <arg direction=\"out\" type=\"a(so)\"/>\n"
482 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
483 " </method>\n"
484 " <method name=\"GetRowHeaderCells\">\n"
485 " <arg direction=\"out\" type=\"a(so)\"/>\n"
486 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
487 " </method>\n"
488 " </interface>\n"
489 );
490
491 static const QLatin1StringView textIntrospection(
492 " <interface name=\"org.a11y.atspi.Text\">\n"
493 " <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
494 " <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
495 " <method name=\"GetStringAtOffset\">\n"
496 " <arg direction=\"in\" name=\"offset\" type=\"i\"/>\n"
497 " <arg direction=\"in\" name=\"granularity\" type=\"u\"/>\n"
498 " <arg direction=\"out\" type=\"s\"/>\n"
499 " <arg direction=\"out\" name=\"startOffset\" type=\"i\"/>\n"
500 " <arg direction=\"out\" name=\"endOffset\" type=\"i\"/>\n"
501 " </method>\n"
502 " <method name=\"GetText\">\n"
503 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
504 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
505 " <arg direction=\"out\" type=\"s\"/>\n"
506 " </method>\n"
507 " <method name=\"SetCaretOffset\">\n"
508 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
509 " <arg direction=\"out\" type=\"b\"/>\n"
510 " </method>\n"
511 " <method name=\"GetTextBeforeOffset\">\n"
512 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
513 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
514 " <arg direction=\"out\" type=\"s\"/>\n"
515 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
516 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
517 " </method>\n"
518 " <method name=\"GetTextAtOffset\">\n"
519 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
520 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
521 " <arg direction=\"out\" type=\"s\"/>\n"
522 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
523 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
524 " </method>\n"
525 " <method name=\"GetTextAfterOffset\">\n"
526 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
527 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
528 " <arg direction=\"out\" type=\"s\"/>\n"
529 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
530 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
531 " </method>\n"
532 " <method name=\"GetCharacterAtOffset\">\n"
533 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
534 " <arg direction=\"out\" type=\"i\"/>\n"
535 " </method>\n"
536 " <method name=\"GetAttributeValue\">\n"
537 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
538 " <arg direction=\"in\" type=\"s\" name=\"attributeName\"/>\n"
539 " <arg direction=\"out\" type=\"s\"/>\n"
540 " </method>\n"
541 " <method name=\"GetAttributes\">\n"
542 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
543 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
544 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
545 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
546 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
547 " </method>\n"
548 " <method name=\"GetDefaultAttributes\">\n"
549 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
550 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
551 " </method>\n"
552 " <method name=\"GetCharacterExtents\">\n"
553 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
554 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
555 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
556 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
557 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
558 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
559 " </method>\n"
560 " <method name=\"GetOffsetAtPoint\">\n"
561 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
562 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
563 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
564 " <arg direction=\"out\" type=\"i\"/>\n"
565 " </method>\n"
566 " <method name=\"GetNSelections\">\n"
567 " <arg direction=\"out\" type=\"i\"/>\n"
568 " </method>\n"
569 " <method name=\"GetSelection\">\n"
570 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
571 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
572 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
573 " </method>\n"
574 " <method name=\"AddSelection\">\n"
575 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
576 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
577 " <arg direction=\"out\" type=\"b\"/>\n"
578 " </method>\n"
579 " <method name=\"RemoveSelection\">\n"
580 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
581 " <arg direction=\"out\" type=\"b\"/>\n"
582 " </method>\n"
583 " <method name=\"SetSelection\">\n"
584 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
585 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
586 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
587 " <arg direction=\"out\" type=\"b\"/>\n"
588 " </method>\n"
589 " <method name=\"GetRangeExtents\">\n"
590 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
591 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
592 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
593 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
594 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
595 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
596 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
597 " </method>\n"
598 " <method name=\"GetBoundedRanges\">\n"
599 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
600 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
601 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
602 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
603 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
604 " <arg direction=\"in\" type=\"u\" name=\"xClipType\"/>\n"
605 " <arg direction=\"in\" type=\"u\" name=\"yClipType\"/>\n"
606 " <arg direction=\"out\" type=\"a(iisv)\"/>\n"
607 " <annotation value=\"QSpiRangeList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
608 " </method>\n"
609 " <method name=\"GetAttributeRun\">\n"
610 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
611 " <arg direction=\"in\" type=\"b\" name=\"includeDefaults\"/>\n"
612 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
613 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
614 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
615 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
616 " </method>\n"
617 " <method name=\"GetDefaultAttributeSet\">\n"
618 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
619 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
620 " </method>\n"
621 " <method name=\"ScrollSubstringTo\">\n"
622 " <arg direction=\"in\" name=\"startOffset\" type=\"i\"/>\n"
623 " <arg direction=\"in\" name=\"endOffset\" type=\"i\"/>\n"
624 " <arg direction=\"in\" name=\"type\" type=\"u\"/>\n"
625 " <arg direction=\"out\" type=\"b\"/>\n"
626 " </method>\n"
627 " </interface>\n"
628 );
629
630 static const QLatin1StringView valueIntrospection(
631 " <interface name=\"org.a11y.atspi.Value\">\n"
632 " <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
633 " <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
634 " <property access=\"read\" type=\"d\" name=\"MinimumIncrement\"/>\n"
635 " <property access=\"readwrite\" type=\"d\" name=\"CurrentValue\"/>\n"
636 " <method name=\"SetCurrentValue\">\n"
637 " <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
638 " </method>\n"
639 " </interface>\n"
640 );
641
642 QAccessibleInterface * interface = interfaceFromPath(path);
643 if (!interface) {
644 qCWarning(lcAccessibilityAtspi) << "Could not find accessible on path:" << path;
645 return QString();
646 }
647
648 QStringList interfaces = accessibleInterfaces(interface);
649
650 QString xml;
651 xml.append(accessibleIntrospection);
652
653 if (interfaces.contains(ATSPI_DBUS_INTERFACE_COMPONENT ""_L1))
654 xml.append(componentIntrospection);
655 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TEXT ""_L1))
656 xml.append(textIntrospection);
657 if (interfaces.contains(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT ""_L1))
658 xml.append(editableTextIntrospection);
659 if (interfaces.contains(ATSPI_DBUS_INTERFACE_ACTION ""_L1))
660 xml.append(actionIntrospection);
661 if (interfaces.contains(ATSPI_DBUS_INTERFACE_SELECTION ""_L1))
662 xml.append(selectionIntrospection);
663 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE ""_L1))
664 xml.append(tableIntrospection);
665 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE_CELL ""_L1))
666 xml.append(tableCellIntrospection);
667 if (interfaces.contains(ATSPI_DBUS_INTERFACE_VALUE ""_L1))
668 xml.append(valueIntrospection);
669 if (path == QSPI_OBJECT_PATH_ROOT ""_L1)
670 xml.append(applicationIntrospection);
671
672 return xml;
673}
674
675void AtSpiAdaptor::setBitFlag(const QString &flag)
676{
677 Q_ASSERT(flag.size());
678
679 // assume we don't get nonsense - look at first letter only
680 switch (flag.at(0).toLower().toLatin1()) {
681 case 'o': {
682 if (flag.size() <= 8) { // Object::
683 sendObject = 1;
684 } else { // Object:Foo:Bar
685 QString right = flag.mid(7);
686 if (false) {
687 } else if (right.startsWith("ActiveDescendantChanged"_L1)) {
688 sendObject_active_descendant_changed = 1;
689 } else if (right.startsWith("Announcement"_L1)) {
690 sendObject_announcement = 1;
691 } else if (right.startsWith("AttributesChanged"_L1)) {
692 sendObject_attributes_changed = 1;
693 } else if (right.startsWith("BoundsChanged"_L1)) {
694 sendObject_bounds_changed = 1;
695 } else if (right.startsWith("ChildrenChanged"_L1)) {
696 sendObject_children_changed = 1;
697 } else if (right.startsWith("ColumnDeleted"_L1)) {
698 sendObject_column_deleted = 1;
699 } else if (right.startsWith("ColumnInserted"_L1)) {
700 sendObject_column_inserted = 1;
701 } else if (right.startsWith("ColumnReordered"_L1)) {
702 sendObject_column_reordered = 1;
703 } else if (right.startsWith("LinkSelected"_L1)) {
704 sendObject_link_selected = 1;
705 } else if (right.startsWith("ModelChanged"_L1)) {
706 sendObject_model_changed = 1;
707 } else if (right.startsWith("PropertyChange"_L1)) {
708 if (right == "PropertyChange:AccessibleDescription"_L1) {
709 sendObject_property_change_accessible_description = 1;
710 } else if (right == "PropertyChange:AccessibleName"_L1) {
711 sendObject_property_change_accessible_name = 1;
712 } else if (right == "PropertyChange:AccessibleParent"_L1) {
713 sendObject_property_change_accessible_parent = 1;
714 } else if (right == "PropertyChange:AccessibleRole"_L1) {
715 sendObject_property_change_accessible_role = 1;
716 } else if (right == "PropertyChange:TableCaption"_L1) {
717 sendObject_property_change_accessible_table_caption = 1;
718 } else if (right == "PropertyChange:TableColumnDescription"_L1) {
719 sendObject_property_change_accessible_table_column_description = 1;
720 } else if (right == "PropertyChange:TableColumnHeader"_L1) {
721 sendObject_property_change_accessible_table_column_header = 1;
722 } else if (right == "PropertyChange:TableRowDescription"_L1) {
723 sendObject_property_change_accessible_table_row_description = 1;
724 } else if (right == "PropertyChange:TableRowHeader"_L1) {
725 sendObject_property_change_accessible_table_row_header = 1;
726 } else if (right == "PropertyChange:TableSummary"_L1) {
727 sendObject_property_change_accessible_table_summary = 1;
728 } else if (right == "PropertyChange:AccessibleValue"_L1) {
729 sendObject_property_change_accessible_value = 1;
730 } else {
731 sendObject_property_change = 1;
732 }
733 } else if (right.startsWith("RowDeleted"_L1)) {
734 sendObject_row_deleted = 1;
735 } else if (right.startsWith("RowInserted"_L1)) {
736 sendObject_row_inserted = 1;
737 } else if (right.startsWith("RowReordered"_L1)) {
738 sendObject_row_reordered = 1;
739 } else if (right.startsWith("SelectionChanged"_L1)) {
740 sendObject_selection_changed = 1;
741 } else if (right.startsWith("StateChanged"_L1)) {
742 sendObject_state_changed = 1;
743 } else if (right.startsWith("TextAttributesChanged"_L1)) {
744 sendObject_text_attributes_changed = 1;
745 } else if (right.startsWith("TextBoundsChanged"_L1)) {
746 sendObject_text_bounds_changed = 1;
747 } else if (right.startsWith("TextCaretMoved"_L1)) {
748 sendObject_text_caret_moved = 1;
749 } else if (right.startsWith("TextChanged"_L1)) {
750 sendObject_text_changed = 1;
751 } else if (right.startsWith("TextSelectionChanged"_L1)) {
752 sendObject_text_selection_changed = 1;
753 } else if (right.startsWith("ValueChanged"_L1)) {
754 sendObject_value_changed = 1;
755 } else if (right.startsWith("VisibleDataChanged"_L1)
756 || right.startsWith("VisibledataChanged"_L1)) { // typo in libatspi
757 sendObject_visible_data_changed = 1;
758 } else {
759 qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag;
760 }
761 }
762 break;
763 }
764 case 'w': { // window
765 if (flag.size() <= 8) {
766 sendWindow = 1;
767 } else { // object:Foo:Bar
768 QString right = flag.mid(7);
769 if (false) {
770 } else if (right.startsWith("Activate"_L1)) {
771 sendWindow_activate = 1;
772 } else if (right.startsWith("Close"_L1)) {
773 sendWindow_close= 1;
774 } else if (right.startsWith("Create"_L1)) {
775 sendWindow_create = 1;
776 } else if (right.startsWith("Deactivate"_L1)) {
777 sendWindow_deactivate = 1;
778 } else if (right.startsWith("Lower"_L1)) {
779 sendWindow_lower = 1;
780 } else if (right.startsWith("Maximize"_L1)) {
781 sendWindow_maximize = 1;
782 } else if (right.startsWith("Minimize"_L1)) {
783 sendWindow_minimize = 1;
784 } else if (right.startsWith("Move"_L1)) {
785 sendWindow_move = 1;
786 } else if (right.startsWith("Raise"_L1)) {
787 sendWindow_raise = 1;
788 } else if (right.startsWith("Reparent"_L1)) {
789 sendWindow_reparent = 1;
790 } else if (right.startsWith("Resize"_L1)) {
791 sendWindow_resize = 1;
792 } else if (right.startsWith("Restore"_L1)) {
793 sendWindow_restore = 1;
794 } else if (right.startsWith("Restyle"_L1)) {
795 sendWindow_restyle = 1;
796 } else if (right.startsWith("Shade"_L1)) {
797 sendWindow_shade = 1;
798 } else if (right.startsWith("Unshade"_L1)) {
799 sendWindow_unshade = 1;
800 } else if (right.startsWith("DesktopCreate"_L1)) {
801 // ignore this one
802 } else if (right.startsWith("DesktopDestroy"_L1)) {
803 // ignore this one
804 } else {
805 qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag;
806 }
807 }
808 break;
809 }
810 case 'f': {
811 sendFocus = 1;
812 break;
813 }
814 case 'd': { // document is not implemented
815 break;
816 }
817 case 't': { // terminal is not implemented
818 break;
819 }
820 case 'm': { // mouse* is handled in a different way by the gnome atspi stack
821 break;
822 }
823 default:
824 qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag;
825 }
826}
827
831void AtSpiAdaptor::updateEventListeners()
832{
833 QDBusMessage m = QDBusMessage::createMethodCall("org.a11y.atspi.Registry"_L1,
834 "/org/a11y/atspi/registry"_L1,
835 "org.a11y.atspi.Registry"_L1, "GetRegisteredEvents"_L1);
836 QDBusReply<QSpiEventListenerArray> listenersReply = m_dbus->connection().call(m);
837 if (listenersReply.isValid()) {
838 const QSpiEventListenerArray evList = listenersReply.value();
839 for (const QSpiEventListener &ev : evList)
840 setBitFlag(ev.eventName);
841 m_applicationAdaptor->sendEvents(!evList.isEmpty());
842 } else {
843 qCDebug(lcAccessibilityAtspi) << "Could not query active accessibility event listeners.";
844 }
845}
846
847void AtSpiAdaptor::eventListenerDeregistered(const QString &/*bus*/, const QString &/*path*/)
848{
849// qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::eventListenerDeregistered: " << bus << path;
850 updateEventListeners();
851}
852
853void AtSpiAdaptor::eventListenerRegistered(const QString &/*bus*/, const QString &/*path*/)
854{
855// qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::eventListenerRegistered: " << bus << path;
856 updateEventListeners();
857}
858
864{
865 if (!(sendWindow || sendWindow_activate))
866 return;
867
868 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
869 // If the window has been quickly activated or disabled, it will cause a crash.
870 if (iface == nullptr)
871 return;
872 Q_ASSERT(!active || iface->isValid());
873
875 // in dtor it may be invalid
876 if (iface->isValid())
877 windowTitle = iface->text(QAccessible::Name);
878
881
882 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
883
884 QString status = active ? "Activate"_L1 : "Deactivate"_L1;
885 QString path = pathForObject(window);
886 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_WINDOW ""_L1, status, args);
887
888 QVariantList stateArgs = packDBusSignalArguments("active"_L1, active ? 1 : 0, 0, variantForPath(path));
889 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "StateChanged"_L1, stateArgs);
890}
891
892QVariantList AtSpiAdaptor::packDBusSignalArguments(const QString &type, int data1, int data2, const QVariant &variantData) const
893{
895 arguments << type << data1 << data2 << variantData
897 return arguments;
898}
899
900QVariant AtSpiAdaptor::variantForPath(const QString &path) const
901{
905}
906
907bool AtSpiAdaptor::sendDBusSignal(const QString &path, const QString &interface, const QString &signalName, const QVariantList &arguments) const
908{
910 message.setArguments(arguments);
911 return m_dbus->connection().send(message);
912}
913
914QAccessibleInterface *AtSpiAdaptor::interfaceFromPath(const QString& dbusPath) const
915{
916 if (dbusPath == QSPI_OBJECT_PATH_ROOT ""_L1)
917 return QAccessible::queryAccessibleInterface(qApp);
918
919 QStringList parts = dbusPath.split(u'/');
920 if (parts.size() != 6) {
921 qCDebug(lcAccessibilityAtspi) << "invalid path: " << dbusPath;
922 return nullptr;
923 }
924
925 QString objectString = parts.at(5);
926 QAccessible::Id id = objectString.toUInt();
927
928 // The id is always in the range [INT_MAX+1, UINT_MAX]
929 if ((int)id >= 0)
930 qCWarning(lcAccessibilityAtspi) << "No accessible object found for id: " << id;
931
932 return QAccessible::accessibleInterface(id);
933}
934
935void AtSpiAdaptor::notifyStateChange(QAccessibleInterface *interface, const QString &state, int value)
936{
937 QString path = pathForInterface(interface);
938 QVariantList stateArgs = packDBusSignalArguments(state, value, 0, variantForPath(path));
939 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "StateChanged"_L1, stateArgs);
940}
941
942void AtSpiAdaptor::sendAnnouncement(QAccessibleAnnouncementEvent *event)
943{
944 QAccessibleInterface *iface = event->accessibleInterface();
945 if (!iface) {
946 qCWarning(lcAccessibilityAtspi, "Announcement event has no accessible set.");
947 return;
948 }
949 if (!iface->isValid()) {
950 qCWarning(lcAccessibilityAtspi) << "Announcement event with invalid accessible: " << iface;
951 return;
952 }
953
954 const QString path = pathForInterface(iface);
955 const QString message = event->message();
956 const QAccessible::AnnouncementPriority prio = event->priority();
957 const int politeness = (prio == QAccessible::AnnouncementPriority::Assertive) ? ATSPI_LIVE_ASSERTIVE : ATSPI_LIVE_POLITE;
958
959 const QVariantList args = packDBusSignalArguments(QString(), politeness, 0, QVariant::fromValue(QDBusVariant(message)));
960 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "Announcement"_L1, args);
961}
962
966void AtSpiAdaptor::notify(QAccessibleEvent *event)
967{
968 switch (event->type()) {
969 case QAccessible::ObjectCreated:
970 if (sendObject || sendObject_children_changed)
971 notifyAboutCreation(event->accessibleInterface());
972 break;
973 case QAccessible::ObjectShow: {
974 if (sendObject || sendObject_state_changed) {
975 notifyStateChange(event->accessibleInterface(), "showing"_L1, 1);
976 }
977 break;
978 }
979 case QAccessible::ObjectHide: {
980 if (sendObject || sendObject_state_changed) {
981 notifyStateChange(event->accessibleInterface(), "showing"_L1, 0);
982 }
983 break;
984 }
985 case QAccessible::ObjectDestroyed: {
986 if (sendObject || sendObject_state_changed)
987 notifyAboutDestruction(event->accessibleInterface());
988 break;
989 }
990 case QAccessible::ObjectReorder: {
991 if (sendObject || sendObject_children_changed)
992 childrenChanged(event->accessibleInterface());
993 break;
994 }
995 case QAccessible::NameChanged: {
996 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
997 QAccessibleInterface *iface = event->accessibleInterface();
998 if (!iface) {
999 qCDebug(lcAccessibilityAtspi,
1000 "NameChanged event from invalid accessible.");
1001 return;
1002 }
1003
1004 QString path = pathForInterface(iface);
1005 QVariantList args = packDBusSignalArguments(
1006 "accessible-name"_L1, 0, 0,
1007 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
1008 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1009 "PropertyChange"_L1, args);
1010 }
1011 break;
1012 }
1013 case QAccessible::DescriptionChanged: {
1014 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
1015 QAccessibleInterface *iface = event->accessibleInterface();
1016 if (!iface) {
1017 qCDebug(lcAccessibilityAtspi,
1018 "DescriptionChanged event from invalid accessible.");
1019 return;
1020 }
1021
1022 QString path = pathForInterface(iface);
1023 QVariantList args = packDBusSignalArguments(
1024 "accessible-description"_L1, 0, 0,
1025 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Description))));
1026 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1027 "PropertyChange"_L1, args);
1028 }
1029 break;
1030 }
1031 case QAccessible::Focus: {
1032 if (sendFocus || sendObject || sendObject_state_changed)
1033 sendFocusChanged(event->accessibleInterface());
1034 break;
1035 }
1036
1037 case QAccessible::Announcement: {
1038 if (sendObject || sendObject_announcement) {
1039 QAccessibleAnnouncementEvent *announcementEvent = static_cast<QAccessibleAnnouncementEvent*>(event);
1040 sendAnnouncement(announcementEvent);
1041 }
1042 break;
1043 }
1044 case QAccessible::TextInserted:
1045 case QAccessible::TextRemoved:
1046 case QAccessible::TextUpdated: {
1047 if (sendObject || sendObject_text_changed) {
1048 QAccessibleInterface * iface = event->accessibleInterface();
1049 if (!iface || !iface->textInterface()) {
1050 qCWarning(lcAccessibilityAtspi) << "Received text event for invalid interface.";
1051 return;
1052 }
1053 QString path = pathForInterface(iface);
1054
1055 int changePosition = 0;
1056 int cursorPosition = 0;
1057 QString textRemoved;
1058 QString textInserted;
1059
1060 if (event->type() == QAccessible::TextInserted) {
1061 QAccessibleTextInsertEvent *textEvent = static_cast<QAccessibleTextInsertEvent*>(event);
1062 textInserted = textEvent->textInserted();
1063 changePosition = textEvent->changePosition();
1064 cursorPosition = textEvent->cursorPosition();
1065 } else if (event->type() == QAccessible::TextRemoved) {
1066 QAccessibleTextRemoveEvent *textEvent = static_cast<QAccessibleTextRemoveEvent*>(event);
1067 textRemoved = textEvent->textRemoved();
1068 changePosition = textEvent->changePosition();
1069 cursorPosition = textEvent->cursorPosition();
1070 } else if (event->type() == QAccessible::TextUpdated) {
1071 QAccessibleTextUpdateEvent *textEvent = static_cast<QAccessibleTextUpdateEvent*>(event);
1072 textInserted = textEvent->textInserted();
1073 textRemoved = textEvent->textRemoved();
1074 changePosition = textEvent->changePosition();
1075 cursorPosition = textEvent->cursorPosition();
1076 }
1077
1079
1080 if (!textRemoved.isEmpty()) {
1081 data.setVariant(QVariant::fromValue(textRemoved));
1082 QVariantList args = packDBusSignalArguments("delete"_L1, changePosition, textRemoved.size(), QVariant::fromValue(data));
1083 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1084 "TextChanged"_L1, args);
1085 }
1086
1087 if (!textInserted.isEmpty()) {
1088 data.setVariant(QVariant::fromValue(textInserted));
1089 QVariantList args = packDBusSignalArguments("insert"_L1, changePosition, textInserted.size(), QVariant::fromValue(data));
1090 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1091 "TextChanged"_L1, args);
1092 }
1093
1094 // send a cursor update
1095 Q_UNUSED(cursorPosition);
1096// QDBusVariant cursorData;
1097// cursorData.setVariant(QVariant::fromValue(cursorPosition));
1098// QVariantList args = packDBusSignalArguments(QString(), cursorPosition, 0, QVariant::fromValue(cursorData));
1099// sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1100// "TextCaretMoved"_L1, args);
1101 }
1102 break;
1103 }
1104 case QAccessible::TextCaretMoved: {
1105 if (sendObject || sendObject_text_caret_moved) {
1106 QAccessibleInterface * iface = event->accessibleInterface();
1107 if (!iface || !iface->textInterface()) {
1108 qCWarning(lcAccessibilityAtspi) << "Sending TextCaretMoved from object that does not implement text interface: " << iface;
1109 return;
1110 }
1111
1112 QString path = pathForInterface(iface);
1113 QDBusVariant cursorData;
1114 int pos = iface->textInterface()->cursorPosition();
1115 cursorData.setVariant(QVariant::fromValue(pos));
1116 QVariantList args = packDBusSignalArguments(QString(), pos, 0, QVariant::fromValue(cursorData));
1117 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1118 "TextCaretMoved"_L1, args);
1119 }
1120 break;
1121 }
1122 case QAccessible::TextSelectionChanged: {
1123 if (sendObject || sendObject_text_selection_changed) {
1124 QAccessibleInterface * iface = event->accessibleInterface();
1125 QString path = pathForInterface(iface);
1126 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1127 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1128 "TextSelectionChanged"_L1, args);
1129 }
1130 break;
1131 }
1132 case QAccessible::ValueChanged: {
1133 if (sendObject || sendObject_value_changed || sendObject_property_change_accessible_value) {
1134 QAccessibleInterface * iface = event->accessibleInterface();
1135 if (!iface) {
1136 qCWarning(lcAccessibilityAtspi) << "ValueChanged event from invalid accessible.";
1137 return;
1138 }
1139 if (iface->valueInterface()) {
1140 QString path = pathForInterface(iface);
1141 QVariantList args = packDBusSignalArguments("accessible-value"_L1, 0, 0, variantForPath(path));
1142 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1143 "PropertyChange"_L1, args);
1144 } else if (iface->role() == QAccessible::ComboBox) {
1145 // Combo Box with AT-SPI likes to be special
1146 // It requires a name-change to update caches and then selection-changed
1147 QString path = pathForInterface(iface);
1148 QVariantList args1 = packDBusSignalArguments(
1149 "accessible-name"_L1, 0, 0,
1150 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
1151 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1152 "PropertyChange"_L1, args1);
1153 QVariantList args2 = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(0))));
1154 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1155 "SelectionChanged"_L1, args2);
1156 } else {
1157 qCWarning(lcAccessibilityAtspi) << "ValueChanged event and no ValueInterface or ComboBox: " << iface;
1158 }
1159 }
1160 break;
1161 }
1162 case QAccessible::SelectionAdd:
1163 case QAccessible::SelectionRemove:
1164 case QAccessible::Selection: {
1165 QAccessibleInterface * iface = event->accessibleInterface();
1166 if (!iface) {
1167 qCWarning(lcAccessibilityAtspi) << "Selection event from invalid accessible.";
1168 return;
1169 }
1170 // send event for change of selected state for the interface itself
1171 QString path = pathForInterface(iface);
1172 int selected = iface->state().selected ? 1 : 0;
1173 QVariantList stateArgs = packDBusSignalArguments("selected"_L1, selected, 0, variantForPath(path));
1174 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "StateChanged"_L1, stateArgs);
1175
1176 // send SelectionChanged event for the parent
1177 QAccessibleInterface* parent = iface->parent();
1178 if (!parent) {
1179 qCDebug(lcAccessibilityAtspi) << "No valid parent in selection event.";
1180 return;
1181 }
1182
1183 QString parentPath = pathForInterface(parent);
1184 QVariantList args = packDBusSignalArguments(QString(), 0, 0, variantForPath(parentPath));
1185 sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1186 QLatin1String("SelectionChanged"), args);
1187 break;
1188 }
1189 case QAccessible::SelectionWithin: {
1190 QAccessibleInterface * iface = event->accessibleInterface();
1191 if (!iface) {
1192 qCWarning(lcAccessibilityAtspi) << "SelectionWithin event from invalid accessible.";
1193 return;
1194 }
1195
1196 QString path = pathForInterface(iface);
1197 QVariantList args = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1198 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("SelectionChanged"), args);
1199 break;
1200 }
1201 case QAccessible::StateChanged: {
1202 if (sendObject || sendObject_state_changed || sendWindow || sendWindow_activate) {
1203 QAccessible::State stateChange = static_cast<QAccessibleStateChangeEvent*>(event)->changedStates();
1204 if (stateChange.checked) {
1205 QAccessibleInterface * iface = event->accessibleInterface();
1206 if (!iface) {
1207 qCWarning(lcAccessibilityAtspi) << "StateChanged event from invalid accessible.";
1208 return;
1209 }
1210 int checked = iface->state().checked;
1211 notifyStateChange(iface, "checked"_L1, checked);
1212 } else if (stateChange.active) {
1213 QAccessibleInterface * iface = event->accessibleInterface();
1214 if (!iface || !(iface->role() == QAccessible::Window && (sendWindow || sendWindow_activate)))
1215 return;
1216 int isActive = iface->state().active;
1217 QString windowTitle = iface->text(QAccessible::Name);
1220 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
1221 QString status = isActive ? "Activate"_L1 : "Deactivate"_L1;
1222 QString path = pathForInterface(iface);
1223 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_WINDOW ""_L1, status, args);
1224 notifyStateChange(iface, "active"_L1, isActive);
1225 } else if (stateChange.disabled) {
1226 QAccessibleInterface *iface = event->accessibleInterface();
1227 QAccessible::State state = iface->state();
1228 bool enabled = !state.disabled;
1229
1230 notifyStateChange(iface, "enabled"_L1, enabled);
1231 notifyStateChange(iface, "sensitive"_L1, enabled);
1232 } else if (stateChange.focused) {
1233 QAccessibleInterface *iface = event->accessibleInterface();
1234 QAccessible::State state = iface->state();
1235 bool focused = state.focused;
1236 notifyStateChange(iface, "focused"_L1, focused);
1237 }
1238 }
1239 break;
1240 }
1241 case QAccessible::TableModelChanged: {
1242 QAccessibleInterface *interface = event->accessibleInterface();
1243 if (!interface || !interface->isValid()) {
1244 qCWarning(lcAccessibilityAtspi) << "TableModelChanged event from invalid accessible.";
1245 return;
1246 }
1247
1248 const QString path = pathForInterface(interface);
1249 QAccessibleTableModelChangeEvent *tableModelEvent = static_cast<QAccessibleTableModelChangeEvent*>(event);
1250 switch (tableModelEvent->modelChangeType()) {
1251 case QAccessibleTableModelChangeEvent::ColumnsInserted: {
1252 if (sendObject || sendObject_column_inserted) {
1253 const int firstColumn = tableModelEvent->firstColumn();
1254 const int insertedColumnCount = tableModelEvent->lastColumn() - firstColumn + 1;
1255 QVariantList args = packDBusSignalArguments(QString(), firstColumn, insertedColumnCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1256 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ColumnInserted"_L1, args);
1257 }
1258 break;
1259 }
1260 case QAccessibleTableModelChangeEvent::ColumnsRemoved: {
1261 if (sendObject || sendObject_column_deleted) {
1262 const int firstColumn = tableModelEvent->firstColumn();
1263 const int removedColumnCount = tableModelEvent->lastColumn() - firstColumn + 1;
1264 QVariantList args = packDBusSignalArguments(QString(), firstColumn, removedColumnCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1265 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ColumnDeleted"_L1, args);
1266 }
1267 break;
1268 }
1269 case QAccessibleTableModelChangeEvent::RowsInserted: {
1270 if (sendObject || sendObject_row_inserted) {
1271 const int firstRow = tableModelEvent->firstRow();
1272 const int insertedRowCount = tableModelEvent->lastRow() - firstRow + 1;
1273 QVariantList args = packDBusSignalArguments(QString(), firstRow, insertedRowCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1274 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "RowInserted"_L1, args);
1275 }
1276 break;
1277 }
1278 case QAccessibleTableModelChangeEvent::RowsRemoved: {
1279 if (sendObject || sendObject_row_deleted) {
1280 const int firstRow = tableModelEvent->firstRow();
1281 const int removedRowCount = tableModelEvent->lastRow() - firstRow + 1;
1282 QVariantList args = packDBusSignalArguments(QString(), firstRow, removedRowCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1283 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "RowDeleted"_L1, args);
1284 }
1285 break;
1286 }
1287 case QAccessibleTableModelChangeEvent::ModelChangeType::ModelReset: {
1288 if (sendObject || sendObject_model_changed) {
1289 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1290 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ModelChanged"_L1, args);
1291 }
1292 break;
1293 }
1294 case QAccessibleTableModelChangeEvent::DataChanged: {
1295 if (sendObject || sendObject_visible_data_changed) {
1296 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1297 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "VisibleDataChanged"_L1, args);
1298 }
1299 break;
1300 }
1301 }
1302 break;
1303 }
1304
1305 // For now we ignore these events
1306 case QAccessible::ParentChanged:
1307 case QAccessible::DialogStart:
1308 case QAccessible::DialogEnd:
1309 case QAccessible::PopupMenuStart:
1310 case QAccessible::PopupMenuEnd:
1311 case QAccessible::SoundPlayed:
1312 case QAccessible::Alert:
1313 case QAccessible::ForegroundChanged:
1314 case QAccessible::MenuStart:
1315 case QAccessible::MenuEnd:
1316 case QAccessible::ContextHelpStart:
1317 case QAccessible::ContextHelpEnd:
1318 case QAccessible::DragDropStart:
1319 case QAccessible::DragDropEnd:
1320 case QAccessible::ScrollingStart:
1321 case QAccessible::ScrollingEnd:
1322 case QAccessible::MenuCommand:
1323 case QAccessible::ActionChanged:
1324 case QAccessible::ActiveDescendantChanged:
1325 case QAccessible::AttributeChanged:
1326 case QAccessible::DocumentContentChanged:
1327 case QAccessible::DocumentLoadComplete:
1328 case QAccessible::DocumentLoadStopped:
1329 case QAccessible::DocumentReload:
1330 case QAccessible::HyperlinkEndIndexChanged:
1331 case QAccessible::HyperlinkNumberOfAnchorsChanged:
1332 case QAccessible::HyperlinkSelectedLinkChanged:
1333 case QAccessible::HypertextLinkActivated:
1334 case QAccessible::HypertextLinkSelected:
1335 case QAccessible::HyperlinkStartIndexChanged:
1336 case QAccessible::HypertextChanged:
1337 case QAccessible::HypertextNLinksChanged:
1338 case QAccessible::ObjectAttributeChanged:
1339 case QAccessible::PageChanged:
1340 case QAccessible::SectionChanged:
1341 case QAccessible::TableCaptionChanged:
1342 case QAccessible::TableColumnDescriptionChanged:
1343 case QAccessible::TableColumnHeaderChanged:
1344 case QAccessible::TableRowDescriptionChanged:
1345 case QAccessible::TableRowHeaderChanged:
1346 case QAccessible::TableSummaryChanged:
1347 case QAccessible::TextAttributeChanged:
1348 case QAccessible::TextColumnChanged:
1349 case QAccessible::VisibleDataChanged:
1350 case QAccessible::LocationChanged:
1351 case QAccessible::HelpChanged:
1352 case QAccessible::DefaultActionChanged:
1353 case QAccessible::AcceleratorChanged:
1354 case QAccessible::InvalidEvent:
1355 break;
1356 }
1357}
1358
1359void AtSpiAdaptor::sendFocusChanged(QAccessibleInterface *interface) const
1360{
1361 static QString lastFocusPath;
1362 // "remove" old focus
1363 if (!lastFocusPath.isEmpty()) {
1364 QVariantList stateArgs = packDBusSignalArguments("focused"_L1, 0, 0, variantForPath(lastFocusPath));
1365 sendDBusSignal(lastFocusPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1366 "StateChanged"_L1, stateArgs);
1367 }
1368 // send new focus
1369 {
1370 QString path = pathForInterface(interface);
1371
1372 QVariantList stateArgs = packDBusSignalArguments("focused"_L1, 1, 0, variantForPath(path));
1373 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1,
1374 "StateChanged"_L1, stateArgs);
1375
1376 QVariantList focusArgs = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1377 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_FOCUS ""_L1, "Focus"_L1, focusArgs);
1378 lastFocusPath = path;
1379 }
1380}
1381
1382void AtSpiAdaptor::childrenChanged(QAccessibleInterface *interface) const
1383{
1384 QString parentPath = pathForInterface(interface);
1385 int childCount = interface->childCount();
1386 for (int i = 0; i < interface->childCount(); ++i) {
1387 QString childPath = pathForInterface(interface->child(i));
1388 QVariantList args = packDBusSignalArguments("add"_L1, childCount, 0, childPath);
1389 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ChildrenChanged"_L1, args);
1390 }
1391}
1392
1393void AtSpiAdaptor::notifyAboutCreation(QAccessibleInterface *interface) const
1394{
1395 // notify about the new child of our parent
1396 QAccessibleInterface * parent = interface->parent();
1397 if (!parent) {
1398 qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::notifyAboutCreation: Could not find parent for " << interface->object();
1399 return;
1400 }
1401 QString path = pathForInterface(interface);
1402 int childCount = parent->childCount();
1403 QString parentPath = pathForInterface(parent);
1404 QVariantList args = packDBusSignalArguments("add"_L1, childCount, 0, variantForPath(path));
1405 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ChildrenChanged"_L1, args);
1406}
1407
1408void AtSpiAdaptor::notifyAboutDestruction(QAccessibleInterface *interface) const
1409{
1410 if (!interface || !interface->isValid())
1411 return;
1412
1413 QAccessibleInterface * parent = interface->parent();
1414 if (!parent) {
1415 qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::notifyAboutDestruction: Could not find parent for " << interface->object();
1416 return;
1417 }
1418 QString path = pathForInterface(interface);
1419
1420 // this is in the destructor. we have no clue which child we used to be.
1421 // FIXME
1422 int childIndex = -1;
1423 // if (child) {
1424 // childIndex = child;
1425 // } else {
1426 // childIndex = parent->indexOfChild(interface);
1427 // }
1428
1429 QString parentPath = pathForInterface(parent);
1430 QVariantList args = packDBusSignalArguments("remove"_L1, childIndex, 0, variantForPath(path));
1431 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "ChildrenChanged"_L1, args);
1432}
1433
1439{
1440 // get accessible interface
1441 QAccessibleInterface * accessible = interfaceFromPath(message.path());
1442 if (!accessible) {
1443 qCWarning(lcAccessibilityAtspi) << "Could not find accessible on path:" << message.path();
1444 return false;
1445 }
1446 if (!accessible->isValid()) {
1447 qCWarning(lcAccessibilityAtspi) << "Accessible invalid:" << accessible << message.path();
1448 return false;
1449 }
1450
1451 QString interface = message.interface();
1452 QString function = message.member();
1453
1454 // qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::handleMessage: " << interface << function;
1455
1456 if (function == "Introspect"_L1) {
1457 //introspect(message.path());
1458 return false;
1459 }
1460
1461 // handle properties like regular functions
1462 if (interface == "org.freedesktop.DBus.Properties"_L1) {
1463 interface = message.arguments().at(0).toString();
1464 // Get/Set + Name
1465 function = message.member() + message.arguments().at(1).toString();
1466 }
1467
1468 // switch interface to call
1470 return accessibleInterface(accessible, function, message, connection);
1472 return applicationInterface(accessible, function, message, connection);
1474 return componentInterface(accessible, function, message, connection);
1476 return actionInterface(accessible, function, message, connection);
1478 return selectionInterface(accessible, function, message, connection);
1480 return textInterface(accessible, function, message, connection);
1482 return editableTextInterface(accessible, function, message, connection);
1484 return valueInterface(accessible, function, message, connection);
1486 return tableInterface(accessible, function, message, connection);
1487 if (interface == ATSPI_DBUS_INTERFACE_TABLE_CELL ""_L1)
1488 return tableCellInterface(accessible, function, message, connection);
1489
1490 qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::handleMessage with unknown interface: " << message.path() << interface << function;
1491 return false;
1492}
1493
1494// Application
1495bool AtSpiAdaptor::applicationInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1496{
1497 if (message.path() != ATSPI_DBUS_PATH_ROOT ""_L1) {
1498 qCWarning(lcAccessibilityAtspi) << "Could not find application interface for:" << message.path() << interface;
1499 return false;
1500 }
1501
1502 if (function == "SetId"_L1) {
1503 Q_ASSERT(message.signature() == "ssv"_L1);
1504 QVariant value = qvariant_cast<QDBusVariant>(message.arguments().at(2)).variant();
1505
1506 m_applicationId = value.toInt();
1507 return true;
1508 }
1509 if (function == "GetId"_L1) {
1510 Q_ASSERT(message.signature() == "ss"_L1);
1511 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(m_applicationId)));
1512 return connection.send(reply);
1513 }
1514 if (function == "GetToolkitName"_L1) {
1515 Q_ASSERT(message.signature() == "ss"_L1);
1517 return connection.send(reply);
1518 }
1519 if (function == "GetVersion"_L1) {
1520 Q_ASSERT(message.signature() == "ss"_L1);
1522 return connection.send(reply);
1523 }
1524 if (function == "GetLocale"_L1) {
1525 Q_ASSERT(message.signature() == "u"_L1);
1527 return connection.send(reply);
1528 }
1529 qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::applicationInterface " << message.path() << interface << function;
1530 return false;
1531}
1532
1537{
1538 OrgA11yAtspiSocketInterface *registry;
1539 registry = new OrgA11yAtspiSocketInterface(QSPI_REGISTRY_NAME ""_L1,
1540 QSPI_OBJECT_PATH_ROOT ""_L1, m_dbus->connection());
1541
1542 QDBusPendingReply<QSpiObjectReference> reply;
1544 reply = registry->Embed(ref);
1545 reply.waitForFinished(); // TODO: make this async
1546 if (reply.isValid ()) {
1547 const QSpiObjectReference &socket = reply.value();
1548 accessibilityRegistry = QSpiObjectReference(socket);
1549 } else {
1550 qCWarning(lcAccessibilityAtspi) << "Error in contacting registry:"
1551 << reply.error().name()
1552 << reply.error().message();
1553 }
1554 delete registry;
1555}
1556
1557namespace {
1558QString accessibleIdForAccessible(QAccessibleInterface *accessible)
1559{
1561 while (accessible) {
1562 if (!result.isEmpty())
1563 result.prepend(u'.');
1564 if (auto obj = accessible->object()) {
1565 const QString name = obj->objectName();
1566 if (!name.isEmpty())
1568 else
1569 result.prepend(QString::fromUtf8(obj->metaObject()->className()));
1570 }
1571 accessible = accessible->parent();
1572 }
1573 return result;
1574}
1575} // namespace
1576
1577// Accessible
1578bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1579{
1580 if (function == "GetRole"_L1) {
1581 sendReply(connection, message, (uint) getRole(interface));
1582 } else if (function == "GetName"_L1) {
1583 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Name))));
1584 } else if (function == "GetRoleName"_L1) {
1586 } else if (function == "GetLocalizedRoleName"_L1) {
1588 } else if (function == "GetChildCount"_L1) {
1589 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->childCount())));
1590 } else if (function == "GetIndexInParent"_L1) {
1591 int childIndex = -1;
1592 QAccessibleInterface * parent = interface->parent();
1593 if (parent) {
1594 childIndex = parent->indexOfChild(interface);
1595 if (childIndex < 0) {
1596 qCDebug(lcAccessibilityAtspi) << "GetIndexInParent get invalid index: " << childIndex << interface;
1597 }
1598 }
1599 sendReply(connection, message, childIndex);
1600 } else if (function == "GetParent"_L1) {
1601 QString path;
1602 QAccessibleInterface * parent = interface->parent();
1603 if (!parent) {
1604 path = ATSPI_DBUS_PATH_NULL ""_L1;
1605 } else if (parent->role() == QAccessible::Application) {
1606 path = ATSPI_DBUS_PATH_ROOT ""_L1;
1607 } else {
1608 path = pathForInterface(parent);
1609 }
1610 // Parent is a property, so it needs to be wrapped inside an extra variant.
1613 } else if (function == "GetChildAtIndex"_L1) {
1614 const int index = message.arguments().at(0).toInt();
1615 if (index < 0) {
1617 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1618 } else {
1619 QAccessibleInterface * childInterface = interface->child(index);
1621 QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(childInterface)))));
1622 }
1623 } else if (function == "GetInterfaces"_L1) {
1624 sendReply(connection, message, accessibleInterfaces(interface));
1625 } else if (function == "GetDescription"_L1) {
1626 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Description))));
1627 } else if (function == "GetState"_L1) {
1628 quint64 spiState = spiStatesFromQState(interface->state());
1629 if (interface->tableInterface()) {
1630 // For tables, setting manages_descendants should
1631 // indicate to the client that it cannot cache these
1632 // interfaces.
1633 setSpiStateBit(&spiState, ATSPI_STATE_MANAGES_DESCENDANTS);
1634 }
1635 QAccessible::Role role = interface->role();
1636 if (role == QAccessible::TreeItem ||
1637 role == QAccessible::ListItem) {
1638 /* Transient means libatspi2 will not cache items.
1639 This is important because when adding/removing an item
1640 the cache becomes outdated and we don't change the paths of
1641 items in lists/trees/tables. */
1642 setSpiStateBit(&spiState, ATSPI_STATE_TRANSIENT);
1643 }
1644 sendReply(connection, message,
1646 } else if (function == "GetAttributes"_L1) {
1648 } else if (function == "GetRelationSet"_L1) {
1649 sendReply(connection, message, QVariant::fromValue(relationSet(interface, connection)));
1650 } else if (function == "GetApplication"_L1) {
1653 } else if (function == "GetChildren"_L1) {
1655 const int numChildren = interface->childCount();
1656 children.reserve(numChildren);
1657 for (int i = 0; i < numChildren; ++i) {
1658 QString childPath = pathForInterface(interface->child(i));
1660 children << ref;
1661 }
1662 connection.send(message.createReply(QVariant::fromValue(children)));
1663 } else if (function == "GetAccessibleId"_L1) {
1664 sendReply(connection, message,
1665 QVariant::fromValue(QDBusVariant(accessibleIdForAccessible(interface))));
1666 } else {
1667 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::accessibleInterface does not implement" << function << message.path();
1668 return false;
1669 }
1670 return true;
1671}
1672
1673AtspiRole AtSpiAdaptor::getRole(QAccessibleInterface *interface) const
1674{
1675 if ((interface->role() == QAccessible::EditableText) && interface->state().passwordEdit)
1676 return ATSPI_ROLE_PASSWORD_TEXT;
1677 return QSpiAccessibleBridge::namesForRole(interface->role()).spiRole();
1678}
1679
1680QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface) const
1681{
1682 QStringList ifaces;
1683 qCDebug(lcAccessibilityAtspiCreation) << "AtSpiAdaptor::accessibleInterfaces create: " << interface->object();
1684 ifaces << u"" ATSPI_DBUS_INTERFACE_ACCESSIBLE ""_s;
1685
1686 if ( (!interface->rect().isEmpty()) ||
1687 (interface->object() && interface->object()->isWidgetType()) ||
1688 (interface->role() == QAccessible::ListItem) ||
1689 (interface->role() == QAccessible::Cell) ||
1690 (interface->role() == QAccessible::TreeItem) ||
1691 (interface->role() == QAccessible::Row) ||
1692 (interface->object() && interface->object()->inherits("QSGItem"))
1693 ) {
1694 ifaces << u"" ATSPI_DBUS_INTERFACE_COMPONENT ""_s;
1695 } else {
1696 qCDebug(lcAccessibilityAtspiCreation) << " IS NOT a component";
1697 }
1698 if (interface->role() == QAccessible::Application)
1699 ifaces << u"" ATSPI_DBUS_INTERFACE_APPLICATION ""_s;
1700
1701 if (interface->actionInterface() || interface->valueInterface())
1702 ifaces << u"" ATSPI_DBUS_INTERFACE_ACTION ""_s;
1703
1704 if (interface->selectionInterface())
1705 ifaces << ATSPI_DBUS_INTERFACE_SELECTION ""_L1;
1706
1707 if (interface->textInterface())
1708 ifaces << u"" ATSPI_DBUS_INTERFACE_TEXT ""_s;
1709
1710 if (interface->editableTextInterface())
1711 ifaces << u"" ATSPI_DBUS_INTERFACE_EDITABLE_TEXT ""_s;
1712
1713 if (interface->valueInterface())
1714 ifaces << u"" ATSPI_DBUS_INTERFACE_VALUE ""_s;
1715
1716 if (interface->tableInterface())
1717 ifaces << u"" ATSPI_DBUS_INTERFACE_TABLE ""_s;
1718
1719 if (interface->tableCellInterface())
1720 ifaces << u"" ATSPI_DBUS_INTERFACE_TABLE_CELL ""_s;
1721
1722 return ifaces;
1723}
1724
1725QSpiRelationArray AtSpiAdaptor::relationSet(QAccessibleInterface *interface, const QDBusConnection &connection) const
1726{
1727 typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
1728 const QList<RelationPair> relationInterfaces = interface->relations();
1729
1730 QSpiRelationArray relations;
1731 for (const RelationPair &pair : relationInterfaces) {
1732// FIXME: this loop seems a bit strange... "related" always have one item when we check.
1733//And why is it a list, when it always have one item? And it seems to assume that the QAccessible::Relation enum maps directly to AtSpi
1735
1736 QDBusObjectPath path = QDBusObjectPath(pathForInterface(pair.first));
1738
1739 if (!related.isEmpty())
1740 relations.append(QSpiRelationArrayEntry(qAccessibleRelationToAtSpiRelation(pair.second), related));
1741 }
1742 return relations;
1743}
1744
1745void AtSpiAdaptor::sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const
1746{
1747 QDBusMessage reply = message.createReply(argument);
1748 connection.send(reply);
1749}
1750
1751
1752QString AtSpiAdaptor::pathForObject(QObject *object) const
1753{
1754 Q_ASSERT(object);
1755
1756 if (inheritsQAction(object)) {
1757 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::pathForObject: Creating path with QAction as object.";
1758 }
1759
1760 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object);
1761 return pathForInterface(iface);
1762}
1763
1764QString AtSpiAdaptor::pathForInterface(QAccessibleInterface *interface) const
1765{
1766 if (!interface || !interface->isValid())
1767 return u"" ATSPI_DBUS_PATH_NULL ""_s;
1768 if (interface->role() == QAccessible::Application)
1769 return u"" QSPI_OBJECT_PATH_ROOT ""_s;
1770
1771 QAccessible::Id id = QAccessible::uniqueId(interface);
1772 Q_ASSERT((int)id < 0);
1773 return QSPI_OBJECT_PATH_PREFIX ""_L1 + QString::number(id);
1774}
1775
1776bool AtSpiAdaptor::inheritsQAction(QObject *object)
1777{
1778 const QMetaObject *mo = object->metaObject();
1779 while (mo) {
1780 const QLatin1StringView cn(mo->className());
1781 if (cn == "QAction"_L1)
1782 return true;
1783 mo = mo->superClass();
1784 }
1785 return false;
1786}
1787
1788// Component
1789static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
1790{
1791 // find top-level window in a11y hierarchy (either has a
1792 // corresponding role or is a direct child of the application object)
1793 QAccessibleInterface* app = QAccessible::queryAccessibleInterface(qApp);
1794 while (interface && interface->role() != QAccessible::Dialog
1795 && interface->role() != QAccessible::Window && interface->parent() != app)
1796 interface = interface->parent();
1797
1798 return interface;
1799}
1800
1801bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1802{
1803 if (function == "Contains"_L1) {
1804 bool ret = false;
1805 int x = message.arguments().at(0).toInt();
1806 int y = message.arguments().at(1).toInt();
1807 uint coordType = message.arguments().at(2).toUInt();
1808 if (!isValidCoordType(coordType))
1809 return false;
1810 ret = getExtents(interface, coordType).contains(x, y);
1812 } else if (function == "GetAccessibleAtPoint"_L1) {
1813 QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
1814 uint coordType = message.arguments().at(2).toUInt();
1815 if (!isValidCoordType(coordType))
1816 return false;
1817 QPoint screenPos = translateToScreenCoordinates(interface, point, coordType);
1818
1819 QAccessibleInterface * childInterface(interface->childAt(screenPos.x(), screenPos.y()));
1820 QAccessibleInterface * iface = nullptr;
1821 while (childInterface) {
1822 iface = childInterface;
1823 childInterface = iface->childAt(screenPos.x(), screenPos.y());
1824 }
1825 if (iface) {
1826 QString path = pathForInterface(iface);
1829 } else {
1831 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1832 }
1833 } else if (function == "GetAlpha"_L1) {
1834 sendReply(connection, message, (double) 1.0);
1835 } else if (function == "GetExtents"_L1) {
1836 uint coordType = message.arguments().at(0).toUInt();
1837 if (!isValidCoordType(coordType))
1838 return false;
1840 } else if (function == "GetLayer"_L1) {
1842 } else if (function == "GetMDIZOrder"_L1) {
1844 } else if (function == "GetPosition"_L1) {
1845 uint coordType = message.arguments().at(0).toUInt();
1846 if (!isValidCoordType(coordType))
1847 return false;
1848 QRect rect = getExtents(interface, coordType);
1850 pos << rect.x() << rect.y();
1851 connection.send(message.createReply(pos));
1852 } else if (function == "GetSize"_L1) {
1853 QRect rect = interface->rect();
1855 size << rect.width() << rect.height();
1856 connection.send(message.createReply(size));
1857 } else if (function == "GrabFocus"_L1) {
1858 QAccessibleActionInterface *actionIface = interface->actionInterface();
1859 if (actionIface && actionIface->actionNames().contains(QAccessibleActionInterface::setFocusAction())) {
1860 actionIface->doAction(QAccessibleActionInterface::setFocusAction());
1862 } else {
1863 sendReply(connection, message, false);
1864 }
1865 } else if (function == "SetExtents"_L1) {
1866// int x = message.arguments().at(0).toInt();
1867// int y = message.arguments().at(1).toInt();
1868// int width = message.arguments().at(2).toInt();
1869// int height = message.arguments().at(3).toInt();
1870// uint coordinateType = message.arguments().at(4).toUInt();
1871 qCDebug(lcAccessibilityAtspi) << "SetExtents is not implemented.";
1872 sendReply(connection, message, false);
1873 } else if (function == "SetPosition"_L1) {
1874// int x = message.arguments().at(0).toInt();
1875// int y = message.arguments().at(1).toInt();
1876// uint coordinateType = message.arguments().at(2).toUInt();
1877 qCDebug(lcAccessibilityAtspi) << "SetPosition is not implemented.";
1878 sendReply(connection, message, false);
1879 } else if (function == "SetSize"_L1) {
1880// int width = message.arguments().at(0).toInt();
1881// int height = message.arguments().at(1).toInt();
1882 qCDebug(lcAccessibilityAtspi) << "SetSize is not implemented.";
1883 sendReply(connection, message, false);
1884 } else {
1885 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::componentInterface does not implement" << function << message.path();
1886 return false;
1887 }
1888 return true;
1889}
1890
1891QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType)
1892{
1893 return translateFromScreenCoordinates(interface, interface->rect(), coordType);
1894}
1895
1896// Action interface
1897bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1898{
1899 if (function == "GetNActions"_L1) {
1902 } else if (function == "DoAction"_L1) {
1903 int index = message.arguments().at(0).toInt();
1905 if (index < 0 || index >= actionNames.size())
1906 return false;
1907 const QString actionName = actionNames.at(index);
1909 sendReply(connection, message, success);
1910 } else if (function == "GetActions"_L1) {
1912 } else if (function == "GetName"_L1) {
1913 int index = message.arguments().at(0).toInt();
1915 if (index < 0 || index >= actionNames.size())
1916 return false;
1917 sendReply(connection, message, actionNames.at(index));
1918 } else if (function == "GetDescription"_L1) {
1919 int index = message.arguments().at(0).toInt();
1921 if (index < 0 || index >= actionNames.size())
1922 return false;
1923 QString description;
1924 if (QAccessibleActionInterface *actionIface = interface->actionInterface())
1925 description = actionIface->localizedActionDescription(actionNames.at(index));
1926 else
1927 description = qAccessibleLocalizedActionDescription(actionNames.at(index));
1928 sendReply(connection, message, description);
1929 } else if (function == "GetKeyBinding"_L1) {
1930 int index = message.arguments().at(0).toInt();
1932 if (index < 0 || index >= actionNames.size())
1933 return false;
1934 QStringList keyBindings;
1935 if (QAccessibleActionInterface *actionIface = interface->actionInterface())
1936 keyBindings = actionIface->keyBindingsForAction(actionNames.at(index));
1937 if (keyBindings.isEmpty()) {
1938 QString acc = interface->text(QAccessible::Accelerator);
1939 if (!acc.isEmpty())
1940 keyBindings.append(acc);
1941 }
1942 if (keyBindings.size() > 0)
1943 sendReply(connection, message, keyBindings.join(u';'));
1944 else
1946 } else {
1947 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::actionInterface does not implement" << function << message.path();
1948 return false;
1949 }
1950 return true;
1951}
1952
1953QSpiActionArray AtSpiAdaptor::getActions(QAccessibleInterface *interface) const
1954{
1955 QAccessibleActionInterface *actionInterface = interface->actionInterface();
1956 QSpiActionArray actions;
1958 actions.reserve(actionNames.size());
1959 for (const QString &actionName : actionNames) {
1960 QSpiAction action;
1961
1962 action.name = actionName;
1963 if (actionInterface) {
1964 action.description = actionInterface->localizedActionDescription(actionName);
1965 const QStringList keyBindings = actionInterface->keyBindingsForAction(actionName);
1966 if (!keyBindings.isEmpty())
1967 action.keyBinding = keyBindings.front();
1968 } else {
1969 action.description = qAccessibleLocalizedActionDescription(actionName);
1970 }
1971
1972 actions.append(std::move(action));
1973 }
1974 return actions;
1975}
1976
1977// Text interface
1978bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1979{
1980 if (!interface->textInterface())
1981 return false;
1982
1983 // properties
1984 if (function == "GetCaretOffset"_L1) {
1986 } else if (function == "GetCharacterCount"_L1) {
1988
1989 // functions
1990 } else if (function == "AddSelection"_L1) {
1991 int startOffset = message.arguments().at(0).toInt();
1992 int endOffset = message.arguments().at(1).toInt();
1993 int lastSelection = interface->textInterface()->selectionCount();
1994 interface->textInterface()->setSelection(lastSelection, startOffset, endOffset);
1995 sendReply(connection, message, (interface->textInterface()->selectionCount() > lastSelection));
1996 } else if (function == "GetAttributeRun"_L1) {
1997 int offset = message.arguments().at(0).toInt();
1998 bool includeDefaults = message.arguments().at(1).toBool();
1999 Q_UNUSED(includeDefaults);
2000 connection.send(message.createReply(getAttributes(interface, offset, includeDefaults)));
2001 } else if (function == "GetAttributeValue"_L1) {
2002 int offset = message.arguments().at(0).toInt();
2003 QString attributeName = message.arguments().at(1).toString();
2004 connection.send(message.createReply(QVariant(getAttributeValue(interface, offset, attributeName))));
2005 } else if (function == "GetAttributes"_L1) {
2006 int offset = message.arguments().at(0).toInt();
2007 connection.send(message.createReply(getAttributes(interface, offset, true)));
2008 } else if (function == "GetBoundedRanges"_L1) {
2009 int x = message.arguments().at(0).toInt();
2010 int y = message.arguments().at(1).toInt();
2011 int width = message.arguments().at(2).toInt();
2012 int height = message.arguments().at(3).toInt();
2013 uint coordType = message.arguments().at(4).toUInt();
2014 uint xClipType = message.arguments().at(5).toUInt();
2015 uint yClipType = message.arguments().at(6).toUInt();
2016 Q_UNUSED(x);
2017 Q_UNUSED(y);
2018 Q_UNUSED(width);
2021 Q_UNUSED(xClipType);
2022 Q_UNUSED(yClipType);
2023 qCDebug(lcAccessibilityAtspi) << "Not implemented: QSpiAdaptor::GetBoundedRanges";
2025 } else if (function == "GetCharacterAtOffset"_L1) {
2026 int offset = message.arguments().at(0).toInt();
2027 int start;
2028 int end;
2029 const QString charString = interface->textInterface()
2030 ->textAtOffset(offset, QAccessible::CharBoundary, &start, &end);
2031 int codePoint = 0;
2032 QStringIterator stringIt(charString);
2033 if (stringIt.hasNext())
2034 codePoint = static_cast<int>(stringIt.peekNext());
2035 sendReply(connection, message, codePoint);
2036 } else if (function == "GetCharacterExtents"_L1) {
2037 int offset = message.arguments().at(0).toInt();
2038 int coordType = message.arguments().at(1).toUInt();
2039 connection.send(message.createReply(getCharacterExtents(interface, offset, coordType)));
2040 } else if (function == "GetDefaultAttributeSet"_L1 || function == "GetDefaultAttributes"_L1) {
2041 // GetDefaultAttributes is deprecated in favour of GetDefaultAttributeSet.
2042 // Empty set seems reasonable. There is no default attribute set.
2044 } else if (function == "GetNSelections"_L1) {
2045 sendReply(connection, message, interface->textInterface()->selectionCount());
2046 } else if (function == "GetOffsetAtPoint"_L1) {
2047 qCDebug(lcAccessibilityAtspi) << message.signature();
2048 Q_ASSERT(!message.signature().isEmpty());
2049 QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
2050 uint coordType = message.arguments().at(2).toUInt();
2051 if (!isValidCoordType(coordType))
2052 return false;
2053 QPoint screenPos = translateToScreenCoordinates(interface, point, coordType);
2054 int offset = interface->textInterface()->offsetAtPoint(screenPos);
2056 } else if (function == "GetRangeExtents"_L1) {
2057 int startOffset = message.arguments().at(0).toInt();
2058 int endOffset = message.arguments().at(1).toInt();
2059 uint coordType = message.arguments().at(2).toUInt();
2060 connection.send(message.createReply(getRangeExtents(interface, startOffset, endOffset, coordType)));
2061 } else if (function == "GetSelection"_L1) {
2062 int selectionNum = message.arguments().at(0).toInt();
2063 int start, end;
2064 interface->textInterface()->selection(selectionNum, &start, &end);
2065 if (start < 0)
2066 start = end = interface->textInterface()->cursorPosition();
2067 QVariantList sel;
2068 sel << start << end;
2069 connection.send(message.createReply(sel));
2070 } else if (function == "GetStringAtOffset"_L1) {
2071 int offset = message.arguments().at(0).toInt();
2072 uint granularity = message.arguments().at(1).toUInt();
2073 if (!isValidAtspiTextGranularity(granularity))
2074 return false;
2075 int startOffset, endOffset;
2076 QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiTextGranularity(granularity), &startOffset, &endOffset);
2078 ret << text << startOffset << endOffset;
2079 connection.send(message.createReply(ret));
2080 } else if (function == "GetText"_L1) {
2081 int startOffset = message.arguments().at(0).toInt();
2082 int endOffset = message.arguments().at(1).toInt();
2083 if (endOffset == -1) // AT-SPI uses -1 to signal all characters
2084 endOffset = interface->textInterface()->characterCount();
2085 sendReply(connection, message, interface->textInterface()->text(startOffset, endOffset));
2086 } else if (function == "GetTextAfterOffset"_L1) {
2087 int offset = message.arguments().at(0).toInt();
2088 int type = message.arguments().at(1).toUInt();
2089 int startOffset, endOffset;
2090 QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2092 ret << text << startOffset << endOffset;
2093 connection.send(message.createReply(ret));
2094 } else if (function == "GetTextAtOffset"_L1) {
2095 int offset = message.arguments().at(0).toInt();
2096 int type = message.arguments().at(1).toUInt();
2097 int startOffset, endOffset;
2098 QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2100 ret << text << startOffset << endOffset;
2101 connection.send(message.createReply(ret));
2102 } else if (function == "GetTextBeforeOffset"_L1) {
2103 int offset = message.arguments().at(0).toInt();
2104 int type = message.arguments().at(1).toUInt();
2105 int startOffset, endOffset;
2106 QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2108 ret << text << startOffset << endOffset;
2109 connection.send(message.createReply(ret));
2110 } else if (function == "RemoveSelection"_L1) {
2111 int selectionNum = message.arguments().at(0).toInt();
2112 interface->textInterface()->removeSelection(selectionNum);
2114 } else if (function == "SetCaretOffset"_L1) {
2115 int offset = message.arguments().at(0).toInt();
2116 interface->textInterface()->setCursorPosition(offset);
2118 } else if (function == "ScrollSubstringTo"_L1) {
2119 int startOffset = message.arguments().at(0).toInt();
2120 int endOffset = message.arguments().at(1).toInt();
2121 // ignore third parameter (scroll type), since QAccessibleTextInterface::scrollToSubstring doesn't have that
2122 qCInfo(lcAccessibilityAtspi) << "AtSpiAdaptor::ScrollSubstringTo doesn'take take scroll type into account.";
2123 interface->textInterface()->scrollToSubstring(startOffset, endOffset);
2125 } else if (function == "SetSelection"_L1) {
2126 int selectionNum = message.arguments().at(0).toInt();
2127 int startOffset = message.arguments().at(1).toInt();
2128 int endOffset = message.arguments().at(2).toInt();
2129 interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
2131 } else {
2132 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::textInterface does not implement" << function << message.path();
2133 return false;
2134 }
2135 return true;
2136}
2137
2138QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiBoundaryType(int atspiTextBoundaryType)
2139{
2140 switch (atspiTextBoundaryType) {
2141 case ATSPI_TEXT_BOUNDARY_CHAR:
2142 return QAccessible::CharBoundary;
2143 case ATSPI_TEXT_BOUNDARY_WORD_START:
2144 case ATSPI_TEXT_BOUNDARY_WORD_END:
2145 return QAccessible::WordBoundary;
2146 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
2147 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
2148 return QAccessible::SentenceBoundary;
2149 case ATSPI_TEXT_BOUNDARY_LINE_START:
2150 case ATSPI_TEXT_BOUNDARY_LINE_END:
2151 return QAccessible::LineBoundary;
2152 }
2153 Q_ASSERT_X(0, "", "Requested invalid boundary type.");
2154 return QAccessible::CharBoundary;
2155}
2156
2157bool AtSpiAdaptor::isValidAtspiTextGranularity(uint atspiTextGranularity)
2158{
2159 if (atspiTextGranularity == ATSPI_TEXT_GRANULARITY_CHAR
2160 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_WORD
2161 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_SENTENCE
2162 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_LINE
2163 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_PARAGRAPH)
2164 return true;
2165
2166 qCWarning(lcAccessibilityAtspi) << "Unknown value" << atspiTextGranularity << "for AT-SPI text granularity type";
2167 return false;
2168}
2169
2170QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiTextGranularity(uint atspiTextGranularity)
2171{
2172 Q_ASSERT(isValidAtspiTextGranularity(atspiTextGranularity));
2173
2174 switch (atspiTextGranularity) {
2175 case ATSPI_TEXT_GRANULARITY_CHAR:
2176 return QAccessible::CharBoundary;
2177 case ATSPI_TEXT_GRANULARITY_WORD:
2178 return QAccessible::WordBoundary;
2179 case ATSPI_TEXT_GRANULARITY_SENTENCE:
2180 return QAccessible::SentenceBoundary;
2181 case ATSPI_TEXT_GRANULARITY_LINE:
2182 return QAccessible::LineBoundary;
2183 case ATSPI_TEXT_GRANULARITY_PARAGRAPH:
2184 return QAccessible::ParagraphBoundary;
2185 }
2186 return QAccessible::CharBoundary;
2187}
2188
2189namespace
2190{
2191 struct AtSpiAttribute {
2192 QString name;
2193 QString value;
2194 AtSpiAttribute(const QString &aName, const QString &aValue) : name(aName), value(aValue) {}
2195 bool isNull() const { return name.isNull() || value.isNull(); }
2196 };
2197
2198 QString atspiColor(const QString &ia2Color)
2199 {
2200 // "rgb(%u,%u,%u)" -> "%u,%u,%u"
2201 return ia2Color.mid(4, ia2Color.size() - (4+1)).replace(u"\\,"_s, u","_s);
2202 }
2203
2204 QString atspiSize(const QString &ia2Size)
2205 {
2206 // "%fpt" -> "%f"
2207 return ia2Size.left(ia2Size.size() - 2);
2208 }
2209
2210 AtSpiAttribute atspiTextAttribute(const QString &ia2Name, const QString &ia2Value)
2211 {
2212 QString name = ia2Name;
2213 QString value = ia2Value;
2214
2215 // IAccessible2: https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
2216 // ATK attribute names: https://gitlab.gnome.org/GNOME/orca/-/blob/master/src/orca/text_attribute_names.py
2217 // ATK attribute values: https://gnome.pages.gitlab.gnome.org/atk/AtkText.html#AtkTextAttribute
2218
2219 // https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes"
2220 // specifically for "weight", "invalid", "language" and value range for colors
2221
2222 if (ia2Name == "background-color"_L1) {
2223 name = QStringLiteral("bg-color");
2224 value = atspiColor(value);
2225 } else if (ia2Name == "font-family"_L1) {
2226 name = QStringLiteral("family-name");
2227 } else if (ia2Name == "color"_L1) {
2228 name = QStringLiteral("fg-color");
2229 value = atspiColor(value);
2230 } else if (ia2Name == "text-align"_L1) {
2231 name = QStringLiteral("justification");
2232 if (value == "justify"_L1) {
2233 value = QStringLiteral("fill");
2234 } else if (value != "left"_L1 && value != "right"_L1 && value != "center"_L1) {
2235 qCDebug(lcAccessibilityAtspi) << "Unknown text-align attribute value \""
2236 << value << "\" cannot be translated to AT-SPI.";
2237 value = QString();
2238 }
2239 } else if (ia2Name == "font-size"_L1) {
2240 name = QStringLiteral("size");
2241 value = atspiSize(value);
2242 } else if (ia2Name == "font-style"_L1) {
2243 name = QStringLiteral("style");
2244 if (value != "normal"_L1 && value != "italic"_L1 && value != "oblique"_L1) {
2245 qCDebug(lcAccessibilityAtspi) << "Unknown font-style attribute value \"" << value
2246 << "\" cannot be translated to AT-SPI.";
2247 value = QString();
2248 }
2249 } else if (ia2Name == "text-underline-type"_L1) {
2250 name = QStringLiteral("underline");
2251 if (value != "none"_L1 && value != "single"_L1 && value != "double"_L1) {
2252 qCDebug(lcAccessibilityAtspi) << "Unknown text-underline-type attribute value \""
2253 << value << "\" cannot be translated to AT-SPI.";
2254 value = QString();
2255 }
2256 } else if (ia2Name == "font-weight"_L1) {
2257 name = QStringLiteral("weight");
2258 if (value == "normal"_L1)
2259 // Orca seems to accept all IAccessible2 values except for "normal"
2260 // (on which it produces traceback and fails to read any following text attributes),
2261 // but that is the default value, so omit it anyway
2262 value = QString();
2263 } else if (((ia2Name == "text-line-through-style"_L1 || ia2Name == "text-line-through-type"_L1) && (ia2Value != "none"_L1))
2264 || (ia2Name == "text-line-through-text"_L1 && !ia2Value.isEmpty())) {
2265 // if any of the above is set, set "strikethrough" to true, but don't explicitly set
2266 // to false otherwise, since any of the others might still be set to indicate strikethrough
2267 // and no strikethrough is assumed anyway when nothing is explicitly set
2268 name = QStringLiteral("strikethrough");
2269 value = QStringLiteral("true");
2270 } else if (ia2Name == "text-position"_L1) {
2271 name = QStringLiteral("vertical-align");
2272 if (value != "baseline"_L1 && value != "super"_L1 && value != "sub"_L1) {
2273 qCDebug(lcAccessibilityAtspi) << "Unknown text-position attribute value \"" << value
2274 << "\" cannot be translated to AT-SPI.";
2275 value = QString();
2276 }
2277 } else if (ia2Name == "writing-mode"_L1) {
2278 name = QStringLiteral("direction");
2279 if (value == "lr"_L1)
2280 value = QStringLiteral("ltr");
2281 else if (value == "rl"_L1)
2282 value = QStringLiteral("rtl");
2283 else if (value == "tb"_L1) {
2284 // IAccessible2 docs refer to XSL, which specifies "tb" is shorthand for "tb-rl"; so at least give a hint about the horizontal direction (ATK does not support vertical direction in this attribute (yet))
2285 value = QStringLiteral("rtl");
2286 qCDebug(lcAccessibilityAtspi) << "writing-mode attribute value \"tb\" translated only w.r.t. horizontal direction; vertical direction ignored";
2287 } else {
2288 qCDebug(lcAccessibilityAtspi) << "Unknown writing-mode attribute value \"" << value
2289 << "\" cannot be translated to AT-SPI.";
2290 value = QString();
2291 }
2292 } else if (ia2Name == "language"_L1) {
2293 // OK - ATK has no docs on the format of the value, IAccessible2 has reasonable format - leave it at that now
2294 } else if (ia2Name == "invalid"_L1) {
2295 // OK - ATK docs are vague but suggest they support the same range of values as IAccessible2
2296 } else {
2297 // attribute we know nothing about
2298 name = QString();
2299 value = QString();
2300 }
2301 return AtSpiAttribute(name, value);
2302 }
2303}
2304
2305// FIXME all attribute methods below should share code
2306QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
2307{
2308 Q_UNUSED(includeDefaults);
2309
2311 int startOffset;
2312 int endOffset;
2313
2314 QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
2315 const QStringList attributes = joined.split(u';', Qt::SkipEmptyParts, Qt::CaseSensitive);
2316 for (const QString &attr : attributes) {
2318 if (items.count() == 2)
2319 {
2320 AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
2321 if (!attribute.isNull())
2322 set[attribute.name] = attribute.value;
2323 }
2324 }
2325
2327 list << QVariant::fromValue(set) << startOffset << endOffset;
2328
2329 return list;
2330}
2331
2332QString AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, int offset, const QString &attributeName) const
2333{
2334 QString joined;
2336 int startOffset;
2337 int endOffset;
2338
2339 joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
2340 const QStringList attributes = joined.split (u';', Qt::SkipEmptyParts, Qt::CaseSensitive);
2341 for (const QString& attr : attributes) {
2343 items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
2344 AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
2345 if (!attribute.isNull())
2346 map[attribute.name] = attribute.value;
2347 }
2348 return map[attributeName];
2349}
2350
2351QList<QVariant> AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const
2352{
2353 QRect rect = interface->textInterface()->characterRect(offset);
2354 rect = translateFromScreenCoordinates(interface, rect, coordType);
2355 return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
2356}
2357
2358QList<QVariant> AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface,
2359 int startOffset, int endOffset, uint coordType) const
2360{
2361 if (endOffset == -1)
2362 endOffset = interface->textInterface()->characterCount();
2363
2364 QAccessibleTextInterface *textInterface = interface->textInterface();
2365 if (endOffset <= startOffset || !textInterface)
2366 return QList<QVariant>() << -1 << -1 << 0 << 0;
2367
2368 QRect rect = textInterface->characterRect(startOffset);
2369 for (int i=startOffset + 1; i <= endOffset; i++)
2370 rect = rect | textInterface->characterRect(i);
2371
2372 rect = translateFromScreenCoordinates(interface, rect, coordType);
2373 return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
2374}
2375
2376bool AtSpiAdaptor::isValidCoordType(uint coordType)
2377{
2378 if (coordType == ATSPI_COORD_TYPE_SCREEN || coordType == ATSPI_COORD_TYPE_WINDOW || coordType == ATSPI_COORD_TYPE_PARENT)
2379 return true;
2380
2381 qCWarning(lcAccessibilityAtspi) << "Unknown value" << coordType << "for AT-SPI coord type";
2382 return false;
2383}
2384
2385QRect AtSpiAdaptor::translateFromScreenCoordinates(QAccessibleInterface *interface, const QRect &screenRect, uint targetCoordType)
2386{
2387 Q_ASSERT(isValidCoordType(targetCoordType));
2388
2389 QAccessibleInterface *upper = nullptr;
2390 if (targetCoordType == ATSPI_COORD_TYPE_WINDOW)
2391 upper = getWindow(interface);
2392 else if (targetCoordType == ATSPI_COORD_TYPE_PARENT)
2393 upper = interface->parent();
2394
2395 QRect rect = screenRect;
2396 if (upper)
2397 rect.translate(-upper->rect().x(), -upper->rect().y());
2398
2399 return rect;
2400}
2401
2402QPoint AtSpiAdaptor::translateToScreenCoordinates(QAccessibleInterface *interface, const QPoint &pos, uint fromCoordType)
2403{
2404 Q_ASSERT(isValidCoordType(fromCoordType));
2405
2406 QAccessibleInterface *upper = nullptr;
2407 if (fromCoordType == ATSPI_COORD_TYPE_WINDOW)
2408 upper = getWindow(interface);
2409 else if (fromCoordType == ATSPI_COORD_TYPE_PARENT)
2410 upper = interface->parent();
2411
2412 QPoint screenPos = pos;
2413 if (upper)
2414 screenPos += upper->rect().topLeft();
2415
2416 return screenPos;
2417}
2418
2419// Editable Text interface
2420static QString textForRange(QAccessibleInterface *accessible, int startOffset, int endOffset)
2421{
2422 if (QAccessibleTextInterface *textIface = accessible->textInterface()) {
2423 if (endOffset == -1)
2424 endOffset = textIface->characterCount();
2425 return textIface->text(startOffset, endOffset);
2426 }
2427 QString txt = accessible->text(QAccessible::Value);
2428 if (endOffset == -1)
2429 endOffset = txt.size();
2430 return txt.mid(startOffset, endOffset - startOffset);
2431}
2432
2433static void replaceTextFallback(QAccessibleInterface *accessible, long startOffset, long endOffset, const QString &txt)
2434{
2435 QString t = textForRange(accessible, 0, -1);
2436 if (endOffset == -1)
2437 endOffset = t.size();
2438 if (endOffset - startOffset == 0)
2439 t.insert(startOffset, txt);
2440 else
2441 t.replace(startOffset, endOffset - startOffset, txt);
2442 accessible->setText(QAccessible::Value, t);
2443}
2444
2445bool AtSpiAdaptor::editableTextInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2446{
2447 if (function == "CopyText"_L1) {
2448#ifndef QT_NO_CLIPBOARD
2449 int startOffset = message.arguments().at(0).toInt();
2450 int endOffset = message.arguments().at(1).toInt();
2451 const QString t = textForRange(interface, startOffset, endOffset);
2452 QGuiApplication::clipboard()->setText(t);
2453#endif
2454 connection.send(message.createReply(true));
2455 } else if (function == "CutText"_L1) {
2456#ifndef QT_NO_CLIPBOARD
2457 int startOffset = message.arguments().at(0).toInt();
2458 int endOffset = message.arguments().at(1).toInt();
2459 const QString t = textForRange(interface, startOffset, endOffset);
2460 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2461 editableTextIface->deleteText(startOffset, endOffset);
2462 else
2463 replaceTextFallback(interface, startOffset, endOffset, QString());
2464 QGuiApplication::clipboard()->setText(t);
2465#endif
2466 connection.send(message.createReply(true));
2467 } else if (function == "DeleteText"_L1) {
2468 int startOffset = message.arguments().at(0).toInt();
2469 int endOffset = message.arguments().at(1).toInt();
2470 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2471 editableTextIface->deleteText(startOffset, endOffset);
2472 else
2473 replaceTextFallback(interface, startOffset, endOffset, QString());
2474 connection.send(message.createReply(true));
2475 } else if (function == "InsertText"_L1) {
2476 int position = message.arguments().at(0).toInt();
2477 QString text = message.arguments().at(1).toString();
2478 int length = message.arguments().at(2).toInt();
2480 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2481 editableTextIface->insertText(position, text);
2482 else
2483 replaceTextFallback(interface, position, position, text);
2484 connection.send(message.createReply(true));
2485 } else if (function == "PasteText"_L1) {
2486#ifndef QT_NO_CLIPBOARD
2487 int position = message.arguments().at(0).toInt();
2488 const QString txt = QGuiApplication::clipboard()->text();
2489 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2490 editableTextIface->insertText(position, txt);
2491 else
2492 replaceTextFallback(interface, position, position, txt);
2493#endif
2494 connection.send(message.createReply(true));
2495 } else if (function == "SetTextContents"_L1) {
2496 QString newContents = message.arguments().at(0).toString();
2497 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2498 editableTextIface->replaceText(0, interface->textInterface()->characterCount(), newContents);
2499 else
2500 replaceTextFallback(interface, 0, -1, newContents);
2501 connection.send(message.createReply(true));
2502 } else if (function.isEmpty()) {
2503 connection.send(message.createReply());
2504 } else {
2505 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::editableTextInterface does not implement" << function << message.path();
2506 return false;
2507 }
2508 return true;
2509}
2510
2511// Value interface
2512bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2513{
2514 QAccessibleValueInterface *valueIface = interface->valueInterface();
2515 if (!valueIface)
2516 return false;
2517
2518 if (function == "SetCurrentValue"_L1) {
2519 QDBusVariant v = qvariant_cast<QDBusVariant>(message.arguments().at(2));
2520 double value = v.variant().toDouble();
2521 //Temporary fix
2522 //See https://bugzilla.gnome.org/show_bug.cgi?id=652596
2523 valueIface->setCurrentValue(value);
2524 connection.send(message.createReply());
2525 } else {
2527 if (function == "GetCurrentValue"_L1)
2528 value = valueIface->currentValue();
2529 else if (function == "GetMaximumValue"_L1)
2530 value = valueIface->maximumValue();
2531 else if (function == "GetMinimumIncrement"_L1)
2532 value = valueIface->minimumStepSize();
2533 else if (function == "GetMinimumValue"_L1)
2534 value = valueIface->minimumValue();
2535 else {
2536 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface does not implement" << function << message.path();
2537 return false;
2538 }
2539 if (!value.canConvert<double>()) {
2540 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface: Could not convert to double:" << function;
2541 }
2542
2543 // explicitly convert to dbus-variant containing one double since atspi expects that
2544 // everything else might fail to convert back on the other end
2545 connection.send(message.createReply(
2547 }
2548 return true;
2549}
2550
2551// Selection interface
2552bool AtSpiAdaptor::selectionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2553{
2554 QAccessibleSelectionInterface* selectionInterface = interface->selectionInterface();
2555 if (!selectionInterface) {
2556 qCWarning(lcAccessibilityAtspi) << "Could not find selection interface for: " << message.path() << interface;
2557 return false;
2558 }
2559
2560 if (function == "ClearSelection"_L1 ) {
2561 connection.send(message.createReply(QVariant::fromValue((selectionInterface->clear()))));
2562 } else if (function == "DeselectChild"_L1 ) {
2563 int childIndex = message.arguments().at(0).toInt();
2564 bool ret = false;
2565 QAccessibleInterface *child = interface->child(childIndex);
2566 if (child)
2567 ret = selectionInterface->unselect(child);
2568 connection.send(message.createReply(QVariant::fromValue(ret)));
2569 } else if (function == "DeselectSelectedChild"_L1 ) {
2570 int selectionIndex = message.arguments().at(0).toInt();
2571 bool ret = false;
2572 QAccessibleInterface *selectedChild = selectionInterface->selectedItem(selectionIndex);
2573 if (selectedChild)
2574 ret = selectionInterface->unselect(selectedChild);
2575 connection.send(message.createReply(QVariant::fromValue(ret)));
2576 } else if (function == "GetNSelectedChildren"_L1) {
2578 QVariant::fromValue(selectionInterface->selectedItemCount())))));
2579 } else if (function == "GetSelectedChild"_L1) {
2580 int selectionIndex = message.arguments().at(0).toInt();
2581 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(selectionInterface->selectedItem(selectionIndex))));
2582 connection.send(message.createReply(QVariant::fromValue(ref)));
2583 } else if (function == "IsChildSelected"_L1 ) {
2584 int childIndex = message.arguments().at(0).toInt();
2585 bool ret = false;
2586 QAccessibleInterface *child = interface->child(childIndex);
2587 if (child)
2588 ret = selectionInterface->isSelected(child);
2589 connection.send(message.createReply(QVariant::fromValue(ret)));
2590 } else if (function == "SelectAll"_L1 ) {
2591 connection.send(message.createReply(QVariant::fromValue(selectionInterface->selectAll())));
2592 } else if (function == "SelectChild"_L1 ) {
2593 int childIndex = message.arguments().at(0).toInt();
2594 bool ret = false;
2595 QAccessibleInterface *child = interface->child(childIndex);
2596 if (child)
2597 ret = selectionInterface->select(child);
2598 connection.send(message.createReply(QVariant::fromValue(ret)));
2599 } else {
2600 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::selectionInterface does not implement " << function << message.path();
2601 return false;
2602 }
2603
2604 return true;
2605}
2606
2607
2608// Table interface
2609bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2610{
2611 if (!(interface->tableInterface() || interface->tableCellInterface())) {
2612 qCWarning(lcAccessibilityAtspi) << "Qt AtSpiAdaptor: Could not find table interface for:" << message.path() << interface;
2613 return false;
2614 }
2615
2616 if (function == "GetCaption"_L1) {
2617 QAccessibleInterface * captionInterface= interface->tableInterface()->caption();
2618 if (captionInterface) {
2619 QSpiObjectReference ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(captionInterface)));
2621 } else {
2623 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))))));
2624 }
2625 } else if (function == "GetNColumns"_L1) {
2627 QVariant::fromValue(interface->tableInterface()->columnCount())))));
2628 } else if (function == "GetNRows"_L1) {
2630 QVariant::fromValue(interface->tableInterface()->rowCount())))));
2631 } else if (function == "GetNSelectedColumns"_L1) {
2633 QVariant::fromValue(interface->tableInterface()->selectedColumnCount())))));
2634 } else if (function == "GetNSelectedRows"_L1) {
2636 QVariant::fromValue(interface->tableInterface()->selectedRowCount())))));
2637 } else if (function == "GetSummary"_L1) {
2638 QAccessibleInterface *summary = interface->tableInterface() ? interface->tableInterface()->summary() : nullptr;
2639 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(summary)));
2641 } else if (function == "GetAccessibleAt"_L1) {
2642 int row = message.arguments().at(0).toInt();
2643 int column = message.arguments().at(1).toInt();
2644 if ((row < 0) ||
2645 (column < 0) ||
2646 (row >= interface->tableInterface()->rowCount()) ||
2647 (column >= interface->tableInterface()->columnCount())) {
2648 qCWarning(lcAccessibilityAtspi) << "Invalid index for tableInterface GetAccessibleAt (" << row << "," << column << ')';
2649 return false;
2650 }
2651
2653 QAccessibleInterface * cell(interface->tableInterface()->cellAt(row, column));
2654 if (cell) {
2655 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell)));
2656 } else {
2657 qCWarning(lcAccessibilityAtspi) << "No cell interface returned for" << interface->object() << row << column;
2659 }
2660 connection.send(message.createReply(QVariant::fromValue(ref)));
2661
2662 } else if (function == "GetIndexAt"_L1) {
2663 int row = message.arguments().at(0).toInt();
2664 int column = message.arguments().at(1).toInt();
2665 QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column);
2666 if (!cell) {
2667 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::GetIndexAt(" << row << ',' << column << ") did not find a cell." << interface;
2668 return false;
2669 }
2670 int index = interface->indexOfChild(cell);
2671 qCDebug(lcAccessibilityAtspi) << "QSpiAdaptor::GetIndexAt row:" << row << " col:" << column << " logical index:" << index;
2672 Q_ASSERT(index > 0);
2673 connection.send(message.createReply(index));
2674 } else if ((function == "GetColumnAtIndex"_L1) || (function == "GetRowAtIndex"_L1)) {
2675 int index = message.arguments().at(0).toInt();
2676 int ret = -1;
2677 if (index >= 0) {
2678 QAccessibleInterface * cell = interface->child(index);
2679 if (cell) {
2680 if (function == "GetColumnAtIndex"_L1) {
2681 if (cell->role() == QAccessible::ColumnHeader) {
2682 ret = index;
2683 } else if (cell->role() == QAccessible::RowHeader) {
2684 ret = -1;
2685 } else {
2686 if (!cell->tableCellInterface()) {
2687 qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No table cell interface: " << cell;
2688 return false;
2689 }
2690 ret = cell->tableCellInterface()->columnIndex();
2691 }
2692 } else {
2693 if (cell->role() == QAccessible::ColumnHeader) {
2694 ret = -1;
2695 } else if (cell->role() == QAccessible::RowHeader) {
2696 ret = index % interface->tableInterface()->columnCount();
2697 } else {
2698 if (!cell->tableCellInterface()) {
2699 qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No table cell interface: " << cell;
2700 return false;
2701 }
2702 ret = cell->tableCellInterface()->rowIndex();
2703 }
2704 }
2705 } else {
2706 qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No cell at index: " << index << " " << interface;
2707 return false;
2708 }
2709 }
2710 connection.send(message.createReply(ret));
2711
2712 } else if (function == "GetColumnDescription"_L1) {
2713 int column = message.arguments().at(0).toInt();
2714 connection.send(message.createReply(interface->tableInterface()->columnDescription(column)));
2715 } else if (function == "GetRowDescription"_L1) {
2716 int row = message.arguments().at(0).toInt();
2717 connection.send(message.createReply(interface->tableInterface()->rowDescription(row)));
2718
2719
2720
2721 } else if (function == "GetRowColumnExtentsAtIndex"_L1) {
2722 int index = message.arguments().at(0).toInt();
2723 bool success = false;
2724
2725 int row = -1;
2726 int col = -1;
2727 int rowExtents = -1;
2728 int colExtents = -1;
2729 bool isSelected = false;
2730
2731 int cols = interface->tableInterface()->columnCount();
2732 if (cols > 0) {
2733 row = index / cols;
2734 col = index % cols;
2735 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, col)) {
2736 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) {
2737 row = cellIface->rowIndex();
2738 col = cellIface->columnIndex();
2739 rowExtents = cellIface->rowExtent();
2740 colExtents = cellIface->columnExtent();
2741 isSelected = cellIface->isSelected();
2742 success = true;
2743 }
2744 }
2745 }
2747 list << success << row << col << rowExtents << colExtents << isSelected;
2748 connection.send(message.createReply(list));
2749
2750 } else if (function == "GetColumnExtentAt"_L1) {
2751 int row = message.arguments().at(0).toInt();
2752 int column = message.arguments().at(1).toInt();
2753 int columnExtent = 0;
2754 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
2755 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2756 columnExtent = cellIface->columnExtent();
2757 }
2758 connection.send(message.createReply(columnExtent));
2759
2760 } else if (function == "GetRowExtentAt"_L1) {
2761 int row = message.arguments().at(0).toInt();
2762 int column = message.arguments().at(1).toInt();
2763 int rowExtent = 0;
2764 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
2765 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2766 rowExtent = cellIface->rowExtent();
2767 }
2768 connection.send(message.createReply(rowExtent));
2769
2770 } else if (function == "GetColumnHeader"_L1) {
2771 int column = message.arguments().at(0).toInt();
2773
2774 QAccessibleInterface * cell(interface->tableInterface()->cellAt(0, column));
2775 if (cell && cell->tableCellInterface()) {
2776 QList<QAccessibleInterface*> header = cell->tableCellInterface()->columnHeaderCells();
2777 if (header.size() > 0) {
2778 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
2779 }
2780 }
2781 connection.send(message.createReply(QVariant::fromValue(ref)));
2782
2783 } else if (function == "GetRowHeader"_L1) {
2784 int row = message.arguments().at(0).toInt();
2786 QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, 0);
2787 if (cell && cell->tableCellInterface()) {
2788 QList<QAccessibleInterface*> header = cell->tableCellInterface()->rowHeaderCells();
2789 if (header.size() > 0) {
2790 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
2791 }
2792 }
2793 connection.send(message.createReply(QVariant::fromValue(ref)));
2794
2795 } else if (function == "GetSelectedColumns"_L1) {
2796 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedColumns())));
2797 } else if (function == "GetSelectedRows"_L1) {
2798 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedRows())));
2799 } else if (function == "IsColumnSelected"_L1) {
2800 int column = message.arguments().at(0).toInt();
2801 connection.send(message.createReply(interface->tableInterface()->isColumnSelected(column)));
2802 } else if (function == "IsRowSelected"_L1) {
2803 int row = message.arguments().at(0).toInt();
2804 connection.send(message.createReply(interface->tableInterface()->isRowSelected(row)));
2805 } else if (function == "IsSelected"_L1) {
2806 int row = message.arguments().at(0).toInt();
2807 int column = message.arguments().at(1).toInt();
2808 bool selected = false;
2809 if (QAccessibleInterface* cell = interface->tableInterface()->cellAt(row, column)) {
2810 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2811 selected = cellIface->isSelected();
2812 }
2813 connection.send(message.createReply(selected));
2814 } else if (function == "AddColumnSelection"_L1) {
2815 int column = message.arguments().at(0).toInt();
2816 connection.send(message.createReply(interface->tableInterface()->selectColumn(column)));
2817 } else if (function == "AddRowSelection"_L1) {
2818 int row = message.arguments().at(0).toInt();
2819 connection.send(message.createReply(interface->tableInterface()->selectRow(row)));
2820 } else if (function == "RemoveColumnSelection"_L1) {
2821 int column = message.arguments().at(0).toInt();
2822 connection.send(message.createReply(interface->tableInterface()->unselectColumn(column)));
2823 } else if (function == "RemoveRowSelection"_L1) {
2824 int row = message.arguments().at(0).toInt();
2825 connection.send(message.createReply(interface->tableInterface()->unselectRow(row)));
2826 } else {
2827 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::tableInterface does not implement" << function << message.path();
2828 return false;
2829 }
2830 return true;
2831}
2832
2833// Table cell interface
2834bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2835{
2836 QAccessibleTableCellInterface* cellInterface = interface->tableCellInterface();
2837 if (!cellInterface) {
2838 qCWarning(lcAccessibilityAtspi) << "Could not find table cell interface for: " << message.path() << interface;
2839 return false;
2840 }
2841
2842 if (function == "GetColumnHeaderCells"_L1) {
2843 QSpiObjectReferenceArray headerCells;
2844 const auto headerCellInterfaces = cellInterface->columnHeaderCells();
2845 headerCells.reserve(headerCellInterfaces.size());
2846 for (QAccessibleInterface *cell : headerCellInterfaces) {
2847 const QString childPath = pathForInterface(cell);
2849 headerCells << ref;
2850 }
2851 connection.send(message.createReply(QVariant::fromValue(headerCells)));
2852 } else if (function == "GetColumnSpan"_L1) {
2854 QVariant::fromValue(cellInterface->columnExtent())))));
2855 } else if (function == "GetPosition"_L1) {
2856 const int row = cellInterface->rowIndex();
2857 const int column = cellInterface->columnIndex();
2860 } else if (function == "GetRowHeaderCells"_L1) {
2861 QSpiObjectReferenceArray headerCells;
2862 const auto headerCellInterfaces = cellInterface->rowHeaderCells();
2863 headerCells.reserve(headerCellInterfaces.size());
2864 for (QAccessibleInterface *cell : headerCellInterfaces) {
2865 const QString childPath = pathForInterface(cell);
2867 headerCells << ref;
2868 }
2869 connection.send(message.createReply(QVariant::fromValue(headerCells)));
2870 } else if (function == "GetRowSpan"_L1) {
2872 QVariant::fromValue(cellInterface->rowExtent())))));
2873 } else if (function == "GetRowColumnSpan"_L1) {
2875 list << cellInterface->rowIndex() << cellInterface->columnIndex() << cellInterface->rowExtent() << cellInterface->columnExtent();
2876 connection.send(message.createReply(list));
2877 } else if (function == "GetTable"_L1) {
2879 QAccessibleInterface* table = cellInterface->table();
2880 if (table && table->tableInterface())
2883 } else {
2884 qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::tableCellInterface does not implement" << function << message.path();
2885 return false;
2886 }
2887
2888 return true;
2889}
2890
2892
2893#include "moc_atspiadaptor_p.cpp"
2894#endif // QT_CONFIG(accessibility)
bool isActive
QString introspect(const QString &path) const override
void notify(QAccessibleEvent *event)
void windowActivated(QObject *window, bool active)
void registerApplication()
void eventListenerDeregistered(const QString &bus, const QString &path)
bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) override
This function needs to handle all messages to the path of the virtual object, when the SubPath option...
void eventListenerRegistered(const QString &bus, const QString &path)
Connects to the accessibility dbus.
QDBusConnection connection() const
Returns the DBus connection that got established.
\inmodule QtGui
\inmodule QtDBus
bool send(const QDBusMessage &message) const
Sends the message over this connection, without waiting for a reply.
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode=QDBus::Block, int timeout=-1) const
Sends the message over this connection and blocks, waiting for a reply, for at most timeout milliseco...
\inmodule QtDBus
static QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
Constructs a new DBus message with the given path, interface and name, representing a signal emission...
static QDBusMessage createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
Constructs a new DBus message representing a method call.
\inmodule QtDBus
\inmodule QtDBus
void setVariant(const QVariant &variant)
Assigns the value of the given Qt variant to this D-Bus variant.
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
bool isEmpty() const noexcept
Definition qlist.h:401
qsizetype count() const noexcept
Definition qlist.h:398
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
NetworkError error() const
Returns the error that was found during the processing of this request.
\inmodule QtCore
Definition qobject.h:103
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition qobject.h:348
bool isWidgetType() const
Returns true if the object is a widget; otherwise returns false.
Definition qobject.h:131
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
Definition qrect.h:245
static RoleNames namesForRole(QAccessible::Role role)
void sendEvents(bool active)
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:8218
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString & prepend(QChar c)
Definition qstring.h:478
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2668
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QMap< QString, QString > map
[6]
QString text
void sendReply(RequestData *data)
[10]
auto mo
[7]
QList< QVariant > arguments
rect
[4]
else opt state
[0]
QStringList effectiveActionNames(QAccessibleInterface *iface)
bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName)
QString dbusPath()
Combined button and popup list for selecting options.
constexpr QBindableInterface iface
Definition qproperty.h:666
bool isNull(const T &t)
@ CaseSensitive
@ SkipEmptyParts
Definition qnamespace.h:128
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
DBusConnection * connection
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT EGLint attribute
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLsizei width
GLenum type
GLuint GLsizei const GLchar * message
GLuint start
GLenum GLuint GLintptr offset
GLsizei const GLubyte GLsizei GLenum coordType
GLint ref
GLuint name
GLint y
GLenum GLenum GLsizei void GLsizei void * column
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLenum GLenum GLsizei void * table
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW
#define ATSPI_DBUS_INTERFACE_TABLE
#define ATSPI_DBUS_PATH_ROOT
#define ATSPI_DBUS_INTERFACE_EVENT_FOCUS
#define QSPI_OBJECT_PATH_PREFIX
#define ATSPI_DBUS_INTERFACE_SELECTION
#define QSPI_OBJECT_PATH_ROOT
#define ATSPI_DBUS_INTERFACE_APPLICATION
#define ATSPI_DBUS_INTERFACE_ACCESSIBLE
AtspiRelationType qAccessibleRelationToAtSpiRelation(QAccessible::Relation relation)
#define ATSPI_DBUS_INTERFACE_COMPONENT
quint64 spiStatesFromQState(QAccessible::State state)
#define ATSPI_DBUS_INTERFACE_EVENT_OBJECT
void setSpiStateBit(quint64 *state, AtspiStateType spiState)
QSpiUIntList spiStateSetFromSpiStates(quint64 states)
#define ATSPI_DBUS_INTERFACE_ACTION
#define ATSPI_DBUS_INTERFACE_VALUE
#define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT
#define ATSPI_DBUS_INTERFACE_TEXT
#define QSPI_REGISTRY_NAME
QList< QSpiTextRange > QSpiTextRangeList
QMap< QString, QString > QSpiAttributeSet
QList< QSpiRelationArrayEntry > QSpiRelationArray
QList< QSpiAction > QSpiActionArray
QList< QSpiEventListener > QSpiEventListenerArray
QPair< unsigned int, QSpiObjectReferenceArray > QSpiRelationArrayEntry
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_UNUSED(x)
QT_BEGIN_NAMESPACE Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char * qVersion(void) Q_DECL_NOEXCEPT
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
static QString windowTitle(HWND hwnd)
QList< int > list
[14]
QFuture< QSet< QChar > > set
[10]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QTcpSocket * socket
[1]
QXmlStreamReader xml
[0]
Text files * txt
QList< QTreeWidgetItem * > items
QApplication app(argc, argv)
[0]
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QAction * at
QNetworkReply * reply
QDBusArgument argument
char * toString(const MyType &t)
[31]
QJSValueList args
\inmodule QtCore