2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008 Novell, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include <droute/droute.h>
25 #include "common/spi-dbus.h"
26 #include "common/spi-stateset.h"
28 #include "accessible-register.h"
29 #include "accessible-marshaller.h"
34 /*---------------------------------------------------------------------------*/
37 spi_dbus_append_name_and_path_inner (DBusMessageIter *iter, const char *bus_name, const char *path)
39 DBusMessageIter iter_struct;
44 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &iter_struct);
45 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &bus_name);
46 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
47 dbus_message_iter_close_container (iter, &iter_struct);
51 spi_dbus_append_name_and_path (DBusMessage *message, DBusMessageIter *iter, AtkObject *obj, gboolean do_register, gboolean unref)
54 DBusMessageIter iter_struct;
55 const char *bus_name = dbus_bus_get_unique_name (atk_adaptor_app_data->bus);
57 path = atk_dbus_object_to_path (obj, do_register);
60 path = g_strdup (SPI_DBUS_PATH_NULL);
62 spi_dbus_append_name_and_path_inner (iter, bus_name, path);
70 * Marshals the D-Bus path of an AtkObject into a D-Bus message.
72 * Unrefs the AtkObject if unref is true.
75 spi_dbus_return_object (DBusMessage *message, AtkObject *obj, gboolean do_register, gboolean unref)
78 reply = dbus_message_new_method_return (message);
82 dbus_message_iter_init_append (reply, &iter);
83 spi_dbus_append_name_and_path (message, &iter, obj, do_register, unref);
90 spi_dbus_return_hyperlink (DBusMessage *message, AtkHyperlink *link, AtkObject *container, gboolean unref)
92 return spi_dbus_return_sub_object (message, G_OBJECT (link), G_OBJECT (container), unref);
96 spi_dbus_return_sub_object (DBusMessage *message, GObject *sub, GObject *container, gboolean unref)
101 path = atk_dbus_sub_object_to_path (sub, container);
104 g_object_unref (sub);
107 path = g_strdup (SPI_DBUS_PATH_NULL);
109 reply = dbus_message_new_method_return (message);
112 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
121 /*---------------------------------------------------------------------------*/
124 * Marshals a variant containing the D-Bus path of an AtkObject into a D-Bus
127 * Unrefs the object if unref is true.
130 spi_dbus_return_v_object (DBusMessageIter *iter, AtkObject *obj, int unref)
132 DBusMessageIter iter_variant;
135 path = atk_dbus_object_to_path (obj, FALSE);
138 path = g_strdup (SPI_DBUS_PATH_NULL);
141 g_object_unref (obj);
143 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)", &iter_variant);
144 spi_dbus_append_name_and_path_inner (&iter_variant, NULL, path);
145 dbus_message_iter_close_container (iter, &iter_variant);
149 /*---------------------------------------------------------------------------*/
152 append_atk_object_interfaces (AtkObject *object, DBusMessageIter *iter)
156 itf = SPI_DBUS_INTERFACE_ACCESSIBLE;
157 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
159 if (ATK_IS_ACTION (object))
161 itf = SPI_DBUS_INTERFACE_ACTION;
162 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
165 if (ATK_IS_COMPONENT (object))
167 itf = SPI_DBUS_INTERFACE_COMPONENT;
168 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
171 if (ATK_IS_EDITABLE_TEXT (object))
173 itf = SPI_DBUS_INTERFACE_EDITABLE_TEXT;
174 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
177 if (ATK_IS_TEXT (object))
179 itf = SPI_DBUS_INTERFACE_TEXT;
180 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
183 if (ATK_IS_HYPERTEXT (object))
185 itf = SPI_DBUS_INTERFACE_HYPERTEXT;
186 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
189 if (ATK_IS_IMAGE (object))
191 itf = SPI_DBUS_INTERFACE_IMAGE;
192 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
195 if (ATK_IS_SELECTION (object))
197 itf = SPI_DBUS_INTERFACE_SELECTION;
198 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
201 if (ATK_IS_TABLE (object))
203 itf = SPI_DBUS_INTERFACE_TABLE;
204 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
207 if (ATK_IS_VALUE (object))
209 itf = SPI_DBUS_INTERFACE_VALUE;
210 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
213 if (ATK_IS_STREAMABLE_CONTENT (object))
215 itf = "org.freedesktop.atspi.StreamableContent";
216 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
219 if (ATK_IS_DOCUMENT (object))
221 itf = "org.freedesktop.atspi.Collection";
222 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
223 itf = SPI_DBUS_INTERFACE_DOCUMENT;
224 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
227 if (ATK_IS_HYPERLINK_IMPL (object))
229 itf = SPI_DBUS_INTERFACE_HYPERLINK;
230 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
234 /*---------------------------------------------------------------------------*/
237 * Marshals the given AtkObject into the provided D-Bus iterator.
239 * The object is marshalled including all its client side cache data.
240 * The format of the structure is (o(so)a(so)assusau).
241 * This is used in the updateTree signal and the GetTree method
242 * of the org.freedesktop.atspi.Tree interface.
244 * To marshal an object its parent, and all its children must already
245 * be registered with D-Bus and have been given a D-Bus object path.
248 spi_atk_append_accessible(AtkObject *obj, gpointer data)
250 DBusMessageIter iter_struct, iter_sub_array;
251 dbus_uint32_t states [2];
254 DBusMessageIter *iter_array = (DBusMessageIter *)data;
256 const char *name, *desc;
259 set = atk_object_ref_state_set (obj);
263 gchar *bus_parent = NULL, *path_parent;
265 /* Marshall object path */
266 path = atk_dbus_object_to_path (obj, FALSE);
268 role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
270 /* Marshall parent */
271 parent = atk_object_get_parent(obj);
274 /* TODO: Support getting parent of an AtkPlug */
275 #ifdef __ATK_PLUG_H__
276 if (role != Accessibility_ROLE_APPLICATION && !ATK_IS_PLUG (obj))
278 if (role != Accessibility_ROLE_APPLICATION)
280 path_parent = g_strdup (SPI_DBUS_PATH_NULL);
282 path_parent = atk_dbus_desktop_object_path ();
286 path_parent = atk_dbus_object_to_path (parent, FALSE);
289 /* This should only happen if a widget is re-parented to
290 * an AtkObject that has not been registered and is then
291 * updated. Ideally objects would be de-registered when
292 * they are removed from a registered tree object, but
293 * this would invalidate a huge amount of cache when
297 g_warning ("AT-SPI: Registered accessible marshalled when parent not registered");
299 path_parent = atk_dbus_desktop_object_path ();
303 dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
304 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
305 spi_dbus_append_name_and_path_inner (&iter_struct, bus_parent, path_parent);
309 /* Marshall children */
310 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_sub_array);
311 if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS))
315 childcount = atk_object_get_n_accessible_children (obj);
316 for (i = 0; i < childcount; i++)
321 child = atk_object_ref_accessible_child (obj, i);
322 child_path = atk_dbus_object_to_path (child, FALSE);
325 spi_dbus_append_name_and_path_inner (&iter_sub_array, NULL, child_path);
328 g_object_unref(G_OBJECT(child));
331 #ifdef __ATK_PLUG_H__
332 if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET(obj)))
334 AtkSocket *socket = ATK_SOCKET(obj);
335 gchar *child_name, *child_path;
336 child_name = g_strdup (socket->embedded_plug_id);
337 child_path = g_utf8_strchr (child_name + 1, -1, ':');
340 *(child_path++) = '\0';
341 spi_dbus_append_name_and_path_inner (&iter_sub_array, child_name, child_path);
347 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
349 /* Marshall interfaces */
350 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array);
351 append_atk_object_interfaces (obj, &iter_sub_array);
352 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
355 name = atk_object_get_name (obj);
358 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
361 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
363 /* Marshall description */
364 desc = atk_object_get_description (obj);
367 dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
371 /* Marshall state set */
372 spi_atk_state_set_to_dbus_array (set, states);
373 dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_sub_array);
374 for (count = 0; count < 2; count++)
376 dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32, &states[count]);
378 dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
380 dbus_message_iter_close_container (iter_array, &iter_struct);
381 g_object_unref (set);
385 spi_atk_append_attribute_set (DBusMessageIter *iter, AtkAttributeSet *attr)
387 DBusMessageIter dictIter;
389 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}", &dictIter);
390 spi_atk_append_attribute_set_inner (&dictIter, attr);
391 dbus_message_iter_close_container (iter, &dictIter);
395 spi_atk_append_attribute_set_inner (DBusMessageIter *iter, AtkAttributeSet *attr)
397 DBusMessageIter dictEntryIter;
401 AtkAttribute *attribute = (AtkAttribute *) attr->data;
402 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &dictEntryIter);
403 dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->name);
404 dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->value);
405 dbus_message_iter_close_container (iter, &dictEntryIter);
406 attr = g_slist_next (attr);
410 /*END------------------------------------------------------------------------*/