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 Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 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 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, 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 ();
74 return "no toolkit name set yet";
76 /* TODO: query object attributes */
81 should_call_index_in_parent (AtkObject *obj, AtkStateSet *set)
83 if (atk_state_set_contains_state (set, ATK_STATE_TRANSIENT))
86 if (!strcmp (get_toolkit_name (obj), "gtk") &&
87 atk_object_get_role (obj) == ATK_ROLE_MENU_ITEM)
94 should_cache_children (AtkObject *obj, AtkStateSet *set)
96 if (atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) ||
97 atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
100 if (!strcmp (get_toolkit_name (obj), "gtk") &&
101 atk_object_get_role (obj) == ATK_ROLE_MENU)
108 * Marshals the given AtkObject into the provided D-Bus iterator.
110 * The object is marshalled including all its client side cache data.
111 * The format of the structure is (o(so)iiassusau).
114 append_cache_item (AtkObject * obj, gpointer data)
116 DBusMessageIter iter_struct, iter_sub_array;
117 dbus_uint32_t states[2];
118 dbus_int32_t count, index;
120 DBusMessageIter *iter_array = (DBusMessageIter *) data;
121 const char *name, *desc;
124 set = atk_object_ref_state_set (obj);
125 AtkObject *application, *parent;
127 dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
130 /* Marshal object path */
131 spi_object_append_reference (&iter_struct, obj);
133 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
135 /* Marshal application */
136 application = spi_global_app_data->root;
137 spi_object_append_reference (&iter_struct, application);
140 parent = atk_object_get_parent (obj);
143 /* TODO, move in to a 'Plug' wrapper. */
144 if (ATK_IS_PLUG (obj))
146 char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
152 bus_parent = g_strdup (id);
153 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
155 DBusMessageIter iter_parent;
156 *(path_parent++) = '\0';
157 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
159 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
160 dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
161 dbus_message_iter_close_container (&iter_struct, &iter_parent);
165 spi_object_append_null_reference (&iter_struct);
170 spi_object_append_null_reference (&iter_struct);
173 else if (role != ATSPI_ROLE_APPLICATION)
174 spi_object_append_null_reference (&iter_struct);
176 spi_object_append_desktop_reference (&iter_struct);
180 spi_object_append_reference (&iter_struct, parent);
183 /* Marshal index in parent */
184 index = (should_call_index_in_parent (obj, set)
185 ? atk_object_get_index_in_parent (obj) : -1);
186 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &index);
188 /* marshal child count */
189 count = (should_cache_children (obj, set)
190 ? atk_object_get_n_accessible_children (obj) : -1);
192 if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
194 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &count);
196 /* Marshal interfaces */
197 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
199 spi_object_append_interfaces (&iter_sub_array, obj);
200 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
203 name = atk_object_get_name (obj);
206 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
209 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
211 /* Marshal description */
212 desc = atk_object_get_description (obj);
215 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
217 /* Marshal state set */
218 spi_atk_state_set_to_dbus_array (set, states);
219 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
221 for (count = 0; count < 2; count++)
223 dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
226 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
228 dbus_message_iter_close_container (iter_array, &iter_struct);
229 g_object_unref (set);
232 /*---------------------------------------------------------------------------*/
235 ref_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
240 /* For use as a GHFunc */
242 append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
244 /* Make sure it isn't a hyperlink */
245 if (ATK_IS_OBJECT (key))
246 append_cache_item (ATK_OBJECT (key), data);
250 add_to_list_hf (gpointer key, gpointer obj_data, gpointer data)
252 GSList **listptr = data;
253 *listptr = g_slist_prepend (*listptr, key);
256 /*---------------------------------------------------------------------------*/
259 emit_cache_remove (SpiCache *cache, GObject * obj)
261 DBusMessage *message;
263 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
264 ATSPI_DBUS_INTERFACE_CACHE,
265 "RemoveAccessible")))
267 DBusMessageIter iter;
269 dbus_message_iter_init_append (message, &iter);
271 spi_object_append_reference (&iter, ATK_OBJECT (obj));
273 dbus_connection_send (spi_global_app_data->bus, message, NULL);
275 dbus_message_unref (message);
280 emit_cache_add (SpiCache *cache, GObject * obj)
282 AtkObject *accessible = ATK_OBJECT (obj);
283 DBusMessage *message;
285 if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
286 ATSPI_DBUS_INTERFACE_CACHE,
289 DBusMessageIter iter;
291 dbus_message_iter_init_append (message, &iter);
292 g_object_ref (accessible);
293 append_cache_item (accessible, &iter);
294 g_object_unref (accessible);
296 dbus_connection_send (spi_global_app_data->bus, message, NULL);
298 dbus_message_unref (message);
303 /*---------------------------------------------------------------------------*/
306 impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
308 return spi_object_return_reference (message, spi_global_app_data->root);
311 /*---------------------------------------------------------------------------*/
314 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
317 DBusMessageIter iter, iter_array;
318 GSList *pending_unrefs = NULL;
320 if (bus == spi_global_app_data->bus)
321 spi_atk_add_client (dbus_message_get_sender (message));
323 reply = dbus_message_new_method_return (message);
325 dbus_message_iter_init_append (reply, &iter);
326 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
327 SPI_CACHE_ITEM_SIGNATURE, &iter_array);
328 spi_cache_foreach (spi_global_cache, ref_accessible_hf, NULL);
329 spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
330 spi_cache_foreach (spi_global_cache, add_to_list_hf, &pending_unrefs);
331 g_slist_free_full (pending_unrefs, g_object_unref);
332 dbus_message_iter_close_container (&iter, &iter_array);
336 /*---------------------------------------------------------------------------*/
338 static DRouteMethod methods[] = {
339 {impl_GetRoot, "GetRoot"},
340 {impl_GetItems, "GetItems"},
345 spi_initialize_cache (DRoutePath * path)
347 droute_path_add_interface (path, ATSPI_DBUS_INTERFACE_CACHE, spi_org_a11y_atspi_Cache, methods, NULL);
349 g_signal_connect (spi_global_cache, "object-added",
350 (GCallback) emit_cache_add, NULL);
352 g_signal_connect (spi_global_cache, "object-removed",
353 (GCallback) emit_cache_remove, NULL);
356 /*END------------------------------------------------------------------------*/