2.38.0
[platform/upstream/at-spi2-atk.git] / atk-adaptor / adaptors / accessible-adaptor.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008 Novell, Inc.
6  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include <atk/atk.h>
26 #include <droute/droute.h>
27 #include "bridge.h"
28
29 #include "atspi/atspi.h"
30 #include "spi-dbus.h"
31 #include "accessible-stateset.h"
32 #include "object.h"
33 #include "introspection.h"
34 #include <string.h>
35
36 static dbus_bool_t
37 impl_get_Name (DBusMessageIter * iter, void *user_data)
38 {
39   AtkObject *object = (AtkObject *) user_data;
40
41   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
42
43   return droute_return_v_string (iter, atk_object_get_name (object));
44 }
45
46 static dbus_bool_t
47 impl_get_Description (DBusMessageIter * iter, void *user_data)
48 {
49   AtkObject *object = (AtkObject *) user_data;
50
51   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
52
53   return droute_return_v_string (iter, atk_object_get_description (object));
54 }
55
56 static dbus_bool_t
57 impl_get_Locale (DBusMessageIter * iter, void *user_data)
58 {
59   AtkObject *object = (AtkObject *) user_data;
60
61   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
62
63   return droute_return_v_string (iter, atk_object_get_object_locale (object));
64 }
65
66 static dbus_bool_t
67 impl_get_Parent (DBusMessageIter * iter, void *user_data)
68 {
69   AtkObject *obj = (AtkObject *) user_data;
70   AtkObject *parent;
71   DBusMessageIter iter_variant;
72   dbus_uint32_t role;
73
74   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
75
76   role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
77
78   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
79                                     &iter_variant);
80
81   parent = atk_object_get_parent (obj);
82   if (parent == NULL)
83     {
84       /* TODO, move in to a 'Plug' wrapper. */
85       if (ATK_IS_PLUG (obj))
86         {
87           char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
88           char *bus_parent;
89           char *path_parent;
90
91           if (id)
92             {
93               bus_parent = g_strdup (id);
94               if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
95                 {
96                   DBusMessageIter iter_parent;
97                   *(path_parent++) = '\0';
98                   dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
99                                                     &iter_parent);
100                   dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
101                   dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
102                   dbus_message_iter_close_container (&iter_variant, &iter_parent);
103                 }
104               else
105                 {
106                   spi_object_append_null_reference (&iter_variant);
107                 }
108             }
109           else
110             {
111               spi_object_append_null_reference (&iter_variant);
112             }
113         }
114       else if (role != ATSPI_ROLE_APPLICATION)
115          spi_object_append_null_reference (&iter_variant);
116       else
117          spi_object_append_desktop_reference (&iter_variant);
118       }
119   else
120     {
121       spi_object_append_reference (&iter_variant, parent);
122     }
123
124
125   dbus_message_iter_close_container (iter, &iter_variant);
126   return TRUE;
127 }
128
129 static dbus_bool_t
130 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
131 {
132   AtkObject *object = (AtkObject *) user_data;
133   int childCount;
134
135   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
136
137   childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
138                ? 1
139                : atk_object_get_n_accessible_children (object);
140   return droute_return_v_int32 (iter, childCount);
141 }
142
143 static DBusMessage *
144 impl_GetChildAtIndex (DBusConnection * bus,
145                       DBusMessage * message, void *user_data)
146 {
147   AtkObject *object = (AtkObject *) user_data;
148   DBusMessage *reply;
149   dbus_int32_t i;
150   AtkObject *child;
151
152   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
153                         droute_not_yet_handled_error (message));
154   if (!dbus_message_get_args 
155        (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
156     {
157       return droute_invalid_arguments_error (message);
158     }
159
160   if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
161     {
162       AtkSocket *socket = ATK_SOCKET (object);
163       gchar *child_name, *child_path;
164       child_name = g_strdup (socket->embedded_plug_id);
165       child_path = g_utf8_strchr (child_name + 1, -1, ':');
166       if (child_path)
167         {
168           DBusMessageIter iter, iter_socket;
169           *(child_path++) = '\0';
170           reply = dbus_message_new_method_return (message);
171           if (!reply)
172             return NULL;
173           dbus_message_iter_init_append (reply, &iter);
174           dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
175                                             &iter_socket);
176           dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
177           dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
178           dbus_message_iter_close_container (&iter, &iter_socket);
179           return reply;
180         }
181       g_free (child_name);
182     }
183   child = atk_object_ref_accessible_child (object, i);
184   reply = spi_object_return_reference (message, child);
185   if (child)
186     g_object_unref (child);
187
188   return reply;
189 }
190
191 static DBusMessage *
192 impl_GetChildren (DBusConnection * bus,
193                   DBusMessage * message, void *user_data)
194 {
195   AtkObject *object = (AtkObject *) user_data;
196   gint i;
197   gint count;
198   DBusMessage *reply;
199   DBusMessageIter iter, iter_array;
200
201   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
202                         droute_not_yet_handled_error (message));
203   count = atk_object_get_n_accessible_children (object);
204   reply = dbus_message_new_method_return (message);
205   if (!reply)
206     goto oom;
207   dbus_message_iter_init_append (reply, &iter);
208   if (!dbus_message_iter_open_container
209       (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
210     goto oom;
211   for (i = 0; i < count; i++)
212     {
213       AtkObject *child = atk_object_ref_accessible_child (object, i);
214       spi_object_append_reference (&iter_array, child); 
215       if (child)
216         g_object_unref (child);
217     }
218   if (!dbus_message_iter_close_container (&iter, &iter_array))
219     goto oom;
220   return reply;
221 oom:
222   // TODO: handle out-of-memory
223   return reply;
224 }
225
226 static DBusMessage *
227 impl_GetIndexInParent (DBusConnection * bus,
228                        DBusMessage * message, void *user_data)
229 {
230   AtkObject *object = (AtkObject *) user_data;
231   dbus_int32_t rv;
232   DBusMessage *reply;
233
234   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
235                         droute_not_yet_handled_error (message));
236
237   rv = atk_object_get_index_in_parent (object);
238   reply = dbus_message_new_method_return (message);
239   dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv, DBUS_TYPE_INVALID);
240   return reply;
241 }
242
243 static gboolean
244 spi_init_relation_type_table (AtspiRelationType * types)
245 {
246   gint i;
247
248   for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
249     types[i] = ATSPI_RELATION_NULL;
250
251   types[ATK_RELATION_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY;
252   types[ATK_RELATION_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR;
253   types[ATK_RELATION_LABEL_FOR] = ATSPI_RELATION_LABEL_FOR;
254   types[ATK_RELATION_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY;
255   types[ATK_RELATION_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF;
256   types[ATK_RELATION_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF;
257   types[ATK_RELATION_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO;
258   types[ATK_RELATION_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM;
259   types[ATK_RELATION_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF;
260   types[ATK_RELATION_EMBEDS] = ATSPI_RELATION_EMBEDS;
261   types[ATK_RELATION_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY;
262   types[ATK_RELATION_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR;
263   types[ATK_RELATION_PARENT_WINDOW_OF] =
264     ATSPI_RELATION_PARENT_WINDOW_OF;
265   types[ATK_RELATION_DESCRIPTION_FOR] =
266     ATSPI_RELATION_DESCRIPTION_FOR;
267   types[ATK_RELATION_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY;
268   types[ATK_RELATION_DETAILS] = ATSPI_RELATION_DETAILS;
269   types[ATK_RELATION_DETAILS_FOR] = ATSPI_RELATION_DETAILS_FOR;
270   types[ATK_RELATION_ERROR_MESSAGE] = ATSPI_RELATION_ERROR_MESSAGE;
271   types[ATK_RELATION_ERROR_FOR] = ATSPI_RELATION_ERROR_FOR;
272   types[ATK_RELATION_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF;
273
274   return TRUE;
275 }
276
277 static AtspiRelationType
278 spi_relation_type_from_atk_relation_type (AtkRelationType type)
279 {
280   static gboolean is_initialized = FALSE;
281   static AtspiRelationType
282     spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
283   AtspiRelationType spi_type;
284
285   if (!is_initialized)
286     is_initialized = spi_init_relation_type_table (spi_relation_type_table);
287
288   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
289     spi_type = spi_relation_type_table[type];
290   else
291     spi_type = ATSPI_RELATION_EXTENDED;
292   return spi_type;
293 }
294
295 static DBusMessage *
296 impl_GetRelationSet (DBusConnection * bus,
297                      DBusMessage * message, void *user_data)
298 {
299   AtkObject *object = (AtkObject *) user_data;
300   DBusMessage *reply;
301   AtkRelationSet *set;
302   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
303   gint count;
304   gint i, j;
305
306   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
307                         droute_not_yet_handled_error (message));
308   reply = dbus_message_new_method_return (message);
309   if (!reply)
310     return NULL;
311   set = atk_object_ref_relation_set (object);
312   dbus_message_iter_init_append (reply, &iter);
313   if (!dbus_message_iter_open_container
314       (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
315     {
316       goto oom;
317     }
318   count = 0;
319   if (set)
320     count = atk_relation_set_get_n_relations (set);
321   for (i = 0; i < count; i++)
322     {
323       AtkRelation *r = atk_relation_set_get_relation (set, i);
324       AtkRelationType rt;
325       GPtrArray *target;
326       dbus_uint32_t type;
327       if (!r)
328         continue;
329       rt = atk_relation_get_relation_type (r);
330       type = spi_relation_type_from_atk_relation_type (rt);
331       target = atk_relation_get_target (r);
332       if (!dbus_message_iter_open_container
333           (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
334         {
335           goto oom;
336         }
337       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
338       if (!dbus_message_iter_open_container
339           (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
340         {
341           goto oom;
342         }
343       for (j = 0; j < target->len; j++)
344         {
345           AtkObject *obj = target->pdata[j];
346           if (!obj)
347             continue;
348           spi_object_append_reference (&iter_targets, obj);
349         }
350       dbus_message_iter_close_container (&iter_struct, &iter_targets);
351       dbus_message_iter_close_container (&iter_array, &iter_struct);
352     }
353   dbus_message_iter_close_container (&iter, &iter_array);
354 oom:
355   if (set)
356     g_object_unref (set);
357   // TODO: handle out of memory */
358   return reply;
359 }
360
361 static DBusMessage *
362 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
363 {
364   AtkObject *object = (AtkObject *) user_data;
365   gint role;
366   dbus_uint32_t rv;
367   DBusMessage *reply;
368
369   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
370                         droute_not_yet_handled_error (message));
371   role = atk_object_get_role (object);
372   rv = spi_accessible_role_from_atk_role (role);
373   reply = dbus_message_new_method_return (message);
374   if (reply)
375     {
376       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
377                                 DBUS_TYPE_INVALID);
378     }
379   return reply;
380 }
381
382 static DBusMessage *
383 impl_GetRoleName (DBusConnection * bus,
384                   DBusMessage * message, void *user_data)
385 {
386   AtkObject *object = (AtkObject *) user_data;
387   gint role;
388   const char *role_name;
389   DBusMessage *reply;
390
391   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
392                         droute_not_yet_handled_error (message));
393   role = atk_object_get_role (object);
394   role_name = atk_role_get_name (role);
395   if (!role_name)
396     role_name = "";
397   reply = dbus_message_new_method_return (message);
398   if (reply)
399     {
400       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
401                                 DBUS_TYPE_INVALID);
402     }
403   return reply;
404 }
405
406 static DBusMessage *
407 impl_GetLocalizedRoleName (DBusConnection * bus,
408                            DBusMessage * message, void *user_data)
409 {
410   AtkObject *object = (AtkObject *) user_data;
411   gint role;
412   const char *role_name;
413   DBusMessage *reply;
414
415   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
416                         droute_not_yet_handled_error (message));
417   role = atk_object_get_role (object);
418   role_name = atk_role_get_localized_name (role);
419   if (!role_name)
420     role_name = "";
421   reply = dbus_message_new_method_return (message);
422   if (reply)
423     {
424       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
425                                 DBUS_TYPE_INVALID);
426     }
427   return reply;
428 }
429
430 static DBusMessage *
431 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
432 {
433   AtkObject *object = (AtkObject *) user_data;
434
435   DBusMessage *reply = NULL;
436   DBusMessageIter iter, iter_array;
437
438   dbus_uint32_t states[2];
439
440   guint count;
441
442   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
443                         droute_not_yet_handled_error (message));
444
445   reply = dbus_message_new_method_return (message);
446   dbus_message_iter_init_append (reply, &iter);
447
448   spi_atk_state_to_dbus_array (object, states);
449   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
450   for (count = 0; count < 2; count++)
451     {
452       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
453                                       &states[count]);
454     }
455   dbus_message_iter_close_container (&iter, &iter_array);
456   return reply;
457 }
458
459 static DBusMessage *
460 impl_GetAttributes (DBusConnection * bus,
461                     DBusMessage * message, void *user_data)
462 {
463   AtkObject *object = (AtkObject *) user_data;
464   AtkAttributeSet *attributes;
465   DBusMessage *reply = NULL;
466   DBusMessageIter iter;
467
468   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
469                         droute_not_yet_handled_error (message));
470
471   attributes = atk_object_get_attributes (object);
472
473   reply = dbus_message_new_method_return (message);
474   dbus_message_iter_init_append (reply, &iter);
475   spi_object_append_attribute_set (&iter, attributes);
476
477   atk_attribute_set_free (attributes);
478
479   return reply;
480 }
481
482 static dbus_bool_t
483 impl_get_Attributes (DBusMessageIter * iter, void *user_data)
484 {
485   DBusMessageIter iter_variant;
486   AtkObject *object = (AtkObject *) user_data;
487   AtkAttributeSet *attributes;
488
489   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
490
491   attributes = atk_object_get_attributes (object);
492
493   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "a{ss}", &iter_variant);
494   spi_object_append_attribute_set (&iter_variant, attributes);
495   dbus_message_iter_close_container (iter, &iter_variant);
496
497   atk_attribute_set_free (attributes);
498
499   return TRUE;
500 }
501
502 static DBusMessage *
503 impl_GetApplication (DBusConnection * bus,
504                      DBusMessage * message, void *user_data)
505 {
506   return spi_object_return_reference (message, atk_get_root ());
507 }
508
509 static DBusMessage *
510 impl_GetInterfaces (DBusConnection * bus,
511                     DBusMessage * message, void *user_data)
512 {
513   AtkObject *object = (AtkObject *) user_data;
514   DBusMessage *reply;
515   DBusMessageIter iter, iter_array;
516
517   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
518                         droute_not_yet_handled_error (message));
519   reply = dbus_message_new_method_return (message);
520   if (reply)
521     {
522       dbus_message_iter_init_append (reply, &iter);
523       dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
524                                         &iter_array);
525       spi_object_append_interfaces (&iter_array, object);
526       dbus_message_iter_close_container (&iter, &iter_array);
527     }
528   return reply;
529 }
530
531 static dbus_bool_t
532 impl_get_AccessibleId (DBusMessageIter * iter, void *user_data)
533 {
534   AtkObject *object = (AtkObject *) user_data;
535
536   g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
537
538   return droute_return_v_string (iter, atk_object_get_accessible_id (object));
539 }
540
541 static DRouteMethod methods[] = {
542   {impl_GetChildAtIndex, "GetChildAtIndex"},
543   {impl_GetChildren, "GetChildren"},
544   {impl_GetIndexInParent, "GetIndexInParent"},
545   {impl_GetRelationSet, "GetRelationSet"},
546   {impl_GetRole, "GetRole"},
547   {impl_GetRoleName, "GetRoleName"},
548   {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
549   {impl_GetState, "GetState"},
550   {impl_GetAttributes, "GetAttributes"},
551   {impl_GetApplication, "GetApplication"},
552   {impl_GetInterfaces, "GetInterfaces"},
553   {NULL, NULL}
554 };
555
556 static DRouteProperty properties[] = {
557   {impl_get_Name, NULL, "Name"},
558   {impl_get_Description, NULL, "Description"},
559   {impl_get_Locale, NULL, "Locale"},
560   {impl_get_Parent, NULL, "Parent"},
561   {impl_get_ChildCount, NULL, "ChildCount"},
562   {impl_get_Attributes, NULL, "Attributes"},
563   {impl_get_AccessibleId, NULL, "AccessibleId"},
564   {NULL, NULL, NULL}
565 };
566
567 void
568 spi_initialize_accessible (DRoutePath * path)
569 {
570   spi_atk_add_interface (path,
571                          ATSPI_DBUS_INTERFACE_ACCESSIBLE,
572                          spi_org_a11y_atspi_Accessible, 
573                          methods, properties);
574 };