a8789c9436a9238c55313160362e8266e87b9b46
[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 (ATK_SOCKET (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   types[ATK_RELATION_NODE_PARENT_OF] = Accessibility_RELATION_NODE_PARENT_OF;
281
282   return TRUE;
283 }
284
285 static Accessibility_RelationType
286 spi_relation_type_from_atk_relation_type (AtkRelationType type)
287 {
288   static gboolean is_initialized = FALSE;
289   static Accessibility_RelationType
290     spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
291   Accessibility_RelationType spi_type;
292
293   if (!is_initialized)
294     is_initialized = spi_init_relation_type_table (spi_relation_type_table);
295
296   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
297     spi_type = spi_relation_type_table[type];
298   else
299     spi_type = Accessibility_RELATION_EXTENDED;
300   return spi_type;
301 }
302
303 static DBusMessage *
304 impl_GetRelationSet (DBusConnection * bus,
305                      DBusMessage * message, void *user_data)
306 {
307   AtkObject *object = (AtkObject *) user_data;
308   DBusMessage *reply;
309   AtkRelationSet *set;
310   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
311   gint count;
312   gint i, j;
313
314   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
315                         droute_not_yet_handled_error (message));
316   reply = dbus_message_new_method_return (message);
317   if (!reply)
318     return NULL;
319   set = atk_object_ref_relation_set (object);
320   dbus_message_iter_init_append (reply, &iter);
321   if (!dbus_message_iter_open_container
322       (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
323     {
324       goto oom;
325     }
326   count = 0;
327   if (set)
328     count = atk_relation_set_get_n_relations (set);
329   for (i = 0; i < count; i++)
330     {
331       AtkRelation *r = atk_relation_set_get_relation (set, i);
332       AtkRelationType rt;
333       GPtrArray *target;
334       dbus_uint32_t type;
335       if (!r)
336         continue;
337       rt = atk_relation_get_relation_type (r);
338       type = spi_relation_type_from_atk_relation_type (rt);
339       target = atk_relation_get_target (r);
340       if (!dbus_message_iter_open_container
341           (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
342         {
343           goto oom;
344         }
345       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
346       if (!dbus_message_iter_open_container
347           (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
348         {
349           goto oom;
350         }
351       for (j = 0; j < target->len; j++)
352         {
353           AtkObject *obj = target->pdata[j];
354           char *path;
355           if (!obj)
356             continue;
357           spi_object_append_reference (&iter_targets, obj);
358         }
359       dbus_message_iter_close_container (&iter_struct, &iter_targets);
360       dbus_message_iter_close_container (&iter_array, &iter_struct);
361     }
362   dbus_message_iter_close_container (&iter, &iter_array);
363 oom:
364   // TODO: handle out of memory */
365   return reply;
366 }
367
368 static DBusMessage *
369 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
370 {
371   AtkObject *object = (AtkObject *) user_data;
372   gint role;
373   dbus_uint32_t rv;
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   rv = spi_accessible_role_from_atk_role (role);
380   reply = dbus_message_new_method_return (message);
381   if (reply)
382     {
383       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
384                                 DBUS_TYPE_INVALID);
385     }
386   return reply;
387 }
388
389 static char *
390 impl_get_role_str (void *datum)
391 {
392   g_return_val_if_fail (ATK_IS_OBJECT (datum), g_strdup (""));
393   return g_strdup_printf ("%d",
394                           spi_accessible_role_from_atk_role
395                           (atk_object_get_role ((AtkObject *) datum)));
396 }
397
398 static DBusMessage *
399 impl_GetRoleName (DBusConnection * bus,
400                   DBusMessage * message, void *user_data)
401 {
402   AtkObject *object = (AtkObject *) user_data;
403   gint role;
404   const char *role_name;
405   DBusMessage *reply;
406
407   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
408                         droute_not_yet_handled_error (message));
409   role = atk_object_get_role (object);
410   role_name = atk_role_get_name (role);
411   if (!role_name)
412     role_name = "";
413   reply = dbus_message_new_method_return (message);
414   if (reply)
415     {
416       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
417                                 DBUS_TYPE_INVALID);
418     }
419   return reply;
420 }
421
422 static DBusMessage *
423 impl_GetLocalizedRoleName (DBusConnection * bus,
424                            DBusMessage * message, void *user_data)
425 {
426   AtkObject *object = (AtkObject *) user_data;
427   gint role;
428   const char *role_name;
429   DBusMessage *reply;
430
431   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
432                         droute_not_yet_handled_error (message));
433   role = atk_object_get_role (object);
434   role_name = atk_role_get_localized_name (role);
435   if (!role_name)
436     role_name = "";
437   reply = dbus_message_new_method_return (message);
438   if (reply)
439     {
440       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
441                                 DBUS_TYPE_INVALID);
442     }
443   return reply;
444 }
445
446 static DBusMessage *
447 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
448 {
449   AtkObject *object = (AtkObject *) user_data;
450
451   DBusMessage *reply = NULL;
452   DBusMessageIter iter, iter_array;
453
454   dbus_uint32_t states[2];
455
456   guint count;
457
458   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
459                         droute_not_yet_handled_error (message));
460
461   reply = dbus_message_new_method_return (message);
462   dbus_message_iter_init_append (reply, &iter);
463
464   spi_atk_state_to_dbus_array (object, states);
465   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
466   for (count = 0; count < 2; count++)
467     {
468       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
469                                       &states[count]);
470     }
471   dbus_message_iter_close_container (&iter, &iter_array);
472   return reply;
473 }
474
475 static DBusMessage *
476 impl_GetAttributes (DBusConnection * bus,
477                     DBusMessage * message, void *user_data)
478 {
479   AtkObject *object = (AtkObject *) user_data;
480   AtkAttributeSet *attributes;
481   DBusMessage *reply = NULL;
482   DBusMessageIter iter;
483
484   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
485                         droute_not_yet_handled_error (message));
486
487   attributes = atk_object_get_attributes (object);
488
489   reply = dbus_message_new_method_return (message);
490   dbus_message_iter_init_append (reply, &iter);
491   spi_object_append_attribute_set (&iter, attributes);
492
493   atk_attribute_set_free (attributes);
494
495   return reply;
496 }
497
498 static DBusMessage *
499 impl_GetApplication (DBusConnection * bus,
500                      DBusMessage * message, void *user_data)
501 {
502   return spi_object_return_reference (message, atk_get_root ());
503 }
504
505 static DBusMessage *
506 impl_GetInterfaces (DBusConnection * bus,
507                     DBusMessage * message, void *user_data)
508 {
509   AtkObject *object = (AtkObject *) user_data;
510   DBusMessage *reply;
511   DBusMessageIter iter, iter_array;
512
513   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
514                         droute_not_yet_handled_error (message));
515   reply = dbus_message_new_method_return (message);
516   if (reply)
517     {
518       dbus_message_iter_init_append (reply, &iter);
519       dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
520                                         &iter_array);
521       spi_object_append_interfaces (&iter_array, object);
522       dbus_message_iter_close_container (&iter, &iter_array);
523     }
524   return reply;
525 }
526
527 static DRouteMethod methods[] = {
528   {impl_GetChildAtIndex, "GetChildAtIndex"},
529   {impl_GetChildren, "GetChildren"},
530   {impl_GetIndexInParent, "GetIndexInParent"},
531   {impl_GetRelationSet, "GetRelationSet"},
532   {impl_GetRole, "GetRole"},
533   {impl_GetRoleName, "GetRoleName"},
534   {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
535   {impl_GetState, "GetState"},
536   {impl_GetAttributes, "GetAttributes"},
537   {impl_GetApplication, "GetApplication"},
538   {impl_GetInterfaces, "GetInterfaces"},
539   {NULL, NULL}
540 };
541
542 static DRouteProperty properties[] = {
543   {impl_get_Name, impl_set_Name, "Name"},
544   {impl_get_Description, impl_set_Description, "Description"},
545   {impl_get_Parent, NULL, "Parent"},
546   {impl_get_ChildCount, NULL, "ChildCount"},
547   {NULL, NULL, NULL}
548 };
549
550 void
551 spi_initialize_accessible (DRoutePath * path)
552 {
553   droute_path_add_interface (path,
554                              SPI_DBUS_INTERFACE_ACCESSIBLE,
555                              spi_org_a11y_atspi_Accessible,     
556                              methods, properties);
557 };