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