19c7420634c25573401aa7f178866ab2d8161a3b
[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 spi_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 spi_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 spi_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   bonobo_object_release_unref (a->objref, NULL);
49
50   memset (a, 0xaa, sizeof (Accessible));
51   a->ref_count = -1;
52
53 #ifndef DEBUG_OBJECTS
54   g_free (a);
55 #endif
56 }
57
58
59 SPIBoolean
60 cspi_accessible_is_a (Accessible *obj,
61                       const char *interface_name)
62 {
63   SPIBoolean        retval;
64   Bonobo_Unknown unknown;
65
66   if (obj == NULL)
67     {
68       return FALSE;
69     }
70
71   unknown = Bonobo_Unknown_queryInterface (CSPI_OBJREF (obj),
72                                            interface_name, cspi_ev ());
73
74   if (BONOBO_EX (cspi_ev ()))
75     {
76       g_error ("Exception '%s' checking if is '%s'",
77                bonobo_exception_get_text (cspi_ev ()),
78                interface_name);
79     }
80
81   if (unknown != CORBA_OBJECT_NIL)
82     {
83       retval = TRUE;
84       bonobo_object_release_unref (unknown, NULL);
85     }
86   else
87     {
88       retval = FALSE;
89     }
90
91   return retval;
92 }
93
94 static GHashTable *
95 get_live_refs (void)
96 {
97   if (!live_refs) 
98     {
99       live_refs = g_hash_table_new_full (spi_object_hash,
100                                          spi_object_equal,
101                                          NULL,
102                                          spi_object_release);
103     }
104   return live_refs;
105 }
106
107 CORBA_Environment *
108 cspi_ev (void)
109 {
110   /* This method is an ugly hack */
111   return &ev;
112 }
113
114 Accessibility_Registry
115 cspi_registry (void)
116 {
117   return registry;
118 }
119
120 SPIBoolean
121 cspi_exception (void)
122 {
123   SPIBoolean retval;
124
125   if (BONOBO_EX (&ev))
126     {
127       CORBA_exception_free (&ev);
128       retval = TRUE;
129     }
130   else
131     {
132       retval = FALSE;
133     }
134
135   return retval;
136 }
137
138 Accessible *
139 cspi_object_add (CORBA_Object corba_object)
140 {
141   Accessible *ref;
142
143   if (corba_object == CORBA_OBJECT_NIL)
144     {
145       ref = NULL;
146     }
147   else
148     {
149       if ((ref = g_hash_table_lookup (get_live_refs (), corba_object)))
150         {
151           g_assert (ref->ref_count > 0);
152           ref->ref_count++;
153           bonobo_object_release_unref (corba_object, NULL);
154 #ifdef DEBUG_OBJECTS
155           g_print ("returning cached %p => %p\n", ref, ref->objref);
156 #endif
157         }
158       else
159         {
160           ref = g_new (Accessible, 1);
161
162 #ifdef DEBUG_OBJECTS
163           g_print ("allocating %p => %p\n", ref, corba_object);
164 #endif
165
166           ref->objref = corba_object;
167           ref->ref_count = 1;
168
169           g_hash_table_insert (get_live_refs (), ref->objref, ref);
170         }
171     }
172
173   return ref;
174 }
175
176 Accessible *
177 cspi_object_add_check (CORBA_Object corba_object)
178 {
179   Accessible *retval;
180
181   if (ev._major == CORBA_USER_EXCEPTION &&
182       !strcmp (ev._id, ex_Accessibility_ChildGone))
183     {
184       retval = NULL;
185     }
186   else if (ev._major != CORBA_NO_EXCEPTION)
187     {
188       cspi_check_ev (cspi_ev (), "pre method check");
189       retval = NULL;
190     }
191   else
192     {
193       retval = cspi_object_add (corba_object);
194
195       cspi_check_ev (cspi_ev (), "post method check");
196     }
197
198   return retval;
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 (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       bonobo_object_release_unref (registry, NULL);
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   int argc = 0;
255   char *obj_id;
256
257   if (SPI_inited)
258     {
259       return 1;
260     }
261
262   SPI_inited = TRUE;
263
264   CORBA_exception_init (&ev);
265
266   if (!bonobo_init (&argc, NULL))
267     {
268       g_error ("Could not initialize Bonobo");
269     }
270
271   obj_id = "OAFIID:Accessibility_Registry:proto0.1";
272
273   registry = bonobo_activation_activate_from_id (
274           obj_id, 0, NULL, cspi_ev ());
275
276   if (ev._major != CORBA_NO_EXCEPTION)
277     {
278       g_error ("AT-SPI error: during registry activation: %s\n",
279                bonobo_exception_get_text (cspi_ev ()));
280     }
281
282   if (registry == CORBA_OBJECT_NIL)
283     {
284       g_error ("Could not locate registry");
285     }
286
287   bonobo_activate ();
288
289   g_atexit (cspi_cleanup);
290   
291   return 0;
292 }
293
294 /**
295  * SPI_event_main:
296  *
297  * Starts/enters the main event loop for the SPI services.
298  *
299  * (NOTE: This method does not return control, it is exited via a call to
300  *  SPI_event_quit () from within an event handler).
301  *
302  **/
303 void
304 SPI_event_main (void)
305 {
306   bonobo_main ();
307 }
308
309 /**
310  * SPI_event_quit:
311  *
312  * Quits the last main event loop for the SPI services,
313  * see SPI_event_main
314  **/
315 void
316 SPI_event_quit (void)
317 {
318   bonobo_main_quit ();
319 }
320
321 /**
322  * SPI_eventIsReady:
323  *
324  * Checks to see if an SPI event is waiting in the event queue.
325  * Used by clients that don't wish to use SPI_event_main().
326  *
327  * Not Yet Implemented.
328  *
329  * Returns: #TRUE if an event is waiting, otherwise #FALSE.
330  *
331  **/
332 SPIBoolean
333 SPI_eventIsReady ()
334 {
335   return FALSE;
336 }
337
338 /**
339  * SPI_nextEvent:
340  * @waitForEvent: a #SPIBoolean indicating whether to block or not.
341  *
342  * Gets the next event in the SPI event queue; blocks if no event
343  * is pending and @waitForEvent is #TRUE.
344  * Used by clients that don't wish to use SPI_event_main().
345  *
346  * Not Yet Implemented.
347  *
348  * Returns: the next #AccessibleEvent in the SPI event queue.
349  **/
350 AccessibleEvent *
351 SPI_nextEvent (SPIBoolean waitForEvent)
352 {
353   return NULL;
354 }
355
356 /**
357  * SPI_exit:
358  *
359  * Disconnects from the Accessibility Registry and releases 
360  * any floating resources. Call only once at exit.
361  *
362  * Returns: 0 if there were no leaks, otherwise non zero.
363  **/
364 int
365 SPI_exit (void)
366 {
367   int leaked;
368
369   if (!SPI_inited)
370     {
371       return 0;
372     }
373
374   SPI_inited = FALSE;
375
376   if (live_refs)
377     {
378       leaked = g_hash_table_size (live_refs);
379     }
380   else
381     {
382       leaked = 0;
383     }
384
385 #ifdef DEBUG_OBJECTS
386   if (leaked)
387     {
388       fprintf (stderr, "Leaked %d SPI handles\n", leaked);
389     }
390 #endif
391
392   cspi_cleanup ();
393
394   fprintf (stderr, "bye-bye!\n");
395
396   return leaked;
397 }