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