2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008 Novell, Inc.
6 * Copyright 2001, 2002 Sun Microsystems Inc.,
7 * Copyright 2001, 2002 Ximian, Inc.
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.
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.
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.
26 #include <droute/droute.h>
28 #include "atspi/atspi.h"
30 #include "accessible-stateset.h"
32 #include "introspection.h"
35 impl_get_Name (DBusMessageIter * iter, void *user_data)
37 AtkObject *object = (AtkObject *) user_data;
39 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
41 return droute_return_v_string (iter, atk_object_get_name (object));
45 impl_set_Name (DBusMessageIter * iter, void *user_data)
47 AtkObject *object = (AtkObject *) user_data;
48 const char *name = droute_get_v_string (iter);
50 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
52 atk_object_set_name (object, name);
57 impl_get_Description (DBusMessageIter * iter, void *user_data)
59 AtkObject *object = (AtkObject *) user_data;
61 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
63 return droute_return_v_string (iter, atk_object_get_description (object));
67 impl_set_Description (DBusMessageIter * iter, void *user_data)
69 AtkObject *object = (AtkObject *) user_data;
70 const char *description = droute_get_v_string (iter);
72 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
74 atk_object_set_description (object, description);
79 impl_get_Parent (DBusMessageIter * iter, void *user_data)
81 AtkObject *obj = (AtkObject *) user_data;
83 DBusMessageIter iter_variant;
86 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
88 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
90 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
93 parent = atk_object_get_parent (obj);
96 /* TODO, move in to a 'Plug' wrapper. */
97 if (ATK_IS_PLUG (obj))
99 char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
105 bus_parent = g_strdup (id);
106 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
108 DBusMessageIter iter_parent;
109 *(path_parent++) = '\0';
110 dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
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);
118 spi_object_append_null_reference (&iter_variant);
123 spi_object_append_null_reference (&iter_variant);
126 else if (role != ATSPI_ROLE_APPLICATION)
127 spi_object_append_null_reference (&iter_variant);
129 spi_object_append_desktop_reference (&iter_variant);
133 spi_object_append_reference (&iter_variant, parent);
137 dbus_message_iter_close_container (iter, &iter_variant);
142 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
144 AtkObject *object = (AtkObject *) user_data;
147 g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
149 childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
151 : atk_object_get_n_accessible_children (object);
152 return droute_return_v_int32 (iter, childCount);
156 impl_GetChildAtIndex (DBusConnection * bus,
157 DBusMessage * message, void *user_data)
159 AtkObject *object = (AtkObject *) user_data;
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))
171 return droute_invalid_arguments_error (message);
174 if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
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, ':');
182 DBusMessageIter iter, iter_socket;
183 *(child_path++) = '\0';
184 reply = dbus_message_new_method_return (message);
187 dbus_message_iter_init_append (reply, &iter);
188 dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
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);
197 child = atk_object_ref_accessible_child (object, i);
198 reply = spi_object_return_reference (message, child);
199 g_object_unref (child);
205 impl_GetChildren (DBusConnection * bus,
206 DBusMessage * message, void *user_data)
208 AtkObject *object = (AtkObject *) user_data;
212 DBusMessageIter iter, iter_array;
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);
220 dbus_message_iter_init_append (reply, &iter);
221 if (!dbus_message_iter_open_container
222 (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
224 for (i = 0; i < count; i++)
226 AtkObject *child = atk_object_ref_accessible_child (object, i);
227 spi_object_append_reference (&iter_array, child);
229 g_object_unref (child);
231 if (!dbus_message_iter_close_container (&iter, &iter_array))
235 // TODO: handle out-of-memory
240 impl_GetIndexInParent (DBusConnection * bus,
241 DBusMessage * message, void *user_data)
243 AtkObject *object = (AtkObject *) user_data;
247 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
248 droute_not_yet_handled_error (message));
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);
257 spi_init_relation_type_table (AtspiRelationType * types)
261 for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
262 types[i] = ATSPI_RELATION_NULL;
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;
286 static AtspiRelationType
287 spi_relation_type_from_atk_relation_type (AtkRelationType type)
289 static gboolean is_initialized = FALSE;
290 static AtspiRelationType
291 spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
292 AtspiRelationType spi_type;
295 is_initialized = spi_init_relation_type_table (spi_relation_type_table);
297 if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
298 spi_type = spi_relation_type_table[type];
300 spi_type = ATSPI_RELATION_EXTENDED;
305 impl_GetRelationSet (DBusConnection * bus,
306 DBusMessage * message, void *user_data)
308 AtkObject *object = (AtkObject *) user_data;
311 DBusMessageIter iter, iter_array, iter_struct, iter_targets;
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);
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))
329 count = atk_relation_set_get_n_relations (set);
330 for (i = 0; i < count; i++)
332 AtkRelation *r = atk_relation_set_get_relation (set, i);
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))
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))
352 for (j = 0; j < target->len; j++)
354 AtkObject *obj = target->pdata[j];
358 spi_object_append_reference (&iter_targets, obj);
360 dbus_message_iter_close_container (&iter_struct, &iter_targets);
361 dbus_message_iter_close_container (&iter_array, &iter_struct);
363 dbus_message_iter_close_container (&iter, &iter_array);
365 // TODO: handle out of memory */
370 impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
372 AtkObject *object = (AtkObject *) user_data;
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);
384 dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
391 impl_get_role_str (void *datum)
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)));
400 impl_GetRoleName (DBusConnection * bus,
401 DBusMessage * message, void *user_data)
403 AtkObject *object = (AtkObject *) user_data;
405 const char *role_name;
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);
414 reply = dbus_message_new_method_return (message);
417 dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
424 impl_GetLocalizedRoleName (DBusConnection * bus,
425 DBusMessage * message, void *user_data)
427 AtkObject *object = (AtkObject *) user_data;
429 const char *role_name;
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);
438 reply = dbus_message_new_method_return (message);
441 dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
448 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
450 AtkObject *object = (AtkObject *) user_data;
452 DBusMessage *reply = NULL;
453 DBusMessageIter iter, iter_array;
455 dbus_uint32_t states[2];
459 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
460 droute_not_yet_handled_error (message));
462 reply = dbus_message_new_method_return (message);
463 dbus_message_iter_init_append (reply, &iter);
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++)
469 dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
472 dbus_message_iter_close_container (&iter, &iter_array);
477 impl_GetAttributes (DBusConnection * bus,
478 DBusMessage * message, void *user_data)
480 AtkObject *object = (AtkObject *) user_data;
481 AtkAttributeSet *attributes;
482 DBusMessage *reply = NULL;
483 DBusMessageIter iter;
485 g_return_val_if_fail (ATK_IS_OBJECT (user_data),
486 droute_not_yet_handled_error (message));
488 attributes = atk_object_get_attributes (object);
490 reply = dbus_message_new_method_return (message);
491 dbus_message_iter_init_append (reply, &iter);
492 spi_object_append_attribute_set (&iter, attributes);
494 atk_attribute_set_free (attributes);
500 impl_GetApplication (DBusConnection * bus,
501 DBusMessage * message, void *user_data)
503 return spi_object_return_reference (message, atk_get_root ());
507 impl_GetInterfaces (DBusConnection * bus,
508 DBusMessage * message, void *user_data)
510 AtkObject *object = (AtkObject *) user_data;
512 DBusMessageIter iter, iter_array;
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);
519 dbus_message_iter_init_append (reply, &iter);
520 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
522 spi_object_append_interfaces (&iter_array, object);
523 dbus_message_iter_close_container (&iter, &iter_array);
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"},
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"},
552 spi_initialize_accessible (DRoutePath * path)
554 droute_path_add_interface (path,
555 ATSPI_DBUS_INTERFACE_ACCESSIBLE,
556 spi_org_a11y_atspi_Accessible,
557 methods, properties);