Finished collection support
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / accessible-marshaller.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008 Novell, Inc.
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include <droute/droute.h>
24
25 #include "common/spi-dbus.h"
26 #include "common/spi-stateset.h"
27
28 #include "accessible-register.h"
29 #include "accessible-marshaller.h"
30 #include "bridge.h"
31
32 #include "adaptors.h"
33
34 /*---------------------------------------------------------------------------*/
35
36 void
37 spi_dbus_append_name_and_path_inner (DBusMessageIter *iter, const char *bus_name, const char *path)
38 {
39   DBusMessageIter iter_struct;
40
41   if (!bus_name)
42     bus_name = "";
43
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);
48 }
49
50 extern gchar *atspi_dbus_name;
51
52 void
53 spi_dbus_append_name_and_path (DBusMessage *message, DBusMessageIter *iter, AtkObject *obj, gboolean do_register, gboolean unref)
54 {
55   gchar *path;
56   DBusMessageIter iter_struct;
57
58   path = atk_dbus_object_to_path (obj, do_register);
59
60   if (!path)
61     path = g_strdup (SPI_DBUS_PATH_NULL);
62
63   spi_dbus_append_name_and_path_inner (iter, atspi_dbus_name, path);
64
65   g_free (path);
66   if (obj && unref)
67     g_object_unref (obj);
68 }
69
70 /*
71  * Marshals the D-Bus path of an AtkObject into a D-Bus message.
72  *
73  * Unrefs the AtkObject if unref is true.
74  */
75 DBusMessage *
76 spi_dbus_return_object (DBusMessage *message, AtkObject *obj, gboolean do_register, gboolean unref)
77 {
78   DBusMessage *reply;
79   reply = dbus_message_new_method_return (message);
80   if (reply)
81     {
82       DBusMessageIter iter;
83       dbus_message_iter_init_append (reply, &iter);
84       spi_dbus_append_name_and_path (message, &iter, obj, do_register, unref);
85     }
86
87   return reply;
88 }
89
90 DBusMessage *
91 spi_dbus_return_hyperlink (DBusMessage *message, AtkHyperlink *link, AtkObject *container, gboolean unref)
92 {
93   return spi_dbus_return_sub_object (message, G_OBJECT (link), G_OBJECT (container), unref);
94 }
95
96 DBusMessage *
97 spi_dbus_return_sub_object (DBusMessage *message, GObject *sub, GObject *container, gboolean unref)
98 {
99   DBusMessage *reply;
100   gchar *path;
101
102   path = atk_dbus_sub_object_to_path (sub, container);
103
104   if (sub && unref)
105     g_object_unref (sub);
106
107   if (!path)
108     path = g_strdup (SPI_DBUS_PATH_NULL);
109
110   reply = dbus_message_new_method_return (message);
111   if (reply)
112     {
113       dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
114                                 DBUS_TYPE_INVALID);
115     }
116
117   g_free (path);
118
119   return reply;
120 }
121
122 /*---------------------------------------------------------------------------*/
123
124 /*
125  * Marshals a variant containing the D-Bus path of an AtkObject into a D-Bus
126  * message.
127  *
128  * Unrefs the object if unref is true.
129  */
130 dbus_bool_t
131 spi_dbus_return_v_object (DBusMessageIter *iter, AtkObject *obj, int unref)
132 {
133   DBusMessageIter iter_variant;
134   char *path;
135
136   path = atk_dbus_object_to_path (obj, FALSE);
137
138   if (!path)
139     path = g_strdup (SPI_DBUS_PATH_NULL);
140
141   if (unref)
142     g_object_unref (obj);
143
144   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)", &iter_variant);
145   spi_dbus_append_name_and_path_inner (&iter_variant, NULL, path);
146   dbus_message_iter_close_container (iter, &iter_variant);
147   return TRUE;
148 }
149
150 /*---------------------------------------------------------------------------*/
151
152 void
153 append_atk_object_interfaces (AtkObject *object, DBusMessageIter *iter)
154 {
155   const gchar *itf;
156
157   itf = SPI_DBUS_INTERFACE_ACCESSIBLE;
158   dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
159
160   if (ATK_IS_ACTION (object))
161     {
162       itf = SPI_DBUS_INTERFACE_ACTION;
163       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
164     }
165
166   if (ATK_IS_COMPONENT (object))
167     {
168       itf = SPI_DBUS_INTERFACE_COMPONENT;
169       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
170     }
171
172   if (ATK_IS_EDITABLE_TEXT (object))
173     {
174       itf = SPI_DBUS_INTERFACE_EDITABLE_TEXT;
175       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
176     }
177
178   if (ATK_IS_TEXT (object))
179     {
180       itf = SPI_DBUS_INTERFACE_TEXT;
181       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
182     }
183
184   if (ATK_IS_HYPERTEXT (object))
185     {
186       itf = SPI_DBUS_INTERFACE_HYPERTEXT;
187       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
188     }
189
190   if (ATK_IS_IMAGE (object))
191     {
192       itf = SPI_DBUS_INTERFACE_IMAGE;
193       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
194     }
195
196   if (ATK_IS_SELECTION (object))
197     {
198       itf = SPI_DBUS_INTERFACE_SELECTION;
199       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
200     }
201
202   if (ATK_IS_TABLE (object))
203     {
204       itf = SPI_DBUS_INTERFACE_TABLE;
205       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
206     }
207
208   if (ATK_IS_VALUE (object))
209     {
210       itf = SPI_DBUS_INTERFACE_VALUE;
211       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
212     }
213
214   if (ATK_IS_STREAMABLE_CONTENT (object))
215     {
216       itf = "org.freedesktop.atspi.StreamableContent";
217       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
218     }
219
220   if (ATK_IS_DOCUMENT (object))
221     {
222       itf = "org.freedesktop.atspi.Collection";
223       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
224       itf = SPI_DBUS_INTERFACE_DOCUMENT;
225       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
226     }
227
228   if (ATK_IS_HYPERLINK_IMPL (object))
229     {
230       itf = SPI_DBUS_INTERFACE_HYPERLINK;
231       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
232     }
233 }
234
235 /*---------------------------------------------------------------------------*/
236
237 /*
238  * Marshals the given AtkObject into the provided D-Bus iterator.
239  *
240  * The object is marshalled including all its client side cache data.
241  * The format of the structure is (o(so)a(so)assusau).
242  * This is used in the updateTree signal and the GetTree method
243  * of the org.freedesktop.atspi.Tree interface.
244  *
245  * To marshal an object its parent, and all its children must already
246  * be registered with D-Bus and have been given a D-Bus object path.
247  */
248 void
249 spi_atk_append_accessible(AtkObject *obj, gpointer data)
250 {
251   DBusMessageIter iter_struct, iter_sub_array;
252   dbus_uint32_t states [2];
253   int count;
254   AtkStateSet *set;
255   DBusMessageIter *iter_array = (DBusMessageIter *)data;
256
257   const char *name, *desc;
258   dbus_uint32_t role;
259
260   set = atk_object_ref_state_set (obj);
261     {
262       AtkObject *parent;
263       gchar *path;
264       gchar *bus_parent = NULL, *path_parent;
265
266       /* Marshall object path */
267       path = atk_dbus_object_to_path (obj, FALSE);
268
269       role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
270
271       /* Marshall parent */
272       parent = atk_object_get_parent(obj);
273       if (parent == NULL)
274         {
275           /* TODO: Support getting parent of an AtkPlug */
276 #ifdef __ATK_PLUG_H__
277           if (role != Accessibility_ROLE_APPLICATION && !ATK_IS_PLUG (obj))
278 #else
279           if (role != Accessibility_ROLE_APPLICATION)
280 #endif
281             path_parent = g_strdup (SPI_DBUS_PATH_NULL);
282           else
283             path_parent = atk_dbus_desktop_object_path ();
284         }
285       else
286         {
287           path_parent = atk_dbus_object_to_path (parent, FALSE);
288           if (!path_parent)
289             {
290               /* This should only happen if a widget is re-parented to
291                * an AtkObject that has not been registered and is then
292                * updated. Ideally objects would be de-registered when
293                * they are removed from a registered tree object, but
294                * this would invalidate a huge amount of cache when
295                * re-parenting.
296                */
297 #if SPI_ATK_DEBUG
298               g_warning ("AT-SPI: Registered accessible marshalled when parent not registered");
299 #endif
300               path_parent = atk_dbus_desktop_object_path ();
301             }
302         }
303
304       dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
305       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
306       spi_dbus_append_name_and_path_inner (&iter_struct, bus_parent, path_parent);
307       g_free(path_parent);
308       g_free (bus_parent);
309
310       /* Marshall children */
311       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_sub_array);
312       if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS))
313         {
314           gint childcount, i;
315
316           childcount = atk_object_get_n_accessible_children (obj);
317           for (i = 0; i < childcount; i++)
318             {
319               AtkObject *child;
320               gchar *child_path;
321
322               child = atk_object_ref_accessible_child (obj, i);
323               child_path = atk_dbus_object_to_path (child, FALSE);
324               if (child_path)
325                 {
326                   spi_dbus_append_name_and_path_inner (&iter_sub_array, NULL, child_path);
327                   g_free (child_path);
328                 }
329               g_object_unref(G_OBJECT(child));
330             }
331         }
332 #ifdef __ATK_PLUG_H__
333       if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET(obj)))
334         {
335           AtkSocket *socket = ATK_SOCKET(obj);
336           gchar *child_name, *child_path;
337           child_name = g_strdup (socket->embedded_plug_id);
338           child_path = g_utf8_strchr (child_name + 1, -1, ':');
339           if (child_path)
340             {
341               *(child_path++) = '\0';
342               spi_dbus_append_name_and_path_inner (&iter_sub_array, child_name, child_path);
343             }
344           g_free (child_name);
345         }
346 #endif
347
348       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
349
350       /* Marshall interfaces */
351       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array);
352       append_atk_object_interfaces (obj, &iter_sub_array);
353       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
354
355       /* Marshall name */
356       name = atk_object_get_name (obj);
357       if (!name)
358         name = "";
359       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
360
361       /* Marshall role */
362       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
363
364       /* Marshall description */
365       desc = atk_object_get_description (obj);
366       if (!desc)
367         desc = "";
368       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
369
370       g_free(path);
371
372       /* Marshall state set */
373       spi_atk_state_set_to_dbus_array (set, states);
374       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_sub_array);
375       for (count = 0; count < 2; count++)
376         {
377           dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32, &states[count]);
378         }
379       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
380     }
381   dbus_message_iter_close_container (iter_array, &iter_struct);
382   g_object_unref (set);
383 }
384
385 void
386 spi_atk_append_attribute_set (DBusMessageIter *iter, AtkAttributeSet *attr)
387 {
388   DBusMessageIter dictIter;
389
390   dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}", &dictIter);
391   spi_atk_append_attribute_set_inner (&dictIter, attr);
392   dbus_message_iter_close_container (iter, &dictIter);
393 }
394
395 void
396 spi_atk_append_attribute_set_inner (DBusMessageIter *iter, AtkAttributeSet *attr)
397 {
398   DBusMessageIter dictEntryIter;
399
400   while (attr)
401     {
402       AtkAttribute *attribute = (AtkAttribute *) attr->data;
403       dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &dictEntryIter);
404       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->name);
405       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->value);
406       dbus_message_iter_close_container (iter, &dictEntryIter);
407       attr = g_slist_next (attr);
408     }
409 }
410
411 /*END------------------------------------------------------------------------*/
412