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