+
+/**
+ * atspi_accessible_set_cache_mask:
+ * @accessible: The #AtspiAccessible to operate on. Must be the desktop or
+ * the root of an application.
+ * @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,
+ * then the desktop's cache flag will be used.
+ * If the desktop's cache flag is also undefined, then all possible data will
+ * be cached.
+ * This function is intended to work around bugs in toolkits where the proper
+ * events are not raised / to aid in testing for such bugs.
+ **/
+void
+atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
+{
+ g_return_if_fail (accessible != NULL);
+ 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.
+ *
+ * Clears the cached information for the given accessible and all of its
+ * descendants.
+ */
+void
+atspi_accessible_clear_cache (AtspiAccessible *accessible)
+{
+ GList *l;
+
+ if (accessible)
+ {
+ accessible->cached_properties = ATSPI_CACHE_NONE;
+ for (l = accessible->children; l; l = l->next)
+ atspi_accessible_clear_cache (l->data);
+ }
+}
+
+/**
+ * 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 undetermined value if @error is set.
+ **/
+guint
+atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
+{
+ DBusMessage *message, *reply;
+ DBusConnection *bus = _atspi_bus ();
+ dbus_uint32_t pid = -1;
+ DBusError d_error;
+
+ if (!accessible->parent.app || !accessible->parent.app->bus_name)
+ {
+ 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",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID");
+ dbus_message_append_args (message, DBUS_TYPE_STRING,
+ &accessible->parent.app->bus_name,
+ DBUS_TYPE_INVALID);
+ dbus_error_init (&d_error);
+ reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
+ dbus_message_unref (message);
+ 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;
+}
+
+AtspiCache
+_atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
+{
+ AtspiCache mask;
+
+ if (!accessible->parent.app)
+ return ATSPI_CACHE_NONE;
+
+ mask = accessible->parent.app->cache;
+ if (mask == ATSPI_CACHE_UNDEFINED &&
+ accessible->parent.app->root &&
+ accessible->parent.app->root->accessible_parent)
+ {
+ AtspiAccessible *desktop = atspi_get_desktop (0);
+ mask = desktop->parent.app->cache;
+ g_object_unref (desktop);
+ }
+
+ if (mask == ATSPI_CACHE_UNDEFINED)
+ mask = ATSPI_CACHE_DEFAULT;
+
+ return mask;
+}
+
+gboolean
+_atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
+{
+ AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
+ AtspiCache result = accessible->cached_properties & mask & flag;
+ 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
+_atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
+{
+ AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
+
+ 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;
+}
+
+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;
+ }
+}