Merge tag 'upstream/2.34.0' into tizen
[platform/upstream/at-spi2-core.git] / atspi / atspi-accessible.c
index 00bb256..b5d7616 100644 (file)
@@ -7,24 +7,82 @@
  * Copyright 2010, 2011 Novell, Inc.
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #include "atspi-private.h"
+#include "atspi-accessible-private.h"
 #include <string.h>
 
+enum {
+  REGION_CHANGED,
+  LAST_SIGNAL
+};
+
+static gboolean enable_caching = FALSE;
+static guint quark_locale;
+
+static guint atspi_accessible_signals[LAST_SIGNAL] = { 0, };
+
+static gboolean
+screen_reader_signal_watcher (GSignalInvocationHint *signal_hint,
+                              guint                  n_param_values,
+                              const GValue          *param_values,
+                              gpointer               data)
+{
+  GObject *object;
+  AtspiAccessible *accessible;
+  GSignalQuery signal_query;
+  const char *name;
+  DBusMessage *signal;
+  DBusMessageIter iter, iter_struct, iter_variant, iter_array;
+  dbus_int32_t detail1, detail2;
+  const char *detail = "";
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (ATSPI_IS_ACCESSIBLE(object), FALSE);
+
+  g_signal_query (signal_hint->signal_id, &signal_query);
+  name = signal_query.signal_name;
+  detail1 = g_value_get_int (param_values + 1);
+  detail2 = g_value_get_int (param_values + 2);
+  accessible = ATSPI_ACCESSIBLE (object);
+
+  signal = dbus_message_new_signal (ATSPI_DBUS_PATH_SCREEN_READER,
+                                    ATSPI_DBUS_INTERFACE_EVENT_SCREEN_READER,
+                                    "RegionChanged");
+  dbus_message_iter_init_append (signal, &iter);
+  dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &detail);
+  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail1);
+  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail2);
+  dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)",
+                                    &iter_variant);
+  dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
+                                    &iter_struct);
+  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &accessible->parent.app->bus_name);
+  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &accessible->parent.path);
+  dbus_message_iter_close_container (&iter_variant, &iter_struct);
+  dbus_message_iter_close_container (&iter, &iter_variant);
+  dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}",
+                                    &iter_array);
+  dbus_message_iter_close_container (&iter, &iter_array);
+  dbus_connection_send (_atspi_bus (), signal, NULL);
+  dbus_message_unref (signal);
+  return TRUE; 
+}
+
 static void
 atspi_action_interface_init (AtspiAction *action)
 {
@@ -71,6 +129,11 @@ atspi_table_interface_init (AtspiTable *table)
 }
 
 static void
+atspi_table_cell_interface_init (AtspiTableCell *cell)
+{
+}
+
+static void
 atspi_text_interface_init (AtspiText *text)
 {
 }
@@ -81,6 +144,7 @@ atspi_value_interface_init (AtspiValue *value)
 }
 
 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
+                         G_ADD_PRIVATE (AtspiAccessible)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
@@ -90,6 +154,7 @@ G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
+                         G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE_CELL, atspi_table_cell_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
 
@@ -98,12 +163,24 @@ static gint accessible_count = 0;
 #endif
 
 static void
+atspi_accessible_unref (GObject *accessible)
+{
+  if (accessible != NULL)
+    g_object_unref(accessible);
+}
+
+static void
 atspi_accessible_init (AtspiAccessible *accessible)
 {
 #ifdef DEBUG_REF_COUNTS
   accessible_count++;
-  printf("at-spi: init: %d objects\n", accessible_count);
+  g_hash_table_insert (_atspi_get_live_refs (), accessible, NULL);
+  g_print("at-spi: init: %d objects\n", accessible_count);
 #endif
+
+  accessible->priv = atspi_accessible_get_instance_private (accessible);
+
+  accessible->children = g_ptr_array_new_with_free_func (atspi_accessible_unref);
 }
 
 static void
@@ -112,39 +189,41 @@ atspi_accessible_dispose (GObject *object)
   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
   AtspiEvent e;
   AtspiAccessible *parent;
+  gint i;
 
   /* TODO: Only fire if object not already marked defunct */
   memset (&e, 0, sizeof (e));
-  e.type = "object:state-change:defunct";
+  e.type = "object:state-changed:defunct";
   e.source = accessible;
   e.detail1 = 1;
   e.detail2 = 0;
   _atspi_send_event (&e);
 
-  if (accessible->states)
+  g_clear_object (&accessible->states);
+
+  parent = accessible->accessible_parent;
+  if (parent)
   {
-    g_object_unref (accessible->states);
-    accessible->states = NULL;
+    accessible->accessible_parent = NULL;
+    if (parent->children)
+      g_ptr_array_remove (parent->children, accessible);
+    g_object_unref (parent);
   }
 
-  parent = accessible->accessible_parent;
-  if (parent && parent->children)
+  if (accessible->children) for (i = accessible->children->len - 1; i >= 0; i--)
   {
-    GList*ls = g_list_find (parent->children, accessible);
-    if(ls)
+    AtspiAccessible *child = g_ptr_array_index (accessible->children, i);
+    if (child && child->accessible_parent == accessible)
     {
-      gboolean replace = (ls == parent->children);
-      ls = g_list_remove (ls, accessible);
-      if (replace)
-        parent->children = ls;
-      g_object_unref (object);
+      child->accessible_parent = NULL;
+      g_object_unref (accessible);
     }
   }
 
-  if (parent)
+  if (accessible->children)
   {
-    g_object_unref (parent);
-    accessible->accessible_parent = NULL;
+    g_ptr_array_free (accessible->children, TRUE);
+    accessible->children = NULL;
   }
 
   G_OBJECT_CLASS (atspi_accessible_parent_class) ->dispose (object);
@@ -155,18 +234,24 @@ atspi_accessible_finalize (GObject *object)
 {
   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
 
-    g_free (accessible->description);
-    g_free (accessible->name);
+  g_free (accessible->description);
+  g_free (accessible->name);
+
   if (accessible->attributes)
     g_hash_table_unref (accessible->attributes);
 
+  if (accessible->priv->cache)
+    g_hash_table_destroy (accessible->priv->cache);
+
 #ifdef DEBUG_REF_COUNTS
   accessible_count--;
+  g_hash_table_remove (_atspi_get_live_refs (), accessible);
   g_print ("at-spi: finalize: %d objects\n", accessible_count);
 #endif
 
-  G_OBJECT_CLASS (atspi_accessible_parent_class)
-    ->finalize (object);
+  G_OBJECT_CLASS (atspi_accessible_parent_class)->finalize (object);
+
+  /* TODO: remove emission hook */
 }
 
 static void
@@ -176,138 +261,35 @@ atspi_accessible_class_init (AtspiAccessibleClass *klass)
 
   object_class->dispose = atspi_accessible_dispose;
   object_class->finalize = atspi_accessible_finalize;
-}
 
-/* TODO: Generate following from spec? */
-static const char *role_names [] =
-{
-  "invalid",
-  "accelerator label",
-  "alert",
-  "animation",
-  "arrow",
-  "calendar",
-  "canvas",
-  "check box",
-  "check menu item",
-  "color chooser",
-  "column header",
-  "combo box",
-  "dateeditor",
-  "desktop icon",
-  "desktop frame",
-  "dial",
-  "dialog",
-  "directory pane",
-  "drawing area",
-  "file chooser",
-  "filler",
-  "focus traversable",
-  "fontchooser",
-  "frame",
-  "glass pane",
-  "html container",
-  "icon",
-  "image",
-  "internal frame",
-  "label",
-  "layered pane",
-  "list",
-  "list item",
-  "menu",
-  "menu bar",
-  "menu item",
-  "option pane",
-  "page tab",
-  "page tab list",
-  "panel",
-  "password text",
-  "popup menu",
-  "progress bar",
-  "push button",
-  "radio button",
-  "radio menu item",
-  "root pane",
-  "row header",
-  "scroll bar",
-  "scroll pane",
-  "separator",
-  "slider",
-  "spin button",
-  "split pane",
-  "statusbar",
-  "table",
-  "table cell",
-  "table column header",
-  "table row header",
-  "tear off menu item",
-  "terminal",
-  "text",
-  "toggle button",
-  "tool bar",
-  "tool tip",
-  "tree",
-  "tree table",
-  "unknown",
-  "viewport",
-  "window",
-  NULL,
-  "header",
-  "footer",
-  "paragraph",
-  "ruler",
-  "application",
-  "autocomplete",
-  "editbar",
-  "embedded component",
-  "entry",
-  "chart",
-  "caption",
-  "document frame",
-  "heading",
-  "page",
-  "section",
-  "redundant object",
-  "form",
-  "link",
-  "input method window",
-  "table row",
-  "tree item",
-  "document spreadsheet",
-  "document presentation",
-  "document text",
-  "document web",
-  "document email",
-  "comment",
-  "list box",
-  "grouping",
-  "image map",
-  "notification",
-  "info bar"
-};
-
-#define MAX_ROLES (sizeof (role_names) / sizeof (char *))
-
-/**
- * atspi_role_get_name:
- * @role: an #AtspiRole object to query.
- *
- * Gets a localizable string that indicates the name of an #AtspiRole.
- * <em>DEPRECATED.</em>
- *
- * Returns: a localizable string name for an #AtspiRole enumerated type.
- **/
-gchar *
-atspi_role_get_name (AtspiRole role)
-{
-  if (role < MAX_ROLES && role_names [(int) role])
-    {
-      return g_strdup (role_names [(int) role]);
-    }
-  else
-    {
-      return g_strdup ("");
-    }
+  quark_locale = g_quark_from_string ("accessible-locale");
+
+  /**
+   * AtspiAccessible::region-changed:
+   * @atspiaccessible: the object which received the signal
+   * @arg1: an integer specifying the current offset of the text being read,
+   *        if the object is textual.
+   * @arg2: an integer specifying the ending offset of the text being read,
+   *        if the object is textual.
+   *
+   * The signal "region-changed" is emitted by a screen reader to indicate
+   * that it is now reading or tracking a new object, or, a new piece of
+   * text within an object. This allows a magnifier to gain the information
+   * needed to highlight the object that the screen reader is reading.
+   */
+  atspi_accessible_signals[REGION_CHANGED] =
+    g_signal_new ("region_changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (AtspiAccessibleClass, region_changed), 
+                 NULL, NULL,
+                 atspi_marshal_VOID__INT_INT,
+                 G_TYPE_NONE,
+                 2, G_TYPE_INT, G_TYPE_INT);
+
+  g_signal_add_emission_hook (atspi_accessible_signals[REGION_CHANGED], 0,
+                              screen_reader_signal_watcher, NULL,
+                              (GDestroyNotify) NULL);
 }
 
 /**
@@ -333,6 +315,522 @@ atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
   return g_strdup (obj->name);
 }
 
+
+/**
+ * atspi_accessible_get_unique_id:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the identificator, uniquely identifying object, or NULL if an error occured.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object
+ * or NULL on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_unique_id(AtspiAccessible *obj, GError **error)
+{
+  if (!obj) {
+    g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "argument is null");
+    return NULL;
+  }
+
+  gchar *id = NULL;
+  gchar *bus_name = atspi_accessible_get_bus_name(obj, error);
+  if (bus_name && bus_name[0]) {
+    gchar *path = atspi_accessible_get_path(obj, error);
+    if (path && path[0])
+      id = g_strdup_printf("%s:%s", bus_name, path);
+         else
+      g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get path");
+    g_free(path);
+  }
+  else
+    g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get bus name");
+  g_free(bus_name);
+  return id;
+}
+
+/**
+ * atspi_accessible_get_bus_name:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the bus name, where object belongs.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object's
+ * bus name or empty string on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_bus_name(AtspiAccessible *obj, GError **error)
+{
+  if (!obj || !obj->parent.app)
+    return g_strdup("");
+  return g_strdup (obj->parent.app->bus_name);
+}
+
+/**
+ * atspi_accessible_get_path:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the path, uniquely identifying object over its bus name.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object
+ * or empty string on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_path(AtspiAccessible *obj, GError **error)
+{
+  static const char *prefix = "/org/a11y/atspi/accessible/";
+  static int prefix_len = 27;
+
+  if (!obj)
+    return g_strdup("");
+  AtspiObject *o = ATSPI_OBJECT (obj);
+  if (!o)
+    return g_strdup("");
+  if (strncmp(o->path, prefix, prefix_len) == 0)
+    return g_strdup(o->path + prefix_len);
+  return g_strdup (o->path);
+}
+
+/**
+ * atspi_accessible_get_navigable_at_point:
+ * @root: a pointer to the #AtspiAccessible to start search from.
+ * @x: a #gint specifying the x coordinate of the point in question.
+ * @y: a #gint specifying the y coordinate of the point in question.
+ * @ctype: the coordinate system of the point (@x, @y)
+ *         (e.g. ATSPI_COORD_TYPE_WINDOW, ATSPI_COORD_TYPE_SCREEN).
+ *
+ * Finds the accessible element closest to user (highest in z-order), at a given coordinate within an #AtspiAccessible.
+ * This should be the element, that should be picked, when doing mouse click or finger tap at given coordinates.
+ *
+ * Returns: (nullable) (transfer full): a pointer to an
+ *          #AtspiAccessible descendant (of any depth) of the specified component which
+ *          contains the point (@x, @y), or NULL if no descendant contains
+ *          the point.
+ **/
+AtspiAccessible *
+atspi_accessible_get_navigable_at_point (AtspiAccessible *root,
+                                          gint x,
+                                          gint y,
+                                          AtspiCoordType ctype, GError **error)
+{
+  dbus_int32_t d_x = x, d_y = y;
+  dbus_uint32_t d_ctype = ctype;
+  DBusMessage *reply;
+  AtspiAccessible *return_value = NULL;
+  unsigned char recurse = 0;
+  DBusMessageIter iter;
+  AtspiAccessible *deputy = NULL;
+
+  g_return_val_if_fail (root != NULL, NULL);
+  do {
+    reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype);
+    // call failed, error is set, so we bail out
+    if (!reply) {
+      if (deputy) g_object_unref(deputy);
+      if (return_value) g_object_unref(return_value);
+      return NULL;
+    }
+    _ATSPI_DBUS_CHECK_SIG (reply, "(so)y(so)", NULL, NULL);
+
+    dbus_message_iter_init (reply, &iter);
+    AtspiAccessible *tmp = _atspi_dbus_return_accessible_from_iter (&iter);
+
+    unsigned char value = 0;
+    dbus_message_iter_get_basic (&iter, &value);
+    dbus_message_iter_next (&iter);
+    recurse = (value != 0);
+
+    /* keep deputy if tmp has deputy */
+    if (!deputy)
+      deputy = _atspi_dbus_return_accessible_from_iter (&iter);
+
+    dbus_message_unref(reply);
+
+    if (!tmp) {
+      if (deputy) {
+        /* TODO: need to check deputy works for return value */
+        if (return_value)
+          g_object_unref(return_value);
+        return deputy;
+      }
+      break;
+    }
+
+    if (return_value)
+      g_object_unref(return_value);
+    return_value = root = tmp;
+  } while(recurse);
+  return return_value;
+}
+
+/**
+ * atspi_accessible_get_reading_material:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets reading material
+ *
+ * Returns: reading material to be used screen-reader side. This is not stable.
+ * You have to handle all alocated memory as below on screen-reader side.
+ *
+ * AtspiAccessibleReadingMaterial *rm
+ * g_object_unref(rm->parent);
+ * g_object_unref(rm->described_by_accessible);
+ * g_hash_table_unref(rm->attributes);
+ * free(rm->name);
+ * free(rm->labeled_by_name);
+ * free(rm->text_interface_name);
+ * free(rm->localized_role_name);
+ * free(rm->description);
+ * free(rm);
+ **/
+AtspiAccessibleReadingMaterial *
+atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error)
+{
+  AtspiAccessible *parent;
+  AtspiAccessibleReadingMaterial *reading_material = NULL;
+  const char *name;
+  double current_value;
+  gint count;
+  guint64 val;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+  DBusMessageIter iter_array;
+  dbus_uint32_t role;
+  dbus_uint32_t *states;
+  dbus_int32_t index_in_parent;
+  dbus_int32_t child_count;
+  dbus_bool_t is_selected;
+
+  g_return_val_if_fail (obj != NULL, NULL);
+
+  reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetReadingMaterial", error, "");
+
+  _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausiddddsibbii(so)auiui(so)", NULL, NULL);
+
+  reading_material = calloc(1, sizeof(AtspiAccessibleReadingMaterial));
+  if (!reading_material)
+  {
+    return reading_material;
+  }
+
+  dbus_message_iter_init (reply, &iter);
+
+  /* get attributes */
+  reading_material->attributes =  _atspi_dbus_hash_from_iter (&iter);
+  dbus_message_iter_next (&iter);
+
+  /* get name */
+  dbus_message_iter_get_basic (&iter, &name);
+  reading_material->name = g_strdup (name);
+  dbus_message_iter_next (&iter);
+
+  /* get name of relation LABELED_BY */
+  dbus_message_iter_get_basic (&iter, &name);
+  reading_material->labeled_by_name = g_strdup (name);
+  dbus_message_iter_next (&iter);
+
+  /* get name of text interface */
+  dbus_message_iter_get_basic (&iter, &name);
+  reading_material->text_interface_name = g_strdup (name);
+  dbus_message_iter_next (&iter);
+
+  /* get role */
+  dbus_message_iter_get_basic (&iter, &role);
+  reading_material->role = role;
+  dbus_message_iter_next (&iter);
+
+  /* get state set */
+  dbus_message_iter_recurse (&iter, &iter_array);
+  dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
+  val = ((guint64)states [1]) << 32;
+  val += states [0];
+  reading_material->states = val;
+  dbus_message_iter_next (&iter);
+
+  /* get localized role name */
+  dbus_message_iter_get_basic (&iter, &name);
+  reading_material->localized_role_name = g_strdup (name);
+  dbus_message_iter_next (&iter);
+
+  /* get child count */
+  dbus_message_iter_get_basic (&iter, &child_count);
+  reading_material->child_count = child_count;
+  dbus_message_iter_next (&iter);
+
+  /* get current value */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->value = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get minimum increment */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->increment = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get maximum value */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->upper = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get minimum value */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->lower = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get description */
+  dbus_message_iter_get_basic (&iter, &name);
+  reading_material->description = g_strdup (name);
+  dbus_message_iter_next (&iter);
+
+  /* get index in parent */
+  dbus_message_iter_get_basic (&iter, &index_in_parent);
+  reading_material->index_in_parent = index_in_parent;
+  dbus_message_iter_next (&iter);
+
+  /* get selected in parent */
+  dbus_message_iter_get_basic (&iter, &is_selected);
+  reading_material->is_selected_in_parent = is_selected;
+  dbus_message_iter_next (&iter);
+
+  /* get has checkbox child */
+  dbus_message_iter_get_basic (&iter, &is_selected);
+  reading_material->has_checkbox_child = is_selected;
+  dbus_message_iter_next (&iter);
+
+  /* get list children count */
+  dbus_message_iter_get_basic (&iter, &child_count);
+  reading_material->list_children_count = child_count;
+  dbus_message_iter_next (&iter);
+
+  /* get first selected child index */
+  dbus_message_iter_get_basic (&iter, &index_in_parent);
+  reading_material->first_selected_child_index = index_in_parent;
+  dbus_message_iter_next (&iter);
+
+  ////////////////
+  /* get parent */
+  parent =  _atspi_dbus_return_accessible_from_iter (&iter);
+  reading_material->parent = parent;
+
+  /* parent states */
+  dbus_message_iter_recurse (&iter, &iter_array);
+  dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
+  val = ((guint64)states [1]) << 32;
+  val += states [0];
+  reading_material->parent_states = val;
+  dbus_message_iter_next (&iter);
+
+  /* get parent child count */
+  dbus_message_iter_get_basic (&iter, &child_count);
+  reading_material->parent_child_count = child_count;
+  dbus_message_iter_next (&iter);
+
+  /* get parent role */
+  dbus_message_iter_get_basic (&iter, &role);
+  reading_material->parent_role = role;
+  dbus_message_iter_next (&iter);
+
+  /* get parent selected child count */
+  dbus_message_iter_get_basic (&iter, &child_count);
+  reading_material->parent_selected_child_count = child_count;
+  dbus_message_iter_next (&iter);
+
+  ////////////////////////////////////////
+  /* get relation object - DESCRIBED_BY */
+  parent =  _atspi_dbus_return_accessible_from_iter (&iter);
+  reading_material->described_by_accessible = parent;
+
+  return reading_material;
+}
+
+/**
+ * atspi_accessible_get_default_label_info:
+ * @obj: a pointer to the #AtspiAccessible object would be window.
+ *
+ * Gets default label information
+ *
+ * Returns: default label information to be used screen-reader side.
+ * This is not stable. And this depends on toolkit side UI definition.
+ * The candidate of default label object could be changed by UI definition.
+ * You have to handle all alocated memory as below on screen-reader side.
+ *
+ * AtspiAccessibleDefaultLabelInfo *dli
+ * g_hash_table_unref(dli->attributes);
+
+ * g_object_unref(dli->obj);
+ * free(dli);
+ **/
+AtspiAccessibleDefaultLabelInfo *
+atspi_accessible_get_default_label_info (AtspiAccessible *obj, GError **error)
+{
+  AtspiAccessibleDefaultLabelInfo *default_label_info = NULL;
+  AtspiAccessible *default_label_object;
+  dbus_uint32_t role;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+
+  g_return_val_if_fail (obj != NULL, NULL);
+
+  reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetDefaultLabelInfo", error, "");
+
+  _ATSPI_DBUS_CHECK_SIG (reply, "(so)ua{ss}", NULL, NULL);
+
+  default_label_info = calloc(1, sizeof(AtspiAccessibleDefaultLabelInfo));
+  if (!default_label_info)
+  {
+    return default_label_info;
+  }
+
+  dbus_message_iter_init (reply, &iter);
+
+  default_label_object =  _atspi_dbus_return_accessible_from_iter (&iter);
+  default_label_info->obj = default_label_object;
+
+  dbus_message_iter_get_basic (&iter, &role);
+  default_label_info->role = role;
+  dbus_message_iter_next (&iter);
+
+  default_label_info->attributes =  _atspi_dbus_hash_from_iter (&iter);
+  dbus_message_iter_next (&iter);
+
+  return default_label_info;
+}
+
+static unsigned char are_objects_on_the_same_bus(AtspiAccessible *obj1, AtspiAccessible *obj2)
+{
+  const char *bus_name_1 = obj1->parent.app->bus_name;
+  const char *bus_name_2 = obj2->parent.app->bus_name;
+  return strcmp(bus_name_1, bus_name_2) == 0;
+}
+
+static unsigned char object_is_valid(AtspiAccessible *obj)
+{
+  if (!obj)
+    return 0;
+  AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
+  if (!ss)
+    return 0;
+  unsigned char valid = atspi_state_set_contains(ss, ATSPI_STATE_DEFUNCT) == 0;
+  g_object_unref(ss);
+  return valid;
+}
+
+typedef enum {
+  NEIGHBOR_SEARCH_MODE_NORMAL = 0,
+  NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
+  NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
+  NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3,
+} GetNeighborSearchMode;
+/**
+ * atspi_accessible_get_neighbor:
+ * @root: a pointer to a #AtspiAccessible, which represents current root of subtree to search
+ * @start: a pointer to the #AtspiAccessible to start search from (can be null, which means start from root)
+ * @direction: direction, in which search (forward or backward)
+ *
+ * Calculates next (or previous) accessible element in logical order or null if none found.
+ *
+ * Returns: (nullable) (transfer full): a pointer to an
+ *          #AtspiAccessible element, which is next (previous) in logical order or null if none found.
+ **/
+AtspiAccessible *
+atspi_accessible_get_neighbor (AtspiAccessible *root,
+                                          AtspiAccessible *start,
+                                          AtspiNeighborSearchDirection direction,
+                                          GError **error)
+{
+  g_return_val_if_fail (object_is_valid(root), NULL);
+  if (!object_is_valid(start))
+    start = root;
+  const char *root_path = ATSPI_OBJECT(root)->path;
+  AtspiAccessible *return_value = NULL;
+  g_object_ref(start);
+  unsigned char recurse;
+  GetNeighborSearchMode search_mode = NEIGHBOR_SEARCH_MODE_NORMAL;
+  GQueue *children_root_stack = g_queue_new();
+  DBusMessageIter iter;
+
+  while(1) {
+    const char *path = are_objects_on_the_same_bus(root, start) ? root_path : "";
+    DBusMessage *reply = _atspi_dbus_call_partial (start, atspi_interface_accessible, "GetNeighbor", error, "sii", path, (int)direction, (int)search_mode);
+    // call failed, error is set, so we bail out
+    if (!reply) break;
+
+    _ATSPI_DBUS_CHECK_SIG (reply, "(so)y", error, NULL);
+    dbus_message_iter_init (reply, &iter);
+    AtspiAccessible *ret = _atspi_dbus_return_accessible_from_iter (&iter);
+
+    unsigned char value = 0;
+    dbus_message_iter_get_basic (&iter, &value);
+    dbus_message_iter_next (&iter);
+    recurse = (value != 0);
+
+    dbus_message_unref(reply);
+
+    // got return value and request for recursive search, it means ret is on another bridge, than start
+    // thus we're recursing. should the recurse failed to find anything it will end with
+    if (ret && recurse) {
+      g_object_unref(G_OBJECT(start));
+      start = ret;
+      g_object_ref(start);
+      if (are_objects_on_the_same_bus(root, ret))
+        {
+          search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE;
+        }
+      else
+        {
+          g_queue_push_tail(children_root_stack, ret);
+          search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT;
+        }
+      continue;
+    }
+    // found the one we've been looking for
+    if (ret) {
+      g_object_unref(G_OBJECT(start));
+      return_value = ret;
+      break;
+    }
+
+    // we've stepped into different bridges previously and now we're going back to the last one
+    // and continuing search where we left
+    if (!g_queue_is_empty(children_root_stack)) {
+      g_object_unref(G_OBJECT(start));
+      start = g_queue_pop_tail(children_root_stack);
+
+      search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
+      continue;
+    }
+    // there's no more bridges to check, but we might have started from one
+    // in that case there might be bridges "below" start, which we yet have to visit
+    if (!are_objects_on_the_same_bus(root, start)) {
+      unsigned char continue_loop = 1;
+      while(continue_loop) {
+        AtspiAccessible *parent = atspi_accessible_get_parent(start, NULL);
+        continue_loop = parent ? are_objects_on_the_same_bus(start, parent) : 0;
+        g_object_unref(G_OBJECT(start));
+        start = parent;
+      }
+
+      // going up thru parents put us in weird place (we didnt meet root on the way)
+      // so we bail out
+      if (!start)
+        break;
+
+      // start object now points to different bridge and must be treated as "resume after recursing"
+      search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
+      continue;
+    }
+
+    // nothing found
+    g_object_unref(start);
+    break;
+  }
+  while(!g_queue_is_empty(children_root_stack))
+    g_object_unref(g_queue_pop_tail(children_root_stack));
+  g_queue_free(children_root_stack);
+
+  return return_value;
+}
+
 /**
  * atspi_accessible_get_description:
  * @obj: a pointer to the #AtspiAccessible object on which to operate.
@@ -366,9 +864,10 @@ const char *str_parent = "Parent";
  *
  * Gets an #AtspiAccessible object's parent container.
  *
- * Returns: (transfer full): a pointer to the #AtspiAccessible object which
- *          contains the given #AtspiAccessible instance, or NULL if the @obj
- *          has no parent container.
+ * Returns: (nullable) (transfer full): a pointer to the
+ *          #AtspiAccessible object which contains the given
+ *          #AtspiAccessible instance, or NULL if the @obj has no
+ *          parent container.
  *
  **/
 AtspiAccessible *
@@ -376,11 +875,12 @@ atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
 {
   g_return_val_if_fail (obj != NULL, NULL);
 
-  if (obj->parent.app &&
-      !_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
+  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
   {
     DBusMessage *message, *reply;
     DBusMessageIter iter, iter_variant;
+    if (!obj->parent.app)
+      return NULL;
     message = dbus_message_new_method_call (obj->parent.app->bus_name,
                                             obj->parent.path,
                                             DBUS_INTERFACE_PROPERTIES, "Get");
@@ -432,7 +932,10 @@ atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
     return ret;
   }
 
-  return g_list_length (obj->children);
+  if (!obj->children)
+    return 0;  /* assume it's disposed */
+
+  return obj->children->len;
 }
 
 /**
@@ -451,22 +954,34 @@ atspi_accessible_get_child_at_index (AtspiAccessible *obj,
                             GError **error)
 {
   AtspiAccessible *child;
+  DBusMessage *reply;
 
   g_return_val_if_fail (obj != NULL, NULL);
 
-  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
+  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
   {
-    DBusMessage *reply;
-    reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
-                                     "GetChildAtIndex", error, "i",
-                                     child_index);
-    return _atspi_dbus_return_accessible_from_message (reply);
+    if (!obj->children)
+      return NULL;     /* assume disposed */
+
+    child = g_ptr_array_index (obj->children, child_index);
+    if (child)
+      return g_object_ref (child);
   }
 
-  child = g_list_nth_data (obj->children, child_index);
+  reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
+                                   "GetChildAtIndex", error, "i", child_index);
+  child = _atspi_dbus_return_accessible_from_message (reply);
+
   if (!child)
     return NULL;
-  return g_object_ref (child);
+
+  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
+  {
+      if (child_index >= obj->children->len)
+        g_ptr_array_set_size (obj->children, child_index + 1);
+    g_ptr_array_index (obj->children, child_index) = g_object_ref (child);
+  }
+  return child;
 }
 
 /**
@@ -483,28 +998,27 @@ atspi_accessible_get_child_at_index (AtspiAccessible *obj,
 gint
 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
 {
-  GList *l;
   gint i = 0;
+  dbus_int32_t ret = -1;
 
   g_return_val_if_fail (obj != NULL, -1);
-  if (!obj->accessible_parent) return -1;
-  if (!_atspi_accessible_test_cache (obj->accessible_parent,
-                                     ATSPI_CACHE_CHILDREN))
+  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
   {
-    dbus_uint32_t ret = -1;
-    _atspi_dbus_call (obj, atspi_interface_accessible,
-                      "GetIndexInParent", NULL, "=>u", &ret);
-    return ret;
-  }
+    if (!obj->accessible_parent)
+      return -1;
 
-  l = obj->accessible_parent->children;
-  while (l)
-  {
-    if (l->data == obj) return i;
-    l = g_list_next (l);
-    i++;
+    if (!_atspi_accessible_test_cache (obj->accessible_parent, ATSPI_CACHE_CHILDREN) || !obj->accessible_parent->children)
+        goto dbus;
+
+    for (i = 0; i < obj->accessible_parent->children->len; i++)
+      if (g_ptr_array_index (obj->accessible_parent->children, i) == obj)
+        return i;
   }
-  return -1;
+
+dbus:
+  _atspi_dbus_call (obj, atspi_interface_accessible,
+                    "GetIndexInParent", NULL, "=>i", &ret);
+  return ret;
 }
 
 typedef struct
@@ -520,7 +1034,7 @@ typedef struct
  * Gets the set of #AtspiRelation objects which describes this #AtspiAccessible object's
  * relationships with other #AtspiAccessible objects.
  *
- * Returns: (element-type AtspiAccessible*) (transfer full): a #GArray of
+ * Returns: (element-type AtspiRelation*) (transfer full): a #GArray of
  *          #AtspiRelation pointers or NULL on exception.
  **/
 GArray *
@@ -594,14 +1108,14 @@ atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
 gchar *
 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
 {
-  char *retval = NULL;
+  gchar *retval = NULL;
   AtspiRole role;
 
   g_return_val_if_fail (obj != NULL, NULL);
 
   role = atspi_accessible_get_role (obj, error);
-  if (role >= 0 && role < MAX_ROLES && role != ATSPI_ROLE_EXTENDED)
-    return g_strdup (role_names [role]);
+  if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
+    return atspi_role_get_name (role);
 
   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
 
@@ -615,12 +1129,12 @@ atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
  * atspi_accessible_get_localized_role_name:
  * @obj: a pointer to the #AtspiAccessible object on which to operate.
  *
- * Gets a UTF-8 string corresponding to the name of the role played by an 
+ * Gets a UTF-8 string corresponding to the name of the role played by an
  * object, translated to the current locale.
  * This method will return useful values for roles that fall outside the
  * enumeration used in atspi_accessible_getRole ().
  *
- * Returns: a localized, UTF-8 string specifying the type of UI role played 
+ * Returns: a localized, UTF-8 string specifying the type of UI role played
  * by an #AtspiAccessible object.
  *
  **/
@@ -659,10 +1173,10 @@ defunct_set ()
 AtspiStateSet *
 atspi_accessible_get_state_set (AtspiAccessible *obj)
 {
+  /* TODO: Should take a GError **, but would be an API break */
   if (!obj->parent.app || !obj->parent.app->bus)
     return defunct_set ();
 
-
   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
   {
     DBusMessage *reply;
@@ -675,7 +1189,6 @@ atspi_accessible_get_state_set (AtspiAccessible *obj)
     dbus_message_unref (reply);
     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
   }
-
   return g_object_ref (obj->states);
 }
 
@@ -683,7 +1196,7 @@ atspi_accessible_get_state_set (AtspiAccessible *obj)
  * atspi_accessible_get_attributes:
  * @obj: The #AtspiAccessible being queried.
  *
- * Gets the #AttributeSet representing any assigned 
+ * Gets the #AttributeSet representing any assigned
  * name-value pair attributes or annotations for this object.
  * For typographic, textual, or textually-semantic attributes, see
  * atspi_text_get_attributes instead.
@@ -698,6 +1211,13 @@ atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
 
     g_return_val_if_fail (obj != NULL, NULL);
 
+  if (obj->priv->cache)
+  {
+    GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
+    if (val)
+      return g_value_dup_boxed (val);
+  }
+
   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
   {
     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
@@ -723,12 +1243,12 @@ add_to_attribute_array (gpointer key, gpointer value, gpointer data)
  * atspi_accessible_get_attributes_as_array:
  * @obj: The #AtspiAccessible being queried.
  *
- * Gets a #GArray representing any assigned 
+ * Gets a #GArray representing any assigned
  * name-value pair attributes or annotations for this object.
  * For typographic, textual, or textually-semantic attributes, see
  * atspi_text_get_attributes_as_array instead.
  *
- * Returns: (element-type GArray*) (transfer full): The name-value-pair
+ * Returns: (element-type gchar*) (transfer full): The name-value-pair
  *          attributes assigned to this object.
  */
 GArray *
@@ -738,15 +1258,16 @@ atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
 
     g_return_val_if_fail (obj != NULL, NULL);
 
-  if (_atspi_accessible_get_cache_mask (obj) & ATSPI_CACHE_ATTRIBUTES)
+  if (obj->priv->cache)
   {
-    GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
-    GHashTable *attributes = atspi_accessible_get_attributes (obj, error);
-    if (!attributes)
-      return NULL;
-    g_hash_table_foreach (attributes, add_to_attribute_array, &array);
-    g_hash_table_unref (attributes);
-    return array;
+    GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
+    if (val)
+    {
+      GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
+      GHashTable *attributes = g_value_get_boxed (val);
+      g_hash_table_foreach (attributes, add_to_attribute_array, &array);
+      return array;
+    }
   }
 
   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
@@ -788,7 +1309,11 @@ atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
     }
     if (!parent || parent == obj ||
         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
+  {
+    if (parent)
+      g_object_unref (parent);
     return obj;
+  }
     g_object_unref (obj);
     obj = parent;
   }
@@ -870,13 +1395,13 @@ atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
 }
 
 /**
- * atspi_accessible_get_toolkit_version:
+ * atspi_accessible_get_id:
  * @obj: a pointer to the #AtspiAccessible object on which to operate.
  *
  * Gets the application id for a #AtspiAccessible object.
  * Only works on application root objects.
  *
- * Returns: a positive #gint indicating the id for the #AtspiAccessible object 
+ * Returns: a positive #gint indicating the id for the #AtspiAccessible object
  * or -1 on exception.
  **/
 gint
@@ -927,7 +1452,7 @@ _atspi_accessible_is_a (AtspiAccessible *accessible,
  * atspi_accessible_is_action:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
- * Query whether the specified #AtspiAccessible implements the 
+ * Query whether the specified #AtspiAccessible implements the
  * #AtspiAction interface.
  *
  * Returns: #TRUE if @obj implements the #AtspiAction interface,
@@ -957,7 +1482,7 @@ atspi_accessible_is_application (AtspiAccessible *obj)
                              atspi_interface_application);
 }
 
-/**                      
+/**
  * atspi_accessible_is_collection:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
@@ -1023,7 +1548,7 @@ atspi_accessible_is_editable_text (AtspiAccessible *obj)
   return _atspi_accessible_is_a (obj,
                              atspi_interface_editable_text);
 }
-                                                                                                                                                                        
+
 /**
  * atspi_accessible_is_hypertext:
  * @obj: a pointer to the #AtspiAccessible instance to query.
@@ -1045,7 +1570,7 @@ atspi_accessible_is_hypertext (AtspiAccessible *obj)
  * atspi_accessible_is_hyperlink:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
- * Query whether the specified #AtspiAccessible implements the 
+ * Query whether the specified #AtspiAccessible implements the
  * #AtspiHyperlink interface.
  *
  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
@@ -1110,6 +1635,23 @@ atspi_accessible_is_table (AtspiAccessible *obj)
 }
 
 /**
+ * atspi_accessible_is_table_cell:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Query whether the specified #AtspiAccessible implements the
+ * #AtspiTableCell interface.
+ *
+ * Returns: #TRUE if @obj implements the #AtspiTable interface,
+ *          #FALSE otherwise.
+**/
+gboolean
+atspi_accessible_is_table_cell (AtspiAccessible *obj)
+{
+  return _atspi_accessible_is_a (obj,
+                             atspi_interface_table_cell);
+}
+
+/**
  * atspi_accessible_is_streamable_content:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
@@ -1135,7 +1677,7 @@ atspi_accessible_is_streamable_content (AtspiAccessible *obj)
  * atspi_accessible_is_text:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
- * Query whether the specified #AtspiAccessible implements the 
+ * Query whether the specified #AtspiAccessible implements the
  * #AtspiText interface.
  *
  * Returns: #TRUE if @obj implements the #AtspiText interface,
@@ -1166,45 +1708,83 @@ atspi_accessible_is_value (AtspiAccessible *obj)
 }
 
 /**
- * atspi_accessible_get_action:
+ * atspi_accessible_get_action: (rename-to atspi_accessible_get_action_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiAction interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiAction interface
  *          instance, or NULL if @obj does not implement #AtspiAction.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
  **/
 AtspiAction *
 atspi_accessible_get_action (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
-          g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
+          g_object_ref (ATSPI_ACTION (accessible)) : NULL);
 }
 
 /**
- * atspi_accessible_get_collection:
+ * atspi_accessible_get_action_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiAction interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiAction interface
+ *          instance, or NULL if @obj does not implement #AtspiAction.
+ **/
+AtspiAction *
+atspi_accessible_get_action_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
+          g_object_ref (ATSPI_ACTION (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_collection: (rename-to atspi_accessible_get_collection_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiCollection interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiCollection interface
  *          instance, or NULL if @obj does not implement #AtspiCollection.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
  **/
 AtspiCollection *
 atspi_accessible_get_collection (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
-          g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
+          g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
 }
 
 /**
- * atspi_accessible_get_component:
+ * atspi_accessible_get_collection_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiCollection interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiCollection interface
+ *          instance, or NULL if @obj does not implement #AtspiCollection.
+ **/
+AtspiCollection *
+atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
+          g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_component: (rename-to atspi_accessible_get_component_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiComponent interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiComponent interface
  *          instance, or NULL if @obj does not implement #AtspiComponent.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
  **/
 AtspiComponent *
 atspi_accessible_get_component (AtspiAccessible *obj)
@@ -1214,35 +1794,87 @@ atspi_accessible_get_component (AtspiAccessible *obj)
 }
 
 /**
- * atspi_accessible_get_document:
+ * atspi_accessible_get_component_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiComponent interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiComponent interface
+ *          instance, or NULL if @obj does not implement #AtspiComponent.
+ **/
+AtspiComponent *
+atspi_accessible_get_component_iface (AtspiAccessible *obj)
+{
+  return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
+          g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_document: (rename-to atspi_accessible_get_document_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiDocument interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiDocument interface
  *          instance, or NULL if @obj does not implement #AtspiDocument.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
  **/
 AtspiDocument *
 atspi_accessible_get_document (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
-          g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
+          g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_document_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiDocument interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiDocument interface
+ *          instance, or NULL if @obj does not implement #AtspiDocument.
+ **/
+AtspiDocument *
+atspi_accessible_get_document_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
+          g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
 }
 
 /**
- * atspi_accessible_get_editable_text:
+ * atspi_accessible_get_editable_text: (rename-to atspi_accessible_get_editable_text_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
  *          instance, or NULL if @obj does not implement #AtspiEditableText.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
  **/
 AtspiEditableText *
 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
-          g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
+          g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_editable_text_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiEditableText interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiEditableText interface
+ *          instance, or NULL if @obj does not implement #AtspiEditableText.
+ **/
+AtspiEditableText *
+atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
+          g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
 }
 
 /**
@@ -1262,51 +1894,105 @@ atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
 }
 
 /**
- * atspi_accessible_get_hypertext:
+ * atspi_accessible_get_hypertext: (rename-to atspi_accessible_get_hypertext_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
  *          instance, or NULL if @obj does not implement #AtspiHypertext.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
  **/
 AtspiHypertext *
 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
-          g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
+          g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
 }
 
 /**
- * atspi_accessible_get_image:
+ * atspi_accessible_get_hypertext_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiHypertext interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiHypertext interface
+ *          instance, or NULL if @obj does not implement #AtspiHypertext.
+ **/
+AtspiHypertext *
+atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
+          g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_image: (rename-to atspi_accessible_get_image_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiImage interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
  *          NULL if @obj does not implement #AtspiImage.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
  **/
 AtspiImage *
 atspi_accessible_get_image (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
-          g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
+          g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_image_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiImage interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
+ *          NULL if @obj does not implement #AtspiImage.
+ **/
+AtspiImage *
+atspi_accessible_get_image_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
+          g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
 }
 
 /**
- * atspi_accessible_get_selection:
+ * atspi_accessible_get_selection: (rename-to atspi_accessible_get_selection_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiSelection interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiSelection interface
  *          instance, or NULL if @obj does not implement #AtspiSelection.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
  **/
 AtspiSelection *
 atspi_accessible_get_selection (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
-          g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
+          g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_selection_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiSelection interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiSelection interface
+ *          instance, or NULL if @obj does not implement #AtspiSelection.
+ **/
+AtspiSelection *
+atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
+          g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
 }
 
 #if 0
@@ -1323,34 +2009,70 @@ AtspiStreamableContent *
 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
-          accessible : NULL);  
+          accessible : NULL);
 }
 #endif
 
 /**
- * atspi_accessible_get_table:
+ * atspi_accessible_get_table: (rename-to atspi_accessible_get_table_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiTable interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
  *          NULL if @obj does not implement #AtspiTable.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
  **/
 AtspiTable *
 atspi_accessible_get_table (AtspiAccessible *obj)
 {
   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
-          g_object_ref (ATSPI_TABLE (obj)) : NULL);  
+          g_object_ref (ATSPI_TABLE (obj)) : NULL);
 }
 
 /**
- * atspi_accessible_get_text:
+ * atspi_accessible_get_table_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiTable interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
+ *          NULL if @obj does not implement #AtspiTable.
+ **/
+AtspiTable *
+atspi_accessible_get_table_iface (AtspiAccessible *obj)
+{
+  return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
+          g_object_ref (ATSPI_TABLE (obj)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_table_cell:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiTableCell interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiTableCell interface instance,
+ *          or NULL if @obj does not implement #AtspiTable.
+ **/
+AtspiTableCell *
+atspi_accessible_get_table_cell (AtspiAccessible *obj)
+{
+  return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ?
+          g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_text: (rename-to atspi_accessible_get_text_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiTable interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
  *          NULL if @obj does not implement #AtspiText.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
  **/
 AtspiText *
 atspi_accessible_get_text (AtspiAccessible *obj)
@@ -1360,19 +2082,53 @@ atspi_accessible_get_text (AtspiAccessible *obj)
 }
 
 /**
- * atspi_accessible_get_value:
+ * atspi_accessible_get_text_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiTable interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
+ *          NULL if @obj does not implement #AtspiText.
+ **/
+AtspiText *
+atspi_accessible_get_text_iface (AtspiAccessible *obj)
+{
+  return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
+          g_object_ref (ATSPI_TEXT (obj)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_value: (rename-to atspi_accessible_get_value_iface)
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
  * Gets the #AtspiTable interface for an #AtspiAccessible.
  *
  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
  *          NULL if @obj does not implement #AtspiValue.
+ *
+ * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
  **/
 AtspiValue *
 atspi_accessible_get_value (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
-          g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
+          g_object_ref (ATSPI_VALUE (accessible)) : NULL);
+}
+
+/**
+ * atspi_accessible_get_value_iface:
+ * @obj: a pointer to the #AtspiAccessible instance to query.
+ *
+ * Gets the #AtspiTable interface for an #AtspiAccessible.
+ *
+ * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
+ *          NULL if @obj does not implement #AtspiValue.
+ **/
+AtspiValue *
+atspi_accessible_get_value_iface (AtspiAccessible *accessible)
+{
+  return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
+          g_object_ref (ATSPI_VALUE (accessible)) : NULL);
 }
 
 static void
@@ -1397,10 +2153,12 @@ append_const_val (GArray *array, const gchar *val)
 GArray *
 atspi_accessible_get_interfaces (AtspiAccessible *obj)
 {
-  GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
+  GArray *ret;
 
   g_return_val_if_fail (obj != NULL, NULL);
 
+  ret  = g_array_new (TRUE, TRUE, sizeof (gchar *));
+
   append_const_val (ret, "Accessible");
   if (atspi_accessible_is_action (obj))
     append_const_val (ret, "Action");
@@ -1422,6 +2180,8 @@ atspi_accessible_get_interfaces (AtspiAccessible *obj)
     append_const_val (ret, "Selection");
   if (atspi_accessible_is_table (obj))
     append_const_val (ret, "Table");
+  if (atspi_accessible_is_table_cell (obj))
+    append_const_val (ret, "TableCell");
   if (atspi_accessible_is_text (obj))
     append_const_val (ret, "Text");
   if (atspi_accessible_is_value (obj))
@@ -1429,19 +2189,12 @@ atspi_accessible_get_interfaces (AtspiAccessible *obj)
 
   return ret;
 }
-/**
- * atspi_accessible_new:
- * @app: an #AtspiApplication reference to the new objects's parent application.
- * @path: a UTF-8 string indicating the new object's parent path.
- *
- * Creates a new #AtspiAccessible object.
- * Returns: a new #AtspiAccessible object. 
- **/
+
 AtspiAccessible *
-atspi_accessible_new (AtspiApplication *app, const gchar *path)
+_atspi_accessible_new (AtspiApplication *app, const gchar *path)
 {
   AtspiAccessible *accessible;
-  
+
   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
   g_return_val_if_fail (accessible != NULL, NULL);
 
@@ -1453,10 +2206,9 @@ atspi_accessible_new (AtspiApplication *app, const gchar *path)
 
 /**
  * atspi_accessible_set_cache_mask:
- *
  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
  *             the root of an application.
- * @mask: (type int): An #AtspiCache specifying a bit mask of the types of data to cache.
+ * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
  *
  * Sets the type of data to cache for accessibles.
  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
@@ -1473,37 +2225,40 @@ atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
   g_return_if_fail (accessible->parent.app != NULL);
   g_return_if_fail (accessible == accessible->parent.app->root);
   accessible->parent.app->cache = mask;
+  enable_caching = TRUE;
 }
 
 /**
  * atspi_accessible_clear_cache:
- * @accessible: The #AtspiAccessible whose cache to clear.
+ * @obj: The #AtspiAccessible whose cache to clear.
  *
  * Clears the cached information for the given accessible and all of its
  * descendants.
  */
 void
-atspi_accessible_clear_cache (AtspiAccessible *accessible)
+atspi_accessible_clear_cache (AtspiAccessible *obj)
 {
-  GList *l;
+  gint i;
 
-  if (accessible)
+  if (obj)
   {
-    accessible->cached_properties = ATSPI_CACHE_NONE;
-    for (l = accessible->children; l; l = l->next)
-      atspi_accessible_clear_cache (l->data);
+    obj->cached_properties = ATSPI_CACHE_NONE;
+    if (obj->children)
+      for (i = 0; i < obj->children->len; i++)
+        atspi_accessible_clear_cache (g_ptr_array_index (obj->children, i));
   }
 }
 
 /**
  * atspi_accessible_get_process_id:
  * @accessible: The #AtspiAccessible to query.
+ * @error: a pointer to a %NULL #GError pointer
  *
  * Returns the process id associated with the given accessible.  Mainly
  * added for debugging; it is a shortcut to explicitly querying the
  * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
  *
- * Returns: The process ID, or -1 if defunct.
+ * Returns: The process ID or undetermined value if @error is set.
  **/
 guint
 atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
@@ -1514,7 +2269,10 @@ atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
   DBusError d_error;
 
   if (!accessible->parent.app || !accessible->parent.app->bus_name)
-    return -1;
+    {
+      g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
+      return -1;
+    }
 
   message = dbus_message_new_method_call ("org.freedesktop.DBus",
                                           "/org/freedesktop/DBus",
@@ -1526,9 +2284,17 @@ atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
   dbus_error_init (&d_error);
   reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
   dbus_message_unref (message);
-  dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
-  dbus_message_unref (reply);
-  dbus_error_free (&d_error);
+  if (reply)
+  {
+    if (!strcmp (dbus_message_get_signature (reply), "u"))
+      dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
+    dbus_message_unref (reply);
+  }
+  if (dbus_error_is_set (&d_error))
+    {
+      g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
+      dbus_error_free (&d_error);
+    }
   return pid;
 }
 
@@ -1561,7 +2327,11 @@ _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
 {
   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
   AtspiCache result = accessible->cached_properties & mask & flag;
-  return (result != 0 && atspi_main_loop && !atspi_no_cache);
+  if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
+    return FALSE;
+  return (result != 0 && (atspi_main_loop || enable_caching ||
+                          flag == ATSPI_CACHE_INTERFACES) &&
+          !atspi_no_cache);
 }
 
 void
@@ -1571,3 +2341,97 @@ _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
 
   accessible->cached_properties |= flag & mask;
 }
+
+/**
+ * atspi_accessible_get_locale:
+ * @accessible: an #AtspiAccessible
+ *
+ * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
+ * of @accessible.
+ *
+ * Since: 2.7.91
+ *
+ * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
+ *          locale of @accessible.
+ **/
+const gchar*
+atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
+{
+  gchar *locale;
+
+  g_return_val_if_fail (accessible != NULL, NULL);
+
+  locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
+  if (!locale)
+  {
+    if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
+                                   "Locale", error, "s", &locale))
+      return NULL;
+    if (locale)
+      g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
+                               g_free);
+  }
+  return locale;
+}
+
+/**
+ * atspi_accessible_get_accessible_id:
+ * @obj: an #AtspiAccessible
+ *
+ * Gets the accessible id of the accessible.  This is not meant to be presented
+ * to the user, but to be an id which is stable over application development.
+ * Typically, this is the gtkbuilder id.
+ *
+ * Since: 2.34
+ *
+ * Returns: a character string representing the accessible id of the
+ * #AtspiAccessible object or NULL on exception.
+ **/
+gchar*
+atspi_accessible_get_accessible_id (AtspiAccessible *obj, GError **error)
+{
+  gchar *accessible_id;
+
+  g_return_val_if_fail (obj != NULL, NULL);
+
+  if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
+                                "AccessibleId", error, "s", &accessible_id))
+    return NULL;
+
+  return accessible_id;
+}
+
+void
+free_value (gpointer data)
+{
+  GValue *value = data;
+
+  g_value_unset (value);
+  g_free (value);
+}
+
+GHashTable *
+_atspi_accessible_ref_cache (AtspiAccessible *accessible)
+{
+  AtspiAccessiblePrivate *priv = accessible->priv;
+
+  priv->cache_ref_count++;
+  if (priv->cache)
+    return g_hash_table_ref (priv->cache);
+  priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                       free_value);
+  return priv->cache;
+}
+
+void
+_atspi_accessible_unref_cache (AtspiAccessible *accessible)
+{
+  AtspiAccessiblePrivate *priv = accessible->priv;
+
+  if (priv->cache)
+  {
+    g_hash_table_unref (priv->cache);
+    if (--priv->cache_ref_count == 0)
+      priv->cache = NULL;
+  }
+}