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_INT32_AS_STRING \
53 DBUS_TYPE_INT32_AS_STRING \
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 get_toolkit_name (AtkObject *obj)
68 static const char *toolkit_name = NULL;
71 toolkit_name = atk_get_toolkit_name ();
73 /* TODO: query object attributes */
78 should_call_index_in_parent (AtkObject *obj, AtkStateSet *set)
80 if (atk_state_set_contains_state (set, ATK_STATE_TRANSIENT))
83 if (!strcmp (get_toolkit_name (obj), "gtk") &&
84 atk_object_get_role (obj) == ATK_ROLE_MENU_ITEM)
91 should_cache_children (AtkObject *obj, AtkStateSet *set)
93 if (atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) ||
94 atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
97 if (!strcmp (get_toolkit_name (obj), "gtk") &&
98 atk_object_get_role (obj) == ATK_ROLE_MENU)
105 * Marshals the given AtkObject into the provided D-Bus iterator.
107 * The object is marshalled including all its client side cache data.
108 * The format of the structure is (o(so)iiassusau).
111 append_cache_item (AtkObject * obj, gpointer data)
113 DBusMessageIter iter_struct, iter_sub_array;
114 dbus_uint32_t states[2];
115 dbus_int32_t count, index;
117 DBusMessageIter *iter_array = (DBusMessageIter *) data;
118 const char *name, *desc;
121 set = atk_object_ref_state_set (obj);
122 AtkObject *application, *parent;
124 dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
127 /* Marshal object path */
128 spi_object_append_reference (&iter_struct, obj);
130 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
132 /* Marshal application */
133 application = spi_global_app_data->root;
134 spi_object_append_reference (&iter_struct, application);
137 parent = atk_object_get_parent (obj);
140 /* TODO, move in to a 'Plug' wrapper. */
141 if (ATK_IS_PLUG (obj))
143 char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
149 bus_parent = g_strdup (id);
150 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
152 DBusMessageIter iter_parent;
153 *(path_parent++) = '\0';
154 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
156 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
157 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
158 dbus_message_iter_close_container (&iter_struct, &iter_parent);
162 spi_object_append_null_reference (&iter_struct);
167 spi_object_append_null_reference (&iter_struct);
170 else if (role != ATSPI_ROLE_APPLICATION)
171 spi_object_append_null_reference (&iter_struct);
173 spi_object_append_desktop_reference (&iter_struct);
177 spi_object_append_reference (&iter_struct, parent);
180 /* Marshal index in parent */
181 index = (should_call_index_in_parent (obj, set)
182 ? atk_object_get_index_in_parent (obj) : -1);
183 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &index);
185 /* marshal child count */
186 count = (should_cache_children (obj, set)
187 ? atk_object_get_n_accessible_children (obj) : -1);
189 if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
191 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &count);
193 /* Marshal interfaces */
194 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
196 spi_object_append_interfaces (&iter_sub_array, obj);
197 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
200 name = atk_object_get_name (obj);
203 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
206 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
208 /* Marshal description */
209 desc = atk_object_get_description (obj);
212 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
214 /* Marshal state set */
215 spi_atk_state_set_to_dbus_array (set, states);
216 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
218 for (count = 0; count < 2; count++)
220 dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
223 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
225 dbus_message_iter_close_container (iter_array, &iter_struct);
226 g_object_unref (set);
229 /*---------------------------------------------------------------------------*/
232 ref_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
237 /* For use as a GHFunc */
239 append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
241 /* Make sure it isn't a hyperlink */
242 if (ATK_IS_OBJECT (key))
243 append_cache_item (ATK_OBJECT (key), data);
247 add_to_list_hf (gpointer key, gpointer obj_data, gpointer data)
249 GSList **listptr = data;
250 *listptr = g_slist_prepend (*listptr, key);
253 /*---------------------------------------------------------------------------*/
256 emit_cache_remove (SpiCache *cache, GObject * obj)
258 DBusMessage *message;
260 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
261 ATSPI_DBUS_INTERFACE_CACHE,
262 "RemoveAccessible")))
264 DBusMessageIter iter;
266 dbus_message_iter_init_append (message, &iter);
268 spi_object_append_reference (&iter, ATK_OBJECT (obj));
270 dbus_connection_send (spi_global_app_data->bus, message, NULL);
272 dbus_message_unref (message);
277 emit_cache_add (SpiCache *cache, GObject * obj)
279 AtkObject *accessible = ATK_OBJECT (obj);
280 DBusMessage *message;
282 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
283 ATSPI_DBUS_INTERFACE_CACHE,
286 DBusMessageIter iter;
288 dbus_message_iter_init_append (message, &iter);
289 g_object_ref (accessible);
290 append_cache_item (accessible, &iter);
291 g_object_unref (accessible);
293 dbus_connection_send (spi_global_app_data->bus, message, NULL);
295 dbus_message_unref (message);
300 /*---------------------------------------------------------------------------*/
303 impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
305 return spi_object_return_reference (message, spi_global_app_data->root);
308 /*---------------------------------------------------------------------------*/
311 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
314 DBusMessageIter iter, iter_array;
315 GSList *pending_unrefs = NULL;
317 if (bus == spi_global_app_data->bus)
318 spi_atk_add_client (dbus_message_get_sender (message));
320 reply = dbus_message_new_method_return (message);
322 dbus_message_iter_init_append (reply, &iter);
323 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
324 SPI_CACHE_ITEM_SIGNATURE, &iter_array);
325 spi_cache_foreach (spi_global_cache, ref_accessible_hf, NULL);
326 spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
327 spi_cache_foreach (spi_global_cache, add_to_list_hf, &pending_unrefs);
328 g_slist_free_full (pending_unrefs, g_object_unref);
329 dbus_message_iter_close_container (&iter, &iter_array);
333 /*---------------------------------------------------------------------------*/
335 static DRouteMethod methods[] = {
336 {impl_GetRoot, "GetRoot"},
337 {impl_GetItems, "GetItems"},
342 spi_initialize_cache (DRoutePath * path)
344 droute_path_add_interface (path, ATSPI_DBUS_INTERFACE_CACHE, spi_org_a11y_atspi_Cache, methods, NULL);
346 g_signal_connect (spi_global_cache, "object-added",
347 (GCallback) emit_cache_add, NULL);
349 g_signal_connect (spi_global_cache, "object-removed",
350 (GCallback) emit_cache_remove, NULL);
353 /*END------------------------------------------------------------------------*/