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