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