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