Updated screen review test program.
[platform/core/uifw/at-spi2-atk.git] / cspi / spi_main.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  *
25  * Basic SPI initialization and event loop function prototypes
26  *
27  */
28 #include <string.h>
29 #include <stdlib.h>
30 #include <cspi/spi-private.h>
31
32 #undef DEBUG_OBJECTS
33
34 static CORBA_Environment ev = { 0 };
35 static Accessibility_Registry registry = CORBA_OBJECT_NIL;
36 static GHashTable *live_refs = NULL;
37
38 static guint
39 cspi_object_hash (gconstpointer key)
40 {
41   CORBA_Object object = (CORBA_Object) key;
42   guint        retval;
43   
44   retval = CORBA_Object_hash (object, 0, &ev);
45
46   return retval;
47 }
48
49 static gboolean
50 cspi_object_equal (gconstpointer a, gconstpointer b)
51 {
52   CORBA_Object objecta = (CORBA_Object) a;
53   CORBA_Object objectb = (CORBA_Object) b;
54   gboolean     retval;
55
56   retval = CORBA_Object_is_equivalent (objecta, objectb, &ev);
57
58   return retval;
59 }
60
61 static void
62 cspi_object_release (gpointer  value)
63 {
64   Accessible *a = (Accessible *) value;
65
66 #ifdef DEBUG_OBJECTS
67   g_print ("releasing %p => %p\n", a, a->objref);
68 #endif
69
70   cspi_release_unref (a->objref);
71
72   memset (a, 0xaa, sizeof (Accessible));
73   a->ref_count = -1;
74
75 #ifndef DEBUG_OBJECTS
76   free (a);
77 #endif
78 }
79
80 SPIBoolean
81 cspi_accessible_is_a (Accessible *obj,
82                       const char *interface_name)
83 {
84   SPIBoolean        retval;
85   Bonobo_Unknown unknown;
86
87   if (obj == NULL)
88     {
89       return FALSE;
90     }
91
92   unknown = Bonobo_Unknown_queryInterface (CSPI_OBJREF (obj),
93                                            interface_name, cspi_ev ());
94
95   if (ev._major != CORBA_NO_EXCEPTION)
96     {
97       g_error ("Exception '%s' checking if is '%s'",
98                cspi_exception_get_text (),
99                interface_name);
100     }
101
102   if (unknown != CORBA_OBJECT_NIL)
103     {
104       retval = TRUE;
105       cspi_release_unref (unknown);
106     }
107   else
108     {
109       retval = FALSE;
110     }
111
112   return retval;
113 }
114
115 static GHashTable *
116 cspi_get_live_refs (void)
117 {
118   if (!live_refs) 
119     {
120       live_refs = g_hash_table_new_full (cspi_object_hash,
121                                          cspi_object_equal,
122                                          NULL,
123                                          cspi_object_release);
124     }
125   return live_refs;
126 }
127
128 CORBA_Environment *
129 cspi_ev (void)
130 {
131   /* This method is an ugly hack */
132   return &ev;
133 }
134
135 Accessibility_Registry
136 cspi_registry (void)
137 {
138   return registry;
139 }
140
141 SPIBoolean
142 cspi_exception (void)
143 {
144   SPIBoolean retval;
145
146   if (ev._major != CORBA_NO_EXCEPTION)
147     {
148       CORBA_exception_free (&ev);
149       retval = TRUE;
150     }
151   else
152     {
153       retval = FALSE;
154     }
155
156   return retval;
157 }
158
159 Accessible *
160 cspi_object_add (CORBA_Object corba_object)
161 {
162   Accessible *ref;
163
164   if (corba_object == CORBA_OBJECT_NIL)
165     {
166       ref = NULL;
167     }
168   else if (!cspi_check_ev ("pre method check: add"))
169     {
170       ref = NULL;
171     }
172   else
173     {
174       if ((ref = g_hash_table_lookup (cspi_get_live_refs (), corba_object)))
175         {
176           g_assert (ref->ref_count > 0);
177           ref->ref_count++;
178           cspi_release_unref (corba_object);
179 #ifdef DEBUG_OBJECTS
180           g_print ("returning cached %p => %p\n", ref, ref->objref);
181 #endif
182         }
183       else
184         {
185           ref = malloc (sizeof (Accessible));
186
187 #ifdef DEBUG_OBJECTS
188           g_print ("allocating %p => %p\n", ref, corba_object);
189 #endif
190
191           ref->objref = corba_object;
192           ref->ref_count = 1;
193
194           g_hash_table_insert (cspi_get_live_refs (), ref->objref, ref);
195         }
196     }
197
198   return ref;
199 }
200
201 void
202 cspi_object_ref (Accessible *accessible)
203 {
204   g_return_if_fail (accessible != NULL);
205
206   accessible->ref_count++;
207 }
208
209 void
210 cspi_object_unref (Accessible *accessible)
211 {
212   if (accessible == NULL)
213     {
214       return;
215     }
216
217   if (--accessible->ref_count == 0)
218     {
219       g_hash_table_remove (cspi_get_live_refs (), accessible->objref);
220     }
221 }
222
223 static void
224 cspi_cleanup (void)
225 {
226   GHashTable *refs;
227
228   refs = live_refs;
229   live_refs = NULL;
230   if (refs)
231     {
232       g_hash_table_destroy (refs);
233     }
234
235   if (registry != CORBA_OBJECT_NIL)
236     {
237       cspi_release_unref (registry);
238       registry = CORBA_OBJECT_NIL;
239     }
240 }
241
242 static gboolean SPI_inited = FALSE;
243
244 /**
245  * SPI_init:
246  *
247  * Connects to the accessibility registry and initializes the SPI.
248  *
249  * Returns: 0 on success, otherwise an integer error code.
250  **/
251 int
252 SPI_init (void)
253 {
254   if (SPI_inited)
255     {
256       return 1;
257     }
258
259   SPI_inited = TRUE;
260
261   CORBA_exception_init (&ev);
262
263   registry = cspi_init ();
264
265   g_atexit (cspi_cleanup);
266   
267   return 0;
268 }
269
270 /**
271  * SPI_event_main:
272  *
273  * Starts/enters the main event loop for the SPI services.
274  *
275  * (NOTE: This method does not return control, it is exited via a call to
276  *  SPI_event_quit () from within an event handler).
277  *
278  **/
279 void
280 SPI_event_main (void)
281 {
282   cspi_main ();
283 }
284
285 /**
286  * SPI_event_quit:
287  *
288  * Quits the last main event loop for the SPI services,
289  * see SPI_event_main
290  **/
291 void
292 SPI_event_quit (void)
293 {
294   cspi_main_quit ();
295 }
296
297 /**
298  * SPI_eventIsReady:
299  *
300  * Checks to see if an SPI event is waiting in the event queue.
301  * Used by clients that don't wish to use SPI_event_main().
302  *
303  * Not Yet Implemented.
304  *
305  * Returns: #TRUE if an event is waiting, otherwise #FALSE.
306  *
307  **/
308 SPIBoolean
309 SPI_eventIsReady ()
310 {
311   return FALSE;
312 }
313
314 /**
315  * SPI_nextEvent:
316  * @waitForEvent: a #SPIBoolean indicating whether to block or not.
317  *
318  * Gets the next event in the SPI event queue; blocks if no event
319  * is pending and @waitForEvent is #TRUE.
320  * Used by clients that don't wish to use SPI_event_main().
321  *
322  * Not Yet Implemented.
323  *
324  * Returns: the next #AccessibleEvent in the SPI event queue.
325  **/
326 AccessibleEvent *
327 SPI_nextEvent (SPIBoolean waitForEvent)
328 {
329   return NULL;
330 }
331
332 /**
333  * SPI_exit:
334  *
335  * Disconnects from the Accessibility Registry and releases 
336  * any floating resources. Call only once at exit.
337  *
338  * Returns: 0 if there were no leaks, otherwise non zero.
339  **/
340 int
341 SPI_exit (void)
342 {
343   int leaked;
344
345   if (!SPI_inited)
346     {
347       return 0;
348     }
349
350   SPI_inited = FALSE;
351
352   if (live_refs)
353     {
354       leaked = g_hash_table_size (live_refs);
355     }
356   else
357     {
358       leaked = 0;
359     }
360
361 #ifdef DEBUG_OBJECTS
362   if (leaked)
363     {
364       fprintf (stderr, "Leaked %d SPI handles\n", leaked);
365     }
366 #endif
367
368   cspi_cleanup ();
369
370   fprintf (stderr, "bye-bye!\n");
371
372   return leaked;
373 }
374
375 /**
376  * SPI_freeString:
377  * @s: a character string returned from another at-spi call.
378  *
379  * Free a character string returned from an at-spi call.  Clients of
380  * at-spi should use this function instead of free () or g_free().
381  * This API should not be used to free strings
382  * from other libraries or allocated by the client.
383  **/
384 void
385 SPI_freeString (char *s)
386 {
387   CORBA_free (s);
388 }