Emit applicationAdd and applicationRemove using the desktop path
[platform/core/uifw/at-spi2-atk.git] / registryd / desktop.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc., Ximian Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* desktop.c: implements SpiDesktop.idl */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <atk/atkcomponent.h>
30 #include <gdk/gdkscreen.h>
31 #include <gdk/gdkx.h>
32
33 #include <spi-common/spi-dbus.h>
34
35 #include "desktop.h"
36 #include "registry.h"
37
38 G_DEFINE_TYPE(SpiDesktop, spi_desktop, G_TYPE_OBJECT)
39
40 /* SpiDesktop signals */
41 enum {
42   APPLICATION_ADDED,
43   APPLICATION_REMOVED,  
44 LAST_SIGNAL
45 };
46 static guint spi_desktop_signals[LAST_SIGNAL];
47
48
49 /* Our parent Gtk object type */
50 #define PARENT_TYPE SPI_ACCESSIBLE_TYPE
51
52 static gboolean exiting = FALSE;
53
54 /* A pointer to our parent object class */
55 static GObjectClass *parent_class;
56
57 #define SPI_TYPE_ATK_DESKTOP            (spi_atk_desktop_get_type ())
58 #define SPI_ATK_DESKTOP(o)              (G_TYPE_CHECK_INSTANCE_CAST ((o), SPI_TYPE_ATK_DESKTOP, SpiAtkDesktop))
59 #define SPI_IS_ATK_DESKTOP(o)           (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPI_TYPE_ATK_DESKTOP))
60
61 typedef struct {
62         AtkObject parent;
63
64         GdkScreen *screen;
65 } SpiAtkDesktop;
66
67 typedef struct {
68         AtkObjectClass parent;
69 } SpiAtkDesktopClass;
70
71 static void spi_atk_desktop_init (SpiAtkDesktop *desktop);
72 static void atk_component_interface_init (AtkComponentIface *iface);
73 static void spi_atk_desktop_get_extents  (AtkComponent    *component,
74                                           gint            *x,
75                                           gint            *y,
76                                           gint            *width,
77                                           gint            *height,
78                                           AtkCoordType    coord_type);
79
80 static GType 
81 spi_atk_desktop_get_type (void)
82 {
83   static GType type = 0;
84
85   if (!type)
86     {
87       static const GTypeInfo typeInfo =
88       {
89         sizeof (SpiAtkDesktopClass),
90         (GBaseInitFunc) NULL,
91         (GBaseFinalizeFunc) NULL,
92         (GClassInitFunc) NULL,
93         (GClassFinalizeFunc) NULL,
94         NULL,
95         sizeof (SpiAtkDesktop),
96         0,
97         (GInstanceInitFunc) spi_atk_desktop_init,
98       } ;
99       static const GInterfaceInfo atk_component_info =
100         {
101         (GInterfaceInitFunc) atk_component_interface_init,
102         (GInterfaceFinalizeFunc) NULL,
103         NULL
104       };
105
106       type = g_type_register_static (ATK_TYPE_OBJECT,
107                                      "SpiAtkDesktop", &typeInfo, 0);
108       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
109                                    &atk_component_info);
110     }
111   return type;
112 }
113
114 static void 
115 spi_atk_desktop_init (SpiAtkDesktop *desktop)
116 {
117   GdkDisplay *display;
118
119   atk_object_set_name (ATK_OBJECT (desktop), "main");
120   display = gdk_x11_lookup_xdisplay (GDK_DISPLAY ());
121   desktop->screen = gdk_display_get_default_screen (display);
122 }
123
124 static void
125 atk_component_interface_init (AtkComponentIface *iface)
126 {
127   g_return_if_fail (iface != NULL);
128
129   iface->get_extents = spi_atk_desktop_get_extents;
130 }
131
132 static void 
133 spi_atk_desktop_get_extents (AtkComponent *component,
134                              gint         *x,
135                              gint         *y,
136                              gint         *width,
137                              gint         *height,
138                              AtkCoordType coord_type)
139 {
140   SpiAtkDesktop *desktop;
141
142   g_return_if_fail (SPI_IS_ATK_DESKTOP (component));
143   desktop = SPI_ATK_DESKTOP (component);
144   *x = 0;
145   *y = 0;
146   *width = gdk_screen_get_width (desktop->screen);
147   *height = gdk_screen_get_height (desktop->screen);
148 }
149
150 static void
151 spi_desktop_init (SpiDesktop *desktop)
152 {
153   desktop->applications = NULL;
154 }
155
156 static void
157 spi_desktop_dispose (GObject *object)
158 {
159   SpiDesktop *desktop = (SpiDesktop *) object;
160
161   while (desktop->applications)
162     {
163       SpiDesktopApplication *app = desktop->applications->data;
164       g_assert (app != NULL);
165       spi_desktop_remove_application (desktop, app->bus_name);
166     }
167
168   G_OBJECT_CLASS (parent_class)->dispose (object); 
169 }
170
171 static dbus_bool_t
172 impl_desktop_get_child_count (const char *path, DBusMessageIter * iter,
173                      void *user_data)
174 {
175   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
176
177   if (desktop->applications)
178     {
179       return droute_return_v_int32(iter, g_list_length (desktop->applications));
180     }
181   else
182     {
183       return droute_return_v_int32(iter, 0);
184     }
185 }
186
187 static DBusMessage *
188 impl_desktop_get_child_at_index (DBusConnection *bus, DBusMessage *message, void *user_data)
189 {
190   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
191   DBusError error;
192   dbus_int32_t index;
193   SpiDesktopApplication *app;
194   const char *bus_name;
195   DBusMessage *reply;
196
197   dbus_error_init (&error);
198   if (!dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
199   {
200     return spi_dbus_general_error (message);
201   }
202   app = g_list_nth_data (desktop->applications, index);
203   bus_name = (app? app->bus_name: "");
204
205   reply = dbus_message_new_method_return (message);
206   if (reply)
207     {
208       dbus_message_append_args (reply, DBUS_TYPE_STRING, &bus_name, DBUS_TYPE_INVALID);
209     }
210
211   return reply;
212 }
213
214 static DBusMessage *
215 impl_desktop_get_children (DBusConnection *bus, DBusMessage *message, void *user_data)
216 {
217   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
218   DBusError error;
219   gint count;
220   gint i;
221   SpiDesktopApplication *app;
222   const char *bus_name;
223   DBusMessage *reply;
224   DBusMessageIter iter, iter_array;
225
226   reply = dbus_message_new_method_return (message);
227   if (!reply) return NULL;
228   dbus_message_iter_init_append (reply, &iter);
229   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &iter_array))
230   {
231     goto oom;
232   }
233   count = g_list_length (desktop->applications);
234   for (i = 0; i < count; i++)
235   {
236     app = g_list_nth_data (desktop->applications, i);
237     bus_name = (app? app->bus_name: "");
238     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &bus_name);
239   }
240   if (!dbus_message_iter_close_container (&iter, &iter_array))
241   {
242     goto oom;
243   }
244   return reply;
245 oom:
246   // TODO: Handle out of memory
247   return reply;
248 }
249
250 static void
251 spi_desktop_exiting (void)
252 {
253   exiting = TRUE;
254 }
255
256 static void
257 spi_desktop_class_init (SpiDesktopClass *klass)
258 {
259   GObjectClass * object_class = (GObjectClass *) klass;
260
261   object_class->dispose = spi_desktop_dispose;
262   
263   parent_class = g_type_class_ref (G_TYPE_OBJECT);
264
265   spi_desktop_signals[APPLICATION_ADDED] =
266     g_signal_new ("application_added",
267                   G_TYPE_FROM_CLASS (klass),
268                   G_SIGNAL_RUN_LAST,
269                   G_STRUCT_OFFSET (SpiDesktopClass, application_added),
270                   NULL, NULL,
271                   g_cclosure_marshal_VOID__UINT,
272                   G_TYPE_NONE,
273                   1, G_TYPE_UINT);
274   spi_desktop_signals[APPLICATION_REMOVED] =
275     g_signal_new ("application_removed",
276                   G_TYPE_FROM_CLASS (klass),
277                   G_SIGNAL_RUN_LAST,
278                   G_STRUCT_OFFSET (SpiDesktopClass, application_removed),
279                   NULL, NULL,
280                   g_cclosure_marshal_VOID__UINT,
281                   G_TYPE_NONE,
282                   1, G_TYPE_UINT);
283   g_atexit (spi_desktop_exiting);
284 }
285
286 SpiDesktop *
287 spi_desktop_new (void)
288 {
289   return g_object_new (SPI_DESKTOP_TYPE, NULL);
290 }
291
292 static void
293 abnormal_application_termination (gpointer object, SpiDesktopApplication *app)
294 {
295   g_return_if_fail (SPI_IS_DESKTOP (app->desktop));
296
297   if (!exiting)
298     spi_desktop_remove_application (app->desktop, app->bus_name);
299 }
300
301 void
302 spi_desktop_add_application (SpiDesktop *desktop,
303                              const char *application)
304 {
305   SpiDesktopApplication       *app;
306
307   g_return_if_fail (SPI_IS_DESKTOP (desktop));
308
309   app = g_new (SpiDesktopApplication, 1);
310   app->desktop = desktop;
311   app->bus_name = application;
312
313       desktop->applications = g_list_append (desktop->applications, app);
314
315   // TODO: Listen for termination, and call abnormal_application_termination
316
317   g_signal_emit (G_OBJECT (desktop),
318                  spi_desktop_signals[APPLICATION_ADDED], 0,
319                  g_list_index (desktop->applications, app));
320 }
321
322 void
323 spi_desktop_remove_application (SpiDesktop *desktop,
324                                 const char *bus_name)
325 {
326   guint idx;
327   GList *l;
328
329   g_return_if_fail (  bus_name != NULL);
330   g_return_if_fail (SPI_IS_DESKTOP (desktop));
331
332   idx = 0;
333   for (l = desktop->applications; l; l = l->next)
334     {
335       SpiDesktopApplication *app = (SpiDesktopApplication *) l->data;
336
337       if (!strcmp(app->bus_name, bus_name))
338         {
339           break;
340         }
341       idx++;
342     }
343
344   if (!l) return;
345
346   g_signal_emit (G_OBJECT (desktop), spi_desktop_signals[APPLICATION_REMOVED], 0, idx);
347
348   SpiDesktopApplication *app = (SpiDesktopApplication *) l->data;
349
350   desktop->applications = g_list_delete_link (desktop->applications, l);
351
352   g_free (app);
353 }
354
355 static DRouteMethod methods[] =
356 {
357   { impl_desktop_get_child_at_index, "getChildAtIndex" },
358   { impl_desktop_get_children, "getChildren" },
359   { NULL, NULL }
360 };
361
362 static DRouteProperty properties[] =
363 {
364   { impl_desktop_get_child_count, NULL, "getChildCount" },
365   { NULL, NULL, NULL }
366 };
367
368 void
369 spi_registry_initialize_desktop_interface (DRouteData * data)
370 {
371   droute_add_interface (data, SPI_DBUS_INTERFACE_DESKTOP, methods,
372                         properties, NULL, NULL);
373 };