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