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