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