2009-08-28 Mike Gorse <mgorse@novell.com>
[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
31 #include "adaptors.h"
32
33 /*---------------------------------------------------------------------------*/
34
35 /*
36  * Marshals the D-Bus path of an AtkObject into a D-Bus message.
37  *
38  * Unrefs the AtkObject if unref is true.
39  */
40 DBusMessage *
41 spi_dbus_return_object (DBusMessage *message, AtkObject *obj, gboolean do_register, gboolean unref)
42 {
43   DBusMessage *reply;
44   gchar *path;
45
46   path = atk_dbus_object_to_path (obj, do_register);
47
48   if (obj && unref)
49     g_object_unref (obj);
50
51   if (!path)
52     path = g_strdup (SPI_DBUS_PATH_NULL);
53
54   reply = dbus_message_new_method_return (message);
55   if (reply)
56     {
57       dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
58                                 DBUS_TYPE_INVALID);
59     }
60
61   g_free (path);
62
63   return reply;
64 }
65
66 DBusMessage *
67 spi_dbus_return_hyperlink (DBusMessage *message, AtkHyperlink *link, AtkObject *container, gboolean unref)
68 {
69   return spi_dbus_return_sub_object (message, G_OBJECT (link), G_OBJECT (container), unref);
70 }
71
72 DBusMessage *
73 spi_dbus_return_sub_object (DBusMessage *message, GObject *sub, GObject *container, gboolean unref)
74 {
75   DBusMessage *reply;
76   gchar *path;
77
78   path = atk_dbus_sub_object_to_path (sub, container);
79
80   if (sub && unref)
81     g_object_unref (sub);
82
83   if (!path)
84     path = g_strdup (SPI_DBUS_PATH_NULL);
85
86   reply = dbus_message_new_method_return (message);
87   if (reply)
88     {
89       dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
90                                 DBUS_TYPE_INVALID);
91     }
92
93   g_free (path);
94
95   return reply;
96 }
97
98 /*---------------------------------------------------------------------------*/
99
100 /*
101  * Marshals a variant containing the D-Bus path of an AtkObject into a D-Bus
102  * message.
103  *
104  * Unrefs the object if unref is true.
105  */
106 dbus_bool_t
107 spi_dbus_return_v_object (DBusMessageIter *iter, AtkObject *obj, int unref)
108 {
109   char *path;
110
111   path = atk_dbus_object_to_path (obj, FALSE);
112
113   if (!path)
114     path = g_strdup (SPI_DBUS_PATH_NULL);
115
116   if (unref)
117     g_object_unref (obj);
118
119   return droute_return_v_object (iter, path);
120 }
121
122 /*---------------------------------------------------------------------------*/
123
124 void
125 append_atk_object_interfaces (AtkObject *object, DBusMessageIter *iter)
126 {
127   const gchar *itf;
128
129   itf = SPI_DBUS_INTERFACE_ACCESSIBLE;
130   dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
131
132   if (ATK_IS_ACTION (object))
133     {
134       itf = SPI_DBUS_INTERFACE_ACTION;
135       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
136     }
137
138   if (ATK_IS_COMPONENT (object))
139     {
140       itf = SPI_DBUS_INTERFACE_COMPONENT;
141       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
142     }
143
144   if (ATK_IS_EDITABLE_TEXT (object))
145     {
146       itf = SPI_DBUS_INTERFACE_EDITABLE_TEXT;
147       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
148     }
149
150   if (ATK_IS_TEXT (object))
151     {
152       itf = SPI_DBUS_INTERFACE_TEXT;
153       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
154     }
155
156   if (ATK_IS_HYPERTEXT (object))
157     {
158       itf = SPI_DBUS_INTERFACE_HYPERTEXT;
159       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
160     }
161
162   if (ATK_IS_IMAGE (object))
163     {
164       itf = SPI_DBUS_INTERFACE_IMAGE;
165       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
166     }
167
168   if (ATK_IS_SELECTION (object))
169     {
170       itf = SPI_DBUS_INTERFACE_SELECTION;
171       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
172     }
173
174   if (ATK_IS_TABLE (object))
175     {
176       itf = SPI_DBUS_INTERFACE_TABLE;
177       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
178     }
179
180   if (ATK_IS_VALUE (object))
181     {
182       itf = SPI_DBUS_INTERFACE_VALUE;
183       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
184     }
185
186   if (ATK_IS_STREAMABLE_CONTENT (object))
187     {
188       itf = "org.freedesktop.atspi.StreamableContent";
189       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
190     }
191
192   if (ATK_IS_DOCUMENT (object))
193     {
194       itf = "org.freedesktop.atspi.Collection";
195       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
196       itf = SPI_DBUS_INTERFACE_DOCUMENT;
197       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
198     }
199
200   if (ATK_IS_HYPERLINK_IMPL (object))
201     {
202       itf = SPI_DBUS_INTERFACE_HYPERLINK;
203       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
204     }
205 }
206
207 /*---------------------------------------------------------------------------*/
208
209 /*
210  * Marshals the given AtkObject into the provided D-Bus iterator.
211  *
212  * The object is marshalled including all its client side cache data.
213  * The format of the structure is (ooaoassusau).
214  * This is used in the updateTree signal and the getTree method
215  * of the org.freedesktop.atspi.Tree interface.
216  *
217  * To marshal an object its parent, and all its children must already
218  * be registered with D-Bus and have been given a D-Bus object path.
219  */
220 void
221 spi_atk_append_accessible(AtkObject *obj, gpointer iter)
222 {
223   DBusMessageIter *iter_array;
224   DBusMessageIter iter_struct, iter_sub_array;
225   dbus_uint32_t states [2];
226   int count;
227
228   const char *name, *desc;
229   dbus_uint32_t role;
230
231   iter_array = (DBusMessageIter *) iter;
232
233   dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
234     {
235       AtkObject *parent;
236       gchar *path, *path_parent;
237
238       /* Marshall object path */
239       path = atk_dbus_object_to_path (obj, FALSE);
240       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
241
242       /* Marshall parent */
243       parent = atk_object_get_parent(obj);
244       if (parent == NULL)
245         {
246           path_parent = atk_dbus_desktop_object_path ();
247         }
248       else
249         {
250           path_parent = atk_dbus_object_to_path (parent, FALSE);
251           if (!path_parent)
252             {
253               /* This should only happen if a widget is re-parented to
254                * an AtkObject that has not been registered and is then
255                * updated. Ideally objects would be de-registered when
256                * they are removed from a registered tree object, but
257                * this would invalidate a huge amount of cache when
258                * re-parenting.
259                */
260 #if SPI_ATK_DEBUG
261               g_warning ("AT-SPI: Registered accessible marshalled when parent not registered");
262 #endif
263               path_parent = atk_dbus_desktop_object_path ();
264             }
265         }
266       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path_parent);
267       g_free(path_parent);
268
269       /* Marshall children */
270       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_sub_array);
271         {
272           gint childcount, i;
273
274           childcount = atk_object_get_n_accessible_children (obj);
275           for (i = 0; i < childcount; i++)
276             {
277               AtkObject *child;
278               gchar *child_path;
279
280               child = atk_object_ref_accessible_child (obj, i);
281               child_path = atk_dbus_object_to_path (child, FALSE);
282               if (child_path)
283                 {
284                   dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_OBJECT_PATH, &child_path);
285                   g_free (child_path);
286                 }
287               g_object_unref(G_OBJECT(child));
288             }
289         }
290       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
291
292       /* Marshall interfaces */
293       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array);
294       append_atk_object_interfaces (obj, &iter_sub_array);
295       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
296
297       /* Marshall name */
298       name = atk_object_get_name (obj);
299       if (!name)
300         name = "";
301       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
302
303       /* Marshall role */
304       role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
305       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
306
307       /* Marshall description */
308       desc = atk_object_get_description (obj);
309       if (!desc)
310         desc = "";
311       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
312
313       g_free(path);
314
315       /* Marshall state set */
316       spi_atk_state_to_dbus_array (obj, states);
317       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_sub_array);
318       for (count = 0; count < 2; count++)
319         {
320           dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32, &states[count]);
321         }
322       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
323     }
324   dbus_message_iter_close_container (iter_array, &iter_struct);
325 }
326
327 void
328 spi_atk_append_attribute_set (DBusMessageIter *iter, AtkAttributeSet *attr)
329 {
330   DBusMessageIter dictIter;
331
332   dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}", &dictIter);
333   spi_atk_append_attribute_set_inner (&dictIter, attr);
334   dbus_message_iter_close_container (iter, &dictIter);
335 }
336
337 void
338 spi_atk_append_attribute_set_inner (DBusMessageIter *iter, AtkAttributeSet *attr)
339 {
340   DBusMessageIter dictEntryIter;
341
342   while (attr)
343     {
344       AtkAttribute *attribute = (AtkAttribute *) attr->data;
345       dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &dictEntryIter);
346       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->name);
347       dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING, &attribute->value);
348       dbus_message_iter_close_container (iter, &dictEntryIter);
349       attr = g_slist_next (attr);
350     }
351 }
352
353 /*END------------------------------------------------------------------------*/
354