Fix compile-time warnings
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / adaptors / cache-adaptor.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  * Copyright 2008, 2009 Codethink Ltd.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #include <string.h>
27
28 #include <atk/atk.h>
29 #include <droute/droute.h>
30
31 #include "spi-dbus.h"
32 #include "accessible-stateset.h"
33 #include "accessible-cache.h"
34 #include "bridge.h"
35 #include "object.h"
36 #include "introspection.h"
37
38 /* TODO - This should possibly be a common define */
39 #define SPI_OBJECT_PREFIX "/org/a11y/atspi"
40 #define SPI_CACHE_OBJECT_SUFFIX "/cache"
41 #define SPI_CACHE_OBJECT_PATH SPI_OBJECT_PREFIX SPI_CACHE_OBJECT_SUFFIX
42
43 #define SPI_OBJECT_REFERENCE_SIGNATURE "(" \
44                                           DBUS_TYPE_STRING_AS_STRING \
45                                           DBUS_TYPE_OBJECT_PATH_AS_STRING \
46                                        ")"
47                                           
48 #define SPI_CACHE_ITEM_SIGNATURE "(" \
49                                    SPI_OBJECT_REFERENCE_SIGNATURE \
50                                    SPI_OBJECT_REFERENCE_SIGNATURE \
51                                    SPI_OBJECT_REFERENCE_SIGNATURE \
52                                    DBUS_TYPE_ARRAY_AS_STRING \
53                                      SPI_OBJECT_REFERENCE_SIGNATURE \
54                                    DBUS_TYPE_ARRAY_AS_STRING \
55                                      DBUS_TYPE_STRING_AS_STRING \
56                                    DBUS_TYPE_STRING_AS_STRING \
57                                    DBUS_TYPE_UINT32_AS_STRING \
58                                    DBUS_TYPE_STRING_AS_STRING \
59                                    DBUS_TYPE_ARRAY_AS_STRING \
60                                      DBUS_TYPE_UINT32_AS_STRING \
61                                  ")"
62
63 /*---------------------------------------------------------------------------*/
64
65 /*
66  * Marshals the given AtkObject into the provided D-Bus iterator.
67  *
68  * The object is marshalled including all its client side cache data.
69  * The format of the structure is (o(so)a(so)assusau).
70  */
71 static void
72 append_cache_item (AtkObject * obj, gpointer data)
73 {
74   DBusMessageIter iter_struct, iter_sub_array;
75   dbus_uint32_t states[2];
76   int count;
77   AtkStateSet *set;
78   DBusMessageIter *iter_array = (DBusMessageIter *) data;
79
80   const char *name, *desc;
81   dbus_uint32_t role;
82
83   set = atk_object_ref_state_set (obj);
84   {
85     AtkObject *application, *parent;
86
87     dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
88                                       &iter_struct);
89
90     /* Marshall object path */
91     spi_object_append_reference (&iter_struct, obj);
92
93     role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
94
95     /* Marshall application */
96     application = spi_global_app_data->root; 
97     spi_object_append_reference (&iter_struct, application);
98
99     /* Marshall parent */
100     parent = atk_object_get_parent (obj);
101     if (parent == NULL)
102       {
103         /* TODO, move in to a 'Plug' wrapper. */
104         if (ATK_IS_PLUG (obj))
105           {
106             char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
107             char *bus_parent;
108             char *path_parent;
109
110             if (id)
111               {
112                 bus_parent = g_strdup (id);
113                 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
114                   {
115                     DBusMessageIter iter_parent;
116                     *(path_parent++) = '\0';
117                     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
118                                                       &iter_parent);
119                     dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
120                     dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
121                     dbus_message_iter_close_container (&iter_struct, &iter_parent);
122                   }
123                 else
124                   {
125                     spi_object_append_null_reference (&iter_struct);
126                   }
127               }
128             else
129               {
130                 spi_object_append_null_reference (&iter_struct);
131               }
132           }
133         else if (role != ATSPI_ROLE_APPLICATION)
134           spi_object_append_null_reference (&iter_struct);
135         else
136           spi_object_append_desktop_reference (&iter_struct);
137       }
138     else
139       {
140         spi_object_append_reference (&iter_struct, parent);
141       }
142
143     /* Marshall children */
144     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)",
145                                       &iter_sub_array);
146     if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) &&
147         !atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
148       {
149         gint childcount, i;
150
151         childcount = atk_object_get_n_accessible_children (obj);
152         for (i = 0; i < childcount; i++)
153           {
154             AtkObject *child;
155
156             child = atk_object_ref_accessible_child (obj, i);
157             spi_object_append_reference (&iter_sub_array, child);
158             g_object_unref (G_OBJECT (child));
159           }
160       }
161     if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
162       {
163         AtkSocket *socket = ATK_SOCKET (obj);
164         gchar *child_name, *child_path;
165         child_name = g_strdup (socket->embedded_plug_id);
166         child_path = g_utf8_strchr (child_name + 1, -1, ':');
167         if (child_path)
168           {
169             DBusMessageIter iter_socket;
170             *(child_path++) = '\0';
171             dbus_message_iter_open_container (&iter_sub_array, DBUS_TYPE_STRUCT, NULL,
172                                               &iter_socket);
173             dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
174             dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
175             dbus_message_iter_close_container (&iter_sub_array, &iter_socket);
176           }
177         g_free (child_name);
178       }
179
180     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
181
182     /* Marshall interfaces */
183     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
184                                       &iter_sub_array);
185     spi_object_append_interfaces (&iter_sub_array, obj);
186     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
187
188     /* Marshall name */
189     name = atk_object_get_name (obj);
190     if (!name)
191       name = "";
192     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
193
194     /* Marshall role */
195     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
196
197     /* Marshall description */
198     desc = atk_object_get_description (obj);
199     if (!desc)
200       desc = "";
201     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
202
203     /* Marshall state set */
204     spi_atk_state_set_to_dbus_array (set, states);
205     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
206                                       &iter_sub_array);
207     for (count = 0; count < 2; count++)
208       {
209         dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
210                                         &states[count]);
211       }
212     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
213   }
214   dbus_message_iter_close_container (iter_array, &iter_struct);
215   g_object_unref (set);
216 }
217
218 /*---------------------------------------------------------------------------*/
219
220 static void
221 ref_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
222 {
223   g_object_ref (key);
224 }
225
226 /* For use as a GHFunc */
227 static void
228 append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
229 {
230   /* Make sure it isn't a hyperlink */
231   if (ATK_IS_OBJECT (key))
232     append_cache_item (ATK_OBJECT (key), data);
233 }
234
235 static void
236 add_to_list_hf (gpointer key, gpointer obj_data, gpointer data)
237 {
238   GSList **listptr = data;
239   *listptr = g_slist_prepend (*listptr, key);
240 }
241
242 /*---------------------------------------------------------------------------*/
243
244 static void
245 emit_cache_remove (SpiCache *cache, GObject * obj)
246 {
247   DBusMessage *message;
248
249   if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
250                                           ATSPI_DBUS_INTERFACE_CACHE,
251                                           "RemoveAccessible")))
252     {
253       DBusMessageIter iter;
254
255       dbus_message_iter_init_append (message, &iter);
256
257       spi_object_append_reference (&iter, ATK_OBJECT (obj));
258
259       dbus_connection_send (spi_global_app_data->bus, message, NULL);
260
261       dbus_message_unref (message);
262     }
263 }
264
265 static void
266 emit_cache_add (SpiCache *cache, GObject * obj)
267 {
268   AtkObject *accessible = ATK_OBJECT (obj);
269   DBusMessage *message;
270
271   if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
272                                           ATSPI_DBUS_INTERFACE_CACHE,
273                                           "AddAccessible")))
274     {
275       DBusMessageIter iter;
276
277       dbus_message_iter_init_append (message, &iter);
278       g_object_ref (accessible);
279       append_cache_item (accessible, &iter);
280       g_object_unref (accessible);
281
282       dbus_connection_send (spi_global_app_data->bus, message, NULL);
283
284       dbus_message_unref (message);
285     }
286 }
287
288
289 /*---------------------------------------------------------------------------*/
290
291 static DBusMessage *
292 impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
293 {
294   return spi_object_return_reference (message, spi_global_app_data->root);
295 }
296
297 /*---------------------------------------------------------------------------*/
298
299 static DBusMessage *
300 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
301 {
302   DBusMessage *reply;
303   DBusMessageIter iter, iter_array;
304   GSList *pending_unrefs = NULL;
305
306   if (bus == spi_global_app_data->bus)
307     spi_atk_add_client (dbus_message_get_sender (message));
308
309   reply = dbus_message_new_method_return (message);
310
311   dbus_message_iter_init_append (reply, &iter);
312   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
313                                     SPI_CACHE_ITEM_SIGNATURE, &iter_array);
314   spi_cache_foreach (spi_global_cache, ref_accessible_hf, NULL);
315   spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
316   spi_cache_foreach (spi_global_cache, add_to_list_hf, &pending_unrefs);
317   g_slist_free_full (pending_unrefs, g_object_unref);
318   dbus_message_iter_close_container (&iter, &iter_array);
319   return reply;
320 }
321
322 /*---------------------------------------------------------------------------*/
323
324 static DRouteMethod methods[] = {
325   {impl_GetRoot, "GetRoot"},
326   {impl_GetItems, "GetItems"},
327   {NULL, NULL}
328 };
329
330 void
331 spi_initialize_cache (DRoutePath * path)
332 {
333   droute_path_add_interface (path, ATSPI_DBUS_INTERFACE_CACHE, spi_org_a11y_atspi_Cache, methods, NULL);
334
335   g_signal_connect (spi_global_cache, "object-added",
336                     (GCallback) emit_cache_add, NULL);
337
338   g_signal_connect (spi_global_cache, "object-removed",
339                     (GCallback) emit_cache_remove, NULL);
340 };
341
342 /*END------------------------------------------------------------------------*/