Enum clean-ups
[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 void
29 atspi_action_interface_init (AtspiAction *action)
30 {
31 }
32
33 static void
34 atspi_collection_interface_init (AtspiCollection *component)
35 {
36 }
37
38 static void
39 atspi_component_interface_init (AtspiComponent *component)
40 {
41 }
42
43 static void
44 atspi_document_interface_init (AtspiDocument *document)
45 {
46 }
47
48 static void
49 atspi_editable_text_interface_init (AtspiEditableText *editable_text)
50 {
51 }
52
53 static void
54 atspi_hypertext_interface_init (AtspiHypertext *hypertext)
55 {
56 }
57
58 static void
59 atspi_image_interface_init (AtspiImage *image)
60 {
61 }
62
63 static void
64 atspi_selection_interface_init (AtspiSelection *selection)
65 {
66 }
67
68 static void
69 atspi_table_interface_init (AtspiTable *table)
70 {
71 }
72
73 static void
74 atspi_text_interface_init (AtspiText *text)
75 {
76 }
77
78 static void
79 atspi_value_interface_init (AtspiValue *value)
80 {
81 }
82
83 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
84                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
85                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
86                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
87                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init)
88                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init)
89                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init)
90                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
91                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
92                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
93                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
94                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
95
96 #ifdef DEBUG_REF_COUNTS
97 static gint accessible_count = 0;
98 #endif
99
100 static void
101 atspi_accessible_init (AtspiAccessible *accessible)
102 {
103 #ifdef DEBUG_REF_COUNTS
104   accessible_count++;
105   printf("at-spi: init: %d objects\n", accessible_count);
106 #endif
107 }
108
109 static void
110 atspi_accessible_dispose (GObject *object)
111 {
112   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
113   AtspiEvent e;
114   AtspiAccessible *parent;
115
116   /* TODO: Only fire if object not already marked defunct */
117   memset (&e, 0, sizeof (e));
118   e.type = "object:state-change:defunct";
119   e.source = accessible;
120   e.detail1 = 1;
121   e.detail2 = 0;
122   _atspi_send_event (&e);
123
124   if (accessible->states)
125   {
126     g_object_unref (accessible->states);
127     accessible->states = NULL;
128   }
129
130   parent = accessible->accessible_parent;
131   if (parent && parent->children)
132   {
133     GList*ls = g_list_find (parent->children, accessible);
134     if(ls)
135     {
136       gboolean replace = (ls == parent->children);
137       ls = g_list_remove (ls, accessible);
138       if (replace)
139         parent->children = ls;
140       g_object_unref (object);
141     }
142   }
143
144   if (parent)
145   {
146     g_object_unref (parent);
147     accessible->accessible_parent = NULL;
148   }
149
150   G_OBJECT_CLASS (atspi_accessible_parent_class) ->dispose (object);
151 }
152
153 static void
154 atspi_accessible_finalize (GObject *object)
155 {
156   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
157
158     g_free (accessible->description);
159     g_free (accessible->name);
160   if (accessible->attributes)
161     g_hash_table_unref (accessible->attributes);
162
163 #ifdef DEBUG_REF_COUNTS
164   accessible_count--;
165   g_print ("at-spi: finalize: %d objects\n", accessible_count);
166 #endif
167
168   G_OBJECT_CLASS (atspi_accessible_parent_class)
169     ->finalize (object);
170 }
171
172 static void
173 atspi_accessible_class_init (AtspiAccessibleClass *klass)
174 {
175   GObjectClass *object_class = G_OBJECT_CLASS (klass);
176
177   object_class->dispose = atspi_accessible_dispose;
178   object_class->finalize = atspi_accessible_finalize;
179 }
180
181
182 /**
183  * atspi_accessible_get_name:
184  * @obj: a pointer to the #AtspiAccessible object on which to operate.
185  *
186  * Get the name of an #AtspiAccessible object.
187  *
188  * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object.
189  * or NULL on exception
190  **/
191 gchar *
192 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
193 {
194   g_return_val_if_fail (obj != NULL, g_strdup (""));
195   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME))
196   {
197     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error,
198                                    "s", &obj->name))
199       return g_strdup ("");
200     _atspi_accessible_add_cache (obj, ATSPI_CACHE_NAME);
201   }
202   return g_strdup (obj->name);
203 }
204
205 /**
206  * atspi_accessible_get_description:
207  * @obj: a pointer to the #AtspiAccessible object on which to operate.
208  *
209  * Get the description of an #AtspiAccessible object.
210  *
211  * Returns: a UTF-8 string describing the #AtspiAccessible object.
212  * or NULL on exception
213  **/
214 gchar *
215 atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
216 {
217   g_return_val_if_fail (obj != NULL, g_strdup (""));
218
219   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION))
220   {
221     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
222                                    "Description", error, "s",
223                                    &obj->description))
224       return g_strdup ("");
225     _atspi_accessible_add_cache (obj, ATSPI_CACHE_DESCRIPTION);
226   }
227   return g_strdup (obj->description);
228 }
229
230 const char *str_parent = "Parent";
231
232 /**
233  * atspi_accessible_get_parent:
234  * @obj: a pointer to the #AtspiAccessible object to query.
235  *
236  * Get an #AtspiAccessible object's parent container.
237  *
238  * Returns: (transfer full): a pointer to the #AtspiAccessible object which
239  *          contains the given #AtspiAccessible instance, or NULL if the @obj
240  *          has no parent container.
241  *
242  **/
243 AtspiAccessible *
244 atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
245 {
246   g_return_val_if_fail (obj != NULL, NULL);
247
248   if (obj->parent.app &&
249       !_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
250   {
251     DBusMessage *message, *reply;
252     DBusMessageIter iter, iter_variant;
253     message = dbus_message_new_method_call (obj->parent.app->bus_name,
254                                             obj->parent.path,
255                                             DBUS_INTERFACE_PROPERTIES, "Get");
256     if (!message)
257       return NULL;
258     dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
259                                DBUS_TYPE_STRING, &str_parent,
260                               DBUS_TYPE_INVALID);
261     reply = _atspi_dbus_send_with_reply_and_block (message, error);
262     if (!reply)
263       return NULL;
264     if (strcmp (dbus_message_get_signature (reply), "v") != 0)
265     {
266       dbus_message_unref (reply);
267       return NULL;
268     }
269     dbus_message_iter_init (reply, &iter);
270     dbus_message_iter_recurse (&iter, &iter_variant);
271     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
272     dbus_message_unref (reply);
273     _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
274   }
275   if (!obj->accessible_parent)
276     return NULL;
277   return g_object_ref (obj->accessible_parent);
278 }
279
280 /**
281  * atspi_accessible_get_child_count:
282  * @obj: a pointer to the #AtspiAccessible object on which to operate.
283  *
284  * Get the number of children contained by an #AtspiAccessible object.
285  *
286  * Returns: a #long indicating the number of #AtspiAccessible children
287  *          contained by an #AtspiAccessible object. or -1 on exception
288  *
289  **/
290 gint
291 atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
292 {
293   g_return_val_if_fail (obj != NULL, -1);
294
295   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
296   {
297     dbus_int32_t ret;
298     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
299                                    "ChildCount", error, "i", &ret))
300       return -1;
301     return ret;
302   }
303
304   return g_list_length (obj->children);
305 }
306
307 /**
308  * atspi_accessible_get_child_at_index:
309  * @obj: a pointer to the #AtspiAccessible object on which to operate.
310  * @child_index: a #long indicating which child is specified.
311  *
312  * Get the #AtspiAccessible child of an #AtspiAccessible object at a given index.
313  *
314  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
315  * index @child_index. or NULL on exception
316  **/
317 AtspiAccessible *
318 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
319                             gint    child_index,
320                             GError **error)
321 {
322   AtspiAccessible *child;
323
324   g_return_val_if_fail (obj != NULL, NULL);
325
326   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
327   {
328     DBusMessage *reply;
329     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
330                                      "GetChildAtIndex", error, "i",
331                                      child_index);
332     return _atspi_dbus_return_accessible_from_message (reply);
333   }
334
335   child = g_list_nth_data (obj->children, child_index);
336   if (!child)
337     return NULL;
338   return g_object_ref (child);
339 }
340
341 /**
342  * atspi_accessible_get_index_in_parent
343  * @obj: a pointer to the #AtspiAccessible object on which to operate.
344  *
345  * Get the index of an #AtspiAccessible object in its containing #AtspiAccessible.
346  *
347  * Returns: a #glong indicating the index of the #AtspiAccessible object
348  *          in its parent (i.e. containing) #AtspiAccessible instance,
349  *          or -1 if @obj has no containing parent or on exception.
350  **/
351 gint
352 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
353 {
354   GList *l;
355   gint i = 0;
356
357   g_return_val_if_fail (obj != NULL, -1);
358   if (!obj->accessible_parent) return -1;
359   if (!_atspi_accessible_test_cache (obj->accessible_parent,
360                                      ATSPI_CACHE_CHILDREN))
361   {
362     dbus_uint32_t ret = -1;
363     _atspi_dbus_call (obj, atspi_interface_accessible,
364                       "GetIndexInParent", NULL, "=>u", &ret);
365     return ret;
366   }
367
368   l = obj->accessible_parent->children;
369   while (l)
370   {
371     if (l->data == obj) return i;
372     l = g_list_next (l);
373     i++;
374   }
375   return -1;
376 }
377
378 typedef struct
379 {
380   dbus_uint32_t type;
381   GArray *targets;
382 } Accessibility_Relation;
383
384 /**
385  * atspi_accessible_get_relation_set:
386  * @obj: a pointer to the #AtspiAccessible object on which to operate.
387  *
388  * Get the set of #AtspiRelation objects which describe this #AtspiAccessible object's
389  *       relationships with other #AtspiAccessible objects.
390  *
391  * Returns: (element-type AtspiAccessible*) (transfer full): an array of
392  *          #AtspiAccessibleRelation pointers. or NULL on exception
393  **/
394 GArray *
395 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
396 {
397   DBusMessage *reply;
398   DBusMessageIter iter, iter_array;
399   GArray *ret;
400
401   g_return_val_if_fail (obj != NULL, NULL);
402
403   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
404   if (!reply)
405     return NULL;
406   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
407
408   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
409   dbus_message_iter_init (reply, &iter);
410   dbus_message_iter_recurse (&iter, &iter_array);
411   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
412   {
413     AtspiRelation *relation;
414     relation = _atspi_relation_new_from_iter (&iter_array);
415     ret = g_array_append_val (ret, relation);
416     dbus_message_iter_next (&iter_array);
417   }
418   dbus_message_unref (reply);
419   return ret;
420 }
421
422 /**
423  * atspi_accessible_get_role:
424  * @obj: a pointer to the #AtspiAccessible object on which to operate.
425  *
426  * Get the UI role of an #AtspiAccessible object.
427  * A UTF-8 string describing this role can be obtained via atspi_accessible_getRoleName ().
428  *
429  * Returns: the #AtspiRole of the object.
430  *
431  **/
432 AtspiRole
433 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
434 {
435   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
436
437   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ROLE))
438   {
439     dbus_uint32_t role;
440     /* TODO: Make this a property */
441     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
442     {
443       obj->role = role;
444     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
445     }
446   }
447   return obj->role;
448 }
449
450 /**
451  * atspi_accessible_get_role_name:
452  * @obj: a pointer to the #AtspiAccessible object on which to operate.
453  *
454  * Get a UTF-8 string describing the role this object plays in the UI.
455  * This method will return useful values for roles that fall outside the
456  * enumeration used in atspi_accessible_getRole ().
457  *
458  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
459  *
460  **/
461 gchar *
462 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
463 {
464   AtspiRole role = atspi_accessible_get_role (obj, error);
465   char *retval = NULL;
466   GTypeClass *type_class;
467   GEnumValue *value;
468   const gchar *name = NULL;
469
470   type_class = g_type_class_ref (ATSPI_TYPE_ROLE);
471   g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), NULL);
472
473   value = g_enum_get_value (G_ENUM_CLASS (type_class), role);
474
475   if (value)
476     {
477       retval = value->value_nick;
478     }
479
480   if (retval)
481     return g_strdup (retval);
482
483   g_return_val_if_fail (obj != NULL, NULL);
484
485   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
486
487   if (!retval)
488     retval = g_strdup ("");
489
490   return retval;
491 }
492
493 /**
494  * atspi_accessible_get_localized_role_name:
495  * @obj: a pointer to the #AtspiAccessible object on which to operate.
496  *
497  * Get a UTF-8 string describing the (localized) role this object plays in the UI.
498  * This method will return useful values for roles that fall outside the
499  * enumeration used in atspi_accessible_getRole ().
500  *
501  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
502  *
503  **/
504 gchar *
505 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
506 {
507   char *retval = NULL;
508
509   g_return_val_if_fail (obj != NULL, NULL);
510
511   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
512
513   if (!retval)
514     return g_strdup ("");
515
516   return retval;
517 }
518
519 static AtspiStateSet *
520 defunct_set ()
521 {
522   AtspiStateSet *set = atspi_state_set_new (NULL);
523   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
524   return set;
525 }
526
527 /**
528  * atspi_accessible_get_state_set:
529  * @obj: a pointer to the #AtspiAccessible object on which to operate.
530  *
531  * Gets the current state of an object.
532  *
533  * Returns: (transfer full): a pointer to an #AtspiStateSet representing the
534  *          object's current state.
535  **/
536 AtspiStateSet *
537 atspi_accessible_get_state_set (AtspiAccessible *obj)
538 {
539   if (!obj->parent.app || !obj->parent.app->bus)
540     return defunct_set ();
541
542
543   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
544   {
545     DBusMessage *reply;
546     DBusMessageIter iter;
547     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
548                                       "GetState", NULL, "");
549     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
550     dbus_message_iter_init (reply, &iter);
551     _atspi_dbus_set_state (obj, &iter);
552     dbus_message_unref (reply);
553     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
554   }
555
556   return g_object_ref (obj->states);
557 }
558
559 /**
560  * atspi_accessible_get_attributes:
561  * @obj: The #AtspiAccessible being queried.
562  *
563  * Get the #AttributeSet representing any assigned 
564  * name-value pair attributes or annotations for this object.
565  * For typographic, textual, or textually-semantic attributes, see
566  * atspi_text_get_attributes instead.
567  *
568  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
569  *          attributes assigned to this object.
570  */
571 GHashTable *
572 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
573 {
574   DBusMessage *message;
575
576     g_return_val_if_fail (obj != NULL, NULL);
577
578   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
579   {
580     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
581                                         "GetAttributes", error, "");
582     obj->attributes = _atspi_dbus_return_hash_from_message (message);
583     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES);
584   }
585
586   if (!obj->attributes)
587     return NULL;
588   return g_hash_table_ref (obj->attributes);
589 }
590
591 static void
592 add_to_attribute_array (gpointer key, gpointer value, gpointer data)
593 {
594   GArray **array = (GArray **)data;
595   gchar *str = g_strconcat (key, ":", value, NULL);
596   *array = g_array_append_val (*array, str);
597 }
598
599 /**
600  * atspi_accessible_get_attributes_as_array:
601  * @obj: The #AtspiAccessible being queried.
602  *
603  * Get the #AttributeSet representing any assigned 
604  * name-value pair attributes or annotations for this object.
605  * For typographic, textual, or textually-semantic attributes, see
606  * atspi_text_get_attributes_as_array instead.
607  *
608  * Returns: (element-type gchar*) (transfer full): The name-value-pair
609  *          attributes assigned to this object.
610  */
611 GArray *
612 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
613 {
614   DBusMessage *message;
615
616     g_return_val_if_fail (obj != NULL, NULL);
617
618   if (_atspi_accessible_get_cache_mask (obj) & ATSPI_CACHE_ATTRIBUTES)
619   {
620     GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
621     GHashTable *attributes = atspi_accessible_get_attributes (obj, error);
622     if (!attributes)
623       return NULL;
624     g_hash_table_foreach (attributes, add_to_attribute_array, &array);
625     g_hash_table_unref (attributes);
626     return array;
627   }
628
629   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
630   return _atspi_dbus_return_attribute_array_from_message (message);
631 }
632
633 /**
634  * atspi_accessible_get_application:
635  * @obj: The #AtspiAccessible being queried.
636  *
637  * Get the containing #AtspiApplication for an object.
638  *
639  * Returns: (transfer full): the containing AtspiApplication instance for
640  *          this object.
641  */
642 AtspiAccessible *
643 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
644 {
645   AtspiAccessible *parent;
646
647   g_object_ref (obj);
648   for (;;)
649   {
650     parent = atspi_accessible_get_parent (obj, NULL);
651     if (!parent && obj->parent.app &&
652         atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
653     {
654       AtspiAccessible *root = g_object_ref (obj->parent.app->root);
655       if (root)
656       {
657         g_object_unref (obj);
658         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
659         {
660           g_object_unref (root);
661           return NULL;
662         }
663         return root;
664       }
665     }
666     if (!parent || parent == obj ||
667         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
668     return obj;
669     g_object_unref (obj);
670     obj = parent;
671   }
672 }
673
674 /* Application-specific methods */
675
676 /**
677  * atspi_accessible_get_toolkit_name:
678  * @obj: a pointer to the #AtspiAccessible object on which to operate.
679  *
680  * Get the toolkit for a #AtspiAccessible object.
681  * Only works on application root objects.
682  *
683  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object.
684  * or NULL on exception
685  **/
686 gchar *
687 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
688 {
689   g_return_val_if_fail (obj != NULL, NULL);
690
691   if (!obj->parent.app)
692     return NULL;
693
694   if (!obj->parent.app->toolkit_name)
695     _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
696                               error, "s", &obj->parent.app->toolkit_name);
697
698   return g_strdup (obj->parent.app->toolkit_name);
699 }
700
701 /**
702  * atspi_accessible_get_toolkit_version:
703  * @obj: a pointer to the #AtspiAccessible object on which to operate.
704  *
705  * Get the toolkit version for a #AtspiAccessible object.
706  * Only works on application root objects.
707  *
708  * Returns: a UTF-8 string indicating the toolkit ersion for the #AtspiAccessible object.
709  * or NULL on exception
710  **/
711 gchar *
712 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
713 {
714   g_return_val_if_fail (obj != NULL, NULL);
715
716   if (!obj->parent.app)
717     return NULL;
718
719   if (!obj->parent.app->toolkit_version)
720     _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
721                               error, "s", &obj->parent.app->toolkit_version);
722
723   return g_strdup (obj->parent.app->toolkit_version);
724 }
725
726 /**
727  * atspi_accessible_get_atspi_version:
728  * @obj: a pointer to the #AtspiAccessible object on which to operate.
729  *
730  * Get the AT-SPI IPC specification version supported by the application
731  * pointed to by the #AtspiAccessible object.
732  * Only works on application root objects.
733  *
734  * Returns: a UTF-8 string indicating the AT-SPI ersion for the #AtspiAccessible object.
735  * or NULL on exception
736  **/
737 gchar *
738 atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
739 {
740   g_return_val_if_fail (obj != NULL, NULL);
741
742   if (!obj->parent.app)
743     return NULL;
744
745   if (!obj->parent.app->atspi_version)
746     _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
747                               error, "s", &obj->parent.app->atspi_version);
748
749   return g_strdup (obj->parent.app->atspi_version);
750 }
751
752 /**
753  * atspi_accessible_get_toolkit_version:
754  * @obj: a pointer to the #AtspiAccessible object on which to operate.
755  *
756  * Get the application id for a #AtspiAccessible object.
757  * Only works on application root objects.
758  *
759  * Returns: a gint indicating the id for the #AtspiAccessible object.
760  * or -1 on exception
761  **/
762 gint
763 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
764 {
765   gint ret = -1;
766
767   g_return_val_if_fail (obj != NULL, -1);
768
769   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
770       return -1;
771   return ret;
772 }
773
774
775 /* Interface query methods */
776
777 static gboolean
778 _atspi_accessible_is_a (AtspiAccessible *accessible,
779                       const char *interface_name)
780 {
781   int n;
782
783   if (accessible == NULL)
784     {
785       return FALSE;
786     }
787
788   if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
789   {
790     DBusMessage *reply;
791     DBusMessageIter iter;
792     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
793                                       "GetInterfaces", NULL, "");
794     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
795     dbus_message_iter_init (reply, &iter);
796     _atspi_dbus_set_interfaces (accessible, &iter);
797     dbus_message_unref (reply);
798     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
799   }
800
801   n = _atspi_get_iface_num (interface_name);
802   if (n == -1) return FALSE;
803   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
804 }
805
806 /**
807  * atspi_accessible_is_action:
808  * @obj: a pointer to the #AtspiAccessible instance to query.
809  *
810  * Query whether the specified #AtspiAccessible implements #AtspiAction.
811  *
812  * Returns: #TRUE if @obj implements the #AtspiAction interface,
813  *          #FALSE otherwise.
814  **/
815 gboolean
816 atspi_accessible_is_action (AtspiAccessible *obj)
817 {
818   return _atspi_accessible_is_a (obj,
819                               atspi_interface_action);
820 }
821
822 /**
823  * atspi_accessible_is_application:
824  * @obj: a pointer to the #AtspiAccessible instance to query.
825  *
826  * Query whether the specified #AtspiAccessible implements #AtspiApplication.
827  *
828  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
829  *          #FALSE otherwise.
830  **/
831 gboolean
832 atspi_accessible_is_application (AtspiAccessible *obj)
833 {
834   return _atspi_accessible_is_a (obj,
835                               atspi_interface_application);
836 }
837
838 /**                      
839  * atspi_accessible_is_collection:                                                                                                                                                                          * @obj: a pointer to the #AtspiAccessible instance to query.                                                                                                                                          
840  *                          
841  * Query whether the specified #AtspiAccessible implements #AtspiCollection.    
842  * Returns: #TRUE if @obj implements the #AtspiCollection interface,                                                                                                               
843  *          #FALSE otherwise.
844  **/
845 gboolean
846 atspi_accessible_is_collection (AtspiAccessible *obj)
847 {
848      return _atspi_accessible_is_a (obj,
849                               atspi_interface_collection);
850 }
851
852 /**
853  * atspi_accessible_is_component:
854  * @obj: a pointer to the #AtspiAccessible instance to query.
855  *
856  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
857  *
858  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
859  *          #FALSE otherwise.
860  **/
861 gboolean
862 atspi_accessible_is_component (AtspiAccessible *obj)
863 {
864   return _atspi_accessible_is_a (obj,
865                               atspi_interface_component);
866 }
867
868 /**
869  * atspi_accessible_is_document:
870  * @obj: a pointer to the #AtspiAccessible instance to query.
871  *
872  * Query whether the specified #AtspiAccessible implements #AtspiDocument.
873  *
874  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
875  *          #FALSE otherwise.
876  **/
877 gboolean
878 atspi_accessible_is_document (AtspiAccessible *obj)
879 {
880   return _atspi_accessible_is_a (obj,
881                               atspi_interface_document);
882 }
883
884 /**
885  * atspi_accessible_is_editable_text:
886  * @obj: a pointer to the #AtspiAccessible instance to query.
887  *
888  * Query whether the specified #AtspiAccessible implements #AtspiEditableText.
889  *
890  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
891  *          #FALSE otherwise.
892  **/
893 gboolean
894 atspi_accessible_is_editable_text (AtspiAccessible *obj)
895 {
896   return _atspi_accessible_is_a (obj,
897                               atspi_interface_editable_text);
898 }
899                                                                                                                                                                         
900 /**
901  * atspi_accessible_is_hypertext:
902  * @obj: a pointer to the #AtspiAccessible instance to query.
903  *
904  * Query whether the specified #AtspiAccessible implements #AtspiHypertext.
905  *
906  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
907  *          #FALSE otherwise.
908  **/
909 gboolean
910 atspi_accessible_is_hypertext (AtspiAccessible *obj)
911 {
912   return _atspi_accessible_is_a (obj,
913                               atspi_interface_hypertext);
914 }
915
916 /**
917  * atspi_accessible_is_hyperlink:
918  * @obj: a pointer to the #AtspiAccessible instance to query.
919  *
920  * Query whether the specified #AtspiAccessible implements #AtspiHyperlink.
921  *
922  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
923  *          #FALSE otherwise.
924  **/
925 gboolean
926 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
927 {
928   return _atspi_accessible_is_a (obj,
929                               atspi_interface_hyperlink);
930 }
931
932 /**
933  * atspi_accessible_is_image:
934  * @obj: a pointer to the #AtspiAccessible instance to query.
935  *
936  * Query whether the specified #AtspiAccessible implements #AtspiImage.
937  *
938  * Returns: #TRUE if @obj implements the #AtspiImage interface,
939  *          #FALSE otherwise.
940 **/
941 gboolean
942 atspi_accessible_is_image (AtspiAccessible *obj)
943 {
944   return _atspi_accessible_is_a (obj,
945                               atspi_interface_image);
946 }
947
948 /**
949  * atspi_accessible_is_selection:
950  * @obj: a pointer to the #AtspiAccessible instance to query.
951  *
952  * Query whether the specified #AtspiAccessible implements #AtspiSelection.
953  *
954  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
955  *          #FALSE otherwise.
956 **/
957 gboolean
958 atspi_accessible_is_selection (AtspiAccessible *obj)
959 {
960   return _atspi_accessible_is_a (obj,
961                               atspi_interface_selection);
962 }
963
964 /**
965  * atspi_accessible_is_table:
966  * @obj: a pointer to the #AtspiAccessible instance to query.
967  *
968  * Query whether the specified #AtspiAccessible implements #AtspiTable.
969  *
970  * Returns: #TRUE if @obj implements the #AtspiTable interface,
971  *          #FALSE otherwise.
972 **/
973 gboolean
974 atspi_accessible_is_table (AtspiAccessible *obj)
975 {
976   return _atspi_accessible_is_a (obj,
977                               atspi_interface_table);
978 }
979
980 /**
981  * atspi_accessible_is_streamable_content:
982  * @obj: a pointer to the #AtspiAccessible instance to query.
983  *
984  * Query whether the specified #AtspiAccessible implements
985  *          #AtspiStreamableContent.
986  *
987  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
988  *          #FALSE otherwise.
989 **/
990 gboolean
991 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
992 {
993 #if 0
994   return _atspi_accessible_is_a (obj,
995                               atspi_interface_streamable_content);
996 #else
997   g_warning ("Streamable content not implemented");
998   return FALSE;
999 #endif
1000 }
1001
1002 /**
1003  * atspi_accessible_is_text:
1004  * @obj: a pointer to the #AtspiAccessible instance to query.
1005  *
1006  * Query whether the specified #AtspiAccessible implements #AtspiText.
1007  *
1008  * Returns: #TRUE if @obj implements the #AtspiText interface,
1009  *          #FALSE otherwise.
1010 **/
1011 gboolean
1012 atspi_accessible_is_text (AtspiAccessible *obj)
1013 {
1014   return _atspi_accessible_is_a (obj,
1015                               atspi_interface_text);
1016 }
1017
1018 /**
1019  * atspi_accessible_is_value:
1020  * @obj: a pointer to the #AtspiAccessible instance to query.
1021  *
1022  * Query whether the specified #AtspiAccessible implements #AtspiValue.
1023  *
1024  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1025  *          #FALSE otherwise.
1026 **/
1027 gboolean
1028 atspi_accessible_is_value (AtspiAccessible *obj)
1029 {
1030   return _atspi_accessible_is_a (obj,
1031                               atspi_interface_value);
1032 }
1033
1034 /**
1035  * atspi_accessible_get_action:
1036  * @obj: a pointer to the #AtspiAccessible instance to query.
1037  *
1038  * Get the #AtspiAction interface for an #AtspiAccessible.
1039  *
1040  * Returns: (transfer full): a pointer to an #AtspiAction interface
1041  *          instance, or NULL if @obj does not implement #AtspiAction.
1042  **/
1043 AtspiAction *
1044 atspi_accessible_get_action (AtspiAccessible *accessible)
1045 {
1046   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1047           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1048 }
1049
1050 /**
1051  * atspi_accessible_get_collection:
1052  * @obj: a pointer to the #AtspiAccessible instance to query.
1053  *
1054  * Get the #AtspiCollection interface for an #AtspiAccessible.
1055  *
1056  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1057  *          instance, or NULL if @obj does not implement #AtspiCollection.
1058  **/
1059 AtspiCollection *
1060 atspi_accessible_get_collection (AtspiAccessible *accessible)
1061 {
1062   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1063           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1064 }
1065
1066 /**
1067  * atspi_accessible_get_component:
1068  * @obj: a pointer to the #AtspiAccessible instance to query.
1069  *
1070  * Get the #AtspiComponent interface for an #AtspiAccessible.
1071  *
1072  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1073  *          instance, or NULL if @obj does not implement #AtspiComponent.
1074  **/
1075 AtspiComponent *
1076 atspi_accessible_get_component (AtspiAccessible *obj)
1077 {
1078   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1079           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1080 }
1081
1082 /**
1083  * atspi_accessible_get_document:
1084  * @obj: a pointer to the #AtspiAccessible instance to query.
1085  *
1086  * Get the #AtspiDocument interface for an #AtspiAccessible.
1087  *
1088  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1089  *          instance, or NULL if @obj does not implement #AtspiDocument.
1090  **/
1091 AtspiDocument *
1092 atspi_accessible_get_document (AtspiAccessible *accessible)
1093 {
1094   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1095           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1096 }
1097
1098 /**
1099  * atspi_accessible_get_editable_text:
1100  * @obj: a pointer to the #AtspiAccessible instance to query.
1101  *
1102  * Get the #AtspiEditableText interface for an #AtspiAccessible.
1103  *
1104  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1105  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1106  **/
1107 AtspiEditableText *
1108 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1109 {
1110   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1111           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1112 }
1113
1114 /**
1115  * atspi_accessible_get_hyperlink:
1116  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1117  *
1118  * Get the #AtspiHyperlink associated with the given #AtspiAccessible, if
1119  * supported.
1120  *
1121  * Returns: (transfer full): the #AtspiHyperlink object associated with
1122  *          the given #AtspiAccessible, or NULL if not supported.
1123  **/
1124 AtspiHyperlink *
1125 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1126 {
1127   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1128           atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1129 }
1130
1131 /**
1132  * atspi_accessible_get_hypertext:
1133  * @obj: a pointer to the #AtspiAccessible instance to query.
1134  *
1135  * Get the #AtspiHypertext interface for an #AtspiAccessible.
1136  *
1137  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1138  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1139  **/
1140 AtspiHypertext *
1141 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1142 {
1143   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1144           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1145 }
1146
1147 /**
1148  * atspi_accessible_get_image:
1149  * @obj: a pointer to the #AtspiAccessible instance to query.
1150  *
1151  * Get the #AtspiImage interface for an #AtspiAccessible.
1152  *
1153  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1154  *          NULL if @obj does not implement #AtspiImage.
1155  **/
1156 AtspiImage *
1157 atspi_accessible_get_image (AtspiAccessible *accessible)
1158 {
1159   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1160           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1161 }
1162
1163 /**
1164  * atspi_accessible_get_selection:
1165  * @obj: a pointer to the #AtspiAccessible instance to query.
1166  *
1167  * Get the #AtspiSelection interface for an #AtspiAccessible.
1168  *
1169  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1170  *          instance, or NULL if @obj does not implement #AtspiSelection.
1171  **/
1172 AtspiSelection *
1173 atspi_accessible_get_selection (AtspiAccessible *accessible)
1174 {
1175   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1176           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1177 }
1178
1179 #if 0
1180 /**
1181  * atspi_accessible_get_streamable_content:
1182  * @obj: a pointer to the #AtspiAccessible instance to query.
1183  *
1184  * Get the #AtspiStreamableContent interface for an #AtspiAccessible.
1185  *
1186  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1187  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1188  **/
1189 AtspiStreamableContent *
1190 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1191 {
1192   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1193           accessible : NULL);  
1194 }
1195 #endif
1196
1197 /**
1198  * atspi_accessible_get_table:
1199  * @obj: a pointer to the #AtspiAccessible instance to query.
1200  *
1201  * Get the #AtspiTable interface for an #AtspiAccessible.
1202  *
1203  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1204  *          NULL if @obj does not implement #AtspiTable.
1205  **/
1206 AtspiTable *
1207 atspi_accessible_get_table (AtspiAccessible *obj)
1208 {
1209   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1210           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1211 }
1212
1213 /**
1214  * atspi_accessible_get_text:
1215  * @obj: a pointer to the #AtspiAccessible instance to query.
1216  *
1217  * Get the #AtspiTable interface for an #AtspiAccessible.
1218  *
1219  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1220  *          NULL if @obj does not implement #AtspiText.
1221  **/
1222 AtspiText *
1223 atspi_accessible_get_text (AtspiAccessible *obj)
1224 {
1225   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1226           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1227 }
1228
1229 /**
1230  * atspi_accessible_get_value:
1231  * @obj: a pointer to the #AtspiAccessible instance to query.
1232  *
1233  * Get the #AtspiTable interface for an #AtspiAccessible.
1234  *
1235  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1236  *          NULL if @obj does not implement #AtspiValue.
1237  **/
1238 AtspiValue *
1239 atspi_accessible_get_value (AtspiAccessible *accessible)
1240 {
1241   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1242           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1243 }
1244
1245 static void
1246 append_const_val (GArray *array, const gchar *val)
1247 {
1248   gchar *dup = g_strdup (val);
1249
1250   if (dup)
1251     g_array_append_val (array, dup);
1252 }
1253
1254 /**
1255  * atspi_accessible_get_interfaces:
1256  *
1257  * #obj: The #AtspiAccessible to query.
1258  *
1259  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
1260  *          describing the interfaces supported by the object.  Interfaces are
1261  *          denoted in short-hand (ie, "Component", "Text", etc.)
1262  **/
1263 GArray *
1264 atspi_accessible_get_interfaces (AtspiAccessible *obj)
1265 {
1266   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1267
1268   g_return_val_if_fail (obj != NULL, NULL);
1269
1270   append_const_val (ret, "Accessible");
1271   if (atspi_accessible_is_action (obj))
1272     append_const_val (ret, "Action");
1273   if (atspi_accessible_is_collection (obj))
1274     append_const_val (ret, "Collection");
1275   if (atspi_accessible_is_component (obj))
1276     append_const_val (ret, "Component");
1277   if (atspi_accessible_is_document (obj))
1278     append_const_val (ret, "Document");
1279   if (atspi_accessible_is_editable_text (obj))
1280     append_const_val (ret, "EditableText");
1281   if (atspi_accessible_is_hypertext (obj))
1282     append_const_val (ret, "Hypertext");
1283   if (atspi_accessible_is_hyperlink (obj))
1284     append_const_val (ret, "Hyperlink");
1285   if (atspi_accessible_is_image (obj))
1286     append_const_val (ret, "Image");
1287   if (atspi_accessible_is_selection (obj))
1288     append_const_val (ret, "Selection");
1289   if (atspi_accessible_is_table (obj))
1290     append_const_val (ret, "Table");
1291   if (atspi_accessible_is_text (obj))
1292     append_const_val (ret, "Text");
1293   if (atspi_accessible_is_value (obj))
1294     append_const_val (ret, "Value");
1295
1296   return ret;
1297 }
1298
1299 AtspiAccessible *
1300 atspi_accessible_new (AtspiApplication *app, const gchar *path)
1301 {
1302   AtspiAccessible *accessible;
1303   
1304   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1305   g_return_val_if_fail (accessible != NULL, NULL);
1306
1307   accessible->parent.app = g_object_ref (app);
1308   accessible->parent.path = g_strdup (path);
1309
1310   return accessible;
1311 }
1312
1313 /**
1314  * atspi_accessible_set_cache_mask:
1315  *
1316  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
1317  *             the root of an application.
1318  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
1319  *
1320  * Sets the type of data to cache for accessibles.
1321  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
1322  * then the desktop's cache flag will be used.
1323  * If the desktop's cache flag is also undefined, then all possible data will
1324  * be cached.
1325  * This function is intended to work around bugs in toolkits where the proper
1326  * events are not raised / to aid in testing for such bugs.
1327  **/
1328 void
1329 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
1330 {
1331   g_return_if_fail (accessible != NULL);
1332   g_return_if_fail (accessible->parent.app != NULL);
1333   g_return_if_fail (accessible == accessible->parent.app->root);
1334   accessible->parent.app->cache = mask;
1335 }
1336
1337 /**
1338  * atspi_accessible_clear_cache:
1339  * @accessible: The #AtspiAccessible whose cache to clear.
1340  *
1341  * Clears the cached information for the given accessible and all of its
1342  * descendants.
1343  */
1344 void
1345 atspi_accessible_clear_cache (AtspiAccessible *accessible)
1346 {
1347   GList *l;
1348
1349   if (accessible)
1350   {
1351     accessible->cached_properties = ATSPI_CACHE_NONE;
1352     for (l = accessible->children; l; l = l->next)
1353       atspi_accessible_clear_cache (l->data);
1354   }
1355 }
1356
1357 AtspiCache
1358 _atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
1359 {
1360   AtspiCache mask;
1361
1362   if (!accessible->parent.app)
1363     return ATSPI_CACHE_NONE;
1364
1365  mask = accessible->parent.app->cache;
1366   if (mask == ATSPI_CACHE_UNDEFINED &&
1367       accessible->parent.app->root &&
1368       accessible->parent.app->root->accessible_parent)
1369   {
1370     AtspiAccessible *desktop = atspi_get_desktop (0);
1371     mask = desktop->parent.app->cache;
1372     g_object_unref (desktop);
1373   }
1374
1375   if (mask == ATSPI_CACHE_UNDEFINED)
1376     mask = ATSPI_CACHE_DEFAULT;
1377
1378   return mask;
1379 }
1380
1381 gboolean
1382 _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
1383 {
1384   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1385   AtspiCache result = accessible->cached_properties & mask & flag;
1386   return (result != 0 && atspi_main_loop && !atspi_no_cache);
1387 }
1388
1389 void
1390 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
1391 {
1392   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1393
1394   accessible->cached_properties |= flag & mask;
1395 }