2009-04-23 Mark Doffman <mark.doffman@codethink.co.uk>
authorMark Doffman <mdoff@silver-wind.(none)>
Thu, 23 Apr 2009 15:01:08 +0000 (16:01 +0100)
committerMark Doffman <mdoff@silver-wind.(none)>
Thu, 23 Apr 2009 15:01:08 +0000 (16:01 +0100)
        Add a hack for registering objects when an event
        needs to be sent on them and they are not already
        registered.

atk-adaptor/accessible-register.c
atk-adaptor/accessible-register.h
atk-adaptor/event.c

index c6c7328..63fc106 100644 (file)
@@ -240,16 +240,15 @@ append_children (AtkObject *accessible, GQueue *traversal)
   for (i =0; i < atk_object_get_n_accessible_children (accessible); i++)
     {
       current = atk_object_ref_accessible_child (accessible, i);
+      if (current)
+        {
 #ifdef SPI_ATK_DEBUG
-      non_owned_accessible (current);
+          non_owned_accessible (current);
 #endif
-      if (!has_manages_descendants (current))
-        {
-          g_queue_push_tail (traversal, current);
-        }
-      else
-        {
-          g_object_unref (G_OBJECT (current));
+          if (!has_manages_descendants (current))
+              g_queue_push_tail (traversal, current);
+          else
+              g_object_unref (G_OBJECT (current));
         }
     }
 }
@@ -363,6 +362,63 @@ atk_dbus_path_to_object (const char *path)
 }
 
 /*
+ * TODO WARNING HACK This function is dangerous.
+ * It should only be called before sending an event on an
+ * object that has not already been registered.
+ */
+gchar *
+atk_dbus_object_attempt_registration (AtkObject *accessible)
+{
+  guint ref;
+
+  ref = object_to_ref (accessible);
+  if (!ref)
+    {
+      /* See if the object is attached to the main tree */
+      AtkObject *current, *prev = NULL;
+      guint cref = 0;
+
+      /* This should iterate until it hits a NULL or registered parent */
+      prev = accessible;
+      current = atk_object_get_parent (accessible);
+      if (current)
+          cref = object_to_ref (current);
+      while (current && !cref)
+        {
+          prev = current;
+          current = atk_object_get_parent (current);
+          if (current)
+              cref = object_to_ref (current);
+        }
+
+      /* A registered parent, with non-registered child, has been found */
+      if (current)
+        {
+          register_subtree (prev);
+        }
+
+      /* The object SHOULD be registered now. If it isn't - I give up */
+      ref = object_to_ref (accessible);
+      if (ref)
+        {
+          return ref_to_path (ref);
+        }
+      else
+        {
+#ifdef SPI_ATK_DEBUG
+          g_debug ("AT-SPI: Could not register a non-attached accessible object");
+#endif
+          return NULL;
+        }
+    }
+  else
+    {
+      return ref_to_path (ref);
+    }
+}
+
+
+/*
  * Used to lookup a D-Bus path from the AtkObject.
  */
 gchar *
index a594413..e14886a 100644 (file)
@@ -36,6 +36,9 @@ AtkObject *
 atk_dbus_path_to_object (const char *path);
 
 gchar *
+atk_dbus_object_attempt_registration (AtkObject *accessible);
+
+gchar *
 atk_dbus_object_to_path (AtkObject *accessible);
 
 gchar *
index a201b37..3d1250e 100644 (file)
@@ -187,14 +187,23 @@ emit(AtkObject  *accessible,
 {
   gchar *path;
 
-  path = atk_dbus_object_to_path (accessible);
+  /* TODO this is a hack, used becuase child-added events are not guaranteed.
+   * On recieving an event from a non-registered object we check if it can be safely 
+   * registered before sending the event.
+   */
+  path = atk_dbus_object_attempt_registration (accessible);
 
   /* Tough decision here
    * We won't send events from accessible
    * objects that have not yet been added to the accessible tree.
    */
   if (path == NULL)
+  {
+#ifdef SPI_ATK_DEBUG
+      g_debug ("AT-SPI: Event recieved from non-registered object");
+#endif
       return;
+  }
 
   spi_dbus_emit_signal (atk_adaptor_app_data->bus, path, klass, major, minor, detail1, detail2, type, val);
   g_free(path);
@@ -298,11 +307,17 @@ property_event_listener (GSignalInvocationHint *signal_hint,
   AtkObject *otemp;
   const gchar *stemp;
   gint i;
-  
+
   accessible = g_value_get_object (&param_values[0]);
   values = (AtkPropertyValues*) g_value_get_pointer (&param_values[1]);
 
   pname = values[0].property_name;
+  if (strcmp (pname, "accessible-name") == 0 ||
+      strcmp (pname, "accessible-description") == 0 ||
+      strcmp (pname, "accessible-parent") == 0)
+  {
+      return TRUE;
+  }
 
   /* TODO Could improve this control statement by matching
    * on only the end of the signal names,