Merge branch 'mgorse' of ssh://git.codethink.co.uk/git/atspi-dbus
[platform/core/uifw/at-spi2-atk.git] / libspi / 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 "accessible.h"
26
27 #define get_object(message) spi_dbus_get_object(dbus_message_get_path(message))
28
29 static dbus_bool_t
30 spi_dbus_append_tree_helper (DBusMessageIter * iter_array, AtkObject * obj,
31                              DRouteData * data)
32 {
33   DBusMessageIter iter_struct, iter_sub, iter_sub_array;
34   char *path = NULL;
35   const char *name, *desc;
36   dbus_uint16_t updating = 1;
37   int i;
38   dbus_uint32_t role;
39
40   gint childcount;
41   GSList *l;
42
43   dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
44                                     &iter_struct);
45   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT16, &updating);
46   path = spi_dbus_get_path (obj);
47   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
48   dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
49                                     &iter_sub);
50   dbus_message_iter_open_container (&iter_sub, DBUS_TYPE_ARRAY, "o",
51                                     &iter_sub_array);
52   childcount = atk_object_get_n_accessible_children (obj);
53   for (i = 0; i < childcount; i++)
54     {
55       AtkObject *child = atk_object_ref_accessible_child (obj, i);
56       char *child_path = spi_dbus_get_path (child);
57       if (child_path)
58         {
59           dbus_message_iter_append_basic (&iter_sub_array,
60                                           DBUS_TYPE_OBJECT_PATH, &child_path);
61           g_free (child_path);
62         }
63       if (child)
64         g_object_unref (child);
65     }
66   if (!dbus_message_iter_close_container (&iter_sub, &iter_sub_array))
67     goto oom;
68   dbus_message_iter_open_container (&iter_sub, DBUS_TYPE_ARRAY, "s",
69                                     &iter_sub_array);
70   for (l = data->interfaces; l; l = g_slist_next (l))
71     {
72       DRouteInterface *iface_def = (DRouteInterface *) l->data;
73       void *datum;
74       if (iface_def->get_datum)
75         {
76           datum = (*iface_def->get_datum) (path, data->user_data);
77           if (!datum)
78             continue;
79         }
80       dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_STRING,
81                                       &iface_def->name);
82       if (iface_def->free_datum)
83         (*iface_def->free_datum) (datum);
84     }
85   if (!dbus_message_iter_close_container (&iter_sub, &iter_sub_array))
86     goto oom;
87   name = atk_object_get_name (obj);
88   if (!name)
89     name = "";
90   dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_STRING, &name);
91   role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
92   dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_UINT32, &role);
93   desc = atk_object_get_description (obj);
94   if (!desc)
95     desc = "";
96   dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_STRING, &desc);
97   if (!dbus_message_iter_close_container (&iter_struct, &iter_sub))
98     goto oom;
99   if (!dbus_message_iter_close_container (iter_array, &iter_struct))
100     goto oom;
101   for (i = 0; i < childcount; i++)
102     {
103       AtkObject *child = atk_object_ref_accessible_child (obj, i);
104       dbus_bool_t result;
105       if (!child)
106         continue;
107       result = spi_dbus_append_tree_helper (iter_array, child, data);
108       g_object_unref (child);
109       if (!result)
110         goto oom;
111     }
112   g_free (path);
113   return TRUE;
114 oom:
115   if (path) g_free(path);
116   return FALSE;
117 }
118
119 dbus_bool_t
120 spi_dbus_append_tree (DBusMessage * message, AtkObject * obj,
121                       DRouteData * data)
122 {
123   DBusMessageIter iter, iter_array;
124   dbus_bool_t result;
125
126   dbus_message_iter_init_append (message, &iter);
127   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(qo(aoassus))",
128                                     &iter_array);
129   result = spi_dbus_append_tree_helper (&iter_array, obj, data);
130   if (result)
131     result = dbus_message_iter_close_container (&iter, &iter_array);
132   return result;
133 }
134
135 static DBusMessage *
136 impl_getTree (DBusConnection * bus, DBusMessage * message, void *user_data)
137 {
138   DBusMessage *reply;
139   AtkObject *root;
140   gchar *path;
141
142   root = atk_get_root ();
143   if (root)
144     path = spi_dbus_get_path (root);
145   if (!root || !path)
146     return spi_dbus_general_error (message);
147   reply = dbus_message_new_method_return (message);
148   dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
149                             DBUS_TYPE_INVALID);
150   g_free (path);
151   spi_dbus_append_tree (reply, root, (DRouteData *) user_data);
152   return reply;
153 }
154
155 static DRouteMethod methods[] = {
156   {DROUTE_METHOD, impl_getTree, "getTree", "o,root,o:a(go(aoassus)),tree,o",
157    TRUE},
158   {0, NULL, NULL, NULL}
159 };
160
161 void
162 spi_initialize_tree (DRouteData * data)
163 {
164   droute_add_interface (data, "org.freedesktop.atspi.AccessibleTree",
165                         methods, NULL, NULL, NULL);
166 };