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