3085452b2043074a58a1c81fe7dab40880f44817
[platform/core/uifw/at-spi2-atk.git] / atk-bridge / bridge.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, 2003 Sun Microsystems Inc.,
6  * Copyright 2001, 2002, 2003 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 #include "config.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xatom.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <libbonobo.h>
34 #include <orbit/orbit.h>
35 #include <atk/atk.h>
36 #include <atk/atkobject.h>
37 #include <atk/atknoopobject.h>
38 #include <libspi/Accessibility.h>
39 #include <libspi/spi-private.h>
40 #include "remoteobject.h"
41 #include "accessible.h"
42 #include "application.h"
43 #include <bonobo-activation/bonobo-activation-register.h>
44
45 #undef SPI_BRIDGE_DEBUG
46
47 #define DBG(a,b) if(_dbg>=(a))b
48
49 int _dbg = 0;
50 static CORBA_Environment ev;
51 static Accessibility_Registry registry = CORBA_OBJECT_NIL;
52 static Accessibility_DeviceEventController device_event_controller = CORBA_OBJECT_NIL;
53 static SpiApplication *this_app = NULL;
54 static gboolean registry_died = FALSE;
55 static gboolean atk_listeners_registered = FALSE;
56 static gint toplevels = 0;
57 static gboolean exiting = FALSE;
58 static AtkMisc *misc = NULL;
59
60 static guint atk_signal_text_changed;
61 static guint atk_signal_children_changed;
62 static guint atk_signal_active_descendant_changed;
63 static guint atk_signal_text_selection_changed;
64
65 /* NOT YET USED
66    static guint atk_signal_row_reordered;
67    static guint atk_signal_row_inserted;
68    static guint atk_signal_row_deleted;
69    static guint atk_signal_column_reordered;
70    static guint atk_signal_column_inserted;
71    static guint atk_signal_column_deleted;
72 */
73
74 static guint atk_signal_link_selected;
75 static guint atk_signal_bounds_changed;
76
77 static Accessibility_Registry spi_atk_bridge_get_registry (void);
78 static gboolean spi_atk_bridge_do_registration         (void);
79 static void     spi_atk_bridge_toplevel_added          (AtkObject             *object,
80                                                         guint                 index,
81                                                         AtkObject             *child);
82 static void     spi_atk_bridge_toplevel_removed        (AtkObject             *object,
83                                                         guint                 index,
84                                                         AtkObject             *child);
85
86 static void     spi_atk_bridge_exit_func               (void);
87 static void     spi_atk_register_event_listeners       (void);
88 static void     spi_atk_bridge_focus_tracker           (AtkObject             *object);
89 static gchar   *spi_atk_bridge_get_registry_ior        (void);
90 static void     spi_atk_bridge_register_application    (Accessibility_Registry registry);
91 static gboolean spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint,
92                                                         guint                  n_param_values,
93                                                         const GValue          *param_values,
94                                                         gpointer               data);
95
96 static void     spi_atk_bridge_init_nil                (CORBA_any *any, 
97                                                         AtkObject *obj);
98 static void     spi_atk_bridge_init_object             (CORBA_any *any, 
99                                                         AtkObject *obj,
100                                                         CORBA_Object *c_obj);
101 static void     spi_atk_bridge_init_string             (CORBA_any *any, 
102                                                         AtkObject *obj, 
103                                                         gchar **string);
104 static void     spi_atk_bridge_init_rect               (CORBA_any *any, 
105                                                         AtkObject *obj, 
106                                                         AtkRectangle *rect);
107
108 static gboolean
109 spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
110                                 guint n_param_values,
111                                 const GValue *param_values,
112                                 gpointer data);
113 static gboolean
114 spi_atk_bridge_document_event_listener (GSignalInvocationHint *signal_hint,
115                                 guint n_param_values,
116                                 const GValue *param_values,
117                                 gpointer data);
118 static gboolean
119 spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint,
120                                      guint n_param_values,
121                                      const GValue *param_values,
122                                      gpointer data);
123 static gboolean spi_atk_bridge_signal_listener         (GSignalInvocationHint *signal_hint,
124                                                         guint                  n_param_values,
125                                                         const GValue          *param_values,
126                                                         gpointer               data);
127 static gint     spi_atk_bridge_key_listener            (AtkKeyEventStruct     *event,
128                                                         gpointer               data);
129 static void     spi_atk_tidy_windows                   (void);
130 static void     deregister_application                 (BonoboObject          *app);
131 static void     reinit_register_vars                   (void);
132
133 /* For automatic libgnome init */
134 extern void gnome_accessibility_module_init     (void);
135 extern void gnome_accessibility_module_shutdown (void);
136
137 static int     atk_bridge_initialized = FALSE;
138 static pid_t   atk_bridge_pid = 0;
139 static guint   atk_bridge_focus_tracker_id = 0;
140 static guint   atk_bridge_key_event_listener_id = 0;
141 static GArray *listener_ids = NULL;
142
143 /*
144  *   These exported symbols are hooked by gnome-program
145  * to provide automatic module initialization and shutdown.
146  */
147 extern void gnome_accessibility_module_init     (void);
148 extern void gnome_accessibility_module_shutdown (void);
149
150 static void
151 spi_atk_bridge_init_event_type_consts ()
152 {
153   static gboolean done = FALSE;
154
155   if (done)
156     return;
157
158   atk_signal_children_changed = g_signal_lookup ("children_changed", 
159                                               ATK_TYPE_OBJECT);
160   atk_signal_text_changed = g_signal_lookup ("text_changed", 
161                                              ATK_TYPE_TEXT);
162   atk_signal_bounds_changed = g_signal_lookup ("bounds_changed", 
163                                               ATK_TYPE_COMPONENT);
164   atk_signal_active_descendant_changed = 
165          g_signal_lookup ("active_descendant_changed", 
166                           ATK_TYPE_OBJECT); 
167   atk_signal_link_selected = g_signal_lookup ("link_selected", 
168                                               ATK_TYPE_HYPERTEXT);
169   atk_signal_text_selection_changed = g_signal_lookup ("text_selection_changed", 
170                                               ATK_TYPE_TEXT);
171   done = TRUE;
172 }
173
174 static int
175 atk_bridge_init (gint *argc, gchar **argv[])
176 {
177   const char *debug_env_string = g_getenv ("AT_SPI_DEBUG");
178   gchar *fname;
179   gboolean success = FALSE;
180
181   if (atk_bridge_initialized)
182     {
183       return 0;
184     }
185   atk_bridge_initialized = TRUE;
186   atk_bridge_pid = getpid ();
187
188   misc = atk_misc_get_instance();
189
190   if (g_getenv ("ATK_BRIDGE_REDIRECT_LOG"))
191   {
192       fname = g_strconcat ("/tmp/", g_get_prgname (), ".at-spi-log", NULL);
193       /* make sure we're not being redirected - security issue */
194       if (!g_file_test (fname, G_FILE_TEST_IS_SYMLINK))
195           freopen (fname, "w", stderr);
196       g_free (fname);
197   }
198
199   if (debug_env_string) 
200       _dbg = (int) g_ascii_strtod (debug_env_string, NULL);
201
202   if (!bonobo_init (argc, argv ? *argv : NULL))
203     {
204       g_error ("Could not initialize Bonobo");
205     }
206
207   /* Create the accessible application server object */
208   this_app = spi_application_new (atk_get_root ());
209   /*
210    * We only want to enable the bridge for top level
211    * applications, we detect bonobo components by seeing
212    * if they were activated with the intention of extracting
213    * an impl. by IID - very solid.
214    */
215   if (bonobo_activation_iid_get ())
216     {
217       DBG (1, g_message ("Found Bonobo component\n"));
218       g_signal_connect (atk_get_root (), 
219                         "children-changed::add",
220                         (GCallback) spi_atk_bridge_toplevel_added, 
221                         NULL);
222       g_signal_connect (atk_get_root (), 
223                         "children-changed::remove",
224                         (GCallback) spi_atk_bridge_toplevel_removed, 
225                         NULL);
226       /* in this case we redefine 'success' to mean 'registry is present' */
227       success = (spi_atk_bridge_get_registry () != CORBA_OBJECT_NIL);
228     }
229   else
230     {
231       success = spi_atk_bridge_do_registration ();
232     }
233   /*
234    * we must emit events even if we are not registered as a
235    * full-fledged app; See bugzilla #400709.
236    */
237   if (success) 
238     {
239       spi_atk_register_event_listeners ();
240       spi_atk_bridge_init_event_type_consts ();
241     }
242   else
243     {
244       atk_bridge_initialized = FALSE;
245     }
246   return 0;
247 }
248
249
250 static gboolean
251 spi_atk_bridge_do_registration (void)
252 {
253   CORBA_Environment ev;
254
255   CORBA_exception_init(&ev);
256
257   if (spi_atk_bridge_get_registry () == CORBA_OBJECT_NIL)
258     {
259       g_warning ("Could not locate registry");
260       return FALSE;
261     }
262
263   bonobo_activate ();
264
265   /* Create the accessible application server object */
266   if (this_app == NULL)
267     this_app = spi_application_new (atk_get_root ());
268
269   DBG (1, g_message ("About to register application\n"));
270
271   spi_atk_bridge_register_application (spi_atk_bridge_get_registry ());
272   
273   g_atexit (spi_atk_bridge_exit_func);
274
275   DBG (1, g_message ("Application registered & listening\n"));
276   return TRUE;
277 }
278
279 static void
280 spi_atk_bridge_toplevel_added (AtkObject *object,
281                                guint     index,
282                                AtkObject *child)
283 {
284   if (toplevels == 0)
285     {
286       spi_atk_bridge_do_registration ();
287     }
288   toplevels++;
289 }
290
291 static void
292 spi_atk_bridge_toplevel_removed (AtkObject *object,
293                                  guint     index,
294                                  AtkObject *child)
295 {
296   BonoboObject *app = (BonoboObject *) this_app;
297
298   toplevels--;
299   if (toplevels == 0)
300     {
301       deregister_application (app);
302       reinit_register_vars ();
303     }
304   if (toplevels < 0)
305     {
306       g_warning ("More toplevels removed than added\n");
307       toplevels = 0;
308     }
309 }
310
311 static void
312 spi_atk_bridge_register_application (Accessibility_Registry registry)
313 {
314   atk_misc_threads_leave (misc);
315   Accessibility_Registry_registerApplication (spi_atk_bridge_get_registry (),
316                                               BONOBO_OBJREF (this_app),
317                                               &ev);
318   atk_misc_threads_enter (misc);
319   if (ev._major != CORBA_NO_EXCEPTION)
320     CORBA_exception_free (&ev);
321 }
322
323 /* 
324  * Returns a 'canonicalized' value for DISPLAY,
325  * with the screen number stripped off if present.
326  */
327 static const gchar*
328 spi_display_name (void)
329 {
330     static const char *canonical_display_name = NULL;
331     if (!canonical_display_name)
332     {
333         const gchar *display_env = g_getenv ("AT_SPI_DISPLAY");
334         if (!display_env)
335         {
336             display_env = g_getenv ("DISPLAY");
337             if (!display_env || !display_env[0]) 
338                 canonical_display_name = ":0";
339             else
340             {
341                 gchar *display_p, *screen_p;
342                 canonical_display_name = g_strdup (display_env);
343                 display_p = strrchr (canonical_display_name, ':');
344                 screen_p = strrchr (canonical_display_name, '.');
345                 if (screen_p && display_p && (screen_p > display_p))
346                 {
347                     *screen_p = '\0';
348                 }
349             }
350         }
351         else
352         {
353             canonical_display_name = display_env;
354         }
355     }
356     return canonical_display_name;
357 }
358
359 static     Display *bridge_display = NULL;
360
361 static gchar *
362 spi_atk_bridge_get_registry_ior (void)
363 {
364      
365      Atom AT_SPI_IOR;
366      Atom actual_type;
367      int actual_format;
368      unsigned char *data = NULL;  
369      unsigned long nitems;
370      unsigned long leftover;
371      if (!bridge_display) 
372        bridge_display = XOpenDisplay (spi_display_name ());
373
374      AT_SPI_IOR = XInternAtom (bridge_display, "AT_SPI_IOR", False); 
375      XGetWindowProperty(bridge_display, 
376                         XDefaultRootWindow (bridge_display),
377                         AT_SPI_IOR, 0L, 
378                         (long)BUFSIZ, False, 
379                         (Atom) 31, &actual_type, &actual_format,
380                         &nitems, &leftover, &data);
381      if (data == NULL)
382           g_warning (_("AT_SPI_REGISTRY was not started at session startup."));
383      
384      return (gchar *) data;
385      
386 }
387
388
389 static Accessibility_Registry
390 spi_atk_bridge_get_registry (void)
391 {
392   CORBA_Environment ev;
393   char *ior =  NULL;
394
395   if (registry_died || (registry == CORBA_OBJECT_NIL)) {
396           CORBA_exception_init (&ev);
397           if (registry_died) 
398             {
399               if (exiting)
400                 return CORBA_OBJECT_NIL;
401               else
402                 DBG (1, g_warning ("registry died! restarting..."));
403             }
404
405           /* XXX: This presumes that the registry has successfully restarted itself already...*/
406           ior = (char *) spi_atk_bridge_get_registry_ior ();
407
408           if (ior != NULL)
409                registry = CORBA_ORB_string_to_object (bonobo_activation_orb_get (), 
410                                                       ior, &ev);
411           else {
412                g_warning ("IOR not set.");  
413                registry = CORBA_OBJECT_NIL;
414           }
415           
416           if (ev._major != CORBA_NO_EXCEPTION)
417           {
418                   g_error ("Accessibility app error: exception during "
419                            "registry activation from id: %s\n",
420                            CORBA_exception_id (&ev));
421                   CORBA_exception_free (&ev);
422           }
423           
424           if (registry_died && registry) {
425                   registry_died = FALSE;
426                   spi_atk_bridge_register_application (registry);
427           }
428   }
429   return registry;
430 }
431
432 static Accessibility_DeviceEventController
433 spi_atk_bridget_get_dec (void)
434 {
435   CORBA_Environment ev;
436
437   if (device_event_controller != CORBA_OBJECT_NIL)
438     {
439       if (ORBit_small_get_connection_status (device_event_controller)
440           == ORBIT_CONNECTION_CONNECTED)
441         return device_event_controller;
442     }
443
444   CORBA_exception_init (&ev);
445
446   device_event_controller =
447     Accessibility_Registry_getDeviceEventController (
448             spi_atk_bridge_get_registry (), &ev);
449
450   if (BONOBO_EX (&ev))
451     {
452       g_warning (_("failure: no device event controller found.\n"));
453       registry_died = TRUE;
454       device_event_controller = CORBA_OBJECT_NIL;
455     }
456
457   return device_event_controller;
458 }
459
460 int
461 gtk_module_init (gint *argc, gchar **argv[])
462 {
463         return atk_bridge_init (argc, argv);
464 }
465
466 static void
467 add_signal_listener (const char *signal_name)
468 {
469   guint id;
470
471   id = atk_add_global_event_listener (
472     spi_atk_bridge_signal_listener, signal_name);
473
474   g_array_append_val (listener_ids, id);
475 }
476
477 static void
478 spi_atk_register_event_listeners (void)
479 {
480   /*
481    * kludge to make sure the Atk interface types are registered, otherwise
482    * the AtkText signal handlers below won't get registered
483    */
484   guint      id;
485   GObject   *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
486   AtkObject *bo = atk_no_op_object_new (ao);
487
488
489   if (atk_listeners_registered) return;
490
491   atk_listeners_registered = TRUE;
492
493   /* Register for focus event notifications, and register app with central registry  */
494
495   listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
496
497   atk_bridge_focus_tracker_id = atk_add_focus_tracker (spi_atk_bridge_focus_tracker);
498
499   id = atk_add_global_event_listener (spi_atk_bridge_property_event_listener,
500                                       "Gtk:AtkObject:property-change");
501   g_array_append_val (listener_ids, id);
502   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
503                                       "window:create");
504   g_array_append_val (listener_ids, id);
505   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
506                                       "window:destroy");
507   g_array_append_val (listener_ids, id);
508   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
509                                       "window:minimize");
510   g_array_append_val (listener_ids, id);
511   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
512                                       "window:maximize");
513   g_array_append_val (listener_ids, id);
514   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
515                                       "window:restore");
516   g_array_append_val (listener_ids, id);
517   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
518                                       "window:activate");
519   g_array_append_val (listener_ids, id);
520   id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
521                                       "window:deactivate");
522   g_array_append_val (listener_ids, id);
523   id = atk_add_global_event_listener (spi_atk_bridge_document_event_listener,
524                                       "Gtk:AtkDocument:load-complete");
525   g_array_append_val (listener_ids, id);
526   id = atk_add_global_event_listener (spi_atk_bridge_document_event_listener,
527                                       "Gtk:AtkDocument:reload");
528   g_array_append_val (listener_ids, id);
529   id = atk_add_global_event_listener (spi_atk_bridge_document_event_listener,
530                                       "Gtk:AtkDocument:load-stopped");
531   g_array_append_val (listener_ids, id);
532   id = atk_add_global_event_listener (spi_atk_bridge_state_event_listener,
533                                       "Gtk:AtkObject:state-change");
534   g_array_append_val (listener_ids, id);
535
536   add_signal_listener ("Gtk:AtkObject:children-changed");
537   add_signal_listener ("Gtk:AtkObject:visible-data-changed");
538   add_signal_listener ("Gtk:AtkObject:active-descendant-changed");
539   add_signal_listener ("Gtk:AtkComponent:bounds-changed");
540   add_signal_listener ("Gtk:AtkSelection:selection-changed");
541   add_signal_listener ("Gtk:AtkText:text-selection-changed");
542   add_signal_listener ("Gtk:AtkText:text-changed");
543   add_signal_listener ("Gtk:AtkText:text-caret-moved");
544   add_signal_listener ("Gtk:AtkTable:row-inserted");
545   add_signal_listener ("Gtk:AtkTable:row-reordered");
546   add_signal_listener ("Gtk:AtkTable:row-deleted");
547   add_signal_listener ("Gtk:AtkTable:column-inserted");
548   add_signal_listener ("Gtk:AtkTable:column-reordered");
549   add_signal_listener ("Gtk:AtkTable:column-deleted");
550   add_signal_listener ("Gtk:AtkTable:model-changed");
551   add_signal_listener ("Gtk:AtkHypertext:link-selected");
552 /*
553  * May add the following listeners to implement preemptive key listening for GTK+
554  *
555  * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
556  * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
557  */
558   atk_bridge_key_event_listener_id = atk_add_key_event_listener (
559     spi_atk_bridge_key_listener, NULL);
560   
561   g_object_unref (G_OBJECT (bo));
562   g_object_unref (ao);
563 }
564
565 static void
566 deregister_application (BonoboObject *app)
567 {
568   Accessibility_Registry registry = spi_atk_bridge_get_registry ();
569   atk_misc_threads_leave (misc);
570   Accessibility_Registry_deregisterApplication (registry, BONOBO_OBJREF (app), &ev);
571   atk_misc_threads_enter (misc);
572
573   device_event_controller = bonobo_object_release_unref (device_event_controller, &ev);
574   registry = bonobo_object_release_unref (registry, &ev);
575   
576   app = bonobo_object_unref (app);
577 }
578
579 static void
580 spi_atk_bridge_exit_func (void)
581 {
582   BonoboObject *app = (BonoboObject *) this_app;
583
584   DBG (1, g_message ("exiting bridge\n"));
585
586   if (!app)
587     {
588       return;
589     }
590   this_app = NULL;
591   if (atk_bridge_pid != getpid ())
592     {
593       _exit (0);
594     }
595
596   exiting = TRUE;
597   /*
598    * Check whether we still have windows which have not been deleted.
599    */
600   spi_atk_tidy_windows ();
601   /*
602    *  FIXME: this may be incorrect for apps that do their own bonobo
603    *  shutdown, until we can explicitly shutdown to get the ordering
604    *  right.
605    */
606   if (!bonobo_is_initialized ())
607     {
608       DBG (1, g_warning ("Re-initializing bonobo\n"));
609       g_assert (bonobo_init (0, NULL));
610       g_assert (bonobo_activate ());
611     }
612   
613   if (!registry_died)
614     deregister_application (app);
615
616   DBG (1, g_message ("bridge exit func complete.\n"));
617
618   if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
619     {
620       g_assert (!bonobo_debug_shutdown ());
621     }
622   if (bridge_display)
623     XCloseDisplay (bridge_display);
624 }
625
626 void
627 gnome_accessibility_module_init (void)
628 {
629   atk_bridge_init (NULL, NULL);
630
631   if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
632     {
633         g_print("Atk Accessibility bridge initialized\n");
634     }
635 }
636
637 void
638 gnome_accessibility_module_shutdown (void)
639 {
640   BonoboObject *app = (BonoboObject *) this_app;
641   int     i;
642   GArray *ids = listener_ids;
643   
644   if (!atk_bridge_initialized)
645     {
646       return;
647     }
648   atk_bridge_initialized = FALSE;
649   this_app = NULL;
650
651   if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
652     {
653         g_print("Atk Accessibility bridge shutdown\n");
654     }
655
656   listener_ids = NULL;
657   if (atk_bridge_focus_tracker_id)
658         atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
659   
660   for (i = 0; ids && i < ids->len; i++)
661   {
662           atk_remove_global_event_listener (g_array_index (ids, guint, i));
663   }
664   
665   if (atk_bridge_key_event_listener_id)
666           atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
667
668   deregister_application (app);
669
670   misc = NULL;
671 }
672
673 static void
674 spi_atk_bridge_focus_tracker (AtkObject *object)
675 {
676   SpiAccessible *source;
677   Accessibility_Event e;
678   
679   source = spi_accessible_new (object);
680   
681   CORBA_exception_init (&ev);
682   
683   e.type = "focus:";
684   e.source = BONOBO_OBJREF (source);
685   e.detail1 = 0;
686   e.detail2 = 0;
687   spi_atk_bridge_init_nil (&e.any_data, object);
688   if (BONOBO_EX (&ev))
689       registry_died = TRUE;
690   else {
691       atk_misc_threads_leave (misc);   
692       Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), 
693                                           &e, &ev);
694       atk_misc_threads_enter (misc);
695   }
696   if (BONOBO_EX (&ev))
697     registry_died = TRUE;
698
699   bonobo_object_unref (source);
700   
701   CORBA_exception_free (&ev);
702 }
703
704 static void
705 spi_atk_emit_eventv (const GObject         *gobject,
706                      long                   detail1,
707                      long                   detail2,
708                      CORBA_any             *any,
709                      const char            *format, ...)
710 {
711   va_list             args;
712   Accessibility_Event e;
713   AtkObject          *aobject;
714   SpiAccessible      *source = NULL;
715   Accessibility_Registry registry;
716   const gchar *name;
717 #ifdef SPI_BRIDGE_DEBUG
718   CORBA_string s = NULL;
719 #endif
720   
721   va_start (args, format);
722   
723   if (ATK_IS_IMPLEMENTOR (gobject))
724     {
725       aobject = atk_implementor_ref_accessible (ATK_IMPLEMENTOR (gobject));
726       source  = spi_accessible_new (aobject);
727       g_object_unref (G_OBJECT (aobject));
728     }
729   else if (ATK_IS_OBJECT (gobject))
730     {
731       aobject = ATK_OBJECT (gobject);
732       if (SPI_IS_REMOTE_OBJECT (aobject))
733          e.source = spi_remote_object_get_accessible (SPI_REMOTE_OBJECT (aobject));
734       else
735          source  = spi_accessible_new (aobject);
736     }
737   else
738     {
739       aobject = NULL;
740       DBG (0, g_warning ("received property-change event from non-AtkImplementor"));
741       va_end (args);
742       return;
743     }
744   name = atk_object_get_name (aobject);
745   e.type = g_strdup_vprintf (format, args);
746   if (source) e.source = BONOBO_OBJREF (source);
747   e.detail1 = detail1;
748   e.detail2 = detail2;
749   if (any) e.any_data = *any;
750   else spi_atk_bridge_init_nil (&e.any_data, aobject);
751
752 #ifdef SPI_BRIDGE_DEBUG
753   if (e.source != CORBA_OBJECT_NIL)
754       s = Accessibility_Accessible__get_name (e.source, &ev);
755   g_message ("Emitting event '%s' (%lu, %lu) on %s",
756              e.type, e.detail1, e.detail2, s);
757   CORBA_free (s);
758 #endif
759   CORBA_exception_init (&ev);
760   registry = spi_atk_bridge_get_registry ();
761   if (!registry_died)
762   {
763     atk_misc_threads_leave (misc); 
764     Accessibility_Registry_notifyEvent (registry, 
765                                         &e, &ev);
766     atk_misc_threads_enter (misc);
767 #ifdef SPI_BRIDGE_DEBUG
768     if (ev._major != CORBA_NO_EXCEPTION)
769         g_message ("error emitting event %s, (%d) %s",
770                    e.type,
771                    ev._major,
772                    CORBA_exception_id(&ev));
773 #endif        
774     if (BONOBO_EX (&ev)) registry_died = TRUE;
775   }
776
777   if (source)
778       bonobo_object_unref (BONOBO_OBJECT (source));
779   else
780       Bonobo_Unknown_unref (e.source, &ev);
781   
782   CORBA_exception_free (&ev);
783   
784   g_free (e.type);
785
786   if (!any && e.any_data._release) CORBA_free (e.any_data._value);
787
788   if (any && any->_release) CORBA_free (any->_value);
789   
790   va_end (args);
791
792 }
793
794 static gboolean
795 spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint,
796                                         guint n_param_values,
797                                         const GValue *param_values,
798                                         gpointer data)
799 {
800   AtkPropertyValues *values;
801   GObject *gobject;
802   const gchar *prop_name;
803   CORBA_any any;
804   const gchar *sp = NULL;
805   AtkObject *ao;
806   SpiAccessible *s_ao = NULL;
807   CORBA_Object c_obj;
808   gint i;
809   const gchar *name = NULL;
810
811 #ifdef SPI_BRIDGE_DEBUG
812   GSignalQuery signal_query;
813   const gchar *signame;
814   const gchar *s, *s2;
815   
816   g_signal_query (signal_hint->signal_id, &signal_query);
817   signame = signal_query.signal_name;
818
819   s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
820   s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
821   values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
822   DBG (2, g_message ("Received (property) signal %s:%s:%s from object %s (gail %s)\n",
823            g_type_name (signal_query.itype), signame, values->property_name, s, s2));
824   
825 #endif
826
827   gobject = g_value_get_object (param_values + 0);
828   name = atk_object_get_name (ATK_OBJECT (gobject));
829   values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
830
831   prop_name = values->property_name;
832   if (strcmp (prop_name, "accessible-name") == 0)
833     {
834       spi_atk_bridge_init_string (&any, 
835                                   ATK_OBJECT (gobject),
836                                   (gchar **)&name);
837     }
838   else if (strcmp (prop_name, "accessible-description") == 0)
839     {
840       sp = atk_object_get_description (ATK_OBJECT (gobject));
841       spi_atk_bridge_init_string (&any, 
842                                   ATK_OBJECT (gobject),
843                                   (gchar **)&sp);
844     }
845   else if (strcmp (prop_name, "accessible-parent") == 0)
846     {
847       ao = atk_object_get_parent (ATK_OBJECT (gobject));
848       if (ao) 
849         {
850           s_ao = spi_accessible_new (ao);
851           c_obj = BONOBO_OBJREF (s_ao);
852           spi_atk_bridge_init_object (&any, 
853                                       ATK_OBJECT (gobject),
854                                       &c_obj);
855         }
856       else
857         {
858           spi_atk_bridge_init_nil (&any,
859                                    ATK_OBJECT (gobject));
860         }
861     }
862   else if (strcmp (prop_name, "accessible-table-summary") == 0)
863     {
864       ao = atk_table_get_summary (ATK_TABLE (gobject));
865       if (ao) 
866         {
867           s_ao = spi_accessible_new (ao);
868           c_obj = BONOBO_OBJREF (s_ao);
869           spi_atk_bridge_init_object (&any, 
870                                       ATK_OBJECT (gobject),
871                                       &c_obj);
872         }
873       else
874         {
875           spi_atk_bridge_init_nil (&any,
876                                    ATK_OBJECT (gobject));
877         }
878     }
879   else if (strcmp (prop_name, "accessible-table-column-header") == 0)
880     {
881       i = g_value_get_int (&(values->new_value));
882       ao = atk_table_get_column_header (ATK_TABLE (gobject), i);
883       if (ao) 
884         {
885           s_ao = spi_accessible_new (ao);
886           c_obj = BONOBO_OBJREF (s_ao);
887           spi_atk_bridge_init_object (&any, 
888                                       ATK_OBJECT (gobject),
889                                       &c_obj);
890         }
891       else
892         {
893           spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
894         }
895     }
896   else if (strcmp (prop_name, "accessible-table-row-header") == 0)
897     {
898       i = g_value_get_int (&(values->new_value));
899       ao = atk_table_get_row_header (ATK_TABLE (gobject), i);
900       if (ao) 
901         {
902           s_ao = spi_accessible_new (ao);
903           c_obj = BONOBO_OBJREF (s_ao);
904           spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
905         }
906       else
907         {
908           spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
909         }
910     }
911   else if (strcmp (prop_name, "accessible-table-row-description") == 0)
912     {
913       i = g_value_get_int (&(values->new_value));
914       sp = atk_table_get_row_description (ATK_TABLE (gobject), i);
915       spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), 
916                                   (gchar **)&sp);
917     }
918   else if (strcmp (prop_name, "accessible-table-column-description") == 0)
919     {
920       i = g_value_get_int (&(values->new_value));
921       sp = atk_table_get_column_description (ATK_TABLE (gobject), i);
922       spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), 
923                                   (gchar **)&sp);
924     }
925   else if (strcmp (prop_name, "accessible-table-caption-object") == 0)
926     {
927       ao = atk_table_get_caption (ATK_TABLE (gobject));
928       sp = atk_object_get_name (ao);
929       spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), 
930                                   (gchar **)&sp);
931     }
932   else
933     {
934       spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
935     }
936
937   spi_atk_emit_eventv (gobject, 0, 0, &any,
938                        "object:property-change:%s", prop_name);
939
940   if (s_ao) 
941     bonobo_object_unref (BONOBO_OBJECT (s_ao));
942
943   return TRUE;
944 }
945
946 static gboolean
947 spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint,
948                                      guint n_param_values,
949                                      const GValue *param_values,
950                                      gpointer data)
951 {
952   GObject *gobject;
953   gchar *property_name;
954   gchar *type;
955   unsigned long detail1;
956 #ifdef SPI_BRIDGE_DEBUG
957   GSignalQuery signal_query;
958   const gchar *name;
959   
960   g_signal_query (signal_hint->signal_id, &signal_query);
961   name = signal_query.signal_name;
962   fprintf (stderr, "Received (state) signal %s:%s\n",
963            g_type_name (signal_query.itype), name);
964 #endif
965
966   gobject = g_value_get_object (param_values + 0);
967   property_name = g_strdup (g_value_get_string (param_values + 1));
968   detail1 = (g_value_get_boolean (param_values + 2))
969     ? 1 : 0;
970   type = g_strdup_printf ("object:state-changed:%s", property_name);
971   spi_atk_emit_eventv (gobject, 
972                        detail1,
973                        0,
974                        NULL,
975                        type);
976   g_free (property_name);
977   g_free (type);
978   return TRUE;
979 }
980
981 static void
982 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent  *keystroke,
983                                        AtkKeyEventStruct          *event)
984 {
985 #ifdef SPI_DEBUG
986   if (event)
987     {
988       g_print ("event %c (%d)\n", (int) event->keyval, (int) event->keycode);
989     }
990   else
991 #endif
992   if (!event)
993     { /* this doesn't really need translating */
994       g_print (_("WARNING: NULL key event reported."));
995     }
996   
997   keystroke->id        = (CORBA_long) event->keyval;
998   keystroke->hw_code   = (CORBA_short) event->keycode;
999   keystroke->timestamp = (CORBA_unsigned_long) event->timestamp;
1000   keystroke->modifiers = (CORBA_unsigned_short) (event->state & 0xFFFF);
1001   if (event->string)
1002     {
1003       gunichar c;
1004
1005       keystroke->event_string = CORBA_string_dup (event->string);
1006       c = g_utf8_get_char_validated (event->string, -1);
1007       if (c > 0 && g_unichar_isprint (c))
1008         keystroke->is_text = CORBA_TRUE;
1009       else
1010         keystroke->is_text = CORBA_FALSE;
1011     }
1012   else
1013     {
1014       keystroke->event_string = CORBA_string_dup ("");
1015       keystroke->is_text = CORBA_FALSE;
1016     }
1017   switch (event->type)
1018     {
1019     case (ATK_KEY_EVENT_PRESS):
1020       keystroke->type = Accessibility_KEY_PRESSED_EVENT;
1021       break;
1022     case (ATK_KEY_EVENT_RELEASE):
1023       keystroke->type = Accessibility_KEY_RELEASED_EVENT;
1024       break;
1025     default:
1026       keystroke->type = 0;
1027       break;
1028     }
1029 #if 0  
1030   g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
1031            (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
1032            (int) keystroke->modifiers,
1033            keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
1034 #endif
1035 }
1036
1037 static gint
1038 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
1039 {
1040   CORBA_boolean             result;
1041   Accessibility_DeviceEvent key_event;
1042
1043   CORBA_exception_init (&ev);
1044
1045   spi_init_keystroke_from_atk_key_event (&key_event, event);
1046
1047   result = Accessibility_DeviceEventController_notifyListenersSync (
1048           spi_atk_bridget_get_dec (), &key_event, &ev);
1049
1050   if (key_event.event_string) CORBA_free (key_event.event_string);
1051
1052   if (BONOBO_EX(&ev)) {
1053       result = FALSE;
1054       CORBA_exception_free (&ev);
1055   }
1056
1057   return result;
1058 }
1059
1060 static gboolean
1061 spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint,
1062                                 guint n_param_values,
1063                                 const GValue *param_values,
1064                                 gpointer data)
1065 {
1066   GObject *gobject;
1067   GSignalQuery signal_query;
1068   const gchar *name;
1069   const gchar *detail;
1070   CORBA_any any;
1071   CORBA_Object c_obj;
1072   char *sp = NULL;
1073   AtkObject *ao;
1074   gint detail1 = 0, detail2 = 0;
1075   SpiAccessible *s_ao = NULL;
1076 #ifdef SPI_BRIDGE_DEBUG
1077   const gchar *s, *s2;
1078 #endif 
1079   
1080   g_signal_query (signal_hint->signal_id, &signal_query);
1081
1082   name = signal_query.signal_name;
1083   if (signal_hint->detail)
1084     detail = g_quark_to_string (signal_hint->detail);
1085   else
1086     detail = NULL;
1087
1088 #ifdef SPI_BRIDGE_DEBUG
1089   s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1090   s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1091   fprintf (stderr, "Received signal %s:%s detail: %s from object %s (gail %s)\n",
1092            g_type_name (signal_query.itype), name, 
1093            detail ? detail : "<NULL>", s ? s : "<NULL>" , s2);
1094 #endif
1095   
1096   gobject = g_value_get_object (param_values + 0);
1097
1098   if (signal_query.signal_id == atk_signal_active_descendant_changed)
1099     {
1100       gpointer child = g_value_get_pointer (param_values + 1);
1101
1102       g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
1103
1104       ao = ATK_OBJECT (child);
1105
1106       detail1 = atk_object_get_index_in_parent (ao);
1107       s_ao = spi_accessible_new (ao);
1108       c_obj = BONOBO_OBJREF (s_ao);
1109       spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
1110     }
1111   else if (signal_query.signal_id == atk_signal_link_selected)
1112     {
1113       if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT)
1114         detail1 = g_value_get_int (param_values + 1);
1115       spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1116     }
1117   else if (signal_query.signal_id == atk_signal_bounds_changed)
1118     {
1119       AtkRectangle *atk_rect = NULL;
1120
1121       if (G_VALUE_HOLDS_BOXED (param_values + 1))
1122           atk_rect = g_value_get_boxed (param_values + 1);
1123       spi_atk_bridge_init_rect (&any, ATK_OBJECT (gobject), atk_rect);
1124     }
1125   else if ((signal_query.signal_id == atk_signal_children_changed) && gobject)
1126     {
1127       detail1 = g_value_get_uint (param_values + 1);
1128       ao = atk_object_ref_accessible_child (ATK_OBJECT (gobject), 
1129                                             detail1);
1130       if (ao) 
1131         {
1132           s_ao = spi_accessible_new (ao);
1133           c_obj = BONOBO_OBJREF (s_ao);
1134           spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
1135           g_object_unref (ao);
1136         }
1137       else
1138         {
1139           spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1140         }
1141     }
1142   else
1143     {
1144       if (n_param_values >= 2)
1145         {
1146           if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT)
1147             detail1 = g_value_get_int (param_values + 1);
1148           if (n_param_values >= 3)
1149             {
1150               if (G_VALUE_TYPE (param_values + 2) == G_TYPE_INT)
1151                 detail2 = g_value_get_int (param_values + 2);
1152             }
1153         }
1154
1155       if (signal_query.signal_id == atk_signal_text_changed)
1156         {
1157           sp = atk_text_get_text (ATK_TEXT (gobject),
1158                                   detail1,
1159                                   detail1+detail2);
1160           spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), 
1161                                       (gchar **) &sp);
1162         }
1163       else if (signal_query.signal_id == atk_signal_text_selection_changed)
1164         {
1165           /* Return NULL as the selected string */
1166           spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1167         }
1168       else
1169         {
1170           spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1171         }
1172     }
1173
1174   if (detail)
1175     spi_atk_emit_eventv (gobject, detail1, detail2, &any,
1176                          "object:%s:%s", name, detail);
1177   else
1178     spi_atk_emit_eventv (gobject, detail1, detail2, &any,
1179                          "object:%s", name);
1180
1181   if (sp) 
1182     g_free (sp);
1183
1184   if (s_ao)
1185      bonobo_object_unref (BONOBO_OBJECT (s_ao));
1186
1187   return TRUE;
1188 }
1189
1190 static gboolean
1191 spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
1192                                       guint n_param_values,
1193                                       const GValue *param_values,
1194                                       gpointer data)
1195 {
1196   GObject *gobject;
1197   GSignalQuery signal_query;
1198   CORBA_any any;
1199   const gchar *name, *s;
1200 #ifdef SPI_BRIDGE_DEBUG
1201   const gchar *s2;
1202 #endif
1203   
1204   g_signal_query (signal_hint->signal_id, &signal_query);
1205
1206   name = signal_query.signal_name;
1207
1208 #ifdef SPI_BRIDGE_DEBUG
1209   s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1210   s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1211   fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n",
1212            g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2);
1213 #endif
1214   
1215   gobject = g_value_get_object (param_values + 0);
1216
1217   s = atk_object_get_name (ATK_OBJECT (gobject));
1218   spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), (gchar **) &s);
1219   
1220   spi_atk_emit_eventv (gobject, 0, 0, &any,
1221                        "window:%s", name);
1222   return TRUE;
1223 }
1224
1225 static gboolean
1226 spi_atk_bridge_document_event_listener (GSignalInvocationHint *signal_hint,
1227                                       guint n_param_values,
1228                                       const GValue *param_values,
1229                                       gpointer data)
1230 {
1231   GObject *gobject;
1232   GSignalQuery signal_query;
1233   CORBA_any any;
1234   const gchar *name, *s;
1235 #ifdef SPI_BRIDGE_DEBUG
1236   const gchar *s2;
1237 #endif
1238
1239   g_signal_query (signal_hint->signal_id, &signal_query);
1240
1241   name = signal_query.signal_name;
1242
1243 #ifdef SPI_BRIDGE_DEBUG
1244   s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1245   s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1246   fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n",
1247            g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2);
1248 #endif
1249
1250   gobject = g_value_get_object (param_values + 0);
1251
1252   s = atk_object_get_name (ATK_OBJECT (gobject));
1253   spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), (gchar **) &s);
1254
1255   spi_atk_emit_eventv (gobject, 0, 0, &any,
1256                        "document:%s", name);
1257   return TRUE;
1258 }
1259
1260 static void
1261 spi_atk_tidy_windows (void)
1262 {
1263   AtkObject *root;
1264   gint n_children;
1265   gint i;
1266
1267   root = atk_get_root ();
1268   n_children = atk_object_get_n_accessible_children (root);
1269   for (i = 0; i < n_children; i++)
1270     {
1271       AtkObject *child;
1272       AtkStateSet *stateset;
1273       CORBA_any any;
1274       const gchar *name;
1275      
1276       child = atk_object_ref_accessible_child (root, i);
1277       stateset = atk_object_ref_state_set (child);
1278       
1279       name = atk_object_get_name (child);
1280       if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
1281         {
1282           spi_atk_bridge_init_string (&any, child, (gchar**) &name);
1283           spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:deactivate");
1284           if (registry_died)
1285             return;
1286         }
1287       g_object_unref (stateset);
1288
1289       spi_atk_bridge_init_string (&any, child, (gchar**) &name);
1290       spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:destroy");
1291       g_object_unref (child);
1292     }
1293 }
1294
1295 static void
1296 reinit_register_vars (void)
1297 {
1298   registry = CORBA_OBJECT_NIL;
1299   device_event_controller = CORBA_OBJECT_NIL;
1300   this_app = NULL;
1301 }
1302
1303 static void
1304 spi_atk_bridge_init_base (CORBA_any *any, AtkObject *obj, 
1305                           Accessibility_Application *app, Accessibility_Role *role,
1306                           CORBA_string *name)
1307 {
1308     const gchar *s = atk_object_get_name (obj);
1309     *app = spi_accessible_new_return (atk_get_root (), FALSE, NULL);
1310     *role = spi_role_from_atk_role (atk_object_get_role (obj));
1311     *name = s ? s : ""; /* string gets dup-ed in util.c spi_init_any_* */
1312 }
1313
1314 static void     
1315 spi_atk_bridge_init_nil  (CORBA_any *any, AtkObject *obj)
1316 {
1317     Accessibility_Application app = CORBA_OBJECT_NIL;
1318     Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1319     CORBA_string name;
1320     spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1321     spi_init_any_nil (any, app, role, name);
1322 }
1323
1324 static void     
1325 spi_atk_bridge_init_object (CORBA_any *any, AtkObject *obj, CORBA_Object *c_obj)
1326 {
1327     Accessibility_Application app = CORBA_OBJECT_NIL;
1328     Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1329     CORBA_string name;
1330     spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1331     spi_init_any_object (any, app, role, name, c_obj);
1332 }
1333
1334 static void     
1335 spi_atk_bridge_init_string (CORBA_any *any, AtkObject *obj, gchar **string)
1336 {
1337     Accessibility_Application app = CORBA_OBJECT_NIL;
1338     Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1339     CORBA_string name;
1340     spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1341     spi_init_any_string (any, app, role, name, string);
1342 }
1343
1344 static void     
1345 spi_atk_bridge_init_rect (CORBA_any *any, AtkObject *obj, AtkRectangle *rect)
1346 {
1347     Accessibility_Application app = CORBA_OBJECT_NIL;
1348     Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1349     CORBA_string name;
1350     spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1351     spi_init_any_rect (any, app, role, name, rect);
1352 }
1353