static SpiApplication *this_app = NULL;
static gboolean registry_died = FALSE;
static gboolean atk_listeners_registered = FALSE;
-static guint toplevel_handler;
+static gint toplevels = 0;
static guint atk_signal_text_changed;
static guint atk_signal_children_changed;
static void spi_atk_bridge_toplevel_added (AtkObject *object,
guint index,
AtkObject *child);
+static void spi_atk_bridge_toplevel_removed (AtkObject *object,
+ guint index,
+ AtkObject *child);
static void spi_atk_bridge_exit_func (void);
static void spi_atk_register_event_listeners (void);
+static void spi_atk_deregister_event_listeners (void);
static void spi_atk_bridge_focus_tracker (AtkObject *object);
static void spi_atk_bridge_register_application (Accessibility_Registry registry);
static gboolean spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint,
gpointer data);
static gint spi_atk_bridge_key_listener (AtkKeyEventStruct *event,
gpointer data);
+static void spi_atk_tidy_windows (void);
+static void deregister_application (BonoboObject *app);
+static void reinit_register_vars (void);
/* For automatic libgnome init */
extern void gnome_accessibility_module_init (void);
static void
spi_atk_bridge_init_event_type_consts ()
{
+ static gboolean done = FALSE;
+
+ if (done)
+ return;
+
atk_signal_children_changed = g_signal_lookup ("children_changed",
ATK_TYPE_OBJECT);
atk_signal_text_changed = g_signal_lookup ("text_changed",
ATK_TYPE_HYPERTEXT);
atk_signal_text_selection_changed = g_signal_lookup ("text_selection_changed",
ATK_TYPE_TEXT);
+ done = TRUE;
}
static int
if (bonobo_activation_iid_get ())
{
DBG (1, g_message ("Found Bonobo component\n"));
- toplevel_handler = g_signal_connect (atk_get_root (),
- "children-changed::add",
- (GCallback) spi_atk_bridge_toplevel_added,
- NULL);
+ g_signal_connect (atk_get_root (),
+ "children-changed::add",
+ (GCallback) spi_atk_bridge_toplevel_added,
+ NULL);
+ g_signal_connect (atk_get_root (),
+ "children-changed::remove",
+ (GCallback) spi_atk_bridge_toplevel_removed,
+ NULL);
}
else
{
spi_atk_bridge_do_registration ();
+ spi_atk_bridge_init_event_type_consts ();
}
- spi_atk_bridge_init_event_type_consts ();
-
return 0;
}
guint index,
AtkObject *child)
{
- g_signal_handler_disconnect (object, toplevel_handler);
- spi_atk_bridge_do_registration ();
+ if (toplevels == 0)
+ {
+ spi_atk_bridge_do_registration ();
+ spi_atk_bridge_init_event_type_consts ();
+ }
+ toplevels++;
+}
+
+static void
+spi_atk_bridge_toplevel_removed (AtkObject *object,
+ guint index,
+ AtkObject *child)
+{
+ BonoboObject *app = (BonoboObject *) this_app;
+
+ toplevels--;
+ if (toplevels == 0)
+ {
+ deregister_application (app);
+ spi_atk_deregister_event_listeners ();
+ reinit_register_vars ();
+ }
+ if (toplevels < 0)
+ {
+ g_warning ("More toplevels removed than added\n");
+ toplevels = 0;
+ }
}
static void
{
CORBA_Environment ev;
- if (registry_died || (registry == NULL)) {
+ if (registry_died || (registry == CORBA_OBJECT_NIL)) {
CORBA_exception_init (&ev);
if (registry_died)
DBG (1, g_warning ("registry died! restarting..."));
}
static void
+spi_atk_deregister_event_listeners (void)
+{
+ gint i;
+ guint id;
+
+ if (!atk_listeners_registered)
+ return;
+
+ atk_listeners_registered = FALSE;
+
+ for (i = 0; i < listener_ids->len; i++)
+ {
+ id = g_array_index (listener_ids, guint, i);
+ atk_remove_global_event_listener (id);
+ }
+ g_array_free (listener_ids, TRUE);
+ listener_ids = NULL;
+
+ atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
+ atk_bridge_focus_tracker_id = 0;
+
+ atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
+ atk_bridge_key_event_listener_id = 0;
+}
+
+static void
deregister_application (BonoboObject *app)
{
Accessibility_Registry registry = spi_atk_bridge_get_registry ();
this_app = NULL;
/*
+ * Check whether we still have windows which have not been deleted.
+ */
+ spi_atk_tidy_windows ();
+ /*
* FIXME: this may be incorrect for apps that do their own bonobo
* shutdown, until we can explicitly shutdown to get the ordering
* right.
"window:%s", name);
return TRUE;
}
+
+static void
+spi_atk_tidy_windows (void)
+{
+ AtkObject *root;
+ gint n_children;
+ gint i;
+
+ root = atk_get_root ();
+ n_children = atk_object_get_n_accessible_children (root);
+ for (i = 0; i < n_children; i++)
+ {
+ AtkObject *child;
+ AtkStateSet *stateset;
+ CORBA_any any;
+ const gchar *name;
+
+ child = atk_object_ref_accessible_child (root, i);
+ stateset = atk_object_ref_state_set (child);
+
+ name = atk_object_get_name (child);
+ spi_init_any_string (&any, (char**) &name);
+ if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
+ {
+ spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:deactivate");
+ }
+ g_free (stateset);
+
+ spi_atk_emit_eventv (G_OBJECT (child), 0, 0, &any, "window:destroy");
+ g_object_unref (child);
+ }
+}
+
+static void
+reinit_register_vars (void)
+{
+ registry = CORBA_OBJECT_NIL;
+ device_event_controller = CORBA_OBJECT_NIL;
+ this_app = NULL;
+}
+