752001c5880fc12544d667649c49d618dea6165e
[platform/upstream/at-spi2-core.git] / atspi / atspi-accessible.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  * Copyright 2010, 2011 Novell, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "atspi-private.h"
26 #include "atspi-accessible-private.h"
27 #include <string.h>
28
29 static gboolean enable_caching = FALSE;
30 static guint quark_locale;
31
32 static void
33 atspi_action_interface_init (AtspiAction *action)
34 {
35 }
36
37 static void
38 atspi_collection_interface_init (AtspiCollection *component)
39 {
40 }
41
42 static void
43 atspi_component_interface_init (AtspiComponent *component)
44 {
45 }
46
47 static void
48 atspi_document_interface_init (AtspiDocument *document)
49 {
50 }
51
52 static void
53 atspi_editable_text_interface_init (AtspiEditableText *editable_text)
54 {
55 }
56
57 static void
58 atspi_hypertext_interface_init (AtspiHypertext *hypertext)
59 {
60 }
61
62 static void
63 atspi_image_interface_init (AtspiImage *image)
64 {
65 }
66
67 static void
68 atspi_selection_interface_init (AtspiSelection *selection)
69 {
70 }
71
72 static void
73 atspi_table_interface_init (AtspiTable *table)
74 {
75 }
76
77 static void
78 atspi_table_cell_interface_init (AtspiTableCell *cell)
79 {
80 }
81
82 static void
83 atspi_text_interface_init (AtspiText *text)
84 {
85 }
86
87 static void
88 atspi_value_interface_init (AtspiValue *value)
89 {
90 }
91
92 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
93                          G_ADD_PRIVATE (AtspiAccessible)
94                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
95                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
96                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
97                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init)
98                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init)
99                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init)
100                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
101                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
102                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
103                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE_CELL, atspi_table_cell_interface_init)
104                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
105                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
106
107 #ifdef DEBUG_REF_COUNTS
108 static gint accessible_count = 0;
109 #endif
110
111 static void
112 atspi_accessible_init (AtspiAccessible *accessible)
113 {
114 #ifdef DEBUG_REF_COUNTS
115   accessible_count++;
116   g_hash_table_insert (_atspi_get_live_refs (), accessible, NULL);
117   g_print("at-spi: init: %d objects\n", accessible_count);
118 #endif
119
120   accessible->priv = atspi_accessible_get_instance_private (accessible);
121 }
122
123 static void
124 atspi_accessible_dispose (GObject *object)
125 {
126   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
127   AtspiEvent e;
128   AtspiAccessible *parent;
129   GList *children;
130   GList *l;
131
132   /* TODO: Only fire if object not already marked defunct */
133   memset (&e, 0, sizeof (e));
134   e.type = "object:state-changed:defunct";
135   e.source = accessible;
136   e.detail1 = 1;
137   e.detail2 = 0;
138   _atspi_send_event (&e);
139
140   if (accessible->states)
141   {
142     g_object_unref (accessible->states);
143     accessible->states = NULL;
144   }
145
146   parent = accessible->accessible_parent;
147   if (parent && parent->children)
148   {
149     GList*ls = g_list_find (parent->children, accessible);
150     if(ls)
151     {
152       gboolean replace = (ls == parent->children);
153       ls = g_list_remove (ls, accessible);
154       if (replace)
155         parent->children = ls;
156       g_object_unref (object);
157     }
158   }
159
160   if (parent)
161   {
162     g_object_unref (parent);
163     accessible->accessible_parent = NULL;
164   }
165
166   children = accessible->children;
167   accessible->children = NULL;
168   for (l = children; l; l = l->next)
169   {
170     AtspiAccessible *child = l->data;
171     if (child && child->accessible_parent == accessible)
172     {
173       g_object_unref (accessible);
174       child->accessible_parent = NULL;
175     }
176     g_object_unref (child);
177   }
178   g_list_free (children);
179
180   G_OBJECT_CLASS (atspi_accessible_parent_class) ->dispose (object);
181 }
182
183 static void
184 atspi_accessible_finalize (GObject *object)
185 {
186   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
187
188     g_free (accessible->description);
189     g_free (accessible->name);
190   if (accessible->attributes)
191     g_hash_table_unref (accessible->attributes);
192
193     if (accessible->priv->cache)
194       g_hash_table_destroy (accessible->priv->cache);
195
196 #ifdef DEBUG_REF_COUNTS
197   accessible_count--;
198   g_hash_table_remove (_atspi_get_live_refs (), accessible);
199   g_print ("at-spi: finalize: %d objects\n", accessible_count);
200 #endif
201
202   G_OBJECT_CLASS (atspi_accessible_parent_class)
203     ->finalize (object);
204 }
205
206 static void
207 atspi_accessible_class_init (AtspiAccessibleClass *klass)
208 {
209   GObjectClass *object_class = G_OBJECT_CLASS (klass);
210
211   object_class->dispose = atspi_accessible_dispose;
212   object_class->finalize = atspi_accessible_finalize;
213
214   quark_locale = g_quark_from_string ("accessible-locale");
215 }
216
217 /**
218  * atspi_accessible_get_name:
219  * @obj: a pointer to the #AtspiAccessible object on which to operate.
220  *
221  * Gets the name of an #AtspiAccessible object.
222  *
223  * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object
224  * or NULL on exception.
225  **/
226 gchar *
227 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
228 {
229   g_return_val_if_fail (obj != NULL, g_strdup (""));
230   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME))
231   {
232     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error,
233                                    "s", &obj->name))
234       return g_strdup ("");
235     _atspi_accessible_add_cache (obj, ATSPI_CACHE_NAME);
236   }
237   return g_strdup (obj->name);
238 }
239
240
241 /**
242  * atspi_accessible_get_unique_id:
243  * @obj: a pointer to the #AtspiAccessible object on which to operate.
244  *
245  * Gets the identificator, uniquely identifying object, or NULL if an error occured.
246  *
247  * Returns: a UTF-8 string describing the #AtspiAccessible object
248  * or NULL on exception or NULL object passed.
249  **/
250 gchar *
251 atspi_accessible_get_unique_id(AtspiAccessible *obj, GError **error)
252 {
253   if (!obj) {
254     g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "argument is null");
255     return NULL;
256   }
257
258   gchar *id = NULL;
259   gchar *bus_name = atspi_accessible_get_bus_name(obj, error);
260   if (bus_name && bus_name[0]) {
261     gchar *path = atspi_accessible_get_path(obj, error);
262     if (path && path[0])
263       id = g_strdup_printf("%s:%s", bus_name, path);
264           else
265       g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get path");
266     g_free(path);
267   }
268   else
269     g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get bus name");
270   g_free(bus_name);
271   return id;
272 }
273
274 /**
275  * atspi_accessible_get_bus_name:
276  * @obj: a pointer to the #AtspiAccessible object on which to operate.
277  *
278  * Gets the bus name, where object belongs.
279  *
280  * Returns: a UTF-8 string describing the #AtspiAccessible object's
281  * bus name or empty string on exception or NULL object passed.
282  **/
283 gchar *
284 atspi_accessible_get_bus_name(AtspiAccessible *obj, GError **error)
285 {
286   if (!obj || !obj->parent.app)
287     return g_strdup("");
288   return g_strdup (obj->parent.app->bus_name);
289 }
290
291 /**
292  * atspi_accessible_get_path:
293  * @obj: a pointer to the #AtspiAccessible object on which to operate.
294  *
295  * Gets the path, uniquely identifying object over its bus name.
296  *
297  * Returns: a UTF-8 string describing the #AtspiAccessible object
298  * or empty string on exception or NULL object passed.
299  **/
300 gchar *
301 atspi_accessible_get_path(AtspiAccessible *obj, GError **error)
302 {
303   static const char *prefix = "/org/a11y/atspi/accessible/";
304   static int prefix_len = 27;
305
306   if (!obj)
307     return g_strdup("");
308   AtspiObject *o = ATSPI_OBJECT (obj);
309   if (!o)
310     return g_strdup("");
311   if (strncmp(o->path, prefix, prefix_len) == 0)
312     return g_strdup(o->path + prefix_len);
313   return g_strdup (o->path);
314 }
315
316 /**
317  * atspi_accessible_get_navigable_at_point:
318  * @root: a pointer to the #AtspiAccessible to start search from.
319  * @x: a #gint specifying the x coordinate of the point in question.
320  * @y: a #gint specifying the y coordinate of the point in question.
321  * @ctype: the coordinate system of the point (@x, @y)
322  *         (e.g. ATSPI_COORD_TYPE_WINDOW, ATSPI_COORD_TYPE_SCREEN).
323  *
324  * Finds the accessible element closest to user (highest in z-order), at a given coordinate within an #AtspiAccessible.
325  * This should be the element, that should be picked, when doing mouse click or finger tap at given coordinates.
326  *
327  * Returns: (nullable) (transfer full): a pointer to an
328  *          #AtspiAccessible descendant (of any depth) of the specified component which
329  *          contains the point (@x, @y), or NULL if no descendant contains
330  *          the point.
331  **/
332 AtspiAccessible *
333 atspi_accessible_get_navigable_at_point (AtspiAccessible *root,
334                                           gint x,
335                                           gint y,
336                                           AtspiCoordType ctype, GError **error)
337 {
338   dbus_int32_t d_x = x, d_y = y;
339   dbus_uint32_t d_ctype = ctype;
340   DBusMessage *reply;
341   AtspiAccessible *return_value = NULL;
342   unsigned char recurse = 0;
343   DBusMessageIter iter;
344   AtspiAccessible *deputy = NULL;
345
346   g_return_val_if_fail (root != NULL, NULL);
347   do {
348     reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype);
349
350     _ATSPI_DBUS_CHECK_SIG (reply, "(so)y(so)", NULL, NULL);
351
352     dbus_message_iter_init (reply, &iter);
353     AtspiAccessible *tmp = _atspi_dbus_return_accessible_from_iter (&iter);
354
355     unsigned char value = 0;
356     dbus_message_iter_get_basic (&iter, &value);
357     dbus_message_iter_next (&iter);
358     recurse = (value != 0);
359
360     /* keep deputy if tmp has deputy */
361     if (!deputy)
362       deputy = _atspi_dbus_return_accessible_from_iter (&iter);
363
364     dbus_message_unref(reply);
365
366     if (!tmp) {
367       if (deputy) {
368         /* TODO: need to check deputy works for return value */
369         if (return_value)
370           g_object_unref(return_value);
371         return deputy;
372       }
373       break;
374     }
375
376     if (return_value)
377       g_object_unref(return_value);
378     return_value = root = tmp;
379   } while(recurse);
380   return return_value;
381 }
382
383 /**
384  * atspi_accessible_get_reading_material:
385  * @obj: a pointer to the #AtspiAccessible object on which to operate.
386  *
387  * Gets reading material
388  *
389  * Returns: reading material to be used screen-reader side. This is not stable.
390  * You have to handle all alocated memory as below on screen-reader side.
391  *
392  * AtspiAccessibleReadingMaterial *rm
393  * g_object_unref(rm->parent);
394  * g_object_unref(rm->described_by_accessible);
395  * g_hash_table_unref(rm->attributes);
396  * free(rm->name);
397  * free(rm->labeled_by_name);
398  * free(rm->text_interface_name);
399  * free(rm->localized_role_name);
400  * free(rm->description);
401  * free(rm);
402  **/
403 AtspiAccessibleReadingMaterial *
404 atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error)
405 {
406   AtspiAccessible *parent;
407   AtspiAccessibleReadingMaterial *reading_material = NULL;
408   const char *name;
409   double current_value;
410   gint count;
411   guint64 val;
412   DBusMessage *reply;
413   DBusMessageIter iter;
414   DBusMessageIter iter_array;
415   dbus_uint32_t role;
416   dbus_uint32_t *states;
417   dbus_int32_t index_in_parent;
418   dbus_int32_t child_count;
419   dbus_bool_t is_selected;
420
421   g_return_val_if_fail (obj != NULL, NULL);
422
423   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetReadingMaterial", error, "");
424
425   _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausiddddsibbii(so)auiui(so)", NULL, NULL);
426
427   reading_material = calloc(1, sizeof(AtspiAccessibleReadingMaterial));
428   if (!reading_material)
429   {
430     return reading_material;
431   }
432
433   dbus_message_iter_init (reply, &iter);
434
435   /* get attributes */
436   reading_material->attributes =  _atspi_dbus_hash_from_iter (&iter);
437   dbus_message_iter_next (&iter);
438
439   /* get name */
440   dbus_message_iter_get_basic (&iter, &name);
441   reading_material->name = g_strdup (name);
442   dbus_message_iter_next (&iter);
443
444   /* get name of relation LABELED_BY */
445   dbus_message_iter_get_basic (&iter, &name);
446   reading_material->labeled_by_name = g_strdup (name);
447   dbus_message_iter_next (&iter);
448
449   /* get name of text interface */
450   dbus_message_iter_get_basic (&iter, &name);
451   reading_material->text_interface_name = g_strdup (name);
452   dbus_message_iter_next (&iter);
453
454   /* get role */
455   dbus_message_iter_get_basic (&iter, &role);
456   reading_material->role = role;
457   dbus_message_iter_next (&iter);
458
459   /* get state set */
460   dbus_message_iter_recurse (&iter, &iter_array);
461   dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
462   val = ((guint64)states [1]) << 32;
463   val += states [0];
464   reading_material->states = val;
465   dbus_message_iter_next (&iter);
466
467   /* get localized role name */
468   dbus_message_iter_get_basic (&iter, &name);
469   reading_material->localized_role_name = g_strdup (name);
470   dbus_message_iter_next (&iter);
471
472   /* get child count */
473   dbus_message_iter_get_basic (&iter, &child_count);
474   reading_material->child_count = child_count;
475   dbus_message_iter_next (&iter);
476
477   /* get current value */
478   dbus_message_iter_get_basic (&iter, &current_value);
479   reading_material->value = current_value;
480   dbus_message_iter_next (&iter);
481
482   /* get minimum increment */
483   dbus_message_iter_get_basic (&iter, &current_value);
484   reading_material->increment = current_value;
485   dbus_message_iter_next (&iter);
486
487   /* get maximum value */
488   dbus_message_iter_get_basic (&iter, &current_value);
489   reading_material->upper = current_value;
490   dbus_message_iter_next (&iter);
491
492   /* get minimum value */
493   dbus_message_iter_get_basic (&iter, &current_value);
494   reading_material->lower = current_value;
495   dbus_message_iter_next (&iter);
496
497   /* get description */
498   dbus_message_iter_get_basic (&iter, &name);
499   reading_material->description = g_strdup (name);
500   dbus_message_iter_next (&iter);
501
502   /* get index in parent */
503   dbus_message_iter_get_basic (&iter, &index_in_parent);
504   reading_material->index_in_parent = index_in_parent;
505   dbus_message_iter_next (&iter);
506
507   /* get selected in parent */
508   dbus_message_iter_get_basic (&iter, &is_selected);
509   reading_material->is_selected_in_parent = is_selected;
510   dbus_message_iter_next (&iter);
511
512   /* get has checkbox child */
513   dbus_message_iter_get_basic (&iter, &is_selected);
514   reading_material->has_checkbox_child = is_selected;
515   dbus_message_iter_next (&iter);
516
517   /* get list children count */
518   dbus_message_iter_get_basic (&iter, &child_count);
519   reading_material->list_children_count = child_count;
520   dbus_message_iter_next (&iter);
521
522   /* get first selected child index */
523   dbus_message_iter_get_basic (&iter, &index_in_parent);
524   reading_material->first_selected_child_index = index_in_parent;
525   dbus_message_iter_next (&iter);
526
527   ////////////////
528   /* get parent */
529   parent =  _atspi_dbus_return_accessible_from_iter (&iter);
530   reading_material->parent = parent;
531
532   /* parent states */
533   dbus_message_iter_recurse (&iter, &iter_array);
534   dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
535   val = ((guint64)states [1]) << 32;
536   val += states [0];
537   reading_material->parent_states = val;
538   dbus_message_iter_next (&iter);
539
540   /* get parent child count */
541   dbus_message_iter_get_basic (&iter, &child_count);
542   reading_material->parent_child_count = child_count;
543   dbus_message_iter_next (&iter);
544
545   /* get parent role */
546   dbus_message_iter_get_basic (&iter, &role);
547   reading_material->parent_role = role;
548   dbus_message_iter_next (&iter);
549
550   /* get parent selected child count */
551   dbus_message_iter_get_basic (&iter, &child_count);
552   reading_material->parent_selected_child_count = child_count;
553   dbus_message_iter_next (&iter);
554
555   ////////////////////////////////////////
556   /* get relation object - DESCRIBED_BY */
557   parent =  _atspi_dbus_return_accessible_from_iter (&iter);
558   reading_material->described_by_accessible = parent;
559
560   return reading_material;
561 }
562
563 static unsigned char are_objects_on_the_same_bus(AtspiAccessible *obj1, AtspiAccessible *obj2)
564 {
565   const char *bus_name_1 = obj1->parent.app->bus_name;
566   const char *bus_name_2 = obj2->parent.app->bus_name;
567   return strcmp(bus_name_1, bus_name_2) == 0;
568 }
569
570 static unsigned char object_is_valid(AtspiAccessible *obj)
571 {
572   if (!obj)
573     return 0;
574   AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
575   if (!ss)
576     return 0;
577   unsigned char valid = atspi_state_set_contains(ss, ATSPI_STATE_DEFUNCT) == 0;
578   g_object_unref(ss);
579   return valid;
580 }
581
582 typedef enum {
583   NEIGHBOR_SEARCH_MODE_NORMAL = 0,
584   NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
585   NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
586   NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3,
587 } GetNeighborSearchMode;
588 /**
589  * atspi_accessible_get_neighbor:
590  * @root: a pointer to a #AtspiAccessible, which represents current root of subtree to search
591  * @start: a pointer to the #AtspiAccessible to start search from (can be null, which means start from root)
592  * @direction: direction, in which search (forward or backward)
593  *
594  * Calculates next (or previous) accessible element in logical order or null if none found.
595  *
596  * Returns: (nullable) (transfer full): a pointer to an
597  *          #AtspiAccessible element, which is next (previous) in logical order or null if none found.
598  **/
599 AtspiAccessible *
600 atspi_accessible_get_neighbor (AtspiAccessible *root,
601                                           AtspiAccessible *start,
602                                           AtspiNeighborSearchDirection direction,
603                                           GError **error)
604 {
605   g_return_val_if_fail (object_is_valid(root), NULL);
606   if (!object_is_valid(start))
607     start = root;
608   const char *root_path = ATSPI_OBJECT(root)->path;
609   AtspiAccessible *return_value = NULL;
610   g_object_ref(start);
611   unsigned char recurse;
612   GetNeighborSearchMode search_mode = NEIGHBOR_SEARCH_MODE_NORMAL;
613   GQueue *children_root_stack = g_queue_new();
614   DBusMessageIter iter;
615
616   while(1) {
617     const char *path = are_objects_on_the_same_bus(root, start) ? root_path : "";
618     DBusMessage *reply = _atspi_dbus_call_partial (start, atspi_interface_accessible, "GetNeighbor", error, "sii", path, (int)direction, (int)search_mode);
619
620     _ATSPI_DBUS_CHECK_SIG (reply, "(so)y", error, NULL);
621     dbus_message_iter_init (reply, &iter);
622     AtspiAccessible *ret = _atspi_dbus_return_accessible_from_iter (&iter);
623
624     unsigned char value = 0;
625     dbus_message_iter_get_basic (&iter, &value);
626     dbus_message_iter_next (&iter);
627     recurse = (value != 0);
628
629     dbus_message_unref(reply);
630
631     // got return value and request for recursive search, it means ret is on another bridge, than start
632     // thus we're recursing. should the recurse failed to find anything it will end with
633     if (ret && recurse) {
634       g_object_unref(G_OBJECT(start));
635       start = ret;
636       g_object_ref(start);
637       if (are_objects_on_the_same_bus(root, ret))
638         {
639           search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE;
640         }
641       else
642         {
643           g_queue_push_tail(children_root_stack, ret);
644           search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT;
645         }
646       continue;
647     }
648     // found the one we've been looking for
649     if (ret) {
650       g_object_unref(G_OBJECT(start));
651       return_value = ret;
652       break;
653     }
654
655     // we've stepped into different bridges previously and now we're going back to the last one
656     // and continuing search where we left
657     if (!g_queue_is_empty(children_root_stack)) {
658       g_object_unref(G_OBJECT(start));
659       start = g_queue_pop_tail(children_root_stack);
660
661       search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
662       continue;
663     }
664     // there's no more bridges to check, but we might have started from one
665     // in that case there might be bridges "below" start, which we yet have to visit
666     if (!are_objects_on_the_same_bus(root, start)) {
667       unsigned char continue_loop = 1;
668       while(continue_loop) {
669         AtspiAccessible *parent = atspi_accessible_get_parent(start, NULL);
670         continue_loop = parent ? are_objects_on_the_same_bus(start, parent) : 0;
671         g_object_unref(G_OBJECT(start));
672         start = parent;
673       }
674
675       // going up thru parents put us in weird place (we didnt meet root on the way)
676       // so we bail out
677       if (!start)
678         break;
679
680       // start object now points to different bridge and must be treated as "resume after recursing"
681       search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
682       continue;
683     }
684
685     // nothing found
686     g_object_unref(start);
687     return_value = NULL;
688     break;
689   }
690   while(!g_queue_is_empty(children_root_stack))
691     g_object_unref(g_queue_pop_tail(children_root_stack));
692   g_queue_free(children_root_stack);
693
694   return return_value;
695 }
696
697 /**
698  * atspi_accessible_get_description:
699  * @obj: a pointer to the #AtspiAccessible object on which to operate.
700  *
701  * Gets the description of an #AtspiAccessible object.
702  *
703  * Returns: a UTF-8 string describing the #AtspiAccessible object
704  * or NULL on exception.
705  **/
706 gchar *
707 atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
708 {
709   g_return_val_if_fail (obj != NULL, g_strdup (""));
710
711   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION))
712   {
713     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
714                                    "Description", error, "s",
715                                    &obj->description))
716       return g_strdup ("");
717     _atspi_accessible_add_cache (obj, ATSPI_CACHE_DESCRIPTION);
718   }
719   return g_strdup (obj->description);
720 }
721
722 const char *str_parent = "Parent";
723
724 /**
725  * atspi_accessible_get_parent:
726  * @obj: a pointer to the #AtspiAccessible object to query.
727  *
728  * Gets an #AtspiAccessible object's parent container.
729  *
730  * Returns: (nullable) (transfer full): a pointer to the
731  *          #AtspiAccessible object which contains the given
732  *          #AtspiAccessible instance, or NULL if the @obj has no
733  *          parent container.
734  *
735  **/
736 AtspiAccessible *
737 atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
738 {
739   g_return_val_if_fail (obj != NULL, NULL);
740
741   if (obj->parent.app &&
742       !_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
743   {
744     DBusMessage *message, *reply;
745     DBusMessageIter iter, iter_variant;
746     message = dbus_message_new_method_call (obj->parent.app->bus_name,
747                                             obj->parent.path,
748                                             DBUS_INTERFACE_PROPERTIES, "Get");
749     if (!message)
750       return NULL;
751     dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
752                                DBUS_TYPE_STRING, &str_parent,
753                               DBUS_TYPE_INVALID);
754     reply = _atspi_dbus_send_with_reply_and_block (message, error);
755     if (!reply)
756       return NULL;
757     if (strcmp (dbus_message_get_signature (reply), "v") != 0)
758     {
759       dbus_message_unref (reply);
760       return NULL;
761     }
762     dbus_message_iter_init (reply, &iter);
763     dbus_message_iter_recurse (&iter, &iter_variant);
764     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
765     dbus_message_unref (reply);
766     _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
767   }
768   if (!obj->accessible_parent)
769     return NULL;
770   return g_object_ref (obj->accessible_parent);
771 }
772
773 /**
774  * atspi_accessible_get_child_count:
775  * @obj: a pointer to the #AtspiAccessible object on which to operate.
776  *
777  * Gets the number of children contained by an #AtspiAccessible object.
778  *
779  * Returns: a #long indicating the number of #AtspiAccessible children
780  *          contained by an #AtspiAccessible object or -1 on exception.
781  *
782  **/
783 gint
784 atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
785 {
786   g_return_val_if_fail (obj != NULL, -1);
787
788   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
789   {
790     dbus_int32_t ret;
791     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
792                                    "ChildCount", error, "i", &ret))
793       return -1;
794     return ret;
795   }
796
797   return g_list_length (obj->children);
798 }
799
800 /**
801  * atspi_accessible_get_child_at_index:
802  * @obj: a pointer to the #AtspiAccessible object on which to operate.
803  * @child_index: a #long indicating which child is specified.
804  *
805  * Gets the #AtspiAccessible child of an #AtspiAccessible object at a given index.
806  *
807  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
808  * index @child_index or NULL on exception.
809  **/
810 AtspiAccessible *
811 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
812                             gint    child_index,
813                             GError **error)
814 {
815   AtspiAccessible *child;
816
817   g_return_val_if_fail (obj != NULL, NULL);
818
819   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
820   {
821     DBusMessage *reply;
822     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
823                                      "GetChildAtIndex", error, "i",
824                                      child_index);
825     return _atspi_dbus_return_accessible_from_message (reply);
826   }
827
828   child = g_list_nth_data (obj->children, child_index);
829   if (!child)
830     return NULL;
831   return g_object_ref (child);
832 }
833
834 /**
835  * atspi_accessible_get_index_in_parent:
836  * @obj: a pointer to the #AtspiAccessible object on which to operate.
837  *
838  * Gets the index of an #AtspiAccessible object within its parent's
839  * #AtspiAccessible children list.
840  *
841  * Returns: a #glong indicating the index of the #AtspiAccessible object
842  *          in its parent,
843  *          or -1 if @obj has no containing parent or on exception.
844  **/
845 gint
846 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
847 {
848   GList *l;
849   gint i = 0;
850
851   g_return_val_if_fail (obj != NULL, -1);
852   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT) &&
853       !obj->accessible_parent)
854     return -1;
855   if (!obj->accessible_parent ||
856       !_atspi_accessible_test_cache (obj->accessible_parent,
857                                      ATSPI_CACHE_CHILDREN))
858   {
859     dbus_int32_t ret = -1;
860     _atspi_dbus_call (obj, atspi_interface_accessible,
861                       "GetIndexInParent", NULL, "=>i", &ret);
862     return ret;
863   }
864
865   l = obj->accessible_parent->children;
866   while (l)
867   {
868     if (l->data == obj) return i;
869     l = g_list_next (l);
870     i++;
871   }
872   return -1;
873 }
874
875 typedef struct
876 {
877   dbus_uint32_t type;
878   GArray *targets;
879 } Accessibility_Relation;
880
881 /**
882  * atspi_accessible_get_relation_set:
883  * @obj: a pointer to the #AtspiAccessible object on which to operate.
884  *
885  * Gets the set of #AtspiRelation objects which describes this #AtspiAccessible object's
886  * relationships with other #AtspiAccessible objects.
887  *
888  * Returns: (element-type AtspiRelation*) (transfer full): a #GArray of
889  *          #AtspiRelation pointers or NULL on exception.
890  **/
891 GArray *
892 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
893 {
894   DBusMessage *reply;
895   DBusMessageIter iter, iter_array;
896   GArray *ret;
897
898   g_return_val_if_fail (obj != NULL, NULL);
899
900   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
901   if (!reply)
902     return NULL;
903   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
904
905   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
906   dbus_message_iter_init (reply, &iter);
907   dbus_message_iter_recurse (&iter, &iter_array);
908   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
909   {
910     AtspiRelation *relation;
911     relation = _atspi_relation_new_from_iter (&iter_array);
912     ret = g_array_append_val (ret, relation);
913     dbus_message_iter_next (&iter_array);
914   }
915   dbus_message_unref (reply);
916   return ret;
917 }
918
919 /**
920  * atspi_accessible_get_role:
921  * @obj: a pointer to the #AtspiAccessible object on which to operate.
922  *
923  * Gets the UI role played by an #AtspiAccessible object.
924  * This role's name can be obtained via atspi_accessible_get_role_name ().
925  *
926  * Returns: the #AtspiRole of an #AtspiAccessible object.
927  *
928  **/
929 AtspiRole
930 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
931 {
932   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
933
934   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ROLE))
935   {
936     dbus_uint32_t role;
937     /* TODO: Make this a property */
938     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
939     {
940       obj->role = role;
941     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
942     }
943   }
944   return obj->role;
945 }
946
947 /**
948  * atspi_accessible_get_role_name:
949  * @obj: a pointer to the #AtspiAccessible object on which to operate.
950  *
951  * Gets a UTF-8 string corresponding to the name of the role played by an object.
952  * This method will return useful values for roles that fall outside the
953  * enumeration used in atspi_accessible_get_role ().
954  *
955  * Returns: a UTF-8 string specifying the type of UI role played by an
956  * #AtspiAccessible object.
957  *
958  **/
959 gchar *
960 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
961 {
962   gchar *retval = NULL;
963   AtspiRole role;
964
965   g_return_val_if_fail (obj != NULL, NULL);
966
967   role = atspi_accessible_get_role (obj, error);
968   if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
969     return atspi_role_get_name (role);
970
971   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
972
973   if (!retval)
974     retval = g_strdup ("");
975
976   return retval;
977 }
978
979 /**
980  * atspi_accessible_get_localized_role_name:
981  * @obj: a pointer to the #AtspiAccessible object on which to operate.
982  *
983  * Gets a UTF-8 string corresponding to the name of the role played by an
984  * object, translated to the current locale.
985  * This method will return useful values for roles that fall outside the
986  * enumeration used in atspi_accessible_getRole ().
987  *
988  * Returns: a localized, UTF-8 string specifying the type of UI role played
989  * by an #AtspiAccessible object.
990  *
991  **/
992 gchar *
993 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
994 {
995   char *retval = NULL;
996
997   g_return_val_if_fail (obj != NULL, NULL);
998
999   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
1000
1001   if (!retval)
1002     return g_strdup ("");
1003
1004   return retval;
1005 }
1006
1007 static AtspiStateSet *
1008 defunct_set ()
1009 {
1010   AtspiStateSet *set = atspi_state_set_new (NULL);
1011   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
1012   return set;
1013 }
1014
1015 /**
1016  * atspi_accessible_get_state_set:
1017  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1018  *
1019  * Gets the states currently held by an object.
1020  *
1021  * Returns: (transfer full): a pointer to an #AtspiStateSet representing an
1022  * object's current state set.
1023  **/
1024 AtspiStateSet *
1025 atspi_accessible_get_state_set (AtspiAccessible *obj)
1026 {
1027   /* TODO: Should take a GError **, but would be an API break */
1028   if (!obj->parent.app || !obj->parent.app->bus)
1029     return defunct_set ();
1030
1031   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
1032   {
1033     DBusMessage *reply;
1034     DBusMessageIter iter;
1035     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
1036                                       "GetState", NULL, "");
1037     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
1038     dbus_message_iter_init (reply, &iter);
1039     _atspi_dbus_set_state (obj, &iter);
1040     dbus_message_unref (reply);
1041     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
1042   }
1043   return g_object_ref (obj->states);
1044 }
1045
1046 /**
1047  * atspi_accessible_get_attributes:
1048  * @obj: The #AtspiAccessible being queried.
1049  *
1050  * Gets the #AttributeSet representing any assigned
1051  * name-value pair attributes or annotations for this object.
1052  * For typographic, textual, or textually-semantic attributes, see
1053  * atspi_text_get_attributes instead.
1054  *
1055  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
1056  * attributes assigned to this object.
1057  */
1058 GHashTable *
1059 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
1060 {
1061   DBusMessage *message;
1062
1063     g_return_val_if_fail (obj != NULL, NULL);
1064
1065   if (obj->priv->cache)
1066   {
1067     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
1068     if (val)
1069       return g_value_dup_boxed (val);
1070   }
1071
1072   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
1073   {
1074     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
1075                                         "GetAttributes", error, "");
1076     obj->attributes = _atspi_dbus_return_hash_from_message (message);
1077     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES);
1078   }
1079
1080   if (!obj->attributes)
1081     return NULL;
1082   return g_hash_table_ref (obj->attributes);
1083 }
1084
1085 static void
1086 add_to_attribute_array (gpointer key, gpointer value, gpointer data)
1087 {
1088   GArray **array = (GArray **)data;
1089   gchar *str = g_strconcat (key, ":", value, NULL);
1090   *array = g_array_append_val (*array, str);
1091 }
1092
1093 /**
1094  * atspi_accessible_get_attributes_as_array:
1095  * @obj: The #AtspiAccessible being queried.
1096  *
1097  * Gets a #GArray representing any assigned
1098  * name-value pair attributes or annotations for this object.
1099  * For typographic, textual, or textually-semantic attributes, see
1100  * atspi_text_get_attributes_as_array instead.
1101  *
1102  * Returns: (element-type gchar*) (transfer full): The name-value-pair
1103  *          attributes assigned to this object.
1104  */
1105 GArray *
1106 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
1107 {
1108   DBusMessage *message;
1109
1110     g_return_val_if_fail (obj != NULL, NULL);
1111
1112   if (obj->priv->cache)
1113   {
1114     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
1115     if (val)
1116     {
1117       GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
1118       GHashTable *attributes = g_value_get_boxed (val);
1119       g_hash_table_foreach (attributes, add_to_attribute_array, &array);
1120       return array;
1121     }
1122   }
1123
1124   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
1125   return _atspi_dbus_return_attribute_array_from_message (message);
1126 }
1127
1128 /**
1129  * atspi_accessible_get_application:
1130  * @obj: The #AtspiAccessible being queried.
1131  *
1132  * Gets the containing #AtspiApplication for an object.
1133  *
1134  * Returns: (transfer full): the containing #AtspiApplication instance for
1135  *          this object.
1136  */
1137 AtspiAccessible *
1138 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
1139 {
1140   AtspiAccessible *parent;
1141
1142   g_object_ref (obj);
1143   for (;;)
1144   {
1145     parent = atspi_accessible_get_parent (obj, NULL);
1146     if (!parent && obj->parent.app &&
1147         atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
1148     {
1149       AtspiAccessible *root = g_object_ref (obj->parent.app->root);
1150       if (root)
1151       {
1152         g_object_unref (obj);
1153         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
1154         {
1155           g_object_unref (root);
1156           return NULL;
1157         }
1158         return root;
1159       }
1160     }
1161     if (!parent || parent == obj ||
1162         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
1163   {
1164     if (parent)
1165       g_object_unref (parent);
1166     return obj;
1167   }
1168     g_object_unref (obj);
1169     obj = parent;
1170   }
1171 }
1172
1173 /* Application-specific methods */
1174
1175 /**
1176  * atspi_accessible_get_toolkit_name:
1177  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1178  *
1179  * Gets the toolkit name for an #AtspiAccessible object.
1180  * Only works on application root objects.
1181  *
1182  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object or NULL on exception.
1183  **/
1184 gchar *
1185 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
1186 {
1187   g_return_val_if_fail (obj != NULL, NULL);
1188
1189   if (!obj->parent.app)
1190     return NULL;
1191
1192   if (!obj->parent.app->toolkit_name)
1193     _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
1194                               error, "s", &obj->parent.app->toolkit_name);
1195
1196   return g_strdup (obj->parent.app->toolkit_name);
1197 }
1198
1199 /**
1200  * atspi_accessible_get_toolkit_version:
1201  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1202  *
1203  * Gets the toolkit version for an #AtspiAccessible object.
1204  * Only works on application root objects.
1205  *
1206  * Returns: a UTF-8 string indicating the toolkit version for the #AtspiAccessible object or NULL on exception.
1207  **/
1208 gchar *
1209 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
1210 {
1211   g_return_val_if_fail (obj != NULL, NULL);
1212
1213   if (!obj->parent.app)
1214     return NULL;
1215
1216   if (!obj->parent.app->toolkit_version)
1217     _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
1218                               error, "s", &obj->parent.app->toolkit_version);
1219
1220   return g_strdup (obj->parent.app->toolkit_version);
1221 }
1222
1223 /**
1224  * atspi_accessible_get_atspi_version:
1225  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1226  *
1227  * Gets the AT-SPI IPC specification version supported by the application
1228  * pointed to by the #AtspiAccessible object.
1229  * Only works on application root objects.
1230  *
1231  * Returns: a UTF-8 string indicating the AT-SPI version for the #AtspiAccessible object or NULL on exception.
1232  **/
1233 gchar *
1234 atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
1235 {
1236   g_return_val_if_fail (obj != NULL, NULL);
1237
1238   if (!obj->parent.app)
1239     return NULL;
1240
1241   if (!obj->parent.app->atspi_version)
1242     _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
1243                               error, "s", &obj->parent.app->atspi_version);
1244
1245   return g_strdup (obj->parent.app->atspi_version);
1246 }
1247
1248 /**
1249  * atspi_accessible_get_id:
1250  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1251  *
1252  * Gets the application id for a #AtspiAccessible object.
1253  * Only works on application root objects.
1254  *
1255  * Returns: a positive #gint indicating the id for the #AtspiAccessible object
1256  * or -1 on exception.
1257  **/
1258 gint
1259 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
1260 {
1261   gint ret = -1;
1262
1263   g_return_val_if_fail (obj != NULL, -1);
1264
1265   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
1266       return -1;
1267   return ret;
1268 }
1269
1270
1271 /* Interface query methods */
1272
1273 static gboolean
1274 _atspi_accessible_is_a (AtspiAccessible *accessible,
1275                       const char *interface_name)
1276 {
1277   int n;
1278
1279   if (accessible == NULL)
1280     {
1281       return FALSE;
1282     }
1283
1284   if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
1285   {
1286     DBusMessage *reply;
1287     DBusMessageIter iter;
1288     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
1289                                       "GetInterfaces", NULL, "");
1290     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
1291     dbus_message_iter_init (reply, &iter);
1292     _atspi_dbus_set_interfaces (accessible, &iter);
1293     dbus_message_unref (reply);
1294     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
1295   }
1296
1297   n = _atspi_get_iface_num (interface_name);
1298   if (n == -1) return FALSE;
1299   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
1300 }
1301
1302 /**
1303  * atspi_accessible_is_action:
1304  * @obj: a pointer to the #AtspiAccessible instance to query.
1305  *
1306  * Query whether the specified #AtspiAccessible implements the
1307  * #AtspiAction interface.
1308  *
1309  * Returns: #TRUE if @obj implements the #AtspiAction interface,
1310  *          #FALSE otherwise.
1311  **/
1312 gboolean
1313 atspi_accessible_is_action (AtspiAccessible *obj)
1314 {
1315   return _atspi_accessible_is_a (obj,
1316                               atspi_interface_action);
1317 }
1318
1319 /**
1320  * atspi_accessible_is_application:
1321  * @obj: a pointer to the #AtspiAccessible instance to query.
1322  *
1323  * Query whether the specified #AtspiAccessible implements the
1324  * #AtspiApplication interface.
1325  *
1326  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
1327  *          #FALSE otherwise.
1328  **/
1329 gboolean
1330 atspi_accessible_is_application (AtspiAccessible *obj)
1331 {
1332   return _atspi_accessible_is_a (obj,
1333                               atspi_interface_application);
1334 }
1335
1336 /**
1337  * atspi_accessible_is_collection:
1338  * @obj: a pointer to the #AtspiAccessible instance to query.
1339  *
1340  * Query whether the specified #AtspiAccessible implements the
1341  * #AtspiCollection interface.
1342  *
1343  * Returns: #TRUE if @obj implements the #AtspiCollection interface,
1344  *          #FALSE otherwise.
1345  **/
1346 gboolean
1347 atspi_accessible_is_collection (AtspiAccessible *obj)
1348 {
1349      return _atspi_accessible_is_a (obj,
1350                               atspi_interface_collection);
1351 }
1352
1353 /**
1354  * atspi_accessible_is_component:
1355  * @obj: a pointer to the #AtspiAccessible instance to query.
1356  *
1357  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
1358  *
1359  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
1360  *          #FALSE otherwise.
1361  **/
1362 gboolean
1363 atspi_accessible_is_component (AtspiAccessible *obj)
1364 {
1365   return _atspi_accessible_is_a (obj,
1366                               atspi_interface_component);
1367 }
1368
1369 /**
1370  * atspi_accessible_is_document:
1371  * @obj: a pointer to the #AtspiAccessible instance to query.
1372  *
1373  * Query whether the specified #AtspiAccessible implements the
1374  * #AtspiDocument interface.
1375  *
1376  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
1377  *          #FALSE otherwise.
1378  **/
1379 gboolean
1380 atspi_accessible_is_document (AtspiAccessible *obj)
1381 {
1382   return _atspi_accessible_is_a (obj,
1383                               atspi_interface_document);
1384 }
1385
1386 /**
1387  * atspi_accessible_is_editable_text:
1388  * @obj: a pointer to the #AtspiAccessible instance to query.
1389  *
1390  * Query whether the specified #AtspiAccessible implements the
1391  * #AtspiEditableText interface.
1392  *
1393  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
1394  *          #FALSE otherwise.
1395  **/
1396 gboolean
1397 atspi_accessible_is_editable_text (AtspiAccessible *obj)
1398 {
1399   return _atspi_accessible_is_a (obj,
1400                               atspi_interface_editable_text);
1401 }
1402
1403 /**
1404  * atspi_accessible_is_hypertext:
1405  * @obj: a pointer to the #AtspiAccessible instance to query.
1406  *
1407  * Query whether the specified #AtspiAccessible implements the
1408  * #AtspiHypertext interface.
1409  *
1410  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
1411  *          #FALSE otherwise.
1412  **/
1413 gboolean
1414 atspi_accessible_is_hypertext (AtspiAccessible *obj)
1415 {
1416   return _atspi_accessible_is_a (obj,
1417                               atspi_interface_hypertext);
1418 }
1419
1420 /**
1421  * atspi_accessible_is_hyperlink:
1422  * @obj: a pointer to the #AtspiAccessible instance to query.
1423  *
1424  * Query whether the specified #AtspiAccessible implements the
1425  * #AtspiHyperlink interface.
1426  *
1427  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
1428  *          #FALSE otherwise.
1429  **/
1430 gboolean
1431 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
1432 {
1433   return _atspi_accessible_is_a (obj,
1434                               atspi_interface_hyperlink);
1435 }
1436
1437 /**
1438  * atspi_accessible_is_image:
1439  * @obj: a pointer to the #AtspiAccessible instance to query.
1440  *
1441  * Query whether the specified #AtspiAccessible implements the
1442  * #AtspiImage interface.
1443  *
1444  * Returns: #TRUE if @obj implements the #AtspiImage interface,
1445  *          #FALSE otherwise.
1446 **/
1447 gboolean
1448 atspi_accessible_is_image (AtspiAccessible *obj)
1449 {
1450   return _atspi_accessible_is_a (obj,
1451                               atspi_interface_image);
1452 }
1453
1454 /**
1455  * atspi_accessible_is_selection:
1456  * @obj: a pointer to the #AtspiAccessible instance to query.
1457  *
1458  * Query whether the specified #AtspiAccessible implements the
1459  * #AtspiSelection interface.
1460  *
1461  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
1462  *          #FALSE otherwise.
1463 **/
1464 gboolean
1465 atspi_accessible_is_selection (AtspiAccessible *obj)
1466 {
1467   return _atspi_accessible_is_a (obj,
1468                               atspi_interface_selection);
1469 }
1470
1471 /**
1472  * atspi_accessible_is_table:
1473  * @obj: a pointer to the #AtspiAccessible instance to query.
1474  *
1475  * Query whether the specified #AtspiAccessible implements the
1476  * #AtspiTable interface.
1477  *
1478  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1479  *          #FALSE otherwise.
1480 **/
1481 gboolean
1482 atspi_accessible_is_table (AtspiAccessible *obj)
1483 {
1484   return _atspi_accessible_is_a (obj,
1485                               atspi_interface_table);
1486 }
1487
1488 /**
1489  * atspi_accessible_is_table_cell:
1490  * @obj: a pointer to the #AtspiAccessible instance to query.
1491  *
1492  * Query whether the specified #AtspiAccessible implements the
1493  * #AtspiTableCell interface.
1494  *
1495  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1496  *          #FALSE otherwise.
1497 **/
1498 gboolean
1499 atspi_accessible_is_table_cell (AtspiAccessible *obj)
1500 {
1501   return _atspi_accessible_is_a (obj,
1502                               atspi_interface_table_cell);
1503 }
1504
1505 /**
1506  * atspi_accessible_is_streamable_content:
1507  * @obj: a pointer to the #AtspiAccessible instance to query.
1508  *
1509  * Query whether the specified #AtspiAccessible implements the
1510  * #AtspiStreamableContent interface.
1511  *
1512  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
1513  *          #FALSE otherwise.
1514 **/
1515 gboolean
1516 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
1517 {
1518 #if 0
1519   return _atspi_accessible_is_a (obj,
1520                               atspi_interface_streamable_content);
1521 #else
1522   g_warning ("Streamable content not implemented");
1523   return FALSE;
1524 #endif
1525 }
1526
1527 /**
1528  * atspi_accessible_is_text:
1529  * @obj: a pointer to the #AtspiAccessible instance to query.
1530  *
1531  * Query whether the specified #AtspiAccessible implements the
1532  * #AtspiText interface.
1533  *
1534  * Returns: #TRUE if @obj implements the #AtspiText interface,
1535  *          #FALSE otherwise.
1536 **/
1537 gboolean
1538 atspi_accessible_is_text (AtspiAccessible *obj)
1539 {
1540   return _atspi_accessible_is_a (obj,
1541                               atspi_interface_text);
1542 }
1543
1544 /**
1545  * atspi_accessible_is_value:
1546  * @obj: a pointer to the #AtspiAccessible instance to query.
1547  *
1548  * Query whether the specified #AtspiAccessible implements the
1549  * #AtspiValue interface.
1550  *
1551  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1552  *          #FALSE otherwise.
1553 **/
1554 gboolean
1555 atspi_accessible_is_value (AtspiAccessible *obj)
1556 {
1557   return _atspi_accessible_is_a (obj,
1558                               atspi_interface_value);
1559 }
1560
1561 /**
1562  * atspi_accessible_get_action: (rename-to atspi_accessible_get_action_iface)
1563  * @obj: a pointer to the #AtspiAccessible instance to query.
1564  *
1565  * Gets the #AtspiAction interface for an #AtspiAccessible.
1566  *
1567  * Returns: (transfer full): a pointer to an #AtspiAction interface
1568  *          instance, or NULL if @obj does not implement #AtspiAction.
1569  *
1570  * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
1571  **/
1572 AtspiAction *
1573 atspi_accessible_get_action (AtspiAccessible *accessible)
1574 {
1575   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1576           g_object_ref (ATSPI_ACTION (accessible)) : NULL);
1577 }
1578
1579 /**
1580  * atspi_accessible_get_action_iface:
1581  * @obj: a pointer to the #AtspiAccessible instance to query.
1582  *
1583  * Gets the #AtspiAction interface for an #AtspiAccessible.
1584  *
1585  * Returns: (transfer full): a pointer to an #AtspiAction interface
1586  *          instance, or NULL if @obj does not implement #AtspiAction.
1587  **/
1588 AtspiAction *
1589 atspi_accessible_get_action_iface (AtspiAccessible *accessible)
1590 {
1591   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1592           g_object_ref (ATSPI_ACTION (accessible)) : NULL);
1593 }
1594
1595 /**
1596  * atspi_accessible_get_collection: (rename-to atspi_accessible_get_collection_iface)
1597  * @obj: a pointer to the #AtspiAccessible instance to query.
1598  *
1599  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1600  *
1601  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1602  *          instance, or NULL if @obj does not implement #AtspiCollection.
1603  *
1604  * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
1605  **/
1606 AtspiCollection *
1607 atspi_accessible_get_collection (AtspiAccessible *accessible)
1608 {
1609   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1610           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
1611 }
1612
1613 /**
1614  * atspi_accessible_get_collection_iface:
1615  * @obj: a pointer to the #AtspiAccessible instance to query.
1616  *
1617  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1618  *
1619  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1620  *          instance, or NULL if @obj does not implement #AtspiCollection.
1621  **/
1622 AtspiCollection *
1623 atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
1624 {
1625   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1626           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
1627 }
1628
1629 /**
1630  * atspi_accessible_get_component: (rename-to atspi_accessible_get_component_iface)
1631  * @obj: a pointer to the #AtspiAccessible instance to query.
1632  *
1633  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1634  *
1635  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1636  *          instance, or NULL if @obj does not implement #AtspiComponent.
1637  *
1638  * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
1639  **/
1640 AtspiComponent *
1641 atspi_accessible_get_component (AtspiAccessible *obj)
1642 {
1643   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1644           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1645 }
1646
1647 /**
1648  * atspi_accessible_get_component_iface:
1649  * @obj: a pointer to the #AtspiAccessible instance to query.
1650  *
1651  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1652  *
1653  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1654  *          instance, or NULL if @obj does not implement #AtspiComponent.
1655  **/
1656 AtspiComponent *
1657 atspi_accessible_get_component_iface (AtspiAccessible *obj)
1658 {
1659   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1660           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1661 }
1662
1663 /**
1664  * atspi_accessible_get_document: (rename-to atspi_accessible_get_document_iface)
1665  * @obj: a pointer to the #AtspiAccessible instance to query.
1666  *
1667  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1668  *
1669  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1670  *          instance, or NULL if @obj does not implement #AtspiDocument.
1671  *
1672  * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
1673  **/
1674 AtspiDocument *
1675 atspi_accessible_get_document (AtspiAccessible *accessible)
1676 {
1677   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1678           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
1679 }
1680
1681 /**
1682  * atspi_accessible_get_document_iface:
1683  * @obj: a pointer to the #AtspiAccessible instance to query.
1684  *
1685  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1686  *
1687  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1688  *          instance, or NULL if @obj does not implement #AtspiDocument.
1689  **/
1690 AtspiDocument *
1691 atspi_accessible_get_document_iface (AtspiAccessible *accessible)
1692 {
1693   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1694           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
1695 }
1696
1697 /**
1698  * atspi_accessible_get_editable_text: (rename-to atspi_accessible_get_editable_text_iface)
1699  * @obj: a pointer to the #AtspiAccessible instance to query.
1700  *
1701  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1702  *
1703  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1704  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1705  *
1706  * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
1707  **/
1708 AtspiEditableText *
1709 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1710 {
1711   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1712           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
1713 }
1714
1715 /**
1716  * atspi_accessible_get_editable_text_iface:
1717  * @obj: a pointer to the #AtspiAccessible instance to query.
1718  *
1719  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1720  *
1721  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1722  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1723  **/
1724 AtspiEditableText *
1725 atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
1726 {
1727   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1728           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
1729 }
1730
1731 /**
1732  * atspi_accessible_get_hyperlink:
1733  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1734  *
1735  * Gets the #AtspiHyperlink interface for an #AtspiAccessible.
1736  *
1737  * Returns: (transfer full): the #AtspiHyperlink object associated with
1738  *          the given #AtspiAccessible, or NULL if not supported.
1739  **/
1740 AtspiHyperlink *
1741 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1742 {
1743   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1744           _atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1745 }
1746
1747 /**
1748  * atspi_accessible_get_hypertext: (rename-to atspi_accessible_get_hypertext_iface)
1749  * @obj: a pointer to the #AtspiAccessible instance to query.
1750  *
1751  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1752  *
1753  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1754  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1755  *
1756  * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
1757  **/
1758 AtspiHypertext *
1759 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1760 {
1761   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1762           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
1763 }
1764
1765 /**
1766  * atspi_accessible_get_hypertext_iface:
1767  * @obj: a pointer to the #AtspiAccessible instance to query.
1768  *
1769  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1770  *
1771  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1772  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1773  **/
1774 AtspiHypertext *
1775 atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
1776 {
1777   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1778           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
1779 }
1780
1781 /**
1782  * atspi_accessible_get_image: (rename-to atspi_accessible_get_image_iface)
1783  * @obj: a pointer to the #AtspiAccessible instance to query.
1784  *
1785  * Gets the #AtspiImage interface for an #AtspiAccessible.
1786  *
1787  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1788  *          NULL if @obj does not implement #AtspiImage.
1789  *
1790  * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
1791  **/
1792 AtspiImage *
1793 atspi_accessible_get_image (AtspiAccessible *accessible)
1794 {
1795   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1796           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
1797 }
1798
1799 /**
1800  * atspi_accessible_get_image_iface:
1801  * @obj: a pointer to the #AtspiAccessible instance to query.
1802  *
1803  * Gets the #AtspiImage interface for an #AtspiAccessible.
1804  *
1805  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1806  *          NULL if @obj does not implement #AtspiImage.
1807  **/
1808 AtspiImage *
1809 atspi_accessible_get_image_iface (AtspiAccessible *accessible)
1810 {
1811   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1812           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
1813 }
1814
1815 /**
1816  * atspi_accessible_get_selection: (rename-to atspi_accessible_get_selection_iface)
1817  * @obj: a pointer to the #AtspiAccessible instance to query.
1818  *
1819  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1820  *
1821  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1822  *          instance, or NULL if @obj does not implement #AtspiSelection.
1823  *
1824  * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
1825  **/
1826 AtspiSelection *
1827 atspi_accessible_get_selection (AtspiAccessible *accessible)
1828 {
1829   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1830           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
1831 }
1832
1833 /**
1834  * atspi_accessible_get_selection_iface:
1835  * @obj: a pointer to the #AtspiAccessible instance to query.
1836  *
1837  * Gets the #AtspiSelection interface for an #AtspiAccessible.
1838  *
1839  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1840  *          instance, or NULL if @obj does not implement #AtspiSelection.
1841  **/
1842 AtspiSelection *
1843 atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
1844 {
1845   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1846           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
1847 }
1848
1849 #if 0
1850 /**
1851  * atspi_accessible_get_streamable_content:
1852  * @obj: a pointer to the #AtspiAccessible instance to query.
1853  *
1854  * Gets the #AtspiStreamableContent interface for an #AtspiAccessible.
1855  *
1856  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1857  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1858  **/
1859 AtspiStreamableContent *
1860 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1861 {
1862   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1863           accessible : NULL);
1864 }
1865 #endif
1866
1867 /**
1868  * atspi_accessible_get_table: (rename-to atspi_accessible_get_table_iface)
1869  * @obj: a pointer to the #AtspiAccessible instance to query.
1870  *
1871  * Gets the #AtspiTable interface for an #AtspiAccessible.
1872  *
1873  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1874  *          NULL if @obj does not implement #AtspiTable.
1875  *
1876  * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
1877  **/
1878 AtspiTable *
1879 atspi_accessible_get_table (AtspiAccessible *obj)
1880 {
1881   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1882           g_object_ref (ATSPI_TABLE (obj)) : NULL);
1883 }
1884
1885 /**
1886  * atspi_accessible_get_table_iface:
1887  * @obj: a pointer to the #AtspiAccessible instance to query.
1888  *
1889  * Gets the #AtspiTable interface for an #AtspiAccessible.
1890  *
1891  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1892  *          NULL if @obj does not implement #AtspiTable.
1893  **/
1894 AtspiTable *
1895 atspi_accessible_get_table_iface (AtspiAccessible *obj)
1896 {
1897   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1898           g_object_ref (ATSPI_TABLE (obj)) : NULL);
1899 }
1900
1901 /**
1902  * atspi_accessible_get_table_cell:
1903  * @obj: a pointer to the #AtspiAccessible instance to query.
1904  *
1905  * Gets the #AtspiTableCell interface for an #AtspiAccessible.
1906  *
1907  * Returns: (transfer full): a pointer to an #AtspiTableCell interface instance,
1908  *          or NULL if @obj does not implement #AtspiTable.
1909  **/
1910 AtspiTableCell *
1911 atspi_accessible_get_table_cell (AtspiAccessible *obj)
1912 {
1913   return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ?
1914           g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
1915 }
1916
1917 /**
1918  * atspi_accessible_get_text: (rename-to atspi_accessible_get_text_iface)
1919  * @obj: a pointer to the #AtspiAccessible instance to query.
1920  *
1921  * Gets the #AtspiTable interface for an #AtspiAccessible.
1922  *
1923  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1924  *          NULL if @obj does not implement #AtspiText.
1925  *
1926  * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
1927  **/
1928 AtspiText *
1929 atspi_accessible_get_text (AtspiAccessible *obj)
1930 {
1931   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1932           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1933 }
1934
1935 /**
1936  * atspi_accessible_get_text_iface:
1937  * @obj: a pointer to the #AtspiAccessible instance to query.
1938  *
1939  * Gets the #AtspiTable interface for an #AtspiAccessible.
1940  *
1941  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1942  *          NULL if @obj does not implement #AtspiText.
1943  **/
1944 AtspiText *
1945 atspi_accessible_get_text_iface (AtspiAccessible *obj)
1946 {
1947   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1948           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1949 }
1950
1951 /**
1952  * atspi_accessible_get_value: (rename-to atspi_accessible_get_value_iface)
1953  * @obj: a pointer to the #AtspiAccessible instance to query.
1954  *
1955  * Gets the #AtspiTable interface for an #AtspiAccessible.
1956  *
1957  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1958  *          NULL if @obj does not implement #AtspiValue.
1959  *
1960  * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
1961  **/
1962 AtspiValue *
1963 atspi_accessible_get_value (AtspiAccessible *accessible)
1964 {
1965   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1966           g_object_ref (ATSPI_VALUE (accessible)) : NULL);
1967 }
1968
1969 /**
1970  * atspi_accessible_get_value_iface:
1971  * @obj: a pointer to the #AtspiAccessible instance to query.
1972  *
1973  * Gets the #AtspiTable interface for an #AtspiAccessible.
1974  *
1975  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1976  *          NULL if @obj does not implement #AtspiValue.
1977  **/
1978 AtspiValue *
1979 atspi_accessible_get_value_iface (AtspiAccessible *accessible)
1980 {
1981   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1982           g_object_ref (ATSPI_VALUE (accessible)) : NULL);
1983 }
1984
1985 static void
1986 append_const_val (GArray *array, const gchar *val)
1987 {
1988   gchar *dup = g_strdup (val);
1989
1990   if (dup)
1991     g_array_append_val (array, dup);
1992 }
1993
1994 /**
1995  * atspi_accessible_get_interfaces:
1996  * @obj: The #AtspiAccessible to query.
1997  *
1998  * A set of pointers to all interfaces supported by an #AtspiAccessible.
1999  *
2000  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
2001  *          describing the interfaces supported by the object.  Interfaces are
2002  *          denoted in short-hand (i.e. "Component", "Text" etc.).
2003  **/
2004 GArray *
2005 atspi_accessible_get_interfaces (AtspiAccessible *obj)
2006 {
2007   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
2008
2009   g_return_val_if_fail (obj != NULL, NULL);
2010
2011   append_const_val (ret, "Accessible");
2012   if (atspi_accessible_is_action (obj))
2013     append_const_val (ret, "Action");
2014   if (atspi_accessible_is_collection (obj))
2015     append_const_val (ret, "Collection");
2016   if (atspi_accessible_is_component (obj))
2017     append_const_val (ret, "Component");
2018   if (atspi_accessible_is_document (obj))
2019     append_const_val (ret, "Document");
2020   if (atspi_accessible_is_editable_text (obj))
2021     append_const_val (ret, "EditableText");
2022   if (atspi_accessible_is_hypertext (obj))
2023     append_const_val (ret, "Hypertext");
2024   if (atspi_accessible_is_hyperlink (obj))
2025     append_const_val (ret, "Hyperlink");
2026   if (atspi_accessible_is_image (obj))
2027     append_const_val (ret, "Image");
2028   if (atspi_accessible_is_selection (obj))
2029     append_const_val (ret, "Selection");
2030   if (atspi_accessible_is_table (obj))
2031     append_const_val (ret, "Table");
2032   if (atspi_accessible_is_table_cell (obj))
2033     append_const_val (ret, "TableCell");
2034   if (atspi_accessible_is_text (obj))
2035     append_const_val (ret, "Text");
2036   if (atspi_accessible_is_value (obj))
2037     append_const_val (ret, "Value");
2038
2039   return ret;
2040 }
2041
2042 AtspiAccessible *
2043 _atspi_accessible_new (AtspiApplication *app, const gchar *path)
2044 {
2045   AtspiAccessible *accessible;
2046
2047   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
2048   g_return_val_if_fail (accessible != NULL, NULL);
2049
2050   accessible->parent.app = g_object_ref (app);
2051   accessible->parent.path = g_strdup (path);
2052
2053   return accessible;
2054 }
2055
2056 /**
2057  * atspi_accessible_set_cache_mask:
2058  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
2059  *             the root of an application.
2060  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
2061  *
2062  * Sets the type of data to cache for accessibles.
2063  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
2064  * then the desktop's cache flag will be used.
2065  * If the desktop's cache flag is also undefined, then all possible data will
2066  * be cached.
2067  * This function is intended to work around bugs in toolkits where the proper
2068  * events are not raised / to aid in testing for such bugs.
2069  **/
2070 void
2071 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
2072 {
2073   g_return_if_fail (accessible != NULL);
2074   g_return_if_fail (accessible->parent.app != NULL);
2075   g_return_if_fail (accessible == accessible->parent.app->root);
2076   accessible->parent.app->cache = mask;
2077   enable_caching = TRUE;
2078 }
2079
2080 /**
2081  * atspi_accessible_clear_cache:
2082  * @accessible: The #AtspiAccessible whose cache to clear.
2083  *
2084  * Clears the cached information for the given accessible and all of its
2085  * descendants.
2086  */
2087 void
2088 atspi_accessible_clear_cache (AtspiAccessible *accessible)
2089 {
2090   GList *l;
2091
2092   if (accessible)
2093   {
2094     accessible->cached_properties = ATSPI_CACHE_NONE;
2095     for (l = accessible->children; l; l = l->next)
2096       atspi_accessible_clear_cache (l->data);
2097   }
2098 }
2099
2100 /**
2101  * atspi_accessible_get_process_id:
2102  * @accessible: The #AtspiAccessible to query.
2103  * @error: a pointer to a %NULL #GError pointer
2104  *
2105  * Returns the process id associated with the given accessible.  Mainly
2106  * added for debugging; it is a shortcut to explicitly querying the
2107  * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
2108  *
2109  * Returns: The process ID or undetermined value if @error is set.
2110  **/
2111 guint
2112 atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
2113 {
2114   DBusMessage *message, *reply;
2115   DBusConnection *bus = _atspi_bus ();
2116   dbus_uint32_t pid = -1;
2117   DBusError d_error;
2118
2119   if (!accessible->parent.app || !accessible->parent.app->bus_name)
2120     {
2121       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
2122       return -1;
2123     }
2124
2125   message = dbus_message_new_method_call ("org.freedesktop.DBus",
2126                                           "/org/freedesktop/DBus",
2127                                           "org.freedesktop.DBus",
2128                                           "GetConnectionUnixProcessID");
2129   dbus_message_append_args (message, DBUS_TYPE_STRING,
2130                             &accessible->parent.app->bus_name,
2131                             DBUS_TYPE_INVALID);
2132   dbus_error_init (&d_error);
2133   reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
2134   dbus_message_unref (message);
2135   if (reply)
2136   {
2137     if (!strcmp (dbus_message_get_signature (reply), "u"))
2138       dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
2139     dbus_message_unref (reply);
2140   }
2141   if (dbus_error_is_set (&d_error))
2142     {
2143       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
2144       dbus_error_free (&d_error);
2145     }
2146   return pid;
2147 }
2148
2149 AtspiCache
2150 _atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
2151 {
2152   AtspiCache mask;
2153
2154   if (!accessible->parent.app)
2155     return ATSPI_CACHE_NONE;
2156
2157  mask = accessible->parent.app->cache;
2158   if (mask == ATSPI_CACHE_UNDEFINED &&
2159       accessible->parent.app->root &&
2160       accessible->parent.app->root->accessible_parent)
2161   {
2162     AtspiAccessible *desktop = atspi_get_desktop (0);
2163     mask = desktop->parent.app->cache;
2164     g_object_unref (desktop);
2165   }
2166
2167   if (mask == ATSPI_CACHE_UNDEFINED)
2168     mask = ATSPI_CACHE_DEFAULT;
2169
2170   return mask;
2171 }
2172
2173 gboolean
2174 _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
2175 {
2176   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
2177   AtspiCache result = accessible->cached_properties & mask & flag;
2178   if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
2179     return FALSE;
2180   return (result != 0 && (atspi_main_loop || enable_caching ||
2181                           flag == ATSPI_CACHE_INTERFACES) &&
2182           !atspi_no_cache);
2183 }
2184
2185 void
2186 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
2187 {
2188   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
2189
2190   accessible->cached_properties |= flag & mask;
2191 }
2192
2193 /**
2194  * atspi_accessible_get_locale:
2195  * @accessible: an #AtspiAccessible
2196  *
2197  * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
2198  * of @accessible.
2199  *
2200  * Since: 2.7.91
2201  *
2202  * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
2203  *          locale of @accessible.
2204  **/
2205 const gchar*
2206 atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
2207 {
2208   gchar *locale;
2209
2210   g_return_val_if_fail (accessible != NULL, NULL);
2211
2212   locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
2213   if (!locale)
2214   {
2215     if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
2216                                    "Locale", error, "s", &locale))
2217       return NULL;
2218     if (locale)
2219       g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
2220                                g_free);
2221   }
2222   return locale;
2223 }
2224
2225 void
2226 free_value (gpointer data)
2227 {
2228   GValue *value = data;
2229
2230   g_value_unset (value);
2231   g_free (value);
2232 }
2233
2234 GHashTable *
2235 _atspi_accessible_ref_cache (AtspiAccessible *accessible)
2236 {
2237   AtspiAccessiblePrivate *priv = accessible->priv;
2238
2239   priv->cache_ref_count++;
2240   if (priv->cache)
2241     return g_hash_table_ref (priv->cache);
2242   priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2243                                        free_value);
2244   return priv->cache;
2245 }
2246
2247 void
2248 _atspi_accessible_unref_cache (AtspiAccessible *accessible)
2249 {
2250   AtspiAccessiblePrivate *priv = accessible->priv;
2251
2252   if (priv->cache)
2253   {
2254     g_hash_table_unref (priv->cache);
2255     if (--priv->cache_ref_count == 0)
2256       priv->cache = NULL;
2257   }
2258 }