1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "atspiadaptor_p.h"
44 #include <QtGui/qwindow.h>
45 #include <QtWidgets/qapplication.h>
46 #include <qdbusmessage.h>
47 #include <qdbusreply.h>
48 #include <QtWidgets/qwidget.h>
49 #include <qclipboard.h>
53 #include "socket_interface.h"
54 #include "constant_mappings_p.h"
56 #include "application_p.h"
61 \brief AtSpiAdaptor is the main class to forward between QAccessibleInterface and AT-SPI DBus
63 AtSpiAdaptor implements the functions specified in all at-spi interfaces.
64 It sends notifications coming from Qt via dbus and listens to incoming dbus requests.
69 AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
70 : QDBusVirtualObject(parent), m_dbus(connection), initialized(false)
73 , sendObject_active_descendant_changed(0)
74 , sendObject_attributes_changed(0)
75 , sendObject_bounds_changed(0)
76 , sendObject_children_changed(0)
77 // , sendObject_children_changed_add(0)
78 // , sendObject_children_changed_remove(0)
79 , sendObject_column_deleted(0)
80 , sendObject_column_inserted(0)
81 , sendObject_column_reordered(0)
82 , sendObject_link_selected(0)
83 , sendObject_model_changed(0)
84 , sendObject_property_change(0)
85 , sendObject_property_change_accessible_description(0)
86 , sendObject_property_change_accessible_name(0)
87 , sendObject_property_change_accessible_parent(0)
88 , sendObject_property_change_accessible_role(0)
89 , sendObject_property_change_accessible_table_caption(0)
90 , sendObject_property_change_accessible_table_column_description(0)
91 , sendObject_property_change_accessible_table_column_header(0)
92 , sendObject_property_change_accessible_table_row_description(0)
93 , sendObject_property_change_accessible_table_row_header(0)
94 , sendObject_property_change_accessible_table_summary(0)
95 , sendObject_property_change_accessible_value(0)
96 , sendObject_row_deleted(0)
97 , sendObject_row_inserted(0)
98 , sendObject_row_reordered(0)
99 , sendObject_selection_changed(0)
100 , sendObject_text_attributes_changed(0)
101 , sendObject_text_bounds_changed(0)
102 , sendObject_text_caret_moved(0)
103 , sendObject_text_changed(0)
104 // , sendObject_text_changed_delete(0)
105 // , sendObject_text_changed_insert(0)
106 , sendObject_text_selection_changed(0)
107 , sendObject_value_changed(0)
108 , sendObject_visible_data_changed(0)
110 , sendWindow_activate(0)
111 , sendWindow_close(0)
112 , sendWindow_create(0)
113 , sendWindow_deactivate(0)
114 // , sendWindow_desktop_create(0)
115 // , sendWindow_desktop_destroy(0)
116 , sendWindow_lower(0)
117 , sendWindow_maximize(0)
118 , sendWindow_minimize(0)
120 , sendWindow_raise(0)
121 , sendWindow_reparent(0)
122 , sendWindow_resize(0)
123 , sendWindow_restore(0)
124 , sendWindow_restyle(0)
125 , sendWindow_shade(0)
126 , sendWindow_unshade(0)
128 m_applicationAdaptor = new QSpiApplicationAdaptor(m_dbus->connection(), this);
129 connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,bool)), this, SLOT(windowActivated(QObject*,bool)));
132 AtSpiAdaptor::~AtSpiAdaptor()
137 Provide DBus introspection.
139 QString AtSpiAdaptor::introspect(const QString &path) const
141 static const QLatin1String accessibleIntrospection(
142 " <interface name=\"org.a11y.atspi.Accessible\">\n"
143 " <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
144 " <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
145 " <property access=\"read\" type=\"(so)\" name=\"Parent\">\n"
146 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
148 " <property access=\"read\" type=\"i\" name=\"ChildCount\"/>\n"
149 " <method name=\"GetChildAtIndex\">\n"
150 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
151 " <arg direction=\"out\" type=\"(so)\"/>\n"
152 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
154 " <method name=\"GetChildren\">\n"
155 " <arg direction=\"out\" type=\"a(so)\"/>\n"
156 " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
158 " <method name=\"GetIndexInParent\">\n"
159 " <arg direction=\"out\" type=\"i\"/>\n"
161 " <method name=\"GetRelationSet\">\n"
162 " <arg direction=\"out\" type=\"a(ua(so))\"/>\n"
163 " <annotation value=\"QSpiRelationArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
165 " <method name=\"GetRole\">\n"
166 " <arg direction=\"out\" type=\"u\"/>\n"
168 " <method name=\"GetRoleName\">\n"
169 " <arg direction=\"out\" type=\"s\"/>\n"
171 " <method name=\"GetLocalizedRoleName\">\n"
172 " <arg direction=\"out\" type=\"s\"/>\n"
174 " <method name=\"GetState\">\n"
175 " <arg direction=\"out\" type=\"au\"/>\n"
176 " <annotation value=\"QSpiUIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
178 " <method name=\"GetAttributes\">\n"
179 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
180 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
182 " <method name=\"GetApplication\">\n"
183 " <arg direction=\"out\" type=\"(so)\"/>\n"
184 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
189 static const QLatin1String actionIntrospection(
190 " <interface name=\"org.a11y.atspi.Action\">\n"
191 " <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
192 " <method name=\"GetDescription\">\n"
193 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
194 " <arg direction=\"out\" type=\"s\"/>\n"
196 " <method name=\"GetName\">\n"
197 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
198 " <arg direction=\"out\" type=\"s\"/>\n"
200 " <method name=\"GetKeyBinding\">\n"
201 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
202 " <arg direction=\"out\" type=\"s\"/>\n"
204 " <method name=\"GetActions\">\n"
205 " <arg direction=\"out\" type=\"a(sss)\" name=\"index\"/>\n"
206 " <annotation value=\"QSpiActionArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
208 " <method name=\"DoAction\">\n"
209 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
210 " <arg direction=\"out\" type=\"b\"/>\n"
215 static const QLatin1String applicationIntrospection(
216 " <interface name=\"org.a11y.atspi.Application\">\n"
217 " <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
218 " <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
219 " <property access=\"readwrite\" type=\"i\" name=\"Id\"/>\n"
220 " <method name=\"GetLocale\">\n"
221 " <arg direction=\"in\" type=\"u\" name=\"lctype\"/>\n"
222 " <arg direction=\"out\" type=\"s\"/>\n"
224 " <method name=\"GetApplicationBusAddress\">\n"
225 " <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
230 static const QLatin1String componentIntrospection(
231 " <interface name=\"org.a11y.atspi.Component\">\n"
232 " <method name=\"Contains\">\n"
233 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
234 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
235 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
236 " <arg direction=\"out\" type=\"b\"/>\n"
238 " <method name=\"GetAccessibleAtPoint\">\n"
239 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
240 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
241 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
242 " <arg direction=\"out\" type=\"(so)\"/>\n"
243 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
245 " <method name=\"GetExtents\">\n"
246 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
247 " <arg direction=\"out\" type=\"(iiii)\"/>\n"
248 " <annotation value=\"QSpiRect\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
250 " <method name=\"GetPosition\">\n"
251 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
252 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
253 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
255 " <method name=\"GetSize\">\n"
256 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
257 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
259 " <method name=\"GetLayer\">\n"
260 " <arg direction=\"out\" type=\"u\"/>\n"
262 " <method name=\"GetMDIZOrder\">\n"
263 " <arg direction=\"out\" type=\"n\"/>\n"
265 " <method name=\"GrabFocus\">\n"
266 " <arg direction=\"out\" type=\"b\"/>\n"
268 " <method name=\"GetAlpha\">\n"
269 " <arg direction=\"out\" type=\"d\"/>\n"
271 " <method name=\"SetExtents\">\n"
272 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
273 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
274 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
275 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
276 " <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
277 " <arg direction=\"out\" type=\"b\"/>\n"
279 " <method name=\"SetPosition\">\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=\"b\"/>\n"
285 " <method name=\"SetSize\">\n"
286 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
287 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
288 " <arg direction=\"out\" type=\"b\"/>\n"
293 static const QLatin1String editableTextIntrospection(
294 " <interface name=\"org.a11y.atspi.EditableText\">\n"
295 " <method name=\"SetTextContents\">\n"
296 " <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
297 " <arg direction=\"out\" type=\"b\"/>\n"
299 " <method name=\"InsertText\">\n"
300 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
301 " <arg direction=\"in\" type=\"s\" name=\"text\"/>\n"
302 " <arg direction=\"in\" type=\"i\" name=\"length\"/>\n"
303 " <arg direction=\"out\" type=\"b\"/>\n"
305 " <method name=\"CopyText\">\n"
306 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
307 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
309 " <method name=\"CutText\">\n"
310 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
311 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
312 " <arg direction=\"out\" type=\"b\"/>\n"
314 " <method name=\"DeleteText\">\n"
315 " <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
316 " <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
317 " <arg direction=\"out\" type=\"b\"/>\n"
319 " <method name=\"PasteText\">\n"
320 " <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
321 " <arg direction=\"out\" type=\"b\"/>\n"
326 static const QLatin1String tableIntrospection(
327 " <interface name=\"org.a11y.atspi.Table\">\n"
328 " <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
329 " <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
330 " <property access=\"read\" type=\"(so)\" name=\"Caption\">\n"
331 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
333 " <property access=\"read\" type=\"(so)\" name=\"Summary\">\n"
334 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
336 " <property access=\"read\" type=\"i\" name=\"NSelectedRows\"/>\n"
337 " <property access=\"read\" type=\"i\" name=\"NSelectedColumns\"/>\n"
338 " <method name=\"GetAccessibleAt\">\n"
339 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
340 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
341 " <arg direction=\"out\" type=\"(so)\"/>\n"
342 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
344 " <method name=\"GetIndexAt\">\n"
345 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
346 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
347 " <arg direction=\"out\" type=\"i\"/>\n"
349 " <method name=\"GetRowAtIndex\">\n"
350 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
351 " <arg direction=\"out\" type=\"i\"/>\n"
353 " <method name=\"GetColumnAtIndex\">\n"
354 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
355 " <arg direction=\"out\" type=\"i\"/>\n"
357 " <method name=\"GetRowDescription\">\n"
358 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
359 " <arg direction=\"out\" type=\"s\"/>\n"
361 " <method name=\"GetColumnDescription\">\n"
362 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
363 " <arg direction=\"out\" type=\"s\"/>\n"
365 " <method name=\"GetRowExtentAt\">\n"
366 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
367 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
368 " <arg direction=\"out\" type=\"i\"/>\n"
370 " <method name=\"GetColumnExtentAt\">\n"
371 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
372 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
373 " <arg direction=\"out\" type=\"i\"/>\n"
375 " <method name=\"GetRowHeader\">\n"
376 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
377 " <arg direction=\"out\" type=\"(so)\"/>\n"
378 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
380 " <method name=\"GetColumnHeader\">\n"
381 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
382 " <arg direction=\"out\" type=\"(so)\"/>\n"
383 " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
385 " <method name=\"GetSelectedRows\">\n"
386 " <arg direction=\"out\" type=\"ai\"/>\n"
387 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
389 " <method name=\"GetSelectedColumns\">\n"
390 " <arg direction=\"out\" type=\"ai\"/>\n"
391 " <annotation value=\"QSpiIntList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
393 " <method name=\"IsRowSelected\">\n"
394 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
395 " <arg direction=\"out\" type=\"b\"/>\n"
397 " <method name=\"IsColumnSelected\">\n"
398 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
399 " <arg direction=\"out\" type=\"b\"/>\n"
401 " <method name=\"IsSelected\">\n"
402 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
403 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
404 " <arg direction=\"out\" type=\"b\"/>\n"
406 " <method name=\"AddRowSelection\">\n"
407 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
408 " <arg direction=\"out\" type=\"b\"/>\n"
410 " <method name=\"AddColumnSelection\">\n"
411 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
412 " <arg direction=\"out\" type=\"b\"/>\n"
414 " <method name=\"RemoveRowSelection\">\n"
415 " <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
416 " <arg direction=\"out\" type=\"b\"/>\n"
418 " <method name=\"RemoveColumnSelection\">\n"
419 " <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
420 " <arg direction=\"out\" type=\"b\"/>\n"
422 " <method name=\"GetRowColumnExtentsAtIndex\">\n"
423 " <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
424 " <arg direction=\"out\" type=\"b\"/>\n"
425 " <arg direction=\"out\" type=\"i\" name=\"row\"/>\n"
426 " <arg direction=\"out\" type=\"i\" name=\"col\"/>\n"
427 " <arg direction=\"out\" type=\"i\" name=\"row_extents\"/>\n"
428 " <arg direction=\"out\" type=\"i\" name=\"col_extents\"/>\n"
429 " <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
434 static const QLatin1String textIntrospection(
435 " <interface name=\"org.a11y.atspi.Text\">\n"
436 " <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
437 " <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
438 " <method name=\"GetText\">\n"
439 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
440 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
441 " <arg direction=\"out\" type=\"s\"/>\n"
443 " <method name=\"SetCaretOffset\">\n"
444 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
445 " <arg direction=\"out\" type=\"b\"/>\n"
447 " <method name=\"GetTextBeforeOffset\">\n"
448 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
449 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
450 " <arg direction=\"out\" type=\"s\"/>\n"
451 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
452 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
454 " <method name=\"GetTextAtOffset\">\n"
455 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
456 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
457 " <arg direction=\"out\" type=\"s\"/>\n"
458 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
459 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
461 " <method name=\"GetTextAfterOffset\">\n"
462 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
463 " <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
464 " <arg direction=\"out\" type=\"s\"/>\n"
465 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
466 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
468 " <method name=\"GetCharacterAtOffset\">\n"
469 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
470 " <arg direction=\"out\" type=\"i\"/>\n"
472 " <method name=\"GetAttributeValue\">\n"
473 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
474 " <arg direction=\"in\" type=\"s\" name=\"attributeName\"/>\n"
475 " <arg direction=\"out\" type=\"s\"/>\n"
476 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
477 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
478 " <arg direction=\"out\" type=\"b\" name=\"defined\"/>\n"
480 " <method name=\"GetAttributes\">\n"
481 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
482 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
483 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
484 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
485 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
487 " <method name=\"GetDefaultAttributes\">\n"
488 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
489 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
491 " <method name=\"GetCharacterExtents\">\n"
492 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
493 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
494 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
495 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
496 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
497 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
499 " <method name=\"GetOffsetAtPoint\">\n"
500 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
501 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
502 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
503 " <arg direction=\"out\" type=\"i\"/>\n"
505 " <method name=\"GetNSelections\">\n"
506 " <arg direction=\"out\" type=\"i\"/>\n"
507 " <method name=\"GetSelection\">\n"
508 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
509 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
510 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
512 " <method name=\"AddSelection\">\n"
513 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
514 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
515 " <arg direction=\"out\" type=\"b\"/>\n"
517 " <method name=\"RemoveSelection\">\n"
518 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
519 " <arg direction=\"out\" type=\"b\"/>\n"
521 " <method name=\"SetSelection\">\n"
522 " <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
523 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
524 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
525 " <arg direction=\"out\" type=\"b\"/>\n"
527 " <method name=\"GetRangeExtents\">\n"
528 " <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
529 " <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
530 " <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
531 " <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
532 " <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
533 " <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
534 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
536 " <method name=\"GetBoundedRanges\">\n"
537 " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
538 " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
539 " <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
540 " <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
541 " <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
542 " <arg direction=\"in\" type=\"u\" name=\"xClipType\"/>\n"
543 " <arg direction=\"in\" type=\"u\" name=\"yClipType\"/>\n"
544 " <arg direction=\"out\" type=\"a(iisv)\"/>\n"
545 " <annotation value=\"QSpiRangeList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
547 " <method name=\"GetAttributeRun\">\n"
548 " <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
549 " <arg direction=\"in\" type=\"b\" name=\"includeDefaults\"/>\n"
550 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
551 " <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
552 " <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
553 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
555 " <method name=\"GetDefaultAttributeSet\">\n"
556 " <arg direction=\"out\" type=\"a{ss}\"/>\n"
557 " <annotation value=\"QSpiAttributeSet\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
562 static const QLatin1String valueIntrospection(
563 " <interface name=\"org.a11y.atspi.Value\">\n"
564 " <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
565 " <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
566 " <property access=\"read\" type=\"d\" name=\"MinimumIncrement\"/>\n"
567 " <property access=\"readwrite\" type=\"d\" name=\"CurrentValue\"/>\n"
568 " <method name=\"SetCurrentValue\">\n"
569 " <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
574 QAIPointer interface = interfaceFromPath(path);
576 qWarning() << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << path;
580 QStringList interfaces = accessibleInterfaces(interface);
583 xml.append(accessibleIntrospection);
585 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT)))
586 xml.append(componentIntrospection);
587 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_TEXT)))
588 xml.append(textIntrospection);
589 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT)))
590 xml.append(editableTextIntrospection);
591 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_ACTION)))
592 xml.append(actionIntrospection);
593 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_TABLE)))
594 xml.append(tableIntrospection);
595 if (interfaces.contains(QLatin1String(ATSPI_DBUS_INTERFACE_VALUE)))
596 xml.append(valueIntrospection);
597 if (path == QLatin1String(QSPI_OBJECT_PATH_ROOT))
598 xml.append(applicationIntrospection);
604 When initialized we will send updates, not before this.
606 This function also checks which event listeners are registered in the at-spi registry.
608 void AtSpiAdaptor::setInitialized(bool init)
615 updateEventListeners();
616 bool success = m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
617 QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerRegistered"), this,
618 SLOT(eventListenerRegistered(QString,QString)));
619 success = success && m_dbus->connection().connect(QLatin1String("org.a11y.atspi.Registry"), QLatin1String("/org/a11y/atspi/registry"),
620 QLatin1String("org.a11y.atspi.Registry"), QLatin1String("EventListenerDeregistered"), this,
621 SLOT(eventListenerDeregistered(QString,QString)));
622 #ifdef QT_ATSPI_DEBUG
623 qDebug() << "Registered event listener change listener: " << success;
627 void AtSpiAdaptor::setBitFlag(const QString &flag)
629 Q_ASSERT(flag.size());
631 // assume we don't get nonsense - look at first letter only
632 switch (flag.at(0).toLower().toLatin1()) {
634 if (flag.size() <= 8) { // Object::
636 } else { // Object:Foo:Bar
637 QString right = flag.mid(7);
639 } else if (right.startsWith(QLatin1String("ActiveDescendantChanged"))) {
640 sendObject_active_descendant_changed = 1;
641 } else if (right.startsWith(QLatin1String("AttributesChanged"))) {
642 sendObject_attributes_changed = 1;
643 } else if (right.startsWith(QLatin1String("BoundsChanged"))) {
644 sendObject_bounds_changed = 1;
645 } else if (right.startsWith(QLatin1String("ChildrenChanged"))) {
646 sendObject_children_changed = 1;
647 } else if (right.startsWith(QLatin1String("ColumnDeleted"))) {
648 sendObject_column_deleted = 1;
649 } else if (right.startsWith(QLatin1String("ColumnInserted"))) {
650 sendObject_column_inserted = 1;
651 } else if (right.startsWith(QLatin1String("ColumnReordered"))) {
652 sendObject_column_reordered = 1;
653 } else if (right.startsWith(QLatin1String("LinkSelected"))) {
654 sendObject_link_selected = 1;
655 } else if (right.startsWith(QLatin1String("ModelChanged"))) {
656 sendObject_model_changed = 1;
657 } else if (right.startsWith(QLatin1String("PropertyChange"))) {
658 if (right == QLatin1String("PropertyChange:AccessibleDescription")) {
659 sendObject_property_change_accessible_description = 1;
660 } else if (right == QLatin1String("PropertyChange:AccessibleName")) {
661 sendObject_property_change_accessible_name = 1;
662 } else if (right == QLatin1String("PropertyChange:AccessibleParent")) {
663 sendObject_property_change_accessible_parent = 1;
664 } else if (right == QLatin1String("PropertyChange:AccessibleRole")) {
665 sendObject_property_change_accessible_role = 1;
666 } else if (right == QLatin1String("PropertyChange:TableCaption")) {
667 sendObject_property_change_accessible_table_caption = 1;
668 } else if (right == QLatin1String("PropertyChange:TableColumnDescription")) {
669 sendObject_property_change_accessible_table_column_description = 1;
670 } else if (right == QLatin1String("PropertyChange:TableColumnHeader")) {
671 sendObject_property_change_accessible_table_column_header = 1;
672 } else if (right == QLatin1String("PropertyChange:TableRowDescription")) {
673 sendObject_property_change_accessible_table_row_description = 1;
674 } else if (right == QLatin1String("PropertyChange:TableRowHeader")) {
675 sendObject_property_change_accessible_table_row_header = 1;
676 } else if (right == QLatin1String("PropertyChange:TableSummary")) {
677 sendObject_property_change_accessible_table_summary = 1;
678 } else if (right == QLatin1String("PropertyChange:AccessibleValue")) {
679 sendObject_property_change_accessible_value = 1;
681 sendObject_property_change = 1;
683 } else if (right.startsWith(QLatin1String("RowDeleted"))) {
684 sendObject_row_deleted = 1;
685 } else if (right.startsWith(QLatin1String("RowInserted"))) {
686 sendObject_row_inserted = 1;
687 } else if (right.startsWith(QLatin1String("RowReordered"))) {
688 sendObject_row_reordered = 1;
689 } else if (right.startsWith(QLatin1String("SelectionChanged"))) {
690 sendObject_selection_changed = 1;
691 } else if (right.startsWith(QLatin1String("StateChanged"))) {
692 sendObject_state_changed = 1;
693 } else if (right.startsWith(QLatin1String("TextAttributesChanged"))) {
694 sendObject_text_attributes_changed = 1;
695 } else if (right.startsWith(QLatin1String("TextBoundsChanged"))) {
696 sendObject_text_bounds_changed = 1;
697 } else if (right.startsWith(QLatin1String("TextCaretMoved"))) {
698 sendObject_text_caret_moved = 1;
699 } else if (right.startsWith(QLatin1String("TextChanged"))) {
700 sendObject_text_changed = 1;
701 } else if (right.startsWith(QLatin1String("TextSelectionChanged"))) {
702 sendObject_text_selection_changed = 1;
703 } else if (right.startsWith(QLatin1String("ValueChanged"))) {
704 sendObject_value_changed = 1;
705 } else if (right.startsWith(QLatin1String("VisibleDataChanged"))) {
706 sendObject_visible_data_changed = 1;
708 qWarning() << "WARNING: subscription string not handled:" << flag;
713 case 'w': { // window
714 if (flag.size() <= 8) {
716 } else { // object:Foo:Bar
717 QString right = flag.mid(7);
719 } else if (right.startsWith(QLatin1String("Activate"))) {
720 sendWindow_activate = 1;
721 } else if (right.startsWith(QLatin1String("Close"))) {
723 } else if (right.startsWith(QLatin1String("Create"))) {
724 sendWindow_create = 1;
725 } else if (right.startsWith(QLatin1String("Deactivate"))) {
726 sendWindow_deactivate = 1;
727 } else if (right.startsWith(QLatin1String("Lower"))) {
728 sendWindow_lower = 1;
729 } else if (right.startsWith(QLatin1String("Maximize"))) {
730 sendWindow_maximize = 1;
731 } else if (right.startsWith(QLatin1String("Minimize"))) {
732 sendWindow_minimize = 1;
733 } else if (right.startsWith(QLatin1String("Move"))) {
735 } else if (right.startsWith(QLatin1String("Raise"))) {
736 sendWindow_raise = 1;
737 } else if (right.startsWith(QLatin1String("Reparent"))) {
738 sendWindow_reparent = 1;
739 } else if (right.startsWith(QLatin1String("Resize"))) {
740 sendWindow_resize = 1;
741 } else if (right.startsWith(QLatin1String("Restore"))) {
742 sendWindow_restore = 1;
743 } else if (right.startsWith(QLatin1String("Restyle"))) {
744 sendWindow_restyle = 1;
745 } else if (right.startsWith(QLatin1String("Shade"))) {
746 sendWindow_shade = 1;
747 } else if (right.startsWith(QLatin1String("Unshade"))) {
748 sendWindow_unshade = 1;
749 } else if (right.startsWith(QLatin1String("DesktopCreate"))) {
751 } else if (right.startsWith(QLatin1String("DesktopDestroy"))) {
754 qWarning() << "WARNING: subscription string not handled:" << flag;
763 case 'd': { // document is not implemented
766 case 't': { // terminal is not implemented
769 case 'm': { // mouse* is handled in a different way by the gnome atspi stack
773 qWarning() << "WARNING: subscription string not handled:" << flag;
778 Checks via dbus which events should be sent.
780 void AtSpiAdaptor::updateEventListeners()
782 QDBusMessage m = QDBusMessage::createMethodCall(QLatin1String("org.a11y.atspi.Registry"),
783 QLatin1String("/org/a11y/atspi/registry"),
784 QLatin1String("org.a11y.atspi.Registry"), QLatin1String("GetRegisteredEvents"));
785 QDBusReply<QSpiEventListenerArray> listenersReply = m_dbus->connection().call(m);
786 if (listenersReply.isValid()) {
787 const QSpiEventListenerArray evList = listenersReply.value();
788 Q_FOREACH (const QSpiEventListener &ev, evList) {
789 setBitFlag(ev.eventName);
791 m_applicationAdaptor->sendEvents(!evList.isEmpty());
793 qWarning() << "Could not query active accessibility event listeners.";
797 void AtSpiAdaptor::eventListenerDeregistered(const QString &/*bus*/, const QString &/*path*/)
799 // qDebug() << "AtSpiAdaptor::eventListenerDeregistered: " << bus << path;
800 updateEventListeners();
803 void AtSpiAdaptor::eventListenerRegistered(const QString &/*bus*/, const QString &/*path*/)
805 // qDebug() << "AtSpiAdaptor::eventListenerRegistered: " << bus << path;
806 updateEventListeners();
810 This slot needs to get called when a \a window has be activated or deactivated (become focused).
811 When \a active is true, the window just received focus, otherwise it lost the focus.
813 void AtSpiAdaptor::windowActivated(QObject* window, bool active)
815 if (!(sendWindow || sendWindow_activate))
818 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
819 Q_ASSERT(iface && iface->isValid());
821 QString windowTitle = iface->text(QAccessible::Name);
825 data.setVariant(windowTitle);
827 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
829 QString status = active ? QLatin1String("Activate") : QLatin1String("Deactivate");
830 QString path = pathForObject(window);
831 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW), status, args);
833 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("active"), active ? 1 : 0, 0, variantForPath(path));
834 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
835 QLatin1String("StateChanged"), stateArgs);
838 QVariantList AtSpiAdaptor::packDBusSignalArguments(const QString &type, int data1, int data2, const QVariant &variantData) const
840 QVariantList arguments;
841 arguments << type << data1 << data2 << variantData
842 << QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT)));
846 QVariant AtSpiAdaptor::variantForPath(const QString &path) const
849 data.setVariant(QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(path))));
850 return QVariant::fromValue(data);
853 bool AtSpiAdaptor::sendDBusSignal(const QString &path, const QString &interface, const QString &signalName, const QVariantList &arguments) const
855 QDBusMessage message = QDBusMessage::createSignal(path, interface, signalName);
856 message.setArguments(arguments);
857 return m_dbus->connection().send(message);
860 QAIPointer AtSpiAdaptor::interfaceFromPath(const QString& dbusPath) const
862 if (dbusPath == QLatin1String(QSPI_OBJECT_PATH_ROOT))
863 return QAIPointer(QAccessible::queryAccessibleInterface(qApp));
865 QStringList parts = dbusPath.split(QLatin1Char('/'));
866 if (parts.size() <= 5) {
867 qWarning() << "invalid path: " << dbusPath;
871 QString objectString = parts.at(5);
872 quintptr uintptr = objectString.toULongLong();
874 if (uintptr && m_handledObjects.contains(uintptr)) {
875 // We found the pointer, check if it's still valid:
876 if (m_handledObjects[uintptr]) {
877 QObject* object = reinterpret_cast<QObject*>(uintptr);
879 QAIPointer interface = QAIPointer(QAccessible::queryAccessibleInterface(object));
883 for (int i = 6; i < parts.size(); ++i) {
884 int childIndex = parts.at(i).toInt();
885 if (childIndex < 0) {
886 qWarning() << "Invalid child index";
889 QAIPointer childInterface(interface->child(childIndex));
891 interface = childInterface;
895 m_handledObjects.remove(uintptr);
903 This function gets called when Qt notifies about accessibility updates.
905 void AtSpiAdaptor::notify(QAccessibleEvent *event)
910 switch (event->type()) {
911 case QAccessible::ObjectCreated:
912 if (sendObject || sendObject_children_changed)
913 notifyAboutCreation(QAIPointer(event->accessibleInterface()));
915 case QAccessible::ObjectShow: {
916 if (sendObject || sendObject_state_changed) {
917 QString path = pathForInterface(QAIPointer(event->accessibleInterface()));
918 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("showing"), 1, 0, variantForPath(path));
919 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
920 QLatin1String("StateChanged"), stateArgs);
924 case QAccessible::ObjectHide: {
925 if (sendObject || sendObject_state_changed) {
926 QString path = pathForInterface(QAIPointer(event->accessibleInterface()));
927 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("showing"), 0, 0, variantForPath(path));
928 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
929 QLatin1String("StateChanged"), stateArgs);
933 case QAccessible::ObjectDestroyed: {
934 if (sendObject || sendObject_state_changed)
935 notifyAboutDestruction(QAIPointer(event->accessibleInterface()));
938 case QAccessible::NameChanged: {
939 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
940 QString path = pathForInterface(QAIPointer(event->accessibleInterface()));
941 QVariantList args = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
942 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
943 QLatin1String("PropertyChange"), args);
947 case QAccessible::DescriptionChanged: {
948 if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
949 QString path = pathForInterface(QAIPointer(event->accessibleInterface()));
950 QVariantList args = packDBusSignalArguments(QLatin1String("accessible-description"), 0, 0, variantForPath(path));
951 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
952 QLatin1String("PropertyChange"), args);
956 case QAccessible::Focus: {
957 if (sendFocus || sendObject || sendObject_state_changed)
958 sendFocusChanged(QAIPointer(event->accessibleInterface()));
961 case QAccessible::TextInserted:
962 case QAccessible::TextRemoved:
963 case QAccessible::TextUpdated: {
964 if (sendObject || sendObject_text_changed) {
965 QAIPointer iface = QAIPointer(event->accessibleInterface());
966 Q_ASSERT(iface->textInterface());
967 QString path = pathForInterface(iface);
969 int changePosition = 0;
970 int cursorPosition = 0;
972 QString textInserted;
974 if (event->type() == QAccessible::TextInserted) {
975 QAccessibleTextInsertEvent *textEvent = static_cast<QAccessibleTextInsertEvent*>(event);
976 textInserted = textEvent->textInserted();
977 changePosition = textEvent->changePosition();
978 cursorPosition = textEvent->cursorPosition();
979 } else if (event->type() == QAccessible::TextRemoved) {
980 QAccessibleTextRemoveEvent *textEvent = static_cast<QAccessibleTextRemoveEvent*>(event);
981 textRemoved = textEvent->textRemoved();
982 changePosition = textEvent->changePosition();
983 cursorPosition = textEvent->cursorPosition();
984 } else if (event->type() == QAccessible::TextInserted) {
985 QAccessibleTextUpdateEvent *textEvent = static_cast<QAccessibleTextUpdateEvent*>(event);
986 textInserted = textEvent->textInserted();
987 textRemoved = textEvent->textRemoved();
988 changePosition = textEvent->changePosition();
989 cursorPosition = textEvent->cursorPosition();
994 if (!textRemoved.isEmpty()) {
995 data.setVariant(QVariant::fromValue(textRemoved));
996 QVariantList args = packDBusSignalArguments(QLatin1String("delete"), changePosition, textRemoved.length(), QVariant::fromValue(data));
997 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
998 QLatin1String("TextChanged"), args);
1001 if (!textInserted.isEmpty()) {
1002 data.setVariant(QVariant::fromValue(textInserted));
1003 QVariantList args = packDBusSignalArguments(QLatin1String("insert"), changePosition, textInserted.length(), QVariant::fromValue(data));
1004 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1005 QLatin1String("TextChanged"), args);
1008 // send a cursor update
1009 Q_UNUSED(cursorPosition)
1010 // QDBusVariant cursorData;
1011 // cursorData.setVariant(QVariant::fromValue(cursorPosition));
1012 // QVariantList args = packDBusSignalArguments(QString(), cursorPosition, 0, QVariant::fromValue(cursorData));
1013 // sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1014 // QLatin1String("TextCaretMoved"), args);
1018 case QAccessible::TextCaretMoved: {
1019 if (sendObject || sendObject_text_caret_moved) {
1020 QAIPointer iface = QAIPointer(event->accessibleInterface());
1021 Q_ASSERT(iface->textInterface());
1022 QString path = pathForInterface(iface);
1023 QDBusVariant cursorData;
1024 int pos = iface->textInterface()->cursorPosition();
1025 cursorData.setVariant(QVariant::fromValue(pos));
1026 QVariantList args = packDBusSignalArguments(QString(), pos, 0, QVariant::fromValue(cursorData));
1027 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1028 QLatin1String("TextCaretMoved"), args);
1032 case QAccessible::TextSelectionChanged: {
1033 if (sendObject || sendObject_text_selection_changed) {
1034 QAIPointer iface = QAIPointer(event->accessibleInterface());
1035 QString path = pathForInterface(iface);
1036 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1037 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1038 QLatin1String("TextSelectionChanged"), args);
1042 case QAccessible::ValueChanged: {
1043 if (sendObject || sendObject_value_changed) {
1044 QAIPointer iface = QAIPointer(event->accessibleInterface());
1045 Q_ASSERT(iface->valueInterface());
1046 QString path = pathForInterface(iface);
1047 QVariantList args = packDBusSignalArguments(QLatin1String("accessible-value"), 0, 0, variantForPath(path));
1048 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1049 QLatin1String("PropertyChange"), args);
1053 case QAccessible::Selection: {
1054 QAIPointer iface = QAIPointer(event->accessibleInterface());
1055 QString path = pathForInterface(iface);
1056 int selected = iface->state().selected ? 1 : 0;
1057 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("selected"), selected, 0, variantForPath(path));
1058 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1059 QLatin1String("StateChanged"), stateArgs);
1063 case QAccessible::StateChanged: {
1064 if (sendObject || sendObject_state_changed || sendWindow || sendWindow_activate) {
1065 QAccessible::State stateChange = static_cast<QAccessibleStateChangeEvent*>(event)->changedStates();
1066 if (stateChange.checked) {
1067 QAIPointer iface = QAIPointer(event->accessibleInterface());
1068 int checked = iface->state().checked;
1069 QString path = pathForInterface(iface);
1070 QVariantList args = packDBusSignalArguments(QLatin1String("checked"), checked, 0, variantForPath(path));
1071 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1072 QLatin1String("StateChanged"), args);
1073 } else if (stateChange.active) {
1074 QAIPointer iface = QAIPointer(event->accessibleInterface());
1075 if (!(iface->role() == QAccessible::Window && (sendWindow || sendWindow_activate)))
1077 QString windowTitle = iface->text(QAccessible::Name);
1079 data.setVariant(windowTitle);
1080 QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
1082 QString status = iface->state().active ? QLatin1String("Activate") : QLatin1String("Deactivate");
1083 QString path = pathForInterface(iface);
1084 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW), status, args);
1086 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("active"), iface->state().active ? 1 : 0, 0, variantForPath(path));
1087 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1088 QLatin1String("StateChanged"), stateArgs);
1093 // case QAccessible::TableModelChanged: {
1094 // // This is rather evil. We don't send data and hope that at-spi fetches the right child.
1095 // // This hack fails when a row gets removed and a different one added in its place.
1096 // QDBusVariant data;
1097 // emit ChildrenChanged("add", 0, 0, data, spiBridge->getRootReference());
1100 // case QAccessible::TableModelChanged:
1101 // QAccessible2::TableModelChange change = interface->tableInterface()->modelChange();
1102 // // assume we should reset if everything is 0
1103 // if (change.firstColumn == 0 && change.firstRow == 0 && change.lastColumn == 0 && change.lastRow == 0) {
1104 // notifyAboutDestruction(accessible);
1105 // notifyAboutCreation(accessible);
1109 case QAccessible::ParentChanged:
1111 case QAccessible::DialogStart:
1113 case QAccessible::DialogEnd:
1115 case QAccessible::SelectionRemove:
1118 QAIPointer iface = QAIPointer(event->accessibleInterface());
1119 qWarning() << "QSpiAccessible::accessibleEvent not handled: " << QString::number(event->type(), 16)
1120 << " obj: " << iface->object()
1121 << ((iface->isValid() && iface->object()) ? iface->object()->objectName() : QLatin1String(" invalid interface!"));
1126 void AtSpiAdaptor::sendFocusChanged(const QAIPointer &interface) const
1128 static QString lastFocusPath;
1129 // "remove" old focus
1130 if (!lastFocusPath.isEmpty()) {
1131 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 0, 0, variantForPath(lastFocusPath));
1132 sendDBusSignal(lastFocusPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1133 QLatin1String("StateChanged"), stateArgs);
1137 QString path = pathForInterface(interface);
1139 QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 1, 0, variantForPath(path));
1140 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1141 QLatin1String("StateChanged"), stateArgs);
1143 QVariantList focusArgs = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1144 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_FOCUS),
1145 QLatin1String("Focus"), focusArgs);
1146 lastFocusPath = path;
1150 void AtSpiAdaptor::notifyAboutCreation(const QAIPointer &interface) const
1152 // // say hello to d-bus
1153 // cache->emitAddAccessible(accessible->getCacheItem());
1155 // notify about the new child of our parent
1156 QAIPointer parent(interface->parent());
1158 qWarning() << "AtSpiAdaptor::notifyAboutCreation: Could not find parent for " << interface->object();
1161 QString path = pathForInterface(interface);
1162 int childCount = parent->childCount();
1163 QString parentPath = pathForInterface(parent);
1164 QVariantList args = packDBusSignalArguments(QLatin1String("add"), childCount, 0, variantForPath(path));
1165 sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("ChildrenChanged"), args);
1168 void AtSpiAdaptor::notifyAboutDestruction(const QAIPointer &interface) const
1170 if (!interface->isValid())
1173 QAIPointer parent(interface->parent());
1175 qWarning() << "AtSpiAdaptor::notifyAboutDestruction: Could not find parent for " << interface->object();
1178 QString path = pathForInterface(interface);
1180 // this is in the destructor. we have no clue which child we used to be.
1182 int childIndex = -1;
1184 // childIndex = child;
1186 // childIndex = parent->indexOfChild(interface);
1189 QString parentPath = pathForInterface(parent, true);
1190 QVariantList args = packDBusSignalArguments(QLatin1String("remove"), childIndex, 0, variantForPath(path));
1191 sendDBusSignal(parentPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT), QLatin1String("ChildrenChanged"), args);
1195 Handle incoming DBus message.
1196 This function dispatches the dbus message to the right interface handler.
1198 bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnection &connection)
1200 // get accessible interface
1201 QAIPointer accessible = interfaceFromPath(message.path());
1203 qWarning() << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << message.path();
1207 QString interface = message.interface();
1208 QString function = message.member();
1210 // qDebug() << "AtSpiAdaptor::handleMessage: " << interface << function;
1212 if (function == QLatin1String("Introspect")) {
1213 //introspect(message.path());
1217 // handle properties like regular functions
1218 if (interface == QLatin1String("org.freedesktop.DBus.Properties")) {
1219 interface = message.arguments().at(0).toString();
1221 function = message.member() + message.arguments().at(1).toString();
1224 // switch interface to call
1225 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE))
1226 return accessibleInterface(accessible, function, message, connection);
1227 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION))
1228 return applicationInterface(accessible, function, message, connection);
1229 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT))
1230 return componentInterface(accessible, function, message, connection);
1231 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_ACTION))
1232 return actionInterface(accessible, function, message, connection);
1233 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_TEXT))
1234 return textInterface(accessible, function, message, connection);
1235 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT))
1236 return editableTextInterface(accessible, function, message, connection);
1237 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_VALUE))
1238 return valueInterface(accessible, function, message, connection);
1239 if (interface == QLatin1String(ATSPI_DBUS_INTERFACE_TABLE))
1240 return tableInterface(accessible, function, message, connection);
1242 qWarning() << "AtSpiAdaptor::handleMessage with unknown interface: " << message.path() << interface << function;
1247 bool AtSpiAdaptor::applicationInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1249 if (message.path() != QLatin1String(ATSPI_DBUS_PATH_ROOT)) {
1250 qWarning() << "WARNING Qt AtSpiAdaptor: Could not find application interface for: " << message.path() << interface;
1254 if (function == QLatin1String("SetId")) {
1255 Q_ASSERT(message.signature() == QLatin1String("ssv"));
1256 QVariant value = qvariant_cast<QDBusVariant>(message.arguments().at(2)).variant();
1258 m_applicationId = value.toInt();
1261 if (function == QLatin1String("GetId")) {
1262 Q_ASSERT(message.signature() == QLatin1String("ss"));
1263 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(m_applicationId)));
1264 return connection.send(reply);
1266 if (function == QLatin1String("GetToolkitName")) {
1267 Q_ASSERT(message.signature() == QLatin1String("ss"));
1268 QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QLatin1String("Qt"))));
1269 return connection.send(reply);
1272 qDebug() << "AtSpiAdaptor::applicationInterface " << message.path() << interface << function;
1277 Register this application as accessible on the accessibility DBus.
1279 void AtSpiAdaptor::registerApplication()
1281 OrgA11yAtspiSocketInterface *registry;
1282 registry = new OrgA11yAtspiSocketInterface(QLatin1String(QSPI_REGISTRY_NAME),
1283 QLatin1String(QSPI_OBJECT_PATH_ROOT), m_dbus->connection());
1285 QDBusPendingReply<QSpiObjectReference> reply;
1286 QSpiObjectReference ref = QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT));
1287 reply = registry->Embed(ref);
1288 reply.waitForFinished(); // TODO: make this async
1289 if (reply.isValid ()) {
1290 const QSpiObjectReference &socket = reply.value();
1291 accessibilityRegistry = QSpiObjectReference(socket);
1293 qWarning() << "Error in contacting registry";
1294 qWarning() << reply.error().name();
1295 qWarning() << reply.error().message();
1301 bool AtSpiAdaptor::accessibleInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1303 if (function == QLatin1String("GetRole")) {
1304 sendReply(connection, message, (uint) getRole(interface));
1305 } else if (function == QLatin1String("GetName")) {
1306 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Name))));
1307 } else if (function == QLatin1String("GetRoleName")) {
1308 sendReply(connection, message, qSpiRoleMapping[interface->role()].name());
1309 } else if (function == QLatin1String("GetLocalizedRoleName")) {
1310 sendReply(connection, message, QVariant::fromValue(qSpiRoleMapping[interface->role()].localizedName()));
1311 } else if (function == QLatin1String("GetChildCount")) {
1312 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->childCount())));
1313 } else if (function == QLatin1String("GetIndexInParent")) {
1314 int childIndex = -1;
1315 QAIPointer parent(interface->parent());
1317 childIndex = parent->indexOfChild(interface.data());
1319 qWarning() << "GetIndexInParent get invalid index: " << childIndex << interface;
1321 sendReply(connection, message, childIndex);
1322 } else if (function == QLatin1String("GetParent")) {
1324 QAIPointer parent(interface->parent());
1326 path = QLatin1String(ATSPI_DBUS_PATH_NULL);
1327 } else if (parent->role() == QAccessible::Application) {
1328 path = QLatin1String(ATSPI_DBUS_PATH_ROOT);
1330 path = pathForInterface(parent);
1332 // Parent is a property, so it needs to be wrapped inside an extra variant.
1333 sendReply(connection, message, QVariant::fromValue(
1334 QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path))))));
1335 } else if (function == QLatin1String("GetChildAtIndex")) {
1336 int index = message.arguments().first().toInt();
1338 sendReply(connection, message, QVariant::fromValue(
1339 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1341 QAIPointer childInterface = QAIPointer(interface->child(index));
1342 sendReply(connection, message, QVariant::fromValue(
1343 QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(childInterface)))));
1345 } else if (function == QLatin1String("GetInterfaces")) {
1346 sendReply(connection, message, accessibleInterfaces(interface));
1347 } else if (function == QLatin1String("GetDescription")) {
1348 sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Description))));
1349 } else if (function == QLatin1String("GetState")) {
1350 quint64 spiState = spiStatesFromQState(interface->state());
1351 if (interface->tableInterface()) {
1352 setSpiStateBit(&spiState, ATSPI_STATE_MANAGES_DESCENDANTS);
1354 // FIXME: figure out if this is a top level window and set its active state accordingly
1355 // if (interface->object() && interface->object()->isWidgetType()) {
1356 // QWidget *w = qobject_cast<QWidget*>(interface->object());
1357 // if (w->topLevelWidget() && w->isActiveWindow()) {
1358 // setSpiStateBit(&spiState, ATSPI_STATE_ACTIVE);
1361 QAccessible::Role role = interface->role();
1362 if (role == QAccessible::TreeItem ||
1363 role == QAccessible::ListItem) {
1364 /* Transient means libatspi2 will not cache items.
1365 This is important because when adding/removing an item
1366 the cache becomes outdated and we don't change the paths of
1367 items in lists/trees/tables. */
1368 setSpiStateBit(&spiState, ATSPI_STATE_TRANSIENT);
1370 sendReply(connection, message,
1371 QVariant::fromValue(spiStateSetFromSpiStates(spiState)));
1372 } else if (function == QLatin1String("GetAttributes")) {
1373 sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
1374 } else if (function == QLatin1String("GetRelationSet")) {
1375 sendReply(connection, message, QVariant::fromValue(relationSet(interface, connection)));
1376 } else if (function == QLatin1String("GetApplication")) {
1377 sendReply(connection, message, QVariant::fromValue(
1378 QSpiObjectReference(connection, QDBusObjectPath(QSPI_OBJECT_PATH_ROOT))));
1379 } else if (function == QLatin1String("GetChildren")) {
1380 QSpiObjectReferenceArray children;
1381 for (int i = 0; i < interface->childCount(); ++i) {
1382 QString childPath = pathForInterface(QAIPointer(interface->child(i)));
1383 QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
1386 connection.send(message.createReply(QVariant::fromValue(children)));
1388 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1394 AtspiRole AtSpiAdaptor::getRole(const QAIPointer &interface) const
1396 if ((interface->role() == QAccessible::EditableText) && interface->state().passwordEdit)
1397 return ATSPI_ROLE_PASSWORD_TEXT;
1398 return qSpiRoleMapping[interface->role()].spiRole();
1401 //#define ACCESSIBLE_CREATION_DEBUG
1403 QStringList AtSpiAdaptor::accessibleInterfaces(const QAIPointer &interface) const
1406 #ifdef ACCESSIBLE_CREATION_DEBUG
1407 qDebug() << "AtSpiAdaptor::accessibleInterfaces create: " << interface->object();
1409 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_ACCESSIBLE);
1411 if ( (!interface->rect().isEmpty()) ||
1412 (interface->object() && interface->object()->isWidgetType()) ||
1413 (interface->role() == QAccessible::ListItem) ||
1414 (interface->role() == QAccessible::Cell) ||
1415 (interface->role() == QAccessible::TreeItem) ||
1416 (interface->role() == QAccessible::Row) ||
1417 (interface->object() && interface->object()->inherits("QSGItem"))
1419 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_COMPONENT);
1421 #ifdef ACCESSIBLE_CREATION_DEBUG
1423 qDebug() << " IS NOT a component";
1427 if (interface->actionInterface())
1428 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_ACTION);
1430 if (interface->textInterface())
1431 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_TEXT);
1433 if (interface->editableTextInterface())
1434 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT);
1436 if (interface->valueInterface())
1437 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_VALUE);
1439 if (interface->tableInterface())
1440 ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_TABLE);
1445 QSpiRelationArray AtSpiAdaptor::relationSet(const QAIPointer &interface, const QDBusConnection &connection) const
1447 typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
1448 QVector<RelationPair> relationInterfaces;
1449 relationInterfaces = interface->relations();
1451 QSpiRelationArray relations;
1452 Q_FOREACH (const RelationPair &pair, relationInterfaces) {
1453 // FIXME: this loop seems a bit strange... "related" always have one item when we check.
1454 //And why is it a list, when it always have one item? And it seems to assume that the QAccessible::Relation enum maps directly to AtSpi
1455 QList<QSpiObjectReference> related;
1457 QDBusObjectPath path = QDBusObjectPath(pathForInterface(QAIPointer(pair.first)));
1458 related.append(QSpiObjectReference(connection, path));
1460 if (!related.isEmpty())
1461 relations.append(QSpiRelationArrayEntry(qAccessibleRelationToAtSpiRelation(pair.second), related));
1466 void AtSpiAdaptor::sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const
1468 QDBusMessage reply = message.createReply(argument);
1469 connection.send(reply);
1473 QString AtSpiAdaptor::pathForObject(QObject *object) const
1477 if (object == qApp) {
1478 return QLatin1String(QSPI_OBJECT_PATH_ROOT);
1481 if (qstrcmp(object->metaObject()->className(), "QAction") == 0) {
1482 qDebug() << "AtSpiAdaptor::pathForObject: warning: creating path with QAction as object.";
1484 quintptr uintptr = reinterpret_cast<quintptr>(object);
1485 if (!m_handledObjects.contains(uintptr))
1486 m_handledObjects[uintptr] = QPointer<QObject>(object);
1487 return QLatin1String(QSPI_OBJECT_PATH_PREFIX) + QString::number(uintptr);
1490 QString AtSpiAdaptor::pathForInterface(const QAIPointer &interface, bool inDestructor) const
1492 if (!interface || !interface->isValid())
1493 return QLatin1String(ATSPI_DBUS_PATH_NULL);
1494 if (interface->role() == QAccessible::Application)
1495 return QLatin1String(QSPI_OBJECT_PATH_ROOT);
1497 QAIPointer interfaceWithObject = interface;
1500 if (interface->role() == QAccessible::MenuItem && interface->object() &&
1501 inheritsQAction(interface->object())) {
1502 interfaceWithObject = QAIPointer(interface->parent());
1503 int childIndex = interfaceWithObject->indexOfChild(interface.data());
1504 path.append(QString::fromLatin1("/%1").arg(childIndex));
1507 while (!interfaceWithObject->object()) {
1508 QAIPointer parentInterface(interfaceWithObject->parent());
1510 Q_ASSERT(parentInterface->isValid());
1511 int index = parentInterface->indexOfChild(interfaceWithObject.data());
1513 qWarning() << "Object claims to have child that we cannot navigate to. FIX IT!" << parentInterface->object();
1514 return QLatin1String(ATSPI_DBUS_PATH_NULL);
1516 path.prepend(QLatin1Char('/') + QString::number(index));
1517 interfaceWithObject = parentInterface;
1519 quintptr uintptr = reinterpret_cast<quintptr>(interfaceWithObject->object());
1520 path.prepend(QLatin1String(QSPI_OBJECT_PATH_PREFIX) + QString::number(uintptr));
1522 if (!inDestructor && !m_handledObjects.contains(uintptr))
1523 m_handledObjects[uintptr] = QPointer<QObject>(interfaceWithObject->object());
1528 bool AtSpiAdaptor::inheritsQAction(QObject *object)
1530 const QMetaObject *mo = object->metaObject();
1532 const QLatin1String cn(mo->className());
1533 if (cn == QLatin1String("QAction"))
1535 mo = mo->superClass();
1541 static QAIPointer getWindow(QAIPointer interface)
1543 if (interface->role() == QAccessible::Window)
1546 QAIPointer parent(interface->parent());
1547 while (parent && parent->role() != QAccessible::Window)
1548 parent = QAIPointer(parent->parent());
1553 static QRect getRelativeRect(const QAIPointer &interface)
1558 cr = interface->rect();
1560 window = getWindow(interface);
1562 wr = window->rect();
1564 cr.setX(cr.x() - wr.x());
1565 cr.setY(cr.x() - wr.y());
1570 bool AtSpiAdaptor::componentInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1572 if (function == QLatin1String("Contains")) {
1574 int x = message.arguments().at(0).toInt();
1575 int y = message.arguments().at(1).toInt();
1576 uint coordType = message.arguments().at(2).toUInt();
1577 if (coordType == ATSPI_COORD_TYPE_SCREEN)
1578 ret = interface->rect().contains(x, y);
1580 ret = getRelativeRect(interface).contains(x, y);
1581 sendReply(connection, message, ret);
1582 } else if (function == QLatin1String("GetAccessibleAtPoint")) {
1583 int x = message.arguments().at(0).toInt();
1584 int y = message.arguments().at(1).toInt();
1585 uint coordType = message.arguments().at(2).toUInt();
1586 Q_UNUSED (coordType) // FIXME
1588 QAIPointer childInterface(interface->childAt(x, y));
1590 while (childInterface) {
1591 iface = childInterface;
1592 childInterface = QAIPointer(iface->childAt(x, y));
1595 QString path = pathForInterface(iface);
1596 sendReply(connection, message, QVariant::fromValue(
1597 QSpiObjectReference(connection, QDBusObjectPath(path))));
1599 sendReply(connection, message, QVariant::fromValue(
1600 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1602 } else if (function == QLatin1String("GetAlpha")) {
1603 sendReply(connection, message, (double) 1.0);
1604 } else if (function == QLatin1String("GetExtents")) {
1605 uint coordType = message.arguments().at(0).toUInt();
1606 sendReply(connection, message, QVariant::fromValue(getExtents(interface, coordType)));
1607 } else if (function == QLatin1String("GetLayer")) {
1608 sendReply(connection, message, QVariant::fromValue((uint)1));
1609 } else if (function == QLatin1String("GetMDIZOrder")) {
1610 sendReply(connection, message, QVariant::fromValue((short)0));
1611 } else if (function == QLatin1String("GetPosition")) {
1612 uint coordType = message.arguments().at(0).toUInt();
1614 if (coordType == ATSPI_COORD_TYPE_SCREEN)
1615 rect = interface->rect();
1617 rect = getRelativeRect(interface);
1619 pos << rect.x() << rect.y();
1620 connection.send(message.createReply(pos));
1621 } else if (function == QLatin1String("GetSize")) {
1622 QRect rect = interface->rect();
1624 size << rect.width() << rect.height();
1625 connection.send(message.createReply(size));
1626 } else if (function == QLatin1String("GrabFocus")) {
1627 // FIXME: implement focus grabbing
1628 // if (interface->object() && interface->object()->isWidgetType()) {
1629 // QWidget* w = static_cast<QWidget*>(interface->object());
1630 // w->setFocus(Qt::OtherFocusReason);
1631 // sendReply(connection, message, true);
1633 sendReply(connection, message, false);
1634 } else if (function == QLatin1String("SetExtents")) {
1635 // int x = message.arguments().at(0).toInt();
1636 // int y = message.arguments().at(1).toInt();
1637 // int width = message.arguments().at(2).toInt();
1638 // int height = message.arguments().at(3).toInt();
1639 // uint coordinateType = message.arguments().at(4).toUInt();
1640 qWarning() << "SetExtents is not implemented.";
1641 sendReply(connection, message, false);
1642 } else if (function == QLatin1String("SetPosition")) {
1643 // int x = message.arguments().at(0).toInt();
1644 // int y = message.arguments().at(1).toInt();
1645 // uint coordinateType = message.arguments().at(2).toUInt();
1646 qWarning() << "SetPosition is not implemented.";
1647 sendReply(connection, message, false);
1648 } else if (function == QLatin1String("SetSize")) {
1649 // int width = message.arguments().at(0).toInt();
1650 // int height = message.arguments().at(1).toInt();
1651 qWarning() << "SetSize is not implemented.";
1652 sendReply(connection, message, false);
1654 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1660 QRect AtSpiAdaptor::getExtents(const QAIPointer &interface, uint coordType)
1662 return (coordType == ATSPI_COORD_TYPE_SCREEN) ? interface->rect() : getRelativeRect(interface);
1666 bool AtSpiAdaptor::actionInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1668 QAccessibleActionInterface *actionIface = interface->actionInterface();
1672 if (function == QLatin1String("GetNActions")) {
1673 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(actionIface->actionNames().count()))));
1674 } else if (function == QLatin1String("DoAction")) {
1675 int index = message.arguments().at(0).toInt();
1676 if (index < 0 || index >= actionIface->actionNames().count())
1678 interface->actionInterface()->doAction(actionIface->actionNames().at(index));
1679 sendReply(connection, message, true);
1680 } else if (function == QLatin1String("GetActions")) {
1681 sendReply(connection, message, QVariant::fromValue(getActions(actionIface)));
1682 } else if (function == QLatin1String("GetName")) {
1683 int index = message.arguments().at(0).toInt();
1684 if (index < 0 || index >= actionIface->actionNames().count())
1686 sendReply(connection, message, actionIface->actionNames().at(index));
1687 } else if (function == QLatin1String("GetDescription")) {
1688 int index = message.arguments().at(0).toInt();
1689 if (index < 0 || index >= actionIface->actionNames().count())
1691 sendReply(connection, message, actionIface->localizedActionDescription(actionIface->actionNames().at(index)));
1692 } else if (function == QLatin1String("GetKeyBinding")) {
1693 int index = message.arguments().at(0).toInt();
1694 if (index < 0 || index >= actionIface->actionNames().count())
1696 QStringList keyBindings;
1697 keyBindings = actionIface->keyBindingsForAction(actionIface->actionNames().value(index));
1698 if (keyBindings.isEmpty()) {
1699 QString acc = interface->text(QAccessible::Accelerator);
1701 keyBindings.append(acc);
1703 if (keyBindings.length() > 0)
1704 sendReply(connection, message, keyBindings.join(QLatin1Char(';')));
1706 sendReply(connection, message, QString());
1708 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1714 QSpiActionArray AtSpiAdaptor::getActions(QAccessibleActionInterface *actionInterface) const
1716 QSpiActionArray actions;
1717 Q_FOREACH (const QString &actionName, actionInterface->actionNames()) {
1719 QStringList keyBindings;
1721 action.description = actionInterface->localizedActionDescription(actionName);
1723 keyBindings = actionInterface->keyBindingsForAction(actionName);
1725 if (keyBindings.length() > 0)
1726 action.keyBinding = keyBindings[0];
1728 action.keyBinding = QString();
1736 bool AtSpiAdaptor::textInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1738 if (!interface->textInterface())
1742 if (function == QLatin1String("GetCaretOffset")) {
1743 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->cursorPosition()))));
1744 } else if (function == QLatin1String("GetCharacterCount")) {
1745 sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->characterCount()))));
1748 } else if (function == QLatin1String("AddSelection")) {
1749 int startOffset = message.arguments().at(0).toInt();
1750 int endOffset = message.arguments().at(1).toInt();
1751 int lastSelection = interface->textInterface()->selectionCount();
1752 interface->textInterface()->setSelection(lastSelection, startOffset, endOffset);
1753 sendReply(connection, message, (interface->textInterface()->selectionCount() > lastSelection));
1754 } else if (function == QLatin1String("GetAttributeRun")) {
1755 int offset = message.arguments().at(0).toInt();
1756 bool includeDefaults = message.arguments().at(1).toBool();
1757 Q_UNUSED(includeDefaults)
1758 connection.send(message.createReply(getAttributes(interface, offset, includeDefaults)));
1759 } else if (function == QLatin1String("GetAttributeValue")) {
1760 int offset = message.arguments().at(0).toInt();
1761 QString attributeName = message.arguments().at(1).toString();
1762 connection.send(message.createReply(getAttributeValue(interface, offset, attributeName)));
1763 } else if (function == QLatin1String("GetAttributes")) {
1764 int offset = message.arguments().at(0).toInt();
1765 connection.send(message.createReply(getAttributes(interface, offset, true)));
1766 } else if (function == QLatin1String("GetBoundedRanges")) {
1767 int x = message.arguments().at(0).toInt();
1768 int y = message.arguments().at(1).toInt();
1769 int width = message.arguments().at(2).toInt();
1770 int height = message.arguments().at(3).toInt();
1771 uint coordType = message.arguments().at(4).toUInt();
1772 uint xClipType = message.arguments().at(5).toUInt();
1773 uint yClipType = message.arguments().at(6).toUInt();
1774 Q_UNUSED(x) Q_UNUSED (y) Q_UNUSED(width)
1775 Q_UNUSED(height) Q_UNUSED(coordType)
1776 Q_UNUSED(xClipType) Q_UNUSED(yClipType)
1777 qWarning("Not implemented: QSpiAdaptor::GetBoundedRanges");
1778 sendReply(connection, message, QVariant::fromValue(QSpiTextRangeList()));
1779 } else if (function == QLatin1String("GetCharacterAtOffset")) {
1780 int offset = message.arguments().at(0).toInt();
1783 QString result = interface->textInterface()->textAtOffset(offset, QAccessible2::CharBoundary, &start, &end);
1784 sendReply(connection, message, (int) *(qPrintable (result)));
1785 } else if (function == QLatin1String("GetCharacterExtents")) {
1786 int offset = message.arguments().at(0).toInt();
1787 int coordType = message.arguments().at(1).toUInt();
1788 connection.send(message.createReply(getCharacterExtents(interface, offset, coordType)));
1789 } else if (function == QLatin1String("GetDefaultAttributeSet") || function == QLatin1String("GetDefaultAttributes")) {
1790 // GetDefaultAttributes is deprecated in favour of GetDefaultAttributeSet.
1791 // Empty set seems reasonable. There is no default attribute set.
1792 sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
1793 } else if (function == QLatin1String("GetNSelections")) {
1794 sendReply(connection, message, interface->textInterface()->selectionCount());
1795 } else if (function == QLatin1String("GetOffsetAtPoint")) {
1796 qDebug() << message.signature();
1797 Q_ASSERT(!message.signature().isEmpty());
1798 QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt());
1799 uint coordType = message.arguments().at(2).toUInt();
1800 if (coordType == ATSPI_COORD_TYPE_WINDOW) {
1801 QWindow *win = interface->window();
1802 point -= QPoint(win->x(), win->y());
1804 int offset = interface->textInterface()->offsetAtPoint(point);
1805 sendReply(connection, message, offset);
1806 } else if (function == QLatin1String("GetRangeExtents")) {
1807 int startOffset = message.arguments().at(0).toInt();
1808 int endOffset = message.arguments().at(1).toInt();
1809 uint coordType = message.arguments().at(2).toUInt();
1810 connection.send(message.createReply(getRangeExtents(interface, startOffset, endOffset, coordType)));
1811 } else if (function == QLatin1String("GetSelection")) {
1812 int selectionNum = message.arguments().at(0).toInt();
1814 interface->textInterface()->selection(selectionNum, &start, &end);
1816 start = end = interface->textInterface()->cursorPosition();
1818 sel << start << end;
1819 connection.send(message.createReply(sel));
1820 } else if (function == QLatin1String("GetText")) {
1821 int startOffset = message.arguments().at(0).toInt();
1822 int endOffset = message.arguments().at(1).toInt();
1823 if (endOffset == -1) // AT-SPI uses -1 to signal all characters
1824 endOffset = interface->textInterface()->characterCount();
1825 sendReply(connection, message, interface->textInterface()->text(startOffset, endOffset));
1826 } else if (function == QLatin1String("GetTextAfterOffset")) {
1827 int offset = message.arguments().at(0).toInt();
1828 int type = message.arguments().at(1).toUInt();
1829 int startOffset, endOffset;
1830 QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1832 ret << text << startOffset << endOffset;
1833 connection.send(message.createReply(ret));
1834 } else if (function == QLatin1String("GetTextAtOffset")) {
1835 int offset = message.arguments().at(0).toInt();
1836 int type = message.arguments().at(1).toUInt();
1837 int startOffset, endOffset;
1838 QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1840 ret << text << startOffset << endOffset;
1841 connection.send(message.createReply(ret));
1842 } else if (function == QLatin1String("GetTextBeforeOffset")) {
1843 int offset = message.arguments().at(0).toInt();
1844 int type = message.arguments().at(1).toUInt();
1845 int startOffset, endOffset;
1846 QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1848 ret << text << startOffset << endOffset;
1849 connection.send(message.createReply(ret));
1850 } else if (function == QLatin1String("RemoveSelection")) {
1851 int selectionNum = message.arguments().at(0).toInt();
1852 interface->textInterface()->removeSelection(selectionNum);
1853 sendReply(connection, message, true);
1854 } else if (function == QLatin1String("SetCaretOffset")) {
1855 int offset = message.arguments().at(0).toInt();
1856 interface->textInterface()->setCursorPosition(offset);
1857 sendReply(connection, message, true);
1858 } else if (function == QLatin1String("SetSelection")) {
1859 int selectionNum = message.arguments().at(0).toInt();
1860 int startOffset = message.arguments().at(1).toInt();
1861 int endOffset = message.arguments().at(2).toInt();
1862 interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
1863 sendReply(connection, message, true);
1865 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1871 QAccessible2::BoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTextBoundaryType) const
1873 switch (atspiTextBoundaryType) {
1874 case ATSPI_TEXT_BOUNDARY_CHAR:
1875 return QAccessible2::CharBoundary;
1876 case ATSPI_TEXT_BOUNDARY_WORD_START:
1877 case ATSPI_TEXT_BOUNDARY_WORD_END:
1878 return QAccessible2::WordBoundary;
1879 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
1880 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
1881 return QAccessible2::SentenceBoundary;
1882 case ATSPI_TEXT_BOUNDARY_LINE_START:
1883 case ATSPI_TEXT_BOUNDARY_LINE_END:
1884 return QAccessible2::LineBoundary;
1886 Q_ASSERT_X(0, "", "Requested invalid boundary type.");
1887 return QAccessible2::CharBoundary;
1890 // FIXME all attribute methods below should share code
1891 QVariantList AtSpiAdaptor::getAttributes(const QAIPointer &interface, int offset, bool includeDefaults) const
1893 Q_UNUSED(includeDefaults);
1895 QSpiAttributeSet set;
1899 QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
1900 QStringList attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive);
1901 foreach (const QString &attr, attributes) {
1903 items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
1904 set[items[0]] = items[1];
1908 list << QVariant::fromValue(set) << startOffset << endOffset;
1913 QVariantList AtSpiAdaptor::getAttributeValue(const QAIPointer &interface, int offset, const QString &attributeName) const
1917 QStringList attributes;
1918 QSpiAttributeSet map;
1923 joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
1924 attributes = joined.split (QLatin1Char(';'), QString::SkipEmptyParts, Qt::CaseSensitive);
1925 foreach (const QString& attr, attributes) {
1927 items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
1928 map[items[0]] = items[1];
1930 mapped = map[attributeName];
1931 defined = mapped.isEmpty();
1933 list << mapped << startOffset << endOffset << defined;
1937 QRect AtSpiAdaptor::getCharacterExtents(const QAIPointer &interface, int offset, uint coordType) const
1939 QRect rect = interface->textInterface()->characterRect(offset);
1941 if (coordType == ATSPI_COORD_TYPE_WINDOW)
1942 rect = translateRectToWindowCoordinates(interface, rect);
1947 QRect AtSpiAdaptor::getRangeExtents(const QAIPointer &interface,
1948 int startOffset, int endOffset, uint coordType) const
1950 if (endOffset == -1)
1951 endOffset = interface->textInterface()->characterCount();
1953 QAccessibleTextInterface *textInterface = interface->textInterface();
1954 if (endOffset <= startOffset || !textInterface)
1957 QRect rect = textInterface->characterRect(startOffset);
1958 for (int i=startOffset + 1; i <= endOffset; i++)
1959 rect = rect | textInterface->characterRect(i);
1961 // relative to window
1962 if (coordType == ATSPI_COORD_TYPE_WINDOW)
1963 rect = translateRectToWindowCoordinates(interface, rect);
1968 QRect AtSpiAdaptor::translateRectToWindowCoordinates(const QAIPointer &interface, const QRect &rect)
1970 QAIPointer window = getWindow(interface);
1972 return rect.translated(-window->rect().x(), -window->rect().y());
1978 // Editable Text interface
1979 static QString textForRange(QAccessibleInterface *accessible, int startOffset, int endOffset)
1981 if (QAccessibleTextInterface *textIface = accessible->textInterface()) {
1982 if (endOffset == -1)
1983 endOffset = textIface->characterCount();
1984 return textIface->text(startOffset, endOffset);
1986 QString txt = accessible->text(QAccessible::Value);
1987 if (endOffset == -1)
1988 endOffset = txt.length();
1989 return txt.mid(startOffset, endOffset - startOffset);
1992 static void replaceTextFallback(QAccessibleInterface *accessible, long startOffset, long endOffset, const QString &txt)
1994 QString t = textForRange(accessible, 0, -1);
1995 if (endOffset == -1)
1996 endOffset = t.length();
1997 if (endOffset - startOffset == 0)
1998 t.insert(startOffset, txt);
2000 t.replace(startOffset, endOffset - startOffset, txt);
2001 accessible->setText(QAccessible::Value, t);
2004 bool AtSpiAdaptor::editableTextInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2006 if (function == QLatin1String("CopyText")) {
2007 #ifndef QT_NO_CLIPBOARD
2008 int startOffset = message.arguments().at(0).toInt();
2009 int endOffset = message.arguments().at(1).toInt();
2010 const QString t = textForRange(interface.data(), startOffset, endOffset);
2011 QGuiApplication::clipboard()->setText(t);
2013 connection.send(message.createReply(true));
2014 } else if (function == QLatin1String("CutText")) {
2015 #ifndef QT_NO_CLIPBOARD
2016 int startOffset = message.arguments().at(0).toInt();
2017 int endOffset = message.arguments().at(1).toInt();
2018 const QString t = textForRange(interface.data(), startOffset, endOffset);
2019 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2020 editableTextIface->deleteText(startOffset, endOffset);
2022 replaceTextFallback(interface.data(), startOffset, endOffset, QString());
2023 QGuiApplication::clipboard()->setText(t);
2025 connection.send(message.createReply(true));
2026 } else if (function == QLatin1String("DeleteText")) {
2027 int startOffset = message.arguments().at(0).toInt();
2028 int endOffset = message.arguments().at(1).toInt();
2029 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2030 editableTextIface->deleteText(startOffset, endOffset);
2032 replaceTextFallback(interface.data(), startOffset, endOffset, QString());
2033 connection.send(message.createReply(true));
2034 } else if (function == QLatin1String("InsertText")) {
2035 int position = message.arguments().at(0).toInt();
2036 QString text = message.arguments().at(1).toString();
2037 int length = message.arguments().at(2).toInt();
2038 text.resize(length);
2039 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2040 editableTextIface->insertText(position, text);
2042 replaceTextFallback(interface.data(), position, position, text);
2043 connection.send(message.createReply(true));
2044 } else if (function == QLatin1String("PasteText")) {
2045 #ifndef QT_NO_CLIPBOARD
2046 int position = message.arguments().at(0).toInt();
2047 const QString txt = QGuiApplication::clipboard()->text();
2048 if (QAccessibleEditableTextInterface *editableTextIface = interface->editableTextInterface())
2049 editableTextIface->insertText(position, txt);
2051 replaceTextFallback(interface.data(), position, position, txt);
2053 connection.send(message.createReply(true));
2054 } else if (function == QLatin1String("SetTextContents")) {
2055 QString newContents = message.arguments().at(0).toString();
2056 interface->editableTextInterface()->replaceText(0, interface->textInterface()->characterCount(), newContents);
2057 connection.send(message.createReply(true));
2058 } else if (function == QLatin1String("")) {
2059 connection.send(message.createReply());
2061 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
2068 bool AtSpiAdaptor::valueInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2071 } else if (function == QLatin1String("SetCurrentValue")) {
2072 QDBusVariant v = message.arguments().at(2).value<QDBusVariant>();
2073 double value = v.variant().toDouble();
2075 //See https://bugzilla.gnome.org/show_bug.cgi?id=652596
2076 interface->valueInterface()->setCurrentValue(value);
2077 connection.send(message.createReply()); // FIXME is the reply needed?
2078 } else if (function == QLatin1String("GetCurrentValue")) {
2080 double val = interface->valueInterface()->currentValue().toDouble(&success);
2082 qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2083 connection.send(message.createReply(
2084 QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2085 } else if (function == QLatin1String("GetMaximumValue")) {
2087 double val = interface->valueInterface()->maximumValue().toDouble(&success);
2089 qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2090 connection.send(message.createReply(
2091 QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2092 } else if (function == QLatin1String("GetMinimumIncrement")) {
2093 connection.send(message.createReply(
2094 QVariant::fromValue(QDBusVariant(QVariant::fromValue(0.0)))));
2095 } else if (function == QLatin1String("GetMinimumValue")) {
2097 double val = interface->valueInterface()->minimumValue().toDouble(&success);
2099 qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2100 connection.send(message.createReply(
2101 QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2103 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
2110 bool AtSpiAdaptor::tableInterface(const QAIPointer &interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2112 if (!(interface->tableInterface() || interface->tableCellInterface())) {
2113 qWarning() << "WARNING Qt AtSpiAdaptor: Could not find table interface for: " << message.path() << interface;
2119 } else if (function == QLatin1String("GetCaption")) {
2120 QAIPointer captionInterface= QAIPointer(interface->tableInterface()->caption());
2121 if (captionInterface) {
2122 QSpiObjectReference ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(captionInterface)));
2123 sendReply(connection, message, QVariant::fromValue(ref));
2125 sendReply(connection, message, QVariant::fromValue(
2126 QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
2128 } else if (function == QLatin1String("GetNColumns")) {
2129 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2130 QVariant::fromValue(interface->tableInterface()->columnCount())))));
2131 } else if (function == QLatin1String("GetNRows")) {
2132 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2133 QVariant::fromValue(interface->tableInterface()->rowCount())))));
2134 } else if (function == QLatin1String("GetNSelectedColumns")) {
2135 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2136 QVariant::fromValue(interface->tableInterface()->selectedColumnCount())))));
2137 } else if (function == QLatin1String("GetNSelectedRows")) {
2138 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2139 QVariant::fromValue(interface->tableInterface()->selectedRowCount())))));
2140 } else if (function == QLatin1String("GetSummary")) {
2141 QAIPointer summary = interface->tableInterface() ? QAIPointer(interface->tableInterface()->summary()) : QAIPointer(0);
2142 QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(summary)));
2143 connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
2144 } else if (function == QLatin1String("GetAccessibleAt")) {
2145 int row = message.arguments().at(0).toInt();
2146 int column = message.arguments().at(1).toInt();
2147 Q_ASSERT(interface->tableInterface());
2149 Q_ASSERT(column >= 0);
2150 Q_ASSERT(row < interface->tableInterface()->rowCount());
2151 Q_ASSERT(column < interface->tableInterface()->columnCount());
2153 QSpiObjectReference ref;
2154 QAIPointer cell(interface->tableInterface()->cellAt(row, column));
2156 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell)));
2158 qWarning() << "WARNING: no cell interface returned for " << interface->object() << row << column;
2159 ref = QSpiObjectReference();
2161 connection.send(message.createReply(QVariant::fromValue(ref)));
2163 } else if (function == QLatin1String("GetIndexAt")) {
2164 int row = message.arguments().at(0).toInt();
2165 int column = message.arguments().at(1).toInt();
2166 QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column);
2168 qWarning() << "WARNING: AtSpiAdaptor::GetIndexAt(" << row << "," << column << ") did not find a cell. " << interface;
2171 int index = interface->indexOfChild(cell);
2172 qDebug() << "QSpiAdaptor::GetIndexAt row:" << row << " col:" << column << " logical index:" << index;
2173 Q_ASSERT(index > 0);
2175 connection.send(message.createReply(index));
2176 } else if ((function == QLatin1String("GetColumnAtIndex")) || (function == QLatin1String("GetRowAtIndex"))) {
2177 int index = message.arguments().at(0).toInt();
2180 QAIPointer cell = QAIPointer(interface->child(index));
2182 if (function == QLatin1String("GetColumnAtIndex")) {
2183 if (cell->role() == QAccessible::ColumnHeader) {
2185 } else if (cell->role() == QAccessible::RowHeader) {
2188 if (!cell->tableCellInterface()) {
2189 qWarning() << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell;
2192 ret = cell->tableCellInterface()->columnIndex();
2195 if (cell->role() == QAccessible::ColumnHeader) {
2197 } else if (cell->role() == QAccessible::RowHeader) {
2198 ret = index % interface->tableInterface()->columnCount();
2200 if (!cell->tableCellInterface()) {
2201 qWarning() << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell;
2204 ret = cell->tableCellInterface()->rowIndex();
2208 qWarning() << "WARNING: AtSpiAdaptor::" << function << " No cell at index: " << index << interface;
2212 connection.send(message.createReply(ret));
2214 } else if (function == QLatin1String("GetColumnDescription")) {
2215 int column = message.arguments().at(0).toInt();
2216 connection.send(message.createReply(interface->tableInterface()->columnDescription(column)));
2217 } else if (function == QLatin1String("GetRowDescription")) {
2218 int row = message.arguments().at(0).toInt();
2219 connection.send(message.createReply(interface->tableInterface()->rowDescription(row)));
2223 } else if (function == QLatin1String("GetRowColumnExtentsAtIndex")) {
2224 int index = message.arguments().at(0).toInt();
2225 bool success = false;
2227 int row, col, rowExtents, colExtents;
2230 int cols = interface->tableInterface()->columnCount();
2233 QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, col)->tableCellInterface();
2235 cell->rowColumnExtents(&row, &col, &rowExtents, &colExtents, &isSelected);
2241 list << success << row << col << rowExtents << colExtents << isSelected;
2242 connection.send(message.createReply(list));
2244 } else if (function == QLatin1String("GetColumnExtentAt")) {
2245 int row = message.arguments().at(0).toInt();
2246 int column = message.arguments().at(1).toInt();
2247 connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->columnExtent()));
2249 } else if (function == QLatin1String("GetRowExtentAt")) {
2250 int row = message.arguments().at(0).toInt();
2251 int column = message.arguments().at(1).toInt();
2252 connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->rowExtent()));
2254 } else if (function == QLatin1String("GetColumnHeader")) {
2255 int column = message.arguments().at(0).toInt();
2256 QSpiObjectReference ref;
2258 QAIPointer cell(interface->tableInterface()->cellAt(0, column));
2259 if (cell && cell->tableCellInterface()) {
2260 QList<QAccessibleInterface*> header = cell->tableCellInterface()->columnHeaderCells();
2261 if (header.size() > 0) {
2262 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(QAIPointer(header.takeAt(0)))));
2266 connection.send(message.createReply(QVariant::fromValue(ref)));
2268 } else if (function == QLatin1String("GetRowHeader")) {
2269 int row = message.arguments().at(0).toInt();
2270 QSpiObjectReference ref;
2271 QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, 0)->tableCellInterface();
2273 QList<QAccessibleInterface*> header = cell->rowHeaderCells();
2275 if (header.size() > 0) {
2276 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(QAIPointer(header.takeAt(0)))));
2280 connection.send(message.createReply(QVariant::fromValue(ref)));
2282 } else if (function == QLatin1String("GetSelectedColumns")) {
2283 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedColumns())));
2284 } else if (function == QLatin1String("GetSelectedRows")) {
2285 connection.send(message.createReply(QVariant::fromValue(interface->tableInterface()->selectedRows())));
2286 } else if (function == QLatin1String("IsColumnSelected")) {
2287 int column = message.arguments().at(0).toInt();
2288 connection.send(message.createReply(interface->tableInterface()->isColumnSelected(column)));
2289 } else if (function == QLatin1String("IsRowSelected")) {
2290 int row = message.arguments().at(0).toInt();
2291 connection.send(message.createReply(interface->tableInterface()->isRowSelected(row)));
2292 } else if (function == QLatin1String("IsSelected")) {
2293 int row = message.arguments().at(0).toInt();
2294 int column = message.arguments().at(1).toInt();
2295 QAccessibleTableCellInterface* cell = interface->tableInterface()->cellAt(row, column)->tableCellInterface();
2296 connection.send(message.createReply(cell->isSelected()));
2298 } else if (function == QLatin1String("AddColumnSelection")) {
2299 int column = message.arguments().at(0).toInt();
2300 connection.send(message.createReply(interface->tableInterface()->selectColumn(column)));
2301 } else if (function == QLatin1String("AddRowSelection")) {
2302 int row = message.arguments().at(0).toInt();
2303 connection.send(message.createReply(interface->tableInterface()->selectRow(row)));
2304 } else if (function == QLatin1String("RemoveColumnSelection")) {
2305 int column = message.arguments().at(0).toInt();
2306 connection.send(message.createReply(interface->tableInterface()->unselectColumn(column)));
2307 } else if (function == QLatin1String("RemoveRowSelection")) {
2308 int row = message.arguments().at(0).toInt();
2309 connection.send(message.createReply(interface->tableInterface()->unselectRow(row)));
2311 qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();