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