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