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