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