2009-02-10 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / accessible-register.c
index ae0bb75..f92c078 100644 (file)
 #include "bridge.h"
 #include "accessible-register.h"
 
-#define ATK_BRIDGE_OBJECT_PATH_PREFIX "/org/freedesktop/atspi/accessible"
-#define ATK_BRIDGE_OBJECT_REFERENCE_TEMPLATE ATK_BRIDGE_OBJECT_PATH_PREFIX "/%d"
-#define ATK_BRIDGE_PATH_PREFIX_LENGTH 33
-
 /*
  * This module is responsible for keeping track of all the AtkObjects in
  * the application, so that they can be accessed remotely and placed in
@@ -39,7 +35,7 @@
  *
  * To access an AtkObject remotely we need to provide a D-Bus object 
  * path for it. The D-Bus object paths used have a standard prefix
- * (ATK_BRIDGE_OBJECT_PATH_PREFIX). Appended to this prefix is a string
+ * (SPI_ATK_OBJECT_PATH_PREFIX). Appended to this prefix is a string
  * representation of an integer reference. So to access an AtkObject 
  * remotely we keep a Hashtable that maps the given reference to 
  * the AtkObject pointer. An object in this hash table is said to be 'registered'.
 /*
  * FIXME
  *
- * While traversing the ATK tree we may modify it unintentionally.
- * This is either a bug in the Gail implementation or this module.
- * If a change is caused that recurses, via a signal into this module
- * we should catch it.
+ * This code seems very brittle.
+ * I would prefer changes to be made to
+ * gail and the ATK interface so that all Accessible
+ * objects are registered with an exporting module.
  *
- * Things could also be changed that do not cause signal emission,
- * but do cause a failure. Not sure what these would be.
+ * This is the same system as Qt has with the QAccessibleBridge
+ * and QAccessibleBridgePlugin. It entails some rather
+ * large structural changes to ATK though:
  *
- * The other option is that there are threads that modify the GUI.
- * This IS A BUG IN THE PROGRAM. But it may happen. If seeing very 
- * odd bugs change this to take the GDK lock. Just to make sure.
+ * Removing infinite spaces (Child access no longer references child).
+ * Removing lazy creation of accessible objects.
  */
 
+#define SPI_ATK_OBJECT_PATH_PREFIX  "/org/freedesktop/atspi/accessible"
+#define SPI_ATK_OBJECT_PATH_DESKTOP "/root"
+
+#define SPI_ATK_PATH_PREFIX_LENGTH 33
+#define SPI_ATK_OBJECT_REFERENCE_TEMPLATE SPI_ATK_OBJECT_PATH_PREFIX "/%d"
+
+
 static GHashTable *ref2ptr = NULL; /* Used for converting a D-Bus path (Reference) to the object pointer */
 
 static guint counter = 1;
@@ -117,6 +120,7 @@ assign_reference(void)
   /* Reference of 0 not allowed as used as direct key in hash table */
   if (counter == 0)
     counter++;
+  return counter;
 }
 
 /*
@@ -134,7 +138,7 @@ object_to_ref (AtkObject *accessible)
 static gchar *
 ref_to_path (guint ref)
 {
-  return g_strdup_printf(ATK_BRIDGE_OBJECT_REFERENCE_TEMPLATE, ref);
+  return g_strdup_printf(SPI_ATK_OBJECT_REFERENCE_TEMPLATE, ref);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -176,6 +180,7 @@ register_accessible (AtkObject *accessible)
 
 /*---------------------------------------------------------------------------*/
 
+#ifdef SPI_ATK_DEBUG
 /*
  * This function checks that the ref-count of an accessible
  * is greater than 1.
@@ -184,7 +189,6 @@ register_accessible (AtkObject *accessible)
  * in AT-SPI D-Bus so objects that are remotely owned are not
  * allowed.
  *
- * HACK - Needs permanent soltion.
  * TODO Add debug wrapper
  */
 static gboolean
@@ -192,7 +196,7 @@ non_owned_accessible (AtkObject *accessible)
 {
    if ((G_OBJECT (accessible))->ref_count <= 1)
      {
-       g_critical ("AT-SPI: Child referenced that is not owned by its parent");
+       g_warning ("AT-SPI: Child referenced that is not owned by its parent");
        return TRUE;
      }
    else
@@ -200,6 +204,7 @@ non_owned_accessible (AtkObject *accessible)
        return FALSE;
      }
 }
+#endif /* SPI_ATK_DEBUG */
 
 /*---------------------------------------------------------------------------*/
 
@@ -216,7 +221,9 @@ has_manages_descendants (AtkObject *accessible)
    state = atk_object_ref_state_set (accessible);
    if (atk_state_set_contains_state (state, ATK_STATE_MANAGES_DESCENDANTS))
      {
-       g_message ("AT-SPI: Object with 'Manages descendants' states not currently handled by AT-SPI");
+#ifdef SPI_ATK_DEBUG
+       g_warning ("AT-SPI: Object with 'Manages descendants' states not currently handled by AT-SPI");
+#endif
        result = TRUE;
      }
    g_object_unref (state);
@@ -270,12 +277,9 @@ register_subtree (AtkObject *accessible)
         {
           tmp = atk_object_ref_accessible_child (current, i);
 
-          /* TODO Add debug wrapper */
-          if (non_owned_accessible (tmp))
-            {
-              i++;
-              continue;
-            }
+#ifdef SPI_ATK_DEBUG
+          non_owned_accessible (tmp);
+#endif
 
           if (object_to_ref (tmp))
             {
@@ -295,9 +299,10 @@ register_subtree (AtkObject *accessible)
 
           if (!recurse)
             {
-              i++;
               g_object_unref (G_OBJECT (tmp));
             }
+
+          i++;
         }
 
       if (recurse)
@@ -306,7 +311,7 @@ register_subtree (AtkObject *accessible)
           current = tmp;
           register_accessible (current);
 
-          g_queue_peek_head_link (stack)->data = GINT_TO_POINTER (i+1);
+          g_queue_peek_head_link (stack)->data = GINT_TO_POINTER (i);
           g_queue_push_head (stack, GINT_TO_POINTER (0));
         }
       else
@@ -360,12 +365,12 @@ atk_dbus_path_to_object (const char *path)
 
   g_assert (path);
 
-  if (strncmp(path, ATK_BRIDGE_OBJECT_PATH_PREFIX, ATK_BRIDGE_PATH_PREFIX_LENGTH) != 0) 
+  if (strncmp(path, SPI_ATK_OBJECT_PATH_PREFIX, SPI_ATK_PATH_PREFIX_LENGTH) != 0)
     return NULL;
 
-  path += ATK_BRIDGE_PATH_PREFIX_LENGTH; /* Skip over the prefix */
+  path += SPI_ATK_PATH_PREFIX_LENGTH; /* Skip over the prefix */
 
-  if (path[0] == '\0')
+  if (!g_strcmp0 (SPI_ATK_OBJECT_PATH_DESKTOP, path))
      return atk_get_root();
   if (path[0] != '/')
      return NULL;
@@ -394,6 +399,12 @@ atk_dbus_object_to_path (AtkObject *accessible)
       return ref_to_path (ref);
 }
 
+gchar *
+atk_dbus_desktop_object_path ()
+{
+  return g_strdup (SPI_ATK_OBJECT_PATH_PREFIX SPI_ATK_OBJECT_PATH_DESKTOP);
+}
+
 /*---------------------------------------------------------------------------*/
 
 /*
@@ -421,30 +432,24 @@ tree_update_listener (GSignalInvocationHint *signal_hint,
    * have their signals processed.
    */
   accessible = g_value_get_object (&param_values[0]);
+  g_assert (ATK_IS_OBJECT (accessible));
+
   if (object_to_ref (accessible))
     {
-      /* TODO Add debug wrapper */
+#ifdef SPI_ATK_DEBUG
       if (recursion_check_and_set ())
-          g_critical ("AT-SPI: Recursive use of registration module");
-
-      if (!ATK_IS_OBJECT (accessible))
-          g_critical ("AT-SPI: Object data updated when not a valid AtkObject");
+          g_warning ("AT-SPI: Recursive use of registration module");
+#endif
 
       values = (AtkPropertyValues*) g_value_get_pointer (&param_values[1]);
       pname = values[0].property_name;
       if (strcmp (pname, "accessible-name") == 0 ||
-          strcmp (pname, "accessible-description"))
-        {
-          update_accessible (accessible);
-        }
-      /* Parent updates not used */
-      /* Parent value us updated buy child-add signal of parent object */
-      /*
-      else if (strcmp (pname, "accessible-parent"))
+          strcmp (pname, "accessible-description") == 0)
         {
           update_accessible (accessible);
         }
-       */
+      /* Parent value us updated by child-add signal of parent object */
+
       recursion_check_unset ();
     }
 
@@ -475,17 +480,18 @@ tree_update_children_listener (GSignalInvocationHint *signal_hint,
    * have their signals processed.
    */
   accessible = g_value_get_object (&param_values[0]);
+  g_assert (ATK_IS_OBJECT (accessible));
+
   if (object_to_ref (accessible))
     {
-      /* TODO Add debug wrapper */
+#ifdef SPI_ATK_DEBUG
       if (recursion_check_and_set ())
           g_warning ("AT-SPI: Recursive use of registration module");
-
-      if (!ATK_IS_OBJECT (accessible))
-          g_critical ("AT-SPI: Object children updated when not a valid AtkObject");
+#endif
 
       if (signal_hint->detail)
-        detail = g_quark_to_string (signal_hint->detail);
+          detail = g_quark_to_string (signal_hint->detail);
+
       if (!strcmp (detail, "add"))
         {
           gpointer child;
@@ -495,17 +501,11 @@ tree_update_children_listener (GSignalInvocationHint *signal_hint,
           if (!ATK_IS_OBJECT (child))
             {
               child = atk_object_ref_accessible_child (accessible, index);
-              /* TODO Add debug wrapper */
-              if (!non_owned_accessible (child))
-                {
-                  register_subtree (child);
-                }
-            }
-          else
-            {
-              register_subtree (child);
+#ifdef SPI_ATK_DEBUG
+              non_owned_accessible (child);
+#endif
             }
-
+          register_subtree (child);
         }
 
       recursion_check_unset ();
@@ -528,8 +528,10 @@ atk_dbus_initialize (AtkObject *root)
   if (!ref2ptr)
     ref2ptr = g_hash_table_new(g_direct_hash, g_direct_equal);
 
+#ifdef SPI_ATK_DEBUG
   if (g_thread_supported ())
       g_message ("AT-SPI: Threads enabled");
+#endif
 
   register_subtree (root);