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