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