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