Fix crash when get_process_id called with an app no longer on the bus
[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         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
676         {
677           g_object_unref (root);
678           return NULL;
679         }
680         return root;
681       }
682     }
683     if (!parent || parent == obj ||
684         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
685   {
686     if (parent)
687       g_object_unref (parent);
688     return obj;
689   }
690     g_object_unref (obj);
691     obj = parent;
692   }
693 }
694
695 /* Application-specific methods */
696
697 /**
698  * atspi_accessible_get_toolkit_name:
699  * @obj: a pointer to the #AtspiAccessible object on which to operate.
700  *
701  * Gets the toolkit name for an #AtspiAccessible object.
702  * Only works on application root objects.
703  *
704  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object or NULL on exception.
705  **/
706 gchar *
707 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
708 {
709   g_return_val_if_fail (obj != NULL, NULL);
710
711   if (!obj->parent.app)
712     return NULL;
713
714   if (!obj->parent.app->toolkit_name)
715     _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
716                               error, "s", &obj->parent.app->toolkit_name);
717
718   return g_strdup (obj->parent.app->toolkit_name);
719 }
720
721 /**
722  * atspi_accessible_get_toolkit_version:
723  * @obj: a pointer to the #AtspiAccessible object on which to operate.
724  *
725  * Gets the toolkit version for an #AtspiAccessible object.
726  * Only works on application root objects.
727  *
728  * Returns: a UTF-8 string indicating the toolkit version for the #AtspiAccessible object or NULL on exception.
729  **/
730 gchar *
731 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
732 {
733   g_return_val_if_fail (obj != NULL, NULL);
734
735   if (!obj->parent.app)
736     return NULL;
737
738   if (!obj->parent.app->toolkit_version)
739     _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
740                               error, "s", &obj->parent.app->toolkit_version);
741
742   return g_strdup (obj->parent.app->toolkit_version);
743 }
744
745 /**
746  * atspi_accessible_get_atspi_version:
747  * @obj: a pointer to the #AtspiAccessible object on which to operate.
748  *
749  * Gets the AT-SPI IPC specification version supported by the application
750  * pointed to by the #AtspiAccessible object.
751  * Only works on application root objects.
752  *
753  * Returns: a UTF-8 string indicating the AT-SPI version for the #AtspiAccessible object or NULL on exception.
754  **/
755 gchar *
756 atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
757 {
758   g_return_val_if_fail (obj != NULL, NULL);
759
760   if (!obj->parent.app)
761     return NULL;
762
763   if (!obj->parent.app->atspi_version)
764     _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
765                               error, "s", &obj->parent.app->atspi_version);
766
767   return g_strdup (obj->parent.app->atspi_version);
768 }
769
770 /**
771  * atspi_accessible_get_id:
772  * @obj: a pointer to the #AtspiAccessible object on which to operate.
773  *
774  * Gets the application id for a #AtspiAccessible object.
775  * Only works on application root objects.
776  *
777  * Returns: a positive #gint indicating the id for the #AtspiAccessible object 
778  * or -1 on exception.
779  **/
780 gint
781 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
782 {
783   gint ret = -1;
784
785   g_return_val_if_fail (obj != NULL, -1);
786
787   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
788       return -1;
789   return ret;
790 }
791
792
793 /* Interface query methods */
794
795 static gboolean
796 _atspi_accessible_is_a (AtspiAccessible *accessible,
797                       const char *interface_name)
798 {
799   int n;
800
801   if (accessible == NULL)
802     {
803       return FALSE;
804     }
805
806   if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
807   {
808     DBusMessage *reply;
809     DBusMessageIter iter;
810     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
811                                       "GetInterfaces", NULL, "");
812     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
813     dbus_message_iter_init (reply, &iter);
814     _atspi_dbus_set_interfaces (accessible, &iter);
815     dbus_message_unref (reply);
816     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
817   }
818
819   n = _atspi_get_iface_num (interface_name);
820   if (n == -1) return FALSE;
821   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
822 }
823
824 /**
825  * atspi_accessible_is_action:
826  * @obj: a pointer to the #AtspiAccessible instance to query.
827  *
828  * Query whether the specified #AtspiAccessible implements the 
829  * #AtspiAction interface.
830  *
831  * Returns: #TRUE if @obj implements the #AtspiAction interface,
832  *          #FALSE otherwise.
833  **/
834 gboolean
835 atspi_accessible_is_action (AtspiAccessible *obj)
836 {
837   return _atspi_accessible_is_a (obj,
838                               atspi_interface_action);
839 }
840
841 /**
842  * atspi_accessible_is_application:
843  * @obj: a pointer to the #AtspiAccessible instance to query.
844  *
845  * Query whether the specified #AtspiAccessible implements the
846  * #AtspiApplication interface.
847  *
848  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
849  *          #FALSE otherwise.
850  **/
851 gboolean
852 atspi_accessible_is_application (AtspiAccessible *obj)
853 {
854   return _atspi_accessible_is_a (obj,
855                               atspi_interface_application);
856 }
857
858 /**                      
859  * atspi_accessible_is_collection:
860  * @obj: a pointer to the #AtspiAccessible instance to query.
861  *
862  * Query whether the specified #AtspiAccessible implements the
863  * #AtspiCollection interface.
864  *
865  * Returns: #TRUE if @obj implements the #AtspiCollection interface,
866  *          #FALSE otherwise.
867  **/
868 gboolean
869 atspi_accessible_is_collection (AtspiAccessible *obj)
870 {
871      return _atspi_accessible_is_a (obj,
872                               atspi_interface_collection);
873 }
874
875 /**
876  * atspi_accessible_is_component:
877  * @obj: a pointer to the #AtspiAccessible instance to query.
878  *
879  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
880  *
881  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
882  *          #FALSE otherwise.
883  **/
884 gboolean
885 atspi_accessible_is_component (AtspiAccessible *obj)
886 {
887   return _atspi_accessible_is_a (obj,
888                               atspi_interface_component);
889 }
890
891 /**
892  * atspi_accessible_is_document:
893  * @obj: a pointer to the #AtspiAccessible instance to query.
894  *
895  * Query whether the specified #AtspiAccessible implements the
896  * #AtspiDocument interface.
897  *
898  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
899  *          #FALSE otherwise.
900  **/
901 gboolean
902 atspi_accessible_is_document (AtspiAccessible *obj)
903 {
904   return _atspi_accessible_is_a (obj,
905                               atspi_interface_document);
906 }
907
908 /**
909  * atspi_accessible_is_editable_text:
910  * @obj: a pointer to the #AtspiAccessible instance to query.
911  *
912  * Query whether the specified #AtspiAccessible implements the
913  * #AtspiEditableText interface.
914  *
915  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
916  *          #FALSE otherwise.
917  **/
918 gboolean
919 atspi_accessible_is_editable_text (AtspiAccessible *obj)
920 {
921   return _atspi_accessible_is_a (obj,
922                               atspi_interface_editable_text);
923 }
924                                                                                                                                                                         
925 /**
926  * atspi_accessible_is_hypertext:
927  * @obj: a pointer to the #AtspiAccessible instance to query.
928  *
929  * Query whether the specified #AtspiAccessible implements the
930  * #AtspiHypertext interface.
931  *
932  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
933  *          #FALSE otherwise.
934  **/
935 gboolean
936 atspi_accessible_is_hypertext (AtspiAccessible *obj)
937 {
938   return _atspi_accessible_is_a (obj,
939                               atspi_interface_hypertext);
940 }
941
942 /**
943  * atspi_accessible_is_hyperlink:
944  * @obj: a pointer to the #AtspiAccessible instance to query.
945  *
946  * Query whether the specified #AtspiAccessible implements the 
947  * #AtspiHyperlink interface.
948  *
949  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
950  *          #FALSE otherwise.
951  **/
952 gboolean
953 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
954 {
955   return _atspi_accessible_is_a (obj,
956                               atspi_interface_hyperlink);
957 }
958
959 /**
960  * atspi_accessible_is_image:
961  * @obj: a pointer to the #AtspiAccessible instance to query.
962  *
963  * Query whether the specified #AtspiAccessible implements the
964  * #AtspiImage interface.
965  *
966  * Returns: #TRUE if @obj implements the #AtspiImage interface,
967  *          #FALSE otherwise.
968 **/
969 gboolean
970 atspi_accessible_is_image (AtspiAccessible *obj)
971 {
972   return _atspi_accessible_is_a (obj,
973                               atspi_interface_image);
974 }
975
976 /**
977  * atspi_accessible_is_selection:
978  * @obj: a pointer to the #AtspiAccessible instance to query.
979  *
980  * Query whether the specified #AtspiAccessible implements the
981  * #AtspiSelection interface.
982  *
983  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
984  *          #FALSE otherwise.
985 **/
986 gboolean
987 atspi_accessible_is_selection (AtspiAccessible *obj)
988 {
989   return _atspi_accessible_is_a (obj,
990                               atspi_interface_selection);
991 }
992
993 /**
994  * atspi_accessible_is_table:
995  * @obj: a pointer to the #AtspiAccessible instance to query.
996  *
997  * Query whether the specified #AtspiAccessible implements the
998  * #AtspiTable interface.
999  *
1000  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1001  *          #FALSE otherwise.
1002 **/
1003 gboolean
1004 atspi_accessible_is_table (AtspiAccessible *obj)
1005 {
1006   return _atspi_accessible_is_a (obj,
1007                               atspi_interface_table);
1008 }
1009
1010 /**
1011  * atspi_accessible_is_streamable_content:
1012  * @obj: a pointer to the #AtspiAccessible instance to query.
1013  *
1014  * Query whether the specified #AtspiAccessible implements the
1015  * #AtspiStreamableContent interface.
1016  *
1017  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
1018  *          #FALSE otherwise.
1019 **/
1020 gboolean
1021 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
1022 {
1023 #if 0
1024   return _atspi_accessible_is_a (obj,
1025                               atspi_interface_streamable_content);
1026 #else
1027   g_warning ("Streamable content not implemented");
1028   return FALSE;
1029 #endif
1030 }
1031
1032 /**
1033  * atspi_accessible_is_text:
1034  * @obj: a pointer to the #AtspiAccessible instance to query.
1035  *
1036  * Query whether the specified #AtspiAccessible implements the 
1037  * #AtspiText interface.
1038  *
1039  * Returns: #TRUE if @obj implements the #AtspiText interface,
1040  *          #FALSE otherwise.
1041 **/
1042 gboolean
1043 atspi_accessible_is_text (AtspiAccessible *obj)
1044 {
1045   return _atspi_accessible_is_a (obj,
1046                               atspi_interface_text);
1047 }
1048
1049 /**
1050  * atspi_accessible_is_value:
1051  * @obj: a pointer to the #AtspiAccessible instance to query.
1052  *
1053  * Query whether the specified #AtspiAccessible implements the
1054  * #AtspiValue interface.
1055  *
1056  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1057  *          #FALSE otherwise.
1058 **/
1059 gboolean
1060 atspi_accessible_is_value (AtspiAccessible *obj)
1061 {
1062   return _atspi_accessible_is_a (obj,
1063                               atspi_interface_value);
1064 }
1065
1066 /**
1067  * atspi_accessible_get_action:
1068  * @obj: a pointer to the #AtspiAccessible instance to query.
1069  *
1070  * Gets the #AtspiAction interface for an #AtspiAccessible.
1071  *
1072  * Returns: (transfer full): a pointer to an #AtspiAction interface
1073  *          instance, or NULL if @obj does not implement #AtspiAction.
1074  *
1075  * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
1076  * Rename to: atspi_accessible_get_action_iface
1077  **/
1078 AtspiAction *
1079 atspi_accessible_get_action (AtspiAccessible *accessible)
1080 {
1081   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1082           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1083 }
1084
1085 /**
1086  * atspi_accessible_get_action_iface:
1087  * @obj: a pointer to the #AtspiAccessible instance to query.
1088  *
1089  * Gets the #AtspiAction interface for an #AtspiAccessible.
1090  *
1091  * Returns: (transfer full): a pointer to an #AtspiAction interface
1092  *          instance, or NULL if @obj does not implement #AtspiAction.
1093  **/
1094 AtspiAction *
1095 atspi_accessible_get_action_iface (AtspiAccessible *accessible)
1096 {
1097   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1098           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1099 }
1100
1101 /**
1102  * atspi_accessible_get_collection:
1103  * @obj: a pointer to the #AtspiAccessible instance to query.
1104  *
1105  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1106  *
1107  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1108  *          instance, or NULL if @obj does not implement #AtspiCollection.
1109  *
1110  * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
1111  * Rename to: atspi_accessible_get_collection_iface
1112  **/
1113 AtspiCollection *
1114 atspi_accessible_get_collection (AtspiAccessible *accessible)
1115 {
1116   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1117           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1118 }
1119
1120 /**
1121  * atspi_accessible_get_collection_iface:
1122  * @obj: a pointer to the #AtspiAccessible instance to query.
1123  *
1124  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1125  *
1126  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1127  *          instance, or NULL if @obj does not implement #AtspiCollection.
1128  **/
1129 AtspiCollection *
1130 atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
1131 {
1132   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1133           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1134 }
1135
1136 /**
1137  * atspi_accessible_get_component:
1138  * @obj: a pointer to the #AtspiAccessible instance to query.
1139  *
1140  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1141  *
1142  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1143  *          instance, or NULL if @obj does not implement #AtspiComponent.
1144  *
1145  * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
1146  * Rename to: atspi_accessible_get_component_iface
1147  **/
1148 AtspiComponent *
1149 atspi_accessible_get_component (AtspiAccessible *obj)
1150 {
1151   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1152           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1153 }
1154
1155 /**
1156  * atspi_accessible_get_component_iface:
1157  * @obj: a pointer to the #AtspiAccessible instance to query.
1158  *
1159  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1160  *
1161  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1162  *          instance, or NULL if @obj does not implement #AtspiComponent.
1163  **/
1164 AtspiComponent *
1165 atspi_accessible_get_component_iface (AtspiAccessible *obj)
1166 {
1167   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1168           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1169 }
1170
1171 /**
1172  * atspi_accessible_get_document:
1173  * @obj: a pointer to the #AtspiAccessible instance to query.
1174  *
1175  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1176  *
1177  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1178  *          instance, or NULL if @obj does not implement #AtspiDocument.
1179  *
1180  * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
1181  * Rename to: atspi_accessible_get_document_iface
1182  **/
1183 AtspiDocument *
1184 atspi_accessible_get_document (AtspiAccessible *accessible)
1185 {
1186   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1187           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1188 }
1189
1190 /**
1191  * atspi_accessible_get_document_iface:
1192  * @obj: a pointer to the #AtspiAccessible instance to query.
1193  *
1194  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1195  *
1196  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1197  *          instance, or NULL if @obj does not implement #AtspiDocument.
1198  **/
1199 AtspiDocument *
1200 atspi_accessible_get_document_iface (AtspiAccessible *accessible)
1201 {
1202   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1203           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1204 }
1205
1206 /**
1207  * atspi_accessible_get_editable_text:
1208  * @obj: a pointer to the #AtspiAccessible instance to query.
1209  *
1210  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1211  *
1212  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1213  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1214  *
1215  * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
1216  * Rename to: atspi_accessible_get_editable_text_iface
1217  **/
1218 AtspiEditableText *
1219 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1220 {
1221   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1222           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1223 }
1224
1225 /**
1226  * atspi_accessible_get_editable_text_iface:
1227  * @obj: a pointer to the #AtspiAccessible instance to query.
1228  *
1229  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1230  *
1231  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1232  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1233  **/
1234 AtspiEditableText *
1235 atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
1236 {
1237   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1238           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1239 }
1240
1241 /**
1242  * atspi_accessible_get_hyperlink:
1243  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1244  *
1245  * Gets the #AtspiHyperlink interface for an #AtspiAccessible.
1246  *
1247  * Returns: (transfer full): the #AtspiHyperlink object associated with
1248  *          the given #AtspiAccessible, or NULL if not supported.
1249  **/
1250 AtspiHyperlink *
1251 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1252 {
1253   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1254           _atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1255 }
1256
1257 /**
1258  * atspi_accessible_get_hypertext:
1259  * @obj: a pointer to the #AtspiAccessible instance to query.
1260  *
1261  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1262  *
1263  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1264  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1265  *
1266  * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
1267  * Rename to: atspi_accessible_get_hypertext_iface
1268  **/
1269 AtspiHypertext *
1270 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1271 {
1272   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1273           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1274 }
1275
1276 /**
1277  * atspi_accessible_get_hypertext_iface:
1278  * @obj: a pointer to the #AtspiAccessible instance to query.
1279  *
1280  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1281  *
1282  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1283  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1284  **/
1285 AtspiHypertext *
1286 atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
1287 {
1288   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1289           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1290 }
1291
1292 /**
1293  * atspi_accessible_get_image:
1294  * @obj: a pointer to the #AtspiAccessible instance to query.
1295  *
1296  * Gets the #AtspiImage interface for an #AtspiAccessible.
1297  *
1298  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1299  *          NULL if @obj does not implement #AtspiImage.
1300  *
1301  * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
1302  * Rename to: atspi_accessible_get_image_iface
1303  **/
1304 AtspiImage *
1305 atspi_accessible_get_image (AtspiAccessible *accessible)
1306 {
1307   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1308           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1309 }
1310
1311 /**
1312  * atspi_accessible_get_image_iface:
1313  * @obj: a pointer to the #AtspiAccessible instance to query.
1314  *
1315  * Gets the #AtspiImage interface for an #AtspiAccessible.
1316  *
1317  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1318  *          NULL if @obj does not implement #AtspiImage.
1319  **/
1320 AtspiImage *
1321 atspi_accessible_get_image_iface (AtspiAccessible *accessible)
1322 {
1323   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1324           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1325 }
1326
1327 /**
1328  * atspi_accessible_get_selection:
1329  * @obj: a pointer to the #AtspiAccessible instance to query.
1330  *
1331  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1332  *
1333  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1334  *          instance, or NULL if @obj does not implement #AtspiSelection.
1335  *
1336  * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
1337  * Rename to: atspi_accessible_get_selection_iface
1338  **/
1339 AtspiSelection *
1340 atspi_accessible_get_selection (AtspiAccessible *accessible)
1341 {
1342   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1343           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1344 }
1345
1346 /**
1347  * atspi_accessible_get_selection_iface:
1348  * @obj: a pointer to the #AtspiAccessible instance to query.
1349  *
1350  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1351  *
1352  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1353  *          instance, or NULL if @obj does not implement #AtspiSelection.
1354  **/
1355 AtspiSelection *
1356 atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
1357 {
1358   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1359           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1360 }
1361
1362 #if 0
1363 /**
1364  * atspi_accessible_get_streamable_content:
1365  * @obj: a pointer to the #AtspiAccessible instance to query.
1366  *
1367  * Gets the #AtspiStreamableContent interface for an #AtspiAccessible.
1368  *
1369  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1370  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1371  **/
1372 AtspiStreamableContent *
1373 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1374 {
1375   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1376           accessible : NULL);  
1377 }
1378 #endif
1379
1380 /**
1381  * atspi_accessible_get_table:
1382  * @obj: a pointer to the #AtspiAccessible instance to query.
1383  *
1384  * Gets the #AtspiTable interface for an #AtspiAccessible.
1385  *
1386  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1387  *          NULL if @obj does not implement #AtspiTable.
1388  *
1389  * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
1390  * Rename to: atspi_accessible_get_table_iface
1391  **/
1392 AtspiTable *
1393 atspi_accessible_get_table (AtspiAccessible *obj)
1394 {
1395   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1396           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1397 }
1398
1399 /**
1400  * atspi_accessible_get_table_iface:
1401  * @obj: a pointer to the #AtspiAccessible instance to query.
1402  *
1403  * Gets the #AtspiTable interface for an #AtspiAccessible.
1404  *
1405  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1406  *          NULL if @obj does not implement #AtspiTable.
1407  **/
1408 AtspiTable *
1409 atspi_accessible_get_table_iface (AtspiAccessible *obj)
1410 {
1411   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1412           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1413 }
1414
1415 /**
1416  * atspi_accessible_get_text:
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 #AtspiText interface instance, or
1422  *          NULL if @obj does not implement #AtspiText.
1423  *
1424  * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
1425  * Rename to: atspi_accessible_get_text_iface
1426  **/
1427 AtspiText *
1428 atspi_accessible_get_text (AtspiAccessible *obj)
1429 {
1430   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1431           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1432 }
1433
1434 /**
1435  * atspi_accessible_get_text_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 #AtspiText interface instance, or
1441  *          NULL if @obj does not implement #AtspiText.
1442  **/
1443 AtspiText *
1444 atspi_accessible_get_text_iface (AtspiAccessible *obj)
1445 {
1446   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1447           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1448 }
1449
1450 /**
1451  * atspi_accessible_get_value:
1452  * @obj: a pointer to the #AtspiAccessible instance to query.
1453  *
1454  * Gets the #AtspiTable interface for an #AtspiAccessible.
1455  *
1456  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1457  *          NULL if @obj does not implement #AtspiValue.
1458  *
1459  * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
1460  * Rename to: atspi_accessible_get_value_iface
1461  **/
1462 AtspiValue *
1463 atspi_accessible_get_value (AtspiAccessible *accessible)
1464 {
1465   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1466           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1467 }
1468
1469 /**
1470  * atspi_accessible_get_value_iface:
1471  * @obj: a pointer to the #AtspiAccessible instance to query.
1472  *
1473  * Gets the #AtspiTable interface for an #AtspiAccessible.
1474  *
1475  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1476  *          NULL if @obj does not implement #AtspiValue.
1477  **/
1478 AtspiValue *
1479 atspi_accessible_get_value_iface (AtspiAccessible *accessible)
1480 {
1481   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1482           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1483 }
1484
1485 static void
1486 append_const_val (GArray *array, const gchar *val)
1487 {
1488   gchar *dup = g_strdup (val);
1489
1490   if (dup)
1491     g_array_append_val (array, dup);
1492 }
1493
1494 /**
1495  * atspi_accessible_get_interfaces:
1496  * @obj: The #AtspiAccessible to query.
1497  *
1498  * A set of pointers to all interfaces supported by an #AtspiAccessible.
1499  *
1500  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
1501  *          describing the interfaces supported by the object.  Interfaces are
1502  *          denoted in short-hand (i.e. "Component", "Text" etc.).
1503  **/
1504 GArray *
1505 atspi_accessible_get_interfaces (AtspiAccessible *obj)
1506 {
1507   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1508
1509   g_return_val_if_fail (obj != NULL, NULL);
1510
1511   append_const_val (ret, "Accessible");
1512   if (atspi_accessible_is_action (obj))
1513     append_const_val (ret, "Action");
1514   if (atspi_accessible_is_collection (obj))
1515     append_const_val (ret, "Collection");
1516   if (atspi_accessible_is_component (obj))
1517     append_const_val (ret, "Component");
1518   if (atspi_accessible_is_document (obj))
1519     append_const_val (ret, "Document");
1520   if (atspi_accessible_is_editable_text (obj))
1521     append_const_val (ret, "EditableText");
1522   if (atspi_accessible_is_hypertext (obj))
1523     append_const_val (ret, "Hypertext");
1524   if (atspi_accessible_is_hyperlink (obj))
1525     append_const_val (ret, "Hyperlink");
1526   if (atspi_accessible_is_image (obj))
1527     append_const_val (ret, "Image");
1528   if (atspi_accessible_is_selection (obj))
1529     append_const_val (ret, "Selection");
1530   if (atspi_accessible_is_table (obj))
1531     append_const_val (ret, "Table");
1532   if (atspi_accessible_is_text (obj))
1533     append_const_val (ret, "Text");
1534   if (atspi_accessible_is_value (obj))
1535     append_const_val (ret, "Value");
1536
1537   return ret;
1538 }
1539
1540 AtspiAccessible * 
1541 _atspi_accessible_new (AtspiApplication *app, const gchar *path)
1542 {
1543   AtspiAccessible *accessible;
1544   
1545   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1546   g_return_val_if_fail (accessible != NULL, NULL);
1547
1548   accessible->parent.app = g_object_ref (app);
1549   accessible->parent.path = g_strdup (path);
1550
1551   return accessible;
1552 }
1553
1554 /**
1555  * atspi_accessible_set_cache_mask:
1556  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
1557  *             the root of an application.
1558  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
1559  *
1560  * Sets the type of data to cache for accessibles.
1561  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
1562  * then the desktop's cache flag will be used.
1563  * If the desktop's cache flag is also undefined, then all possible data will
1564  * be cached.
1565  * This function is intended to work around bugs in toolkits where the proper
1566  * events are not raised / to aid in testing for such bugs.
1567  **/
1568 void
1569 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
1570 {
1571   g_return_if_fail (accessible != NULL);
1572   g_return_if_fail (accessible->parent.app != NULL);
1573   g_return_if_fail (accessible == accessible->parent.app->root);
1574   accessible->parent.app->cache = mask;
1575   enable_caching = TRUE;
1576 }
1577
1578 /**
1579  * atspi_accessible_clear_cache:
1580  * @accessible: The #AtspiAccessible whose cache to clear.
1581  *
1582  * Clears the cached information for the given accessible and all of its
1583  * descendants.
1584  */
1585 void
1586 atspi_accessible_clear_cache (AtspiAccessible *accessible)
1587 {
1588   GList *l;
1589
1590   if (accessible)
1591   {
1592     accessible->cached_properties = ATSPI_CACHE_NONE;
1593     for (l = accessible->children; l; l = l->next)
1594       atspi_accessible_clear_cache (l->data);
1595   }
1596 }
1597
1598 /**
1599  * atspi_accessible_get_process_id:
1600  * @accessible: The #AtspiAccessible to query.
1601  *
1602  * Returns the process id associated with the given accessible.  Mainly
1603  * added for debugging; it is a shortcut to explicitly querying the
1604  * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
1605  *
1606  * Returns: The process ID, or -1 if defunct.
1607  **/
1608 guint
1609 atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
1610 {
1611   DBusMessage *message, *reply;
1612   DBusConnection *bus = _atspi_bus ();
1613   dbus_uint32_t pid = -1;
1614   DBusError d_error;
1615
1616   if (!accessible->parent.app || !accessible->parent.app->bus_name)
1617     return -1;
1618
1619   message = dbus_message_new_method_call ("org.freedesktop.DBus",
1620                                           "/org/freedesktop/DBus",
1621                                           "org.freedesktop.DBus",
1622                                           "GetConnectionUnixProcessID");
1623   dbus_message_append_args (message, DBUS_TYPE_STRING,
1624                             &accessible->parent.app->bus_name,
1625                             DBUS_TYPE_INVALID);
1626   dbus_error_init (&d_error);
1627   reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
1628   dbus_message_unref (message);
1629   if (reply)
1630   {
1631     if (!strcmp (dbus_message_get_signature (reply), "u"))
1632       dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
1633     dbus_message_unref (reply);
1634   }
1635   if (dbus_error_is_set (&d_error))
1636     {
1637       g_warning ("GetConnectionUnixProcessID failed: %s", d_error.message);
1638       dbus_error_free (&d_error);
1639     }
1640   return pid;
1641 }
1642
1643 AtspiCache
1644 _atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
1645 {
1646   AtspiCache mask;
1647
1648   if (!accessible->parent.app)
1649     return ATSPI_CACHE_NONE;
1650
1651  mask = accessible->parent.app->cache;
1652   if (mask == ATSPI_CACHE_UNDEFINED &&
1653       accessible->parent.app->root &&
1654       accessible->parent.app->root->accessible_parent)
1655   {
1656     AtspiAccessible *desktop = atspi_get_desktop (0);
1657     mask = desktop->parent.app->cache;
1658     g_object_unref (desktop);
1659   }
1660
1661   if (mask == ATSPI_CACHE_UNDEFINED)
1662     mask = ATSPI_CACHE_DEFAULT;
1663
1664   return mask;
1665 }
1666
1667 gboolean
1668 _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
1669 {
1670   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1671   AtspiCache result = accessible->cached_properties & mask & flag;
1672   if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
1673     return FALSE;
1674   return (result != 0 && (atspi_main_loop || enable_caching) &&
1675           !atspi_no_cache);
1676 }
1677
1678 void
1679 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
1680 {
1681   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1682
1683   accessible->cached_properties |= flag & mask;
1684 }
1685
1686 /**
1687  * atspi_accessible_get_locale:
1688  * @accessible: an #AtspiAccessible
1689  *
1690  * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
1691  * of @accessible.
1692  *
1693  * Since: 2.7.91
1694  *
1695  * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
1696  *          locale of @accessible.
1697  **/
1698 const gchar*
1699 atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
1700 {
1701   gchar *locale;
1702
1703   g_return_val_if_fail (accessible != NULL, NULL);
1704
1705   locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
1706   if (!locale)
1707   {
1708     if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
1709                                    "Locale", error, "s", &locale))
1710       return NULL;
1711     if (locale)
1712       g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
1713                                g_free);
1714   }
1715   return locale;
1716 }