Ensure the detail ints are initialized before sending events
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / event.c
index 53e7cfe..7624844 100644 (file)
 
 #include <atk/atk.h>
 #include <droute/droute.h>
+#include <atspi/atspi.h>
 
 #include "bridge.h"
 #include "accessible-register.h"
 
 #include "common/spi-dbus.h"
+#include "event.h"
+#include "object.h"
 
 static GArray *listener_ids = NULL;
 
@@ -56,16 +59,14 @@ typedef struct _SpiReentrantCallClosure
 static void
 switch_main_context (GMainContext *cnx)
 {
-/* This code won't work on dbus-glib earlier than 0.9.0 because of FDO#30574 */
-  if (spi_global_app_data->app_bus_addr [0] == '\0')
-    return;
-
   GList *list;
 
-  dbus_server_setup_with_g_main (spi_global_app_data->server, cnx);
-  dbus_connection_setup_with_g_main (spi_global_app_data->bus, cnx);
+#ifndef DISABLE_P2P
+  atspi_dbus_server_setup_with_g_main (spi_global_app_data->server, cnx);
+#endif
+  atspi_dbus_connection_setup_with_g_main (spi_global_app_data->bus, cnx);
   for (list = spi_global_app_data->direct_connections; list; list = list->next)
-    dbus_connection_setup_with_g_main (list->data, cnx);
+    atspi_dbus_connection_setup_with_g_main (list->data, cnx);
 }
 
 static void
@@ -227,7 +228,7 @@ convert_signal_name (const gchar * s)
 }
 
 static const void *
-replace_null (const gint type,
+validate_for_dbus (const gint type,
               const void *val)
 {
   switch (type)
@@ -236,6 +237,11 @@ replace_null (const gint type,
       case DBUS_TYPE_OBJECT_PATH:
           if (!val)
              return "";
+          else if (!g_utf8_validate (val, -1, NULL))
+             {
+              g_warning ("atk-bridge: Received bad UTF-8 string when emitting event");
+              return "";
+               }
           else
              return val;
       default:
@@ -252,7 +258,7 @@ append_basic (DBusMessageIter *iter,
 
   dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type, &sub);
 
-    val = replace_null ((int) *type, val);
+    val = validate_for_dbus ((int) *type, val);
     dbus_message_iter_append_basic(&sub, (int) *type, &val);
 
   dbus_message_iter_close_container(iter, &sub);
@@ -357,6 +363,19 @@ signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor)
   data [2] = ensure_proper_format (minor);
   data [3] = NULL;
 
+  /* Hack: Always pass events that update the cache.
+   * TODO: FOr 2.2, have at-spi2-core define a special "cache listener" for
+   * this instead, so that we don't send these if no one is listening */
+  if (!g_strcmp0 (data [1], "ChildrenChanged") ||
+      !g_strcmp0 (data [1], "PropertyChange") ||
+      !g_strcmp0 (data [1], "StateChanged"))
+  {
+    g_free (data [2]);
+    g_free (data [1]);
+    g_free (data [0]);
+    return TRUE;
+  }
+
   /* Hack: events such as "object::text-changed::insert:system" as
      generated by Gecko */
   data [2][strcspn (data [2], ":")] = '\0';
@@ -370,6 +389,9 @@ signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor)
         }
     }
 
+#if 0
+  g_print("event: %s %s %s: %d\n", data[0], data[1], data[2], ret);
+#endif
   g_free (data [2]);
   g_free (data [1]);
   g_free (data [0]);
@@ -584,15 +606,14 @@ state_event_listener (GSignalInvocationHint * signal_hint,
   guint detail1;
 
   accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
-  pname = g_strdup (g_value_get_string (&param_values[1]));
+  pname = g_value_get_string (&param_values[1]);
 
-  /* TODO - Possibly ignore a change to the 'defunct' state.
-   * This is because without reference counting defunct objects should be removed.
-   */
   detail1 = (g_value_get_boolean (&param_values[2])) ? 1 : 0;
   emit_event (accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0,
               DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
-  g_free (pname);
+
+  if (!g_strcmp0 (pname, "defunct"))
+    spi_register_deregister_object (spi_global_register, G_OBJECT (accessible));
   return TRUE;
 }
 
@@ -738,7 +759,7 @@ link_selected_event_listener (GSignalInvocationHint * signal_hint,
   AtkObject *accessible;
   GSignalQuery signal_query;
   const gchar *name, *minor;
-  gint detail1;
+  gint detail1 = 0;
 
   g_signal_query (signal_hint->signal_id, &signal_query);
   name = signal_query.signal_name;
@@ -759,6 +780,8 @@ link_selected_event_listener (GSignalInvocationHint * signal_hint,
 /* 
  * Handles the ATK signal 'Gtk:AtkText:text-changed' and
  * converts it to the AT-SPI signal - 'object:text-changed'
+ * This signal is deprecated by Gtk:AtkText:text-insert
+ * and Gtk:AtkText:text-remove
  *
  */
 static gboolean
@@ -770,7 +793,7 @@ text_changed_event_listener (GSignalInvocationHint * signal_hint,
   GSignalQuery signal_query;
   const gchar *name, *minor;
   gchar *selected;
-  gint detail1, detail2;
+  gint detail1 = 0, detail2 = 0;
 
   g_signal_query (signal_hint->signal_id, &signal_query);
   name = signal_query.signal_name;
@@ -789,9 +812,109 @@ text_changed_event_listener (GSignalInvocationHint * signal_hint,
 
   emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
               DBUS_TYPE_STRING_AS_STRING, selected, append_basic);
+  g_free (selected);
+
+  return TRUE;
+}
+
+/* 
+ * Handles the ATK signal 'Gtk:AtkText:text-insert' and
+ * converts it to the AT-SPI signal - 'object:text-changed'
+ *
+ */
+static gboolean
+text_insert_event_listener (GSignalInvocationHint * signal_hint,
+                            guint n_param_values,
+                            const GValue * param_values, gpointer data)
+{
+  AtkObject *accessible;
+  guint text_changed_signal_id;
+  GSignalQuery signal_query;
+  const gchar *name;
+  gchar *minor, *text;
+  gint detail1 = 0, detail2 = 0;
+
+  accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+  /* Get signal name for 'Gtk:AtkText:text-changed' so
+   * we convert it to the AT-SPI signal - 'object:text-changed'
+   */
+  text_changed_signal_id = g_signal_lookup ("text-changed", G_OBJECT_TYPE (accessible));
+  g_signal_query (text_changed_signal_id, &signal_query);
+  name = signal_query.signal_name;
+
+
+  /* Add the insert and keep any detail coming from atk */
+  minor = g_quark_to_string (signal_hint->detail);
+  if (minor)
+    minor = g_strconcat ("insert:", minor, NULL);
+  else
+    minor = g_strdup ("insert");
+
+  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]);
+
+  if (G_VALUE_TYPE (&param_values[3]) == G_TYPE_STRING)
+    text = g_value_get_string (&param_values[3]);
+
+  emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+              DBUS_TYPE_STRING_AS_STRING, text, append_basic);
+  g_free (minor);
   return TRUE;
 }
 
+/* 
+ * Handles the ATK signal 'Gtk:AtkText:text-remove' and
+ * converts it to the AT-SPI signal - 'object:text-changed'
+ *
+ */
+static gboolean
+text_remove_event_listener (GSignalInvocationHint * signal_hint,
+                            guint n_param_values,
+                            const GValue * param_values, gpointer data)
+{
+  AtkObject *accessible;
+  guint text_changed_signal_id;
+  GSignalQuery signal_query;
+  const gchar *name;
+  gchar *minor, *text;
+  gint detail1 = 0, detail2 = 0;
+
+  accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+  /* Get signal name for 'Gtk:AtkText:text-changed' so
+   * we convert it to the AT-SPI signal - 'object:text-changed'
+   */
+  text_changed_signal_id = g_signal_lookup ("text-changed", G_OBJECT_TYPE (accessible));
+  g_signal_query (text_changed_signal_id, &signal_query);
+  name = signal_query.signal_name;
+
+  minor = g_quark_to_string (signal_hint->detail);
+
+  /* Add the delete and keep any detail coming from atk */
+  minor = g_quark_to_string (signal_hint->detail);
+  if (minor)
+    minor = g_strconcat ("delete:", minor, NULL);
+  else
+    minor = g_strdup ("delete");
+
+  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]);
+
+  if (G_VALUE_TYPE (&param_values[3]) == G_TYPE_STRING)
+    text = g_value_get_string (&param_values[3]);
+
+  emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+              DBUS_TYPE_STRING_AS_STRING, text, append_basic);
+  g_free (minor);
+  return TRUE;
+}
+
+
 /*---------------------------------------------------------------------------*/
 
 /* 
@@ -808,7 +931,7 @@ text_selection_changed_event_listener (GSignalInvocationHint * signal_hint,
   AtkObject *accessible;
   GSignalQuery signal_query;
   const gchar *name, *minor;
-  gint detail1, detail2;
+  gint detail1 = 0, detail2 = 0;
 
   g_signal_query (signal_hint->signal_id, &signal_query);
   name = signal_query.signal_name;
@@ -846,7 +969,7 @@ children_changed_event_listener (GSignalInvocationHint * signal_hint,
 {
   GSignalQuery signal_query;
   const gchar *name, *minor;
-  gint detail1, detail2 = 0;
+  gint detail1 = 0, detail2 = 0;
 
   AtkObject *accessible, *ao=NULL;
   gpointer child;
@@ -972,6 +1095,12 @@ spi_atk_register_event_listeners (void)
   g_object_unref (G_OBJECT (bo));
   g_object_unref (ao);
 
+  if (listener_ids)
+  {
+    g_warning ("atk_bridge: spi_atk-register_event_listeners called multiple times");
+    return;
+  }
+
   /* Register for focus event notifications, and register app with central registry  */
   listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
 
@@ -1002,6 +1131,10 @@ spi_atk_register_event_listeners (void)
                        "Gtk:AtkText:text-selection-changed");
   add_signal_listener (text_changed_event_listener,
                        "Gtk:AtkText:text-changed");
+  add_signal_listener (text_insert_event_listener,
+                       "Gtk:AtkText:text-insert");
+  add_signal_listener (text_remove_event_listener,
+                       "Gtk:AtkText:text-remove");
   add_signal_listener (link_selected_event_listener,
                        "Gtk:AtkHypertext:link-selected");
   add_signal_listener (generic_event_listener,
@@ -1021,10 +1154,7 @@ spi_atk_register_event_listeners (void)
                        "Gtk:AtkTable:column-reordered");
   add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
   add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
-
-  /* Children signal listeners */
-  atk_add_global_event_listener (children_changed_event_listener,
-                                 "Gtk:AtkObject:children-changed");
+  add_signal_listener (children_changed_event_listener, "Gtk:AtkObject:children-changed");
 
 #if 0
   g_signal_connect (G_OBJECT (spi_global_app_data->root),
@@ -1059,15 +1189,22 @@ spi_atk_deregister_event_listeners (void)
   listener_ids = NULL;
 
   if (atk_bridge_focus_tracker_id)
+  {
     atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
+    atk_bridge_focus_tracker_id = 0;
+  }
 
   for (i = 0; ids && i < ids->len; i++)
     {
       atk_remove_global_event_listener (g_array_index (ids, guint, i));
     }
+  g_array_free (ids, TRUE);
 
   if (atk_bridge_key_event_listener_id)
+  {
     atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
+    atk_bridge_key_event_listener_id = 0;
+  }
 }
 
 /*---------------------------------------------------------------------------*/