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