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