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