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