Fix for 99024, debug messages and warnings are only printed
[platform/core/uifw/at-spi2-atk.git] / atk-bridge / bridge.c
index 1731497..dfb8d4f 100644 (file)
@@ -2,7 +2,8 @@
  * AT-SPI - Assistive Technology Service Provider Interface
  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
  *
- * Copyright 2001 Sun Microsystems Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #undef SPI_BRIDGE_DEBUG
 
+#define DBG(a,b) if(_dbg>=(a))b
+
+static int _dbg;
+
 static CORBA_Environment ev;
 static Accessibility_Registry registry = NULL;
 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 guint atk_signal_text_changed;
+static guint atk_signal_child_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;
+   static guint atk_signal_column_reordered;
+   static guint atk_signal_column_inserted;
+   static guint atk_signal_column_deleted;
+*/
+
+#define ATK_BRIDGE_RESERVED_CONTEXT_SIZE 16
+
+typedef enum {
+  ATK_BRIDGE_CONTEXT_TYPE_NONE = 0,
+  ATK_BRIDGE_CONTEXT_TYPE_STRING,
+  ATK_BRIDGE_CONTEXT_TYPE_OBJECT
+} AtkBridgeEventContextType;
+
+typedef union {
+  gchar       *string;
+  AtkObject   *object;
+  gpointer    *foo;
+} AtkBridgeEventContextData;
+
+typedef struct {
+  AtkBridgeEventContextType _type;
+  AtkBridgeEventContextData _data;
+} AtkBridgeEventContext;
 
 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_exit_func               (void);
 static void     spi_atk_register_event_listeners       (void);
 static void     spi_atk_bridge_focus_tracker           (AtkObject             *object);
@@ -83,30 +138,59 @@ static GArray *listener_ids = NULL;
 extern void gnome_accessibility_module_init     (void);
 extern void gnome_accessibility_module_shutdown (void);
 
+static void
+atk_bridge_init_event_type_consts ()
+{
+  atk_signal_child_changed = g_signal_lookup ("child_changed", 
+                                             ATK_TYPE_OBJECT);
+  atk_signal_text_changed = g_signal_lookup ("text_changed", 
+                                            ATK_TYPE_TEXT);
+}
+
 static int
 atk_bridge_init (gint *argc, gchar **argv[])
 {
-  CORBA_Environment ev;
-
   if (atk_bridge_initialized)
     {
       return 0;
     }
   atk_bridge_initialized = TRUE;
 
+  _dbg = g_ascii_digit_value (g_getenv ("AT_SPI_DEBUG"));
+
   if (!bonobo_init (argc, argv ? *argv : NULL))
     {
       g_error ("Could not initialize Bonobo");
     }
 
   /*
-   *   We only want to enable the bridge for top level
+   * We only want to enable the bridge for top level
    * applications, we detect bonobo components by seeing
    * if they were activated with the intention of extracting
    * an impl. by IID - very solid.
    */
   if (bonobo_activation_iid_get ())
-         return 0;
+    {
+      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);
+    }
+  else
+    {
+      spi_atk_bridge_do_registration ();
+    }
+  atk_bridge_init_event_type_consts ();
+
+  return 0;
+}
+
+static void
+spi_atk_bridge_do_registration (void)
+{
+  CORBA_Environment ev;
 
   CORBA_exception_init(&ev);
 
@@ -121,15 +205,23 @@ atk_bridge_init (gint *argc, gchar **argv[])
 
   this_app = spi_application_new (atk_get_root ());
 
-  fprintf (stderr, "About to register application\n");
+  DBG (1, g_message ("About to register application\n"));
 
   spi_atk_bridge_register_application (spi_atk_bridge_get_registry ());
   
   g_atexit (spi_atk_bridge_exit_func);
 
-  fprintf (stderr, "Application registered & listening\n");
+  DBG (1, g_message ("Application registered & listening\n"));
 
-  return 0;
+}
+
+static void
+spi_atk_bridge_toplevel_added (AtkObject *object,
+                               guint     index,
+                               AtkObject *child)
+{
+  g_signal_handler_disconnect (object, toplevel_handler);
+  spi_atk_bridge_do_registration ();
 }
 
 static void
@@ -148,7 +240,8 @@ spi_atk_bridge_get_registry ()
 
   if (registry_died || (registry == NULL)) {
          CORBA_exception_init (&ev);
-         if (registry_died) g_warning ("registry died! restarting...");
+         if (registry_died) 
+           DBG (1, g_warning ("registry died! restarting..."));
          registry = bonobo_activation_activate_from_id (
                  "OAFIID:Accessibility_Registry:1.0", 0, NULL, &ev);
          
@@ -272,7 +365,7 @@ spi_atk_bridge_exit_func (void)
 {
   BonoboObject *app = (BonoboObject *) this_app;
 
-  fprintf (stderr, "exiting bridge\n");
+  DBG (1, g_message ("exiting bridge\n"));
 
   if (!app)
     {
@@ -287,14 +380,14 @@ spi_atk_bridge_exit_func (void)
    */
   if (!bonobo_is_initialized ())
     {
-      fprintf (stderr, "Re-initializing bonobo\n");
+      DBG (1, g_warning ("Re-initializing bonobo\n"));
       g_assert (bonobo_init (0, NULL));
       g_assert (bonobo_activate ());
     }
   
   deregister_application (app);
 
-  fprintf (stderr, "bridge exit func complete.\n");
+  DBG (1, g_message ("bridge exit func complete.\n"));
 
   if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
     {
@@ -340,6 +433,34 @@ gnome_accessibility_module_shutdown (void)
 }
 
 static void
+atk_bridge_event_context_init (CORBA_any *any, 
+                              AtkBridgeEventContext *ctx)
+{
+  SpiAccessible *accessible;
+  if (ctx) 
+    {
+      switch (ctx->_type) 
+       {
+         /* FIXME      
+           case ATK_BRIDGE_CONTEXT_TYPE_OBJECT:
+               accessible = spi_accessible_new (ctx->_data.object);    
+               spi_init_any_object (any, BONOBO_OBJREF (accessible));
+               break;
+         */
+       case ATK_BRIDGE_CONTEXT_TYPE_STRING:
+         spi_init_any_string (any, &ctx->_data.string);
+         break;
+       default:
+         spi_init_any_nil (any); 
+       } 
+    }
+  else
+    {
+      spi_init_any_nil (any); 
+    }
+} 
+
+static void
 spi_atk_bridge_focus_tracker (AtkObject *object)
 {
   SpiAccessible *source;
@@ -351,7 +472,7 @@ spi_atk_bridge_focus_tracker (AtkObject *object)
   e.source = BONOBO_OBJREF (source);
   e.detail1 = 0;
   e.detail2 = 0;
-
+  spi_init_any_nil (&e.any_data);
   Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), &e, &ev);
   if (BONOBO_EX (&ev)) registry_died = TRUE;
   
@@ -360,10 +481,49 @@ spi_atk_bridge_focus_tracker (AtkObject *object)
   CORBA_exception_free (&ev);
 }
 
+static
+AtkBridgeEventContext *
+spi_atk_bridge_event_context_create (GObject *gobject, 
+                                    long detail1, 
+                                    long detail2, 
+                                    GSignalQuery *signal_query, 
+                                    const gchar *detail)
+{
+  AtkBridgeEventContext *ctx = g_new0 (AtkBridgeEventContext, 1);
+  /*
+  if (signal_query->signal_id == atk_signal_child_changed) 
+    {  
+      ctx->_type = ATK_BRIDGE_CONTEXT_TYPE_OBJECT;
+      ctx->_data.object = atk_object_ref_accessible_child (ATK_OBJECT (gobject),
+                                                          (gint) detail1);
+    }
+  else */ if (signal_query->signal_id == atk_signal_text_changed)
+    {
+      ctx->_type = ATK_BRIDGE_CONTEXT_TYPE_STRING;
+      ctx->_data.string = atk_text_get_text (ATK_TEXT (gobject),
+                                            (gint) detail1,
+                                            (gint) detail1+detail2);
+    }
+  else
+    {
+      ctx->_type = ATK_BRIDGE_CONTEXT_TYPE_NONE;
+    }
+  return ctx;
+}
+
 static void
-spi_atk_emit_eventv (GObject      *gobject,
-                    unsigned long detail1,
-                    unsigned long detail2,
+spi_atk_bridge_event_context_free (AtkBridgeEventContext *ctx)
+{
+  if (ctx->_type == ATK_BRIDGE_CONTEXT_TYPE_OBJECT)
+    g_object_unref (ctx->_data.object);
+  g_free (ctx);
+}
+
+static void
+spi_atk_emit_eventv (GObject               *gobject,
+                    unsigned long          detail1,
+                    unsigned long          detail2,
+                    AtkBridgeEventContext *context,
                     const char   *format, ...)
 {
   va_list             args;
@@ -400,15 +560,16 @@ spi_atk_emit_eventv (GObject      *gobject,
       e.source = BONOBO_OBJREF (source);
       e.detail1 = detail1;
       e.detail2 = detail2;
-
 #ifdef SPI_BRIDGE_DEBUG
       s = Accessibility_Accessible__get_name (BONOBO_OBJREF (source), &ev);
       g_warning ("Emitting event '%s' (%lu, %lu) on %s",
                 e.type, e.detail1, e.detail2, s);
       CORBA_free (s);
 #endif
-
+      CORBA_exception_init (&ev);
+      atk_bridge_event_context_init (&e.any_data, context); 
       Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), &e, &ev);
+      /* I haven't freed any_data._value when it's a char*, does it leak ? */
 #ifdef SPI_BRIDGE_DEBUG
       if (ev._major != CORBA_NO_EXCEPTION)
              g_warning ("error emitting event %s, (%d) %s",
@@ -448,15 +609,16 @@ spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint,
   s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0)));
   s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0)));
   values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
-  fprintf (stderr, "Received (property) signal %s:%s:%s from object %s (gail %s)\n",
-          g_type_name (signal_query.itype), name, values->property_name, s, s2);
+  DBG (2, g_message ("Received (property) signal %s:%s:%s from object %s (gail %s)\n",
+          g_type_name (signal_query.itype), name, values->property_name, s, s2));
   
 #endif
 
   gobject = g_value_get_object (param_values + 0);
   values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1);
 
-  spi_atk_emit_eventv (gobject, 0, 0, "object:property-change:%s", values->property_name);
+  spi_atk_emit_eventv (gobject, 0, 0, NULL,
+                      "object:property-change:%s", values->property_name);
 
   return TRUE;
 }
@@ -489,6 +651,7 @@ spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint,
   spi_atk_emit_eventv (gobject, 
                       detail1,
                       0,
+                      NULL,
                       type);
   g_free (property_name);
   g_free (type);
@@ -592,6 +755,7 @@ spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint,
   GSignalQuery signal_query;
   const gchar *name;
   const gchar *detail;
+  AtkBridgeEventContext *ctx = NULL;
   
   gint detail1 = 0, detail2 = 0;
 #ifdef SPI_BRIDGE_DEBUG
@@ -619,11 +783,22 @@ spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint,
     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);
-  
+
+  /* build some event context data, depending on the type */
+  ctx = spi_atk_bridge_event_context_create (gobject, 
+                                            detail1, detail2, 
+                                            &signal_query, 
+                                            detail);
+
   if (detail)
-    spi_atk_emit_eventv (gobject, detail1, detail2, "object:%s:%s", name, detail);
+    spi_atk_emit_eventv (gobject, detail1, detail2, ctx,
+                        "object:%s:%s", name, detail);
   else
-    spi_atk_emit_eventv (gobject, detail1, detail2, "object:%s", name);
+    spi_atk_emit_eventv (gobject, detail1, detail2, ctx,
+                        "object:%s", name);
+
+  if (ctx) 
+    spi_atk_bridge_event_context_free (ctx);
 
   return TRUE;
 }
@@ -636,9 +811,11 @@ spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
 {
   GObject *gobject;
   GSignalQuery signal_query;
-  const gchar *name;
+  AtkBridgeEventContext ctx;
+
+  const gchar *name, *s;
 #ifdef SPI_BRIDGE_DEBUG
-  const gchar *s, *s2;
+  const gchar *s2;
 #endif
   
   g_signal_query (signal_hint->signal_id, &signal_query);
@@ -651,9 +828,13 @@ spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint,
   fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n",
           g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2);
 #endif
-
+  
   gobject = g_value_get_object (param_values + 0);
-  spi_atk_emit_eventv (gobject, 0, 0, "window:%s", name);
-
+  ctx._type = ATK_BRIDGE_CONTEXT_TYPE_STRING;
+  s = atk_object_get_name (ATK_OBJECT (gobject));
+  ctx._data.string = (gchar *) s;
+  /* cast from const silences compiler */
+  spi_atk_emit_eventv (gobject, 0, 0, &ctx, "window:%s", name);
+  /* don't free the context, it's on the stack */
   return TRUE;
 }