85970d25ca1e61206236afa0e3a9fe9b503f4833
[platform/upstream/at-spi2-core.git] / atspi / atspi-accessible.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  * Copyright 2010, 2011 Novell, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "atspi-private.h"
26 #include "atspi-accessible-private.h"
27 #include <string.h>
28
29 static gboolean enable_caching = FALSE;
30 static guint quark_locale;
31
32 static void
33 atspi_action_interface_init (AtspiAction *action)
34 {
35 }
36
37 static void
38 atspi_collection_interface_init (AtspiCollection *component)
39 {
40 }
41
42 static void
43 atspi_component_interface_init (AtspiComponent *component)
44 {
45 }
46
47 static void
48 atspi_document_interface_init (AtspiDocument *document)
49 {
50 }
51
52 static void
53 atspi_editable_text_interface_init (AtspiEditableText *editable_text)
54 {
55 }
56
57 static void
58 atspi_hypertext_interface_init (AtspiHypertext *hypertext)
59 {
60 }
61
62 static void
63 atspi_image_interface_init (AtspiImage *image)
64 {
65 }
66
67 static void
68 atspi_selection_interface_init (AtspiSelection *selection)
69 {
70 }
71
72 static void
73 atspi_table_interface_init (AtspiTable *table)
74 {
75 }
76
77 static void
78 atspi_table_cell_interface_init (AtspiTableCell *cell)
79 {
80 }
81
82 static void
83 atspi_text_interface_init (AtspiText *text)
84 {
85 }
86
87 static void
88 atspi_value_interface_init (AtspiValue *value)
89 {
90 }
91
92 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
93                          G_ADD_PRIVATE (AtspiAccessible)
94                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
95                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
96                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
97                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init)
98                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init)
99                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init)
100                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
101                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
102                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
103                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE_CELL, atspi_table_cell_interface_init)
104                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
105                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
106
107 #ifdef DEBUG_REF_COUNTS
108 static gint accessible_count = 0;
109 #endif
110
111 static void
112 atspi_accessible_init (AtspiAccessible *accessible)
113 {
114 #ifdef DEBUG_REF_COUNTS
115   accessible_count++;
116   g_hash_table_insert (_atspi_get_live_refs (), accessible, NULL);
117   g_print("at-spi: init: %d objects\n", accessible_count);
118 #endif
119
120   accessible->priv = atspi_accessible_get_instance_private (accessible);
121
122   accessible->children = g_ptr_array_new_with_free_func (g_object_unref);
123 }
124
125 static void
126 atspi_accessible_dispose (GObject *object)
127 {
128   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
129   AtspiEvent e;
130   AtspiAccessible *parent;
131   gint i;
132
133   /* TODO: Only fire if object not already marked defunct */
134   memset (&e, 0, sizeof (e));
135   e.type = "object:state-changed:defunct";
136   e.source = accessible;
137   e.detail1 = 1;
138   e.detail2 = 0;
139   _atspi_send_event (&e);
140
141   g_clear_object (&accessible->states);
142
143   parent = accessible->accessible_parent;
144   if (parent)
145   {
146     accessible->accessible_parent = NULL;
147     if (parent->children)
148       g_ptr_array_remove (parent->children, accessible);
149     g_object_unref (parent);
150   }
151
152   if (accessible->children) for (i = accessible->children->len - 1; i >= 0; i--)
153   {
154     AtspiAccessible *child = g_ptr_array_index (accessible->children, i);
155     if (child && child->accessible_parent == accessible)
156     {
157       child->accessible_parent = NULL;
158       g_object_unref (accessible);
159     }
160   }
161
162   if (accessible->children)
163   {
164     g_ptr_array_free (accessible->children, TRUE);
165     accessible->children = NULL;
166   }
167
168   G_OBJECT_CLASS (atspi_accessible_parent_class) ->dispose (object);
169 }
170
171 static void
172 atspi_accessible_finalize (GObject *object)
173 {
174   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
175
176     g_free (accessible->description);
177     g_free (accessible->name);
178   if (accessible->attributes)
179     g_hash_table_unref (accessible->attributes);
180
181     if (accessible->priv->cache)
182       g_hash_table_destroy (accessible->priv->cache);
183
184 #ifdef DEBUG_REF_COUNTS
185   accessible_count--;
186   g_hash_table_remove (_atspi_get_live_refs (), accessible);
187   g_print ("at-spi: finalize: %d objects\n", accessible_count);
188 #endif
189
190   G_OBJECT_CLASS (atspi_accessible_parent_class)->finalize (object);
191 }
192
193 static void
194 atspi_accessible_class_init (AtspiAccessibleClass *klass)
195 {
196   GObjectClass *object_class = G_OBJECT_CLASS (klass);
197
198   object_class->dispose = atspi_accessible_dispose;
199   object_class->finalize = atspi_accessible_finalize;
200
201   quark_locale = g_quark_from_string ("accessible-locale");
202 }
203
204 /**
205  * atspi_accessible_get_name:
206  * @obj: a pointer to the #AtspiAccessible object on which to operate.
207  *
208  * Gets the name of an #AtspiAccessible object.
209  *
210  * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object 
211  * or NULL on exception.
212  **/
213 gchar *
214 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
215 {
216   g_return_val_if_fail (obj != NULL, g_strdup (""));
217   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME))
218   {
219     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error,
220                                    "s", &obj->name))
221       return g_strdup ("");
222     _atspi_accessible_add_cache (obj, ATSPI_CACHE_NAME);
223   }
224   return g_strdup (obj->name);
225 }
226
227 /**
228  * atspi_accessible_get_description:
229  * @obj: a pointer to the #AtspiAccessible object on which to operate.
230  *
231  * Gets the description of an #AtspiAccessible object.
232  *
233  * Returns: a UTF-8 string describing the #AtspiAccessible object 
234  * or NULL on exception.
235  **/
236 gchar *
237 atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
238 {
239   g_return_val_if_fail (obj != NULL, g_strdup (""));
240
241   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION))
242   {
243     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
244                                    "Description", error, "s",
245                                    &obj->description))
246       return g_strdup ("");
247     _atspi_accessible_add_cache (obj, ATSPI_CACHE_DESCRIPTION);
248   }
249   return g_strdup (obj->description);
250 }
251
252 const char *str_parent = "Parent";
253
254 /**
255  * atspi_accessible_get_parent:
256  * @obj: a pointer to the #AtspiAccessible object to query.
257  *
258  * Gets an #AtspiAccessible object's parent container.
259  *
260  * Returns: (nullable) (transfer full): a pointer to the
261  *          #AtspiAccessible object which contains the given
262  *          #AtspiAccessible instance, or NULL if the @obj has no
263  *          parent container.
264  *
265  **/
266 AtspiAccessible *
267 atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
268 {
269   g_return_val_if_fail (obj != NULL, NULL);
270
271   if (obj->parent.app &&
272       !_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
273   {
274     DBusMessage *message, *reply;
275     DBusMessageIter iter, iter_variant;
276     message = dbus_message_new_method_call (obj->parent.app->bus_name,
277                                             obj->parent.path,
278                                             DBUS_INTERFACE_PROPERTIES, "Get");
279     if (!message)
280       return NULL;
281     dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
282                                DBUS_TYPE_STRING, &str_parent,
283                               DBUS_TYPE_INVALID);
284     reply = _atspi_dbus_send_with_reply_and_block (message, error);
285     if (!reply)
286       return NULL;
287     if (strcmp (dbus_message_get_signature (reply), "v") != 0)
288     {
289       dbus_message_unref (reply);
290       return NULL;
291     }
292     dbus_message_iter_init (reply, &iter);
293     dbus_message_iter_recurse (&iter, &iter_variant);
294     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
295     dbus_message_unref (reply);
296     _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
297   }
298   if (!obj->accessible_parent)
299     return NULL;
300   return g_object_ref (obj->accessible_parent);
301 }
302
303 /**
304  * atspi_accessible_get_child_count:
305  * @obj: a pointer to the #AtspiAccessible object on which to operate.
306  *
307  * Gets the number of children contained by an #AtspiAccessible object.
308  *
309  * Returns: a #long indicating the number of #AtspiAccessible children
310  *          contained by an #AtspiAccessible object or -1 on exception.
311  *
312  **/
313 gint
314 atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
315 {
316   g_return_val_if_fail (obj != NULL, -1);
317
318   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
319   {
320     dbus_int32_t ret;
321     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
322                                    "ChildCount", error, "i", &ret))
323       return -1;
324     return ret;
325   }
326
327   if (!obj->children)
328     return 0;   /* assume it's disposed */
329
330   return obj->children->len;
331 }
332
333 /**
334  * atspi_accessible_get_child_at_index:
335  * @obj: a pointer to the #AtspiAccessible object on which to operate.
336  * @child_index: a #long indicating which child is specified.
337  *
338  * Gets the #AtspiAccessible child of an #AtspiAccessible object at a given index.
339  *
340  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
341  * index @child_index or NULL on exception.
342  **/
343 AtspiAccessible *
344 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
345                             gint    child_index,
346                             GError **error)
347 {
348   AtspiAccessible *child;
349   DBusMessage *reply;
350
351   g_return_val_if_fail (obj != NULL, NULL);
352
353   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
354   {
355     if (!obj->children)
356       return NULL;      /* assume disposed */
357
358     child = g_ptr_array_index (obj->children, child_index);
359     if (child)
360       return g_object_ref (child);
361   }
362
363   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
364                                    "GetChildAtIndex", error, "i", child_index);
365   child = _atspi_dbus_return_accessible_from_message (reply);
366
367   if (!child)
368     return NULL;
369
370   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
371   {
372       if (child_index >= obj->children->len)
373         g_ptr_array_set_size (obj->children, child_index + 1);
374     g_ptr_array_index (obj->children, child_index) = g_object_ref (child);
375   }
376   return child;
377 }
378
379 /**
380  * atspi_accessible_get_index_in_parent:
381  * @obj: a pointer to the #AtspiAccessible object on which to operate.
382  *
383  * Gets the index of an #AtspiAccessible object within its parent's 
384  * #AtspiAccessible children list.
385  *
386  * Returns: a #glong indicating the index of the #AtspiAccessible object
387  *          in its parent,
388  *          or -1 if @obj has no containing parent or on exception.
389  **/
390 gint
391 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
392 {
393   gint i = 0;
394   dbus_int32_t ret = -1;
395
396   g_return_val_if_fail (obj != NULL, -1);
397   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
398   {
399     if (!obj->accessible_parent)
400       return -1;
401
402     for (i = 0; i < obj->accessible_parent->children->len; i++)
403       if (g_ptr_array_index (obj->accessible_parent->children, i) == obj)
404         return i;
405   }
406
407   _atspi_dbus_call (obj, atspi_interface_accessible,
408                     "GetIndexInParent", NULL, "=>i", &ret);
409   return ret;
410 }
411
412 typedef struct
413 {
414   dbus_uint32_t type;
415   GArray *targets;
416 } Accessibility_Relation;
417
418 /**
419  * atspi_accessible_get_relation_set:
420  * @obj: a pointer to the #AtspiAccessible object on which to operate.
421  *
422  * Gets the set of #AtspiRelation objects which describes this #AtspiAccessible object's
423  * relationships with other #AtspiAccessible objects.
424  *
425  * Returns: (element-type AtspiRelation*) (transfer full): a #GArray of
426  *          #AtspiRelation pointers or NULL on exception.
427  **/
428 GArray *
429 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
430 {
431   DBusMessage *reply;
432   DBusMessageIter iter, iter_array;
433   GArray *ret;
434
435   g_return_val_if_fail (obj != NULL, NULL);
436
437   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
438   if (!reply)
439     return NULL;
440   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
441
442   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
443   dbus_message_iter_init (reply, &iter);
444   dbus_message_iter_recurse (&iter, &iter_array);
445   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
446   {
447     AtspiRelation *relation;
448     relation = _atspi_relation_new_from_iter (&iter_array);
449     ret = g_array_append_val (ret, relation);
450     dbus_message_iter_next (&iter_array);
451   }
452   dbus_message_unref (reply);
453   return ret;
454 }
455
456 /**
457  * atspi_accessible_get_role:
458  * @obj: a pointer to the #AtspiAccessible object on which to operate.
459  *
460  * Gets the UI role played by an #AtspiAccessible object.
461  * This role's name can be obtained via atspi_accessible_get_role_name ().
462  *
463  * Returns: the #AtspiRole of an #AtspiAccessible object.
464  *
465  **/
466 AtspiRole
467 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
468 {
469   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
470
471   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ROLE))
472   {
473     dbus_uint32_t role;
474     /* TODO: Make this a property */
475     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
476     {
477       obj->role = role;
478     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
479     }
480   }
481   return obj->role;
482 }
483
484 /**
485  * atspi_accessible_get_role_name:
486  * @obj: a pointer to the #AtspiAccessible object on which to operate.
487  *
488  * Gets a UTF-8 string corresponding to the name of the role played by an object.
489  * This method will return useful values for roles that fall outside the
490  * enumeration used in atspi_accessible_get_role ().
491  *
492  * Returns: a UTF-8 string specifying the type of UI role played by an
493  * #AtspiAccessible object.
494  *
495  **/
496 gchar *
497 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
498 {
499   gchar *retval = NULL;
500   AtspiRole role;
501
502   g_return_val_if_fail (obj != NULL, NULL);
503
504   role = atspi_accessible_get_role (obj, error);
505   if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
506     return atspi_role_get_name (role);
507
508   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
509
510   if (!retval)
511     retval = g_strdup ("");
512
513   return retval;
514 }
515
516 /**
517  * atspi_accessible_get_localized_role_name:
518  * @obj: a pointer to the #AtspiAccessible object on which to operate.
519  *
520  * Gets a UTF-8 string corresponding to the name of the role played by an 
521  * object, translated to the current locale.
522  * This method will return useful values for roles that fall outside the
523  * enumeration used in atspi_accessible_getRole ().
524  *
525  * Returns: a localized, UTF-8 string specifying the type of UI role played 
526  * by an #AtspiAccessible object.
527  *
528  **/
529 gchar *
530 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
531 {
532   char *retval = NULL;
533
534   g_return_val_if_fail (obj != NULL, NULL);
535
536   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
537
538   if (!retval)
539     return g_strdup ("");
540
541   return retval;
542 }
543
544 static AtspiStateSet *
545 defunct_set ()
546 {
547   AtspiStateSet *set = atspi_state_set_new (NULL);
548   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
549   return set;
550 }
551
552 /**
553  * atspi_accessible_get_state_set:
554  * @obj: a pointer to the #AtspiAccessible object on which to operate.
555  *
556  * Gets the states currently held by an object.
557  *
558  * Returns: (transfer full): a pointer to an #AtspiStateSet representing an
559  * object's current state set.
560  **/
561 AtspiStateSet *
562 atspi_accessible_get_state_set (AtspiAccessible *obj)
563 {
564   /* TODO: Should take a GError **, but would be an API break */
565   if (!obj->parent.app || !obj->parent.app->bus)
566     return defunct_set ();
567
568   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
569   {
570     DBusMessage *reply;
571     DBusMessageIter iter;
572     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
573                                       "GetState", NULL, "");
574     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
575     dbus_message_iter_init (reply, &iter);
576     _atspi_dbus_set_state (obj, &iter);
577     dbus_message_unref (reply);
578     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
579   }
580
581   return g_object_ref (obj->states);
582 }
583
584 /**
585  * atspi_accessible_get_attributes:
586  * @obj: The #AtspiAccessible being queried.
587  *
588  * Gets the #AttributeSet representing any assigned 
589  * name-value pair attributes or annotations for this object.
590  * For typographic, textual, or textually-semantic attributes, see
591  * atspi_text_get_attributes instead.
592  *
593  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
594  * attributes assigned to this object.
595  */
596 GHashTable *
597 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
598 {
599   DBusMessage *message;
600
601     g_return_val_if_fail (obj != NULL, NULL);
602
603   if (obj->priv->cache)
604   {
605     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
606     if (val)
607       return g_value_dup_boxed (val);
608   }
609
610   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
611   {
612     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
613                                         "GetAttributes", error, "");
614     obj->attributes = _atspi_dbus_return_hash_from_message (message);
615     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES);
616   }
617
618   if (!obj->attributes)
619     return NULL;
620   return g_hash_table_ref (obj->attributes);
621 }
622
623 static void
624 add_to_attribute_array (gpointer key, gpointer value, gpointer data)
625 {
626   GArray **array = (GArray **)data;
627   gchar *str = g_strconcat (key, ":", value, NULL);
628   *array = g_array_append_val (*array, str);
629 }
630
631 /**
632  * atspi_accessible_get_attributes_as_array:
633  * @obj: The #AtspiAccessible being queried.
634  *
635  * Gets a #GArray representing any assigned 
636  * name-value pair attributes or annotations for this object.
637  * For typographic, textual, or textually-semantic attributes, see
638  * atspi_text_get_attributes_as_array instead.
639  *
640  * Returns: (element-type gchar*) (transfer full): The name-value-pair
641  *          attributes assigned to this object.
642  */
643 GArray *
644 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
645 {
646   DBusMessage *message;
647
648     g_return_val_if_fail (obj != NULL, NULL);
649
650   if (obj->priv->cache)
651   {
652     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
653     if (val)
654     {
655       GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
656       GHashTable *attributes = g_value_get_boxed (val);
657       g_hash_table_foreach (attributes, add_to_attribute_array, &array);
658       return array;
659     }
660   }
661
662   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
663   return _atspi_dbus_return_attribute_array_from_message (message);
664 }
665
666 /**
667  * atspi_accessible_get_application:
668  * @obj: The #AtspiAccessible being queried.
669  *
670  * Gets the containing #AtspiApplication for an object.
671  *
672  * Returns: (transfer full): the containing #AtspiApplication instance for
673  *          this object.
674  */
675 AtspiAccessible *
676 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
677 {
678   AtspiAccessible *parent;
679
680   g_object_ref (obj);
681   for (;;)
682   {
683     parent = atspi_accessible_get_parent (obj, NULL);
684     if (!parent && obj->parent.app &&
685         atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
686     {
687       AtspiAccessible *root = g_object_ref (obj->parent.app->root);
688       if (root)
689       {
690         g_object_unref (obj);
691         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
692         {
693           g_object_unref (root);
694           return NULL;
695         }
696         return root;
697       }
698     }
699     if (!parent || parent == obj ||
700         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
701   {
702     if (parent)
703       g_object_unref (parent);
704     return obj;
705   }
706     g_object_unref (obj);
707     obj = parent;
708   }
709 }
710
711 /* Application-specific methods */
712
713 /**
714  * atspi_accessible_get_toolkit_name:
715  * @obj: a pointer to the #AtspiAccessible object on which to operate.
716  *
717  * Gets the toolkit name for an #AtspiAccessible object.
718  * Only works on application root objects.
719  *
720  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object or NULL on exception.
721  **/
722 gchar *
723 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
724 {
725   g_return_val_if_fail (obj != NULL, NULL);
726
727   if (!obj->parent.app)
728     return NULL;
729
730   if (!obj->parent.app->toolkit_name)
731     _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
732                               error, "s", &obj->parent.app->toolkit_name);
733
734   return g_strdup (obj->parent.app->toolkit_name);
735 }
736
737 /**
738  * atspi_accessible_get_toolkit_version:
739  * @obj: a pointer to the #AtspiAccessible object on which to operate.
740  *
741  * Gets the toolkit version for an #AtspiAccessible object.
742  * Only works on application root objects.
743  *
744  * Returns: a UTF-8 string indicating the toolkit version for the #AtspiAccessible object or NULL on exception.
745  **/
746 gchar *
747 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
748 {
749   g_return_val_if_fail (obj != NULL, NULL);
750
751   if (!obj->parent.app)
752     return NULL;
753
754   if (!obj->parent.app->toolkit_version)
755     _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
756                               error, "s", &obj->parent.app->toolkit_version);
757
758   return g_strdup (obj->parent.app->toolkit_version);
759 }
760
761 /**
762  * atspi_accessible_get_atspi_version:
763  * @obj: a pointer to the #AtspiAccessible object on which to operate.
764  *
765  * Gets the AT-SPI IPC specification version supported by the application
766  * pointed to by the #AtspiAccessible object.
767  * Only works on application root objects.
768  *
769  * Returns: a UTF-8 string indicating the AT-SPI version for the #AtspiAccessible object or NULL on exception.
770  **/
771 gchar *
772 atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
773 {
774   g_return_val_if_fail (obj != NULL, NULL);
775
776   if (!obj->parent.app)
777     return NULL;
778
779   if (!obj->parent.app->atspi_version)
780     _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
781                               error, "s", &obj->parent.app->atspi_version);
782
783   return g_strdup (obj->parent.app->atspi_version);
784 }
785
786 /**
787  * atspi_accessible_get_id:
788  * @obj: a pointer to the #AtspiAccessible object on which to operate.
789  *
790  * Gets the application id for a #AtspiAccessible object.
791  * Only works on application root objects.
792  *
793  * Returns: a positive #gint indicating the id for the #AtspiAccessible object 
794  * or -1 on exception.
795  **/
796 gint
797 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
798 {
799   gint ret = -1;
800
801   g_return_val_if_fail (obj != NULL, -1);
802
803   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
804       return -1;
805   return ret;
806 }
807
808
809 /* Interface query methods */
810
811 static gboolean
812 _atspi_accessible_is_a (AtspiAccessible *accessible,
813                       const char *interface_name)
814 {
815   int n;
816
817   if (accessible == NULL)
818     {
819       return FALSE;
820     }
821
822   if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
823   {
824     DBusMessage *reply;
825     DBusMessageIter iter;
826     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
827                                       "GetInterfaces", NULL, "");
828     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
829     dbus_message_iter_init (reply, &iter);
830     _atspi_dbus_set_interfaces (accessible, &iter);
831     dbus_message_unref (reply);
832     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
833   }
834
835   n = _atspi_get_iface_num (interface_name);
836   if (n == -1) return FALSE;
837   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
838 }
839
840 /**
841  * atspi_accessible_is_action:
842  * @obj: a pointer to the #AtspiAccessible instance to query.
843  *
844  * Query whether the specified #AtspiAccessible implements the 
845  * #AtspiAction interface.
846  *
847  * Returns: #TRUE if @obj implements the #AtspiAction interface,
848  *          #FALSE otherwise.
849  **/
850 gboolean
851 atspi_accessible_is_action (AtspiAccessible *obj)
852 {
853   return _atspi_accessible_is_a (obj,
854                               atspi_interface_action);
855 }
856
857 /**
858  * atspi_accessible_is_application:
859  * @obj: a pointer to the #AtspiAccessible instance to query.
860  *
861  * Query whether the specified #AtspiAccessible implements the
862  * #AtspiApplication interface.
863  *
864  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
865  *          #FALSE otherwise.
866  **/
867 gboolean
868 atspi_accessible_is_application (AtspiAccessible *obj)
869 {
870   return _atspi_accessible_is_a (obj,
871                               atspi_interface_application);
872 }
873
874 /**                      
875  * atspi_accessible_is_collection:
876  * @obj: a pointer to the #AtspiAccessible instance to query.
877  *
878  * Query whether the specified #AtspiAccessible implements the
879  * #AtspiCollection interface.
880  *
881  * Returns: #TRUE if @obj implements the #AtspiCollection interface,
882  *          #FALSE otherwise.
883  **/
884 gboolean
885 atspi_accessible_is_collection (AtspiAccessible *obj)
886 {
887      return _atspi_accessible_is_a (obj,
888                               atspi_interface_collection);
889 }
890
891 /**
892  * atspi_accessible_is_component:
893  * @obj: a pointer to the #AtspiAccessible instance to query.
894  *
895  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
896  *
897  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
898  *          #FALSE otherwise.
899  **/
900 gboolean
901 atspi_accessible_is_component (AtspiAccessible *obj)
902 {
903   return _atspi_accessible_is_a (obj,
904                               atspi_interface_component);
905 }
906
907 /**
908  * atspi_accessible_is_document:
909  * @obj: a pointer to the #AtspiAccessible instance to query.
910  *
911  * Query whether the specified #AtspiAccessible implements the
912  * #AtspiDocument interface.
913  *
914  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
915  *          #FALSE otherwise.
916  **/
917 gboolean
918 atspi_accessible_is_document (AtspiAccessible *obj)
919 {
920   return _atspi_accessible_is_a (obj,
921                               atspi_interface_document);
922 }
923
924 /**
925  * atspi_accessible_is_editable_text:
926  * @obj: a pointer to the #AtspiAccessible instance to query.
927  *
928  * Query whether the specified #AtspiAccessible implements the
929  * #AtspiEditableText interface.
930  *
931  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
932  *          #FALSE otherwise.
933  **/
934 gboolean
935 atspi_accessible_is_editable_text (AtspiAccessible *obj)
936 {
937   return _atspi_accessible_is_a (obj,
938                               atspi_interface_editable_text);
939 }
940                                                                                                                                                                         
941 /**
942  * atspi_accessible_is_hypertext:
943  * @obj: a pointer to the #AtspiAccessible instance to query.
944  *
945  * Query whether the specified #AtspiAccessible implements the
946  * #AtspiHypertext interface.
947  *
948  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
949  *          #FALSE otherwise.
950  **/
951 gboolean
952 atspi_accessible_is_hypertext (AtspiAccessible *obj)
953 {
954   return _atspi_accessible_is_a (obj,
955                               atspi_interface_hypertext);
956 }
957
958 /**
959  * atspi_accessible_is_hyperlink:
960  * @obj: a pointer to the #AtspiAccessible instance to query.
961  *
962  * Query whether the specified #AtspiAccessible implements the 
963  * #AtspiHyperlink interface.
964  *
965  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
966  *          #FALSE otherwise.
967  **/
968 gboolean
969 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
970 {
971   return _atspi_accessible_is_a (obj,
972                               atspi_interface_hyperlink);
973 }
974
975 /**
976  * atspi_accessible_is_image:
977  * @obj: a pointer to the #AtspiAccessible instance to query.
978  *
979  * Query whether the specified #AtspiAccessible implements the
980  * #AtspiImage interface.
981  *
982  * Returns: #TRUE if @obj implements the #AtspiImage interface,
983  *          #FALSE otherwise.
984 **/
985 gboolean
986 atspi_accessible_is_image (AtspiAccessible *obj)
987 {
988   return _atspi_accessible_is_a (obj,
989                               atspi_interface_image);
990 }
991
992 /**
993  * atspi_accessible_is_selection:
994  * @obj: a pointer to the #AtspiAccessible instance to query.
995  *
996  * Query whether the specified #AtspiAccessible implements the
997  * #AtspiSelection interface.
998  *
999  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
1000  *          #FALSE otherwise.
1001 **/
1002 gboolean
1003 atspi_accessible_is_selection (AtspiAccessible *obj)
1004 {
1005   return _atspi_accessible_is_a (obj,
1006                               atspi_interface_selection);
1007 }
1008
1009 /**
1010  * atspi_accessible_is_table:
1011  * @obj: a pointer to the #AtspiAccessible instance to query.
1012  *
1013  * Query whether the specified #AtspiAccessible implements the
1014  * #AtspiTable interface.
1015  *
1016  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1017  *          #FALSE otherwise.
1018 **/
1019 gboolean
1020 atspi_accessible_is_table (AtspiAccessible *obj)
1021 {
1022   return _atspi_accessible_is_a (obj,
1023                               atspi_interface_table);
1024 }
1025
1026 /**
1027  * atspi_accessible_is_table_cell:
1028  * @obj: a pointer to the #AtspiAccessible instance to query.
1029  *
1030  * Query whether the specified #AtspiAccessible implements the
1031  * #AtspiTableCell interface.
1032  *
1033  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1034  *          #FALSE otherwise.
1035 **/
1036 gboolean
1037 atspi_accessible_is_table_cell (AtspiAccessible *obj)
1038 {
1039   return _atspi_accessible_is_a (obj,
1040                               atspi_interface_table_cell);
1041 }
1042
1043 /**
1044  * atspi_accessible_is_streamable_content:
1045  * @obj: a pointer to the #AtspiAccessible instance to query.
1046  *
1047  * Query whether the specified #AtspiAccessible implements the
1048  * #AtspiStreamableContent interface.
1049  *
1050  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
1051  *          #FALSE otherwise.
1052 **/
1053 gboolean
1054 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
1055 {
1056 #if 0
1057   return _atspi_accessible_is_a (obj,
1058                               atspi_interface_streamable_content);
1059 #else
1060   g_warning ("Streamable content not implemented");
1061   return FALSE;
1062 #endif
1063 }
1064
1065 /**
1066  * atspi_accessible_is_text:
1067  * @obj: a pointer to the #AtspiAccessible instance to query.
1068  *
1069  * Query whether the specified #AtspiAccessible implements the 
1070  * #AtspiText interface.
1071  *
1072  * Returns: #TRUE if @obj implements the #AtspiText interface,
1073  *          #FALSE otherwise.
1074 **/
1075 gboolean
1076 atspi_accessible_is_text (AtspiAccessible *obj)
1077 {
1078   return _atspi_accessible_is_a (obj,
1079                               atspi_interface_text);
1080 }
1081
1082 /**
1083  * atspi_accessible_is_value:
1084  * @obj: a pointer to the #AtspiAccessible instance to query.
1085  *
1086  * Query whether the specified #AtspiAccessible implements the
1087  * #AtspiValue interface.
1088  *
1089  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1090  *          #FALSE otherwise.
1091 **/
1092 gboolean
1093 atspi_accessible_is_value (AtspiAccessible *obj)
1094 {
1095   return _atspi_accessible_is_a (obj,
1096                               atspi_interface_value);
1097 }
1098
1099 /**
1100  * atspi_accessible_get_action: (rename-to atspi_accessible_get_action_iface)
1101  * @obj: a pointer to the #AtspiAccessible instance to query.
1102  *
1103  * Gets the #AtspiAction interface for an #AtspiAccessible.
1104  *
1105  * Returns: (transfer full): a pointer to an #AtspiAction interface
1106  *          instance, or NULL if @obj does not implement #AtspiAction.
1107  *
1108  * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
1109  **/
1110 AtspiAction *
1111 atspi_accessible_get_action (AtspiAccessible *accessible)
1112 {
1113   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1114           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1115 }
1116
1117 /**
1118  * atspi_accessible_get_action_iface:
1119  * @obj: a pointer to the #AtspiAccessible instance to query.
1120  *
1121  * Gets the #AtspiAction interface for an #AtspiAccessible.
1122  *
1123  * Returns: (transfer full): a pointer to an #AtspiAction interface
1124  *          instance, or NULL if @obj does not implement #AtspiAction.
1125  **/
1126 AtspiAction *
1127 atspi_accessible_get_action_iface (AtspiAccessible *accessible)
1128 {
1129   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1130           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1131 }
1132
1133 /**
1134  * atspi_accessible_get_collection: (rename-to atspi_accessible_get_collection_iface)
1135  * @obj: a pointer to the #AtspiAccessible instance to query.
1136  *
1137  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1138  *
1139  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1140  *          instance, or NULL if @obj does not implement #AtspiCollection.
1141  *
1142  * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
1143  **/
1144 AtspiCollection *
1145 atspi_accessible_get_collection (AtspiAccessible *accessible)
1146 {
1147   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1148           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1149 }
1150
1151 /**
1152  * atspi_accessible_get_collection_iface:
1153  * @obj: a pointer to the #AtspiAccessible instance to query.
1154  *
1155  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1156  *
1157  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1158  *          instance, or NULL if @obj does not implement #AtspiCollection.
1159  **/
1160 AtspiCollection *
1161 atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
1162 {
1163   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1164           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1165 }
1166
1167 /**
1168  * atspi_accessible_get_component: (rename-to atspi_accessible_get_component_iface)
1169  * @obj: a pointer to the #AtspiAccessible instance to query.
1170  *
1171  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1172  *
1173  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1174  *          instance, or NULL if @obj does not implement #AtspiComponent.
1175  *
1176  * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
1177  **/
1178 AtspiComponent *
1179 atspi_accessible_get_component (AtspiAccessible *obj)
1180 {
1181   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1182           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1183 }
1184
1185 /**
1186  * atspi_accessible_get_component_iface:
1187  * @obj: a pointer to the #AtspiAccessible instance to query.
1188  *
1189  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1190  *
1191  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1192  *          instance, or NULL if @obj does not implement #AtspiComponent.
1193  **/
1194 AtspiComponent *
1195 atspi_accessible_get_component_iface (AtspiAccessible *obj)
1196 {
1197   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1198           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1199 }
1200
1201 /**
1202  * atspi_accessible_get_document: (rename-to atspi_accessible_get_document_iface)
1203  * @obj: a pointer to the #AtspiAccessible instance to query.
1204  *
1205  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1206  *
1207  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1208  *          instance, or NULL if @obj does not implement #AtspiDocument.
1209  *
1210  * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
1211  **/
1212 AtspiDocument *
1213 atspi_accessible_get_document (AtspiAccessible *accessible)
1214 {
1215   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1216           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1217 }
1218
1219 /**
1220  * atspi_accessible_get_document_iface:
1221  * @obj: a pointer to the #AtspiAccessible instance to query.
1222  *
1223  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1224  *
1225  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1226  *          instance, or NULL if @obj does not implement #AtspiDocument.
1227  **/
1228 AtspiDocument *
1229 atspi_accessible_get_document_iface (AtspiAccessible *accessible)
1230 {
1231   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1232           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1233 }
1234
1235 /**
1236  * atspi_accessible_get_editable_text: (rename-to atspi_accessible_get_editable_text_iface)
1237  * @obj: a pointer to the #AtspiAccessible instance to query.
1238  *
1239  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1240  *
1241  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1242  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1243  *
1244  * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
1245  **/
1246 AtspiEditableText *
1247 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1248 {
1249   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1250           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1251 }
1252
1253 /**
1254  * atspi_accessible_get_editable_text_iface:
1255  * @obj: a pointer to the #AtspiAccessible instance to query.
1256  *
1257  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1258  *
1259  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1260  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1261  **/
1262 AtspiEditableText *
1263 atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
1264 {
1265   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1266           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1267 }
1268
1269 /**
1270  * atspi_accessible_get_hyperlink:
1271  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1272  *
1273  * Gets the #AtspiHyperlink interface for an #AtspiAccessible.
1274  *
1275  * Returns: (transfer full): the #AtspiHyperlink object associated with
1276  *          the given #AtspiAccessible, or NULL if not supported.
1277  **/
1278 AtspiHyperlink *
1279 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1280 {
1281   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1282           _atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1283 }
1284
1285 /**
1286  * atspi_accessible_get_hypertext: (rename-to atspi_accessible_get_hypertext_iface)
1287  * @obj: a pointer to the #AtspiAccessible instance to query.
1288  *
1289  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1290  *
1291  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1292  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1293  *
1294  * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
1295  **/
1296 AtspiHypertext *
1297 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1298 {
1299   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1300           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1301 }
1302
1303 /**
1304  * atspi_accessible_get_hypertext_iface:
1305  * @obj: a pointer to the #AtspiAccessible instance to query.
1306  *
1307  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1308  *
1309  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1310  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1311  **/
1312 AtspiHypertext *
1313 atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
1314 {
1315   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1316           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1317 }
1318
1319 /**
1320  * atspi_accessible_get_image: (rename-to atspi_accessible_get_image_iface)
1321  * @obj: a pointer to the #AtspiAccessible instance to query.
1322  *
1323  * Gets the #AtspiImage interface for an #AtspiAccessible.
1324  *
1325  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1326  *          NULL if @obj does not implement #AtspiImage.
1327  *
1328  * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
1329  **/
1330 AtspiImage *
1331 atspi_accessible_get_image (AtspiAccessible *accessible)
1332 {
1333   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1334           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1335 }
1336
1337 /**
1338  * atspi_accessible_get_image_iface:
1339  * @obj: a pointer to the #AtspiAccessible instance to query.
1340  *
1341  * Gets the #AtspiImage interface for an #AtspiAccessible.
1342  *
1343  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1344  *          NULL if @obj does not implement #AtspiImage.
1345  **/
1346 AtspiImage *
1347 atspi_accessible_get_image_iface (AtspiAccessible *accessible)
1348 {
1349   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1350           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1351 }
1352
1353 /**
1354  * atspi_accessible_get_selection: (rename-to atspi_accessible_get_selection_iface)
1355  * @obj: a pointer to the #AtspiAccessible instance to query.
1356  *
1357  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1358  *
1359  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1360  *          instance, or NULL if @obj does not implement #AtspiSelection.
1361  *
1362  * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
1363  **/
1364 AtspiSelection *
1365 atspi_accessible_get_selection (AtspiAccessible *accessible)
1366 {
1367   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1368           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1369 }
1370
1371 /**
1372  * atspi_accessible_get_selection_iface:
1373  * @obj: a pointer to the #AtspiAccessible instance to query.
1374  *
1375  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1376  *
1377  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1378  *          instance, or NULL if @obj does not implement #AtspiSelection.
1379  **/
1380 AtspiSelection *
1381 atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
1382 {
1383   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1384           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1385 }
1386
1387 #if 0
1388 /**
1389  * atspi_accessible_get_streamable_content:
1390  * @obj: a pointer to the #AtspiAccessible instance to query.
1391  *
1392  * Gets the #AtspiStreamableContent interface for an #AtspiAccessible.
1393  *
1394  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1395  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1396  **/
1397 AtspiStreamableContent *
1398 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1399 {
1400   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1401           accessible : NULL);  
1402 }
1403 #endif
1404
1405 /**
1406  * atspi_accessible_get_table: (rename-to atspi_accessible_get_table_iface)
1407  * @obj: a pointer to the #AtspiAccessible instance to query.
1408  *
1409  * Gets the #AtspiTable interface for an #AtspiAccessible.
1410  *
1411  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1412  *          NULL if @obj does not implement #AtspiTable.
1413  *
1414  * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
1415  **/
1416 AtspiTable *
1417 atspi_accessible_get_table (AtspiAccessible *obj)
1418 {
1419   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1420           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1421 }
1422
1423 /**
1424  * atspi_accessible_get_table_iface:
1425  * @obj: a pointer to the #AtspiAccessible instance to query.
1426  *
1427  * Gets the #AtspiTable interface for an #AtspiAccessible.
1428  *
1429  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1430  *          NULL if @obj does not implement #AtspiTable.
1431  **/
1432 AtspiTable *
1433 atspi_accessible_get_table_iface (AtspiAccessible *obj)
1434 {
1435   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1436           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1437 }
1438
1439 /**
1440  * atspi_accessible_get_table_cell:
1441  * @obj: a pointer to the #AtspiAccessible instance to query.
1442  *
1443  * Gets the #AtspiTableCell interface for an #AtspiAccessible.
1444  *
1445  * Returns: (transfer full): a pointer to an #AtspiTableCell interface instance,
1446  *          or NULL if @obj does not implement #AtspiTable.
1447  **/
1448 AtspiTableCell *
1449 atspi_accessible_get_table_cell (AtspiAccessible *obj)
1450 {
1451   return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ?
1452           g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);  
1453 }
1454
1455 /**
1456  * atspi_accessible_get_text: (rename-to atspi_accessible_get_text_iface)
1457  * @obj: a pointer to the #AtspiAccessible instance to query.
1458  *
1459  * Gets the #AtspiTable interface for an #AtspiAccessible.
1460  *
1461  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1462  *          NULL if @obj does not implement #AtspiText.
1463  *
1464  * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
1465  **/
1466 AtspiText *
1467 atspi_accessible_get_text (AtspiAccessible *obj)
1468 {
1469   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1470           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1471 }
1472
1473 /**
1474  * atspi_accessible_get_text_iface:
1475  * @obj: a pointer to the #AtspiAccessible instance to query.
1476  *
1477  * Gets the #AtspiTable interface for an #AtspiAccessible.
1478  *
1479  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1480  *          NULL if @obj does not implement #AtspiText.
1481  **/
1482 AtspiText *
1483 atspi_accessible_get_text_iface (AtspiAccessible *obj)
1484 {
1485   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1486           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1487 }
1488
1489 /**
1490  * atspi_accessible_get_value: (rename-to atspi_accessible_get_value_iface)
1491  * @obj: a pointer to the #AtspiAccessible instance to query.
1492  *
1493  * Gets the #AtspiTable interface for an #AtspiAccessible.
1494  *
1495  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1496  *          NULL if @obj does not implement #AtspiValue.
1497  *
1498  * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
1499  **/
1500 AtspiValue *
1501 atspi_accessible_get_value (AtspiAccessible *accessible)
1502 {
1503   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1504           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1505 }
1506
1507 /**
1508  * atspi_accessible_get_value_iface:
1509  * @obj: a pointer to the #AtspiAccessible instance to query.
1510  *
1511  * Gets the #AtspiTable interface for an #AtspiAccessible.
1512  *
1513  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1514  *          NULL if @obj does not implement #AtspiValue.
1515  **/
1516 AtspiValue *
1517 atspi_accessible_get_value_iface (AtspiAccessible *accessible)
1518 {
1519   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1520           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1521 }
1522
1523 static void
1524 append_const_val (GArray *array, const gchar *val)
1525 {
1526   gchar *dup = g_strdup (val);
1527
1528   if (dup)
1529     g_array_append_val (array, dup);
1530 }
1531
1532 /**
1533  * atspi_accessible_get_interfaces:
1534  * @obj: The #AtspiAccessible to query.
1535  *
1536  * A set of pointers to all interfaces supported by an #AtspiAccessible.
1537  *
1538  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
1539  *          describing the interfaces supported by the object.  Interfaces are
1540  *          denoted in short-hand (i.e. "Component", "Text" etc.).
1541  **/
1542 GArray *
1543 atspi_accessible_get_interfaces (AtspiAccessible *obj)
1544 {
1545   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1546
1547   g_return_val_if_fail (obj != NULL, NULL);
1548
1549   append_const_val (ret, "Accessible");
1550   if (atspi_accessible_is_action (obj))
1551     append_const_val (ret, "Action");
1552   if (atspi_accessible_is_collection (obj))
1553     append_const_val (ret, "Collection");
1554   if (atspi_accessible_is_component (obj))
1555     append_const_val (ret, "Component");
1556   if (atspi_accessible_is_document (obj))
1557     append_const_val (ret, "Document");
1558   if (atspi_accessible_is_editable_text (obj))
1559     append_const_val (ret, "EditableText");
1560   if (atspi_accessible_is_hypertext (obj))
1561     append_const_val (ret, "Hypertext");
1562   if (atspi_accessible_is_hyperlink (obj))
1563     append_const_val (ret, "Hyperlink");
1564   if (atspi_accessible_is_image (obj))
1565     append_const_val (ret, "Image");
1566   if (atspi_accessible_is_selection (obj))
1567     append_const_val (ret, "Selection");
1568   if (atspi_accessible_is_table (obj))
1569     append_const_val (ret, "Table");
1570   if (atspi_accessible_is_table_cell (obj))
1571     append_const_val (ret, "TableCell");
1572   if (atspi_accessible_is_text (obj))
1573     append_const_val (ret, "Text");
1574   if (atspi_accessible_is_value (obj))
1575     append_const_val (ret, "Value");
1576
1577   return ret;
1578 }
1579
1580 AtspiAccessible * 
1581 _atspi_accessible_new (AtspiApplication *app, const gchar *path)
1582 {
1583   AtspiAccessible *accessible;
1584   
1585   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1586   g_return_val_if_fail (accessible != NULL, NULL);
1587
1588   accessible->parent.app = g_object_ref (app);
1589   accessible->parent.path = g_strdup (path);
1590
1591   return accessible;
1592 }
1593
1594 /**
1595  * atspi_accessible_set_cache_mask:
1596  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
1597  *             the root of an application.
1598  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
1599  *
1600  * Sets the type of data to cache for accessibles.
1601  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
1602  * then the desktop's cache flag will be used.
1603  * If the desktop's cache flag is also undefined, then all possible data will
1604  * be cached.
1605  * This function is intended to work around bugs in toolkits where the proper
1606  * events are not raised / to aid in testing for such bugs.
1607  **/
1608 void
1609 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
1610 {
1611   g_return_if_fail (accessible != NULL);
1612   g_return_if_fail (accessible->parent.app != NULL);
1613   g_return_if_fail (accessible == accessible->parent.app->root);
1614   accessible->parent.app->cache = mask;
1615   enable_caching = TRUE;
1616 }
1617
1618 /**
1619  * atspi_accessible_clear_cache:
1620  * @obj: The #AtspiAccessible whose cache to clear.
1621  *
1622  * Clears the cached information for the given accessible and all of its
1623  * descendants.
1624  */
1625 void
1626 atspi_accessible_clear_cache (AtspiAccessible *obj)
1627 {
1628   gint i;
1629
1630   if (obj)
1631   {
1632     obj->cached_properties = ATSPI_CACHE_NONE;
1633     for (i = 0; i < obj->children->len; i++)
1634       atspi_accessible_clear_cache (g_ptr_array_index (obj->children, i));
1635   }
1636 }
1637
1638 /**
1639  * atspi_accessible_get_process_id:
1640  * @accessible: The #AtspiAccessible to query.
1641  * @error: a pointer to a %NULL #GError pointer
1642  *
1643  * Returns the process id associated with the given accessible.  Mainly
1644  * added for debugging; it is a shortcut to explicitly querying the
1645  * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
1646  *
1647  * Returns: The process ID or undetermined value if @error is set.
1648  **/
1649 guint
1650 atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
1651 {
1652   DBusMessage *message, *reply;
1653   DBusConnection *bus = _atspi_bus ();
1654   dbus_uint32_t pid = -1;
1655   DBusError d_error;
1656
1657   if (!accessible->parent.app || !accessible->parent.app->bus_name)
1658     {
1659       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
1660       return -1;
1661     }
1662
1663   message = dbus_message_new_method_call ("org.freedesktop.DBus",
1664                                           "/org/freedesktop/DBus",
1665                                           "org.freedesktop.DBus",
1666                                           "GetConnectionUnixProcessID");
1667   dbus_message_append_args (message, DBUS_TYPE_STRING,
1668                             &accessible->parent.app->bus_name,
1669                             DBUS_TYPE_INVALID);
1670   dbus_error_init (&d_error);
1671   reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
1672   dbus_message_unref (message);
1673   if (reply)
1674   {
1675     if (!strcmp (dbus_message_get_signature (reply), "u"))
1676       dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
1677     dbus_message_unref (reply);
1678   }
1679   if (dbus_error_is_set (&d_error))
1680     {
1681       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
1682       dbus_error_free (&d_error);
1683     }
1684   return pid;
1685 }
1686
1687 AtspiCache
1688 _atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
1689 {
1690   AtspiCache mask;
1691
1692   if (!accessible->parent.app)
1693     return ATSPI_CACHE_NONE;
1694
1695  mask = accessible->parent.app->cache;
1696   if (mask == ATSPI_CACHE_UNDEFINED &&
1697       accessible->parent.app->root &&
1698       accessible->parent.app->root->accessible_parent)
1699   {
1700     AtspiAccessible *desktop = atspi_get_desktop (0);
1701     mask = desktop->parent.app->cache;
1702     g_object_unref (desktop);
1703   }
1704
1705   if (mask == ATSPI_CACHE_UNDEFINED)
1706     mask = ATSPI_CACHE_DEFAULT;
1707
1708   return mask;
1709 }
1710
1711 gboolean
1712 _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
1713 {
1714   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1715   AtspiCache result = accessible->cached_properties & mask & flag;
1716   if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
1717     return FALSE;
1718   return (result != 0 && (atspi_main_loop || enable_caching ||
1719                           flag == ATSPI_CACHE_INTERFACES) &&
1720           !atspi_no_cache);
1721 }
1722
1723 void
1724 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
1725 {
1726   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1727
1728   accessible->cached_properties |= flag & mask;
1729 }
1730
1731 /**
1732  * atspi_accessible_get_locale:
1733  * @accessible: an #AtspiAccessible
1734  *
1735  * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
1736  * of @accessible.
1737  *
1738  * Since: 2.7.91
1739  *
1740  * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
1741  *          locale of @accessible.
1742  **/
1743 const gchar*
1744 atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
1745 {
1746   gchar *locale;
1747
1748   g_return_val_if_fail (accessible != NULL, NULL);
1749
1750   locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
1751   if (!locale)
1752   {
1753     if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
1754                                    "Locale", error, "s", &locale))
1755       return NULL;
1756     if (locale)
1757       g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
1758                                g_free);
1759   }
1760   return locale;
1761 }
1762
1763 void
1764 free_value (gpointer data)
1765 {
1766   GValue *value = data;
1767
1768   g_value_unset (value);
1769   g_free (value);
1770 }
1771
1772 GHashTable *
1773 _atspi_accessible_ref_cache (AtspiAccessible *accessible)
1774 {
1775   AtspiAccessiblePrivate *priv = accessible->priv;
1776
1777   priv->cache_ref_count++;
1778   if (priv->cache)
1779     return g_hash_table_ref (priv->cache);
1780   priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
1781                                        free_value);
1782   return priv->cache;
1783 }
1784
1785 void
1786 _atspi_accessible_unref_cache (AtspiAccessible *accessible)
1787 {
1788   AtspiAccessiblePrivate *priv = accessible->priv;
1789
1790   if (priv->cache)
1791   {
1792     g_hash_table_unref (priv->cache);
1793     if (--priv->cache_ref_count == 0)
1794       priv->cache = NULL;
1795   }
1796 }