65528cfcb51a7d5bc4cd3b221818fb0ea2e2a646
[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 #include <droute/introspect-loader.h>
27
28 #include "accessible.h"
29 #include "bridge.h"
30
31 extern SpiAppData *app_data;
32 static gboolean update_pending = FALSE;
33
34 /*---------------------------------------------------------------------------*/
35
36 static const char *dumm = "/APath/1";
37
38 /*
39  * Marshals the given AtkObject into the provided D-Bus iterator.
40  *
41  * The object is marshalled including all its client side cache data.
42  * The format of the structure is (ooaoassusau).
43  * This is used in the updateTree signal and the getTree method
44  * of the org.freedesktop.atspi.Tree interface.
45  */
46 static void
47 append_accessible(gpointer ref, gpointer obj_data, gpointer iter)
48 {
49   AtkObject *obj;
50   DBusMessageIter *iter_array;
51   DBusMessageIter iter_struct, iter_sub_array;
52   DRouteData *data;
53   dbus_int32_t *states;
54   int count;
55
56   const char *name, *desc;
57   int i;
58   dbus_uint32_t role;
59   GSList *l;
60
61   obj = ATK_OBJECT(obj_data);
62   iter_array = (DBusMessageIter *) iter;
63   data = &(app_data->droute);
64
65   dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
66     {
67       AtkObject *parent;
68       gchar *path, *path_parent;
69
70       path = atk_dbus_get_path_from_ref(GPOINTER_TO_INT(ref));
71       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
72
73       parent = atk_object_get_parent(obj);
74       if (parent == NULL)
75         path_parent = g_strdup("/");
76       else
77         path_parent = atk_dbus_get_path (parent);
78       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path_parent);
79       g_free(path_parent);
80
81       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_sub_array);
82         {
83           gint childcount, i;
84
85           childcount = atk_object_get_n_accessible_children (obj);
86           for (i = 0; i < childcount; i++)
87             {
88               AtkObject *child;
89               gchar *child_path;
90               
91               child = atk_object_ref_accessible_child (obj, i);
92               child_path = atk_dbus_get_path (child);
93               g_object_unref(G_OBJECT(child));
94               dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_OBJECT_PATH, &child_path);
95               g_free (child_path);
96             }
97         }
98       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
99
100       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array);
101         {
102           for (l = data->interfaces; l; l = g_slist_next (l))
103             {
104               DRouteInterface *iface_def = (DRouteInterface *) l->data;
105               void *datum = NULL;
106
107               if (iface_def->get_datum)
108                 {
109                   datum = (*iface_def->get_datum) (path, data->user_data);
110                   if (!datum)
111                     continue;
112                 }
113               dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_STRING, &iface_def->name);
114               if (iface_def->free_datum)
115                 (*iface_def->free_datum) (datum);
116             }
117         }
118       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
119
120       name = atk_object_get_name (obj);
121       if (!name)
122         name = "";
123       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
124
125       role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
126       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
127
128       desc = atk_object_get_description (obj);
129       if (!desc)
130         desc = "";
131       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
132
133       g_free(path);
134     }      
135   spi_atk_state_to_dbus_array (obj, &states);
136       dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_sub_array);
137   for (count = 0; states[count]; count++)
138     dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32, &states[count]);
139       dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
140   dbus_message_iter_close_container (iter_array, &iter_struct);
141 }
142
143 /*---------------------------------------------------------------------------*/
144
145 /*
146  * Used to marshal array of objects to remove.
147  * Marshalls an object path onto the iter provided.
148  */
149 static void
150 append_accessible_path(gpointer ref_data, gpointer null, gpointer data)
151 {
152   guint ref;
153   gchar *path;
154   DBusMessageIter *iter_array;
155
156   iter_array = (DBusMessageIter *) data;
157   ref = GPOINTER_TO_INT(ref_data);
158   path = atk_dbus_get_path_from_ref(ref);
159   dbus_message_iter_append_basic (iter_array, DBUS_TYPE_OBJECT_PATH, &path);
160   g_free(path);
161 }
162
163 /*---------------------------------------------------------------------------*/
164
165 static gboolean
166 send_cache_update(gpointer d)
167 {
168   DBusMessage *message;
169   DBusMessageIter iter;
170   DBusMessageIter iter_array;
171   DRouteData *data;
172
173   data = &(app_data->droute);
174
175   message = dbus_message_new_signal ("/org/freedesktop/atspi/tree", SPI_DBUS_INTERFACE_TREE, "updateTree");
176
177   dbus_message_iter_init_append (message, &iter);
178
179   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ooaoassusau)", &iter_array);
180   atk_dbus_foreach_update_list(append_accessible, &iter_array);
181   dbus_message_iter_close_container(&iter, &iter_array);
182
183   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array);
184   atk_dbus_foreach_remove_list(append_accessible_path, &iter_array);
185   dbus_message_iter_close_container(&iter, &iter_array);
186
187   dbus_connection_send(data->bus, message, NULL);
188   update_pending = FALSE;
189
190   return FALSE;
191 }
192
193 /*---------------------------------------------------------------------------*/
194
195 void
196 atk_tree_cache_needs_update(void)
197 {
198   if (!update_pending)
199     {
200       g_idle_add(send_cache_update, NULL);
201       update_pending = TRUE;
202     }
203 }
204
205 /*---------------------------------------------------------------------------*/
206
207 static DBusMessage *
208 impl_getRoot (DBusConnection *bus, DBusMessage *message, void *user_data)
209 {
210   AtkObject *root = atk_get_root();
211   char *path;
212   DBusMessage *reply;
213
214   if (root) path = atk_dbus_get_path(root);
215   if (!root || !path)
216     return spi_dbus_general_error (message);
217   reply = dbus_message_new_method_return (message);
218   dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
219   g_free (path);
220   return reply;
221 }
222
223 /*---------------------------------------------------------------------------*/
224
225 static DBusMessage *
226 impl_getTree (DBusConnection *bus, DBusMessage *message, void *user_data)
227 {
228   DBusMessage *reply;
229   DBusMessageIter iter, iter_array;
230   AtkObject *root = atk_get_root();
231
232   if (!root) 
233      return spi_dbus_general_error(message);
234   reply = dbus_message_new_method_return (message);
235
236   dbus_message_iter_init_append (reply, &iter);
237   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ooaoassusau)", &iter_array);
238   atk_dbus_foreach_registered(append_accessible, &iter_array);
239   dbus_message_iter_close_container(&iter, &iter_array);
240   return reply;
241 }
242
243 /*---------------------------------------------------------------------------*/
244
245 static DBusMessage *
246 impl_introspect (DBusConnection *bus, DBusMessage *message, void *user_data)
247 {
248   const char *path;
249   GString *output;
250   char *final;
251
252   DBusMessage *reply;
253
254   path = dbus_message_get_path(message);
255
256   output = g_string_new(spi_introspection_header);
257   
258   g_string_append_printf(output, spi_introspection_node_element, path);
259
260   spi_append_interface(output, SPI_DBUS_INTERFACE_TREE);
261
262   g_string_append(output, spi_introspection_footer);
263   final = g_string_free(output, FALSE);
264
265   reply = dbus_message_new_method_return (message);
266   g_assert(reply != NULL);
267   dbus_message_append_args(reply, DBUS_TYPE_STRING, &final,
268                            DBUS_TYPE_INVALID);
269
270   g_free(final);
271   return reply;
272 }
273
274 /*---------------------------------------------------------------------------*/
275
276 static DBusHandlerResult
277 message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
278 {
279   const char *iface = dbus_message_get_interface (message);
280   const char *member = dbus_message_get_member (message);
281
282   DBusMessage *reply = NULL;
283
284   g_return_val_if_fail(iface != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
285   
286   if (!strcmp(iface, SPI_DBUS_INTERFACE_TREE))
287     {
288       if (!strcmp(member, "getRoot"))
289         {
290           reply = impl_getRoot(bus, message, user_data);
291         }
292
293       if (!strcmp(member, "getTree"))
294         {
295           reply = impl_getTree(bus, message, user_data);
296         }
297     }
298
299   if (!strcmp(iface, "org.freedesktop.DBus.Introspectable"))
300     {
301       if (!strcmp(member, "Introspect"))
302         {
303           reply = impl_introspect(bus, message, user_data);
304         }
305     }
306
307   if (reply)
308     {
309       dbus_connection_send (bus, reply, NULL);
310       dbus_message_unref (reply);
311     }
312
313   return DBUS_HANDLER_RESULT_HANDLED;
314 }
315
316 /*---------------------------------------------------------------------------*/
317
318 static DBusObjectPathVTable tree_vtable =
319 {
320   NULL,
321   &message_handler,
322   NULL, NULL, NULL, NULL
323 };
324
325 /*---------------------------------------------------------------------------*/
326
327 void
328 spi_register_tree_object(DBusConnection *bus,
329                          DRouteData *data,
330                          const char *path)
331 {
332   dbus_bool_t mem = FALSE;
333   mem = dbus_connection_register_object_path(bus, path, &tree_vtable, data);
334   g_assert(mem == TRUE);
335 }
336
337 /*END------------------------------------------------------------------------*/