X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=atk-bridge%2Fbridge.c;h=1d3c73250845cf340e1e896a9c612c6fc44d66d3;hb=8228cc05105506c3bcfb5a88ff38165c55c89ecc;hp=e1befeab14327cbff70aa4ef392af46239c7865a;hpb=306430033b38ba2dad70cd93964abbf7803f9d72;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/atk-bridge/bridge.c b/atk-bridge/bridge.c index e1befea..1d3c732 100644 --- a/atk-bridge/bridge.c +++ b/atk-bridge/bridge.c @@ -2,8 +2,8 @@ * AT-SPI - Assistive Technology Service Provider Interface * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) * - * Copyright 2001, 2002 Sun Microsystems Inc., - * Copyright 2001, 2002 Ximian, Inc. + * Copyright 2001, 2002, 2003 Sun Microsystems Inc., + * Copyright 2001, 2002, 2003 Ximian, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,6 +21,7 @@ * Boston, MA 02111-1307, USA. */ +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include "accessible.h" #include "application.h" @@ -40,31 +42,20 @@ #define DBG(a,b) if(_dbg>=(a))b static int _dbg = 0; -static char *spi_nil_string = ""; - static CORBA_Environment ev; -static Accessibility_Registry registry = NULL; +static Accessibility_Registry registry = CORBA_OBJECT_NIL; +static Accessibility_DeviceEventController device_event_controller = CORBA_OBJECT_NIL; static SpiApplication *this_app = NULL; static gboolean registry_died = FALSE; -static guint toplevel_handler; - -/* NOT YET USED - static GQuark atk_quark_property_changed_name; - static GQuark atk_quark_property_changed_description; - static GQuark atk_quark_property_changed_parent; - static GQuark atk_quark_property_changed_role; - static GQuark atk_quark_property_changed_table_caption; - static GQuark atk_quark_property_changed_table_column_description; - static GQuark atk_quark_property_changed_table_row_description; - static guint atk_signal_property_changed; -*/ +static gboolean atk_listeners_registered = FALSE; +static gint toplevels = 0; static guint atk_signal_text_changed; -static guint atk_signal_child_changed; +static guint atk_signal_children_changed; +static guint atk_signal_active_descendant_changed; +static guint atk_signal_text_selection_changed; /* NOT YET USED - static guint atk_signal_text_selection_changed; - static guint atk_signal_active_descendant_changed; static guint atk_signal_row_reordered; static guint atk_signal_row_inserted; static guint atk_signal_row_deleted; @@ -73,14 +64,20 @@ static guint atk_signal_child_changed; static guint atk_signal_column_deleted; */ +static guint atk_signal_link_selected; + static Accessibility_Registry spi_atk_bridge_get_registry (void); static void spi_atk_bridge_do_registration (void); 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, @@ -103,6 +100,9 @@ static gboolean spi_atk_bridge_signal_listener (GSignalInvocationHint *s 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); @@ -123,10 +123,23 @@ extern void gnome_accessibility_module_shutdown (void); static void spi_atk_bridge_init_event_type_consts () { - atk_signal_child_changed = g_signal_lookup ("child_changed", + 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_TEXT); + atk_signal_active_descendant_changed = + g_signal_lookup ("active_descendant_changed", + ATK_TYPE_OBJECT); + atk_signal_link_selected = g_signal_lookup ("link_selected", + ATK_TYPE_HYPERTEXT); + atk_signal_text_selection_changed = g_signal_lookup ("text_selection_changed", + ATK_TYPE_TEXT); + done = TRUE; } static int @@ -157,18 +170,21 @@ atk_bridge_init (gint *argc, gchar **argv[]) 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; } @@ -206,8 +222,33 @@ spi_atk_bridge_toplevel_added (AtkObject *object, 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 @@ -220,11 +261,11 @@ spi_atk_bridge_register_application (Accessibility_Registry registry) } static Accessibility_Registry -spi_atk_bridge_get_registry () +spi_atk_bridge_get_registry (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...")); @@ -247,6 +288,34 @@ spi_atk_bridge_get_registry () return registry; } +static Accessibility_DeviceEventController +spi_atk_bridget_get_dec (void) +{ + CORBA_Environment ev; + + if (device_event_controller != CORBA_OBJECT_NIL) + { + if (ORBit_small_get_connection_status (device_event_controller) + == ORBIT_CONNECTION_CONNECTED) + return device_event_controller; + } + + CORBA_exception_init (&ev); + + device_event_controller = + Accessibility_Registry_getDeviceEventController ( + spi_atk_bridge_get_registry (), &ev); + + if (BONOBO_EX (&ev)) + { + g_warning ("failure: no deviceeventcontroller found\n"); + registry_died = TRUE; + device_event_controller = CORBA_OBJECT_NIL; + } + + return device_event_controller; +} + int gtk_module_init (gint *argc, gchar **argv[]) { @@ -274,7 +343,12 @@ spi_atk_register_event_listeners (void) guint id; GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL); AtkObject *bo = atk_no_op_object_new (ao); - + + + if (atk_listeners_registered) return; + + atk_listeners_registered = TRUE; + /* Register for focus event notifications, and register app with central registry */ listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16); @@ -311,6 +385,7 @@ spi_atk_register_event_listeners (void) add_signal_listener ("Gtk:AtkObject:children-changed"); add_signal_listener ("Gtk:AtkObject:visible-data-changed"); + add_signal_listener ("Gtk:AtkObject:active-descendant-changed"); add_signal_listener ("Gtk:AtkSelection:selection-changed"); add_signal_listener ("Gtk:AtkText:text-selection-changed"); add_signal_listener ("Gtk:AtkText:text-changed"); @@ -322,6 +397,7 @@ spi_atk_register_event_listeners (void) add_signal_listener ("Gtk:AtkTable:column-reordered"); add_signal_listener ("Gtk:AtkTable:column-deleted"); add_signal_listener ("Gtk:AtkTable:model-changed"); + add_signal_listener ("Gtk:AtkHypertext:link-selected"); /* * May add the following listeners to implement preemptive key listening for GTK+ * @@ -336,11 +412,38 @@ spi_atk_register_event_listeners (void) } 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 (); Accessibility_Registry_deregisterApplication (registry, BONOBO_OBJREF (app), &ev); + device_event_controller = bonobo_object_release_unref (device_event_controller, &ev); registry = bonobo_object_release_unref (registry, &ev); app = bonobo_object_unref (app); @@ -360,6 +463,10 @@ spi_atk_bridge_exit_func (void) 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. @@ -431,10 +538,13 @@ spi_atk_bridge_focus_tracker (AtkObject *object) e.detail1 = 0; e.detail2 = 0; spi_init_any_nil (&e.any_data); + + CORBA_exception_init (&ev); Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), &e, &ev); - if (BONOBO_EX (&ev)) registry_died = TRUE; - - Accessibility_Accessible_unref (e.source, &ev); + if (BONOBO_EX (&ev)) + registry_died = TRUE; + + bonobo_object_unref (source); CORBA_exception_free (&ev); } @@ -482,7 +592,7 @@ spi_atk_emit_eventv (const GObject *gobject, e.detail2 = detail2; if (any) e.any_data = *any; else spi_init_any_nil (&e.any_data); - + #ifdef SPI_BRIDGE_DEBUG s = Accessibility_Accessible__get_name (BONOBO_OBJREF (source), &ev); g_warning ("Emitting event '%s' (%lu, %lu) on %s", @@ -519,6 +629,13 @@ spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint, { AtkPropertyValues *values; GObject *gobject; + const gchar *prop_name; + CORBA_any any; + const gchar *sp = NULL; + AtkObject *ao; + SpiAccessible *s_ao = NULL; + CORBA_Object c_obj; + gint i; #ifdef SPI_BRIDGE_DEBUG GSignalQuery signal_query; @@ -539,8 +656,101 @@ spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint, gobject = g_value_get_object (param_values + 0); values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1); - spi_atk_emit_eventv (gobject, 0, 0, NULL, - "object:property-change:%s", values->property_name); + prop_name = values->property_name; + if (strcmp (prop_name, "accessible-name") == 0) + { + sp = atk_object_get_name (ATK_OBJECT (gobject)); + spi_init_any_string (&any, (gchar **)&sp); + } + else if (strcmp (prop_name, "accessible-description") == 0) + { + sp = atk_object_get_description (ATK_OBJECT (gobject)); + spi_init_any_string (&any, (gchar **)&sp); + } + else if (strcmp (prop_name, "accessible-parent") == 0) + { + ao = atk_object_get_parent (ATK_OBJECT (gobject)); + if (ao) + { + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + } + else + { + spi_init_any_nil (&any); + } + } + else if (strcmp (prop_name, "accessible-table-summary") == 0) + { + ao = atk_table_get_summary (ATK_TABLE (gobject)); + if (ao) + { + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + } + else + { + spi_init_any_nil (&any); + } + } + else if (strcmp (prop_name, "accessible-table-column-header") == 0) + { + i = g_value_get_int (&(values->new_value)); + ao = atk_table_get_column_header (ATK_TABLE (gobject), i); + if (ao) + { + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + } + else + { + spi_init_any_nil (&any); + } + } + else if (strcmp (prop_name, "accessible-table-row-header") == 0) + { + i = g_value_get_int (&(values->new_value)); + ao = atk_table_get_row_header (ATK_TABLE (gobject), i); + if (ao) + { + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + } + else + { + spi_init_any_nil (&any); + } + } + else if (strcmp (prop_name, "accessible-table-row-description") == 0) + { + i = g_value_get_int (&(values->new_value)); + sp = atk_table_get_row_description (ATK_TABLE (gobject), i); + spi_init_any_string (&any, (gchar **)&sp); + } + else if (strcmp (prop_name, "accessible-table-column-description") == 0) + { + i = g_value_get_int (&(values->new_value)); + sp = atk_table_get_column_description (ATK_TABLE (gobject), i); + spi_init_any_string (&any, (gchar **)&sp); + } + else if (strcmp (prop_name, "accessible-table-caption-object") == 0) + { + ao = atk_table_get_caption (ATK_TABLE (gobject)); + sp = atk_object_get_name (ao); + spi_init_any_string (&any, (gchar **)&sp); + } + else + { + spi_init_any_nil (&any); + } + + spi_atk_emit_eventv (gobject, 0, 0, &any, + "object:property-change:%s", prop_name); + return TRUE; } @@ -580,7 +790,6 @@ spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint, return TRUE; } - static void spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke, AtkKeyEventStruct *event) @@ -603,8 +812,14 @@ spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke, keystroke->modifiers = (CORBA_unsigned_short) (event->state & 0xFFFF); if (event->string) { + gunichar c; + keystroke->event_string = CORBA_string_dup (event->string); - keystroke->is_text = CORBA_TRUE; + c = g_utf8_get_char_validated (event->string, -1); + if (c > 0 && g_unichar_isprint (c)) + keystroke->is_text = CORBA_TRUE; + else + keystroke->is_text = CORBA_FALSE; } else { @@ -636,90 +851,19 @@ spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data) { CORBA_boolean result; Accessibility_DeviceEvent key_event; - Accessibility_DeviceEventController controller; - - if (BONOBO_EX (&ev)) - g_warning ("failure: pre-listener get dec\n"); - controller = - Accessibility_Registry_getDeviceEventController ( - spi_atk_bridge_get_registry (), &ev); + CORBA_exception_init (&ev); - if (BONOBO_EX (&ev)) - { - g_warning ("failure: no deviceeventcontroller found\n"); - CORBA_exception_free (&ev); - registry_died = TRUE; - result = FALSE; - } - else - { + spi_init_keystroke_from_atk_key_event (&key_event, event); - spi_init_keystroke_from_atk_key_event (&key_event, event); + result = Accessibility_DeviceEventController_notifyListenersSync ( + spi_atk_bridget_get_dec (), &key_event, &ev); - result = Accessibility_DeviceEventController_notifyListenersSync ( - controller, &key_event, &ev); - - bonobo_object_release_unref (controller, &ev); - CORBA_exception_free (&ev); - } + CORBA_exception_free (&ev); return result; } - -static void -spi_atk_signal_emit_event (const GObject *gobject, - const GSignalQuery *signal_query, - long detail1, - long detail2, - const gchar *name, - const gchar *detail) -{ - CORBA_any any; - CORBA_char *sp = NULL; - AtkObject *ao; - - if (signal_query->signal_id == atk_signal_text_changed) - { - sp = atk_text_get_text (ATK_TEXT (gobject), - detail1, - detail1+detail2); - spi_init_any_string (&any, &sp); - } -#ifdef EXTENDED_OBJECT_EVENTS_ARE_WORKING - else if ((signal_query->signal_id == atk_signal_child_changed) && gobject) - { - ao = atk_object_ref_accessible_child (ATK_OBJECT (gobject), - detail1); - if (ao) - { - spi_init_any_object (&any, ao); - atk_object_unref (ao); - } - else - { - spi_init_any_nil (&any); - } - } -#endif - else - { - spi_init_any_nil (&any); - } - - if (detail) - spi_atk_emit_eventv (gobject, detail1, detail2, &any, - "object:%s:%s", name, detail); - else - spi_atk_emit_eventv (gobject, detail1, detail2, &any, - "object:%s", name); - if (sp) - g_free (sp); -} - - - static gboolean spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint, guint n_param_values, @@ -730,9 +874,13 @@ spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint, GSignalQuery signal_query; const gchar *name; const gchar *detail; - CORBA_char *sp; - + CORBA_any any; + CORBA_Object c_obj; + char *sp = NULL; + AtkObject *ao; + AtkText *text; gint detail1 = 0, detail2 = 0; + SpiAccessible *s_ao = NULL; #ifdef SPI_BRIDGE_DEBUG const gchar *s, *s2; #endif @@ -754,14 +902,85 @@ spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint, #endif gobject = g_value_get_object (param_values + 0); - if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT) - detail1 = g_value_get_int (param_values + 1); - if (G_VALUE_TYPE (param_values + 2) == G_TYPE_INT) - detail2 = g_value_get_int (param_values + 2); - - spi_atk_signal_emit_event (gobject, &signal_query, - detail2, detail2, - name, detail); + + if (signal_query.signal_id == atk_signal_active_descendant_changed) + { + gpointer child = g_value_get_pointer (param_values + 1); + + g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE); + + ao = ATK_OBJECT (child); + + detail1 = atk_object_get_index_in_parent (ao); + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + } + else if (signal_query.signal_id == atk_signal_link_selected) + { + if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT) + detail1 = g_value_get_int (param_values + 1); + spi_init_any_nil (&any); + } + else if ((signal_query.signal_id == atk_signal_children_changed) && gobject) + { + ao = atk_object_ref_accessible_child (ATK_OBJECT (gobject), + detail1); + if (ao) + { + s_ao = spi_accessible_new (ao); + c_obj = BONOBO_OBJREF (s_ao); + spi_init_any_object (&any, &c_obj); + g_object_unref (ao); + } + else + { + spi_init_any_nil (&any); + } + } + else + { + if (n_param_values >= 2) + { + if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT) + detail1 = g_value_get_int (param_values + 1); + if (n_param_values >= 3) + { + if (G_VALUE_TYPE (param_values + 2) == G_TYPE_INT) + detail2 = g_value_get_int (param_values + 2); + } + } + + if (signal_query.signal_id == atk_signal_text_changed) + { + sp = atk_text_get_text (ATK_TEXT (gobject), + detail1, + detail1+detail2); + spi_init_any_string (&any, &sp); + } + else if (signal_query.signal_id == atk_signal_text_selection_changed) + { + text = ATK_TEXT (gobject); + + /* Return NULL as the selected string */ + spi_init_any_nil (&any); + } + else + { + spi_init_any_nil (&any); + } + } + + if (detail) + spi_atk_emit_eventv (gobject, detail1, detail2, &any, + "object:%s:%s", name, detail); + else + spi_atk_emit_eventv (gobject, detail1, detail2, &any, + "object:%s", name); + + if (sp) + g_free (sp); + return TRUE; } @@ -793,9 +1012,50 @@ spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint, gobject = g_value_get_object (param_values + 0); s = atk_object_get_name (ATK_OBJECT (gobject)); - spi_init_any_string (&any, &s); + spi_init_any_string (&any, (char **) &s); spi_atk_emit_eventv (gobject, 0, 0, &any, "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; +} +