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.
8 * Copyright 2008, 2009 Codethink Ltd.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
29 #include <droute/droute.h>
32 #include "accessible-stateset.h"
33 #include "accessible-cache.h"
36 #include "introspection.h"
38 /* TODO - This should possibly be a common define */
39 #define SPI_OBJECT_PREFIX "/org/a11y/atspi"
40 #define SPI_CACHE_OBJECT_SUFFIX "/cache"
41 #define SPI_CACHE_OBJECT_PATH SPI_OBJECT_PREFIX SPI_CACHE_OBJECT_SUFFIX
43 #define SPI_OBJECT_REFERENCE_SIGNATURE "(" \
44 DBUS_TYPE_STRING_AS_STRING \
45 DBUS_TYPE_OBJECT_PATH_AS_STRING \
48 #define SPI_CACHE_ITEM_SIGNATURE "(" \
49 SPI_OBJECT_REFERENCE_SIGNATURE \
50 SPI_OBJECT_REFERENCE_SIGNATURE \
51 SPI_OBJECT_REFERENCE_SIGNATURE \
52 DBUS_TYPE_ARRAY_AS_STRING \
53 SPI_OBJECT_REFERENCE_SIGNATURE \
54 DBUS_TYPE_ARRAY_AS_STRING \
55 DBUS_TYPE_STRING_AS_STRING \
56 DBUS_TYPE_STRING_AS_STRING \
57 DBUS_TYPE_UINT32_AS_STRING \
58 DBUS_TYPE_STRING_AS_STRING \
59 DBUS_TYPE_ARRAY_AS_STRING \
60 DBUS_TYPE_UINT32_AS_STRING \
63 /*---------------------------------------------------------------------------*/
66 * Marshals the given AtkObject into the provided D-Bus iterator.
68 * The object is marshalled including all its client side cache data.
69 * The format of the structure is (o(so)a(so)assusau).
72 append_cache_item (AtkObject * obj, gpointer data)
74 DBusMessageIter iter_struct, iter_sub_array;
75 dbus_uint32_t states[2];
78 DBusMessageIter *iter_array = (DBusMessageIter *) data;
80 const char *name, *desc;
83 set = atk_object_ref_state_set (obj);
85 AtkObject *application, *parent;
87 dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
90 /* Marshall object path */
91 spi_object_append_reference (&iter_struct, obj);
93 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
95 /* Marshall application */
96 application = spi_global_app_data->root;
97 spi_object_append_reference (&iter_struct, application);
100 parent = atk_object_get_parent (obj);
103 /* TODO, move in to a 'Plug' wrapper. */
104 if (ATK_IS_PLUG (obj))
106 char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
112 bus_parent = g_strdup (id);
113 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
115 DBusMessageIter iter_parent;
116 *(path_parent++) = '\0';
117 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
119 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
120 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
121 dbus_message_iter_close_container (&iter_struct, &iter_parent);
125 spi_object_append_null_reference (&iter_struct);
130 spi_object_append_null_reference (&iter_struct);
133 else if (role != ATSPI_ROLE_APPLICATION)
134 spi_object_append_null_reference (&iter_struct);
136 spi_object_append_desktop_reference (&iter_struct);
140 spi_object_append_reference (&iter_struct, parent);
143 /* Marshall children */
144 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)",
146 if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) &&
147 !atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
151 childcount = atk_object_get_n_accessible_children (obj);
152 for (i = 0; i < childcount; i++)
156 child = atk_object_ref_accessible_child (obj, i);
157 spi_object_append_reference (&iter_sub_array, child);
158 g_object_unref (G_OBJECT (child));
161 if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
163 AtkSocket *socket = ATK_SOCKET (obj);
164 gchar *child_name, *child_path;
165 child_name = g_strdup (socket->embedded_plug_id);
166 child_path = g_utf8_strchr (child_name + 1, -1, ':');
169 DBusMessageIter iter_socket;
170 *(child_path++) = '\0';
171 dbus_message_iter_open_container (&iter_sub_array, DBUS_TYPE_STRUCT, NULL,
173 dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
174 dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
175 dbus_message_iter_close_container (&iter_sub_array, &iter_socket);
180 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
182 /* Marshall interfaces */
183 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
185 spi_object_append_interfaces (&iter_sub_array, obj);
186 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
189 name = atk_object_get_name (obj);
192 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
195 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
197 /* Marshall description */
198 desc = atk_object_get_description (obj);
201 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
203 /* Marshall state set */
204 spi_atk_state_set_to_dbus_array (set, states);
205 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
207 for (count = 0; count < 2; count++)
209 dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
212 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
214 dbus_message_iter_close_container (iter_array, &iter_struct);
215 g_object_unref (set);
218 /*---------------------------------------------------------------------------*/
221 ref_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
226 /* For use as a GHFunc */
228 append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
230 /* Make sure it isn't a hyperlink */
231 if (ATK_IS_OBJECT (key))
232 append_cache_item (ATK_OBJECT (key), data);
236 add_to_list_hf (gpointer key, gpointer obj_data, gpointer data)
238 GSList **listptr = data;
239 *listptr = g_slist_prepend (*listptr, key);
242 /*---------------------------------------------------------------------------*/
245 emit_cache_remove (SpiCache *cache, GObject * obj)
247 DBusMessage *message;
249 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
250 ATSPI_DBUS_INTERFACE_CACHE,
251 "RemoveAccessible")))
253 DBusMessageIter iter;
255 dbus_message_iter_init_append (message, &iter);
257 spi_object_append_reference (&iter, ATK_OBJECT (obj));
259 dbus_connection_send (spi_global_app_data->bus, message, NULL);
261 dbus_message_unref (message);
266 emit_cache_add (SpiCache *cache, GObject * obj)
268 AtkObject *accessible = ATK_OBJECT (obj);
269 DBusMessage *message;
271 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
272 ATSPI_DBUS_INTERFACE_CACHE,
275 DBusMessageIter iter;
277 dbus_message_iter_init_append (message, &iter);
278 g_object_ref (accessible);
279 append_cache_item (accessible, &iter);
280 g_object_unref (accessible);
282 dbus_connection_send (spi_global_app_data->bus, message, NULL);
284 dbus_message_unref (message);
289 /*---------------------------------------------------------------------------*/
292 impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
294 return spi_object_return_reference (message, spi_global_app_data->root);
297 /*---------------------------------------------------------------------------*/
300 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
303 DBusMessageIter iter, iter_array;
304 GSList *pending_unrefs = NULL;
306 if (bus == spi_global_app_data->bus)
307 spi_atk_add_client (dbus_message_get_sender (message));
309 reply = dbus_message_new_method_return (message);
311 dbus_message_iter_init_append (reply, &iter);
312 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
313 SPI_CACHE_ITEM_SIGNATURE, &iter_array);
314 spi_cache_foreach (spi_global_cache, ref_accessible_hf, NULL);
315 spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
316 spi_cache_foreach (spi_global_cache, add_to_list_hf, &pending_unrefs);
317 g_slist_free_full (pending_unrefs, g_object_unref);
318 dbus_message_iter_close_container (&iter, &iter_array);
322 /*---------------------------------------------------------------------------*/
324 static DRouteMethod methods[] = {
325 {impl_GetRoot, "GetRoot"},
326 {impl_GetItems, "GetItems"},
331 spi_initialize_cache (DRoutePath * path)
333 droute_path_add_interface (path, ATSPI_DBUS_INTERFACE_CACHE, spi_org_a11y_atspi_Cache, methods, NULL);
335 g_signal_connect (spi_global_cache, "object-added",
336 (GCallback) emit_cache_add, NULL);
338 g_signal_connect (spi_global_cache, "object-removed",
339 (GCallback) emit_cache_remove, NULL);
342 /*END------------------------------------------------------------------------*/