Add debug output for keyboard events.
[qt-at-spi:qt-at-spi.git] / src / atspiadaptor.cpp
1 /*
2  * Copyright 2011 Nokia Corporation and/or its subsidiary(-ies).
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18
19 #include "atspiadaptor.h"
20
21 #include <qaccessible.h>
22 #include <qaccessible2.h>
23 #include <qapplication.h>
24 #include <qdbusmessage.h>
25 #include <qdbusreply.h>
26 #include <qwidget.h>
27
28 #include <qdebug.h>
29
30 #include "generated/socket_proxy.h"
31
32 #include "standardactionwrapper.h"
33 #include "constant_mappings.h"
34
35 #include "application.h"
36
37 #define ACCESSIBLE_LAST_TEXT "QIA2_LAST_TEXT"
38 #define ACCESSIBLE_LAST_STATE "QIA2_LAST_STATE"
39
40 /*!
41     \class AtSpiAdaptor
42
43     \brief AtSpiAdaptor is the main class to forward between QAccessibleInterface and AT-SPI DBus
44
45     AtSpiAdaptor implements the functions specified in all at-spi interfaces.
46     It sends notifications comming from Qt via dbus and listens to incoming dbus requests.
47 */
48
49 AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
50     : QDBusVirtualObject(parent), m_dbus(connection), initialized(false)
51     , sendFocus(0)
52     , sendObject(0)
53     , sendObject_active_descendant_changed(0)
54     , sendObject_attributes_changed(0)
55     , sendObject_bounds_changed(0)
56     , sendObject_children_changed(0)
57 //    , sendObject_children_changed_add(0)
58 //    , sendObject_children_changed_remove(0)
59     , sendObject_column_deleted(0)
60     , sendObject_column_inserted(0)
61     , sendObject_column_reordered(0)
62     , sendObject_link_selected(0)
63     , sendObject_model_changed(0)
64     , sendObject_property_change(0)
65     , sendObject_property_change_accessible_description(0)
66     , sendObject_property_change_accessible_name(0)
67     , sendObject_property_change_accessible_parent(0)
68     , sendObject_property_change_accessible_role(0)
69     , sendObject_property_change_accessible_table_caption(0)
70     , sendObject_property_change_accessible_table_column_description(0)
71     , sendObject_property_change_accessible_table_column_header(0)
72     , sendObject_property_change_accessible_table_row_description(0)
73     , sendObject_property_change_accessible_table_row_header(0)
74     , sendObject_property_change_accessible_table_summary(0)
75     , sendObject_property_change_accessible_value(0)
76     , sendObject_row_deleted(0)
77     , sendObject_row_inserted(0)
78     , sendObject_row_reordered(0)
79     , sendObject_selection_changed(0)
80     , sendObject_text_attributes_changed(0)
81     , sendObject_text_bounds_changed(0)
82     , sendObject_text_caret_moved(0)
83     , sendObject_text_changed(0)
84 //    , sendObject_text_changed_delete(0)
85 //    , sendObject_text_changed_insert(0)
86     , sendObject_text_selection_changed(0)
87     , sendObject_value_changed(0)
88     , sendObject_visible_data_changed(0)
89     , sendWindow(0)
90     , sendWindow_activate(0)
91     , sendWindow_close(0)
92     , sendWindow_create(0)
93     , sendWindow_deactivate(0)
94 //    , sendWindow_desktop_create(0)
95 //    , sendWindow_desktop_destroy(0)
96     , sendWindow_lower(0)
97     , sendWindow_maximize(0)
98     , sendWindow_minimize(0)
99     , sendWindow_move(0)
100     , sendWindow_raise(0)
101     , sendWindow_reparent(0)
102     , sendWindow_resize(0)
103     , sendWindow_restore(0)
104     , sendWindow_restyle(0)
105     , sendWindow_shade(0)
106     , sendWindow_unshade(0)
107 {
108     m_applicationAdaptor = new QSpiApplicationAdaptor(m_dbus->connection(), this);
109     connect(m_applicationAdaptor, SIGNAL(windowActivated(QObject*,bool)), this, SLOT(windowActivated(QObject*,bool)));
110 }
111
112 AtSpiAdaptor::~AtSpiAdaptor()
113 {
114 }
115
116 /*!
117   Provide DBus introspection.
118   */
119 QString AtSpiAdaptor::introspect(const QString &path) const
120 {
121     QLatin1String accessibleIntrospection(
122                 "  <interface name=\"org.a11y.atspi.Accessible\">\n"
123                 "    <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
124                 "    <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
125                 "    <property access=\"read\" type=\"(so)\" name=\"Parent\">\n"
126                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName\"/>\n"
127                 "    </property>\n"
128                 "    <property access=\"read\" type=\"i\" name=\"ChildCount\"/>\n"
129                 "    <method name=\"GetChildAtIndex\">\n"
130                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
131                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
132                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
133                 "    </method>\n"
134                 "    <method name=\"GetChildren\">\n"
135                 "      <arg direction=\"out\" type=\"a(so)\"/>\n"
136                 "      <annotation value=\"QSpiObjectReferenceArray\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
137                 "    </method>\n"
138                 "    <method name=\"GetIndexInParent\">\n"
139                 "      <arg direction=\"out\" type=\"i\"/>\n"
140                 "    </method>\n"
141                 "    <method name=\"GetRelationSet\">\n"
142                 "      <arg direction=\"out\" type=\"a(ua(so))\"/>\n"
143                 "      <annotation value=\"QSpiRelationArray\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
144                 "    </method>\n"
145                 "    <method name=\"GetRole\">\n"
146                 "      <arg direction=\"out\" type=\"u\"/>\n"
147                 "    </method>\n"
148                 "    <method name=\"GetRoleName\">\n"
149                 "      <arg direction=\"out\" type=\"s\"/>\n"
150                 "    </method>\n"
151                 "    <method name=\"GetLocalizedRoleName\">\n"
152                 "      <arg direction=\"out\" type=\"s\"/>\n"
153                 "    </method>\n"
154                 "    <method name=\"GetState\">\n"
155                 "      <arg direction=\"out\" type=\"au\"/>\n"
156                 "      <annotation value=\"QSpiUIntList\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
157                 "    </method>\n"
158                 "    <method name=\"GetAttributes\">\n"
159                 "      <arg direction=\"out\" type=\"a{ss}\"/>\n"
160                 "      <annotation value=\"QSpiAttributeSet\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
161                 "    </method>\n"
162                 "    <method name=\"GetApplication\">\n"
163                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
164                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
165                 "    </method>\n"
166                 "  </interface>\n"
167                 );
168
169     QLatin1String actionIntrospection(
170                 "  <interface name=\"org.a11y.atspi.Action\">\n"
171                 "    <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
172                 "    <method name=\"GetDescription\">\n"
173                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
174                 "      <arg direction=\"out\" type=\"s\"/>\n"
175                 "    </method>\n"
176                 "    <method name=\"GetName\">\n"
177                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
178                 "      <arg direction=\"out\" type=\"s\"/>\n"
179                 "    </method>\n"
180                 "    <method name=\"GetKeyBinding\">\n"
181                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
182                 "      <arg direction=\"out\" type=\"s\"/>\n"
183                 "    </method>\n"
184                 "    <method name=\"GetActions\">\n"
185                 "      <arg direction=\"out\" type=\"a(sss)\" name=\"index\"/>\n"
186                 "      <annotation value=\"QSpiActionArray\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
187                 "    </method>\n"
188                 "    <method name=\"DoAction\">\n"
189                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
190                 "      <arg direction=\"out\" type=\"b\"/>\n"
191                 "    </method>\n"
192                 "  </interface>\n"
193                 );
194
195     QLatin1String applicationIntrospection(
196                 "  <interface name=\"org.a11y.atspi.Application\">\n"
197                 "    <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
198                 "    <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
199                 "    <property access=\"readwrite\" type=\"i\" name=\"Id\"/>\n"
200                 "    <method name=\"GetLocale\">\n"
201                 "      <arg direction=\"in\" type=\"u\" name=\"lctype\"/>\n"
202                 "      <arg direction=\"out\" type=\"s\"/>\n"
203                 "    </method>\n"
204                 "    <method name=\"GetApplicationBusAddress\">\n"
205                 "      <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
206                 "    </method>\n"
207                 "    <!--\n"
208                 "  <method name=\"RegisterEventListener\">\n"
209                 "    <arg direction=\"in\" name=\"event\" type=\"s\"/>\n"
210                 "  </method>\n"
211                 "\n"
212                 "  <method name=\"DeregisterEventListener\">\n"
213                 "    <arg direction=\"in\" name=\"event\" type=\"s\"/>\n"
214                 "  </method>\n"
215                 "-->\n"
216                 "  </interface>\n"
217                 );
218
219     QLatin1String componentIntrospection(
220                 "  <interface name=\"org.a11y.atspi.Component\">\n"
221                 "    <method name=\"Contains\">\n"
222                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
223                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
224                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
225                 "      <arg direction=\"out\" type=\"b\"/>\n"
226                 "    </method>\n"
227                 "    <method name=\"GetAccessibleAtPoint\">\n"
228                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
229                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
230                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
231                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
232                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
233                 "    </method>\n"
234                 "    <method name=\"GetExtents\">\n"
235                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
236                 "      <arg direction=\"out\" type=\"(iiii)\"/>\n"
237                 "      <annotation value=\"QSpiRect\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
238                 "    </method>\n"
239                 "    <method name=\"GetPosition\">\n"
240                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
241                 "      <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
242                 "      <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
243                 "    </method>\n"
244                 "    <method name=\"GetSize\">\n"
245                 "      <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
246                 "      <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
247                 "    </method>\n"
248                 "    <method name=\"GetLayer\">\n"
249                 "      <arg direction=\"out\" type=\"u\"/>\n"
250                 "    </method>\n"
251                 "    <method name=\"GetMDIZOrder\">\n"
252                 "      <arg direction=\"out\" type=\"n\"/>\n"
253                 "    </method>\n"
254                 "    <method name=\"GrabFocus\">\n"
255                 "      <arg direction=\"out\" type=\"b\"/>\n"
256                 "    </method>\n"
257                 "    <method name=\"GetAlpha\">\n"
258                 "      <arg direction=\"out\" type=\"d\"/>\n"
259                 "    </method>\n"
260                 "    <method name=\"SetExtents\">\n"
261                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
262                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
263                 "      <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
264                 "      <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
265                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
266                 "      <arg direction=\"out\" type=\"b\"/>\n"
267                 "    </method>\n"
268                 "    <method name=\"SetPosition\">\n"
269                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
270                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
271                 "      <arg direction=\"in\" type=\"u\" name=\"coord_type\"/>\n"
272                 "      <arg direction=\"out\" type=\"b\"/>\n"
273                 "    </method>\n"
274                 "    <method name=\"SetSize\">\n"
275                 "      <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
276                 "      <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
277                 "      <arg direction=\"out\" type=\"b\"/>\n"
278                 "    </method>\n"
279                 "  </interface>\n"
280                 );
281
282     QLatin1String editableTextIntrospection(
283                 "  <interface name=\"org.a11y.atspi.EditableText\">\n"
284                 "    <method name=\"SetTextContents\">\n"
285                 "      <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
286                 "      <arg direction=\"out\" type=\"b\"/>\n"
287                 "    </method>\n"
288                 "    <method name=\"InsertText\">\n"
289                 "      <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
290                 "      <arg direction=\"in\" type=\"s\" name=\"text\"/>\n"
291                 "      <arg direction=\"in\" type=\"i\" name=\"length\"/>\n"
292                 "      <arg direction=\"out\" type=\"b\"/>\n"
293                 "    </method>\n"
294                 "    <method name=\"CopyText\">\n"
295                 "      <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
296                 "      <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
297                 "    </method>\n"
298                 "    <method name=\"CutText\">\n"
299                 "      <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
300                 "      <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
301                 "      <arg direction=\"out\" type=\"b\"/>\n"
302                 "    </method>\n"
303                 "    <method name=\"DeleteText\">\n"
304                 "      <arg direction=\"in\" type=\"i\" name=\"startPos\"/>\n"
305                 "      <arg direction=\"in\" type=\"i\" name=\"endPos\"/>\n"
306                 "      <arg direction=\"out\" type=\"b\"/>\n"
307                 "    </method>\n"
308                 "    <method name=\"PasteText\">\n"
309                 "      <arg direction=\"in\" type=\"i\" name=\"position\"/>\n"
310                 "      <arg direction=\"out\" type=\"b\"/>\n"
311                 "    </method>\n"
312                 "  </interface>\n"
313                 );
314
315     QLatin1String tableIntrospection(
316                 "  <interface name=\"org.a11y.atspi.Table\">\n"
317                 "    <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
318                 "    <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
319                 "    <property access=\"read\" type=\"(so)\" name=\"Caption\">\n"
320                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName\"/>\n"
321                 "    </property>\n"
322                 "    <property access=\"read\" type=\"(so)\" name=\"Summary\">\n"
323                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName\"/>\n"
324                 "    </property>\n"
325                 "    <property access=\"read\" type=\"i\" name=\"NSelectedRows\"/>\n"
326                 "    <property access=\"read\" type=\"i\" name=\"NSelectedColumns\"/>\n"
327                 "    <method name=\"GetAccessibleAt\">\n"
328                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
329                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
330                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
331                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
332                 "    </method>\n"
333                 "    <method name=\"GetIndexAt\">\n"
334                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
335                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
336                 "      <arg direction=\"out\" type=\"i\"/>\n"
337                 "    </method>\n"
338                 "    <method name=\"GetRowAtIndex\">\n"
339                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
340                 "      <arg direction=\"out\" type=\"i\"/>\n"
341                 "    </method>\n"
342                 "    <method name=\"GetColumnAtIndex\">\n"
343                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
344                 "      <arg direction=\"out\" type=\"i\"/>\n"
345                 "    </method>\n"
346                 "    <method name=\"GetRowDescription\">\n"
347                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
348                 "      <arg direction=\"out\" type=\"s\"/>\n"
349                 "    </method>\n"
350                 "    <method name=\"GetColumnDescription\">\n"
351                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
352                 "      <arg direction=\"out\" type=\"s\"/>\n"
353                 "    </method>\n"
354                 "    <method name=\"GetRowExtentAt\">\n"
355                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
356                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
357                 "      <arg direction=\"out\" type=\"i\"/>\n"
358                 "    </method>\n"
359                 "    <method name=\"GetColumnExtentAt\">\n"
360                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
361                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
362                 "      <arg direction=\"out\" type=\"i\"/>\n"
363                 "    </method>\n"
364                 "    <method name=\"GetRowHeader\">\n"
365                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
366                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
367                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
368                 "    </method>\n"
369                 "    <method name=\"GetColumnHeader\">\n"
370                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
371                 "      <arg direction=\"out\" type=\"(so)\"/>\n"
372                 "      <annotation value=\"QSpiObjectReference\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
373                 "    </method>\n"
374                 "    <method name=\"GetSelectedRows\">\n"
375                 "      <arg direction=\"out\" type=\"ai\"/>\n"
376                 "      <annotation value=\"QSpiIntList\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
377                 "    </method>\n"
378                 "    <method name=\"GetSelectedColumns\">\n"
379                 "      <arg direction=\"out\" type=\"ai\"/>\n"
380                 "      <annotation value=\"QSpiIntList\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
381                 "    </method>\n"
382                 "    <method name=\"IsRowSelected\">\n"
383                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
384                 "      <arg direction=\"out\" type=\"b\"/>\n"
385                 "    </method>\n"
386                 "    <method name=\"IsColumnSelected\">\n"
387                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
388                 "      <arg direction=\"out\" type=\"b\"/>\n"
389                 "    </method>\n"
390                 "    <method name=\"IsSelected\">\n"
391                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
392                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
393                 "      <arg direction=\"out\" type=\"b\"/>\n"
394                 "    </method>\n"
395                 "    <method name=\"AddRowSelection\">\n"
396                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
397                 "      <arg direction=\"out\" type=\"b\"/>\n"
398                 "    </method>\n"
399                 "    <method name=\"AddColumnSelection\">\n"
400                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
401                 "      <arg direction=\"out\" type=\"b\"/>\n"
402                 "    </method>\n"
403                 "    <method name=\"RemoveRowSelection\">\n"
404                 "      <arg direction=\"in\" type=\"i\" name=\"row\"/>\n"
405                 "      <arg direction=\"out\" type=\"b\"/>\n"
406                 "    </method>\n"
407                 "    <method name=\"RemoveColumnSelection\">\n"
408                 "      <arg direction=\"in\" type=\"i\" name=\"column\"/>\n"
409                 "      <arg direction=\"out\" type=\"b\"/>\n"
410                 "    </method>\n"
411                 "    <method name=\"GetRowColumnExtentsAtIndex\">\n"
412                 "      <arg direction=\"in\" type=\"i\" name=\"index\"/>\n"
413                 "      <arg direction=\"out\" type=\"b\"/>\n"
414                 "      <arg direction=\"out\" type=\"i\" name=\"row\"/>\n"
415                 "      <arg direction=\"out\" type=\"i\" name=\"col\"/>\n"
416                 "      <arg direction=\"out\" type=\"i\" name=\"row_extents\"/>\n"
417                 "      <arg direction=\"out\" type=\"i\" name=\"col_extents\"/>\n"
418                 "      <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
419                 "    </method>\n"
420                 "  </interface>\n"
421                 );
422
423     QLatin1String textIntrospection(
424                 "  <interface name=\"org.a11y.atspi.Text\">\n"
425                 "    <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
426                 "    <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
427                 "    <method name=\"GetText\">\n"
428                 "      <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
429                 "      <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
430                 "      <arg direction=\"out\" type=\"s\"/>\n"
431                 "    </method>\n"
432                 "    <method name=\"SetCaretOffset\">\n"
433                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
434                 "      <arg direction=\"out\" type=\"b\"/>\n"
435                 "    </method>\n"
436                 "    <method name=\"GetTextBeforeOffset\">\n"
437                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
438                 "      <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
439                 "      <arg direction=\"out\" type=\"s\"/>\n"
440                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
441                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
442                 "    </method>\n"
443                 "    <method name=\"GetTextAtOffset\">\n"
444                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
445                 "      <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
446                 "      <arg direction=\"out\" type=\"s\"/>\n"
447                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
448                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
449                 "    </method>\n"
450                 "    <method name=\"GetTextAfterOffset\">\n"
451                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
452                 "      <arg direction=\"in\" type=\"u\" name=\"type\"/>\n"
453                 "      <arg direction=\"out\" type=\"s\"/>\n"
454                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
455                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
456                 "    </method>\n"
457                 "    <method name=\"GetCharacterAtOffset\">\n"
458                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
459                 "      <arg direction=\"out\" type=\"i\"/>\n"
460                 "    </method>\n"
461                 "    <method name=\"GetAttributeValue\">\n"
462                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
463                 "      <arg direction=\"in\" type=\"s\" name=\"attributeName\"/>\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"
467                 "      <arg direction=\"out\" type=\"b\" name=\"defined\"/>\n"
468                 "    </method>\n"
469                 "    <method name=\"GetAttributes\">\n"
470                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
471                 "      <arg direction=\"out\" type=\"a{ss}\"/>\n"
472                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
473                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
474                 "      <annotation value=\"QSpiAttributeSet\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
475                 "    </method>\n"
476                 "    <method name=\"GetDefaultAttributes\">\n"
477                 "      <arg direction=\"out\" type=\"a{ss}\"/>\n"
478                 "      <annotation value=\"QSpiAttributeSet\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
479                 "    </method>\n"
480                 "    <method name=\"GetCharacterExtents\">\n"
481                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
482                 "      <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
483                 "      <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
484                 "      <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
485                 "      <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
486                 "      <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
487                 "    </method>\n"
488                 "    <method name=\"GetOffsetAtPoint\">\n"
489                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
490                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
491                 "      <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
492                 "      <arg direction=\"out\" type=\"i\"/>\n"
493                 "    </method>\n"
494                 "    <method name=\"GetNSelections\">\n"
495                 "      <arg direction=\"out\" type=\"i\"/>\n"
496                 "    <method name=\"GetSelection\">\n"
497                 "      <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
498                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
499                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
500                 "    </method>\n"
501                 "    <method name=\"AddSelection\">\n"
502                 "      <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
503                 "      <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
504                 "      <arg direction=\"out\" type=\"b\"/>\n"
505                 "    </method>\n"
506                 "    <method name=\"RemoveSelection\">\n"
507                 "      <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
508                 "      <arg direction=\"out\" type=\"b\"/>\n"
509                 "    </method>\n"
510                 "    <method name=\"SetSelection\">\n"
511                 "      <arg direction=\"in\" type=\"i\" name=\"selectionNum\"/>\n"
512                 "      <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
513                 "      <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
514                 "      <arg direction=\"out\" type=\"b\"/>\n"
515                 "    </method>\n"
516                 "    <method name=\"GetRangeExtents\">\n"
517                 "      <arg direction=\"in\" type=\"i\" name=\"startOffset\"/>\n"
518                 "      <arg direction=\"in\" type=\"i\" name=\"endOffset\"/>\n"
519                 "      <arg direction=\"out\" type=\"i\" name=\"x\"/>\n"
520                 "      <arg direction=\"out\" type=\"i\" name=\"y\"/>\n"
521                 "      <arg direction=\"out\" type=\"i\" name=\"width\"/>\n"
522                 "      <arg direction=\"out\" type=\"i\" name=\"height\"/>\n"
523                 "      <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
524                 "    </method>\n"
525                 "    <method name=\"GetBoundedRanges\">\n"
526                 "      <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
527                 "      <arg direction=\"in\" type=\"i\" name=\"y\"/>\n"
528                 "      <arg direction=\"in\" type=\"i\" name=\"width\"/>\n"
529                 "      <arg direction=\"in\" type=\"i\" name=\"height\"/>\n"
530                 "      <arg direction=\"in\" type=\"u\" name=\"coordType\"/>\n"
531                 "      <arg direction=\"in\" type=\"u\" name=\"xClipType\"/>\n"
532                 "      <arg direction=\"in\" type=\"u\" name=\"yClipType\"/>\n"
533                 "      <arg direction=\"out\" type=\"a(iisv)\"/>\n"
534                 "      <annotation value=\"QSpiRangeList\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
535                 "    </method>\n"
536                 "    <method name=\"GetAttributeRun\">\n"
537                 "      <arg direction=\"in\" type=\"i\" name=\"offset\"/>\n"
538                 "      <arg direction=\"in\" type=\"b\" name=\"includeDefaults\"/>\n"
539                 "      <arg direction=\"out\" type=\"a{ss}\"/>\n"
540                 "      <arg direction=\"out\" type=\"i\" name=\"startOffset\"/>\n"
541                 "      <arg direction=\"out\" type=\"i\" name=\"endOffset\"/>\n"
542                 "      <annotation value=\"QSpiAttributeSet\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
543                 "    </method>\n"
544                 "    <method name=\"GetDefaultAttributeSet\">\n"
545                 "      <arg direction=\"out\" type=\"a{ss}\"/>\n"
546                 "      <annotation value=\"QSpiAttributeSet\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
547                 "    </method>\n"
548                 "  </interface>\n"
549                 );
550
551     QLatin1String valueIntrospection(
552                 "  <interface name=\"org.a11y.atspi.Value\">\n"
553                 "    <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
554                 "    <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
555                 "    <property access=\"read\" type=\"d\" name=\"MinimumIncrement\"/>\n"
556                 "    <property access=\"readwrite\" type=\"d\" name=\"CurrentValue\"/>\n"
557                 "    <method name=\"SetCurrentValue\">\n"
558                 "      <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
559                 "    </method>\n"
560                 "  </interface>\n"
561                 );
562
563     QPair<QAIPointer, int> pair = interfaceFromPath(path);
564     if (!pair.first) {
565         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << path;
566         return QString();
567     }
568
569     QStringList interfaces = accessibleInterfaces(pair.first.data(), pair.second);
570
571     QString xml;
572     xml.append(accessibleIntrospection);
573
574     if (interfaces.contains(ATSPI_DBUS_INTERFACE_COMPONENT))
575         xml.append(componentIntrospection);
576     if (interfaces.contains(ATSPI_DBUS_INTERFACE_TEXT))
577         xml.append(textIntrospection);
578     if (interfaces.contains(ATSPI_DBUS_INTERFACE_EDITABLE_TEXT))
579         xml.append(editableTextIntrospection);
580     if (interfaces.contains(ATSPI_DBUS_INTERFACE_ACTION))
581         xml.append(actionIntrospection);
582     if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE))
583         xml.append(tableIntrospection);
584     if (interfaces.contains(ATSPI_DBUS_INTERFACE_VALUE))
585         xml.append(valueIntrospection);
586     if (path == QSPI_OBJECT_PATH_ROOT)
587         xml.append(applicationIntrospection);
588
589     return xml;
590 }
591
592 /*!
593   When initialized we will send updates, not before this.
594
595   This function also checks which event listeners are registered in the at-spi registry.
596   */
597 void AtSpiAdaptor::setInitialized(bool init)
598 {
599     initialized = init;
600
601     if (!initialized)
602         return;
603
604     updateEventListeners();
605     bool success = m_dbus->connection().connect("org.a11y.atspi.Registry", "/org/a11y/atspi/registry",
606                                                "org.a11y.atspi.Registry", "EventListenerRegistered", this,
607                                                SLOT(eventListenerRegistered(QString,QString)));
608     success = success && m_dbus->connection().connect("org.a11y.atspi.Registry", "/org/a11y/atspi/registry",
609                                                "org.a11y.atspi.Registry", "EventListenerDeregistered", this,
610                                                SLOT(eventListenerDeregistered(QString,QString)));
611     qDebug() << "Registered event listener change listener: " << success;
612 }
613
614 void AtSpiAdaptor::setBitFlag(const QString &flag)
615 {
616     Q_ASSERT(flag.size());
617
618     // assume we don't get nonsense - look at first letter only
619     switch (flag.at(0).toLower().toLatin1()) {
620     case 'o': {
621         if (flag.size() <= 8) { // Object::
622             sendObject = 1;
623             break;
624         } else { // Object:Foo:Bar
625             QString right = flag.mid(7);
626             if (false) {
627             } else if (right.startsWith(QLatin1String("ActiveDescendantChanged"))) {
628                 sendObject_active_descendant_changed = 1;
629             } else if (right.startsWith(QLatin1String("AttributesChanged"))) {
630                 sendObject_attributes_changed = 1;
631             } else if (right.startsWith(QLatin1String("BoundsChanged"))) {
632                 sendObject_bounds_changed = 1;
633             } else if (right.startsWith(QLatin1String("ChildrenChanged"))) {
634                 sendObject_children_changed = 1;
635             } else if (right.startsWith(QLatin1String("ColumnDeleted"))) {
636                 sendObject_column_deleted = 1;
637             } else if (right.startsWith(QLatin1String("ColumnInserted"))) {
638                 sendObject_column_inserted = 1;
639             } else if (right.startsWith(QLatin1String("ColumnReordered"))) {
640                 sendObject_column_reordered = 1;
641             } else if (right.startsWith(QLatin1String("LinkSelected"))) {
642                 sendObject_link_selected = 1;
643             } else if (right.startsWith(QLatin1String("ModelChanged"))) {
644                 sendObject_model_changed = 1;
645             } else if (right.startsWith(QLatin1String("PropertyChange"))) {
646                 if (right == QLatin1String("PropertyChange:AccessibleDescription")) {
647                     sendObject_property_change_accessible_description = 1;
648                 } else if (right == QLatin1String("PropertyChange:AccessibleName")) {
649                     sendObject_property_change_accessible_name = 1;
650                 } else if (right == QLatin1String("PropertyChange:AccessibleParent")) {
651                     sendObject_property_change_accessible_parent = 1;
652                 } else if (right == QLatin1String("PropertyChange:AccessibleRole")) {
653                     sendObject_property_change_accessible_role = 1;
654                 } else if (right == QLatin1String("PropertyChange:TableCaption")) {
655                     sendObject_property_change_accessible_table_caption = 1;
656                 } else if (right == QLatin1String("PropertyChange:TableColumnDescription")) {
657                     sendObject_property_change_accessible_table_column_description = 1;
658                 } else if (right == QLatin1String("PropertyChange:TableColumnHeader")) {
659                     sendObject_property_change_accessible_table_column_header = 1;
660                 } else if (right == QLatin1String("PropertyChange:TableRowDescription")) {
661                     sendObject_property_change_accessible_table_row_description = 1;
662                 } else if (right == QLatin1String("PropertyChange:TableRowHeader")) {
663                     sendObject_property_change_accessible_table_row_header = 1;
664                 } else if (right == QLatin1String("PropertyChange:TableSummary")) {
665                     sendObject_property_change_accessible_table_summary = 1;
666                 } else if (right == QLatin1String("PropertyChange:AccessibleValue")) {
667                     sendObject_property_change_accessible_value = 1;
668                 } else {
669                     sendObject_property_change = 1;
670                 }
671             } else if (right.startsWith(QLatin1String("RowDeleted"))) {
672                 sendObject_row_deleted = 1;
673             } else if (right.startsWith(QLatin1String("RowInserted"))) {
674                 sendObject_row_inserted = 1;
675             } else if (right.startsWith(QLatin1String("RowReordered"))) {
676                 sendObject_row_reordered = 1;
677             } else if (right.startsWith(QLatin1String("SelectionChanged"))) {
678                 sendObject_selection_changed = 1;
679             } else if (right.startsWith(QLatin1String("StateChanged"))) {
680                 sendObject_state_changed = 1;
681             } else if (right.startsWith(QLatin1String("TextAttributesChanged"))) {
682                 sendObject_text_attributes_changed = 1;
683             } else if (right.startsWith(QLatin1String("TextBoundsChanged"))) {
684                 sendObject_text_bounds_changed = 1;
685             } else if (right.startsWith(QLatin1String("TextCaretMoved"))) {
686                 sendObject_text_caret_moved = 1;
687             } else if (right.startsWith(QLatin1String("TextChanged"))) {
688                 sendObject_text_changed = 1;
689             } else if (right.startsWith(QLatin1String("TextSelectionChanged"))) {
690                 sendObject_text_selection_changed = 1;
691             } else if (right.startsWith(QLatin1String("ValueChanged"))) {
692                 sendObject_value_changed = 1;
693             } else if (right.startsWith(QLatin1String("VisibleDataChanged"))) {
694                 sendObject_visible_data_changed = 1;
695             } else {
696                 qWarning() << "WARNING: subscription string not handled:" << flag;
697             }
698         }
699         break;
700     }
701     case 'w': { // window
702         if (flag.size() < 7) {
703             sendWindow = 1;
704         } else { // object:Foo:Bar
705             QString right = flag.mid(7);
706             if (false) {
707             } else if (right.startsWith(QLatin1String("Activate"))) {
708                 sendWindow_activate = 1;
709             } else if (right.startsWith(QLatin1String("Close"))) {
710                 sendWindow_close= 1;
711             } else if (right.startsWith(QLatin1String("Create"))) {
712                 sendWindow_create = 1;
713             } else if (right.startsWith(QLatin1String("Deactivate"))) {
714                 sendWindow_deactivate = 1;
715             } else if (right.startsWith(QLatin1String("Lower"))) {
716                 sendWindow_lower = 1;
717             } else if (right.startsWith(QLatin1String("Maximize"))) {
718                 sendWindow_maximize = 1;
719             } else if (right.startsWith(QLatin1String("Minimize"))) {
720                 sendWindow_minimize = 1;
721             } else if (right.startsWith(QLatin1String("Move"))) {
722                 sendWindow_move = 1;
723             } else if (right.startsWith(QLatin1String("Raise"))) {
724                 sendWindow_raise = 1;
725             } else if (right.startsWith(QLatin1String("Reparent"))) {
726                 sendWindow_reparent = 1;
727             } else if (right.startsWith(QLatin1String("Resize"))) {
728                 sendWindow_resize = 1;
729             } else if (right.startsWith(QLatin1String("Restore"))) {
730                 sendWindow_restore = 1;
731             } else if (right.startsWith(QLatin1String("Restyle"))) {
732                 sendWindow_restyle = 1;
733             } else if (right.startsWith(QLatin1String("Shade"))) {
734                 sendWindow_shade = 1;
735             } else if (right.startsWith(QLatin1String("Unshade"))) {
736                 sendWindow_unshade = 1;
737             } else if (right.startsWith(QLatin1String("DesktopCreate"))) {
738                 // ignore this one
739             } else if (right.startsWith(QLatin1String("DesktopDestroy"))) {
740                 // ignore this one
741             } else {
742                 qWarning() << "WARNING: subscription string not handled:" << flag;
743             }
744         }
745         break;
746     }
747     case 'f': {
748         sendFocus = 1;
749         break;
750     }
751     case 'd': { // document is not implemented
752         break;
753     }
754     case 't': { // terminal is not implemented
755         break;
756     }
757     case 'm': { // mouse* is handled in a different way by the gnome atspi stack
758         break;
759     }
760     default:
761         qWarning() << "WARNING: subscription string not handled:" << flag;
762     }
763 }
764
765 /*!
766   Checks via dbus which events should be sent.
767   */
768 void AtSpiAdaptor::updateEventListeners()
769 {
770     QDBusMessage m = QDBusMessage::createMethodCall("org.a11y.atspi.Registry",
771                                                     "/org/a11y/atspi/registry",
772                                                     "org.a11y.atspi.Registry", "GetRegisteredEvents");
773     QDBusReply<QSpiEventListenerArray> listenersReply = m_dbus->connection().call(m);
774     if (listenersReply.isValid()) {
775         qDebug() << "Event listeners: ";
776         const QSpiEventListenerArray evList = listenersReply.value();
777         Q_FOREACH(const QSpiEventListener &ev, evList) {
778             setBitFlag(ev.eventName);
779             qDebug() << "Event listeners: " << ev.eventName;
780         }
781         m_applicationAdaptor->sendEvents(true /*!evList.isEmpty()*/);
782     } else {
783         qWarning() << "Could not query active accessibility event listeners.";
784     }
785 }
786
787 void AtSpiAdaptor::eventListenerDeregistered(const QString &/*bus*/, const QString &/*path*/)
788 {
789 //    qDebug() << "AtSpiAdaptor::eventListenerDeregistered: " << bus << path;
790     updateEventListeners();
791 }
792
793 void AtSpiAdaptor::eventListenerRegistered(const QString &/*bus*/, const QString &/*path*/)
794 {
795 //    qDebug() << "AtSpiAdaptor::eventListenerRegistered: " << bus << path;
796     updateEventListeners();
797 }
798
799 /*!
800   This slot needs to get called when a \a window has be activated or deactivated (become focused).
801   When \a active is true, the window just received focus, otherwise it lost the focus.
802   */
803 void AtSpiAdaptor::windowActivated(QObject* window, bool active)
804 {
805     if (!(sendWindow || sendWindow_activate))
806         return;
807
808     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
809     QString windowTitle = iface->text(QAccessible::Name, 0);
810     delete iface;
811
812     QDBusVariant data;
813     data.setVariant(windowTitle);
814
815     QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data));
816
817     QString status = active ? QLatin1String("Activate") : QLatin1String("Deactivate");
818     QString path = pathForObject(window);
819     sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_WINDOW, status, args);
820
821     QVariantList stateArgs = packDBusSignalArguments(QLatin1String("active"), active ? 1 : 0, 0, variantForPath(path));
822     sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
823                    QLatin1String("StateChanged"), stateArgs);
824 }
825
826 QVariantList AtSpiAdaptor::packDBusSignalArguments(const QString &type, int data1, int data2, const QVariant &variantData) const
827 {
828     QVariantList arguments;
829     arguments << type << data1 << data2 << variantData
830               << QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT)));
831     return arguments;
832 }
833
834 QVariant AtSpiAdaptor::variantForPath(const QString &path) const
835 {
836     QDBusVariant data;
837     data.setVariant(QVariant::fromValue(QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(path))));
838     return QVariant::fromValue(data);
839 }
840
841 bool AtSpiAdaptor::sendDBusSignal(const QString &path, const QString &interface, const QString &signalName, const QVariantList &arguments) const
842 {
843     QDBusMessage message = QDBusMessage::createSignal(path, interface, signalName);
844     message.setArguments(arguments);
845     return m_dbus->connection().send(message);
846 }
847
848 QPair<QAIPointer, int> AtSpiAdaptor::interfaceFromPath(const QString& dbusPath) const
849 {
850     int index = 0;
851
852     if (dbusPath == QSPI_OBJECT_PATH_ROOT) {
853         QAIPointer interface = QAIPointer(QAccessible::queryAccessibleInterface(qApp));
854         return qMakePair(interface, index);
855     }
856
857     QStringList parts = dbusPath.split('/');
858     if (parts.size() <= 5) {
859         qWarning() << "invalid path: " << dbusPath;
860         return qMakePair(QAIPointer(), 0);
861     }
862
863     QString objectString = parts.at(5);
864     quintptr uintptr = objectString.toULongLong();
865
866     if (uintptr && m_handledObjects.contains(uintptr)) {
867         // We found the pointer, check if it's still valid:
868         if (m_handledObjects[uintptr].data() != 0) {
869             QObject* object = reinterpret_cast<QObject*>(uintptr);
870
871             QAIPointer interface = QAIPointer(QAccessible::queryAccessibleInterface(object));
872             if (!interface)
873                 return qMakePair(QAIPointer(), 0);
874             QAIPointer child;
875
876             for (int i = 6; i < parts.size(); ++i) {
877                 QAccessibleInterface *childInterface;
878                 index = interface->navigate(QAccessible::Child, parts.at(i).toInt(), &childInterface);
879                 if (index < 0)
880                     return qMakePair(QAIPointer(), 0);
881
882                 child = QAIPointer(childInterface);
883                 if (index == 0 && child)
884                     interface = child;
885             }
886             return qMakePair(interface, index);
887
888         } else {
889             m_handledObjects.remove(uintptr);
890         }
891     }
892     return qMakePair(QAIPointer(), 0);
893 }
894
895
896 /*!
897     This function gets called when Qt notifies about accessibility updates.
898 */
899 void AtSpiAdaptor::notify(int reason, QAccessibleInterface *interface, int child)
900 {
901     Q_ASSERT(interface);
902
903     if (!interface->isValid()) {
904         //spiBridge->removeAdaptor(this);
905         // FIXME announce that this thing is dead? will it ever happen?
906         Q_ASSERT_X(0, "", "Got an update for an invalid inteface. Investigate this.");
907         return;
908     }
909
910     if (reason == QAccessible::ObjectShow && interface->object()) {
911         if (child != 0) {
912             qWarning() << "State for child changed: " << interface->object() << child;
913             return;
914         }
915         int state = interface->state(child);
916         interface->object()->setProperty(ACCESSIBLE_LAST_STATE, state);
917     }
918     // Saving of the last text should not be skipped, even when initialized is still false.
919     if (reason == QAccessible::ObjectShow && interface->textInterface()) {
920         Q_ASSERT(interface->object());
921         QString text = interface->textInterface()->text(0, interface->textInterface()->characterCount());
922         interface->object()->setProperty(ACCESSIBLE_LAST_TEXT, text);
923     }
924
925     if (!initialized)
926         return;
927
928     switch (reason) {
929     case QAccessible::ObjectCreated:
930         if (sendObject || sendObject_children_changed)
931             notifyAboutCreation(interface, child);
932         break;
933     case QAccessible::ObjectShow: {
934         if (sendObject || sendObject_state_changed) {
935             QString path = pathForInterface(interface, child);
936             QVariantList stateArgs = packDBusSignalArguments(QLatin1String("showing"), 1, 0, variantForPath(path));
937             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
938                            QLatin1String("StateChanged"), stateArgs);
939         }
940         break;
941     }
942     case QAccessible::ObjectHide: {
943         if (sendObject || sendObject_state_changed) {
944             QString path = pathForInterface(interface, child);
945             QVariantList stateArgs = packDBusSignalArguments(QLatin1String("showing"), 0, 0, variantForPath(path));
946             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
947                            QLatin1String("StateChanged"), stateArgs);
948         }
949         break;
950     }
951     case QAccessible::ObjectDestroyed: {
952         if (sendObject || sendObject_state_changed)
953             notifyAboutDestruction(interface, child);
954         break;
955     }
956     case QAccessible::NameChanged: {
957         if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
958             QString path = pathForInterface(interface, child);
959             QVariantList args = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
960             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
961                            QLatin1String("PropertyChange"), args);
962         }
963         break;
964     }
965     case QAccessible::DescriptionChanged: {
966         if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
967             QString path = pathForInterface(interface, child);
968             QVariantList args = packDBusSignalArguments(QLatin1String("accessible-description"), 0, 0, variantForPath(path));
969             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
970                            QLatin1String("PropertyChange"), args);
971         }
972         break;
973     }
974     case QAccessible::Focus: {
975         if(sendFocus || sendObject || sendObject_state_changed)
976             sendFocusChanged(interface, child);
977         break;
978     }
979     case QAccessible::TextUpdated: {
980         if (sendObject || sendObject_text_changed) {
981             Q_ASSERT(interface->textInterface());
982             QString path = pathForInterface(interface, child);
983             // at-spi doesn't have a text updated/changed, so remove all and re-add the new text
984             QString oldText = interface->object()->property(ACCESSIBLE_LAST_TEXT).toString();
985
986             QDBusVariant data;
987             data.setVariant(QVariant::fromValue(oldText));
988             QVariantList args = packDBusSignalArguments(QLatin1String("delete"), 0, oldText.length(), QVariant::fromValue(data));
989             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
990                            QLatin1String("TextChanged"), args);
991
992             QString text = interface->textInterface()->text(0, interface->textInterface()->characterCount());
993             data.setVariant(QVariant::fromValue(text));
994             args = packDBusSignalArguments(QLatin1String("insert"), 0, text.length(), QVariant::fromValue(data));
995             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
996                            QLatin1String("TextChanged"), args);
997
998             interface->object()->setProperty(ACCESSIBLE_LAST_TEXT, text);
999         }
1000         break;
1001     }
1002     case QAccessible::TextCaretMoved: {
1003         if (sendObject || sendObject_text_caret_moved) {
1004             Q_ASSERT(interface->textInterface());
1005             QString path = pathForInterface(interface, child);
1006             QDBusVariant cursorData;
1007             int pos = interface->textInterface()->cursorPosition();
1008             cursorData.setVariant(QVariant::fromValue(pos));
1009             QVariantList args = packDBusSignalArguments(QString(), pos, 0, QVariant::fromValue(cursorData));
1010             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1011                            QLatin1String("TextCaretMoved"), args);
1012         }
1013         break;
1014     }
1015     case QAccessible::TextSelectionChanged: {
1016         if (sendObject || sendObject_text_selection_changed) {
1017             QString path = pathForInterface(interface, child);
1018             QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(QString()))));
1019             sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1020                            QLatin1String("TextSelectionChanged"), args);
1021
1022         }
1023         break;
1024     }
1025     case QAccessible::ValueChanged: {
1026             if (sendObject || sendObject_value_changed) {
1027                 Q_ASSERT(interface->valueInterface());
1028                 QString path = pathForInterface(interface, child);
1029                 QVariantList args = packDBusSignalArguments(QLatin1String("accessible-value"), 0, 0, variantForPath(path));
1030                 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1031                                QLatin1String("PropertyChange"), args);
1032             }
1033             break;
1034     }
1035
1036     case QAccessible::Selection: {
1037         QString path = pathForInterface(interface, child);
1038         int selected = (interface->state(child) & QAccessible::Selected) ? 1 : 0;
1039         QVariantList stateArgs = packDBusSignalArguments(QLatin1String("selected"), selected, 0, variantForPath(path));
1040         sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1041                        QLatin1String("StateChanged"), stateArgs);
1042         break;
1043     }
1044
1045     case QAccessible::StateChanged: {
1046         if (sendObject || sendObject_state_changed) {
1047             if (!interface->object()) {
1048                 qWarning() << "Interface has no object";
1049                 return;
1050             }
1051             if (child != 0) {
1052                 qWarning() << "State for child changed: " << interface->object() << child;
1053                 return;
1054             }
1055
1056             QAccessible::State oldState = (QAccessible::State) interface->object()->property(ACCESSIBLE_LAST_STATE).toUInt();
1057             QAccessible::State newState = interface->state(child);
1058             //qDebug() << "StateChanged: old: " << oldState << " new: " << newState << " xor: " << (oldState^newState);
1059             if ((oldState^newState) & QAccessible::Checked) {
1060                 int checked = (newState & QAccessible::Checked) ? 1 : 0;
1061                 QString path = pathForInterface(interface, child);
1062                 QVariantList args = packDBusSignalArguments(QLatin1String("checked"), checked, 0, variantForPath(path));
1063                 sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1064                                QLatin1String("StateChanged"), args);
1065             }
1066             interface->object()->setProperty(ACCESSIBLE_LAST_STATE, (uint)newState);
1067         }
1068         break;
1069     }
1070 //    case QAccessible::TableModelChanged: {
1071 //        // This is rather evil. We don't send data and hope that at-spi fetches the right child.
1072 //        // This hack fails when a row gets removed and a different one added in its place.
1073 //        QDBusVariant data;
1074 //        emit ChildrenChanged("add", 0, 0, data, spiBridge->getRootReference());
1075 //        break;
1076 //    }
1077         //    case QAccessible::TableModelChanged:
1078         //        QAccessible2::TableModelChange change = interface->table2Interface()->modelChange();
1079         //        // assume we should reset if everything is 0
1080         //        if (change.firstColumn == 0 && change.firstRow == 0 && change.lastColumn == 0 && change.lastRow == 0) {
1081         //            notifyAboutDestruction(accessible);
1082         //            notifyAboutCreation(accessible);
1083         //        }
1084         //        break;
1085
1086     case QAccessible::ParentChanged:
1087         break;
1088     case QAccessible::DialogStart:
1089         break;
1090     case QAccessible::DialogEnd:
1091         break;
1092     case QAccessible::TableModelChanged:
1093         // For now ignore this event, should be handled together with active descendant changed
1094         break;
1095     case QAccessible::SelectionRemove:
1096         break;
1097     default:
1098         qWarning() << "QSpiAccessible::accessibleEvent not handled: " << QString::number(reason, 16)
1099                    << " obj: " << interface->object()
1100                    << ((interface->isValid() && interface->object()) ? interface->object()->objectName() : " invalid interface!");
1101         break;
1102     }
1103 }
1104
1105 void AtSpiAdaptor::sendFocusChanged(QAccessibleInterface *interface, int child) const
1106 {
1107     static QString lastFocusPath;
1108     // "remove" old focus
1109     if (!lastFocusPath.isEmpty()) {
1110         QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 0, 0, variantForPath(lastFocusPath));
1111         sendDBusSignal(lastFocusPath, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1112                        QLatin1String("StateChanged"), stateArgs);
1113     }
1114     // send new focus
1115     {
1116         QString path = pathForInterface(interface, child);
1117
1118         QVariantList stateArgs = packDBusSignalArguments(QLatin1String("focused"), 1, 0, variantForPath(path));
1119         sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
1120                        QLatin1String("StateChanged"), stateArgs);
1121
1122         QVariantList focusArgs = packDBusSignalArguments(QString(), 0, 0, variantForPath(path));
1123         sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_FOCUS),
1124                        QLatin1String("Focus"), focusArgs);
1125         lastFocusPath = path;
1126     }
1127 }
1128
1129 void AtSpiAdaptor::notifyAboutCreation(QAccessibleInterface *interface, int child) const
1130 {
1131 //    // say hello to d-bus
1132 //    cache->emitAddAccessible(accessible->getCacheItem());
1133
1134     // notify about the new child of our parent
1135     QAccessibleInterface *parent = accessibleParent(interface, child);
1136     if (!parent) {
1137         qWarning() << "AtSpiAdaptor::notifyAboutCreation: Could not find parent for " << interface->object() << child;
1138         return;
1139     }
1140     QString path = pathForInterface(interface, child);
1141     int childCount = parent->childCount();
1142     QString parentPath = pathForInterface(parent, 0);
1143     QVariantList args = packDBusSignalArguments(QLatin1String("add"), childCount, 0, variantForPath(path));
1144     sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", args);
1145     delete parent;
1146 }
1147
1148 void AtSpiAdaptor::notifyAboutDestruction(QAccessibleInterface *interface, int child) const
1149 {
1150     if (!interface->isValid())
1151         return;
1152
1153     QAccessibleInterface *parent = accessibleParent(interface, child);
1154     if (!parent) {
1155         qWarning() << "AtSpiAdaptor::notifyAboutDestruction: Could not find parent for " << interface->object() << child;
1156         return;
1157     }
1158     QString path = pathForInterface(interface, child);
1159
1160     // this is in the destructor. we have no clue which child we used to be.
1161     // FIXME
1162     int childIndex = -1;
1163     //    if (child) {
1164     //        childIndex = child;
1165     //    } else {
1166     //        childIndex = parent->indexOfChild(interface);
1167     //    }
1168
1169     QString parentPath = pathForInterface(parent, 0, true);
1170     QVariantList args = packDBusSignalArguments(QLatin1String("remove"), childIndex, 0, variantForPath(path));
1171     sendDBusSignal(parentPath, ATSPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", args);
1172     delete parent;
1173 }
1174
1175 /*!
1176   Handle incoming DBus message.
1177   This function dispatches the dbus message to the right interface handler.
1178   */
1179 bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnection &connection)
1180 {
1181     // get accessible interface
1182     QPair<QAIPointer, int> accessible = interfaceFromPath(message.path());
1183     if (!(accessible.first)) {
1184         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << message.path();
1185         return false;
1186     }
1187
1188     QString interface = message.interface();
1189     QString function = message.member();
1190
1191     // qDebug() << "AtSpiAdaptor::handleMessage: " << interface << function;
1192
1193     if (function == "Introspect") {
1194         //introspect(message.path());
1195         return false;
1196     }
1197
1198     // handle properties like regular functions
1199     if (interface == "org.freedesktop.DBus.Properties") {
1200         interface = message.arguments().at(0).toString();
1201         // Get/Set + Name
1202         function = message.member() + message.arguments().at(1).toString();
1203     }
1204
1205     // switch interface to call
1206     if (interface == ATSPI_DBUS_INTERFACE_ACCESSIBLE) {
1207         return accessibleInterface(accessible.first.data(), accessible.second, function, message, connection);
1208     } else if (interface == ATSPI_DBUS_INTERFACE_APPLICATION) {
1209         return applicationInterface(accessible.first.data(), accessible.second, function, message, connection);
1210     } else if (interface == ATSPI_DBUS_INTERFACE_COMPONENT) {
1211         return componentInterface(accessible.first.data(), accessible.second, function, message, connection);
1212     } else if (interface == ATSPI_DBUS_INTERFACE_ACTION) {
1213         return actionInterface(accessible.first.data(), accessible.second, function, message, connection);
1214     } else if (interface == ATSPI_DBUS_INTERFACE_TEXT) {
1215         return textInterface(accessible.first.data(), accessible.second, function, message, connection);
1216     } else if (interface == ATSPI_DBUS_INTERFACE_EDITABLE_TEXT) {
1217         return editableTextInterface(accessible.first.data(), accessible.second, function, message, connection);
1218     } else if (interface == ATSPI_DBUS_INTERFACE_VALUE) {
1219         return valueInterface(accessible.first.data(), accessible.second, function, message, connection);
1220     } else if (interface == ATSPI_DBUS_INTERFACE_TABLE) {
1221         return tableInterface(accessible.first.data(), accessible.second, function, message, connection);
1222     } else {
1223         qDebug() << "AtSpiAdaptor::handleMessage " << message.path() << interface << function;
1224     }
1225     return false;
1226 }
1227
1228 // Application
1229 bool AtSpiAdaptor::applicationInterface(QAccessibleInterface *interface, int, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1230 {
1231     if (message.path() != ATSPI_DBUS_PATH_ROOT) {
1232         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find application interface for: " << message.path() << interface;
1233         return false;
1234     }
1235
1236     if (function == "SetId") {
1237         Q_ASSERT(message.signature() == "ssv");
1238         QVariant value = qvariant_cast<QDBusVariant>(message.arguments().at(2)).variant();
1239
1240         m_applicationId = value.toInt();
1241         return true;
1242
1243     } else if (function == "GetId") {
1244         Q_ASSERT(message.signature() == "ss");
1245         QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(m_applicationId)));
1246         return connection.send(reply);
1247     } else if (function == "GetToolkitName") {
1248         Q_ASSERT(message.signature() == "ss");
1249         QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QLatin1String("Qt"))));
1250         return connection.send(reply);
1251     } else {
1252         qDebug() << "AtSpiAdaptor::applicationInterface " << message.path() << interface << function;
1253     }
1254
1255     return false;
1256 }
1257
1258 /*!
1259   Register this application as accessible on the accessibility DBus.
1260   */
1261 void AtSpiAdaptor::registerApplication()
1262 {
1263     SocketProxy *registry;
1264     registry = new SocketProxy(QSPI_REGISTRY_NAME,
1265                                QSPI_OBJECT_PATH_ROOT, m_dbus->connection());
1266
1267     QDBusPendingReply<QSpiObjectReference> reply;
1268     QSpiObjectReference ref = QSpiObjectReference(m_dbus->connection(), QDBusObjectPath(QSPI_OBJECT_PATH_ROOT));
1269     reply = registry->Embed(ref);
1270     reply.waitForFinished();
1271     if (reply.isValid ()) {
1272         const QSpiObjectReference &socket = reply.value();
1273         accessibilityRegistry = QSpiObjectReference(socket);
1274     } else {
1275         qWarning() << "Error in contacting registry";
1276         qWarning() << reply.error().name();
1277         qWarning() << reply.error().message();
1278     }
1279     delete registry;
1280 }
1281
1282 // Accessible
1283 bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1284 {
1285     if (child < 0) {
1286         qWarning() << "AtSpiAdaptor::accessibleInterface called with child<0. FIXME";
1287         return false;
1288     }
1289
1290     if (function == "GetRole") {
1291         sendReply(connection, message, (uint) getRole(interface, child));
1292     } else if (function == "GetName") {
1293         sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Name, child))));
1294     } else if (function == "GetRoleName") {
1295         sendReply(connection, message, qSpiRoleMapping[interface->role(child)].name());
1296     } else if (function == "GetLocalizedRoleName") {
1297         sendReply(connection, message, QVariant::fromValue(qSpiRoleMapping[interface->role(child)].localizedName()));
1298     } else if (function == "GetChildCount") {
1299         int childCount = child ? 0 : interface->childCount();
1300         sendReply(connection, message, QVariant::fromValue(QDBusVariant(childCount)));
1301     } else if (function == "GetIndexInParent") {
1302         int childIndex = -1;
1303         if (child) {
1304             childIndex = child;
1305         } else {
1306             QAccessibleInterface *parent = accessibleParent(interface, child);
1307             if (parent)
1308                 childIndex = parent->indexOfChild(interface) - 1;
1309             delete parent;
1310         }
1311         sendReply(connection, message, childIndex);
1312     } else if (function == "GetParent") {
1313         QString path;
1314         QAccessibleInterface *parent = accessibleParent(interface, child);
1315         if (!parent) {
1316             path = ATSPI_DBUS_PATH_NULL;
1317         } else if (parent->role(0) == QAccessible::Application) {
1318             path = ATSPI_DBUS_PATH_ROOT;
1319         } else {
1320             path = pathForInterface(parent, 0);
1321         }
1322         if (parent != interface)
1323             delete parent;
1324
1325         // Parent is a property, so it needs to be wrapped inside an extra variant.
1326         sendReply(connection, message, QVariant::fromValue(
1327                       QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path))))));
1328     } else if (function == "GetChildAtIndex") {
1329         int index = message.arguments().first().toInt() + 1;
1330         if (child || index < 0 || index > interface->childCount()) {
1331             interface = 0;
1332             child = 0;
1333         }
1334         sendReply(connection, message, QVariant::fromValue(
1335                       QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(interface, index)))));
1336     } else if (function == "GetInterfaces") {
1337         sendReply(connection, message, accessibleInterfaces(interface, child));
1338     } else if (function == "GetDescription") {
1339         sendReply(connection, message, QVariant::fromValue(QDBusVariant(interface->text(QAccessible::Description, child))));
1340     } else if (function == "GetState") {
1341         quint64 spiState = spiStatesFromQState(interface->state(child));
1342         if (interface->table2Interface()) {
1343             setSpiStateBit(&spiState, ATSPI_STATE_MANAGES_DESCENDANTS);
1344         }
1345         if (interface->object() && interface->object()->isWidgetType()) {
1346             QWidget *w = qobject_cast<QWidget*>(interface->object());
1347             if (w && w->topLevelWidget() && w->isActiveWindow()) {
1348                 setSpiStateBit(&spiState, ATSPI_STATE_ACTIVE);
1349             }
1350         }
1351         QAccessible::Role role = interface->role(child);
1352         if (role == QAccessible::TreeItem ||
1353             role == QAccessible::ListItem) {
1354             /* Transient means libatspi2 will not cache items.
1355                This is important because when adding/removing an item
1356                the cache becomes outdated and we don't change the paths of
1357                items in lists/trees/tables. */
1358             setSpiStateBit(&spiState, ATSPI_STATE_TRANSIENT);
1359         }
1360         sendReply(connection, message,
1361                   QVariant::fromValue(spiStateSetFromSpiStates(spiState)));
1362     } else if (function == "GetAttributes") {
1363         sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
1364     } else if (function == "GetRelationSet") {
1365         sendReply(connection, message, QVariant::fromValue(relationSet(interface, child, connection)));
1366     } else if (function == "GetApplication") {
1367         sendReply(connection, message, QVariant::fromValue(
1368                       QSpiObjectReference(connection, QDBusObjectPath(QSPI_OBJECT_PATH_ROOT))));
1369     } else if (function == "GetChildren") {
1370         QSpiObjectReferenceArray children;
1371         for (int i = 0; i < interface->childCount(); ++i) {
1372             QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(interface, i + 1)));
1373             children << ref;
1374         }
1375         connection.send(message.createReply(QVariant::fromValue(children)));
1376     } else {
1377         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1378         return false;
1379     }
1380     return true;
1381 }
1382
1383 AtspiRole AtSpiAdaptor::getRole(QAccessibleInterface *interface, int child) const
1384 {
1385     if ((interface->role(child) == QAccessible::EditableText) && (interface->state(child) & QAccessible::Protected))
1386         return ATSPI_ROLE_PASSWORD_TEXT;
1387     return qSpiRoleMapping[interface->role(child)].spiRole();
1388 }
1389
1390 QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface, int index) const
1391 {
1392     QStringList ifaces;
1393 #ifdef ACCESSIBLE_CREATION_DEBUG
1394     qDebug() << "ACCESSIBLE: " << interface->object();
1395 #endif
1396     ifaces << ATSPI_DBUS_INTERFACE_ACCESSIBLE;
1397
1398     if (    (!interface->rect(index).isEmpty()) ||
1399             (interface->object() && interface->object()->isWidgetType()) ||
1400             (interface->role(index) == QAccessible::ListItem) ||
1401             (interface->role(index) == QAccessible::Cell) ||
1402             (interface->role(index) == QAccessible::TreeItem) ||
1403             (interface->role(index) == QAccessible::Row) ||
1404             (interface->object() && interface->object()->inherits("QSGItem"))
1405             ) {
1406         ifaces << ATSPI_DBUS_INTERFACE_COMPONENT;
1407         }
1408 #ifdef ACCESSIBLE_CREATION_DEBUG
1409     else {
1410         qDebug() << " IS NOT a component";
1411     }
1412 #endif
1413
1414     ifaces << ATSPI_DBUS_INTERFACE_ACTION;
1415
1416     if (!index) {
1417         if (interface->textInterface()) {
1418             ifaces << ATSPI_DBUS_INTERFACE_TEXT;
1419             // Cache the last text?
1420             // oldText = interface->textInterface()->text(0, interface->textInterface()->characterCount());
1421         }
1422
1423         if (interface->editableTextInterface())
1424             ifaces << ATSPI_DBUS_INTERFACE_EDITABLE_TEXT;
1425
1426         if (interface->valueInterface())
1427             ifaces << ATSPI_DBUS_INTERFACE_VALUE;
1428
1429         if (interface->table2Interface())
1430             ifaces << ATSPI_DBUS_INTERFACE_TABLE;
1431     }
1432
1433     // Do we need to cache the state?
1434     //    state = interface->state(childIndex());
1435
1436     return ifaces;
1437 }
1438
1439 QSpiRelationArray AtSpiAdaptor::relationSet(QAccessibleInterface *interface, int child, const QDBusConnection &connection) const
1440 {
1441     QSpiRelationArray relations;
1442     if (child != 0) {
1443         qDebug() << "AtSpiAdaptor::relationSet currently has a problem with child ids.";
1444         // FIXME for example trees need to express their child relations here.
1445         return relations;
1446     }
1447
1448     const QAccessible::RelationFlag relationsToCheck[] = {QAccessible::Label, QAccessible::Labelled, QAccessible::Controller, QAccessible::Controlled, static_cast<QAccessible::RelationFlag>(-1)};
1449     const AtspiRelationType relationTypes[] = {ATSPI_RELATION_LABELLED_BY, ATSPI_RELATION_LABEL_FOR, ATSPI_RELATION_CONTROLLED_BY, ATSPI_RELATION_CONTROLLER_FOR};
1450
1451     for (int i = 0; relationsToCheck[i] >= 0; i++) {
1452         QList<QSpiObjectReference> related;
1453         int navigateResult = 1;
1454
1455         for (int j = 1; navigateResult >= 0; j++) {
1456             QAccessibleInterface *target;
1457             navigateResult = interface->navigate(relationsToCheck[i], j, &target);
1458
1459             if (navigateResult >= 0) {
1460                 QDBusObjectPath path = QDBusObjectPath(pathForInterface(target ? target : interface, navigateResult));
1461                 related.append(QSpiObjectReference(connection, path));
1462                 delete target;
1463             }
1464         }
1465         if (!related.isEmpty())
1466             relations.append(QSpiRelationArrayEntry(relationTypes[i], related));
1467     }
1468     return relations;
1469 }
1470
1471 void AtSpiAdaptor::sendReply(const QDBusConnection &connection, const QDBusMessage &message, const QVariant &argument) const
1472 {
1473     QDBusMessage reply = message.createReply(argument);
1474     connection.send(reply);
1475 }
1476
1477 QAccessibleInterface *AtSpiAdaptor::accessibleParent(QAccessibleInterface *iface, int child) const
1478 {
1479     if (child) //It's necessary to return a new instance as it might be deleted
1480         return QAccessible::queryAccessibleInterface(iface->object());
1481
1482     QAccessibleInterface *parent = 0;
1483     iface->navigate(QAccessible::Ancestor, 1, &parent);
1484     return parent;
1485 }
1486
1487 QString AtSpiAdaptor::pathForObject(QObject *object) const
1488 {
1489     Q_ASSERT(object);
1490
1491     if (object->metaObject()->className() == QLatin1String("QAction")) {
1492         qDebug() << "AtSpiAdaptor::pathForObject: warning: creating path with QAction as object.";
1493     }
1494     quintptr uintptr = reinterpret_cast<quintptr>(object);
1495     if (!m_handledObjects.contains(uintptr))
1496         m_handledObjects[uintptr] = QWeakPointer<QObject>(object);
1497     return QSPI_OBJECT_PATH_PREFIX + QString::number(uintptr);
1498 }
1499
1500 QString AtSpiAdaptor::pathForInterface(QAccessibleInterface *interface, int childIndex, bool inDestructor) const
1501 {
1502     if (!interface)
1503         return ATSPI_DBUS_PATH_NULL;
1504
1505     // Try to navigate to the child.
1506     // If we get a proper interface, use it since it might have an object associated.
1507     QAccessibleInterface* childInterface = 0;
1508     if (childIndex) {
1509         int ret = interface->navigate(QAccessible::Child, childIndex, &childInterface);
1510         if (ret == 0 && childInterface) {
1511             interface = childInterface;
1512             childIndex = 0;
1513         }
1514     }
1515
1516     QAccessibleInterface* interfaceWithObject = interface;
1517
1518     if (interface->role(0) == QAccessible::MenuItem && interface->object() &&
1519             inheritsQAction(interface->object())) {
1520         interface->navigate(QAccessible::Ancestor, 1, &interfaceWithObject);
1521         childIndex = interfaceWithObject->indexOfChild(interface);
1522     }
1523
1524     QString path;
1525     while(!interfaceWithObject->object()) {
1526         QAccessibleInterface* parentInterface;
1527         interfaceWithObject->navigate(QAccessible::Ancestor, 1, &parentInterface);
1528         Q_ASSERT(parentInterface->isValid());
1529         int index = parentInterface->indexOfChild(interfaceWithObject);
1530
1531         if (index < 0) {
1532             qWarning() << "Object claims to have child that we cannot navigate to. FIX IT!" << parentInterface->object();
1533             return ATSPI_DBUS_PATH_NULL;
1534         }
1535         path.prepend('/' + QString::number(index));
1536         interfaceWithObject = parentInterface;
1537     }
1538     quintptr uintptr = reinterpret_cast<quintptr>(interfaceWithObject->object());
1539     path.prepend(QSPI_OBJECT_PATH_PREFIX + QString::number(uintptr));
1540
1541     if (childIndex > 0) {
1542         path.append('/' + QString::number(childIndex));
1543     }
1544     if (!inDestructor && !m_handledObjects.contains(uintptr))
1545         m_handledObjects[uintptr] = QWeakPointer<QObject>(interfaceWithObject->object());
1546     delete childInterface;
1547     return path;
1548 }
1549
1550 bool AtSpiAdaptor::inheritsQAction(QObject *object)
1551 {
1552     const QMetaObject *mo = object->metaObject();
1553     while (mo) {
1554         const QLatin1String cn(mo->className());
1555         if (cn == "QAction")
1556             return true;
1557         mo = mo->superClass();
1558     }
1559     return false;
1560 }
1561
1562 // Component
1563 static QAccessibleInterface *getWindow(QAccessibleInterface* interface)
1564 {
1565     QAccessibleInterface *original = interface;
1566     while (interface &&
1567            interface->role(0) != QAccessible::Window) {
1568         QAccessibleInterface *oldParent = interface;
1569         oldParent->navigate(QAccessible::Ancestor, 1, &interface);
1570         // do not delete the parameter we got as that would lead to double delete
1571         if (oldParent != original)
1572             delete oldParent;
1573     }
1574     return interface;
1575 }
1576
1577 static QRect getRelativeRect(QAccessibleInterface* interface, int child)
1578 {
1579     QAccessibleInterface *window;
1580     QRect wr, cr;
1581
1582     cr = interface->rect(child);
1583
1584     window = getWindow(interface);
1585     if (window)
1586     {
1587         wr = window->rect(child);
1588
1589         cr.setX(cr.x() - wr.x());
1590         cr.setY(cr.x() - wr.y());
1591     }
1592     return cr;
1593 }
1594
1595 bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1596 {
1597     if (function == "Contains") {
1598         bool ret = false;
1599         int x = message.arguments().at(0).toInt();
1600         int y = message.arguments().at(1).toInt();
1601         uint coordType = message.arguments().at(2).toUInt();
1602         if (coordType == ATSPI_COORD_TYPE_SCREEN)
1603             ret = interface->rect(child).contains(x, y);
1604         else
1605             ret = getRelativeRect(interface, child).contains(x, y);
1606         sendReply(connection, message, ret);
1607     } else if (function == "GetAccessibleAtPoint") {
1608         int x = message.arguments().at(0).toInt();
1609         int y = message.arguments().at(1).toInt();
1610         uint coordType = message.arguments().at(2).toUInt();
1611         Q_UNUSED (coordType) // FIXME
1612
1613         // Grab the top level widget. For complex widgets we want to return a child
1614         // at the right position instead.
1615         QWidget* w = qApp->widgetAt(x, y);
1616         if (w) {
1617             QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(w);
1618             if (!iface) {
1619                 return false;
1620             }
1621             int childIndex = iface->childAt(x, y);
1622             if (childIndex < 0)
1623                 childIndex = 0;
1624             QString path = pathForInterface(iface, childIndex);
1625             sendReply(connection, message, QVariant::fromValue(
1626                           QSpiObjectReference(connection, QDBusObjectPath(path))));
1627         } else {
1628             qDebug() << "GetAccessibleAtPoint found now widget";
1629             sendReply(connection, message, QVariant::fromValue(
1630                           QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
1631         }
1632     } else if (function == "GetAlpha") {
1633         sendReply(connection, message, (double) 1.0);
1634     } else if (function == "GetExtents") {
1635         uint coordType = message.arguments().at(0).toUInt();
1636         sendReply(connection, message, QVariant::fromValue(getExtents(interface, child, coordType)));
1637     } else if (function == "GetLayer") {
1638         sendReply(connection, message, QVariant::fromValue((uint)1));
1639     } else if (function == "GetMDIZOrder") {
1640         sendReply(connection, message, QVariant::fromValue((short)0));
1641     } else if (function == "GetPosition") {
1642         uint coordType = message.arguments().at(0).toUInt();
1643         QRect rect;
1644         if (coordType == ATSPI_COORD_TYPE_SCREEN)
1645             rect = interface->rect(child);
1646         else
1647             rect = getRelativeRect(interface, child);
1648         QVariantList pos;
1649         pos << rect.x() << rect.y();
1650         connection.send(message.createReply(pos));
1651     } else if (function == "GetSize") {
1652         QRect rect = interface->rect(child);
1653         QVariantList size;
1654         size << rect.width() << rect.height();
1655         connection.send(message.createReply(size));
1656     } else if (function == "GrabFocus") {
1657         if (interface->object() && interface->object()->isWidgetType()) {
1658             QWidget* w = static_cast<QWidget*>(interface->object());
1659             w->setFocus(Qt::OtherFocusReason);
1660             sendReply(connection, message, true);
1661         }
1662         sendReply(connection, message, false);
1663     } else if (function == "SetExtents") {
1664 //        int x = message.arguments().at(0).toInt();
1665 //        int y = message.arguments().at(1).toInt();
1666 //        int width = message.arguments().at(2).toInt();
1667 //        int height = message.arguments().at(3).toInt();
1668 //        uint coordinateType = message.arguments().at(4).toUInt();
1669         qWarning() << "SetExtents is not implemented.";
1670         sendReply(connection, message, false);
1671     } else if (function == "SetPosition") {
1672 //        int x = message.arguments().at(0).toInt();
1673 //        int y = message.arguments().at(1).toInt();
1674 //        uint coordinateType = message.arguments().at(2).toUInt();
1675         qWarning() << "SetPosition is not implemented.";
1676         sendReply(connection, message, false);
1677     } else if (function == "SetSize") {
1678 //        int width = message.arguments().at(0).toInt();
1679 //        int height = message.arguments().at(1).toInt();
1680         qWarning() << "SetSize is not implemented.";
1681         sendReply(connection, message, false);
1682     } else {
1683         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1684         return false;
1685     }
1686     return true;
1687 }
1688
1689 QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, int child, uint coordType)
1690 {
1691     QRect rect;
1692     if (coordType == ATSPI_COORD_TYPE_SCREEN) {
1693         rect = interface->rect(child);
1694     } else {
1695         rect = getRelativeRect(interface, child);
1696     }
1697     qDebug() << "Get extents: " << coordType << rect;
1698     return rect;
1699 }
1700
1701 // Action interface
1702 bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1703 {
1704     QAccessibleActionInterface *actionIface = interface->actionInterface();
1705     bool deleteActionInterface = false;
1706     if (!actionIface) {
1707         actionIface = new StandardActionWrapper(interface, child);
1708         deleteActionInterface = true;
1709         child = 0;
1710     }
1711
1712     if (function == "GetNActions") {
1713         sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(actionIface->actionCount()))));
1714     } else if (function == "DoAction") {
1715         int index = message.arguments().at(0).toInt();
1716         actionIface->doAction(index);
1717         sendReply(connection, message, true);
1718     } else if (function == "GetActions") {
1719         if (child) {
1720             qWarning() << "AtSpiAdaptor::actionInterface: Requesting action interface for child";
1721             return false;
1722         }
1723         sendReply(connection, message, QVariant::fromValue(getActions(actionIface)));
1724     } else if (function == "GetName") {
1725         int index = message.arguments().at(0).toInt();
1726         sendReply(connection, message, actionIface->name(index));
1727     } else if (function == "GetDescription") {
1728         int index = message.arguments().at(0).toInt();
1729         sendReply(connection, message, actionIface->description(index));
1730     } else if (function == "GetKeyBinding") {
1731         int index = message.arguments().at(0).toInt();
1732         QStringList keyBindings;
1733         keyBindings = actionIface->keyBindings(index);
1734         if (keyBindings.isEmpty()) {
1735             QString acc = interface->text(QAccessible::Accelerator, child);
1736             if (!acc.isEmpty())
1737                 keyBindings.append(acc);
1738         }
1739         if (keyBindings.length() > 0)
1740             sendReply(connection, message, keyBindings.join(";"));
1741         else
1742             sendReply(connection, message, QString());
1743     } else {
1744         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1745         if (deleteActionInterface)
1746             delete actionIface;
1747
1748         return false;
1749     }
1750
1751     if (deleteActionInterface)
1752         delete actionIface;
1753
1754     return true;
1755 }
1756
1757 QSpiActionArray AtSpiAdaptor::getActions(QAccessibleActionInterface *actionInterface) const
1758 {
1759     QSpiActionArray actions;
1760     for (int i = 0; i < actionInterface->actionCount(); i++)
1761     {
1762         QSpiAction action;
1763         QStringList keyBindings;
1764
1765         action.name = actionInterface->name(i);
1766         action.description = actionInterface->description(i);
1767
1768         keyBindings = actionInterface->keyBindings(i);
1769
1770         if (keyBindings.length() > 0)
1771                 action.keyBinding = keyBindings[0];
1772         else
1773                 action.keyBinding = "";
1774
1775         actions << action;
1776     }
1777     return actions;
1778 }
1779
1780 // Text interface
1781 bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
1782 {
1783     Q_ASSERT(child == 0); // We should never claim to have a text interface on a virtual child
1784     if (!interface->textInterface()) {
1785         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find text interface for: " << message.path() << interface;
1786         return false;
1787     }
1788
1789     // properties
1790     if (function == "GetCaretOffset") {
1791         sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->cursorPosition()))));
1792     } else if (function == "GetCharacterCount") {
1793         sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(interface->textInterface()->characterCount()))));
1794
1795     // functions
1796     } else if (function == "AddSelection") {
1797         int startOffset = message.arguments().at(0).toInt();
1798         int endOffset = message.arguments().at(1).toInt();
1799         int lastSelection = interface->textInterface()->selectionCount();
1800         interface->textInterface()->setSelection(lastSelection, startOffset, endOffset);
1801         sendReply(connection, message, (interface->textInterface()->selectionCount() > lastSelection));
1802     } else if (function == "GetAttributeRun") {
1803         int offset = message.arguments().at(0).toInt();
1804         bool includeDefaults = message.arguments().at(1).toBool();
1805         Q_UNUSED(includeDefaults)
1806         connection.send(message.createReply(getAttributes(interface, offset, includeDefaults)));
1807     } else if (function == "GetAttributeValue") {
1808         int offset = message.arguments().at(0).toInt();
1809         QString attributeName = message.arguments().at(1).toString();
1810         connection.send(message.createReply(getAttributeValue(interface, offset, attributeName)));
1811     } else if (function == "GetAttributes") {
1812         int offset = message.arguments().at(0).toInt();
1813         connection.send(message.createReply(getAttributes(interface, offset, true)));
1814     } else if (function == "GetBoundedRanges") {
1815         int x = message.arguments().at(0).toInt();
1816         int y = message.arguments().at(1).toInt();
1817         int width = message.arguments().at(2).toInt();
1818         int height = message.arguments().at(3).toInt();
1819         uint coordType = message.arguments().at(4).toUInt();
1820         uint xClipType = message.arguments().at(5).toUInt();
1821         uint yClipType = message.arguments().at(6).toUInt();
1822         Q_UNUSED(x) Q_UNUSED (y) Q_UNUSED(width)
1823         Q_UNUSED(height) Q_UNUSED(coordType)
1824         Q_UNUSED(xClipType) Q_UNUSED(yClipType)
1825         qWarning("Not implemented: QSpiAdaptor::GetBoundedRanges");
1826         sendReply(connection, message, QVariant::fromValue(QSpiTextRangeList()));
1827     } else if (function == "GetCharacterAtOffset") {
1828         int offset = message.arguments().at(0).toInt();
1829         int start;
1830         int end;
1831         QString result = interface->textInterface()->textAtOffset(offset, QAccessible2::CharBoundary, &start, &end);
1832         sendReply(connection, message, (int) *(qPrintable (result)));
1833         Q_ASSERT(0); // FIXME wtf is this!!!???!!! at least test if it produces the desired result bah
1834
1835     } else if (function == "GetCharacterExtents") {
1836         int offset = message.arguments().at(0).toInt();
1837         int coordType = message.arguments().at(1).toUInt();
1838         connection.send(message.createReply(getCharacterExtents(interface, offset, coordType)));
1839     } else if (function == "GetDefaultAttributeSet" || function == "GetDefaultAttributes") {
1840         // GetDefaultAttributes is deprecated in favour of GetDefaultAttributeSet.
1841         // Empty set seems reasonable. There is no default attribute set.
1842         sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
1843     } else if (function == "GetNSelections") {
1844         sendReply(connection, message, interface->textInterface()->selectionCount());
1845     } else if (function == "GetOffsetAtPoint") {
1846         int x = message.arguments().at(0).toInt();
1847         int y = message.arguments().at(1).toInt();
1848         uint coordType = message.arguments().at(2).toUInt();
1849         //            int (int x, int y, uint coordType);
1850         // FIXME: relative to screen and relative to parent is not the same
1851         int offset = interface->textInterface()->offsetAtPoint(QPoint (x, y), static_cast <QAccessible2::CoordinateType> (coordType));
1852         sendReply(connection, message, offset);
1853     } else if (function == "GetRangeExtents") {
1854         int startOffset = message.arguments().at(0).toInt();
1855         int endOffset = message.arguments().at(1).toInt();
1856         uint coordType = message.arguments().at(2).toUInt();
1857         connection.send(message.createReply(getRangeExtents(interface, startOffset, endOffset, coordType)));
1858     } else if (function == "GetSelection") {
1859         int selectionNum = message.arguments().at(0).toInt();
1860         int start, end;
1861         interface->textInterface()->selection(selectionNum, &start, &end);
1862             if (start < 0) {
1863             // FIXME: what is this for?
1864             end = interface->textInterface()->cursorPosition();
1865         }
1866         QVariantList sel;
1867         sel << start << end;
1868         connection.send(message.createReply(sel));
1869     } else if (function == "GetText") {
1870         int startOffset = message.arguments().at(0).toInt();
1871         int endOffset = message.arguments().at(1).toInt();
1872         if (endOffset == -1) // AT-SPI uses -1 to signal all characters
1873             endOffset = interface->textInterface()->characterCount();
1874         sendReply(connection, message, interface->textInterface()->text(startOffset, endOffset));
1875     } else if (function == "GetTextAfterOffset") {
1876         int offset = message.arguments().at(0).toInt();
1877         int type = message.arguments().at(1).toUInt();
1878         int startOffset, endOffset;
1879         QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1880         QVariantList ret;
1881         ret << text << startOffset << endOffset;
1882         connection.send(message.createReply(ret));
1883     } else if (function == "GetTextAtOffset") {
1884         int offset = message.arguments().at(0).toInt();
1885         int type = message.arguments().at(1).toUInt();
1886         int startOffset, endOffset;
1887         QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1888         QVariantList ret;
1889         ret << text << startOffset << endOffset;
1890         connection.send(message.createReply(ret));
1891     } else if (function == "GetTextBeforeOffset") {
1892         int offset = message.arguments().at(0).toInt();
1893         int type = message.arguments().at(1).toUInt();
1894         int startOffset, endOffset;
1895         QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset);
1896         QVariantList ret;
1897         ret << text << startOffset << endOffset;
1898         connection.send(message.createReply(ret));
1899     } else if (function == "RemoveSelection") {
1900         int selectionNum = message.arguments().at(0).toInt();
1901         interface->textInterface()->removeSelection(selectionNum);
1902         sendReply(connection, message, true);
1903     } else if (function == "SetCaretOffset") {
1904         int offset = message.arguments().at(0).toInt();
1905         interface->textInterface()->setCursorPosition(offset);
1906         sendReply(connection, message, true);
1907     } else if (function == "SetSelection") {
1908         int selectionNum = message.arguments().at(0).toInt();
1909         int startOffset = message.arguments().at(1).toInt();
1910         int endOffset = message.arguments().at(2).toInt();
1911         interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
1912         sendReply(connection, message, true);
1913     } else {
1914         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
1915         return false;
1916     }
1917     return true;
1918 }
1919
1920 QAccessible2::BoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTextBoundaryType) const
1921 {
1922     switch (atspiTextBoundaryType) {
1923     case ATSPI_TEXT_BOUNDARY_CHAR:
1924         return QAccessible2::CharBoundary;
1925     case ATSPI_TEXT_BOUNDARY_WORD_START:
1926     case ATSPI_TEXT_BOUNDARY_WORD_END:
1927         return QAccessible2::WordBoundary;
1928     case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
1929     case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
1930         return QAccessible2::SentenceBoundary;
1931     case ATSPI_TEXT_BOUNDARY_LINE_START:
1932     case ATSPI_TEXT_BOUNDARY_LINE_END:
1933         return QAccessible2::LineBoundary;
1934     }
1935     Q_ASSERT_X(0, "", "Requested invalid boundary type.");
1936     return QAccessible2::CharBoundary;
1937 }
1938
1939 // FIXME all attribute methods below should share code
1940 QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
1941 {
1942     Q_UNUSED(includeDefaults);
1943
1944     QSpiAttributeSet set;
1945     int startOffset;
1946     int endOffset;
1947
1948     QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
1949     QStringList attributes = joined.split (';', QString::SkipEmptyParts, Qt::CaseSensitive);
1950     foreach (const QString &attr, attributes) {
1951         QStringList items;
1952         items = attr.split(':', QString::SkipEmptyParts, Qt::CaseSensitive);
1953         set[items[0]] = items[1];
1954     }
1955
1956     QVariantList list;
1957     list << QVariant::fromValue(set) << startOffset << endOffset;
1958
1959     return list;
1960 }
1961
1962 QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, int offset, const QString &attributeName) const
1963 {
1964     QString     mapped;
1965     QString     joined;
1966     QStringList attributes;
1967     QSpiAttributeSet map;
1968     int startOffset;
1969     int endOffset;
1970     bool defined;
1971
1972     joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
1973     attributes = joined.split (';', QString::SkipEmptyParts, Qt::CaseSensitive);
1974     foreach (const QString& attr, attributes) {
1975         QStringList items;
1976         items = attr.split(':', QString::SkipEmptyParts, Qt::CaseSensitive);
1977         map[items[0]] = items[1];
1978     }
1979     mapped = map[attributeName];
1980     if (mapped == QString())
1981        defined = true;
1982     else
1983        defined = false;
1984     QVariantList list;
1985     list << mapped << startOffset << endOffset << defined;
1986     return list;
1987 }
1988
1989 QRect AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const
1990 {
1991     QRect rect = interface->textInterface()->characterRect(offset, QAccessible2::RelativeToScreen);
1992     if (coordType == ATSPI_COORD_TYPE_WINDOW)
1993         rect = translateRectToWindowCoordinates(interface, rect);
1994     return rect;
1995 }
1996
1997 QRect AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface,
1998                                     int startOffset, int endOffset, uint coordType) const
1999 {
2000     if (endOffset == -1)
2001         endOffset = interface->textInterface()->characterCount();
2002
2003     if (endOffset <= startOffset) {
2004         return QRect();
2005     }
2006
2007     QRect rect = interface->textInterface()->characterRect(startOffset, QAccessible2::RelativeToScreen);
2008     for (int i=startOffset + 1; i <= endOffset; i++) {
2009         rect = rect | interface->textInterface()->characterRect(i, QAccessible2::RelativeToScreen);
2010     }
2011
2012     // relative to window
2013     if (coordType == ATSPI_COORD_TYPE_WINDOW)
2014         rect = translateRectToWindowCoordinates(interface, rect);
2015
2016     return rect;
2017 }
2018
2019 QRect translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect)
2020 {
2021     QAccessibleInterface *window = getWindow(interface);
2022     if (window) {
2023         QRect ret = rect.translated(-window->rect(0).x(), -window->rect(0).y());
2024         delete window;
2025         return ret;
2026     }
2027
2028     return rect;
2029 }
2030
2031 // Editable Text interface
2032 bool AtSpiAdaptor::editableTextInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2033 {
2034     Q_ASSERT(child == 0); // We should never claim to have a text interface on a virtual child
2035     if (!interface->editableTextInterface()) {
2036         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find editable text interface for: " << message.path() << interface;
2037         return false;
2038     }
2039
2040     if (function == "CopyText") {
2041         int startPos = message.arguments().at(0).toInt();
2042         int endPos = message.arguments().at(1).toInt();
2043         interface->editableTextInterface()->copyText(startPos, endPos);
2044         connection.send(message.createReply(true));
2045     } else if (function == "CutText") {
2046         int startPos = message.arguments().at(0).toInt();
2047         int endPos = message.arguments().at(1).toInt();
2048         interface->editableTextInterface()->cutText(startPos, endPos);
2049         connection.send(message.createReply(true));
2050     } else if (function == "DeleteText") {
2051         int startPos = message.arguments().at(0).toInt();
2052         int endPos = message.arguments().at(1).toInt();
2053         interface->editableTextInterface()->deleteText(startPos, endPos);
2054         connection.send(message.createReply(true));
2055     } else if (function == "InsertText") {
2056         int position = message.arguments().at(0).toInt();
2057         QString text = message.arguments().at(1).toString();
2058         int length = message.arguments().at(2).toInt();
2059         QString resized (text);
2060         resized.resize(length);
2061         interface->editableTextInterface()->insertText(position, resized);
2062         connection.send(message.createReply(true));
2063     } else if (function == "PasteText") {
2064         int position = message.arguments().at(0).toInt();
2065         interface->editableTextInterface()->pasteText(position);
2066         connection.send(message.createReply(true));
2067     } else if (function == "SetTextContents") {
2068         QString newContents = message.arguments().at(0).toString();
2069         interface->editableTextInterface()->replaceText(0, interface->textInterface()->characterCount(), newContents);
2070         connection.send(message.createReply(true));
2071     } else if (function == "") {
2072         connection.send(message.createReply());
2073     } else {
2074         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
2075         return false;
2076     }
2077     return true;
2078 }
2079
2080 // Value interface
2081 bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2082 {
2083     Q_ASSERT(child == 0);
2084     if (!interface->valueInterface()) {
2085         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find value interface for: " << message.path() << interface;
2086         return false;
2087     }
2088
2089     if (0) {
2090     } else if (function == "SetCurrentValue") {
2091         QDBusVariant v = message.arguments().at(2).value<QDBusVariant>();
2092         double value = v.variant().toDouble();
2093         //Temporal fix
2094         //See https://bugzilla.gnome.org/show_bug.cgi?id=652596
2095         interface->valueInterface()->setCurrentValue(value);
2096         connection.send(message.createReply()); // FIXME is the reply needed?
2097     } else if (function == "GetCurrentValue") {
2098         bool success;
2099         double val = interface->valueInterface()->currentValue().toDouble(&success);
2100         if (!success) {
2101             qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2102         }
2103         connection.send(message.createReply(
2104                             QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2105     } else if (function == "GetMaximumValue") {
2106         bool success;
2107         double val = interface->valueInterface()->maximumValue().toDouble(&success);
2108         if (!success) {
2109             qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2110         }
2111         connection.send(message.createReply(
2112                             QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2113     } else if (function == "GetMinimumIncrement") {
2114         connection.send(message.createReply(
2115                             QVariant::fromValue(QDBusVariant(QVariant::fromValue(0.0)))));
2116     } else if (function == "GetMinimumValue") {
2117         bool success;
2118         double val = interface->valueInterface()->minimumValue().toDouble(&success);
2119         if (!success) {
2120             qWarning ("AtSpiAdaptor::valueInterface: Could not convert current value to double.");
2121         }
2122         connection.send(message.createReply(
2123                             QVariant::fromValue(QDBusVariant(QVariant::fromValue(val)))));
2124     } else {
2125         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
2126         return false;
2127     }
2128     return true;
2129 }
2130
2131 // Table interface
2132 bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, int child, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
2133 {
2134     Q_ASSERT(child == 0);
2135     if (!interface->table2Interface()) {
2136         qWarning() << "WARNING Qt AtSpiAdaptor: Could not find table interface for: " << message.path() << interface;
2137         return false;
2138     }
2139
2140     if (0) {
2141     // properties
2142     } else if (function == "GetCaption") {
2143         // fixme: leak of QAI
2144         QAccessibleInterface *caption = interface->table2Interface()->caption();
2145         if (!caption)
2146             caption = interface->tableInterface() ? interface->tableInterface()->caption() : 0;
2147
2148         QObject *object = caption ? caption->object() : 0;
2149         if (!object) {
2150             connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(QSpiObjectReference())))));
2151         } else {
2152             QDBusObjectPath path(pathForObject(object));
2153             QSpiObjectReference ref(connection, path);
2154             connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
2155         }
2156     } else if (function == "GetNColumns") {
2157         connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2158             QVariant::fromValue(interface->table2Interface()->columnCount())))));
2159     } else if (function == "GetNRows") {
2160         connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2161             QVariant::fromValue(interface->table2Interface()->rowCount())))));
2162     } else if (function == "GetNSelectedColumns") {
2163         connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2164             QVariant::fromValue(interface->table2Interface()->selectedColumnCount())))));
2165     } else if (function == "GetNSelectedRows") {
2166         connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
2167             QVariant::fromValue(interface->table2Interface()->selectedRowCount())))));
2168     } else if (function == "GetSummary") {
2169         // fixme: leak of QAI
2170         QAccessibleInterface *summary = interface->table2Interface()->summary();
2171         if (!summary)
2172             summary = interface->tableInterface() ? interface->tableInterface()->summary() : 0;
2173
2174         QObject *object = summary ? summary->object() : 0;
2175         if (!object) {
2176             QDBusMessage reply = message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(QSpiObjectReference()))));
2177             qDebug() << "signature: " << reply.signature();
2178             connection.send(reply);
2179         } else {
2180             QDBusObjectPath path(pathForObject(object));
2181             QSpiObjectReference ref(connection, path);
2182             connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
2183         }
2184
2185     // methods
2186     } else if (function == "GetAccessibleAt") {
2187         int row = message.arguments().at(0).toInt();
2188         int column = message.arguments().at(1).toInt();
2189         Q_ASSERT(interface->table2Interface());
2190         Q_ASSERT(row >= 0);
2191         Q_ASSERT(column >= 0);
2192         Q_ASSERT(row < interface->table2Interface()->rowCount());
2193         Q_ASSERT(column < interface->table2Interface()->columnCount());
2194
2195         QSpiObjectReference ref;
2196         QAccessibleInterface* cell = interface->table2Interface()->cellAt(row, column);
2197         if (cell) {
2198             ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell, 0)));
2199             delete cell;
2200         } else {
2201             qWarning() << "WARNING: no cell interface returned for " << interface->object() << row << column;
2202             ref = QSpiObjectReference();
2203         }
2204         connection.send(message.createReply(QVariant::fromValue(ref)));
2205
2206     } else if (function == "GetIndexAt") {
2207         int row = message.arguments().at(0).toInt();
2208         int column = message.arguments().at(1).toInt();
2209         QAccessibleInterface *cell = interface->table2Interface()->cellAt(row, column);
2210         int index = interface->indexOfChild(cell);
2211         qDebug() << "QSpiAdaptor::GetIndexAt" << row << column << index;
2212         Q_ASSERT(index > 0);
2213         delete cell;
2214         connection.send(message.createReply(index));
2215
2216     } else if (function == "GetColumnAtIndex") {
2217         int index = message.arguments().at(0).toInt();
2218         int ret = -1;
2219         if (index >= 0) {
2220             QAccessibleInterface *iface;
2221             interface->navigate(QAccessible::Child, index + 1, &iface);
2222             if (iface) {
2223                 if (iface->role(0) == QAccessible::ColumnHeader) {
2224                     ret = index;
2225                 } else if (iface->role(0) == QAccessible::RowHeader) {
2226                     ret = -1;
2227                 } else {
2228                     QAccessibleTable2CellInterface *cell = static_cast<QAccessibleTable2CellInterface*>(iface);
2229                     ret = cell->columnIndex();
2230                     delete cell;
2231                 }
2232             }
2233         }
2234         connection.send(message.createReply(ret));
2235     } else if (function == "GetRowAtIndex") {
2236         // FIXME merge with GetColumnAtIndex
2237         int index = message.arguments().at(0).toInt();
2238         int ret = -1;
2239         if (index >= 0) {
2240             QAccessibleInterface *iface;
2241             interface->navigate(QAccessible::Child, index + 1, &iface);
2242             if (iface) {
2243                 if (iface->role(0) == QAccessible::ColumnHeader) {
2244                     ret = -1;
2245                 } else if (iface->role(0) == QAccessible::RowHeader) {
2246                     ret = index % interface->table2Interface()->columnCount();
2247                 } else {
2248                     QAccessibleTable2CellInterface *cell = static_cast<QAccessibleTable2CellInterface*>(iface);
2249                     ret = cell->rowIndex();
2250                     delete cell;
2251                 }
2252             }
2253         }
2254         connection.send(message.createReply(ret));
2255
2256     } else if (function == "GetColumnDescription") {
2257         int column = message.arguments().at(0).toInt();
2258         connection.send(message.createReply(interface->table2Interface()->columnDescription(column)));
2259     } else if (function == "GetRowDescription") {
2260         int row = message.arguments().at(0).toInt();
2261         connection.send(message.createReply(interface->table2Interface()->rowDescription(row)));
2262
2263
2264
2265     } else if (function == "GetRowColumnExtentsAtIndex") {
2266         int index = message.arguments().at(0).toInt();
2267         bool success = false;
2268
2269         int row, col, rowExtents, colExtents;
2270         bool isSelected;
2271
2272         int cols = interface->table2Interface()->columnCount();
2273         row = index/cols;
2274         col = index%cols;
2275         QAccessibleTable2CellInterface *cell = interface->table2Interface()->cellAt(row, col);
2276         if (cell) {
2277             cell->rowColumnExtents(&row, &col, &rowExtents, &colExtents, &isSelected);
2278             success = true;
2279             delete cell;
2280         }
2281
2282         QVariantList list;
2283         list << success << row << col << rowExtents << colExtents << isSelected;
2284         connection.send(message.createReply(list));
2285
2286     } else if (function == "GetColumnExtentAt") {
2287         int row = message.arguments().at(0).toInt();
2288         int column = message.arguments().at(1).toInt();
2289         connection.send(message.createReply(interface->table2Interface()->cellAt(row, column)->columnExtent()));
2290
2291     } else if (function == "GetRowExtentAt") {
2292         int row = message.arguments().at(0).toInt();
2293         int column = message.arguments().at(1).toInt();
2294         connection.send(message.createReply(interface->table2Interface()->cellAt(row, column)->rowExtent()));
2295
2296     } else if (function == "GetColumnHeader") {
2297         int column = message.arguments().at(0).toInt();
2298         QSpiObjectReference ref;
2299
2300         QAccessibleTable2CellInterface *cell = interface->table2Interface()->cellAt(0, column);
2301         if (cell) {
2302             QList<QAccessibleInterface*> header = cell->columnHeaderCells();
2303             delete cell;
2304             if (header.size() > 0) {
2305                 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.at(0), 0)));
2306                 qDeleteAll(header);
2307             }
2308         }
2309         connection.send(message.createReply(QVariant::fromValue(ref)));
2310
2311     } else if (function == "GetRowHeader") {
2312         int row = message.arguments().at(0).toInt();
2313         QSpiObjectReference ref;
2314         QAccessibleTable2CellInterface *cell = interface->table2Interface()->cellAt(row, 0);
2315         if (cell) {
2316             QList<QAccessibleInterface*> header = cell->rowHeaderCells();
2317             delete cell;
2318             if (header.size() > 0) {
2319                 ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(header.at(0), 0)));
2320                 qDeleteAll(header);
2321             }
2322         }
2323         connection.send(message.createReply(QVariant::fromValue(ref)));
2324
2325     } else if (function == "GetSelectedColumns") {
2326         connection.send(message.createReply(QVariant::fromValue(interface->table2Interface()->selectedColumns())));
2327     } else if (function == "GetSelectedRows") {
2328         connection.send(message.createReply(QVariant::fromValue(interface->table2Interface()->selectedRows())));
2329     } else if (function == "IsColumnSelected") {
2330         int column = message.arguments().at(0).toInt();
2331         connection.send(message.createReply(interface->table2Interface()->isColumnSelected(column)));
2332     } else if (function == "IsRowSelected") {
2333         int row = message.arguments().at(0).toInt();
2334         connection.send(message.createReply(interface->table2Interface()->isRowSelected(row)));
2335     } else if (function == "IsSelected") {
2336         int row = message.arguments().at(0).toInt();
2337         int column = message.arguments().at(1).toInt();
2338         QAccessibleTable2CellInterface* cell = interface->table2Interface()->cellAt(row, column);
2339         connection.send(message.createReply(cell->isSelected()));
2340         delete cell;
2341     } else if (function == "AddColumnSelection") {
2342         int column = message.arguments().at(0).toInt();
2343         connection.send(message.createReply(interface->table2Interface()->selectColumn(column)));
2344     } else if (function == "AddRowSelection") {
2345         int row = message.arguments().at(0).toInt();
2346         connection.send(message.createReply(interface->table2Interface()->selectRow(row)));
2347     } else if (function == "RemoveColumnSelection") {
2348         int column = message.arguments().at(0).toInt();
2349         connection.send(message.createReply(interface->table2Interface()->unselectColumn(column)));
2350     } else if (function == "RemoveRowSelection") {
2351         int row = message.arguments().at(0).toInt();
2352         connection.send(message.createReply(interface->table2Interface()->unselectRow(row)));
2353     } else {
2354         qWarning() << "WARNING: AtSpiAdaptor::handleMessage does not implement " << function << message.path();
2355         return false;
2356     }
2357     return true;
2358 }