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