2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
6 * Copyright 2001, 2002, 2003 Ximian, Inc.
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.
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.
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.
27 #include <X11/Xatom.h>
33 #include <libbonobo.h>
34 #include <orbit/orbit.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>
45 #undef SPI_BRIDGE_DEBUG
47 #define DBG(a,b) if(_dbg>=(a))b
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;
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;
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;
74 static guint atk_signal_link_selected;
75 static guint atk_signal_bounds_changed;
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,
82 static void spi_atk_bridge_toplevel_removed (AtkObject *object,
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,
93 const GValue *param_values,
96 static void spi_atk_bridge_init_nil (CORBA_any *any,
98 static void spi_atk_bridge_init_object (CORBA_any *any,
100 CORBA_Object *c_obj);
101 static void spi_atk_bridge_init_string (CORBA_any *any,
104 static void spi_atk_bridge_init_rect (CORBA_any *any,
109 spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
110 guint n_param_values,
111 const GValue *param_values,
114 spi_atk_bridge_document_event_listener (GSignalInvocationHint *signal_hint,
115 guint n_param_values,
116 const GValue *param_values,
119 spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint,
120 guint n_param_values,
121 const GValue *param_values,
123 static gboolean spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint,
124 guint n_param_values,
125 const GValue *param_values,
127 static gint spi_atk_bridge_key_listener (AtkKeyEventStruct *event,
129 static void spi_atk_tidy_windows (void);
130 static void deregister_application (BonoboObject *app);
131 static void reinit_register_vars (void);
133 /* For automatic libgnome init */
134 extern void gnome_accessibility_module_init (void);
135 extern void gnome_accessibility_module_shutdown (void);
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;
144 * These exported symbols are hooked by gnome-program
145 * to provide automatic module initialization and shutdown.
147 extern void gnome_accessibility_module_init (void);
148 extern void gnome_accessibility_module_shutdown (void);
151 spi_atk_bridge_init_event_type_consts ()
153 static gboolean done = FALSE;
158 atk_signal_children_changed = g_signal_lookup ("children_changed",
160 atk_signal_text_changed = g_signal_lookup ("text_changed",
162 atk_signal_bounds_changed = g_signal_lookup ("bounds_changed",
164 atk_signal_active_descendant_changed =
165 g_signal_lookup ("active_descendant_changed",
167 atk_signal_link_selected = g_signal_lookup ("link_selected",
169 atk_signal_text_selection_changed = g_signal_lookup ("text_selection_changed",
175 atk_bridge_init (gint *argc, gchar **argv[])
177 const char *debug_env_string = g_getenv ("AT_SPI_DEBUG");
179 gboolean success = FALSE;
181 if (atk_bridge_initialized)
185 atk_bridge_initialized = TRUE;
186 atk_bridge_pid = getpid ();
188 misc = atk_misc_get_instance();
190 if (g_getenv ("ATK_BRIDGE_REDIRECT_LOG"))
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);
199 if (debug_env_string)
200 _dbg = (int) g_ascii_strtod (debug_env_string, NULL);
202 if (!bonobo_init (argc, argv ? *argv : NULL))
204 g_error ("Could not initialize Bonobo");
207 /* Create the accessible application server object */
208 this_app = spi_application_new (atk_get_root ());
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.
215 if (bonobo_activation_iid_get ())
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,
222 g_signal_connect (atk_get_root (),
223 "children-changed::remove",
224 (GCallback) spi_atk_bridge_toplevel_removed,
229 success = spi_atk_bridge_do_registration ();
233 spi_atk_register_event_listeners ();
234 spi_atk_bridge_init_event_type_consts ();
238 atk_bridge_initialized = FALSE;
245 spi_atk_bridge_do_registration (void)
247 CORBA_Environment ev;
249 CORBA_exception_init(&ev);
251 if (spi_atk_bridge_get_registry () == CORBA_OBJECT_NIL)
253 g_warning ("Could not locate registry");
259 /* Create the accessible application server object */
260 if (this_app == NULL)
261 this_app = spi_application_new (atk_get_root ());
263 DBG (1, g_message ("About to register application\n"));
265 spi_atk_bridge_register_application (spi_atk_bridge_get_registry ());
267 g_atexit (spi_atk_bridge_exit_func);
269 DBG (1, g_message ("Application registered & listening\n"));
274 spi_atk_bridge_toplevel_added (AtkObject *object,
280 spi_atk_bridge_do_registration ();
286 spi_atk_bridge_toplevel_removed (AtkObject *object,
290 BonoboObject *app = (BonoboObject *) this_app;
295 deregister_application (app);
296 reinit_register_vars ();
300 g_warning ("More toplevels removed than added\n");
306 spi_atk_bridge_register_application (Accessibility_Registry registry)
308 atk_misc_threads_leave (misc);
309 Accessibility_Registry_registerApplication (spi_atk_bridge_get_registry (),
310 BONOBO_OBJREF (this_app),
312 atk_misc_threads_enter (misc);
313 if (ev._major != CORBA_NO_EXCEPTION)
314 CORBA_exception_free (&ev);
318 * Returns a 'canonicalized' value for DISPLAY,
319 * with the screen number stripped off if present.
322 spi_display_name (void)
324 static const char *canonical_display_name = NULL;
325 if (!canonical_display_name)
327 const gchar *display_env = g_getenv ("AT_SPI_DISPLAY");
330 display_env = g_getenv ("DISPLAY");
331 if (!display_env || !display_env[0])
332 canonical_display_name = ":0";
335 gchar *display_p, *screen_p;
336 canonical_display_name = g_strdup (display_env);
337 display_p = strrchr (canonical_display_name, ':');
338 screen_p = strrchr (canonical_display_name, '.');
339 if (screen_p && display_p && (screen_p > display_p))
347 canonical_display_name = display_env;
350 return canonical_display_name;
353 static Display *bridge_display = NULL;
356 spi_atk_bridge_get_registry_ior (void)
362 unsigned char *data = NULL;
363 unsigned long nitems;
364 unsigned long leftover;
366 bridge_display = XOpenDisplay (spi_display_name ());
368 AT_SPI_IOR = XInternAtom (bridge_display, "AT_SPI_IOR", False);
369 XGetWindowProperty(bridge_display,
370 XDefaultRootWindow (bridge_display),
373 (Atom) 31, &actual_type, &actual_format,
374 &nitems, &leftover, &data);
376 g_warning (_("AT_SPI_REGISTRY was not started at session startup."));
378 return (gchar *) data;
383 static Accessibility_Registry
384 spi_atk_bridge_get_registry (void)
386 CORBA_Environment ev;
389 if (registry_died || (registry == CORBA_OBJECT_NIL)) {
390 CORBA_exception_init (&ev);
394 return CORBA_OBJECT_NIL;
396 DBG (1, g_warning ("registry died! restarting..."));
399 /* XXX: This presumes that the registry has successfully restarted itself already...*/
400 ior = (char *) spi_atk_bridge_get_registry_ior ();
403 registry = CORBA_ORB_string_to_object (bonobo_activation_orb_get (),
406 g_warning ("IOR not set.");
407 registry = CORBA_OBJECT_NIL;
410 if (ev._major != CORBA_NO_EXCEPTION)
412 g_error ("Accessibility app error: exception during "
413 "registry activation from id: %s\n",
414 CORBA_exception_id (&ev));
415 CORBA_exception_free (&ev);
418 if (registry_died && registry) {
419 registry_died = FALSE;
420 spi_atk_bridge_register_application (registry);
426 static Accessibility_DeviceEventController
427 spi_atk_bridget_get_dec (void)
429 CORBA_Environment ev;
431 if (device_event_controller != CORBA_OBJECT_NIL)
433 if (ORBit_small_get_connection_status (device_event_controller)
434 == ORBIT_CONNECTION_CONNECTED)
435 return device_event_controller;
438 CORBA_exception_init (&ev);
440 device_event_controller =
441 Accessibility_Registry_getDeviceEventController (
442 spi_atk_bridge_get_registry (), &ev);
446 g_warning (_("failure: no device event controller found.\n"));
447 registry_died = TRUE;
448 device_event_controller = CORBA_OBJECT_NIL;
451 return device_event_controller;
455 gtk_module_init (gint *argc, gchar **argv[])
457 return atk_bridge_init (argc, argv);
461 add_signal_listener (const char *signal_name)
465 id = atk_add_global_event_listener (
466 spi_atk_bridge_signal_listener, signal_name);
468 g_array_append_val (listener_ids, id);
472 spi_atk_register_event_listeners (void)
475 * kludge to make sure the Atk interface types are registered, otherwise
476 * the AtkText signal handlers below won't get registered
479 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
480 AtkObject *bo = atk_no_op_object_new (ao);
483 if (atk_listeners_registered) return;
485 atk_listeners_registered = TRUE;
487 /* Register for focus event notifications, and register app with central registry */
489 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
491 atk_bridge_focus_tracker_id = atk_add_focus_tracker (spi_atk_bridge_focus_tracker);
493 id = atk_add_global_event_listener (spi_atk_bridge_property_event_listener,
494 "Gtk:AtkObject:property-change");
495 g_array_append_val (listener_ids, id);
496 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
498 g_array_append_val (listener_ids, id);
499 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
501 g_array_append_val (listener_ids, id);
502 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
504 g_array_append_val (listener_ids, id);
505 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
507 g_array_append_val (listener_ids, id);
508 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
510 g_array_append_val (listener_ids, id);
511 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
513 g_array_append_val (listener_ids, id);
514 id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener,
515 "window:deactivate");
516 g_array_append_val (listener_ids, id);
517 id = atk_add_global_event_listener (spi_atk_bridge_document_event_listener,
518 "Gtk:AtkDocument:load-complete");
519 g_array_append_val (listener_ids, id);
520 id = atk_add_global_event_listener (spi_atk_bridge_document_event_listener,
521 "Gtk:AtkDocument:reload");
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-stopped");
525 g_array_append_val (listener_ids, id);
526 id = atk_add_global_event_listener (spi_atk_bridge_state_event_listener,
527 "Gtk:AtkObject:state-change");
528 g_array_append_val (listener_ids, id);
530 add_signal_listener ("Gtk:AtkObject:children-changed");
531 add_signal_listener ("Gtk:AtkObject:visible-data-changed");
532 add_signal_listener ("Gtk:AtkObject:active-descendant-changed");
533 add_signal_listener ("Gtk:AtkComponent:bounds-changed");
534 add_signal_listener ("Gtk:AtkSelection:selection-changed");
535 add_signal_listener ("Gtk:AtkText:text-selection-changed");
536 add_signal_listener ("Gtk:AtkText:text-changed");
537 add_signal_listener ("Gtk:AtkText:text-caret-moved");
538 add_signal_listener ("Gtk:AtkTable:row-inserted");
539 add_signal_listener ("Gtk:AtkTable:row-reordered");
540 add_signal_listener ("Gtk:AtkTable:row-deleted");
541 add_signal_listener ("Gtk:AtkTable:column-inserted");
542 add_signal_listener ("Gtk:AtkTable:column-reordered");
543 add_signal_listener ("Gtk:AtkTable:column-deleted");
544 add_signal_listener ("Gtk:AtkTable:model-changed");
545 add_signal_listener ("Gtk:AtkHypertext:link-selected");
547 * May add the following listeners to implement preemptive key listening for GTK+
549 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
550 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
552 atk_bridge_key_event_listener_id = atk_add_key_event_listener (
553 spi_atk_bridge_key_listener, NULL);
555 g_object_unref (G_OBJECT (bo));
560 deregister_application (BonoboObject *app)
562 Accessibility_Registry registry = spi_atk_bridge_get_registry ();
563 atk_misc_threads_leave (misc);
564 Accessibility_Registry_deregisterApplication (registry, BONOBO_OBJREF (app), &ev);
565 atk_misc_threads_enter (misc);
567 device_event_controller = bonobo_object_release_unref (device_event_controller, &ev);
568 registry = bonobo_object_release_unref (registry, &ev);
570 app = bonobo_object_unref (app);
574 spi_atk_bridge_exit_func (void)
576 BonoboObject *app = (BonoboObject *) this_app;
578 DBG (1, g_message ("exiting bridge\n"));
585 if (atk_bridge_pid != getpid ())
592 * Check whether we still have windows which have not been deleted.
594 spi_atk_tidy_windows ();
596 * FIXME: this may be incorrect for apps that do their own bonobo
597 * shutdown, until we can explicitly shutdown to get the ordering
600 if (!bonobo_is_initialized ())
602 DBG (1, g_warning ("Re-initializing bonobo\n"));
603 g_assert (bonobo_init (0, NULL));
604 g_assert (bonobo_activate ());
608 deregister_application (app);
610 DBG (1, g_message ("bridge exit func complete.\n"));
612 if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
614 g_assert (!bonobo_debug_shutdown ());
617 XCloseDisplay (bridge_display);
621 gnome_accessibility_module_init (void)
623 atk_bridge_init (NULL, NULL);
625 if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
627 g_print("Atk Accessibility bridge initialized\n");
632 gnome_accessibility_module_shutdown (void)
634 BonoboObject *app = (BonoboObject *) this_app;
636 GArray *ids = listener_ids;
638 if (!atk_bridge_initialized)
642 atk_bridge_initialized = FALSE;
645 if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
647 g_print("Atk Accessibility bridge shutdown\n");
651 if (atk_bridge_focus_tracker_id)
652 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
654 for (i = 0; ids && i < ids->len; i++)
656 atk_remove_global_event_listener (g_array_index (ids, guint, i));
659 if (atk_bridge_key_event_listener_id)
660 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
662 deregister_application (app);
666 spi_atk_bridge_focus_tracker (AtkObject *object)
668 SpiAccessible *source;
669 Accessibility_Event e;
671 source = spi_accessible_new (object);
673 CORBA_exception_init (&ev);
676 e.source = BONOBO_OBJREF (source);
679 spi_atk_bridge_init_nil (&e.any_data, object);
681 registry_died = TRUE;
683 atk_misc_threads_leave (misc);
684 Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (),
686 atk_misc_threads_enter (misc);
689 registry_died = TRUE;
691 bonobo_object_unref (source);
693 CORBA_exception_free (&ev);
697 spi_atk_emit_eventv (const GObject *gobject,
701 const char *format, ...)
704 Accessibility_Event e;
706 SpiAccessible *source = NULL;
707 Accessibility_Registry registry;
709 #ifdef SPI_BRIDGE_DEBUG
710 CORBA_string s = NULL;
713 va_start (args, format);
715 if (ATK_IS_IMPLEMENTOR (gobject))
717 aobject = atk_implementor_ref_accessible (ATK_IMPLEMENTOR (gobject));
718 source = spi_accessible_new (aobject);
719 g_object_unref (G_OBJECT (aobject));
721 else if (ATK_IS_OBJECT (gobject))
723 aobject = ATK_OBJECT (gobject);
724 if (SPI_IS_REMOTE_OBJECT (aobject))
725 e.source = spi_remote_object_get_accessible (SPI_REMOTE_OBJECT (aobject));
727 source = spi_accessible_new (aobject);
732 DBG (0, g_warning ("received property-change event from non-AtkImplementor"));
736 name = atk_object_get_name (aobject);
737 e.type = g_strdup_vprintf (format, args);
738 if (source) e.source = BONOBO_OBJREF (source);
741 if (any) e.any_data = *any;
742 else spi_atk_bridge_init_nil (&e.any_data, aobject);
744 #ifdef SPI_BRIDGE_DEBUG
745 if (e.source != CORBA_OBJECT_NIL)
746 s = Accessibility_Accessible__get_name (e.source, &ev);
747 g_message ("Emitting event '%s' (%lu, %lu) on %s",
748 e.type, e.detail1, e.detail2, s);
751 CORBA_exception_init (&ev);
752 registry = spi_atk_bridge_get_registry ();
755 atk_misc_threads_leave (misc);
756 Accessibility_Registry_notifyEvent (registry,
758 atk_misc_threads_enter (misc);
759 #ifdef SPI_BRIDGE_DEBUG
760 if (ev._major != CORBA_NO_EXCEPTION)
761 g_message ("error emitting event %s, (%d) %s",
764 CORBA_exception_id(&ev));
766 if (BONOBO_EX (&ev)) registry_died = TRUE;
770 bonobo_object_unref (BONOBO_OBJECT (source));
772 Bonobo_Unknown_unref (e.source, &ev);
774 CORBA_exception_free (&ev);
778 if (!any && e.any_data._release) CORBA_free (e.any_data._value);
780 if (any && any->_release) CORBA_free (any->_value);
787 spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint,
788 guint n_param_values,
789 const GValue *param_values,
792 AtkPropertyValues *values;
794 const gchar *prop_name;
796 const gchar *sp = NULL;
798 SpiAccessible *s_ao = NULL;
801 const gchar *name = NULL;
803 #ifdef SPI_BRIDGE_DEBUG
804 GSignalQuery signal_query;
805 const gchar *signame;
808 g_signal_query (signal_hint->signal_id, &signal_query);
809 signame = signal_query.signal_name;
811 s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
812 s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
813 values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
814 DBG (2, g_message ("Received (property) signal %s:%s:%s from object %s (gail %s)\n",
815 g_type_name (signal_query.itype), signame, values->property_name, s, s2));
819 gobject = g_value_get_object (param_values + 0);
820 name = atk_object_get_name (ATK_OBJECT (gobject));
821 values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
823 prop_name = values->property_name;
824 if (strcmp (prop_name, "accessible-name") == 0)
826 spi_atk_bridge_init_string (&any,
827 ATK_OBJECT (gobject),
830 else if (strcmp (prop_name, "accessible-description") == 0)
832 sp = atk_object_get_description (ATK_OBJECT (gobject));
833 spi_atk_bridge_init_string (&any,
834 ATK_OBJECT (gobject),
837 else if (strcmp (prop_name, "accessible-parent") == 0)
839 ao = atk_object_get_parent (ATK_OBJECT (gobject));
842 s_ao = spi_accessible_new (ao);
843 c_obj = BONOBO_OBJREF (s_ao);
844 spi_atk_bridge_init_object (&any,
845 ATK_OBJECT (gobject),
850 spi_atk_bridge_init_nil (&any,
851 ATK_OBJECT (gobject));
854 else if (strcmp (prop_name, "accessible-table-summary") == 0)
856 ao = atk_table_get_summary (ATK_TABLE (gobject));
859 s_ao = spi_accessible_new (ao);
860 c_obj = BONOBO_OBJREF (s_ao);
861 spi_atk_bridge_init_object (&any,
862 ATK_OBJECT (gobject),
867 spi_atk_bridge_init_nil (&any,
868 ATK_OBJECT (gobject));
871 else if (strcmp (prop_name, "accessible-table-column-header") == 0)
873 i = g_value_get_int (&(values->new_value));
874 ao = atk_table_get_column_header (ATK_TABLE (gobject), i);
877 s_ao = spi_accessible_new (ao);
878 c_obj = BONOBO_OBJREF (s_ao);
879 spi_atk_bridge_init_object (&any,
880 ATK_OBJECT (gobject),
885 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
888 else if (strcmp (prop_name, "accessible-table-row-header") == 0)
890 i = g_value_get_int (&(values->new_value));
891 ao = atk_table_get_row_header (ATK_TABLE (gobject), i);
894 s_ao = spi_accessible_new (ao);
895 c_obj = BONOBO_OBJREF (s_ao);
896 spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
900 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
903 else if (strcmp (prop_name, "accessible-table-row-description") == 0)
905 i = g_value_get_int (&(values->new_value));
906 sp = atk_table_get_row_description (ATK_TABLE (gobject), i);
907 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject),
910 else if (strcmp (prop_name, "accessible-table-column-description") == 0)
912 i = g_value_get_int (&(values->new_value));
913 sp = atk_table_get_column_description (ATK_TABLE (gobject), i);
914 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject),
917 else if (strcmp (prop_name, "accessible-table-caption-object") == 0)
919 ao = atk_table_get_caption (ATK_TABLE (gobject));
920 sp = atk_object_get_name (ao);
921 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject),
926 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
929 spi_atk_emit_eventv (gobject, 0, 0, &any,
930 "object:property-change:%s", prop_name);
933 bonobo_object_unref (BONOBO_OBJECT (s_ao));
939 spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint,
940 guint n_param_values,
941 const GValue *param_values,
945 gchar *property_name;
947 unsigned long detail1;
948 #ifdef SPI_BRIDGE_DEBUG
949 GSignalQuery signal_query;
952 g_signal_query (signal_hint->signal_id, &signal_query);
953 name = signal_query.signal_name;
954 fprintf (stderr, "Received (state) signal %s:%s\n",
955 g_type_name (signal_query.itype), name);
958 gobject = g_value_get_object (param_values + 0);
959 property_name = g_strdup (g_value_get_string (param_values + 1));
960 detail1 = (g_value_get_boolean (param_values + 2))
962 type = g_strdup_printf ("object:state-changed:%s", property_name);
963 spi_atk_emit_eventv (gobject,
968 g_free (property_name);
974 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
975 AtkKeyEventStruct *event)
980 g_print ("event %c (%d)\n", (int) event->keyval, (int) event->keycode);
985 { /* this doesn't really need translating */
986 g_print (_("WARNING: NULL key event reported."));
989 keystroke->id = (CORBA_long) event->keyval;
990 keystroke->hw_code = (CORBA_short) event->keycode;
991 keystroke->timestamp = (CORBA_unsigned_long) event->timestamp;
992 keystroke->modifiers = (CORBA_unsigned_short) (event->state & 0xFFFF);
997 keystroke->event_string = CORBA_string_dup (event->string);
998 c = g_utf8_get_char_validated (event->string, -1);
999 if (c > 0 && g_unichar_isprint (c))
1000 keystroke->is_text = CORBA_TRUE;
1002 keystroke->is_text = CORBA_FALSE;
1006 keystroke->event_string = CORBA_string_dup ("");
1007 keystroke->is_text = CORBA_FALSE;
1009 switch (event->type)
1011 case (ATK_KEY_EVENT_PRESS):
1012 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
1014 case (ATK_KEY_EVENT_RELEASE):
1015 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
1018 keystroke->type = 0;
1022 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
1023 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
1024 (int) keystroke->modifiers,
1025 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
1030 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
1032 CORBA_boolean result;
1033 Accessibility_DeviceEvent key_event;
1035 CORBA_exception_init (&ev);
1037 spi_init_keystroke_from_atk_key_event (&key_event, event);
1039 result = Accessibility_DeviceEventController_notifyListenersSync (
1040 spi_atk_bridget_get_dec (), &key_event, &ev);
1042 if (key_event.event_string) CORBA_free (key_event.event_string);
1044 if (BONOBO_EX(&ev)) {
1046 CORBA_exception_free (&ev);
1053 spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint,
1054 guint n_param_values,
1055 const GValue *param_values,
1059 GSignalQuery signal_query;
1061 const gchar *detail;
1066 gint detail1 = 0, detail2 = 0;
1067 SpiAccessible *s_ao = NULL;
1068 #ifdef SPI_BRIDGE_DEBUG
1069 const gchar *s, *s2;
1072 g_signal_query (signal_hint->signal_id, &signal_query);
1074 name = signal_query.signal_name;
1075 if (signal_hint->detail)
1076 detail = g_quark_to_string (signal_hint->detail);
1080 #ifdef SPI_BRIDGE_DEBUG
1081 s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1082 s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1083 fprintf (stderr, "Received signal %s:%s detail: %s from object %s (gail %s)\n",
1084 g_type_name (signal_query.itype), name,
1085 detail ? detail : "<NULL>", s ? s : "<NULL>" , s2);
1088 gobject = g_value_get_object (param_values + 0);
1090 if (signal_query.signal_id == atk_signal_active_descendant_changed)
1092 gpointer child = g_value_get_pointer (param_values + 1);
1094 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
1096 ao = ATK_OBJECT (child);
1098 detail1 = atk_object_get_index_in_parent (ao);
1099 s_ao = spi_accessible_new (ao);
1100 c_obj = BONOBO_OBJREF (s_ao);
1101 spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
1103 else if (signal_query.signal_id == atk_signal_link_selected)
1105 if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT)
1106 detail1 = g_value_get_int (param_values + 1);
1107 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1109 else if (signal_query.signal_id == atk_signal_bounds_changed)
1111 AtkRectangle *atk_rect = NULL;
1113 if (G_VALUE_HOLDS_BOXED (param_values + 1))
1114 atk_rect = g_value_get_boxed (param_values + 1);
1115 spi_atk_bridge_init_rect (&any, ATK_OBJECT (gobject), atk_rect);
1117 else if ((signal_query.signal_id == atk_signal_children_changed) && gobject)
1119 detail1 = g_value_get_uint (param_values + 1);
1120 ao = atk_object_ref_accessible_child (ATK_OBJECT (gobject),
1124 s_ao = spi_accessible_new (ao);
1125 c_obj = BONOBO_OBJREF (s_ao);
1126 spi_atk_bridge_init_object (&any, ATK_OBJECT (gobject), &c_obj);
1127 g_object_unref (ao);
1131 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1136 if (n_param_values >= 2)
1138 if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT)
1139 detail1 = g_value_get_int (param_values + 1);
1140 if (n_param_values >= 3)
1142 if (G_VALUE_TYPE (param_values + 2) == G_TYPE_INT)
1143 detail2 = g_value_get_int (param_values + 2);
1147 if (signal_query.signal_id == atk_signal_text_changed)
1149 sp = atk_text_get_text (ATK_TEXT (gobject),
1152 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject),
1155 else if (signal_query.signal_id == atk_signal_text_selection_changed)
1157 /* Return NULL as the selected string */
1158 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1162 spi_atk_bridge_init_nil (&any, ATK_OBJECT (gobject));
1167 spi_atk_emit_eventv (gobject, detail1, detail2, &any,
1168 "object:%s:%s", name, detail);
1170 spi_atk_emit_eventv (gobject, detail1, detail2, &any,
1177 bonobo_object_unref (BONOBO_OBJECT (s_ao));
1183 spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
1184 guint n_param_values,
1185 const GValue *param_values,
1189 GSignalQuery signal_query;
1191 const gchar *name, *s;
1192 #ifdef SPI_BRIDGE_DEBUG
1196 g_signal_query (signal_hint->signal_id, &signal_query);
1198 name = signal_query.signal_name;
1200 #ifdef SPI_BRIDGE_DEBUG
1201 s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1202 s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1203 fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n",
1204 g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2);
1207 gobject = g_value_get_object (param_values + 0);
1209 s = atk_object_get_name (ATK_OBJECT (gobject));
1210 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), (gchar **) &s);
1212 spi_atk_emit_eventv (gobject, 0, 0, &any,
1218 spi_atk_bridge_document_event_listener (GSignalInvocationHint *signal_hint,
1219 guint n_param_values,
1220 const GValue *param_values,
1224 GSignalQuery signal_query;
1226 const gchar *name, *s;
1227 #ifdef SPI_BRIDGE_DEBUG
1231 g_signal_query (signal_hint->signal_id, &signal_query);
1233 name = signal_query.signal_name;
1235 #ifdef SPI_BRIDGE_DEBUG
1236 s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
1237 s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
1238 fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n",
1239 g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2);
1242 gobject = g_value_get_object (param_values + 0);
1244 s = atk_object_get_name (ATK_OBJECT (gobject));
1245 spi_atk_bridge_init_string (&any, ATK_OBJECT (gobject), (gchar **) &s);
1247 spi_atk_emit_eventv (gobject, 0, 0, &any,
1248 "document:%s", name);
1253 spi_atk_tidy_windows (void)
1259 root = atk_get_root ();
1260 n_children = atk_object_get_n_accessible_children (root);
1261 for (i = 0; i < n_children; i++)
1264 AtkStateSet *stateset;
1268 child = atk_object_ref_accessible_child (root, i);
1269 stateset = atk_object_ref_state_set (child);
1271 name = atk_object_get_name (child);
1272 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
1274 spi_atk_bridge_init_string (&any, child, (gchar**) &name);
1275 spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:deactivate");
1279 g_object_unref (stateset);
1281 spi_atk_bridge_init_string (&any, child, (gchar**) &name);
1282 spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:destroy");
1283 g_object_unref (child);
1288 reinit_register_vars (void)
1290 registry = CORBA_OBJECT_NIL;
1291 device_event_controller = CORBA_OBJECT_NIL;
1296 spi_atk_bridge_init_base (CORBA_any *any, AtkObject *obj,
1297 Accessibility_Application *app, Accessibility_Role *role,
1300 const gchar *s = atk_object_get_name (obj);
1301 *app = spi_accessible_new_return (atk_get_root (), FALSE, NULL);
1302 *role = spi_role_from_atk_role (atk_object_get_role (obj));
1303 *name = s ? s : ""; /* string gets dup-ed in util.c spi_init_any_* */
1307 spi_atk_bridge_init_nil (CORBA_any *any, AtkObject *obj)
1309 Accessibility_Application app = CORBA_OBJECT_NIL;
1310 Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1312 spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1313 spi_init_any_nil (any, app, role, name);
1317 spi_atk_bridge_init_object (CORBA_any *any, AtkObject *obj, CORBA_Object *c_obj)
1319 Accessibility_Application app = CORBA_OBJECT_NIL;
1320 Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1322 spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1323 spi_init_any_object (any, app, role, name, c_obj);
1327 spi_atk_bridge_init_string (CORBA_any *any, AtkObject *obj, gchar **string)
1329 Accessibility_Application app = CORBA_OBJECT_NIL;
1330 Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1332 spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1333 spi_init_any_string (any, app, role, name, string);
1337 spi_atk_bridge_init_rect (CORBA_any *any, AtkObject *obj, AtkRectangle *rect)
1339 Accessibility_Application app = CORBA_OBJECT_NIL;
1340 Accessibility_Role role = Accessibility_ROLE_UNKNOWN;
1342 spi_atk_bridge_init_base (any, obj, &app, &role, &name);
1343 spi_init_any_rect (any, app, role, name, rect);