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