Plug/socket fixes, and remove conditional
[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 "common/spi-dbus.h"
32 #include "accessible-cache.h"
33 #include "bridge.h"
34 #include "object.h"
35
36 /* TODO - This should possibly be a common define */
37 #define SPI_OBJECT_PREFIX "/org/at_spi"
38 #define SPI_CACHE_OBJECT_SUFFIX "/cache"
39 #define SPI_CACHE_OBJECT_PATH SPI_OBJECT_PREFIX SPI_CACHE_OBJECT_SUFFIX
40
41 #define SPI_OBJECT_REFERENCE_SIGNATURE "(" \
42                                           DBUS_TYPE_STRING_AS_STRING \
43                                           DBUS_TYPE_OBJECT_PATH_AS_STRING \
44                                        ")"
45                                           
46 #define SPI_CACHE_ITEM_SIGNATURE "(" \
47                                    SPI_OBJECT_REFERENCE_SIGNATURE \
48                                    SPI_OBJECT_REFERENCE_SIGNATURE \
49                                    SPI_OBJECT_REFERENCE_SIGNATURE \
50                                    DBUS_TYPE_ARRAY_AS_STRING \
51                                      SPI_OBJECT_REFERENCE_SIGNATURE \
52                                    DBUS_TYPE_ARRAY_AS_STRING \
53                                      DBUS_TYPE_STRING_AS_STRING \
54                                    DBUS_TYPE_STRING_AS_STRING \
55                                    DBUS_TYPE_UINT32_AS_STRING \
56                                    DBUS_TYPE_STRING_AS_STRING \
57                                    DBUS_TYPE_ARRAY_AS_STRING \
58                                      DBUS_TYPE_UINT32_AS_STRING \
59                                  ")"
60
61 /*---------------------------------------------------------------------------*/
62
63 /*
64  * Marshals the given AtkObject into the provided D-Bus iterator.
65  *
66  * The object is marshalled including all its client side cache data.
67  * The format of the structure is (o(so)a(so)assusau).
68  */
69 static void
70 append_cache_item (AtkObject * obj, gpointer data)
71 {
72   DBusMessageIter iter_struct, iter_sub_array;
73   dbus_uint32_t states[2];
74   int count;
75   AtkStateSet *set;
76   DBusMessageIter *iter_array = (DBusMessageIter *) data;
77
78   const char *name, *desc;
79   dbus_uint32_t role;
80
81   set = atk_object_ref_state_set (obj);
82   {
83     AtkObject *application, *parent;
84
85     dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
86                                       &iter_struct);
87
88     /* Marshall object path */
89     spi_object_append_reference (&iter_struct, obj);
90
91     role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
92
93     /* Marshall application */
94     application = spi_global_app_data->root; 
95     spi_object_append_reference (&iter_struct, application);
96
97     /* Marshall parent */
98     parent = atk_object_get_parent (obj);
99     if (parent == NULL)
100       {
101         /* TODO, move in to a 'Plug' wrapper. */
102         if (ATK_IS_PLUG (obj))
103           {
104             char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
105             char *bus_parent;
106             char *path_parent;
107
108             if (id)
109               {
110                 bus_parent = g_strdup (id);
111                 if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
112                   {
113                     DBusMessageIter iter_parent;
114                     *(path_parent++) = '\0';
115                     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
116                                                       &iter_parent);
117                     dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
118                     dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
119                     dbus_message_iter_close_container (&iter_struct, &iter_parent);
120                   }
121                 else
122                   {
123                     spi_object_append_null_reference (&iter_struct);
124                   }
125               }
126             else
127               {
128                 spi_object_append_null_reference (&iter_struct);
129               }
130           }
131         else if (role != Accessibility_ROLE_APPLICATION)
132           spi_object_append_null_reference (&iter_struct);
133         else
134           spi_object_append_desktop_reference (&iter_struct);
135       }
136     else
137       {
138         spi_object_append_reference (&iter_struct, parent);
139       }
140
141     /* Marshall children */
142     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)",
143                                       &iter_sub_array);
144     if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS))
145       {
146         gint childcount, i;
147
148         childcount = atk_object_get_n_accessible_children (obj);
149         for (i = 0; i < childcount; i++)
150           {
151             AtkObject *child;
152             gchar *child_path;
153
154             child = atk_object_ref_accessible_child (obj, i);
155             spi_object_append_reference (&iter_sub_array, child);
156             g_object_unref (G_OBJECT (child));
157           }
158       }
159     if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
160       {
161         AtkSocket *socket = ATK_SOCKET (obj);
162         gchar *child_name, *child_path;
163         child_name = g_strdup (socket->embedded_plug_id);
164         child_path = g_utf8_strchr (child_name + 1, -1, ':');
165         if (child_path)
166           {
167             DBusMessageIter iter_socket;
168             *(child_path++) = '\0';
169             dbus_message_iter_open_container (&iter_sub_array, DBUS_TYPE_STRUCT, NULL,
170                                               &iter_socket);
171             dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
172             dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
173             dbus_message_iter_close_container (&iter_sub_array, &iter_socket);
174           }
175         g_free (child_name);
176       }
177
178     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
179
180     /* Marshall interfaces */
181     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
182                                       &iter_sub_array);
183     spi_object_append_interfaces (&iter_sub_array, obj);
184     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
185
186     /* Marshall name */
187     name = atk_object_get_name (obj);
188     if (!name)
189       name = "";
190     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
191
192     /* Marshall role */
193     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
194
195     /* Marshall description */
196     desc = atk_object_get_description (obj);
197     if (!desc)
198       desc = "";
199     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
200
201     /* Marshall state set */
202     spi_atk_state_set_to_dbus_array (set, states);
203     dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
204                                       &iter_sub_array);
205     for (count = 0; count < 2; count++)
206       {
207         dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
208                                         &states[count]);
209       }
210     dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
211   }
212   dbus_message_iter_close_container (iter_array, &iter_struct);
213   g_object_unref (set);
214 }
215
216 /*---------------------------------------------------------------------------*/
217
218 /* For use as a GHFunc */
219 static void
220 append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
221 {
222   /* Make sure it isn't a hyperlink */
223   if (ATK_IS_OBJECT (key))
224     append_cache_item (ATK_OBJECT (key), data);
225 }
226
227 /*---------------------------------------------------------------------------*/
228
229 static void
230 emit_cache_remove (SpiCache *cache, GObject * obj)
231 {
232   DBusMessage *message;
233
234   if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
235                                           SPI_DBUS_INTERFACE_CACHE,
236                                           "RemoveAccessible")))
237     {
238       DBusMessageIter iter;
239       gchar *path;
240
241       dbus_message_iter_init_append (message, &iter);
242
243       spi_object_append_reference (&iter, ATK_OBJECT (obj));
244
245       dbus_connection_send (spi_global_app_data->bus, message, NULL);
246
247       dbus_message_unref (message);
248     }
249 }
250
251 static void
252 emit_cache_add (SpiCache *cache, GObject * obj)
253 {
254   AtkObject *accessible = ATK_OBJECT (obj);
255   DBusMessage *message;
256
257   if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
258                                           SPI_DBUS_INTERFACE_CACHE,
259                                           "AddAccessible")))
260     {
261       DBusMessageIter iter;
262
263       dbus_message_iter_init_append (message, &iter);
264       append_cache_item (accessible, &iter);
265
266       dbus_connection_send (spi_global_app_data->bus, message, NULL);
267
268       dbus_message_unref (message);
269     }
270 }
271
272
273 /*---------------------------------------------------------------------------*/
274
275 static DBusMessage *
276 impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
277 {
278   return spi_object_return_reference (message,
279                                       g_object_ref (G_OBJECT (spi_global_app_data->root)));
280 }
281
282 /*---------------------------------------------------------------------------*/
283
284 static DBusMessage *
285 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
286 {
287   DBusMessage *reply;
288   DBusMessageIter iter, iter_array;
289
290   reply = dbus_message_new_method_return (message);
291
292   dbus_message_iter_init_append (reply, &iter);
293   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
294                                     SPI_CACHE_ITEM_SIGNATURE, &iter_array);
295   spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
296   dbus_message_iter_close_container (&iter, &iter_array);
297   return reply;
298 }
299
300 /*---------------------------------------------------------------------------*/
301
302 static DRouteMethod methods[] = {
303   {impl_GetRoot, "GetRoot"},
304   {impl_GetItems, "GetItems"},
305   {NULL, NULL}
306 };
307
308 void
309 spi_initialize_cache (DRoutePath * path)
310 {
311   droute_path_add_interface (path, SPI_DBUS_INTERFACE_CACHE, methods, NULL);
312
313   g_signal_connect (spi_global_cache,
314                     "object-added",
315                     (GCallback) emit_cache_add,
316                     NULL);
317
318   g_signal_connect (spi_global_cache,
319                     "object-removed",
320                     (GCallback) emit_cache_remove,
321                     NULL);
322 };
323
324 /*END------------------------------------------------------------------------*/