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