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