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