2009-01-09 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / tree.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  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <string.h>
26
27 #include <atk/atk.h>
28 #include <droute/droute.h>
29
30 #include "atk-dbus.h"
31 #include "spi-common/spi-dbus.h"
32 #include "bridge.h"
33
34 /*---------------------------------------------------------------------------*/
35
36 static void
37 append_atk_object_interfaces (AtkObject *object, DBusMessageIter *iter)
38 {
39   const gchar *itf;
40
41   itf = SPI_DBUS_INTERFACE_ACCESSIBLE;
42   dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
43
44   if (ATK_IS_ACTION (object))
45     {
46       itf = SPI_DBUS_INTERFACE_ACTION;
47       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
48     }
49
50   if (ATK_IS_COMPONENT (object))
51     {
52       itf = SPI_DBUS_INTERFACE_COMPONENT;
53       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
54     }
55
56   if (ATK_IS_EDITABLE_TEXT (object))
57     {
58       itf = SPI_DBUS_INTERFACE_EDITABLE_TEXT;
59       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
60     }
61
62   if (ATK_IS_TEXT (object))
63     {
64       itf = SPI_DBUS_INTERFACE_TEXT;
65       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
66     }
67
68   if (ATK_IS_HYPERTEXT (object))
69     {
70       itf = SPI_DBUS_INTERFACE_HYPERTEXT;
71       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
72     }
73
74   if (ATK_IS_IMAGE (object))
75     {
76       itf = SPI_DBUS_INTERFACE_IMAGE;
77       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
78     }
79
80   if (ATK_IS_SELECTION (object))
81     {
82       itf = SPI_DBUS_INTERFACE_SELECTION;
83       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
84     }
85
86   if (ATK_IS_TABLE (object))
87     {
88       itf = SPI_DBUS_INTERFACE_TABLE;
89       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
90     }
91
92   if (ATK_IS_VALUE (object))
93     {
94       itf = SPI_DBUS_INTERFACE_VALUE;
95       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
96     }
97
98   if (ATK_IS_STREAMABLE_CONTENT (object))
99     {
100       itf = "org.freedesktop.atspi.StreamableContent";
101       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
102     }
103
104   if (ATK_IS_DOCUMENT (object))
105     {
106       itf = "org.freedesktop.atspi.Collection";
107       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
108       itf = SPI_DBUS_INTERFACE_DOCUMENT;
109       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
110     }
111
112   if (ATK_IS_HYPERLINK_IMPL (object))
113     {
114       itf = SPI_DBUS_INTERFACE_HYPERLINK;
115       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
116     }
117 }
118
119 /*---------------------------------------------------------------------------*/
120
121 static const char *dumm = "/APath/1";
122
123
124 /*
125  * Marshals the given AtkObject into the provided D-Bus iterator.
126  *
127  * The object is marshalled including all its client side cache data.
128  * The format of the structure is (ooaoassusau).
129  * This is used in the updateTree signal and the getTree method
130  * of the org.freedesktop.atspi.Tree interface.
131  */
132 static void
133 append_accessible(gpointer obj_data, gpointer iter)
134 {
135   AtkObject *obj;
136   DBusMessageIter *iter_array;
137   DBusMessageIter iter_struct, iter_sub_array;
138   dbus_int32_t states [2];
139   int count;
140
141   const char *name, *desc;
142   int i;
143   dbus_uint32_t role;
144   GSList *l;
145
146   obj = ATK_OBJECT(obj_data);
147   iter_array = (DBusMessageIter *) iter;
148
149   dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
150     {
151       AtkObject *parent;
152       gchar *path, *path_parent;
153
154       path = atk_dbus_object_to_path (obj);
155       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
156
157       parent = atk_object_get_parent(obj);
158       if (parent == NULL)
159         path_parent = g_strdup("/");
160       else
161         path_parent = atk_dbus_object_to_path (parent);
162       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path_parent);
163       g_free(path_parent);
164
165       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_sub_array);
166         {
167           gint childcount, i;
168
169           childcount = atk_object_get_n_accessible_children (obj);
170           for (i = 0; i < childcount; i++)
171             {
172               AtkObject *child;
173               gchar *child_path;
174
175               child = atk_object_ref_accessible_child (obj, i);
176               child_path = atk_dbus_object_to_path (child);
177               g_object_unref(G_OBJECT(child));
178               if (G_LIKELY (child_path))
179                 {
180                   dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_OBJECT_PATH, &child_path);
181                 }
182               else
183                 {
184                   g_critical ("AT-SPI: Child object exists in accessible tree but has not been registered");
185                   g_free (child_path);
186                 }
187             }
188         }
189       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
190
191       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array);
192       append_atk_object_interfaces (obj, &iter_sub_array);
193       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
194
195       name = atk_object_get_name (obj);
196       if (!name)
197         name = "";
198       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
199
200       role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
201       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
202
203       desc = atk_object_get_description (obj);
204       if (!desc)
205         desc = "";
206       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
207
208       g_free(path);
209     }
210   spi_atk_state_to_dbus_array (obj, &states);
211       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_sub_array);
212   for (count = 0; count < 2; count++)
213     dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32, &states[count]);
214       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
215   dbus_message_iter_close_container (iter_array, &iter_struct);
216 }
217
218 /* For use as a GHFunc */
219 static void
220 append_accessible_hf (gpointer key, gpointer obj_data, gpointer iter)
221 {
222   append_accessible (obj_data, iter);
223 }
224
225 /*---------------------------------------------------------------------------*/
226
227 void
228 spi_emit_cache_removal (guint ref,  DBusConnection *bus)
229 {
230   DBusMessage *message;
231   DBusMessageIter iter;
232   gchar *path;
233
234   message = dbus_message_new_signal ("/org/freedesktop/atspi/tree", SPI_DBUS_INTERFACE_TREE, "removeAccessible");
235
236   dbus_message_iter_init_append (message, &iter);
237
238   path = atk_dbus_ref_to_path (ref);
239   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &path);
240
241   dbus_connection_send(bus, message, NULL);
242 }
243
244 void
245 spi_emit_cache_update (const GList *accessibles, DBusConnection *bus)
246 {
247    DBusMessage *message;
248    DBusMessageIter iter;
249    DBusMessageIter iter_array;
250    message = dbus_message_new_signal ("/org/freedesktop/atspi/tree", SPI_DBUS_INTERFACE_TREE, "updateAccessible");
251
252    dbus_message_iter_init_append (message, &iter);
253    dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ooaoassusau)", &iter_array);
254    g_list_foreach ((GList *)accessibles, append_accessible, &iter_array);
255    dbus_message_iter_close_container(&iter, &iter_array);
256
257    dbus_connection_send(bus, message, NULL);
258 }
259
260
261 /*---------------------------------------------------------------------------*/
262
263 static DBusMessage *
264 impl_getRoot (DBusConnection *bus, DBusMessage *message, void *user_data)
265 {
266   AtkObject *root = atk_get_root();
267   char *path;
268   DBusMessage *reply;
269
270   if (!root)
271       return spi_dbus_general_error (message);
272   path = atk_dbus_object_to_path (root);
273   if (!path)
274       return spi_dbus_general_error (message);
275   reply = dbus_message_new_method_return (message);
276   dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
277   g_free (path);
278   return reply;
279 }
280
281 /*---------------------------------------------------------------------------*/
282
283 static DBusMessage *
284 impl_getTree (DBusConnection *bus, DBusMessage *message, void *user_data)
285 {
286   DBusMessage *reply;
287   DBusMessageIter iter, iter_array;
288
289   reply = dbus_message_new_method_return (message);
290
291   dbus_message_iter_init_append (reply, &iter);
292   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ooaoassusau)", &iter_array);
293   atk_dbus_foreach_registered(append_accessible_hf, &iter_array);
294   dbus_message_iter_close_container(&iter, &iter_array);
295   return reply;
296 }
297
298 /*---------------------------------------------------------------------------*/
299
300 static DRouteMethod methods[] = {
301   {impl_getRoot, "getRoot"},
302   {impl_getTree, "getTree"},
303   {NULL, NULL}
304 };
305
306 void
307 spi_initialize_tree (DRoutePath *path)
308 {
309   droute_path_add_interface (path,
310                              SPI_DBUS_INTERFACE_TREE,
311                              methods,
312                              NULL);
313 };
314
315 /*END------------------------------------------------------------------------*/