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