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