1983807a084e0441b08f96de1a56147d34fca0e4
[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   DBusError error;
160   dbus_int32_t i;
161   AtkObject *child;
162
163   dbus_error_init (&error);
164   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
165                         droute_not_yet_handled_error (message));
166   if (!dbus_message_get_args 
167        (message, &error, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
168     {
169       return droute_invalid_arguments_error (message);
170     }
171
172   if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
173     {
174       AtkSocket *socket = ATK_SOCKET (object);
175       gchar *child_name, *child_path;
176       child_name = g_strdup (socket->embedded_plug_id);
177       child_path = g_utf8_strchr (child_name + 1, -1, ':');
178       if (child_path)
179         {
180           DBusMessage *reply;
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   return spi_object_return_reference (message, child, TRUE);
198 }
199
200 static DBusMessage *
201 impl_GetChildren (DBusConnection * bus,
202                   DBusMessage * message, void *user_data)
203 {
204   AtkObject *object = (AtkObject *) user_data;
205   gint i;
206   gint count;
207   DBusMessage *reply;
208   DBusMessageIter iter, iter_array;
209
210   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
211                         droute_not_yet_handled_error (message));
212   count = atk_object_get_n_accessible_children (object);
213   reply = dbus_message_new_method_return (message);
214   if (!reply)
215     goto oom;
216   dbus_message_iter_init_append (reply, &iter);
217   if (!dbus_message_iter_open_container
218       (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
219     goto oom;
220   for (i = 0; i < count; i++)
221     {
222       AtkObject *child = atk_object_ref_accessible_child (object, i);
223       spi_object_append_reference (&iter_array, child); 
224       if (child)
225         g_object_unref (child);
226     }
227   if (!dbus_message_iter_close_container (&iter, &iter_array))
228     goto oom;
229   return reply;
230 oom:
231   // TODO: handle out-of-memory
232   return reply;
233 }
234
235 static DBusMessage *
236 impl_GetIndexInParent (DBusConnection * bus,
237                        DBusMessage * message, void *user_data)
238 {
239   AtkObject *object = (AtkObject *) user_data;
240   dbus_uint32_t rv;
241   DBusMessage *reply;
242
243   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
244                         droute_not_yet_handled_error (message));
245
246   rv = atk_object_get_index_in_parent (object);
247   reply = dbus_message_new_method_return (message);
248   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv, DBUS_TYPE_INVALID);
249   return reply;
250 }
251
252 static gboolean
253 spi_init_relation_type_table (Accessibility_RelationType * types)
254 {
255   gint i;
256
257   for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
258     types[i] = Accessibility_RELATION_NULL;
259
260   types[ATK_RELATION_CONTROLLED_BY] = Accessibility_RELATION_CONTROLLED_BY;
261   types[ATK_RELATION_CONTROLLER_FOR] = Accessibility_RELATION_CONTROLLER_FOR;
262   types[ATK_RELATION_LABEL_FOR] = Accessibility_RELATION_LABEL_FOR;
263   types[ATK_RELATION_LABELLED_BY] = Accessibility_RELATION_LABELLED_BY;
264   types[ATK_RELATION_MEMBER_OF] = Accessibility_RELATION_MEMBER_OF;
265   types[ATK_RELATION_NODE_CHILD_OF] = Accessibility_RELATION_NODE_CHILD_OF;
266   types[ATK_RELATION_FLOWS_TO] = Accessibility_RELATION_FLOWS_TO;
267   types[ATK_RELATION_FLOWS_FROM] = Accessibility_RELATION_FLOWS_FROM;
268   types[ATK_RELATION_SUBWINDOW_OF] = Accessibility_RELATION_SUBWINDOW_OF;
269   types[ATK_RELATION_EMBEDS] = Accessibility_RELATION_EMBEDS;
270   types[ATK_RELATION_EMBEDDED_BY] = Accessibility_RELATION_EMBEDDED_BY;
271   types[ATK_RELATION_POPUP_FOR] = Accessibility_RELATION_POPUP_FOR;
272   types[ATK_RELATION_PARENT_WINDOW_OF] =
273     Accessibility_RELATION_PARENT_WINDOW_OF;
274   types[ATK_RELATION_DESCRIPTION_FOR] =
275     Accessibility_RELATION_DESCRIPTION_FOR;
276   types[ATK_RELATION_DESCRIBED_BY] = Accessibility_RELATION_DESCRIBED_BY;
277
278   return TRUE;
279 }
280
281 static Accessibility_RelationType
282 spi_relation_type_from_atk_relation_type (AtkRelationType type)
283 {
284   static gboolean is_initialized = FALSE;
285   static Accessibility_RelationType
286     spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
287   Accessibility_RelationType spi_type;
288
289   if (!is_initialized)
290     is_initialized = spi_init_relation_type_table (spi_relation_type_table);
291
292   if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
293     spi_type = spi_relation_type_table[type];
294   else
295     spi_type = Accessibility_RELATION_EXTENDED;
296   return spi_type;
297 }
298
299 static DBusMessage *
300 impl_GetRelationSet (DBusConnection * bus,
301                      DBusMessage * message, void *user_data)
302 {
303   AtkObject *object = (AtkObject *) user_data;
304   DBusMessage *reply;
305   AtkRelationSet *set;
306   DBusMessageIter iter, iter_array, iter_struct, iter_targets;
307   gint count;
308   gint i, j;
309
310   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
311                         droute_not_yet_handled_error (message));
312   reply = dbus_message_new_method_return (message);
313   if (!reply)
314     return NULL;
315   set = atk_object_ref_relation_set (object);
316   dbus_message_iter_init_append (reply, &iter);
317   if (!dbus_message_iter_open_container
318       (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
319     {
320       goto oom;
321     }
322   count = 0;
323   if (set)
324     count = atk_relation_set_get_n_relations (set);
325   for (i = 0; i < count; i++)
326     {
327       AtkRelation *r = atk_relation_set_get_relation (set, i);
328       AtkRelationType rt;
329       GPtrArray *target;
330       dbus_uint32_t type;
331       if (!r)
332         continue;
333       rt = atk_relation_get_relation_type (r);
334       type = spi_relation_type_from_atk_relation_type (rt);
335       target = atk_relation_get_target (r);
336       if (!dbus_message_iter_open_container
337           (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
338         {
339           goto oom;
340         }
341       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
342       if (!dbus_message_iter_open_container
343           (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
344         {
345           goto oom;
346         }
347       for (j = 0; j < target->len; j++)
348         {
349           AtkObject *obj = target->pdata[j];
350           char *path;
351           if (!obj)
352             continue;
353           spi_object_append_reference (&iter_targets, obj);
354         }
355       dbus_message_iter_close_container (&iter_struct, &iter_targets);
356       dbus_message_iter_close_container (&iter_array, &iter_struct);
357     }
358   dbus_message_iter_close_container (&iter, &iter_array);
359 oom:
360   // TODO: handle out of memory */
361   return reply;
362 }
363
364 static DBusMessage *
365 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
366 {
367   AtkObject *object = (AtkObject *) user_data;
368   gint role;
369   dbus_uint32_t rv;
370   DBusMessage *reply;
371
372   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
373                         droute_not_yet_handled_error (message));
374   role = atk_object_get_role (object);
375   rv = spi_accessible_role_from_atk_role (role);
376   reply = dbus_message_new_method_return (message);
377   if (reply)
378     {
379       dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
380                                 DBUS_TYPE_INVALID);
381     }
382   return reply;
383 }
384
385 static char *
386 impl_get_role_str (void *datum)
387 {
388   g_return_val_if_fail (ATK_IS_OBJECT (datum), g_strdup (""));
389   return g_strdup_printf ("%d",
390                           spi_accessible_role_from_atk_role
391                           (atk_object_get_role ((AtkObject *) datum)));
392 }
393
394 static DBusMessage *
395 impl_GetRoleName (DBusConnection * bus,
396                   DBusMessage * message, void *user_data)
397 {
398   AtkObject *object = (AtkObject *) user_data;
399   gint role;
400   const char *role_name;
401   DBusMessage *reply;
402
403   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
404                         droute_not_yet_handled_error (message));
405   role = atk_object_get_role (object);
406   role_name = atk_role_get_name (role);
407   if (!role_name)
408     role_name = "";
409   reply = dbus_message_new_method_return (message);
410   if (reply)
411     {
412       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
413                                 DBUS_TYPE_INVALID);
414     }
415   return reply;
416 }
417
418 static DBusMessage *
419 impl_GetLocalizedRoleName (DBusConnection * bus,
420                            DBusMessage * message, void *user_data)
421 {
422   AtkObject *object = (AtkObject *) user_data;
423   gint role;
424   const char *role_name;
425   DBusMessage *reply;
426
427   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
428                         droute_not_yet_handled_error (message));
429   role = atk_object_get_role (object);
430   role_name = atk_role_get_localized_name (role);
431   if (!role_name)
432     role_name = "";
433   reply = dbus_message_new_method_return (message);
434   if (reply)
435     {
436       dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
437                                 DBUS_TYPE_INVALID);
438     }
439   return reply;
440 }
441
442 static DBusMessage *
443 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
444 {
445   AtkObject *object = (AtkObject *) user_data;
446
447   DBusMessage *reply = NULL;
448   DBusMessageIter iter, iter_array;
449
450   dbus_uint32_t states[2];
451
452   guint count;
453
454   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
455                         droute_not_yet_handled_error (message));
456
457   reply = dbus_message_new_method_return (message);
458   dbus_message_iter_init_append (reply, &iter);
459
460   spi_atk_state_to_dbus_array (object, states);
461   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
462   for (count = 0; count < 2; count++)
463     {
464       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
465                                       &states[count]);
466     }
467   dbus_message_iter_close_container (&iter, &iter_array);
468   return reply;
469 }
470
471 static DBusMessage *
472 impl_GetAttributes (DBusConnection * bus,
473                     DBusMessage * message, void *user_data)
474 {
475   AtkObject *object = (AtkObject *) user_data;
476   AtkAttributeSet *attributes;
477   DBusMessage *reply = NULL;
478   DBusMessageIter iter;
479
480   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
481                         droute_not_yet_handled_error (message));
482
483   attributes = atk_object_get_attributes (object);
484
485   reply = dbus_message_new_method_return (message);
486   dbus_message_iter_init_append (reply, &iter);
487   spi_object_append_attribute_set (&iter, attributes);
488
489   atk_attribute_set_free (attributes);
490
491   return reply;
492 }
493
494 static DBusMessage *
495 impl_GetApplication (DBusConnection * bus,
496                      DBusMessage * message, void *user_data)
497 {
498   AtkObject *root = g_object_ref (atk_get_root ());
499   return spi_object_return_reference (message, root, TRUE);
500 }
501
502 static DBusMessage *
503 impl_GetInterfaces (DBusConnection * bus,
504                     DBusMessage * message, void *user_data)
505 {
506   AtkObject *object = (AtkObject *) user_data;
507   gint role;
508   const char *role_name;
509   DBusMessage *reply;
510   DBusMessageIter iter, iter_array;
511
512   g_return_val_if_fail (ATK_IS_OBJECT (user_data),
513                         droute_not_yet_handled_error (message));
514   reply = dbus_message_new_method_return (message);
515   if (reply)
516     {
517       dbus_message_iter_init_append (reply, &iter);
518       dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
519                                         &iter_array);
520       spi_object_append_interfaces (&iter_array, object);
521       dbus_message_iter_close_container (&iter, &iter_array);
522     }
523   return reply;
524 }
525
526 static DRouteMethod methods[] = {
527   {impl_GetChildAtIndex, "GetChildAtIndex"},
528   {impl_GetChildren, "GetChildren"},
529   {impl_GetIndexInParent, "GetIndexInParent"},
530   {impl_GetRelationSet, "GetRelationSet"},
531   {impl_GetRole, "GetRole"},
532   {impl_GetRoleName, "GetRoleName"},
533   {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
534   {impl_GetState, "GetState"},
535   {impl_GetAttributes, "GetAttributes"},
536   {impl_GetApplication, "GetApplication"},
537   {impl_GetInterfaces, "GetInterfaces"},
538   {NULL, NULL}
539 };
540
541 static DRouteProperty properties[] = {
542   {impl_get_Name, impl_set_Name, "Name"},
543   {impl_get_Description, impl_set_Description, "Description"},
544   {impl_get_Parent, NULL, "Parent"},
545   {impl_get_ChildCount, NULL, "ChildCount"},
546   {NULL, NULL, NULL}
547 };
548
549 void
550 spi_initialize_accessible (DRoutePath * path)
551 {
552   droute_path_add_interface (path,
553                              SPI_DBUS_INTERFACE_ACCESSIBLE,
554                              spi_org_a11y_atspi_Accessible,     
555                              methods, properties);
556 };