Merge branch 'master' into mgorse
authorMike Gorse <mgorse@novell.com>
Tue, 10 Nov 2009 15:35:56 +0000 (10:35 -0500)
committerMike Gorse <mgorse@novell.com>
Tue, 10 Nov 2009 15:35:56 +0000 (10:35 -0500)
1  2 
atk-adaptor/accessible-adaptor.c
atk-adaptor/accessible-register.c

@@@ -31,7 -31,7 +31,7 @@@
  #include "accessible-register.h"
  
  static dbus_bool_t
 -impl_get_name (DBusMessageIter *iter, void *user_data)
 +impl_get_Name (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
  
@@@ -41,7 -41,7 +41,7 @@@
  }
  
  static dbus_bool_t
 -impl_set_name (DBusMessageIter *iter, void *user_data)
 +impl_set_Name (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
    const char *name = droute_get_v_string (iter);
@@@ -53,7 -53,7 +53,7 @@@
  }
  
  static dbus_bool_t
 -impl_get_description (DBusMessageIter *iter, void *user_data)
 +impl_get_Description (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
  
@@@ -63,7 -63,7 +63,7 @@@
  }
  
  static dbus_bool_t
 -impl_set_description (DBusMessageIter *iter, void *user_data)
 +impl_set_Description (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
    const char *description = droute_get_v_string (iter);
@@@ -75,7 -75,7 +75,7 @@@
  }
  
  static dbus_bool_t
 -impl_get_parent (DBusMessageIter *iter, void *user_data)
 +impl_get_Parent (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
  
@@@ -87,7 -87,7 +87,7 @@@
  }
  
  static dbus_bool_t
 -impl_get_childCount (DBusMessageIter *iter, void *user_data)
 +impl_get_ChildCount (DBusMessageIter *iter, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
  
@@@ -99,7 -99,7 +99,7 @@@
  }
  
  static DBusMessage *
 -impl_getChildAtIndex (DBusConnection *bus,
 +impl_GetChildAtIndex (DBusConnection *bus,
                        DBusMessage *message,
                        void *user_data)
  {
    if (!dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
        return spi_dbus_general_error (message);
    child = atk_object_ref_accessible_child (object, i);
 -  return spi_dbus_return_object (message, child, FALSE);
 +  return spi_dbus_return_object (message, child, FALSE, FALSE);
  }
  
  static DBusMessage *
 -impl_getChildren (DBusConnection *bus,
 +impl_GetChildren (DBusConnection *bus,
                    DBusMessage *message,
                    void *user_data)
  {
    for (i = 0; i < count; i++)
      {
        AtkObject *child = atk_object_ref_accessible_child (object, i);
 -      char *path = atk_dbus_object_to_path (child);
 +      char *path = atk_dbus_object_to_path (child, FALSE);
        if (path)
        {
          dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_OBJECT_PATH,
@@@ -159,7 -159,7 +159,7 @@@ oom
  }
  
  static DBusMessage *
 -impl_getIndexInParent (DBusConnection *bus,
 +impl_GetIndexInParent (DBusConnection *bus,
                         DBusMessage *message,
                         void *user_data)
  {
@@@ -224,7 -224,7 +224,7 @@@ spi_relation_type_from_atk_relation_typ
  }
  
  static DBusMessage *
 -impl_getRelationSet (DBusConnection *bus,
 +impl_GetRelationSet (DBusConnection *bus,
                       DBusMessage *message,
                       void *user_data)
  {
    if (!reply) return NULL;
    set = atk_object_ref_relation_set (object);
    dbus_message_iter_init_append (reply, &iter);
 -  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(uao)", &iter_array))
 +  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
    {
      goto oom;
    }
        goto oom;
      }
      dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
 -    if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_targets))
 +    if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
      {
        goto oom;
      }
        AtkObject *obj = target->pdata[j];
        char *path;
        if (!obj) continue;
 -      path = atk_dbus_object_to_path (obj);
 -      dbus_message_iter_append_basic (&iter_targets, DBUS_TYPE_OBJECT_PATH, &path);
 +      path = atk_dbus_object_to_path (obj, FALSE);
 +      if (!path)
 +      {
 +      g_warning ("Unknown object in relation type %d\n", type);
 +      continue;
 +      }
 +      spi_dbus_append_name_and_path_inner (&iter_targets, NULL, path);
      }
      dbus_message_iter_close_container (&iter_struct, &iter_targets);
      dbus_message_iter_close_container (&iter_array, &iter_struct);
@@@ -415,7 -410,7 +415,7 @@@ spi_accessible_role_from_atk_role (AtkR
  }
  
  static DBusMessage *
 -impl_getRole (DBusConnection *bus, DBusMessage *message, void *user_data)
 +impl_GetRole (DBusConnection *bus, DBusMessage *message, void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
    gint role;
@@@ -445,7 -440,7 +445,7 @@@ impl_get_role_str (void *datum
  }
  
  static DBusMessage *
 -impl_getRoleName (DBusConnection *bus,
 +impl_GetRoleName (DBusConnection *bus,
                    DBusMessage *message,
                    void *user_data)
  {
  }
  
  static DBusMessage *
 -impl_getLocalizedRoleName (DBusConnection *bus,
 +impl_GetLocalizedRoleName (DBusConnection *bus,
                             DBusMessage *message,
                             void *user_data)
  {
  }
  
  static DBusMessage *
 -impl_getState (DBusConnection *bus,
 +impl_GetState (DBusConnection *bus,
                 DBusMessage *message,
                 void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
-   dbus_uint32_t rv[2];
-   dbus_uint32_t *array = rv;
-   DBusMessage *reply;
+   DBusMessage    *reply = NULL;
+   DBusMessageIter iter, iter_array;
+   dbus_uint32_t  states [2];
+   guint count;
  
    g_return_val_if_fail (ATK_IS_OBJECT (user_data),
                          droute_not_yet_handled_error (message));
-   spi_atk_state_to_dbus_array (object, rv);
    reply = dbus_message_new_method_return (message);
-   if (reply)
+   dbus_message_iter_init_append (reply, &iter);
+   spi_atk_state_to_dbus_array (object, states);
+   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
+   for (count = 0; count < 2; count++)
      {
-       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array,
-                               2, DBUS_TYPE_INVALID);
+       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32, &states[count]);
      }
+   dbus_message_iter_close_container (&iter, &iter_array);
    return reply;
  }
  
  static DBusMessage *
 -impl_getAttributes (DBusConnection *bus,
 +impl_GetAttributes (DBusConnection *bus,
                      DBusMessage *message,
                      void *user_data)
  {
    AtkObject *object = (AtkObject *) user_data;
-   DBusMessage *reply;
+   DBusMessage *reply = NULL;
  
    AtkAttributeSet *attributes;
    DBusMessageIter iter;
  }
  
  static DBusMessage *
 -impl_getApplication (DBusConnection *bus,
 +impl_GetApplication (DBusConnection *bus,
                       DBusMessage *message,
                       void *user_data)
  {
    AtkObject *root = atk_get_root ();
 -  return spi_dbus_return_object (message, root, FALSE);
 +  return spi_dbus_return_object (message, root, FALSE, FALSE);
  }
  
  static DBusMessage *
 -impl_getInterfaces (DBusConnection *bus,
 +impl_GetInterfaces (DBusConnection *bus,
                      DBusMessage *message,
                      void *user_data)
  {
  }
  
  static DRouteMethod methods[] = {
 -  {impl_getChildAtIndex, "getChildAtIndex"},
 -  {impl_getChildren, "getChildren"},
 -  {impl_getIndexInParent, "getIndexInParent"},
 -  {impl_getRelationSet, "getRelationSet"},
 -  {impl_getRole, "getRole"},
 -  {impl_getRoleName, "getRoleName"},
 -  {impl_getLocalizedRoleName, "getLocalizedRoleName"},
 -  {impl_getState, "getState"},
 -  {impl_getAttributes, "getAttributes"},
 -  {impl_getApplication, "getApplication"},
 -  {impl_getInterfaces, "getInterfaces"},
 +  {impl_GetChildAtIndex, "GetChildAtIndex"},
 +  {impl_GetChildren, "GetChildren"},
 +  {impl_GetIndexInParent, "GetIndexInParent"},
 +  {impl_GetRelationSet, "GetRelationSet"},
 +  {impl_GetRole, "GetRole"},
 +  {impl_GetRoleName, "GetRoleName"},
 +  {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
 +  {impl_GetState, "GetState"},
 +  {impl_GetAttributes, "GetAttributes"},
 +  {impl_GetApplication, "GetApplication"},
 +  {impl_GetInterfaces, "GetInterfaces"},
    {NULL, NULL}
  };
  
  static DRouteProperty properties[] = {
 -  {impl_get_name, impl_set_name, "name"},
 -  {impl_get_description, impl_set_description, "description"},
 -  {impl_get_parent, NULL, "parent"},
 -  {impl_get_childCount, NULL, "childCount"},
 +  {impl_get_Name, impl_set_Name, "Name"},
 +  {impl_get_Description, impl_set_Description, "Description"},
 +  {impl_get_Parent, NULL, "Parent"},
 +  {impl_get_ChildCount, NULL, "ChildCount"},
    {NULL, NULL, NULL}
  };
  
   */
  
  #define SPI_ATK_OBJECT_PATH_PREFIX  "/org/freedesktop/atspi/accessible"
- #define SPI_ATK_OBJECT_PATH_DESKTOP "/root"
+ #define SPI_ATK_OBJECT_PATH_DESKTOP "/desktop"
  
  #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 GHashTable *objects_with_subrefs = NULL;
 +static GHashTable *leased_refs = NULL;
 +static int leased_refs_count;
  
  static guint reference_counter = 0;
  
@@@ -89,11 -86,6 +89,11 @@@ static GStaticRecMutex registration_mut
  
  static GStaticMutex   recursion_check_guard = G_STATIC_MUTEX_INIT;
  static gboolean       recursion_check = FALSE;
 +static int last_gc_time;
 +
 +static void deregister_sub_accessible (gpointer key, gpointer obj_data, gpointer iter);
 +
 +static void deregister_sub_hyperlink (gpointer key, gpointer obj_data, gpointer iter);
  
  static gboolean
  recursion_check_and_set ()
@@@ -129,7 -121,6 +129,7 @@@ assign_reference(void
    /* Reference of 0 not allowed as used as direct key in hash table */
    if (reference_counter == 0)
      reference_counter++;
 +  /* TODO: If we've wrapped, ensure that two objects don't have the same ref */
    return reference_counter;
  }
  
   * Returns the reference of the object, or 0 if it is not registered.
   */
  static guint
 +gobject_to_ref (GObject *gobj)
 +{
 +  return GPOINTER_TO_INT(g_object_get_data (gobj, "dbus-id"));
 +}
 +
 +static guint
  object_to_ref (AtkObject *accessible)
  {
 -  return GPOINTER_TO_INT(g_object_get_data (G_OBJECT (accessible), "dbus-id"));
 +  return gobject_to_ref (G_OBJECT (accessible));
 +}
 +
 +static guint
 +hyperlink_to_ref (AtkHyperlink *link)
 +{
 +  return gobject_to_ref (G_OBJECT (link));
  }
  
  /*
@@@ -172,136 -151,33 +172,136 @@@ atk_dbus_ref_to_path (guint ref
   * it is no longer exposed over D-Bus.
   */
  static void
 -deregister_accessible (gpointer data, GObject *accessible)
 +deregister_object (gpointer data, GObject *gobj)
  {
    guint ref;
 -  g_return_if_fail (ATK_IS_OBJECT (accessible));
 +  GHashTable *subrefs_atk;
 +  GHashTable *subrefs_hyperlink;
 +  g_return_if_fail (ATK_IS_OBJECT (gobj) || ATK_IS_HYPERLINK (gobj));
 +
 +  subrefs_atk = (GHashTable *) g_object_get_data (gobj, "dbus-subrefs-atk");
 +  subrefs_hyperlink = (GHashTable *) g_object_get_data (gobj, "dbus-subrefs-hyperlink");
 +
 +  if (subrefs_atk)
 +  {
 +    g_hash_table_foreach (subrefs_atk, deregister_sub_accessible, data);
 +    g_hash_table_unref (subrefs_atk);
 +  }
 +  
 +  if (subrefs_hyperlink)
 +  {
 +    g_hash_table_foreach (subrefs_hyperlink, deregister_sub_hyperlink, data);
 +    g_hash_table_unref (subrefs_hyperlink);
 +  }
 +  
 +  if (subrefs_atk || subrefs_hyperlink)
 +    g_hash_table_remove (objects_with_subrefs, gobj);
 +
 +  if (ATK_IS_OBJECT (gobj))
 +  {
 +    ref = object_to_ref (ATK_OBJECT (gobj));
 +    if (ref != 0)
 +      {
 +        spi_emit_cache_removal (ref, atk_adaptor_app_data->bus);
 +        g_hash_table_remove(ref2ptr, GINT_TO_POINTER(ref));
 +      }
 +    }
 +  }
  
 -  ref = object_to_ref (ATK_OBJECT(accessible));
 +static void
 +deregister_sub_accessible (gpointer key, gpointer obj_data, gpointer iter)
 +{
 +  GObject *obj = G_OBJECT (obj_data);
 +  deregister_object (NULL, obj);
 +  g_hash_table_remove (leased_refs, obj);
 +  g_object_unref (obj);
 +}
 +
 +static void
 +deregister_sub_hyperlink (gpointer key, gpointer obj_data, gpointer iter)
 +{
 +  guint ref;
 +  GObject *ghyperlink = G_OBJECT (obj_data);
 +
 +  g_return_if_fail (ATK_IS_HYPERLINK (ghyperlink));
 +
 +  ref = gobject_to_ref (ghyperlink);
    if (ref != 0)
      {
 -      spi_emit_cache_removal (ref, atk_adaptor_app_data->bus);
        g_hash_table_remove(ref2ptr, GINT_TO_POINTER(ref));
      }
 +  g_object_unref (ghyperlink);
 +}
 +
 +static void
 +register_gobject (GObject *gobj, GObject *container)
 +{
 +  guint ref;
 +  g_return_if_fail (G_IS_OBJECT(gobj));
 +
 +  ref = assign_reference();
 +
 +  g_hash_table_insert (ref2ptr, GINT_TO_POINTER(ref), gobj);
 +  g_object_set_data (G_OBJECT(gobj), "dbus-id", GINT_TO_POINTER(ref));
 +  g_object_weak_ref(G_OBJECT(gobj), deregister_object, NULL);
 +
 +  if (container)
 +  {
 +    GHashTable *subrefs = (GHashTable *) g_object_get_data (G_OBJECT (container), "dbus-subrefs-atk");
 +    if (!subrefs)
 +    {
 +      subrefs = g_hash_table_new(g_direct_hash, g_direct_equal);
 +      g_object_set_data (G_OBJECT (container), "dbus-subrefs-atk", subrefs);
 +    }
 +    g_hash_table_insert (subrefs, GINT_TO_POINTER(ref), gobj);
 +    g_hash_table_insert (objects_with_subrefs, gobj, subrefs);
 +  }
 +
 +  if (ATK_IS_HYPERLINK (gobj))
 +    g_object_ref (gobj);
 +  else if (ATK_IS_OBJECT (gobj))
 +  {
 +    AtkObject *accessible = ATK_OBJECT (gobj);
 +    AtkStateSet *state = atk_object_ref_state_set (accessible);
 +    if (atk_state_set_contains_state (state, ATK_STATE_TRANSIENT))
 +    {
 +      g_object_ref (gobj);
 +    }
 +    g_object_unref (state);
 +  }
  }
  
  /*
   * Called to register an AtkObject with AT-SPI and expose it over D-Bus.
   */
  static void
 -register_accessible (AtkObject *accessible)
 +register_accessible (AtkObject *accessible, AtkObject *container)
  {
 -  guint ref;
    g_return_if_fail (ATK_IS_OBJECT(accessible));
  
 +  register_gobject (G_OBJECT (accessible), G_OBJECT (container));
 +}
 +
 +static void
 +register_hyperlink (AtkHyperlink *hyperlink, AtkObject *container)
 +{
 +  guint ref;
 +  g_return_if_fail (ATK_IS_HYPERLINK (hyperlink));
 +  g_return_if_fail (container);
 +
    ref = assign_reference();
  
 -  g_hash_table_insert (ref2ptr, GINT_TO_POINTER(ref), accessible);
 -  g_object_set_data (G_OBJECT(accessible), "dbus-id", GINT_TO_POINTER(ref));
 -  g_object_weak_ref(G_OBJECT(accessible), deregister_accessible, NULL);
 +  g_hash_table_insert (ref2ptr, GINT_TO_POINTER(ref), hyperlink);
 +  g_object_set_data (G_OBJECT(hyperlink), "dbus-id", GINT_TO_POINTER(ref));
 +  g_object_ref (G_OBJECT (hyperlink));
 +
 +  GHashTable *subrefs = (GHashTable *) g_object_get_data (G_OBJECT (container), "dbus-subrefs-hyperlink");
 +  if (!subrefs)
 +  {
 +    subrefs = g_hash_table_new(g_direct_hash, g_direct_equal);
 +    g_object_set_data (G_OBJECT (container), "dbus-subrefs-hyperlink", GINT_TO_POINTER(ref));
 +  }
 +  g_hash_table_insert (subrefs, GINT_TO_POINTER(ref), hyperlink);
  }
  
  /*---------------------------------------------------------------------------*/
@@@ -334,11 -210,8 +334,11 @@@ non_owned_accessible (AtkObject *access
  
  /*---------------------------------------------------------------------------*/
  
 +/* TRUE if we should not keep this object / tell the AT about it
 + * Currently true if TRANSIENT and not SHOWING
 + */
  static gboolean
 -has_manages_descendants (AtkObject *accessible)
 +object_is_moot (AtkObject *accessible)
  {
     AtkStateSet *state;
     gboolean result = FALSE;
      * by modifying the tree alot.
      */
     state = atk_object_ref_state_set (accessible);
 -   if (atk_state_set_contains_state (state, ATK_STATE_MANAGES_DESCENDANTS))
 +   if ( atk_state_set_contains_state (state, ATK_STATE_TRANSIENT) &&
 +       !atk_state_set_contains_state (state, ATK_STATE_SHOWING))
       {
 -#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);
@@@ -374,7 -249,10 +374,7 @@@ append_children (AtkObject *accessible
  #ifdef SPI_ATK_DEBUG
            non_owned_accessible (current);
  #endif
 -          if (!has_manages_descendants (current))
 -              g_queue_push_tail (traversal, current);
 -          else
 -              g_object_unref (G_OBJECT (current));
 +          g_queue_push_tail (traversal, current);
          }
      }
  }
@@@ -409,7 -287,7 +409,7 @@@ register_subtree (AtkObject *accessible
        g_queue_push_tail (emit_update, current);
        if (!object_to_ref (current))
          {
 -          register_accessible (current);
 +          register_accessible (current, NULL);
  #ifdef SPI_ATK_DEBUG
            g_debug ("REG  - %s - %d - %s", atk_object_get_name     (current),
                                            atk_object_get_role     (current),
@@@ -460,8 -338,8 +460,8 @@@ atk_dbus_foreach_registered(GHFunc func
  /*
   * Used to lookup an AtkObject from its D-Bus path.
   */
 -AtkObject *
 -atk_dbus_path_to_object (const char *path)
 +GObject *
 +atk_dbus_path_to_gobject (const char *path)
  {
    guint index;
    void *data;
    path += SPI_ATK_PATH_PREFIX_LENGTH; /* Skip over the prefix */
  
    if (!g_strcmp0 (SPI_ATK_OBJECT_PATH_DESKTOP, path))
 -     return atk_get_root();
 +     return G_OBJECT (atk_get_root());
    if (path[0] != '/')
       return NULL;
  
    index = atoi (path);
    data = g_hash_table_lookup (ref2ptr, GINT_TO_POINTER(index));
    if (data)
 -    return ATK_OBJECT (data);
 +  {
 +    GObject *gobj = G_OBJECT (data);
 +    g_object_set_data (gobj, "last-ref-time", (gpointer) time (NULL));
 +    return gobj;
 +  }
    else
      return NULL;
  }
  
 +AtkObject *
 +atk_dbus_path_to_object (const char *path)
 +{
 +  return ATK_OBJECT (atk_dbus_path_to_gobject (path));
 +}
 +
  /*
   * TODO WARNING HACK This function is dangerous.
   * It should only be called before sending an event on an
@@@ -557,49 -425,12 +557,49 @@@ atk_dbus_object_attempt_registration (A
  /*
   * Used to lookup a D-Bus path from the AtkObject.
   */
 +static gchar *
 +atk_dbus_gobject_to_path_internal (GObject *gobj, gboolean do_register, GObject *container)
 +{
 +  guint ref;
 +
 +  ref = gobject_to_ref (gobj);
 +  if (!ref && do_register)
 +  {
 +    register_gobject (gobj, container);
 +    ref = gobject_to_ref (gobj);
 +  }
 +
 +  if (!ref)
 +      return NULL;
 +  else
 +      return atk_dbus_ref_to_path (ref);
 +}
 +
 +gchar *
 +atk_dbus_object_to_path (AtkObject *accessible, gboolean do_register)
 +{
 +  AtkObject *container = (accessible && do_register? atk_object_get_parent (accessible): NULL);
 +  return atk_dbus_gobject_to_path_internal (G_OBJECT (accessible), do_register, G_OBJECT (container));
 +}
 +
 +gchar *
 +atk_dbus_sub_object_to_path (GObject *gobj, GObject *container)
 +{
 +  return atk_dbus_gobject_to_path_internal (gobj, TRUE, container);
 +}
 +
  gchar *
 -atk_dbus_object_to_path (AtkObject *accessible)
 +atk_dbus_hyperlink_to_path (AtkHyperlink *hyperlink, AtkObject *container)
  {
    guint ref;
  
 -  ref = object_to_ref (accessible);
 +  ref = gobject_to_ref (G_OBJECT (hyperlink));
 +  if (!ref && container)
 +  {
 +    register_hyperlink (hyperlink, container);
 +    ref = hyperlink_to_ref (hyperlink);
 +  }
 +
    if (!ref)
        return NULL;
    else
@@@ -666,68 -497,12 +666,68 @@@ tree_update_wrapper (GSignalInvocationH
  }
  
  static gboolean
 +maybe_expire_lease (gpointer key, gpointer obj_data, gpointer iter)
 +{
 +  time_t secs = time (NULL) - (time_t)obj_data;
 +
 +  if (secs < 30)
 +    return FALSE;
 +  deregister_sub_accessible (key, obj_data, iter);
 +  return TRUE;
 +}
 +
 +static void
 +expire_old_leases_in (gpointer key, gpointer obj_data, gpointer iter)
 +{
 +  g_hash_table_foreach_remove ((GHashTable *)obj_data, maybe_expire_lease, NULL);
 +}
 +
 +static void
 +expire_old_leases ()
 +{
 +  g_hash_table_foreach (objects_with_subrefs, expire_old_leases_in, NULL);
 +}
 +
 +static gboolean
  tree_update_state_action (GSignalInvocationHint *signal_hint,
                            guint                  n_param_values,
                            const GValue          *param_values,
                            gpointer               data,
                            AtkObject             *accessible)
  {
 +  const gchar *name;
 +  gboolean state;
 +
 +  if (n_param_values < 3)
 +  {
 +    g_warning ("at-spi: Not enough params in state-changed signal");
 +                              return TRUE;
 +  }
 +
 +  name = g_value_get_string (param_values + 1);
 +  state = g_value_get_boolean (param_values + 2);
 +  if (!strcmp (name, "visible"))
 +  {
 +    AtkStateSet *set = atk_object_ref_state_set (accessible);
 +    if (atk_state_set_contains_state (set, ATK_STATE_TRANSIENT))
 +    {
 +      if (state == 0)
 +      {
 +      g_hash_table_insert (leased_refs, accessible, (gpointer) time (NULL));
 +      leased_refs_count++;
 +      /* todo: Set to a high number: 5 for dbg. */
 +      if (leased_refs_count > 5)
 +        expire_old_leases ();
 +      }
 +      else
 +      {
 +      g_hash_table_remove (leased_refs, accessible);
 +      leased_refs_count--;
 +      }
 +    }
 +    g_object_unref (set);
 +  }
 +
        update_accessible (accessible);
    return TRUE;
  }
@@@ -756,8 -531,7 +756,8 @@@ tree_update_property_action (GSignalInv
        pname = values[0].property_name;
        if (strcmp (pname, "accessible-name") == 0 ||
            strcmp (pname, "accessible-description") == 0 ||
 -          strcmp (pname, "accessible-parent") == 0)
 +          strcmp (pname, "accessible-parent") == 0 ||
 +          strcmp (pname, "accessible-role") == 0)
          {
            update_accessible (accessible);
          }
@@@ -785,6 -559,7 +785,6 @@@ tree_update_children_action (GSignalInv
        const gchar *detail = NULL;
        AtkObject *child;
  
 -      if (has_manages_descendants (accessible)) return TRUE;
        if (signal_hint->detail)
            detail = g_quark_to_string (signal_hint->detail);
  
@@@ -888,12 -663,6 +888,12 @@@ atk_dbus_initialize (AtkObject *root
    if (!ref2ptr)
      ref2ptr = g_hash_table_new(g_direct_hash, g_direct_equal);
  
 +  if (!objects_with_subrefs)
 +    objects_with_subrefs = g_hash_table_new(g_direct_hash, g_direct_equal);
 +
 +  if (!leased_refs)
 +    leased_refs = g_hash_table_new(g_direct_hash, g_direct_equal);
 +
  #ifdef SPI_ATK_DEBUG
    if (g_thread_supported ())
        g_message ("AT-SPI: Threads enabled");