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