Fix spelling of some function names
[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 typedef struct {
53         SpiDesktop *desktop;
54         const char *path;
55 } Application;
56
57 static gboolean exiting = FALSE;
58
59 /* A pointer to our parent object class */
60 static GObjectClass *parent_class;
61
62 #define SPI_TYPE_ATK_DESKTOP            (spi_atk_desktop_get_type ())
63 #define SPI_ATK_DESKTOP(o)              (G_TYPE_CHECK_INSTANCE_CAST ((o), SPI_TYPE_ATK_DESKTOP, SpiAtkDesktop))
64 #define SPI_IS_ATK_DESKTOP(o)           (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPI_TYPE_ATK_DESKTOP))
65
66 typedef struct {
67         AtkObject parent;
68
69         GdkScreen *screen;
70 } SpiAtkDesktop;
71
72 typedef struct {
73         AtkObjectClass parent;
74 } SpiAtkDesktopClass;
75
76 static void spi_atk_desktop_init (SpiAtkDesktop *desktop);
77 static void atk_component_interface_init (AtkComponentIface *iface);
78 static void spi_atk_desktop_get_extents  (AtkComponent    *component,
79                                           gint            *x,
80                                           gint            *y,
81                                           gint            *width,
82                                           gint            *height,
83                                           AtkCoordType    coord_type);
84
85 static GType 
86 spi_atk_desktop_get_type (void)
87 {
88   static GType type = 0;
89
90   if (!type)
91     {
92       static const GTypeInfo typeInfo =
93       {
94         sizeof (SpiAtkDesktopClass),
95         (GBaseInitFunc) NULL,
96         (GBaseFinalizeFunc) NULL,
97         (GClassInitFunc) NULL,
98         (GClassFinalizeFunc) NULL,
99         NULL,
100         sizeof (SpiAtkDesktop),
101         0,
102         (GInstanceInitFunc) spi_atk_desktop_init,
103       } ;
104       static const GInterfaceInfo atk_component_info =
105         {
106         (GInterfaceInitFunc) atk_component_interface_init,
107         (GInterfaceFinalizeFunc) NULL,
108         NULL
109       };
110
111       type = g_type_register_static (ATK_TYPE_OBJECT,
112                                      "SpiAtkDesktop", &typeInfo, 0);
113       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
114                                    &atk_component_info);
115     }
116   return type;
117 }
118
119 static void 
120 spi_atk_desktop_init (SpiAtkDesktop *desktop)
121 {
122   GdkDisplay *display;
123
124   atk_object_set_name (ATK_OBJECT (desktop), "main");
125   display = gdk_x11_lookup_xdisplay (GDK_DISPLAY ());
126   desktop->screen = gdk_display_get_default_screen (display);
127 }
128
129 static void
130 atk_component_interface_init (AtkComponentIface *iface)
131 {
132   g_return_if_fail (iface != NULL);
133
134   iface->get_extents = spi_atk_desktop_get_extents;
135 }
136
137 static void 
138 spi_atk_desktop_get_extents (AtkComponent *component,
139                              gint         *x,
140                              gint         *y,
141                              gint         *width,
142                              gint         *height,
143                              AtkCoordType coord_type)
144 {
145   SpiAtkDesktop *desktop;
146
147   g_return_if_fail (SPI_IS_ATK_DESKTOP (component));
148   desktop = SPI_ATK_DESKTOP (component);
149   *x = 0;
150   *y = 0;
151   *width = gdk_screen_get_width (desktop->screen);
152   *height = gdk_screen_get_height (desktop->screen);
153 }
154
155 static void
156 spi_desktop_init (SpiDesktop *desktop)
157 {
158   desktop->applications = NULL;
159 }
160
161 static void
162 spi_desktop_dispose (GObject *object)
163 {
164   SpiDesktop *desktop = (SpiDesktop *) object;
165
166   while (desktop->applications)
167     {
168       Application *app = desktop->applications->data;
169       g_assert (app != NULL);
170       spi_desktop_remove_application (desktop, app->path);
171     }
172
173   G_OBJECT_CLASS (parent_class)->dispose (object); 
174 }
175
176 static dbus_bool_t
177 impl_desktop_get_child_count (const char *path, DBusMessageIter * iter,
178                      void *user_data)
179 {
180   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
181
182   if (desktop->applications)
183     {
184       return droute_return_v_int32(iter, g_list_length (desktop->applications));
185     }
186   else
187     {
188       return droute_return_v_int32(iter, 0);
189     }
190 }
191
192 static DBusMessage *
193 impl_desktop_get_child_at_index (DBusConnection *bus, DBusMessage *message, void *user_data)
194 {
195   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
196   DBusError error;
197   dbus_int32_t index;
198   Application *app;
199   const char *path;
200   DBusMessage *reply;
201
202   dbus_error_init (&error);
203   if (!dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
204   {
205     return spi_dbus_general_error (message);
206   }
207   app = g_list_nth_data (desktop->applications, index);
208   path = (app? app->path: SPI_DBUS_PATH_NULL);
209
210   reply = dbus_message_new_method_return (message);
211   if (reply)
212     {
213       dbus_message_append_args (reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
214     }
215
216   return reply;
217 }
218
219 static DBusMessage *
220 impl_desktop_get_children (DBusConnection *bus, DBusMessage *message, void *user_data)
221 {
222   SpiDesktop *desktop = SPI_REGISTRY(user_data)->desktop;
223   DBusError error;
224   gint count;
225   gint i;
226   Application *app;
227   const char *path;
228   DBusMessage *reply;
229   DBusMessageIter iter, iter_array;
230
231   reply = dbus_message_new_method_return (message);
232   if (!reply) return NULL;
233   dbus_message_iter_init_append (reply, &iter);
234   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &iter_array))
235   {
236     goto oom;
237   }
238   count = g_list_length (desktop->applications);
239   for (i = 0; i < count; i++)
240   {
241     app = g_list_nth_data (desktop->applications, i);
242     path = (app? app->path: SPI_DBUS_PATH_NULL);
243     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
244   }
245   if (!dbus_message_iter_close_container (&iter, &iter_array))
246   {
247     goto oom;
248   }
249   return reply;
250 oom:
251   // TODO: Handle out of memory
252   return reply;
253 }
254
255 static void
256 spi_desktop_exiting (void)
257 {
258   exiting = TRUE;
259 }
260
261 static void
262 spi_desktop_class_init (SpiDesktopClass *klass)
263 {
264   GObjectClass * object_class = (GObjectClass *) klass;
265
266   object_class->dispose = spi_desktop_dispose;
267   
268   parent_class = g_type_class_ref (G_TYPE_OBJECT);
269
270   spi_desktop_signals[APPLICATION_ADDED] =
271     g_signal_new ("application_added",
272                   G_TYPE_FROM_CLASS (klass),
273                   G_SIGNAL_RUN_LAST,
274                   G_STRUCT_OFFSET (SpiDesktopClass, application_added),
275                   NULL, NULL,
276                   g_cclosure_marshal_VOID__UINT,
277                   G_TYPE_NONE,
278                   1, G_TYPE_UINT);
279   spi_desktop_signals[APPLICATION_REMOVED] =
280     g_signal_new ("application_removed",
281                   G_TYPE_FROM_CLASS (klass),
282                   G_SIGNAL_RUN_LAST,
283                   G_STRUCT_OFFSET (SpiDesktopClass, application_removed),
284                   NULL, NULL,
285                   g_cclosure_marshal_VOID__UINT,
286                   G_TYPE_NONE,
287                   1, G_TYPE_UINT);
288   g_atexit (spi_desktop_exiting);
289 }
290
291 SpiDesktop *
292 spi_desktop_new (void)
293 {
294   return g_object_new (SPI_DESKTOP_TYPE, NULL);
295 }
296
297 static void
298 abnormal_application_termination (gpointer object, Application *app)
299 {
300   g_return_if_fail (SPI_IS_DESKTOP (app->desktop));
301
302   if (!exiting)
303     spi_desktop_remove_application (app->desktop, app->path);
304 }
305
306 void
307 spi_desktop_add_application (SpiDesktop *desktop,
308                              const char *application)
309 {
310   Application       *app;
311
312   g_return_if_fail (SPI_IS_DESKTOP (desktop));
313
314   spi_desktop_remove_application (desktop, application);
315
316   app = g_new (Application, 1);
317   app->desktop = desktop;
318   app->path = application;
319
320       desktop->applications = g_list_append (desktop->applications, app);
321
322   // TODO: Listen for termination, and call abnormal_application_termination
323
324   g_signal_emit (G_OBJECT (desktop),
325                  spi_desktop_signals[APPLICATION_ADDED], 0,
326                  g_list_index (desktop->applications, app));
327 }
328
329 void
330 spi_desktop_remove_application (SpiDesktop *desktop,
331                                 const char *path)
332 {
333   guint idx;
334   GList *l;
335
336   g_return_if_fail (path != NULL);
337   g_return_if_fail (SPI_IS_DESKTOP (desktop));
338
339   idx = 0;
340   for (l = desktop->applications; l; l = l->next)
341     {
342       Application *app = (Application *) l->data;
343
344       if (!strcmp(app->path, path))
345         {
346           break;
347         }
348       idx++;
349     }
350
351   if (l)
352     {
353       Application *app = (Application *) l->data;
354
355       desktop->applications = g_list_delete_link (desktop->applications, l);
356
357       // TODO: unlisten for broken app, if appropriate
358       g_free (app);
359       
360       g_signal_emit (G_OBJECT (desktop), spi_desktop_signals[APPLICATION_REMOVED], 0, idx);
361     }
362 }
363
364 static DRouteMethod methods[] =
365 {
366   { impl_desktop_get_child_at_index, "getChildAtIndex" },
367   { impl_desktop_get_children, "getChildren" },
368   { NULL, NULL }
369 };
370
371 static DRouteProperty properties[] =
372 {
373   { impl_desktop_get_child_count, NULL, "getChildCount" },
374   { NULL, NULL, NULL }
375 };
376
377 void
378 spi_registry_initialize_desktop_interface (DRouteData * data)
379 {
380   droute_add_interface (data, "org.freedesktop.atspi.Accessible", methods,
381                         properties, NULL, NULL);
382 };