7#include <QtGui/qwindow.h>
8#include <QtGui/qguiapplication.h>
9#include <qdbusmessage.h>
10#include <qdbusreply.h>
11#include <qclipboard.h>
13#include <QtCore/qloggingcategory.h>
14#include <QtCore/qtversion.h>
16#if QT_CONFIG(accessibility)
17#include "socket_interface.h"
18#include "qspi_constant_mappings_p.h"
19#include <QtCore/private/qstringiterator_p.h>
20#include <QtGui/private/qaccessiblebridgeutils_p.h>
22#include "qspiapplicationadaptor_p.h"
24
25
26
27
28
29
30
31
34#if ATSPI_COORD_TYPE_COUNT < 3
35#define ATSPI_COORD_TYPE_PARENT 2
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
47using namespace Qt::StringLiterals;
48using namespace QtGuiPrivate;
50Q_STATIC_LOGGING_CATEGORY(lcAccessibilityAtspi,
"qt.accessibility.atspi")
51Q_STATIC_LOGGING_CATEGORY(lcAccessibilityAtspiCreation,
"qt.accessibility.atspi.creation")
53AtSpiAdaptor::AtSpiAdaptor(QAtSpiDBusConnection *connection, QObject *parent)
54 : QDBusVirtualObject(parent), m_dbus(connection)
57 , sendObject_active_descendant_changed(0)
58 , sendObject_announcement(0)
59 , sendObject_attributes_changed(0)
60 , sendObject_bounds_changed(0)
61 , sendObject_children_changed(0)
64 , sendObject_column_deleted(0)
65 , sendObject_column_inserted(0)
66 , sendObject_column_reordered(0)
67 , sendObject_link_selected(0)
68 , sendObject_model_changed(0)
69 , sendObject_property_change(0)
70 , sendObject_property_change_accessible_description(0)
71 , sendObject_property_change_accessible_name(0)
72 , sendObject_property_change_accessible_parent(0)
73 , sendObject_property_change_accessible_role(0)
74 , sendObject_property_change_accessible_table_caption(0)
75 , sendObject_property_change_accessible_table_column_description(0)
76 , sendObject_property_change_accessible_table_column_header(0)
77 , sendObject_property_change_accessible_table_row_description(0)
78 , sendObject_property_change_accessible_table_row_header(0)
79 , sendObject_property_change_accessible_table_summary(0)
80 , sendObject_property_change_accessible_value(0)
81 , sendObject_row_deleted(0)
82 , sendObject_row_inserted(0)
83 , sendObject_row_reordered(0)
84 , sendObject_selection_changed(0)
85 , sendObject_state_changed(0)
86 , sendObject_text_attributes_changed(0)
87 , sendObject_text_bounds_changed(0)
88 , sendObject_text_caret_moved(0)
89 , sendObject_text_changed(0)
92 , sendObject_text_selection_changed(0)
93 , sendObject_value_changed(0)
94 , sendObject_visible_data_changed(0)
96 , sendWindow_activate(0)
98 , sendWindow_create(0)
99 , sendWindow_deactivate(0)
102 , sendWindow_lower(0)
103 , sendWindow_maximize(0)
104 , sendWindow_minimize(0)
106 , sendWindow_raise(0)
107 , sendWindow_reparent(0)
108 , sendWindow_resize(0)
109 , sendWindow_restore(0)
110 , sendWindow_restyle(0)
111 , sendWindow_shade(0)
112 , sendWindow_unshade(0)
114 m_applicationAdaptor =
new QSpiApplicationAdaptor(m_dbus->connection(),
this);
115 connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,
bool)),
this, SLOT(windowActivated(QObject*,
bool)));
117 updateEventListeners();
118 bool success = m_dbus->connection().connect(
"org.a11y.atspi.Registry"_L1,
"/org/a11y/atspi/registry"_L1,
119 "org.a11y.atspi.Registry"_L1,
"EventListenerRegistered"_L1,
this,
120 SLOT(eventListenerRegistered(QString,QString)));
121 success = success && m_dbus->connection().connect(
"org.a11y.atspi.Registry"_L1,
"/org/a11y/atspi/registry"_L1,
122 "org.a11y.atspi.Registry"_L1,
"EventListenerDeregistered"_L1,
this,
123 SLOT(eventListenerDeregistered(QString,QString)));
126AtSpiAdaptor::~AtSpiAdaptor()
131
132
133QString AtSpiAdaptor::introspect(
const QString &path)
const
135 static const QLatin1StringView accessibleIntrospection(
136 " <interface name=\"org.a11y.atspi.Accessible\">\n"
137 " <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
138 " <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
139 " <property access=\"read\" type=\"s\" name=\"HelpText\"/>\n"
140 " <property access=\"read\" type=\"(so)\" name=\"Parent\">\n"
141 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
143 " <property access=\"read\" type=\"i\" name=\"ChildCount\"/>\n"
144 " <method name=\"GetChildAtIndex\">\n"
145 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
146 " <arg direction=\"out\" type=\"(so)\"/>\n"
147 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
149 " <method name=\"GetChildren\">\n"
150 " <arg direction=\"out\" type=\"a(so)\"/>\n"
151 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
153 " <method name=\"GetIndexInParent\">\n"
154 " <arg direction=\"out\" type=\"i\"/>\n"
156 " <method name=\"GetRelationSet\">\n"
157 " <arg direction=\"out\" type=\"a(ua(so))\"/>\n"
158 " <annotation value=\"QSpiRelationArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
160 " <method name=\"GetRole\">\n"
161 " <arg direction=\"out\" type=\"u\"/>\n"
163 " <method name=\"GetRoleName\">\n"
164 " <arg direction=\"out\" type=\"s\"/>\n"
166 " <method name=\"GetLocalizedRoleName\">\n"
167 " <arg direction=\"out\" type=\"s\"/>\n"
169 " <method name=\"GetState\">\n"
170 " <arg direction=\"out\" type=\"au\"/>\n"
171 " <annotation value=\"QSpiUIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
173 " <method name=\"GetAttributes\">\n"
174 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
175 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
177 " <method name=\"GetApplication\">\n"
178 " <arg direction=\"out\" type=\"(so)\"/>\n"
179 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
181 " <method name=\"GetAccessibleId\">\n"
182 " <arg direction=\"out\" type=\"s\"/>\n"
187 static const QLatin1StringView actionIntrospection(
188 " <interface name=\"org.a11y.atspi.Action\">\n"
189 " <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
190 " <method name=\"GetDescription\">\n"
191 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
192 " <arg direction=\"out\" type=\"s\"/>\n"
194 " <method name=\"GetName\">\n"
195 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
196 " <arg direction=\"out\" type=\"s\"/>\n"
198 " <method name=\"GetKeyBinding\">\n"
199 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
200 " <arg direction=\"out\" type=\"s\"/>\n"
202 " <method name=\"GetActions\">\n"
203 " <arg direction=\"out\" type=\"a(sss)\" name=\"index\"/>\n"
204 " <annotation value=\"QSpiActionArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
206 " <method name=\"DoAction\">\n"
207 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
208 " <arg direction=\"out\" type=\"b\"/>\n"
213 static const QLatin1StringView applicationIntrospection(
214 " <interface name=\"org.a11y.atspi.Application\">\n"
215 " <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
216 " <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
217 " <property access=\"readwrite\" type=\"i\" name=\"Id\"/>\n"
218 " <method name=\"GetLocale\">\n"
219 " <arg direction=\"in\" type=\"u\" name=\"lctype\"/>\n"
220 " <arg direction=\"out\" type=\"s\"/>\n"
222 " <method name=\"GetApplicationBusAddress\">\n"
223 " <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
228 static const QLatin1StringView collectionIntrospection(
229 " <interface name=\"org.a11y.atspi.Collection\">\n"
230 " <method name=\"GetMatches\">\n"
231 " <arg direction=\"in\" name=\"rule\" type=\"(aiia{ss}iaiiasib)\"/>\n"
232 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QSpiMatchRule\"/>\n"
233 " <arg direction=\"in\" name=\"sortby\" type=\"u\"/>\n"
234 " <arg direction=\"in\" name=\"count\" type=\"i\"/>\n"
235 " <arg direction=\"in\" name=\"traverse\" type=\"b\"/>\n"
236 " <arg direction=\"out\" type=\"a(so)\"/>\n"
237 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiReferenceSet\"/>\n"
239 " <method name=\"GetMatchesTo\">\n"
240 " <arg direction=\"in\" name=\"current_object\" type=\"o\"/>\n"
241 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QSpiObjectReference\"/>\n"
242 " <arg direction=\"in\" name=\"rule\" type=\"(aiia{ss}iaiiasib)\"/>\n"
243 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In1\" value=\"QSpiMatchRule\"/>\n"
244 " <arg direction=\"in\" name=\"sortby\" type=\"u\"/>\n"
245 " <arg direction=\"in\" name=\"tree\" type=\"u\"/>\n"
246 " <arg direction=\"in\" name=\"limit_scope\" type=\"b\"/>\n"
247 " <arg direction=\"in\" name=\"count\" type=\"i\"/>\n"
248 " <arg direction=\"in\" name=\"traverse\" type=\"b\"/>\n"
249 " <arg direction=\"out\" type=\"a(so)\"/>\n"
250 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiReferenceSet\"/>\n"
252 " <method name=\"GetMatchesFrom\">\n"
253 " <arg direction=\"in\" name=\"current_object\" type=\"o\"/>\n"
254 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QSpiObjectReference\"/>\n"
255 " <arg direction=\"in\" name=\"rule\" type=\"(aiia{ss}iaiiasib)\"/>\n"
256 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In1\" value=\"QSpiMatchRule\"/>\n"
257 " <arg direction=\"in\" name=\"sortby\" type=\"u\"/>\n"
258 " <arg direction=\"in\" name=\"tree\" type=\"u\"/>\n"
259 " <arg direction=\"in\" name=\"count\" type=\"i\"/>\n"
260 " <arg direction=\"in\" name=\"traverse\" type=\"b\"/>\n"
261 " <arg direction=\"out\" type=\"a(so)\"/>\n"
262 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiReferenceSet\"/>\n"
264 " <method name=\"GetActiveDescendant\">\n"
265 " <arg direction=\"out\" type=\"(so)\"/>\n"
266 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiReferenceSet\"/>\n"
271 static const QLatin1StringView componentIntrospection(
272 " <interface name=\"org.a11y.atspi.Component\">\n"
273 " <method name=\"Contains\">\n"
274 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
275 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
276 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
277 " <arg direction=\"out\" type=\"b\"/>\n"
279 " <method name=\"GetAccessibleAtPoint\">\n"
280 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
281 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
282 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
283 " <arg direction=\"out\" type=\"(so)\"/>\n"
284 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
286 " <method name=\"GetExtents\">\n"
287 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
288 " <arg direction=\"out\" type=\"(iiii)\"/>\n"
289 " <annotation value=\"QSpiRect\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
291 " <method name=\"GetPosition\">\n"
292 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
293 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
294 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
296 " <method name=\"GetSize\">\n"
297 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
298 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
300 " <method name=\"GetLayer\">\n"
301 " <arg direction=\"out\" type=\"u\"/>\n"
303 " <method name=\"GetMDIZOrder\">\n"
304 " <arg direction=\"out\" type=\"n\"/>\n"
306 " <method name=\"GrabFocus\">\n"
307 " <arg direction=\"out\" type=\"b\"/>\n"
309 " <method name=\"GetAlpha\">\n"
310 " <arg direction=\"out\" type=\"d\"/>\n"
312 " <method name=\"SetExtents\">\n"
313 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
314 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
315 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
316 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
317 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
318 " <arg direction=\"out\" type=\"b\"/>\n"
320 " <method name=\"SetPosition\">\n"
321 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
322 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
323 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
324 " <arg direction=\"out\" type=\"b\"/>\n"
326 " <method name=\"SetSize\">\n"
327 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
328 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
329 " <arg direction=\"out\" type=\"b\"/>\n"
334 static const QLatin1StringView editableTextIntrospection(
335 " <interface name=\"org.a11y.atspi.EditableText\">\n"
336 " <method name=\"SetTextContents\">\n"
337 " <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
338 " <arg direction=\"out\" type=\"b\"/>\n"
340 " <method name=\"InsertText\">\n"
341 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
342 " <arg direction=\"in\" type=\"s\" name=\"text\"/>\n"
343 " <arg direction=\"in\" type=\"i\" name=\"length\"/>\n"
344 " <arg direction=\"out\" type=\"b\"/>\n"
346 " <method name=\"CopyText\">\n"
347 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
348 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
350 " <method name=\"CutText\">\n"
351 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
352 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
353 " <arg direction=\"out\" type=\"b\"/>\n"
355 " <method name=\"DeleteText\">\n"
356 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
357 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
358 " <arg direction=\"out\" type=\"b\"/>\n"
360 " <method name=\"PasteText\">\n"
361 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
362 " <arg direction=\"out\" type=\"b\"/>\n"
367 static const QLatin1StringView selectionIntrospection(
368 " <interface name=\"org.a11y.atspi.Selection\">\n"
369 " <property name=\"NSelectedChildren\" type=\"i\" access=\"read\"/>\n"
370 " <method name=\"GetSelectedChild\">\n"
371 " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n"
372 " <arg direction=\"out\" type=\"(so)\"/>\n"
373 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiObjectReference\"/>\n"
375 " <method name=\"SelectChild\">\n"
376 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
377 " <arg direction=\"out\" type=\"b\"/>\n"
379 " <method name=\"DeselectSelectedChild\">\n"
380 " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n"
381 " <arg direction=\"out\" type=\"b\"/>\n"
383 " <method name=\"IsChildSelected\">\n"
384 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
385 " <arg direction=\"out\" type=\"b\"/>\n"
387 " <method name=\"SelectAll\">\n"
388 " <arg direction=\"out\" type=\"b\"/>\n"
390 " <method name=\"ClearSelection\">\n"
391 " <arg direction=\"out\" type=\"b\"/>\n"
393 " <method name=\"DeselectChild\">\n"
394 " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n"
395 " <arg direction=\"out\" type=\"b\"/>\n"
400 static const QLatin1StringView tableIntrospection(
401 " <interface name=\"org.a11y.atspi.Table\">\n"
402 " <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
403 " <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
404 " <property access=\"read\" type=\"(so)\" name=\"Caption\">\n"
405 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
407 " <property access=\"read\" type=\"(so)\" name=\"Summary\">\n"
408 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
410 " <property access=\"read\" type=\"i\" name=\"NSelectedRows\"/>\n"
411 " <property access=\"read\" type=\"i\" name=\"NSelectedColumns\"/>\n"
412 " <method name=\"GetAccessibleAt\">\n"
413 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
414 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
415 " <arg direction=\"out\" type=\"(so)\"/>\n"
416 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
418 " <method name=\"GetIndexAt\">\n"
419 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
420 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
421 " <arg direction=\"out\" type=\"i\"/>\n"
423 " <method name=\"GetRowAtIndex\">\n"
424 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
425 " <arg direction=\"out\" type=\"i\"/>\n"
427 " <method name=\"GetColumnAtIndex\">\n"
428 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
429 " <arg direction=\"out\" type=\"i\"/>\n"
431 " <method name=\"GetRowDescription\">\n"
432 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
433 " <arg direction=\"out\" type=\"s\"/>\n"
435 " <method name=\"GetColumnDescription\">\n"
436 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
437 " <arg direction=\"out\" type=\"s\"/>\n"
439 " <method name=\"GetRowExtentAt\">\n"
440 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
441 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
442 " <arg direction=\"out\" type=\"i\"/>\n"
444 " <method name=\"GetColumnExtentAt\">\n"
445 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
446 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
447 " <arg direction=\"out\" type=\"i\"/>\n"
449 " <method name=\"GetRowHeader\">\n"
450 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
451 " <arg direction=\"out\" type=\"(so)\"/>\n"
452 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
454 " <method name=\"GetColumnHeader\">\n"
455 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
456 " <arg direction=\"out\" type=\"(so)\"/>\n"
457 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
459 " <method name=\"GetSelectedRows\">\n"
460 " <arg direction=\"out\" type=\"ai\"/>\n"
461 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
463 " <method name=\"GetSelectedColumns\">\n"
464 " <arg direction=\"out\" type=\"ai\"/>\n"
465 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
467 " <method name=\"IsRowSelected\">\n"
468 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
469 " <arg direction=\"out\" type=\"b\"/>\n"
471 " <method name=\"IsColumnSelected\">\n"
472 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
473 " <arg direction=\"out\" type=\"b\"/>\n"
475 " <method name=\"IsSelected\">\n"
476 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
477 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
478 " <arg direction=\"out\" type=\"b\"/>\n"
480 " <method name=\"AddRowSelection\">\n"
481 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
482 " <arg direction=\"out\" type=\"b\"/>\n"
484 " <method name=\"AddColumnSelection\">\n"
485 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
486 " <arg direction=\"out\" type=\"b\"/>\n"
488 " <method name=\"RemoveRowSelection\">\n"
489 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
490 " <arg direction=\"out\" type=\"b\"/>\n"
492 " <method name=\"RemoveColumnSelection\">\n"
493 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
494 " <arg direction=\"out\" type=\"b\"/>\n"
496 " <method name=\"GetRowColumnExtentsAtIndex\">\n"
497 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
498 " <arg direction=\"out\" type=\"b\"/>\n"
499 " <arg direction=\"out\" type=\"i\" name=\"row\"/>\n"
500 " <arg direction=\"out\" type=\"i\" name=\"col\"/>\n"
501 " <arg direction=\"out\" type=\"i\" name=\"row_extents\"/>\n"
502 " <arg direction=\"out\" type=\"i\" name=\"col_extents\"/>\n"
503 " <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
508 static const QLatin1StringView tableCellIntrospection(
509 " <interface name=\"org.a11y.atspi.TableCell\">\n"
510 " <property access=\"read\" name=\"ColumnSpan\" type=\"i\" />\n"
511 " <property access=\"read\" name=\"Position\" type=\"(ii)\">\n"
512 " <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QPoint\"/>\n"
514 " <property access=\"read\" name=\"RowSpan\" type=\"i\" />\n"
515 " <property access=\"read\" name=\"Table\" type=\"(so)\" >\n"
516 " <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QSpiObjectReference\"/>\n"
518 " <method name=\"GetRowColumnSpan\">\n"
519 " <arg direction=\"out\" type=\"b\" />\n"
520 " <arg direction=\"out\" name=\"row\" type=\"i\" />\n"
521 " <arg direction=\"out\" name=\"col\" type=\"i\" />\n"
522 " <arg direction=\"out\" name=\"row_extents\" type=\"i\" />\n"
523 " <arg direction=\"out\" name=\"col_extents\" type=\"i\" />\n"
525 " <method name=\"GetColumnHeaderCells\">\n"
526 " <arg direction=\"out\" type=\"a(so)\"/>\n"
527 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
529 " <method name=\"GetRowHeaderCells\">\n"
530 " <arg direction=\"out\" type=\"a(so)\"/>\n"
531 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
536 static const QLatin1StringView textIntrospection(
537 " <interface name=\"org.a11y.atspi.Text\">\n"
538 " <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
539 " <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
540 " <method name=\"GetStringAtOffset\">\n"
541 " <arg direction=\"in\" name=\"offset\" type=\"i\"/>\n"
542 " <arg direction=\"in\" name=\"granularity\" type=\"u\"/>\n"
543 " <arg direction=\"out\" type=\"s\"/>\n"
544 " <arg direction=\"out\" name=\"startOffset\" type=\"i\"/>\n"
545 " <arg direction=\"out\" name=\"endOffset\" type=\"i\"/>\n"
547 " <method name=\"GetText\">\n"
548 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
549 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
550 " <arg direction=\"out\" type=\"s\"/>\n"
552 " <method name=\"SetCaretOffset\">\n"
553 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
554 " <arg direction=\"out\" type=\"b\"/>\n"
556 " <method name=\"GetTextBeforeOffset\">\n"
557 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
558 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
559 " <arg direction=\"out\" type=\"s\"/>\n"
560 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
561 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
563 " <method name=\"GetTextAtOffset\">\n"
564 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
565 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
566 " <arg direction=\"out\" type=\"s\"/>\n"
567 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
568 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
570 " <method name=\"GetTextAfterOffset\">\n"
571 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
572 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
573 " <arg direction=\"out\" type=\"s\"/>\n"
574 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
575 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
577 " <method name=\"GetCharacterAtOffset\">\n"
578 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
579 " <arg direction=\"out\" type=\"i\"/>\n"
581 " <method name=\"GetAttributeValue\">\n"
582 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
583 " <arg direction=\"in\" type=\"s\" name=\"attributeName\"/>\n"
584 " <arg direction=\"out\" type=\"s\"/>\n"
586 " <method name=\"GetAttributes\">\n"
587 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
588 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
589 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
590 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
591 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
593 " <method name=\"GetDefaultAttributes\">\n"
594 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
595 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
597 " <method name=\"GetCharacterExtents\">\n"
598 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
599 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
600 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
601 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
602 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
603 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
605 " <method name=\"GetOffsetAtPoint\">\n"
606 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
607 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
608 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
609 " <arg direction=\"out\" type=\"i\"/>\n"
611 " <method name=\"GetNSelections\">\n"
612 " <arg direction=\"out\" type=\"i\"/>\n"
614 " <method name=\"GetSelection\">\n"
615 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
616 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
617 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
619 " <method name=\"AddSelection\">\n"
620 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
621 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
622 " <arg direction=\"out\" type=\"b\"/>\n"
624 " <method name=\"RemoveSelection\">\n"
625 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
626 " <arg direction=\"out\" type=\"b\"/>\n"
628 " <method name=\"SetSelection\">\n"
629 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
630 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
631 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
632 " <arg direction=\"out\" type=\"b\"/>\n"
634 " <method name=\"GetRangeExtents\">\n"
635 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
636 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
637 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
638 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
639 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
640 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
641 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
643 " <method name=\"GetBoundedRanges\">\n"
644 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
645 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
646 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
647 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
648 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
649 " <arg direction=\"in\" type=\"u\" name=\"xClipType\"/>\n"
650 " <arg direction=\"in\" type=\"u\" name=\"yClipType\"/>\n"
651 " <arg direction=\"out\" type=\"a(iisv)\"/>\n"
652 " <annotation value=\"QSpiRangeList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
654 " <method name=\"GetAttributeRun\">\n"
655 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
656 " <arg direction=\"in\" type=\"b\" name=\"includeDefaults\"/>\n"
657 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
658 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
659 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
660 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
662 " <method name=\"GetDefaultAttributeSet\">\n"
663 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
664 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
666 " <method name=\"ScrollSubstringTo\">\n"
667 " <arg direction=\"in\" name=\"startOffset\" type=\"i\"/>\n"
668 " <arg direction=\"in\" name=\"endOffset\" type=\"i\"/>\n"
669 " <arg direction=\"in\" name=\"type\" type=\"u\"/>\n"
670 " <arg direction=\"out\" type=\"b\"/>\n"
675 static const QLatin1StringView valueIntrospection(
676 " <interface name=\"org.a11y.atspi.Value\">\n"
677 " <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
678 " <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
679 " <property access=\"read\" type=\"d\" name=\"MinimumIncrement\"/>\n"
680 " <property access=\"readwrite\" type=\"d\" name=\"CurrentValue\"/>\n"
681 " <method name=\"SetCurrentValue\">\n"
682 " <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
687 QAccessibleInterface * interface = interfaceFromPath(path);
689 qCWarning(lcAccessibilityAtspi) <<
"Could not find accessible on path:" << path;
693 QStringList interfaces = accessibleInterfaces(interface);
696 xml.append(accessibleIntrospection);
697 xml.append(collectionIntrospection);
699 if (interfaces.contains(ATSPI_DBUS_INTERFACE_COMPONENT
""_L1))
700 xml.append(componentIntrospection);
701 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TEXT
""_L1))
702 xml.append(textIntrospection);
703 if (interfaces.contains(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT
""_L1))
704 xml.append(editableTextIntrospection);
705 if (interfaces.contains(ATSPI_DBUS_INTERFACE_ACTION
""_L1))
706 xml.append(actionIntrospection);
707 if (interfaces.contains(ATSPI_DBUS_INTERFACE_SELECTION
""_L1))
708 xml.append(selectionIntrospection);
709 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE
""_L1))
710 xml.append(tableIntrospection);
711 if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE_CELL
""_L1))
712 xml.append(tableCellIntrospection);
713 if (interfaces.contains(ATSPI_DBUS_INTERFACE_VALUE
""_L1))
714 xml.append(valueIntrospection);
715 if (path == ATSPI_DBUS_PATH_ROOT
""_L1)
716 xml.append(applicationIntrospection);
721void AtSpiAdaptor::setBitFlag(
const QString &flag)
723 Q_ASSERT(flag.size());
726 switch (flag.at(0).toLower().toLatin1()) {
728 if (flag.size() <= 8) {
731 QString right = flag.mid(7);
733 }
else if (right.startsWith(
"ActiveDescendantChanged"_L1)) {
734 sendObject_active_descendant_changed = 1;
735 }
else if (right.startsWith(
"Announcement"_L1)) {
736 sendObject_announcement = 1;
737 }
else if (right.startsWith(
"AttributesChanged"_L1)) {
738 sendObject_attributes_changed = 1;
739 }
else if (right.startsWith(
"BoundsChanged"_L1)) {
740 sendObject_bounds_changed = 1;
741 }
else if (right.startsWith(
"ChildrenChanged"_L1)) {
742 sendObject_children_changed = 1;
743 }
else if (right.startsWith(
"ColumnDeleted"_L1)) {
744 sendObject_column_deleted = 1;
745 }
else if (right.startsWith(
"ColumnInserted"_L1)) {
746 sendObject_column_inserted = 1;
747 }
else if (right.startsWith(
"ColumnReordered"_L1)) {
748 sendObject_column_reordered = 1;
749 }
else if (right.startsWith(
"LinkSelected"_L1)) {
750 sendObject_link_selected = 1;
751 }
else if (right.startsWith(
"ModelChanged"_L1)) {
752 sendObject_model_changed = 1;
753 }
else if (right.startsWith(
"PropertyChange"_L1)) {
754 if (right ==
"PropertyChange:AccessibleDescription"_L1) {
755 sendObject_property_change_accessible_description = 1;
756 }
else if (right ==
"PropertyChange:AccessibleName"_L1) {
757 sendObject_property_change_accessible_name = 1;
758 }
else if (right ==
"PropertyChange:AccessibleParent"_L1) {
759 sendObject_property_change_accessible_parent = 1;
760 }
else if (right ==
"PropertyChange:AccessibleRole"_L1) {
761 sendObject_property_change_accessible_role = 1;
762 }
else if (right ==
"PropertyChange:TableCaption"_L1) {
763 sendObject_property_change_accessible_table_caption = 1;
764 }
else if (right ==
"PropertyChange:TableColumnDescription"_L1) {
765 sendObject_property_change_accessible_table_column_description = 1;
766 }
else if (right ==
"PropertyChange:TableColumnHeader"_L1) {
767 sendObject_property_change_accessible_table_column_header = 1;
768 }
else if (right ==
"PropertyChange:TableRowDescription"_L1) {
769 sendObject_property_change_accessible_table_row_description = 1;
770 }
else if (right ==
"PropertyChange:TableRowHeader"_L1) {
771 sendObject_property_change_accessible_table_row_header = 1;
772 }
else if (right ==
"PropertyChange:TableSummary"_L1) {
773 sendObject_property_change_accessible_table_summary = 1;
774 }
else if (right ==
"PropertyChange:AccessibleValue"_L1) {
775 sendObject_property_change_accessible_value = 1;
777 sendObject_property_change = 1;
779 }
else if (right.startsWith(
"RowDeleted"_L1)) {
780 sendObject_row_deleted = 1;
781 }
else if (right.startsWith(
"RowInserted"_L1)) {
782 sendObject_row_inserted = 1;
783 }
else if (right.startsWith(
"RowReordered"_L1)) {
784 sendObject_row_reordered = 1;
785 }
else if (right.startsWith(
"SelectionChanged"_L1)) {
786 sendObject_selection_changed = 1;
787 }
else if (right.startsWith(
"StateChanged"_L1)) {
788 sendObject_state_changed = 1;
789 }
else if (right.startsWith(
"TextAttributesChanged"_L1)) {
790 sendObject_text_attributes_changed = 1;
791 }
else if (right.startsWith(
"TextBoundsChanged"_L1)) {
792 sendObject_text_bounds_changed = 1;
793 }
else if (right.startsWith(
"TextCaretMoved"_L1)) {
794 sendObject_text_caret_moved = 1;
795 }
else if (right.startsWith(
"TextChanged"_L1)) {
796 sendObject_text_changed = 1;
797 }
else if (right.startsWith(
"TextSelectionChanged"_L1)) {
798 sendObject_text_selection_changed = 1;
799 }
else if (right.startsWith(
"ValueChanged"_L1)) {
800 sendObject_value_changed = 1;
801 }
else if (right.startsWith(
"VisibleDataChanged"_L1)
802 || right.startsWith(
"VisibledataChanged"_L1)) {
803 sendObject_visible_data_changed = 1;
805 qCWarning(lcAccessibilityAtspi) <<
"Subscription string not handled:" << flag;
811 if (flag.size() <= 8) {
814 QString right = flag.mid(7);
816 }
else if (right.startsWith(
"Activate"_L1)) {
817 sendWindow_activate = 1;
818 }
else if (right.startsWith(
"Close"_L1)) {
820 }
else if (right.startsWith(
"Create"_L1)) {
821 sendWindow_create = 1;
822 }
else if (right.startsWith(
"Deactivate"_L1)) {
823 sendWindow_deactivate = 1;
824 }
else if (right.startsWith(
"Lower"_L1)) {
825 sendWindow_lower = 1;
826 }
else if (right.startsWith(
"Maximize"_L1)) {
827 sendWindow_maximize = 1;
828 }
else if (right.startsWith(
"Minimize"_L1)) {
829 sendWindow_minimize = 1;
830 }
else if (right.startsWith(
"Move"_L1)) {
832 }
else if (right.startsWith(
"Raise"_L1)) {
833 sendWindow_raise = 1;
834 }
else if (right.startsWith(
"Reparent"_L1)) {
835 sendWindow_reparent = 1;
836 }
else if (right.startsWith(
"Resize"_L1)) {
837 sendWindow_resize = 1;
838 }
else if (right.startsWith(
"Restore"_L1)) {
839 sendWindow_restore = 1;
840 }
else if (right.startsWith(
"Restyle"_L1)) {
841 sendWindow_restyle = 1;
842 }
else if (right.startsWith(
"Shade"_L1)) {
843 sendWindow_shade = 1;
844 }
else if (right.startsWith(
"Unshade"_L1)) {
845 sendWindow_unshade = 1;
846 }
else if (right.startsWith(
"DesktopCreate"_L1)) {
848 }
else if (right.startsWith(
"DesktopDestroy"_L1)) {
851 qCWarning(lcAccessibilityAtspi) <<
"Subscription string not handled:" << flag;
870 qCWarning(lcAccessibilityAtspi) <<
"Subscription string not handled:" << flag;
875
876
877void AtSpiAdaptor::updateEventListeners()
879 QDBusMessage m = QDBusMessage::createMethodCall(
"org.a11y.atspi.Registry"_L1,
880 "/org/a11y/atspi/registry"_L1,
881 "org.a11y.atspi.Registry"_L1,
"GetRegisteredEvents"_L1);
882 QDBusReply<QSpiEventListenerArray> listenersReply = m_dbus->connection().call(m);
883 if (listenersReply.isValid()) {
884 const QSpiEventListenerArray evList = listenersReply.value();
885 for (
const QSpiEventListener &ev : evList)
886 setBitFlag(ev.eventName);
887 m_applicationAdaptor->sendEvents(!evList.isEmpty());
889 qCDebug(lcAccessibilityAtspi) <<
"Could not query active accessibility event listeners.";
893void AtSpiAdaptor::eventListenerDeregistered(
const QString &,
const QString &)
896 updateEventListeners();
899void AtSpiAdaptor::eventListenerRegistered(
const QString &,
const QString &)
902 updateEventListeners();
906
907
908
909void AtSpiAdaptor::windowActivated(QObject* window,
bool active)
911 if (!(sendWindow || sendWindow_activate))
914 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
916 if (iface ==
nullptr)
918 Q_ASSERT(!active || iface->isValid());
922 if (iface->isValid())
923 windowTitle = iface->text(QAccessible::Name);
926 data.setVariant(windowTitle);
928 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
930 QString status = active ?
"Activate"_L1 :
"Deactivate"_L1;
931 QString path = pathForObject(window);
932 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_WINDOW
""_L1, status, args);
934 QVariantList stateArgs = packDBusSignalArguments(
"active"_L1, active ? 1 : 0, 0, variantForPath(path));
935 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"StateChanged"_L1, stateArgs);
938QVariantList AtSpiAdaptor::packDBusSignalArguments(
const QString &type,
int data1,
int data2,
const QVariant &variantData)
940 QVariantList arguments;
941 arguments << type << data1 << data2 << variantData << QMap<QString, QVariant>();
945QVariant AtSpiAdaptor::variantForPath(
const QString &path)
const
948 data.setVariant(QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(path))));
949 return QVariant::fromValue(data);
952bool AtSpiAdaptor::sendDBusSignal(
const QString &path,
const QString &interface,
const QString &signalName,
const QVariantList &arguments)
const
954 QDBusMessage message = QDBusMessage::createSignal(path, interface, signalName);
955 message.setArguments(arguments);
956 return m_dbus->connection().send(message);
959QAccessibleInterface *AtSpiAdaptor::interfaceFromPath(
const QString &dbusPath)
961 if (dbusPath == ATSPI_DBUS_PATH_ROOT
""_L1)
962 return QAccessible::queryAccessibleInterface(qApp);
964 QStringList parts = dbusPath.split(u'/');
965 if (parts.size() != 6) {
966 qCDebug(lcAccessibilityAtspi) <<
"invalid path: " << dbusPath;
970 QString objectString = parts.at(5);
971 QAccessible::Id id = objectString.toUInt();
975 qCWarning(lcAccessibilityAtspi) <<
"No accessible object found for id: " << id;
977 return QAccessible::accessibleInterface(id);
980void AtSpiAdaptor::notifyStateChange(QAccessibleInterface *interface,
const QString &state,
int value)
982 QString path = pathForInterface(interface);
983 QVariantList stateArgs = packDBusSignalArguments(state, value, 0, variantForPath(path));
984 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"StateChanged"_L1, stateArgs);
987void AtSpiAdaptor::sendAnnouncement(QAccessibleAnnouncementEvent *event)
989 QAccessibleInterface *iface = event->accessibleInterface();
991 qCWarning(lcAccessibilityAtspi,
"Announcement event has no accessible set.");
994 if (!iface->isValid()) {
995 qCWarning(lcAccessibilityAtspi) <<
"Announcement event with invalid accessible: " << iface;
999 const QString path = pathForInterface(iface);
1000 const QString message = event->message();
1001 const QAccessible::AnnouncementPoliteness prio = event->politeness();
1002 const int politeness = (prio == QAccessible::AnnouncementPoliteness::Assertive) ? ATSPI_LIVE_ASSERTIVE : ATSPI_LIVE_POLITE;
1004 const QVariantList args = packDBusSignalArguments(QString(), politeness, 0, QVariant::fromValue(QDBusVariant(message)));
1005 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"Announcement"_L1, args);
1009
1010
1011void AtSpiAdaptor::notify(QAccessibleEvent *event)
1013 switch (event->type()) {
1014 case QAccessible::ObjectCreated:
1015 if (sendObject || sendObject_children_changed)
1016 notifyAboutCreation(event->accessibleInterface());
1018 case QAccessible::ObjectShow: {
1019 if (sendObject || sendObject_state_changed) {
1020 notifyStateChange(event->accessibleInterface(),
"showing"_L1, 1);
1024 case QAccessible::ObjectHide: {
1025 if (sendObject || sendObject_state_changed) {
1026 notifyStateChange(event->accessibleInterface(),
"showing"_L1, 0);
1030 case QAccessible::ObjectDestroyed: {
1031 if (sendObject || sendObject_state_changed)
1032 notifyAboutDestruction(event->accessibleInterface());
1035 case QAccessible::ObjectReorder: {
1036 if (sendObject || sendObject_children_changed)
1037 childrenChanged(event->accessibleInterface());
1040 case QAccessible::NameChanged: {
1041 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
1042 QAccessibleInterface *iface = event->accessibleInterface();
1044 qCDebug(lcAccessibilityAtspi,
1045 "NameChanged event from invalid accessible.");
1049 QString path = pathForInterface(iface);
1050 QVariantList args = packDBusSignalArguments(
1051 "accessible-name"_L1, 0, 0,
1052 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
1053 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1054 "PropertyChange"_L1, args);
1058 case QAccessible::RoleChanged: {
1059 if (sendObject || sendObject_property_change
1060 || sendObject_property_change_accessible_role) {
1061 QAccessibleInterface *iface = event->accessibleInterface();
1062 if (!iface || !iface->isValid()) {
1063 qCDebug(lcAccessibilityAtspi,
"RoleChanged event from invalid accessible.");
1067 QString path = pathForInterface(iface);
1068 QVariantList args = packDBusSignalArguments(
1069 "accessible-role"_L1, 0, 0,
1070 QVariant::fromValue(QDBusVariant(uint(getRole(iface)))));
1071 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"PropertyChange"_L1,
1076 case QAccessible::DescriptionChanged: {
1077 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
1078 QAccessibleInterface *iface = event->accessibleInterface();
1080 qCDebug(lcAccessibilityAtspi,
1081 "DescriptionChanged event from invalid accessible.");
1085 QString path = pathForInterface(iface);
1086 QVariantList args = packDBusSignalArguments(
1087 "accessible-description"_L1, 0, 0,
1088 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Description))));
1089 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1090 "PropertyChange"_L1, args);
1094 case QAccessible::Focus: {
1095 if (sendFocus || sendObject || sendObject_state_changed)
1096 sendFocusChanged(event->accessibleInterface());
1100 case QAccessible::Announcement: {
1101 if (sendObject || sendObject_announcement) {
1102 QAccessibleAnnouncementEvent *announcementEvent =
static_cast<QAccessibleAnnouncementEvent*>(event);
1103 sendAnnouncement(announcementEvent);
1107 case QAccessible::TextInserted:
1108 case QAccessible::TextRemoved:
1109 case QAccessible::TextUpdated: {
1110 if (sendObject || sendObject_text_changed) {
1111 QAccessibleInterface * iface = event->accessibleInterface();
1112 if (!iface || !iface->textInterface()) {
1113 qCWarning(lcAccessibilityAtspi) <<
"Received text event for invalid interface.";
1116 QString path = pathForInterface(iface);
1118 int changePosition = 0;
1119 int cursorPosition = 0;
1120 QString textRemoved;
1121 QString textInserted;
1123 if (event->type() == QAccessible::TextInserted) {
1124 QAccessibleTextInsertEvent *textEvent =
static_cast<QAccessibleTextInsertEvent*>(event);
1125 textInserted = textEvent->textInserted();
1126 changePosition = textEvent->changePosition();
1127 cursorPosition = textEvent->cursorPosition();
1128 }
else if (event->type() == QAccessible::TextRemoved) {
1129 QAccessibleTextRemoveEvent *textEvent =
static_cast<QAccessibleTextRemoveEvent*>(event);
1130 textRemoved = textEvent->textRemoved();
1131 changePosition = textEvent->changePosition();
1132 cursorPosition = textEvent->cursorPosition();
1133 }
else if (event->type() == QAccessible::TextUpdated) {
1134 QAccessibleTextUpdateEvent *textEvent =
static_cast<QAccessibleTextUpdateEvent*>(event);
1135 textInserted = textEvent->textInserted();
1136 textRemoved = textEvent->textRemoved();
1137 changePosition = textEvent->changePosition();
1138 cursorPosition = textEvent->cursorPosition();
1143 if (!textRemoved.isEmpty()) {
1144 data.setVariant(QVariant::fromValue(textRemoved));
1145 QVariantList args = packDBusSignalArguments(
"delete"_L1, changePosition, textRemoved.size(), QVariant::fromValue(data));
1146 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1147 "TextChanged"_L1, args);
1150 if (!textInserted.isEmpty()) {
1151 data.setVariant(QVariant::fromValue(textInserted));
1152 QVariantList args = packDBusSignalArguments(
"insert"_L1, changePosition, textInserted.size(), QVariant::fromValue(data));
1153 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1154 "TextChanged"_L1, args);
1158 Q_UNUSED(cursorPosition);
1167 case QAccessible::TextCaretMoved: {
1168 if (sendObject || sendObject_text_caret_moved) {
1169 QAccessibleInterface * iface = event->accessibleInterface();
1170 if (!iface || !iface->textInterface()) {
1171 qCWarning(lcAccessibilityAtspi) <<
"Sending TextCaretMoved from object that does not implement text interface: " << iface;
1175 QString path = pathForInterface(iface);
1176 QDBusVariant cursorData;
1177 int pos = iface->textInterface()->cursorPosition();
1178 cursorData.setVariant(QVariant::fromValue(pos));
1179 QVariantList args = packDBusSignalArguments(QString(), pos, 0, QVariant::fromValue(cursorData));
1180 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1181 "TextCaretMoved"_L1, args);
1185 case QAccessible::TextSelectionChanged: {
1186 if (sendObject || sendObject_text_selection_changed) {
1187 QAccessibleInterface * iface = event->accessibleInterface();
1188 QString path = pathForInterface(iface);
1189 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1190 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1191 "TextSelectionChanged"_L1, args);
1195 case QAccessible::ValueChanged: {
1196 if (sendObject || sendObject_value_changed || sendObject_property_change_accessible_value) {
1197 QAccessibleInterface * iface = event->accessibleInterface();
1199 qCWarning(lcAccessibilityAtspi) <<
"ValueChanged event from invalid accessible.";
1202 if (iface->valueInterface()) {
1203 QString path = pathForInterface(iface);
1204 QVariantList args = packDBusSignalArguments(
"accessible-value"_L1, 0, 0, variantForPath(path));
1205 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1206 "PropertyChange"_L1, args);
1207 }
else if (iface->role() == QAccessible::ComboBox) {
1210 QString path = pathForInterface(iface);
1211 QVariantList args1 = packDBusSignalArguments(
1212 "accessible-name"_L1, 0, 0,
1213 QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
1214 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1215 "PropertyChange"_L1, args1);
1216 QVariantList args2 = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(0))));
1217 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1218 "SelectionChanged"_L1, args2);
1220 qCWarning(lcAccessibilityAtspi) <<
"ValueChanged event and no ValueInterface or ComboBox: " << iface;
1225 case QAccessible::SelectionAdd:
1226 case QAccessible::SelectionRemove:
1227 case QAccessible::Selection: {
1228 QAccessibleInterface * iface = event->accessibleInterface();
1230 qCWarning(lcAccessibilityAtspi) <<
"Selection event from invalid accessible.";
1234 QString path = pathForInterface(iface);
1235 int selected = iface->state().selected ? 1 : 0;
1236 QVariantList stateArgs = packDBusSignalArguments(
"selected"_L1, selected, 0, variantForPath(path));
1237 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"StateChanged"_L1, stateArgs);
1240 QAccessibleInterface* parent = iface->parent();
1242 qCDebug(lcAccessibilityAtspi) <<
"No valid parent in selection event.";
1246 QString parentPath = pathForInterface(parent);
1247 QVariantList args = packDBusSignalArguments(QString(), 0, 0, variantForPath(parentPath));
1248 sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1249 QLatin1String(
"SelectionChanged"), args);
1252 case QAccessible::SelectionWithin: {
1253 QAccessibleInterface * iface = event->accessibleInterface();
1255 qCWarning(lcAccessibilityAtspi) <<
"SelectionWithin event from invalid accessible.";
1259 QString path = pathForInterface(iface);
1260 QVariantList args = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1261 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String(
"SelectionChanged"), args);
1264 case QAccessible::StateChanged: {
1265 if (sendObject || sendObject_state_changed || sendWindow || sendWindow_activate) {
1266 QAccessible::State stateChange =
static_cast<QAccessibleStateChangeEvent*>(event)->changedStates();
1267 if (stateChange.checked) {
1268 QAccessibleInterface * iface = event->accessibleInterface();
1270 qCWarning(lcAccessibilityAtspi) <<
"StateChanged event from invalid accessible.";
1273 int checked = iface->state().checked;
1274 notifyStateChange(iface,
"checked"_L1, checked);
1275 }
else if (stateChange.active) {
1276 QAccessibleInterface * iface = event->accessibleInterface();
1277 if (!iface || !(iface->role() == QAccessible::Window && (sendWindow || sendWindow_activate)))
1279 int isActive = iface->state().active;
1280 QString windowTitle = iface->text(QAccessible::Name);
1282 data.setVariant(windowTitle);
1283 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
1284 QString status = isActive ?
"Activate"_L1 :
"Deactivate"_L1;
1285 QString path = pathForInterface(iface);
1286 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_WINDOW
""_L1, status, args);
1287 notifyStateChange(iface,
"active"_L1, isActive);
1288 }
else if (stateChange.disabled) {
1289 QAccessibleInterface *iface = event->accessibleInterface();
1290 QAccessible::State state = iface->state();
1291 bool enabled = !state.disabled;
1293 notifyStateChange(iface,
"enabled"_L1, enabled);
1294 notifyStateChange(iface,
"sensitive"_L1, enabled);
1295 }
else if (stateChange.focused) {
1296 QAccessibleInterface *iface = event->accessibleInterface();
1297 QAccessible::State state = iface->state();
1298 bool focused = state.focused;
1299 notifyStateChange(iface,
"focused"_L1, focused);
1304 case QAccessible::TableModelChanged: {
1305 QAccessibleInterface *interface = event->accessibleInterface();
1306 if (!interface || !interface->isValid()) {
1307 qCWarning(lcAccessibilityAtspi) <<
"TableModelChanged event from invalid accessible.";
1311 const QString path = pathForInterface(interface);
1312 QAccessibleTableModelChangeEvent *tableModelEvent =
static_cast<QAccessibleTableModelChangeEvent*>(event);
1313 switch (tableModelEvent->modelChangeType()) {
1314 case QAccessibleTableModelChangeEvent::ColumnsInserted: {
1315 if (sendObject || sendObject_column_inserted) {
1316 const int firstColumn = tableModelEvent->firstColumn();
1317 const int insertedColumnCount = tableModelEvent->lastColumn() - firstColumn + 1;
1318 QVariantList args = packDBusSignalArguments(QString(), firstColumn, insertedColumnCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1319 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ColumnInserted"_L1, args);
1323 case QAccessibleTableModelChangeEvent::ColumnsRemoved: {
1324 if (sendObject || sendObject_column_deleted) {
1325 const int firstColumn = tableModelEvent->firstColumn();
1326 const int removedColumnCount = tableModelEvent->lastColumn() - firstColumn + 1;
1327 QVariantList args = packDBusSignalArguments(QString(), firstColumn, removedColumnCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1328 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ColumnDeleted"_L1, args);
1332 case QAccessibleTableModelChangeEvent::RowsInserted: {
1333 if (sendObject || sendObject_row_inserted) {
1334 const int firstRow = tableModelEvent->firstRow();
1335 const int insertedRowCount = tableModelEvent->lastRow() - firstRow + 1;
1336 QVariantList args = packDBusSignalArguments(QString(), firstRow, insertedRowCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1337 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"RowInserted"_L1, args);
1341 case QAccessibleTableModelChangeEvent::RowsRemoved: {
1342 if (sendObject || sendObject_row_deleted) {
1343 const int firstRow = tableModelEvent->firstRow();
1344 const int removedRowCount = tableModelEvent->lastRow() - firstRow + 1;
1345 QVariantList args = packDBusSignalArguments(QString(), firstRow, removedRowCount, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1346 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"RowDeleted"_L1, args);
1350 case QAccessibleTableModelChangeEvent::ModelChangeType::ModelReset: {
1351 if (sendObject || sendObject_model_changed) {
1352 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1353 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ModelChanged"_L1, args);
1357 case QAccessibleTableModelChangeEvent::DataChanged: {
1358 if (sendObject || sendObject_visible_data_changed) {
1359 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1360 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"VisibleDataChanged"_L1, args);
1369 case QAccessible::ParentChanged:
1370 case QAccessible::DialogStart:
1371 case QAccessible::DialogEnd:
1372 case QAccessible::PopupMenuStart:
1373 case QAccessible::PopupMenuEnd:
1374 case QAccessible::SoundPlayed:
1375 case QAccessible::Alert:
1376 case QAccessible::ForegroundChanged:
1377 case QAccessible::MenuStart:
1378 case QAccessible::MenuEnd:
1379 case QAccessible::ContextHelpStart:
1380 case QAccessible::ContextHelpEnd:
1381 case QAccessible::DragDropStart:
1382 case QAccessible::DragDropEnd:
1383 case QAccessible::ScrollingStart:
1384 case QAccessible::ScrollingEnd:
1385 case QAccessible::MenuCommand:
1386 case QAccessible::ActionChanged:
1387 case QAccessible::ActiveDescendantChanged:
1388 case QAccessible::AttributeChanged:
1389 case QAccessible::DocumentContentChanged:
1390 case QAccessible::DocumentLoadComplete:
1391 case QAccessible::DocumentLoadStopped:
1392 case QAccessible::DocumentReload:
1393 case QAccessible::HyperlinkEndIndexChanged:
1394 case QAccessible::HyperlinkNumberOfAnchorsChanged:
1395 case QAccessible::HyperlinkSelectedLinkChanged:
1396 case QAccessible::HypertextLinkActivated:
1397 case QAccessible::HypertextLinkSelected:
1398 case QAccessible::HyperlinkStartIndexChanged:
1399 case QAccessible::HypertextChanged:
1400 case QAccessible::HypertextNLinksChanged:
1401 case QAccessible::ObjectAttributeChanged:
1402 case QAccessible::PageChanged:
1403 case QAccessible::SectionChanged:
1404 case QAccessible::TableCaptionChanged:
1405 case QAccessible::TableColumnDescriptionChanged:
1406 case QAccessible::TableColumnHeaderChanged:
1407 case QAccessible::TableRowDescriptionChanged:
1408 case QAccessible::TableRowHeaderChanged:
1409 case QAccessible::TableSummaryChanged:
1410 case QAccessible::TextAttributeChanged:
1411 case QAccessible::TextColumnChanged:
1412 case QAccessible::VisibleDataChanged:
1413 case QAccessible::LocationChanged:
1414 case QAccessible::HelpChanged:
1415 case QAccessible::DefaultActionChanged:
1416 case QAccessible::AcceleratorChanged:
1417 case QAccessible::IdentifierChanged:
1418 case QAccessible::InvalidEvent:
1423void AtSpiAdaptor::sendFocusChanged(QAccessibleInterface *interface)
const
1425 static QString lastFocusPath;
1427 if (!lastFocusPath.isEmpty()) {
1428 QVariantList stateArgs = packDBusSignalArguments(
"focused"_L1, 0, 0, variantForPath(lastFocusPath));
1429 sendDBusSignal(lastFocusPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1430 "StateChanged"_L1, stateArgs);
1434 QString path = pathForInterface(interface);
1436 QVariantList stateArgs = packDBusSignalArguments(
"focused"_L1, 1, 0, variantForPath(path));
1437 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
1438 "StateChanged"_L1, stateArgs);
1440 QVariantList focusArgs = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1441 sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_FOCUS
""_L1,
"Focus"_L1, focusArgs);
1442 lastFocusPath = path;
1446void AtSpiAdaptor::childrenChanged(QAccessibleInterface *interface)
const
1448 QString parentPath = pathForInterface(interface);
1449 const int childCount = interface->childCount();
1450 for (
int i = 0; i < childCount; ++i) {
1451 QString childPath = pathForInterface(interface->child(i));
1452 QVariantList args = packDBusSignalArguments(
"add"_L1, i, 0, childPath);
1453 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ChildrenChanged"_L1, args);
1457void AtSpiAdaptor::notifyAboutCreation(QAccessibleInterface *interface)
const
1460 QAccessibleInterface * parent = interface->parent();
1462 qCDebug(lcAccessibilityAtspi) <<
"AtSpiAdaptor::notifyAboutCreation: Could not find parent for " << interface->object();
1465 QString path = pathForInterface(interface);
1466 const int childIndex = parent->indexOfChild(interface);
1467 QString parentPath = pathForInterface(parent);
1468 QVariantList args = packDBusSignalArguments(
"add"_L1, childIndex, 0, variantForPath(path));
1469 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ChildrenChanged"_L1, args);
1472void AtSpiAdaptor::notifyAboutDestruction(QAccessibleInterface *interface)
const
1474 if (!interface || !interface->isValid())
1477 QAccessibleInterface * parent = interface->parent();
1479 qCDebug(lcAccessibilityAtspi) <<
"AtSpiAdaptor::notifyAboutDestruction: Could not find parent for " << interface->object();
1482 QString path = pathForInterface(interface);
1486 int childIndex = -1;
1493 QString parentPath = pathForInterface(parent);
1494 QVariantList args = packDBusSignalArguments(
"remove"_L1, childIndex, 0, variantForPath(path));
1495 sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT
""_L1,
"ChildrenChanged"_L1, args);
1499
1500
1501
1502bool AtSpiAdaptor::handleMessage(
const QDBusMessage &message,
const QDBusConnection &connection)
1505 QAccessibleInterface * accessible = interfaceFromPath(message.path());
1507 qCWarning(lcAccessibilityAtspi) <<
"Could not find accessible on path:" << message.path();
1510 if (!accessible->isValid()) {
1511 qCWarning(lcAccessibilityAtspi) <<
"Accessible invalid:" << accessible << message.path();
1515 QString interface = message.interface();
1516 QString function = message.member();
1520 if (function ==
"Introspect"_L1) {
1526 if (interface ==
"org.freedesktop.DBus.Properties"_L1) {
1527 const auto arguments = message.arguments();
1528 if (arguments.size() > 0) {
1529 interface = arguments.at(0).toString();
1530 if (arguments.size() > 1)
1531 function = function + arguments.at(1).toString();
1536 if (interface == ATSPI_DBUS_INTERFACE_ACCESSIBLE
""_L1)
1537 return accessibleInterface(accessible, function, message, connection);
1538 if (interface == ATSPI_DBUS_INTERFACE_APPLICATION
""_L1)
1539 return applicationInterface(accessible, function, message, connection);
1540 if (interface == ATSPI_DBUS_INTERFACE_COLLECTION
""_L1)
1541 return collectionInterface(accessible, function, message, connection);
1542 if (interface == ATSPI_DBUS_INTERFACE_COMPONENT
""_L1)
1543 return componentInterface(accessible, function, message, connection);
1544 if (interface == ATSPI_DBUS_INTERFACE_ACTION
""_L1)
1545 return actionInterface(accessible, function, message, connection);
1546 if (interface == ATSPI_DBUS_INTERFACE_SELECTION
""_L1)
1547 return selectionInterface(accessible, function, message, connection);
1548 if (interface == ATSPI_DBUS_INTERFACE_TEXT
""_L1)
1549 return textInterface(accessible, function, message, connection);
1550 if (interface == ATSPI_DBUS_INTERFACE_EDITABLE_TEXT
""_L1)
1551 return editableTextInterface(accessible, function, message, connection);
1552 if (interface == ATSPI_DBUS_INTERFACE_VALUE
""_L1)
1553 return valueInterface(accessible, function, message, connection);
1554 if (interface == ATSPI_DBUS_INTERFACE_TABLE
""_L1)
1555 return tableInterface(accessible, function, message, connection);
1556 if (interface == ATSPI_DBUS_INTERFACE_TABLE_CELL
""_L1)
1557 return tableCellInterface(accessible, function, message, connection);
1559 qCDebug(lcAccessibilityAtspi) <<
"AtSpiAdaptor::handleMessage with unknown interface: " << message.path() << interface << function;
1564bool AtSpiAdaptor::applicationInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
1566 if (message.path() != ATSPI_DBUS_PATH_ROOT
""_L1) {
1567 qCWarning(lcAccessibilityAtspi) <<
"Could not find application interface for:" << message.path() << interface;
1571 if (function ==
"SetId"_L1) {
1572 Q_ASSERT(message.signature() ==
"ssv"_L1);
1573 QVariant value = qvariant_cast<QDBusVariant>(message.arguments().at(2)).variant();
1575 m_applicationId = value.toInt();
1578 if (function ==
"GetId"_L1) {
1579 Q_ASSERT(message.signature() ==
"ss"_L1);
1580 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(m_applicationId)));
1581 return connection.send(reply);
1583 if (function ==
"GetAtspiVersion"_L1) {
1584 Q_ASSERT(message.signature() ==
"ss"_L1);
1586 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(
"2.1"_L1)));
1587 return connection.send(reply);
1589 if (function ==
"GetToolkitName"_L1) {
1590 Q_ASSERT(message.signature() ==
"ss"_L1);
1591 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(
"Qt"_L1)));
1592 return connection.send(reply);
1594 if (function ==
"GetVersion"_L1) {
1595 Q_ASSERT(message.signature() ==
"ss"_L1);
1596 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QLatin1StringView(qVersion()))));
1597 return connection.send(reply);
1599 if (function ==
"GetLocale"_L1) {
1600 Q_ASSERT(message.signature() ==
"u"_L1);
1601 QDBusMessage reply = message.createReply(QVariant::fromValue(QLocale().name()));
1602 return connection.send(reply);
1604 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::applicationInterface does not implement"
1605 << function << message.path();
1610
1611
1612void AtSpiAdaptor::registerApplication()
1614 OrgA11yAtspiSocketInterface registry(ATSPI_DBUS_NAME_REGISTRY
""_L1, ATSPI_DBUS_PATH_ROOT
""_L1,
1615 m_dbus->connection());
1617 QDBusPendingReply<QSpiObjectReference> reply;
1618 QSpiObjectReference ref = QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(ATSPI_DBUS_PATH_ROOT));
1619 reply = registry.Embed(ref);
1620 reply.waitForFinished();
1621 if (reply.isValid ()) {
1622 const QSpiObjectReference &socket = reply.value();
1623 m_accessibilityRegistry = QSpiObjectReference(socket);
1625 qCWarning(lcAccessibilityAtspi) <<
"Error in contacting registry:"
1626 << reply.error().name()
1627 << reply.error().message();
1632bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
1634 if (function ==
"GetRole"_L1) {
1635 sendReply(connection, message, (uint) getRole(interface));
1636 }
else if (function ==
"GetName"_L1) {
1637 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Name))));
1638 }
else if (function ==
"GetRoleName"_L1) {
1639 sendReply(connection, message, QSpiAccessibleBridge::namesForRole(interface->role()).name());
1640 }
else if (function ==
"GetLocalizedRoleName"_L1) {
1641 sendReply(connection, message, QVariant::fromValue(QSpiAccessibleBridge::namesForRole(interface->role()).localizedName()));
1642 }
else if (function ==
"GetChildCount"_L1) {
1643 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->childCount())));
1644 }
else if (function ==
"GetIndexInParent"_L1) {
1645 int childIndex = -1;
1646 QAccessibleInterface * parent = interface->parent();
1648 childIndex = parent->indexOfChild(interface);
1649 if (childIndex < 0) {
1650 qCDebug(lcAccessibilityAtspi) <<
"GetIndexInParent get invalid index: " << childIndex << interface;
1653 sendReply(connection, message, childIndex);
1654 }
else if (function ==
"GetParent"_L1) {
1656 QAccessibleInterface * parent = interface->parent();
1658 if (interface->object() == qApp) {
1659 sendReply(connection, message,
1660 QVariant::fromValue(QDBusVariant(QVariant::fromValue(m_accessibilityRegistry))));
1664 path = ATSPI_DBUS_PATH_NULL
""_L1;
1665 }
else if (parent->role() == QAccessible::Application) {
1666 path = ATSPI_DBUS_PATH_ROOT
""_L1;
1668 path = pathForInterface(parent);
1671 sendReply(connection, message, QVariant::fromValue(
1672 QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path))))));
1673 }
else if (function ==
"GetChildAtIndex"_L1) {
1674 const int index = message.arguments().at(0).toInt();
1676 sendReply(connection, message, QVariant::fromValue(
1677 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1679 QAccessibleInterface * childInterface = interface->child(index);
1680 sendReply(connection, message, QVariant::fromValue(
1681 QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(childInterface)))));
1683 }
else if (function ==
"GetInterfaces"_L1) {
1684 sendReply(connection, message, accessibleInterfaces(interface));
1685 }
else if (function ==
"GetDescription"_L1) {
1686 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Description))));
1687 }
else if (function ==
"GetHelpText"_L1) {
1688 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Help))));
1689 }
else if (function ==
"GetState"_L1) {
1690 quint64 spiState = spiStatesFromQState(interface->state());
1691 if (interface->tableInterface()) {
1695 setSpiStateBit(&spiState, ATSPI_STATE_MANAGES_DESCENDANTS);
1697 QAccessible::Role role = interface->role();
1698 if (role == QAccessible::TreeItem ||
1699 role == QAccessible::ListItem) {
1701
1702
1703
1704 setSpiStateBit(&spiState, ATSPI_STATE_TRANSIENT);
1706 sendReply(connection, message,
1707 QVariant::fromValue(spiStateSetFromSpiStates(spiState)));
1708 }
else if (function ==
"GetAttributes"_L1) {
1709 sendReply(connection, message, QVariant::fromValue(getAttributes(interface)));
1710 }
else if (function ==
"GetRelationSet"_L1) {
1711 sendReply(connection, message, QVariant::fromValue(relationSet(interface, connection)));
1712 }
else if (function ==
"GetApplication"_L1) {
1713 sendReply(connection, message, QVariant::fromValue(
1714 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_ROOT))));
1715 }
else if (function ==
"GetLocale"_L1) {
1717 if (QAccessibleAttributesInterface *attributesIface = interface->attributesInterface()) {
1718 const QVariant localeVariant = attributesIface->attributeValue(QAccessible::Attribute::Locale);
1719 if (localeVariant.isValid()) {
1720 Q_ASSERT(localeVariant.canConvert<QLocale>());
1721 locale = localeVariant.toLocale();
1724 sendReply(connection, message, QVariant::fromValue(QDBusVariant(locale.name())));
1725 }
else if (function ==
"GetChildren"_L1) {
1726 QSpiObjectReferenceArray children;
1727 const int numChildren = interface->childCount();
1728 children.reserve(numChildren);
1729 for (
int i = 0; i < numChildren; ++i) {
1730 QString childPath = pathForInterface(interface->child(i));
1731 QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
1734 connection.send(message.createReply(QVariant::fromValue(children)));
1735 }
else if (function ==
"GetAccessibleId"_L1) {
1736 sendReply(connection, message,
1737 QVariant::fromValue(QDBusVariant(QAccessibleBridgeUtils::accessibleId(interface))));
1739 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::accessibleInterface does not implement" << function << message.path();
1745AtspiRole AtSpiAdaptor::getRole(QAccessibleInterface *interface)
1747 if ((interface->role() == QAccessible::EditableText) && interface->state().passwordEdit)
1748 return ATSPI_ROLE_PASSWORD_TEXT;
1749 return QSpiAccessibleBridge::namesForRole(interface->role()).spiRole();
1752QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface)
1755 qCDebug(lcAccessibilityAtspiCreation) <<
"AtSpiAdaptor::accessibleInterfaces create: " << interface->object();
1756 ifaces << u"" ATSPI_DBUS_INTERFACE_ACCESSIBLE
""_s;
1758 ifaces << u"" ATSPI_DBUS_INTERFACE_COLLECTION
""_s;
1760 if ( (!interface->rect().isEmpty()) ||
1761 (interface->object() && interface->object()->isWidgetType()) ||
1762 (interface->role() == QAccessible::ListItem) ||
1763 (interface->role() == QAccessible::Cell) ||
1764 (interface->role() == QAccessible::TreeItem) ||
1765 (interface->role() == QAccessible::Row) ||
1766 (interface->object() && interface->object()->inherits(
"QSGItem"))
1768 ifaces << u"" ATSPI_DBUS_INTERFACE_COMPONENT
""_s;
1770 qCDebug(lcAccessibilityAtspiCreation) <<
" IS NOT a component";
1772 if (interface->role() == QAccessible::Application)
1773 ifaces << u"" ATSPI_DBUS_INTERFACE_APPLICATION
""_s;
1775 if (interface->actionInterface() || interface->valueInterface())
1776 ifaces << u"" ATSPI_DBUS_INTERFACE_ACTION
""_s;
1778 if (interface->selectionInterface())
1779 ifaces << ATSPI_DBUS_INTERFACE_SELECTION
""_L1;
1781 if (interface->textInterface())
1782 ifaces << u"" ATSPI_DBUS_INTERFACE_TEXT
""_s;
1784 if (interface->editableTextInterface())
1785 ifaces << u"" ATSPI_DBUS_INTERFACE_EDITABLE_TEXT
""_s;
1787 if (interface->valueInterface())
1788 ifaces << u"" ATSPI_DBUS_INTERFACE_VALUE
""_s;
1790 if (interface->tableInterface())
1791 ifaces << u"" ATSPI_DBUS_INTERFACE_TABLE
""_s;
1793 if (interface->tableCellInterface())
1794 ifaces << u"" ATSPI_DBUS_INTERFACE_TABLE_CELL
""_s;
1799QSpiRelationArray AtSpiAdaptor::relationSet(QAccessibleInterface *interface,
1800 const QDBusConnection &connection)
1802 typedef std::pair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
1803 const QList<RelationPair> relationInterfaces = interface->relations();
1805 QSpiRelationArray relations;
1806 for (
const RelationPair &pair : relationInterfaces) {
1809 QSpiObjectReferenceArray related;
1811 QDBusObjectPath path = QDBusObjectPath(pathForInterface(pair.first));
1812 related.append(QSpiObjectReference(connection, path));
1814 if (!related.isEmpty())
1815 relations.append(QSpiRelationArrayEntry(qAccessibleRelationToAtSpiRelation(pair.second), related));
1820void AtSpiAdaptor::sendReply(
const QDBusConnection &connection,
const QDBusMessage &message,
const QVariant &argument)
const
1822 QDBusMessage reply = message.createReply(argument);
1823 connection.send(reply);
1826QString AtSpiAdaptor::pathForObject(QObject *object)
1830 if (inheritsQAction(object)) {
1831 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::pathForObject: Creating path with QAction as object.";
1834 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object);
1835 return pathForInterface(iface);
1838QString AtSpiAdaptor::pathForInterface(QAccessibleInterface *interface)
1840 if (!interface || !interface->isValid())
1841 return u"" ATSPI_DBUS_PATH_NULL
""_s;
1842 if (interface->role() == QAccessible::Application)
1843 return u"" ATSPI_DBUS_PATH_ROOT
""_s;
1845 QAccessible::Id id = QAccessible::uniqueId(interface);
1846 Q_ASSERT((
int)id < 0);
1847 return QSPI_OBJECT_PATH_PREFIX
""_L1 + QString::number(id);
1850bool AtSpiAdaptor::inheritsQAction(QObject *object)
1852 const QMetaObject *mo = object->metaObject();
1854 const QLatin1StringView cn(mo->className());
1855 if (cn ==
"QAction"_L1)
1857 mo = mo->superClass();
1863static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
1867 QAccessibleInterface* app = QAccessible::queryAccessibleInterface(qApp);
1868 while (interface && interface->role() != QAccessible::Dialog
1869 && interface->role() != QAccessible::Window && interface->parent() != app)
1870 interface = interface->parent();
1875void AtSpiAdaptor::addMatchingDescendants(QList<QAccessibleInterface *> &matches,
1876 QAccessibleInterface *accessible,
1877 const QSpiMatchRuleMatcher &matcher,
bool invert,
1878 int count,
bool traverse)
1880 if (!accessible || matches.size() >= count)
1883 const int childCount = accessible->childCount();
1884 for (
int i = 0; i < childCount; ++i) {
1885 if (QAccessibleInterface *child = accessible->child(i)) {
1886 if (matcher.match(*child) != invert)
1887 matches.append(child);
1890 addMatchingDescendants(matches, child, matcher, invert, count, traverse);
1892 if (matches.size() >= count)
1898bool AtSpiAdaptor::collectionInterface(QAccessibleInterface *interface,
const QString &function,
1899 const QDBusMessage &message,
1900 const QDBusConnection &connection)
1902 if (function ==
"GetMatches"_L1) {
1903 if (message.signature() != u"(aiia{ss}iaiiasib)uib") {
1904 qCWarning(lcAccessibilityAtspi)
1905 <<
"AtSpiAdaptor::collectionInterface: Invalid signature for " << function
1906 <<
": " << message.path();
1910 const QSpiMatchRule matchRule = qdbus_cast<QSpiMatchRule>(message.arguments().at(0));
1911 const int count = message.arguments().at(2).toInt();
1912 const bool traverse = message.arguments().at(3).toBool();
1914 QList<QAccessibleInterface *> matchedAccessibles;
1915 addMatchingDescendants(matchedAccessibles, interface, QSpiMatchRuleMatcher(matchRule),
1916 matchRule.invert, count, traverse);
1918 QSpiObjectReferenceArray result;
1919 result.reserve(matchedAccessibles.size());
1920 for (QAccessibleInterface *iface : std::as_const(matchedAccessibles)) {
1921 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(iface)));
1924 connection.send(message.createReply(QVariant::fromValue(result)));
1928 qCWarning(lcAccessibilityAtspi)
1929 <<
"AtSpiAdaptor::collectionInterface does not implement" << function << message.path();
1933bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
1935 if (function ==
"Contains"_L1) {
1937 int x = message.arguments().at(0).toInt();
1938 int y = message.arguments().at(1).toInt();
1939 uint coordType = message.arguments().at(2).toUInt();
1940 if (!isValidCoordType(coordType))
1942 ret = getExtents(interface, coordType).contains(x, y);
1943 sendReply(connection, message, ret);
1944 }
else if (function ==
"GetAccessibleAtPoint"_L1) {
1945 QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
1946 uint coordType = message.arguments().at(2).toUInt();
1947 if (!isValidCoordType(coordType))
1949 QPoint screenPos = translateToScreenCoordinates(interface, point, coordType);
1951 QAccessibleInterface * childInterface(interface->childAt(screenPos.x(), screenPos.y()));
1952 QAccessibleInterface * iface =
nullptr;
1953 while (childInterface) {
1954 iface = childInterface;
1955 childInterface = iface->childAt(screenPos.x(), screenPos.y());
1958 QString path = pathForInterface(iface);
1959 sendReply(connection, message, QVariant::fromValue(
1960 QSpiObjectReference(connection, QDBusObjectPath(path))));
1962 sendReply(connection, message, QVariant::fromValue(
1963 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1965 }
else if (function ==
"GetAlpha"_L1) {
1966 sendReply(connection, message, (
double) 1.0);
1967 }
else if (function ==
"GetExtents"_L1) {
1968 uint coordType = message.arguments().at(0).toUInt();
1969 if (!isValidCoordType(coordType))
1971 sendReply(connection, message, QVariant::fromValue(getExtents(interface, coordType)));
1972 }
else if (function ==
"GetLayer"_L1) {
1973 sendReply(connection, message, QVariant::fromValue((uint)1));
1974 }
else if (function ==
"GetMDIZOrder"_L1) {
1975 sendReply(connection, message, QVariant::fromValue((
short)0));
1976 }
else if (function ==
"GetPosition"_L1) {
1977 uint coordType = message.arguments().at(0).toUInt();
1978 if (!isValidCoordType(coordType))
1980 QRect rect = getExtents(interface, coordType);
1982 pos << rect.x() << rect.y();
1983 connection.send(message.createReply(pos));
1984 }
else if (function ==
"GetSize"_L1) {
1985 QRect rect = interface->rect();
1987 size << rect.width() << rect.height();
1988 connection.send(message.createReply(size));
1989 }
else if (function ==
"GrabFocus"_L1) {
1990 QAccessibleActionInterface *actionIface = interface->actionInterface();
1991 if (actionIface && actionIface->actionNames().contains(QAccessibleActionInterface::setFocusAction())) {
1992 actionIface->doAction(QAccessibleActionInterface::setFocusAction());
1993 sendReply(connection, message,
true);
1995 sendReply(connection, message,
false);
1997 }
else if (function ==
"SetExtents"_L1) {
2003 qCDebug(lcAccessibilityAtspi) <<
"SetExtents is not implemented.";
2004 sendReply(connection, message,
false);
2005 }
else if (function ==
"SetPosition"_L1) {
2009 qCDebug(lcAccessibilityAtspi) <<
"SetPosition is not implemented.";
2010 sendReply(connection, message,
false);
2011 }
else if (function ==
"SetSize"_L1) {
2014 qCDebug(lcAccessibilityAtspi) <<
"SetSize is not implemented.";
2015 sendReply(connection, message,
false);
2017 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::componentInterface does not implement" << function << message.path();
2023QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType)
2025 return translateFromScreenCoordinates(interface, interface->rect(), coordType);
2029bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2031 if (function ==
"GetNActions"_L1) {
2032 int count = QAccessibleBridgeUtils::effectiveActionNames(interface).size();
2033 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(count))));
2034 }
else if (function ==
"DoAction"_L1) {
2035 int index = message.arguments().at(0).toInt();
2036 const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
2037 if (index < 0 || index >= actionNames.size())
2039 const QString actionName = actionNames.at(index);
2040 bool success = QAccessibleBridgeUtils::performEffectiveAction(interface, actionName);
2041 sendReply(connection, message, success);
2042 }
else if (function ==
"GetActions"_L1) {
2043 sendReply(connection, message, QVariant::fromValue(getActions(interface)));
2044 }
else if (function ==
"GetName"_L1) {
2045 int index = message.arguments().at(0).toInt();
2046 const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
2047 if (index < 0 || index >= actionNames.size())
2049 sendReply(connection, message, actionNames.at(index));
2050 }
else if (function ==
"GetDescription"_L1) {
2051 int index = message.arguments().at(0).toInt();
2052 const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
2053 if (index < 0 || index >= actionNames.size())
2055 QString description;
2056 if (QAccessibleActionInterface *actionIface = interface->actionInterface())
2057 description = actionIface->localizedActionDescription(actionNames.at(index));
2059 description = qAccessibleLocalizedActionDescription(actionNames.at(index));
2060 sendReply(connection, message, description);
2061 }
else if (function ==
"GetKeyBinding"_L1) {
2062 int index = message.arguments().at(0).toInt();
2063 const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
2064 if (index < 0 || index >= actionNames.size())
2066 QStringList keyBindings;
2067 if (QAccessibleActionInterface *actionIface = interface->actionInterface())
2068 keyBindings = actionIface->keyBindingsForAction(actionNames.at(index));
2069 if (keyBindings.isEmpty()) {
2070 QString acc = interface->text(QAccessible::Accelerator);
2072 keyBindings.append(acc);
2074 if (keyBindings.size() > 0)
2075 sendReply(connection, message, keyBindings.join(u';'));
2077 sendReply(connection, message, QString());
2079 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::actionInterface does not implement" << function << message.path();
2085QSpiActionArray AtSpiAdaptor::getActions(QAccessibleInterface *interface)
const
2087 QAccessibleActionInterface *actionInterface = interface->actionInterface();
2088 QSpiActionArray actions;
2089 const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
2090 actions.reserve(actionNames.size());
2091 for (
const QString &actionName : actionNames) {
2094 action.name = actionName;
2095 if (actionInterface) {
2096 action.description = actionInterface->localizedActionDescription(actionName);
2097 const QStringList keyBindings = actionInterface->keyBindingsForAction(actionName);
2098 if (!keyBindings.isEmpty())
2099 action.keyBinding = keyBindings.front();
2101 action.description = qAccessibleLocalizedActionDescription(actionName);
2104 actions.append(std::move(action));
2110bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2112 if (!interface->textInterface())
2116 if (function ==
"GetCaretOffset"_L1) {
2117 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->cursorPosition()))));
2118 }
else if (function ==
"GetCharacterCount"_L1) {
2119 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->characterCount()))));
2122 }
else if (function ==
"AddSelection"_L1) {
2123 int startOffset = message.arguments().at(0).toInt();
2124 int endOffset = message.arguments().at(1).toInt();
2125 int lastSelection = interface->textInterface()->selectionCount();
2126 interface->textInterface()->setSelection(lastSelection, startOffset, endOffset);
2127 sendReply(connection, message, (interface->textInterface()->selectionCount() > lastSelection));
2128 }
else if (function ==
"GetAttributeRun"_L1) {
2129 int offset = message.arguments().at(0).toInt();
2130 bool includeDefaults = message.arguments().at(1).toBool();
2131 Q_UNUSED(includeDefaults);
2132 connection.send(message.createReply(getAttributes(interface, offset, includeDefaults)));
2133 }
else if (function ==
"GetAttributeValue"_L1) {
2134 int offset = message.arguments().at(0).toInt();
2135 QString attributeName = message.arguments().at(1).toString();
2136 connection.send(message.createReply(QVariant(getAttributeValue(interface, offset, attributeName))));
2137 }
else if (function ==
"GetAttributes"_L1) {
2138 int offset = message.arguments().at(0).toInt();
2139 connection.send(message.createReply(getAttributes(interface, offset,
true)));
2140 }
else if (function ==
"GetBoundedRanges"_L1) {
2141 int x = message.arguments().at(0).toInt();
2142 int y = message.arguments().at(1).toInt();
2143 int width = message.arguments().at(2).toInt();
2144 int height = message.arguments().at(3).toInt();
2145 uint coordType = message.arguments().at(4).toUInt();
2146 uint xClipType = message.arguments().at(5).toUInt();
2147 uint yClipType = message.arguments().at(6).toUInt();
2152 Q_UNUSED(coordType);
2153 Q_UNUSED(xClipType);
2154 Q_UNUSED(yClipType);
2155 qCDebug(lcAccessibilityAtspi) <<
"Not implemented: QSpiAdaptor::GetBoundedRanges";
2156 sendReply(connection, message, QVariant::fromValue(QSpiTextRangeList()));
2157 }
else if (function ==
"GetCharacterAtOffset"_L1) {
2158 int offset = message.arguments().at(0).toInt();
2161 const QString charString = interface->textInterface()
2162 ->textAtOffset(offset, QAccessible::CharBoundary, &start, &end);
2164 QStringIterator stringIt(charString);
2165 if (stringIt.hasNext())
2166 codePoint =
static_cast<
int>(stringIt.peekNext());
2167 sendReply(connection, message, codePoint);
2168 }
else if (function ==
"GetCharacterExtents"_L1) {
2169 int offset = message.arguments().at(0).toInt();
2170 int coordType = message.arguments().at(1).toUInt();
2171 connection.send(message.createReply(getCharacterExtents(interface, offset, coordType)));
2172 }
else if (function ==
"GetDefaultAttributeSet"_L1 || function ==
"GetDefaultAttributes"_L1) {
2175 sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
2176 }
else if (function ==
"GetNSelections"_L1) {
2177 sendReply(connection, message, interface->textInterface()->selectionCount());
2178 }
else if (function ==
"GetOffsetAtPoint"_L1) {
2179 qCDebug(lcAccessibilityAtspi) << message.signature();
2180 Q_ASSERT(!message.signature().isEmpty());
2181 QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
2182 uint coordType = message.arguments().at(2).toUInt();
2183 if (!isValidCoordType(coordType))
2185 QPoint screenPos = translateToScreenCoordinates(interface, point, coordType);
2186 int offset = interface->textInterface()->offsetAtPoint(screenPos);
2187 sendReply(connection, message, offset);
2188 }
else if (function ==
"GetRangeExtents"_L1) {
2189 int startOffset = message.arguments().at(0).toInt();
2190 int endOffset = message.arguments().at(1).toInt();
2191 uint coordType = message.arguments().at(2).toUInt();
2192 connection.send(message.createReply(getRangeExtents(interface, startOffset, endOffset, coordType)));
2193 }
else if (function ==
"GetSelection"_L1) {
2194 int selectionNum = message.arguments().at(0).toInt();
2196 interface->textInterface()->selection(selectionNum, &start, &end);
2198 start = end = interface->textInterface()->cursorPosition();
2200 sel << start << end;
2201 connection.send(message.createReply(sel));
2202 }
else if (function ==
"GetStringAtOffset"_L1) {
2203 int offset = message.arguments().at(0).toInt();
2204 uint granularity = message.arguments().at(1).toUInt();
2205 if (!isValidAtspiTextGranularity(granularity))
2207 int startOffset, endOffset;
2208 QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiTextGranularity(granularity), &startOffset, &endOffset);
2210 ret << text << startOffset << endOffset;
2211 connection.send(message.createReply(ret));
2212 }
else if (function ==
"GetText"_L1) {
2213 int startOffset = message.arguments().at(0).toInt();
2214 int endOffset = message.arguments().at(1).toInt();
2215 if (endOffset == -1)
2216 endOffset = interface->textInterface()->characterCount();
2217 sendReply(connection, message, interface->textInterface()->text(startOffset, endOffset));
2218 }
else if (function ==
"GetTextAfterOffset"_L1) {
2219 int offset = message.arguments().at(0).toInt();
2220 int type = message.arguments().at(1).toUInt();
2221 int startOffset, endOffset;
2222 QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2224 ret << text << startOffset << endOffset;
2225 connection.send(message.createReply(ret));
2226 }
else if (function ==
"GetTextAtOffset"_L1) {
2227 int offset = message.arguments().at(0).toInt();
2228 int type = message.arguments().at(1).toUInt();
2229 int startOffset, endOffset;
2230 QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2232 ret << text << startOffset << endOffset;
2233 connection.send(message.createReply(ret));
2234 }
else if (function ==
"GetTextBeforeOffset"_L1) {
2235 int offset = message.arguments().at(0).toInt();
2236 int type = message.arguments().at(1).toUInt();
2237 int startOffset, endOffset;
2238 QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset);
2240 ret << text << startOffset << endOffset;
2241 connection.send(message.createReply(ret));
2242 }
else if (function ==
"RemoveSelection"_L1) {
2243 int selectionNum = message.arguments().at(0).toInt();
2244 interface->textInterface()->removeSelection(selectionNum);
2245 sendReply(connection, message,
true);
2246 }
else if (function ==
"SetCaretOffset"_L1) {
2247 int offset = message.arguments().at(0).toInt();
2248 interface->textInterface()->setCursorPosition(offset);
2249 sendReply(connection, message,
true);
2250 }
else if (function ==
"ScrollSubstringTo"_L1) {
2251 int startOffset = message.arguments().at(0).toInt();
2252 int endOffset = message.arguments().at(1).toInt();
2254 qCInfo(lcAccessibilityAtspi) <<
"AtSpiAdaptor::ScrollSubstringTo doesn'take take scroll type into account.";
2255 interface->textInterface()->scrollToSubstring(startOffset, endOffset);
2256 sendReply(connection, message,
true);
2257 }
else if (function ==
"SetSelection"_L1) {
2258 int selectionNum = message.arguments().at(0).toInt();
2259 int startOffset = message.arguments().at(1).toInt();
2260 int endOffset = message.arguments().at(2).toInt();
2261 interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
2262 sendReply(connection, message,
true);
2264 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::textInterface does not implement" << function << message.path();
2270QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiBoundaryType(
int atspiTextBoundaryType)
2272 switch (atspiTextBoundaryType) {
2273 case ATSPI_TEXT_BOUNDARY_CHAR:
2274 return QAccessible::CharBoundary;
2275 case ATSPI_TEXT_BOUNDARY_WORD_START:
2276 case ATSPI_TEXT_BOUNDARY_WORD_END:
2277 return QAccessible::WordBoundary;
2278 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
2279 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
2280 return QAccessible::SentenceBoundary;
2281 case ATSPI_TEXT_BOUNDARY_LINE_START:
2282 case ATSPI_TEXT_BOUNDARY_LINE_END:
2283 return QAccessible::LineBoundary;
2285 Q_ASSERT_X(0,
"",
"Requested invalid boundary type.");
2286 return QAccessible::CharBoundary;
2289bool AtSpiAdaptor::isValidAtspiTextGranularity(uint atspiTextGranularity)
2291 if (atspiTextGranularity == ATSPI_TEXT_GRANULARITY_CHAR
2292 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_WORD
2293 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_SENTENCE
2294 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_LINE
2295 || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_PARAGRAPH)
2298 qCWarning(lcAccessibilityAtspi) <<
"Unknown value" << atspiTextGranularity <<
"for AT-SPI text granularity type";
2302QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiTextGranularity(uint atspiTextGranularity)
2304 Q_ASSERT(isValidAtspiTextGranularity(atspiTextGranularity));
2306 switch (atspiTextGranularity) {
2307 case ATSPI_TEXT_GRANULARITY_CHAR:
2308 return QAccessible::CharBoundary;
2309 case ATSPI_TEXT_GRANULARITY_WORD:
2310 return QAccessible::WordBoundary;
2311 case ATSPI_TEXT_GRANULARITY_SENTENCE:
2312 return QAccessible::SentenceBoundary;
2313 case ATSPI_TEXT_GRANULARITY_LINE:
2314 return QAccessible::LineBoundary;
2315 case ATSPI_TEXT_GRANULARITY_PARAGRAPH:
2316 return QAccessible::ParagraphBoundary;
2318 return QAccessible::CharBoundary;
2323 struct AtSpiAttribute {
2326 AtSpiAttribute(
const QString &aName,
const QString &aValue) : name(aName), value(aValue) {}
2327 bool isNull()
const {
return name.isNull() || value.isNull(); }
2330 QString atspiColor(
const QString &ia2Color)
2333 return ia2Color.mid(4, ia2Color.size() - (4+1)).replace(u"\\,"_s, u","_s);
2336 QString atspiSize(
const QString &ia2Size)
2339 return ia2Size.left(ia2Size.size() - 2);
2342 AtSpiAttribute atspiTextAttribute(
const QString &ia2Name,
const QString &ia2Value)
2344 QString name = ia2Name;
2345 QString value = ia2Value;
2354 if (ia2Name ==
"background-color"_L1) {
2355 name = QStringLiteral(
"bg-color");
2356 value = atspiColor(value);
2357 }
else if (ia2Name ==
"font-family"_L1) {
2358 name = QStringLiteral(
"family-name");
2359 }
else if (ia2Name ==
"color"_L1) {
2360 name = QStringLiteral(
"fg-color");
2361 value = atspiColor(value);
2362 }
else if (ia2Name ==
"text-align"_L1) {
2363 name = QStringLiteral(
"justification");
2364 if (value ==
"justify"_L1) {
2365 value = QStringLiteral(
"fill");
2366 }
else if (value !=
"left"_L1 && value !=
"right"_L1 && value !=
"center"_L1) {
2367 qCDebug(lcAccessibilityAtspi) <<
"Unknown text-align attribute value \""
2368 << value <<
"\" cannot be translated to AT-SPI.";
2371 }
else if (ia2Name ==
"font-size"_L1) {
2372 name = QStringLiteral(
"size");
2373 value = atspiSize(value);
2374 }
else if (ia2Name ==
"font-style"_L1) {
2375 name = QStringLiteral(
"style");
2376 if (value !=
"normal"_L1 && value !=
"italic"_L1 && value !=
"oblique"_L1) {
2377 qCDebug(lcAccessibilityAtspi) <<
"Unknown font-style attribute value \"" << value
2378 <<
"\" cannot be translated to AT-SPI.";
2381 }
else if (ia2Name ==
"text-underline-type"_L1) {
2382 name = QStringLiteral(
"underline");
2383 if (value !=
"none"_L1 && value !=
"single"_L1 && value !=
"double"_L1) {
2384 qCDebug(lcAccessibilityAtspi) <<
"Unknown text-underline-type attribute value \""
2385 << value <<
"\" cannot be translated to AT-SPI.";
2388 }
else if (ia2Name ==
"font-weight"_L1) {
2389 name = QStringLiteral(
"weight");
2390 if (value ==
"normal"_L1)
2395 }
else if (((ia2Name ==
"text-line-through-style"_L1 || ia2Name ==
"text-line-through-type"_L1) && (ia2Value !=
"none"_L1))
2396 || (ia2Name ==
"text-line-through-text"_L1 && !ia2Value.isEmpty())) {
2400 name = QStringLiteral(
"strikethrough");
2401 value = QStringLiteral(
"true");
2402 }
else if (ia2Name ==
"text-position"_L1) {
2403 name = QStringLiteral(
"vertical-align");
2404 if (value !=
"baseline"_L1 && value !=
"super"_L1 && value !=
"sub"_L1) {
2405 qCDebug(lcAccessibilityAtspi) <<
"Unknown text-position attribute value \"" << value
2406 <<
"\" cannot be translated to AT-SPI.";
2409 }
else if (ia2Name ==
"writing-mode"_L1) {
2410 name = QStringLiteral(
"direction");
2411 if (value ==
"lr"_L1)
2412 value = QStringLiteral(
"ltr");
2413 else if (value ==
"rl"_L1)
2414 value = QStringLiteral(
"rtl");
2415 else if (value ==
"tb"_L1) {
2417 value = QStringLiteral(
"rtl");
2418 qCDebug(lcAccessibilityAtspi) <<
"writing-mode attribute value \"tb\" translated only w.r.t. horizontal direction; vertical direction ignored";
2420 qCDebug(lcAccessibilityAtspi) <<
"Unknown writing-mode attribute value \"" << value
2421 <<
"\" cannot be translated to AT-SPI.";
2424 }
else if (ia2Name ==
"language"_L1) {
2426 }
else if (ia2Name ==
"invalid"_L1) {
2433 return AtSpiAttribute(name, value);
2437QSpiAttributeSet AtSpiAdaptor::getAttributes(QAccessibleInterface *interface)
2439 QSpiAttributeSet set;
2440 QAccessibleAttributesInterface *attributesIface = interface->attributesInterface();
2441 if (!attributesIface)
2444 const QList<QAccessible::Attribute> attrKeys = attributesIface->attributeKeys();
2445 for (QAccessible::Attribute key : attrKeys) {
2446 const QVariant value = attributesIface->attributeValue(key);
2449 case QAccessible::Attribute::Custom:
2452 Q_ASSERT((value.canConvert<QHash<QString, QString>>()));
2453 const QHash<QString, QString> attrMap = value.value<QHash<QString, QString>>();
2454 for (
auto [name, val] : attrMap.asKeyValueRange())
2455 set.insert(name, val);
2458 case QAccessible::Attribute::Level:
2459 Q_ASSERT(value.canConvert<
int>());
2460 set.insert(QStringLiteral(
"level"), QString::number(value.toInt()));
2470QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface,
int offset,
2471 bool includeDefaults)
2473 Q_UNUSED(includeDefaults);
2475 QSpiAttributeSet set;
2479 QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
2480 const QStringList attributes = joined.split(u';', Qt::SkipEmptyParts, Qt::CaseSensitive);
2481 for (
const QString &attr : attributes) {
2482 QStringList items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
2483 if (items.count() == 2)
2485 AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
2486 if (!attribute.isNull())
2487 set[attribute.name] = attribute.value;
2492 list << QVariant::fromValue(set) << startOffset << endOffset;
2497QString AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface,
int offset,
2498 const QString &attributeName)
2501 QSpiAttributeSet map;
2505 joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
2506 const QStringList attributes = joined.split (u';', Qt::SkipEmptyParts, Qt::CaseSensitive);
2507 for (
const QString& attr : attributes) {
2509 items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
2510 AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
2511 if (!attribute.isNull())
2512 map[attribute.name] = attribute.value;
2514 return map[attributeName];
2517QList<QVariant> AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface,
int offset,
2520 QRect rect = interface->textInterface()->characterRect(offset);
2521 rect = translateFromScreenCoordinates(interface, rect, coordType);
2522 return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
2525QList<QVariant> AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface,
int startOffset,
2526 int endOffset, uint coordType)
2528 if (endOffset == -1)
2529 endOffset = interface->textInterface()->characterCount();
2531 QAccessibleTextInterface *textInterface = interface->textInterface();
2532 if (endOffset <= startOffset || !textInterface)
2533 return QList<QVariant>() << -1 << -1 << 0 << 0;
2535 QRect rect = textInterface->characterRect(startOffset);
2536 for (
int i=startOffset + 1; i <= endOffset; i++)
2537 rect = rect | textInterface->characterRect(i);
2539 rect = translateFromScreenCoordinates(interface, rect, coordType);
2540 return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height();
2543bool AtSpiAdaptor::isValidCoordType(uint coordType)
2545 if (coordType == ATSPI_COORD_TYPE_SCREEN || coordType == ATSPI_COORD_TYPE_WINDOW || coordType == ATSPI_COORD_TYPE_PARENT)
2548 qCWarning(lcAccessibilityAtspi) <<
"Unknown value" << coordType <<
"for AT-SPI coord type";
2552QRect AtSpiAdaptor::translateFromScreenCoordinates(QAccessibleInterface *interface,
const QRect &screenRect, uint targetCoordType)
2554 Q_ASSERT(isValidCoordType(targetCoordType));
2556 QAccessibleInterface *upper =
nullptr;
2557 if (targetCoordType == ATSPI_COORD_TYPE_WINDOW)
2558 upper = getWindow(interface);
2559 else if (targetCoordType == ATSPI_COORD_TYPE_PARENT)
2560 upper = interface->parent();
2562 QRect rect = screenRect;
2564 rect.translate(-upper->rect().x(), -upper->rect().y());
2569QPoint AtSpiAdaptor::translateToScreenCoordinates(QAccessibleInterface *interface,
const QPoint &pos, uint fromCoordType)
2571 Q_ASSERT(isValidCoordType(fromCoordType));
2573 QAccessibleInterface *upper =
nullptr;
2574 if (fromCoordType == ATSPI_COORD_TYPE_WINDOW)
2575 upper = getWindow(interface);
2576 else if (fromCoordType == ATSPI_COORD_TYPE_PARENT)
2577 upper = interface->parent();
2579 QPoint screenPos = pos;
2581 screenPos += upper->rect().topLeft();
2587static QString textForRange(QAccessibleInterface *accessible,
int startOffset,
int endOffset)
2589 if (QAccessibleTextInterface *textIface = accessible->textInterface()) {
2590 if (endOffset == -1)
2591 endOffset = textIface->characterCount();
2592 return textIface->text(startOffset, endOffset);
2594 QString txt = accessible->text(QAccessible::Value);
2595 if (endOffset == -1)
2596 endOffset = txt.size();
2597 return txt.mid(startOffset, endOffset - startOffset);
2600static void replaceTextFallback(QAccessibleInterface *accessible,
long startOffset,
long endOffset,
const QString &txt)
2602 QString t = textForRange(accessible, 0, -1);
2603 if (endOffset == -1)
2604 endOffset = t.size();
2605 if (endOffset - startOffset == 0)
2606 t.insert(startOffset, txt);
2608 t.replace(startOffset, endOffset - startOffset, txt);
2609 accessible->setText(QAccessible::Value, t);
2612bool AtSpiAdaptor::editableTextInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2614 if (function ==
"CopyText"_L1) {
2615#ifndef QT_NO_CLIPBOARD
2616 int startOffset = message.arguments().at(0).toInt();
2617 int endOffset = message.arguments().at(1).toInt();
2618 const QString t = textForRange(interface, startOffset, endOffset);
2619 QGuiApplication::clipboard()->setText(t);
2621 connection.send(message.createReply(
true));
2622 }
else if (function ==
"CutText"_L1) {
2623#ifndef QT_NO_CLIPBOARD
2624 int startOffset = message.arguments().at(0).toInt();
2625 int endOffset = message.arguments().at(1).toInt();
2626 const QString t = textForRange(interface, startOffset, endOffset);
2627 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2628 editableTextIface->deleteText(startOffset, endOffset);
2630 replaceTextFallback(interface, startOffset, endOffset, QString());
2631 QGuiApplication::clipboard()->setText(t);
2633 connection.send(message.createReply(
true));
2634 }
else if (function ==
"DeleteText"_L1) {
2635 int startOffset = message.arguments().at(0).toInt();
2636 int endOffset = message.arguments().at(1).toInt();
2637 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2638 editableTextIface->deleteText(startOffset, endOffset);
2640 replaceTextFallback(interface, startOffset, endOffset, QString());
2641 connection.send(message.createReply(
true));
2642 }
else if (function ==
"InsertText"_L1) {
2643 int position = message.arguments().at(0).toInt();
2644 QString text = message.arguments().at(1).toString();
2645 int length = message.arguments().at(2).toInt();
2646 text.resize(length);
2647 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2648 editableTextIface->insertText(position, text);
2650 replaceTextFallback(interface, position, position, text);
2651 connection.send(message.createReply(
true));
2652 }
else if (function ==
"PasteText"_L1) {
2653#ifndef QT_NO_CLIPBOARD
2654 int position = message.arguments().at(0).toInt();
2655 const QString txt = QGuiApplication::clipboard()->text();
2656 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2657 editableTextIface->insertText(position, txt);
2659 replaceTextFallback(interface, position, position, txt);
2661 connection.send(message.createReply(
true));
2662 }
else if (function ==
"SetTextContents"_L1) {
2663 QString newContents = message.arguments().at(0).toString();
2664 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2665 editableTextIface->replaceText(0, interface->textInterface()->characterCount(), newContents);
2667 replaceTextFallback(interface, 0, -1, newContents);
2668 connection.send(message.createReply(
true));
2669 }
else if (function.isEmpty()) {
2670 connection.send(message.createReply());
2672 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::editableTextInterface does not implement" << function << message.path();
2679bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2681 QAccessibleValueInterface *valueIface = interface->valueInterface();
2685 if (function ==
"SetCurrentValue"_L1) {
2686 QDBusVariant v = qvariant_cast<QDBusVariant>(message.arguments().at(2));
2687 double value = v.variant().toDouble();
2690 valueIface->setCurrentValue(value);
2691 connection.send(message.createReply());
2694 if (function ==
"GetCurrentValue"_L1)
2695 value = valueIface->currentValue();
2696 else if (function ==
"GetMaximumValue"_L1)
2697 value = valueIface->maximumValue();
2698 else if (function ==
"GetMinimumIncrement"_L1)
2699 value = valueIface->minimumStepSize();
2700 else if (function ==
"GetMinimumValue"_L1)
2701 value = valueIface->minimumValue();
2703 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::valueInterface does not implement" << function << message.path();
2706 if (!value.canConvert<
double>()) {
2707 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::valueInterface: Could not convert to double:" << function;
2712 connection.send(message.createReply(
2713 QVariant::fromValue(QDBusVariant(QVariant::fromValue(value.toDouble())))));
2719bool AtSpiAdaptor::selectionInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2721 QAccessibleSelectionInterface* selectionInterface = interface->selectionInterface();
2722 if (!selectionInterface) {
2723 qCWarning(lcAccessibilityAtspi) <<
"Could not find selection interface for: " << message.path() << interface;
2727 if (function ==
"ClearSelection"_L1 ) {
2728 connection.send(message.createReply(QVariant::fromValue((selectionInterface->clear()))));
2729 }
else if (function ==
"DeselectChild"_L1 ) {
2730 int childIndex = message.arguments().at(0).toInt();
2732 QAccessibleInterface *child = interface->child(childIndex);
2734 ret = selectionInterface->unselect(child);
2735 connection.send(message.createReply(QVariant::fromValue(ret)));
2736 }
else if (function ==
"DeselectSelectedChild"_L1 ) {
2737 int selectionIndex = message.arguments().at(0).toInt();
2739 QAccessibleInterface *selectedChild = selectionInterface->selectedItem(selectionIndex);
2741 ret = selectionInterface->unselect(selectedChild);
2742 connection.send(message.createReply(QVariant::fromValue(ret)));
2743 }
else if (function ==
"GetNSelectedChildren"_L1) {
2744 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2745 QVariant::fromValue(selectionInterface->selectedItemCount())))));
2746 }
else if (function ==
"GetSelectedChild"_L1) {
2747 int selectionIndex = message.arguments().at(0).toInt();
2748 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(selectionInterface->selectedItem(selectionIndex))));
2749 connection.send(message.createReply(QVariant::fromValue(ref)));
2750 }
else if (function ==
"IsChildSelected"_L1 ) {
2751 int childIndex = message.arguments().at(0).toInt();
2753 QAccessibleInterface *child = interface->child(childIndex);
2755 ret = selectionInterface->isSelected(child);
2756 connection.send(message.createReply(QVariant::fromValue(ret)));
2757 }
else if (function ==
"SelectAll"_L1 ) {
2758 connection.send(message.createReply(QVariant::fromValue(selectionInterface->selectAll())));
2759 }
else if (function ==
"SelectChild"_L1 ) {
2760 int childIndex = message.arguments().at(0).toInt();
2762 QAccessibleInterface *child = interface->child(childIndex);
2764 ret = selectionInterface->select(child);
2765 connection.send(message.createReply(QVariant::fromValue(ret)));
2767 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::selectionInterface does not implement " << function << message.path();
2776bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
2778 if (!(interface->tableInterface() || interface->tableCellInterface())) {
2779 qCWarning(lcAccessibilityAtspi) <<
"Qt AtSpiAdaptor: Could not find table interface for:" << message.path() << interface;
2783 if (function ==
"GetCaption"_L1) {
2784 QAccessibleInterface * captionInterface= interface->tableInterface()->caption();
2785 if (captionInterface) {
2786 QSpiObjectReference ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(captionInterface)));
2787 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref))));
2789 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(
2790 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))))));
2792 }
else if (function ==
"GetNColumns"_L1) {
2793 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2794 QVariant::fromValue(interface->tableInterface()->columnCount())))));
2795 }
else if (function ==
"GetNRows"_L1) {
2796 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2797 QVariant::fromValue(interface->tableInterface()->rowCount())))));
2798 }
else if (function ==
"GetNSelectedColumns"_L1) {
2799 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2800 QVariant::fromValue(interface->tableInterface()->selectedColumnCount())))));
2801 }
else if (function ==
"GetNSelectedRows"_L1) {
2802 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2803 QVariant::fromValue(interface->tableInterface()->selectedRowCount())))));
2804 }
else if (function ==
"GetSummary"_L1) {
2805 QAccessibleInterface *summary = interface->tableInterface() ? interface->tableInterface()->summary() :
nullptr;
2806 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(summary)));
2807 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
2808 }
else if (function ==
"GetAccessibleAt"_L1) {
2809 int row = message.arguments().at(0).toInt();
2810 int column = message.arguments().at(1).toInt();
2813 (row >= interface->tableInterface()->rowCount()) ||
2814 (column >= interface->tableInterface()->columnCount())) {
2815 qCWarning(lcAccessibilityAtspi) <<
"Invalid index for tableInterface GetAccessibleAt (" << row <<
"," << column <<
')';
2819 QSpiObjectReference ref;
2820 QAccessibleInterface * cell(interface->tableInterface()->cellAt(row, column));
2822 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell)));
2824 qCWarning(lcAccessibilityAtspi) <<
"No cell interface returned for" << interface->object() << row << column;
2825 ref = QSpiObjectReference();
2827 connection.send(message.createReply(QVariant::fromValue(ref)));
2829 }
else if (function ==
"GetIndexAt"_L1) {
2830 int row = message.arguments().at(0).toInt();
2831 int column = message.arguments().at(1).toInt();
2832 QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column);
2834 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::GetIndexAt(" << row <<
',' << column <<
") did not find a cell." << interface;
2837 int index = interface->indexOfChild(cell);
2838 qCDebug(lcAccessibilityAtspi) <<
"QSpiAdaptor::GetIndexAt row:" << row <<
" col:" << column <<
" logical index:" << index;
2839 Q_ASSERT(index > 0);
2840 connection.send(message.createReply(index));
2841 }
else if ((function ==
"GetColumnAtIndex"_L1) || (function ==
"GetRowAtIndex"_L1)) {
2842 int index = message.arguments().at(0).toInt();
2845 QAccessibleInterface * cell = interface->child(index);
2847 if (function ==
"GetColumnAtIndex"_L1) {
2848 if (cell->role() == QAccessible::ColumnHeader) {
2850 }
else if (cell->role() == QAccessible::RowHeader) {
2853 if (!cell->tableCellInterface()) {
2854 qCWarning(lcAccessibilityAtspi).nospace() <<
"AtSpiAdaptor::" << function <<
" No table cell interface: " << cell;
2857 ret = cell->tableCellInterface()->columnIndex();
2860 if (cell->role() == QAccessible::ColumnHeader) {
2862 }
else if (cell->role() == QAccessible::RowHeader) {
2863 ret = index % interface->tableInterface()->columnCount();
2865 if (!cell->tableCellInterface()) {
2866 qCWarning(lcAccessibilityAtspi).nospace() <<
"AtSpiAdaptor::" << function <<
" No table cell interface: " << cell;
2869 ret = cell->tableCellInterface()->rowIndex();
2873 qCWarning(lcAccessibilityAtspi).nospace() <<
"AtSpiAdaptor::" << function <<
" No cell at index: " << index <<
" " << interface;
2877 connection.send(message.createReply(ret));
2879 }
else if (function ==
"GetColumnDescription"_L1) {
2880 int column = message.arguments().at(0).toInt();
2881 connection.send(message.createReply(interface->tableInterface()->columnDescription(column)));
2882 }
else if (function ==
"GetRowDescription"_L1) {
2883 int row = message.arguments().at(0).toInt();
2884 connection.send(message.createReply(interface->tableInterface()->rowDescription(row)));
2888 }
else if (function ==
"GetRowColumnExtentsAtIndex"_L1) {
2889 int index = message.arguments().at(0).toInt();
2890 bool success =
false;
2894 int rowExtents = -1;
2895 int colExtents = -1;
2896 bool isSelected =
false;
2898 int cols = interface->tableInterface()->columnCount();
2902 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, col)) {
2903 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) {
2904 row = cellIface->rowIndex();
2905 col = cellIface->columnIndex();
2906 rowExtents = cellIface->rowExtent();
2907 colExtents = cellIface->columnExtent();
2908 isSelected = cellIface->isSelected();
2914 list << success << row << col << rowExtents << colExtents << isSelected;
2915 connection.send(message.createReply(list));
2917 }
else if (function ==
"GetColumnExtentAt"_L1) {
2918 int row = message.arguments().at(0).toInt();
2919 int column = message.arguments().at(1).toInt();
2920 int columnExtent = 0;
2921 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
2922 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2923 columnExtent = cellIface->columnExtent();
2925 connection.send(message.createReply(columnExtent));
2927 }
else if (function ==
"GetRowExtentAt"_L1) {
2928 int row = message.arguments().at(0).toInt();
2929 int column = message.arguments().at(1).toInt();
2931 if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
2932 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2933 rowExtent = cellIface->rowExtent();
2935 connection.send(message.createReply(rowExtent));
2937 }
else if (function ==
"GetColumnHeader"_L1) {
2938 int column = message.arguments().at(0).toInt();
2939 QSpiObjectReference ref;
2941 QAccessibleInterface * cell(interface->tableInterface()->cellAt(0, column));
2942 if (cell && cell->tableCellInterface()) {
2943 QList<QAccessibleInterface*> header = cell->tableCellInterface()->columnHeaderCells();
2944 if (header.size() > 0) {
2945 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
2948 connection.send(message.createReply(QVariant::fromValue(ref)));
2950 }
else if (function ==
"GetRowHeader"_L1) {
2951 int row = message.arguments().at(0).toInt();
2952 QSpiObjectReference ref;
2953 QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, 0);
2954 if (cell && cell->tableCellInterface()) {
2955 QList<QAccessibleInterface*> header = cell->tableCellInterface()->rowHeaderCells();
2956 if (header.size() > 0) {
2957 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.takeAt(0))));
2960 connection.send(message.createReply(QVariant::fromValue(ref)));
2962 }
else if (function ==
"GetSelectedColumns"_L1) {
2963 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedColumns())));
2964 }
else if (function ==
"GetSelectedRows"_L1) {
2965 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedRows())));
2966 }
else if (function ==
"IsColumnSelected"_L1) {
2967 int column = message.arguments().at(0).toInt();
2968 connection.send(message.createReply(interface->tableInterface()->isColumnSelected(column)));
2969 }
else if (function ==
"IsRowSelected"_L1) {
2970 int row = message.arguments().at(0).toInt();
2971 connection.send(message.createReply(interface->tableInterface()->isRowSelected(row)));
2972 }
else if (function ==
"IsSelected"_L1) {
2973 int row = message.arguments().at(0).toInt();
2974 int column = message.arguments().at(1).toInt();
2975 bool selected =
false;
2976 if (QAccessibleInterface* cell = interface->tableInterface()->cellAt(row, column)) {
2977 if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
2978 selected = cellIface->isSelected();
2980 connection.send(message.createReply(selected));
2981 }
else if (function ==
"AddColumnSelection"_L1) {
2982 int column = message.arguments().at(0).toInt();
2983 connection.send(message.createReply(interface->tableInterface()->selectColumn(column)));
2984 }
else if (function ==
"AddRowSelection"_L1) {
2985 int row = message.arguments().at(0).toInt();
2986 connection.send(message.createReply(interface->tableInterface()->selectRow(row)));
2987 }
else if (function ==
"RemoveColumnSelection"_L1) {
2988 int column = message.arguments().at(0).toInt();
2989 connection.send(message.createReply(interface->tableInterface()->unselectColumn(column)));
2990 }
else if (function ==
"RemoveRowSelection"_L1) {
2991 int row = message.arguments().at(0).toInt();
2992 connection.send(message.createReply(interface->tableInterface()->unselectRow(row)));
2994 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::tableInterface does not implement" << function << message.path();
3001bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface,
const QString &function,
const QDBusMessage &message,
const QDBusConnection &connection)
3003 QAccessibleTableCellInterface* cellInterface = interface->tableCellInterface();
3004 if (!cellInterface) {
3005 qCWarning(lcAccessibilityAtspi) <<
"Could not find table cell interface for: " << message.path() << interface;
3009 if (function ==
"GetColumnHeaderCells"_L1) {
3010 QSpiObjectReferenceArray headerCells;
3011 const auto headerCellInterfaces = cellInterface->columnHeaderCells();
3012 headerCells.reserve(headerCellInterfaces.size());
3013 for (QAccessibleInterface *cell : headerCellInterfaces) {
3014 const QString childPath = pathForInterface(cell);
3015 const QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
3018 connection.send(message.createReply(QVariant::fromValue(headerCells)));
3019 }
else if (function ==
"GetColumnSpan"_L1) {
3020 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
3021 QVariant::fromValue(cellInterface->columnExtent())))));
3022 }
else if (function ==
"GetPosition"_L1) {
3023 const int row = cellInterface->rowIndex();
3024 const int column = cellInterface->columnIndex();
3025 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
3026 QVariant::fromValue(QPoint(row, column))))));
3027 }
else if (function ==
"GetRowHeaderCells"_L1) {
3028 QSpiObjectReferenceArray headerCells;
3029 const auto headerCellInterfaces = cellInterface->rowHeaderCells();
3030 headerCells.reserve(headerCellInterfaces.size());
3031 for (QAccessibleInterface *cell : headerCellInterfaces) {
3032 const QString childPath = pathForInterface(cell);
3033 const QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
3036 connection.send(message.createReply(QVariant::fromValue(headerCells)));
3037 }
else if (function ==
"GetRowSpan"_L1) {
3038 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
3039 QVariant::fromValue(cellInterface->rowExtent())))));
3040 }
else if (function ==
"GetRowColumnSpan"_L1) {
3042 list << cellInterface->rowIndex() << cellInterface->columnIndex() << cellInterface->rowExtent() << cellInterface->columnExtent();
3043 connection.send(message.createReply(list));
3044 }
else if (function ==
"GetTable"_L1) {
3045 QSpiObjectReference ref;
3046 QAccessibleInterface* table = cellInterface->table();
3047 if (table && table->tableInterface())
3048 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(table)));
3049 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
3051 qCWarning(lcAccessibilityAtspi) <<
"AtSpiAdaptor::tableCellInterface does not implement" << function << message.path();
3060#include "moc_atspiadaptor_p.cpp"