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