e5a2c7c8a89fbc153ccd699dd9a4959401a28797
[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 /**
989  * atspi_accessible_get_child_at_index:
990  * @obj: a pointer to the #AtspiAccessible object on which to operate.
991  * @child_index: a #long indicating which child is specified.
992  *
993  * Gets the #AtspiAccessible child of an #AtspiAccessible object at a given index.
994  *
995  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
996  * index @child_index or NULL on exception.
997  **/
998 AtspiAccessible *
999 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
1000                             gint    child_index,
1001                             GError **error)
1002 {
1003   AtspiAccessible *child;
1004   DBusMessage *reply;
1005
1006   g_return_val_if_fail (obj != NULL, NULL);
1007
1008   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
1009   {
1010     if (!obj->children)
1011       return NULL;      /* assume disposed */
1012
1013     child = g_ptr_array_index (obj->children, child_index);
1014     if (child)
1015       return g_object_ref (child);
1016   }
1017
1018   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
1019                                    "GetChildAtIndex", error, "i", child_index);
1020   child = _atspi_dbus_return_accessible_from_message (reply);
1021
1022   if (!child)
1023     return NULL;
1024
1025   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
1026   {
1027       if (child_index >= obj->children->len)
1028         g_ptr_array_set_size (obj->children, child_index + 1);
1029     g_ptr_array_index (obj->children, child_index) = g_object_ref (child);
1030   }
1031   return child;
1032 }
1033
1034 /**
1035  * atspi_accessible_get_index_in_parent:
1036  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1037  *
1038  * Gets the index of an #AtspiAccessible object within its parent's 
1039  * #AtspiAccessible children list.
1040  *
1041  * Returns: a #glong indicating the index of the #AtspiAccessible object
1042  *          in its parent,
1043  *          or -1 if @obj has no containing parent or on exception.
1044  **/
1045 gint
1046 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
1047 {
1048   gint i = 0;
1049   dbus_int32_t ret = -1;
1050
1051   g_return_val_if_fail (obj != NULL, -1);
1052   if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
1053   {
1054     if (!obj->accessible_parent)
1055       return -1;
1056
1057     if (!_atspi_accessible_test_cache (obj->accessible_parent, ATSPI_CACHE_CHILDREN) || !obj->accessible_parent->children)
1058         goto dbus;
1059
1060     for (i = 0; i < obj->accessible_parent->children->len; i++)
1061       if (atspi_accessible_is_equal (g_ptr_array_index (obj->accessible_parent->children, i), obj))
1062         return i;
1063   }
1064
1065 dbus:
1066   _atspi_dbus_call (obj, atspi_interface_accessible,
1067                     "GetIndexInParent", NULL, "=>i", &ret);
1068   return ret;
1069 }
1070
1071 typedef struct
1072 {
1073   dbus_uint32_t type;
1074   GArray *targets;
1075 } Accessibility_Relation;
1076
1077 /**
1078  * atspi_accessible_get_relation_set:
1079  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1080  *
1081  * Gets the set of #AtspiRelation objects which describes this #AtspiAccessible object's
1082  * relationships with other #AtspiAccessible objects.
1083  *
1084  * Returns: (element-type AtspiRelation*) (transfer full): a #GArray of
1085  *          #AtspiRelation pointers or NULL on exception.
1086  **/
1087 GArray *
1088 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
1089 {
1090   DBusMessage *reply;
1091   DBusMessageIter iter, iter_array;
1092   GArray *ret;
1093
1094   g_return_val_if_fail (obj != NULL, NULL);
1095
1096   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
1097   if (!reply)
1098     return NULL;
1099   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
1100
1101   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
1102   dbus_message_iter_init (reply, &iter);
1103   dbus_message_iter_recurse (&iter, &iter_array);
1104   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
1105   {
1106     AtspiRelation *relation;
1107     relation = _atspi_relation_new_from_iter (&iter_array);
1108     ret = g_array_append_val (ret, relation);
1109     dbus_message_iter_next (&iter_array);
1110   }
1111   dbus_message_unref (reply);
1112   return ret;
1113 }
1114
1115 /**
1116  * atspi_accessible_get_role:
1117  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1118  *
1119  * Gets the UI role played by an #AtspiAccessible object.
1120  * This role's name can be obtained via atspi_accessible_get_role_name ().
1121  *
1122  * Returns: the #AtspiRole of an #AtspiAccessible object.
1123  *
1124  **/
1125 AtspiRole
1126 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
1127 {
1128   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
1129
1130   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ROLE))
1131   {
1132     dbus_uint32_t role;
1133     /* TODO: Make this a property */
1134     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
1135     {
1136       obj->role = role;
1137     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
1138     }
1139   }
1140   return obj->role;
1141 }
1142
1143 /**
1144  * atspi_accessible_get_role_name:
1145  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1146  *
1147  * Gets a UTF-8 string corresponding to the name of the role played by an object.
1148  * This method will return useful values for roles that fall outside the
1149  * enumeration used in atspi_accessible_get_role ().
1150  *
1151  * Returns: a UTF-8 string specifying the type of UI role played by an
1152  * #AtspiAccessible object.
1153  *
1154  **/
1155 gchar *
1156 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
1157 {
1158   gchar *retval = NULL;
1159   AtspiRole role;
1160
1161   g_return_val_if_fail (obj != NULL, NULL);
1162
1163   role = atspi_accessible_get_role (obj, error);
1164   if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
1165     return atspi_role_get_name (role);
1166
1167   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
1168
1169   if (!retval)
1170     retval = g_strdup ("");
1171
1172   return retval;
1173 }
1174
1175 /**
1176  * atspi_accessible_get_localized_role_name:
1177  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1178  *
1179  * Gets a UTF-8 string corresponding to the name of the role played by an
1180  * object, translated to the current locale.
1181  * This method will return useful values for roles that fall outside the
1182  * enumeration used in atspi_accessible_getRole ().
1183  *
1184  * Returns: a localized, UTF-8 string specifying the type of UI role played
1185  * by an #AtspiAccessible object.
1186  *
1187  **/
1188 gchar *
1189 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
1190 {
1191   char *retval = NULL;
1192
1193   g_return_val_if_fail (obj != NULL, NULL);
1194
1195   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
1196
1197   if (!retval)
1198     return g_strdup ("");
1199
1200   return retval;
1201 }
1202
1203 static AtspiStateSet *
1204 defunct_set ()
1205 {
1206   AtspiStateSet *set = atspi_state_set_new (NULL);
1207   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
1208   return set;
1209 }
1210
1211 /**
1212  * atspi_accessible_get_state_set:
1213  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1214  *
1215  * Gets the states currently held by an object.
1216  *
1217  * Returns: (transfer full): a pointer to an #AtspiStateSet representing an
1218  * object's current state set.
1219  **/
1220 AtspiStateSet *
1221 atspi_accessible_get_state_set (AtspiAccessible *obj)
1222 {
1223   /* TODO: Should take a GError **, but would be an API break */
1224   if (!obj->parent.app || !obj->parent.app->bus)
1225     return defunct_set ();
1226
1227   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
1228   {
1229     DBusMessage *reply;
1230     DBusMessageIter iter;
1231     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
1232                                       "GetState", NULL, "");
1233     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
1234     dbus_message_iter_init (reply, &iter);
1235     _atspi_dbus_set_state (obj, &iter);
1236     dbus_message_unref (reply);
1237     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
1238   }
1239   return g_object_ref (obj->states);
1240 }
1241
1242 /**
1243  * atspi_accessible_get_attributes:
1244  * @obj: The #AtspiAccessible being queried.
1245  *
1246  * Gets the #AttributeSet representing any assigned
1247  * name-value pair attributes or annotations for this object.
1248  * For typographic, textual, or textually-semantic attributes, see
1249  * atspi_text_get_attributes instead.
1250  *
1251  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
1252  * attributes assigned to this object.
1253  */
1254 GHashTable *
1255 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
1256 {
1257   DBusMessage *message;
1258
1259     g_return_val_if_fail (obj != NULL, NULL);
1260
1261   if (obj->priv->cache)
1262   {
1263     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
1264     if (val)
1265       return g_value_dup_boxed (val);
1266   }
1267
1268   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
1269   {
1270     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
1271                                         "GetAttributes", error, "");
1272     g_clear_pointer (&(obj->attributes), g_hash_table_unref);
1273
1274     obj->attributes = _atspi_dbus_return_hash_from_message (message);
1275     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES);
1276   }
1277
1278   if (!obj->attributes)
1279     return NULL;
1280   return g_hash_table_ref (obj->attributes);
1281 }
1282
1283 static void
1284 add_to_attribute_array (gpointer key, gpointer value, gpointer data)
1285 {
1286   GArray **array = (GArray **)data;
1287   gchar *str = g_strconcat (key, ":", value, NULL);
1288   *array = g_array_append_val (*array, str);
1289 }
1290
1291 /**
1292  * atspi_accessible_get_attributes_as_array:
1293  * @obj: The #AtspiAccessible being queried.
1294  *
1295  * Gets a #GArray representing any assigned
1296  * name-value pair attributes or annotations for this object.
1297  * For typographic, textual, or textually-semantic attributes, see
1298  * atspi_text_get_attributes_as_array instead.
1299  *
1300  * Returns: (element-type gchar*) (transfer full): The name-value-pair
1301  *          attributes assigned to this object.
1302  */
1303 GArray *
1304 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
1305 {
1306   DBusMessage *message;
1307
1308     g_return_val_if_fail (obj != NULL, NULL);
1309
1310   if (obj->priv->cache)
1311   {
1312     GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
1313     if (val)
1314     {
1315       GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
1316       GHashTable *attributes = g_value_get_boxed (val);
1317       g_hash_table_foreach (attributes, add_to_attribute_array, &array);
1318       return array;
1319     }
1320   }
1321
1322   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
1323   return _atspi_dbus_return_attribute_array_from_message (message);
1324 }
1325
1326 /**
1327  * atspi_accessible_get_application:
1328  * @obj: The #AtspiAccessible being queried.
1329  *
1330  * Gets the containing #AtspiApplication for an object.
1331  *
1332  * Returns: (transfer full): the containing #AtspiApplication instance for
1333  *          this object.
1334  */
1335 AtspiAccessible *
1336 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
1337 {
1338   AtspiAccessible *parent;
1339
1340   g_object_ref (obj);
1341   for (;;)
1342   {
1343     parent = atspi_accessible_get_parent (obj, NULL);
1344     if (!parent && obj->parent.app &&
1345         atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
1346     {
1347       AtspiAccessible *root = g_object_ref (obj->parent.app->root);
1348       if (root)
1349       {
1350         g_object_unref (obj);
1351         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
1352         {
1353           g_object_unref (root);
1354           return NULL;
1355         }
1356         return root;
1357       }
1358     }
1359     if (!parent || atspi_accessible_is_equal (parent, obj) ||
1360         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
1361   {
1362     if (parent)
1363       g_object_unref (parent);
1364     return obj;
1365   }
1366     g_object_unref (obj);
1367     obj = parent;
1368   }
1369 }
1370
1371 /* Application-specific methods */
1372
1373 /**
1374  * atspi_accessible_get_toolkit_name:
1375  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1376  *
1377  * Gets the toolkit name for an #AtspiAccessible object.
1378  * Only works on application root objects.
1379  *
1380  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object or NULL on exception.
1381  **/
1382 gchar *
1383 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
1384 {
1385   g_return_val_if_fail (obj != NULL, NULL);
1386
1387   if (!obj->parent.app)
1388     return NULL;
1389
1390   if (!obj->parent.app->toolkit_name)
1391     _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
1392                               error, "s", &obj->parent.app->toolkit_name);
1393
1394   return g_strdup (obj->parent.app->toolkit_name);
1395 }
1396
1397 /**
1398  * atspi_accessible_get_toolkit_version:
1399  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1400  *
1401  * Gets the toolkit version for an #AtspiAccessible object.
1402  * Only works on application root objects.
1403  *
1404  * Returns: a UTF-8 string indicating the toolkit version for the #AtspiAccessible object or NULL on exception.
1405  **/
1406 gchar *
1407 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
1408 {
1409   g_return_val_if_fail (obj != NULL, NULL);
1410
1411   if (!obj->parent.app)
1412     return NULL;
1413
1414   if (!obj->parent.app->toolkit_version)
1415     _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
1416                               error, "s", &obj->parent.app->toolkit_version);
1417
1418   return g_strdup (obj->parent.app->toolkit_version);
1419 }
1420
1421 /**
1422  * atspi_accessible_get_atspi_version:
1423  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1424  *
1425  * Gets the AT-SPI IPC specification version supported by the application
1426  * pointed to by the #AtspiAccessible object.
1427  * Only works on application root objects.
1428  *
1429  * Returns: a UTF-8 string indicating the AT-SPI version for the #AtspiAccessible object or NULL on exception.
1430  **/
1431 gchar *
1432 atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
1433 {
1434   g_return_val_if_fail (obj != NULL, NULL);
1435
1436   if (!obj->parent.app)
1437     return NULL;
1438
1439   if (!obj->parent.app->atspi_version)
1440     _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
1441                               error, "s", &obj->parent.app->atspi_version);
1442
1443   return g_strdup (obj->parent.app->atspi_version);
1444 }
1445
1446 /**
1447  * atspi_accessible_get_id:
1448  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1449  *
1450  * Gets the application id for a #AtspiAccessible object.
1451  * Only works on application root objects.
1452  *
1453  * Returns: a positive #gint indicating the id for the #AtspiAccessible object
1454  * or -1 on exception.
1455  **/
1456 gint
1457 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
1458 {
1459   gint ret = -1;
1460
1461   g_return_val_if_fail (obj != NULL, -1);
1462
1463   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
1464       return -1;
1465   return ret;
1466 }
1467
1468 //TIZEN_ONLY(20230307) Provide post render callback to client
1469 /**
1470  * atspi_accessible_set_listen_post_render:
1471  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1472  * @enabled: a boolean true listen post render callback, false otherwise.
1473  *
1474  * Asks the UI Toolkit listen for the post render callback.
1475  **/
1476 void
1477 atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error)
1478 {
1479   g_return_if_fail (obj != NULL);
1480
1481   _atspi_dbus_call (obj, atspi_interface_accessible, "SetListenPostRender", error, "b", enabled, NULL);
1482 }
1483
1484 /* Interface query methods */
1485
1486 static gboolean
1487 _atspi_accessible_is_a (AtspiAccessible *accessible,
1488                       const char *interface_name)
1489 {
1490   int n;
1491
1492   if (accessible == NULL)
1493     {
1494       return FALSE;
1495     }
1496
1497   if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
1498   {
1499     DBusMessage *reply;
1500     DBusMessageIter iter;
1501     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
1502                                       "GetInterfaces", NULL, "");
1503     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
1504     dbus_message_iter_init (reply, &iter);
1505     _atspi_dbus_set_interfaces (accessible, &iter);
1506     dbus_message_unref (reply);
1507     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
1508   }
1509
1510   n = _atspi_get_iface_num (interface_name);
1511   if (n == -1) return FALSE;
1512   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
1513 }
1514
1515 /**
1516  * atspi_accessible_is_action:
1517  * @obj: a pointer to the #AtspiAccessible instance to query.
1518  *
1519  * Query whether the specified #AtspiAccessible implements the
1520  * #AtspiAction interface.
1521  *
1522  * Returns: #TRUE if @obj implements the #AtspiAction interface,
1523  *          #FALSE otherwise.
1524  **/
1525 gboolean
1526 atspi_accessible_is_action (AtspiAccessible *obj)
1527 {
1528   return _atspi_accessible_is_a (obj,
1529                               atspi_interface_action);
1530 }
1531
1532 /**
1533  * atspi_accessible_is_application:
1534  * @obj: a pointer to the #AtspiAccessible instance to query.
1535  *
1536  * Query whether the specified #AtspiAccessible implements the
1537  * #AtspiApplication interface.
1538  *
1539  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
1540  *          #FALSE otherwise.
1541  **/
1542 gboolean
1543 atspi_accessible_is_application (AtspiAccessible *obj)
1544 {
1545   return _atspi_accessible_is_a (obj,
1546                               atspi_interface_application);
1547 }
1548
1549 /**
1550  * atspi_accessible_is_collection:
1551  * @obj: a pointer to the #AtspiAccessible instance to query.
1552  *
1553  * Query whether the specified #AtspiAccessible implements the
1554  * #AtspiCollection interface.
1555  *
1556  * Returns: #TRUE if @obj implements the #AtspiCollection interface,
1557  *          #FALSE otherwise.
1558  **/
1559 gboolean
1560 atspi_accessible_is_collection (AtspiAccessible *obj)
1561 {
1562      return _atspi_accessible_is_a (obj,
1563                               atspi_interface_collection);
1564 }
1565
1566 /**
1567  * atspi_accessible_is_component:
1568  * @obj: a pointer to the #AtspiAccessible instance to query.
1569  *
1570  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
1571  *
1572  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
1573  *          #FALSE otherwise.
1574  **/
1575 gboolean
1576 atspi_accessible_is_component (AtspiAccessible *obj)
1577 {
1578   return _atspi_accessible_is_a (obj,
1579                               atspi_interface_component);
1580 }
1581
1582 /**
1583  * atspi_accessible_is_document:
1584  * @obj: a pointer to the #AtspiAccessible instance to query.
1585  *
1586  * Query whether the specified #AtspiAccessible implements the
1587  * #AtspiDocument interface.
1588  *
1589  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
1590  *          #FALSE otherwise.
1591  **/
1592 gboolean
1593 atspi_accessible_is_document (AtspiAccessible *obj)
1594 {
1595   return _atspi_accessible_is_a (obj,
1596                               atspi_interface_document);
1597 }
1598
1599 /**
1600  * atspi_accessible_is_editable_text:
1601  * @obj: a pointer to the #AtspiAccessible instance to query.
1602  *
1603  * Query whether the specified #AtspiAccessible implements the
1604  * #AtspiEditableText interface.
1605  *
1606  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
1607  *          #FALSE otherwise.
1608  **/
1609 gboolean
1610 atspi_accessible_is_editable_text (AtspiAccessible *obj)
1611 {
1612   return _atspi_accessible_is_a (obj,
1613                               atspi_interface_editable_text);
1614 }
1615
1616 /**
1617  * atspi_accessible_is_hypertext:
1618  * @obj: a pointer to the #AtspiAccessible instance to query.
1619  *
1620  * Query whether the specified #AtspiAccessible implements the
1621  * #AtspiHypertext interface.
1622  *
1623  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
1624  *          #FALSE otherwise.
1625  **/
1626 gboolean
1627 atspi_accessible_is_hypertext (AtspiAccessible *obj)
1628 {
1629   return _atspi_accessible_is_a (obj,
1630                               atspi_interface_hypertext);
1631 }
1632
1633 /**
1634  * atspi_accessible_is_hyperlink:
1635  * @obj: a pointer to the #AtspiAccessible instance to query.
1636  *
1637  * Query whether the specified #AtspiAccessible implements the
1638  * #AtspiHyperlink interface.
1639  *
1640  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
1641  *          #FALSE otherwise.
1642  **/
1643 gboolean
1644 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
1645 {
1646   return _atspi_accessible_is_a (obj,
1647                               atspi_interface_hyperlink);
1648 }
1649
1650 /**
1651  * atspi_accessible_is_image:
1652  * @obj: a pointer to the #AtspiAccessible instance to query.
1653  *
1654  * Query whether the specified #AtspiAccessible implements the
1655  * #AtspiImage interface.
1656  *
1657  * Returns: #TRUE if @obj implements the #AtspiImage interface,
1658  *          #FALSE otherwise.
1659 **/
1660 gboolean
1661 atspi_accessible_is_image (AtspiAccessible *obj)
1662 {
1663   return _atspi_accessible_is_a (obj,
1664                               atspi_interface_image);
1665 }
1666
1667 /**
1668  * atspi_accessible_is_selection:
1669  * @obj: a pointer to the #AtspiAccessible instance to query.
1670  *
1671  * Query whether the specified #AtspiAccessible implements the
1672  * #AtspiSelection interface.
1673  *
1674  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
1675  *          #FALSE otherwise.
1676 **/
1677 gboolean
1678 atspi_accessible_is_selection (AtspiAccessible *obj)
1679 {
1680   return _atspi_accessible_is_a (obj,
1681                               atspi_interface_selection);
1682 }
1683
1684 /**
1685  * atspi_accessible_is_table:
1686  * @obj: a pointer to the #AtspiAccessible instance to query.
1687  *
1688  * Query whether the specified #AtspiAccessible implements the
1689  * #AtspiTable interface.
1690  *
1691  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1692  *          #FALSE otherwise.
1693 **/
1694 gboolean
1695 atspi_accessible_is_table (AtspiAccessible *obj)
1696 {
1697   return _atspi_accessible_is_a (obj,
1698                               atspi_interface_table);
1699 }
1700
1701 /**
1702  * atspi_accessible_is_table_cell:
1703  * @obj: a pointer to the #AtspiAccessible instance to query.
1704  *
1705  * Query whether the specified #AtspiAccessible implements the
1706  * #AtspiTableCell interface.
1707  *
1708  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1709  *          #FALSE otherwise.
1710 **/
1711 gboolean
1712 atspi_accessible_is_table_cell (AtspiAccessible *obj)
1713 {
1714   return _atspi_accessible_is_a (obj,
1715                               atspi_interface_table_cell);
1716 }
1717
1718 /**
1719  * atspi_accessible_is_streamable_content:
1720  * @obj: a pointer to the #AtspiAccessible instance to query.
1721  *
1722  * Query whether the specified #AtspiAccessible implements the
1723  * #AtspiStreamableContent interface.
1724  *
1725  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
1726  *          #FALSE otherwise.
1727 **/
1728 gboolean
1729 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
1730 {
1731 #if 0
1732   return _atspi_accessible_is_a (obj,
1733                               atspi_interface_streamable_content);
1734 #else
1735   g_warning ("Streamable content not implemented");
1736   return FALSE;
1737 #endif
1738 }
1739
1740 /**
1741  * atspi_accessible_is_text:
1742  * @obj: a pointer to the #AtspiAccessible instance to query.
1743  *
1744  * Query whether the specified #AtspiAccessible implements the
1745  * #AtspiText interface.
1746  *
1747  * Returns: #TRUE if @obj implements the #AtspiText interface,
1748  *          #FALSE otherwise.
1749 **/
1750 gboolean
1751 atspi_accessible_is_text (AtspiAccessible *obj)
1752 {
1753   return _atspi_accessible_is_a (obj,
1754                               atspi_interface_text);
1755 }
1756
1757 /**
1758  * atspi_accessible_is_value:
1759  * @obj: a pointer to the #AtspiAccessible instance to query.
1760  *
1761  * Query whether the specified #AtspiAccessible implements the
1762  * #AtspiValue interface.
1763  *
1764  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1765  *          #FALSE otherwise.
1766 **/
1767 gboolean
1768 atspi_accessible_is_value (AtspiAccessible *obj)
1769 {
1770   return _atspi_accessible_is_a (obj,
1771                               atspi_interface_value);
1772 }
1773
1774 /**
1775  * atspi_accessible_get_action: (rename-to atspi_accessible_get_action_iface)
1776  * @obj: a pointer to the #AtspiAccessible instance to query.
1777  *
1778  * Gets the #AtspiAction interface for an #AtspiAccessible.
1779  *
1780  * Returns: (transfer full): a pointer to an #AtspiAction interface
1781  *          instance, or NULL if @obj does not implement #AtspiAction.
1782  *
1783  * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
1784  **/
1785 AtspiAction *
1786 atspi_accessible_get_action (AtspiAccessible *accessible)
1787 {
1788   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1789           g_object_ref (ATSPI_ACTION (accessible)) : NULL);
1790 }
1791
1792 /**
1793  * atspi_accessible_get_action_iface:
1794  * @obj: a pointer to the #AtspiAccessible instance to query.
1795  *
1796  * Gets the #AtspiAction interface for an #AtspiAccessible.
1797  *
1798  * Returns: (transfer full): a pointer to an #AtspiAction interface
1799  *          instance, or NULL if @obj does not implement #AtspiAction.
1800  **/
1801 AtspiAction *
1802 atspi_accessible_get_action_iface (AtspiAccessible *accessible)
1803 {
1804   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1805           g_object_ref (ATSPI_ACTION (accessible)) : NULL);
1806 }
1807
1808 /**
1809  * atspi_accessible_get_collection: (rename-to atspi_accessible_get_collection_iface)
1810  * @obj: a pointer to the #AtspiAccessible instance to query.
1811  *
1812  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1813  *
1814  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1815  *          instance, or NULL if @obj does not implement #AtspiCollection.
1816  *
1817  * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
1818  **/
1819 AtspiCollection *
1820 atspi_accessible_get_collection (AtspiAccessible *accessible)
1821 {
1822   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1823           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
1824 }
1825
1826 /**
1827  * atspi_accessible_get_collection_iface:
1828  * @obj: a pointer to the #AtspiAccessible instance to query.
1829  *
1830  * Gets the #AtspiCollection interface for an #AtspiAccessible.
1831  *
1832  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1833  *          instance, or NULL if @obj does not implement #AtspiCollection.
1834  **/
1835 AtspiCollection *
1836 atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
1837 {
1838   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1839           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
1840 }
1841
1842 /**
1843  * atspi_accessible_get_component: (rename-to atspi_accessible_get_component_iface)
1844  * @obj: a pointer to the #AtspiAccessible instance to query.
1845  *
1846  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1847  *
1848  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1849  *          instance, or NULL if @obj does not implement #AtspiComponent.
1850  *
1851  * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
1852  **/
1853 AtspiComponent *
1854 atspi_accessible_get_component (AtspiAccessible *obj)
1855 {
1856   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1857           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1858 }
1859
1860 /**
1861  * atspi_accessible_get_component_iface:
1862  * @obj: a pointer to the #AtspiAccessible instance to query.
1863  *
1864  * Gets the #AtspiComponent interface for an #AtspiAccessible.
1865  *
1866  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1867  *          instance, or NULL if @obj does not implement #AtspiComponent.
1868  **/
1869 AtspiComponent *
1870 atspi_accessible_get_component_iface (AtspiAccessible *obj)
1871 {
1872   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1873           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1874 }
1875
1876 /**
1877  * atspi_accessible_get_document: (rename-to atspi_accessible_get_document_iface)
1878  * @obj: a pointer to the #AtspiAccessible instance to query.
1879  *
1880  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1881  *
1882  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1883  *          instance, or NULL if @obj does not implement #AtspiDocument.
1884  *
1885  * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
1886  **/
1887 AtspiDocument *
1888 atspi_accessible_get_document (AtspiAccessible *accessible)
1889 {
1890   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1891           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
1892 }
1893
1894 /**
1895  * atspi_accessible_get_document_iface:
1896  * @obj: a pointer to the #AtspiAccessible instance to query.
1897  *
1898  * Gets the #AtspiDocument interface for an #AtspiAccessible.
1899  *
1900  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1901  *          instance, or NULL if @obj does not implement #AtspiDocument.
1902  **/
1903 AtspiDocument *
1904 atspi_accessible_get_document_iface (AtspiAccessible *accessible)
1905 {
1906   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1907           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
1908 }
1909
1910 /**
1911  * atspi_accessible_get_editable_text: (rename-to atspi_accessible_get_editable_text_iface)
1912  * @obj: a pointer to the #AtspiAccessible instance to query.
1913  *
1914  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1915  *
1916  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1917  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1918  *
1919  * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
1920  **/
1921 AtspiEditableText *
1922 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1923 {
1924   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1925           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
1926 }
1927
1928 /**
1929  * atspi_accessible_get_editable_text_iface:
1930  * @obj: a pointer to the #AtspiAccessible instance to query.
1931  *
1932  * Gets the #AtspiEditableText interface for an #AtspiAccessible.
1933  *
1934  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1935  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1936  **/
1937 AtspiEditableText *
1938 atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
1939 {
1940   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1941           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
1942 }
1943
1944 /**
1945  * atspi_accessible_get_hyperlink:
1946  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1947  *
1948  * Gets the #AtspiHyperlink interface for an #AtspiAccessible.
1949  *
1950  * Returns: (transfer full): the #AtspiHyperlink object associated with
1951  *          the given #AtspiAccessible, or NULL if not supported.
1952  **/
1953 AtspiHyperlink *
1954 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1955 {
1956   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1957           _atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1958 }
1959
1960 /**
1961  * atspi_accessible_get_hypertext: (rename-to atspi_accessible_get_hypertext_iface)
1962  * @obj: a pointer to the #AtspiAccessible instance to query.
1963  *
1964  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1965  *
1966  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1967  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1968  *
1969  * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
1970  **/
1971 AtspiHypertext *
1972 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1973 {
1974   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1975           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
1976 }
1977
1978 /**
1979  * atspi_accessible_get_hypertext_iface:
1980  * @obj: a pointer to the #AtspiAccessible instance to query.
1981  *
1982  * Gets the #AtspiHypertext interface for an #AtspiAccessible.
1983  *
1984  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1985  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1986  **/
1987 AtspiHypertext *
1988 atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
1989 {
1990   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1991           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
1992 }
1993
1994 /**
1995  * atspi_accessible_get_image: (rename-to atspi_accessible_get_image_iface)
1996  * @obj: a pointer to the #AtspiAccessible instance to query.
1997  *
1998  * Gets the #AtspiImage interface for an #AtspiAccessible.
1999  *
2000  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
2001  *          NULL if @obj does not implement #AtspiImage.
2002  *
2003  * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
2004  **/
2005 AtspiImage *
2006 atspi_accessible_get_image (AtspiAccessible *accessible)
2007 {
2008   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
2009           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
2010 }
2011
2012 /**
2013  * atspi_accessible_get_image_iface:
2014  * @obj: a pointer to the #AtspiAccessible instance to query.
2015  *
2016  * Gets the #AtspiImage interface for an #AtspiAccessible.
2017  *
2018  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
2019  *          NULL if @obj does not implement #AtspiImage.
2020  **/
2021 AtspiImage *
2022 atspi_accessible_get_image_iface (AtspiAccessible *accessible)
2023 {
2024   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
2025           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
2026 }
2027
2028 /**
2029  * atspi_accessible_get_selection: (rename-to atspi_accessible_get_selection_iface)
2030  * @obj: a pointer to the #AtspiAccessible instance to query.
2031  *
2032  * Gets the #AtspiSelection interface for an #AtspiAccessible.
2033  *
2034  * Returns: (transfer full): a pointer to an #AtspiSelection interface
2035  *          instance, or NULL if @obj does not implement #AtspiSelection.
2036  *
2037  * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
2038  **/
2039 AtspiSelection *
2040 atspi_accessible_get_selection (AtspiAccessible *accessible)
2041 {
2042   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
2043           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
2044 }
2045
2046 /**
2047  * atspi_accessible_get_selection_iface:
2048  * @obj: a pointer to the #AtspiAccessible instance to query.
2049  *
2050  * Gets the #AtspiSelection interface for an #AtspiAccessible.
2051  *
2052  * Returns: (transfer full): a pointer to an #AtspiSelection interface
2053  *          instance, or NULL if @obj does not implement #AtspiSelection.
2054  **/
2055 AtspiSelection *
2056 atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
2057 {
2058   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
2059           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
2060 }
2061
2062 #if 0
2063 /**
2064  * atspi_accessible_get_streamable_content:
2065  * @obj: a pointer to the #AtspiAccessible instance to query.
2066  *
2067  * Gets the #AtspiStreamableContent interface for an #AtspiAccessible.
2068  *
2069  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
2070  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
2071  **/
2072 AtspiStreamableContent *
2073 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
2074 {
2075   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
2076           accessible : NULL);
2077 }
2078 #endif
2079
2080 /**
2081  * atspi_accessible_get_table: (rename-to atspi_accessible_get_table_iface)
2082  * @obj: a pointer to the #AtspiAccessible instance to query.
2083  *
2084  * Gets the #AtspiTable interface for an #AtspiAccessible.
2085  *
2086  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
2087  *          NULL if @obj does not implement #AtspiTable.
2088  *
2089  * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
2090  **/
2091 AtspiTable *
2092 atspi_accessible_get_table (AtspiAccessible *obj)
2093 {
2094   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
2095           g_object_ref (ATSPI_TABLE (obj)) : NULL);
2096 }
2097
2098 /**
2099  * atspi_accessible_get_table_iface:
2100  * @obj: a pointer to the #AtspiAccessible instance to query.
2101  *
2102  * Gets the #AtspiTable interface for an #AtspiAccessible.
2103  *
2104  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
2105  *          NULL if @obj does not implement #AtspiTable.
2106  **/
2107 AtspiTable *
2108 atspi_accessible_get_table_iface (AtspiAccessible *obj)
2109 {
2110   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
2111           g_object_ref (ATSPI_TABLE (obj)) : NULL);
2112 }
2113
2114 /**
2115  * atspi_accessible_get_table_cell:
2116  * @obj: a pointer to the #AtspiAccessible instance to query.
2117  *
2118  * Gets the #AtspiTableCell interface for an #AtspiAccessible.
2119  *
2120  * Returns: (transfer full): a pointer to an #AtspiTableCell interface instance,
2121  *          or NULL if @obj does not implement #AtspiTable.
2122  **/
2123 AtspiTableCell *
2124 atspi_accessible_get_table_cell (AtspiAccessible *obj)
2125 {
2126   return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ?
2127           g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
2128 }
2129
2130 /**
2131  * atspi_accessible_get_text: (rename-to atspi_accessible_get_text_iface)
2132  * @obj: a pointer to the #AtspiAccessible instance to query.
2133  *
2134  * Gets the #AtspiTable interface for an #AtspiAccessible.
2135  *
2136  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
2137  *          NULL if @obj does not implement #AtspiText.
2138  *
2139  * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
2140  **/
2141 AtspiText *
2142 atspi_accessible_get_text (AtspiAccessible *obj)
2143 {
2144   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
2145           g_object_ref (ATSPI_TEXT (obj)) : NULL);
2146 }
2147
2148 /**
2149  * atspi_accessible_get_text_iface:
2150  * @obj: a pointer to the #AtspiAccessible instance to query.
2151  *
2152  * Gets the #AtspiTable interface for an #AtspiAccessible.
2153  *
2154  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
2155  *          NULL if @obj does not implement #AtspiText.
2156  **/
2157 AtspiText *
2158 atspi_accessible_get_text_iface (AtspiAccessible *obj)
2159 {
2160   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
2161           g_object_ref (ATSPI_TEXT (obj)) : NULL);
2162 }
2163
2164 /**
2165  * atspi_accessible_get_value: (rename-to atspi_accessible_get_value_iface)
2166  * @obj: a pointer to the #AtspiAccessible instance to query.
2167  *
2168  * Gets the #AtspiTable interface for an #AtspiAccessible.
2169  *
2170  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
2171  *          NULL if @obj does not implement #AtspiValue.
2172  *
2173  * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
2174  **/
2175 AtspiValue *
2176 atspi_accessible_get_value (AtspiAccessible *accessible)
2177 {
2178   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
2179           g_object_ref (ATSPI_VALUE (accessible)) : NULL);
2180 }
2181
2182 /**
2183  * atspi_accessible_get_value_iface:
2184  * @obj: a pointer to the #AtspiAccessible instance to query.
2185  *
2186  * Gets the #AtspiTable interface for an #AtspiAccessible.
2187  *
2188  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
2189  *          NULL if @obj does not implement #AtspiValue.
2190  **/
2191 AtspiValue *
2192 atspi_accessible_get_value_iface (AtspiAccessible *accessible)
2193 {
2194   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
2195           g_object_ref (ATSPI_VALUE (accessible)) : NULL);
2196 }
2197
2198 static void
2199 append_const_val (GArray *array, const gchar *val)
2200 {
2201   gchar *dup = g_strdup (val);
2202
2203   if (dup)
2204     g_array_append_val (array, dup);
2205 }
2206
2207 /**
2208  * atspi_accessible_get_interfaces:
2209  * @obj: The #AtspiAccessible to query.
2210  *
2211  * A set of pointers to all interfaces supported by an #AtspiAccessible.
2212  *
2213  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
2214  *          describing the interfaces supported by the object.  Interfaces are
2215  *          denoted in short-hand (i.e. "Component", "Text" etc.).
2216  **/
2217 GArray *
2218 atspi_accessible_get_interfaces (AtspiAccessible *obj)
2219 {
2220   GArray *ret;
2221
2222   g_return_val_if_fail (obj != NULL, NULL);
2223
2224   ret  = g_array_new (TRUE, TRUE, sizeof (gchar *));
2225
2226   append_const_val (ret, "Accessible");
2227   if (atspi_accessible_is_action (obj))
2228     append_const_val (ret, "Action");
2229   if (atspi_accessible_is_collection (obj))
2230     append_const_val (ret, "Collection");
2231   if (atspi_accessible_is_component (obj))
2232     append_const_val (ret, "Component");
2233   if (atspi_accessible_is_document (obj))
2234     append_const_val (ret, "Document");
2235   if (atspi_accessible_is_editable_text (obj))
2236     append_const_val (ret, "EditableText");
2237   if (atspi_accessible_is_hypertext (obj))
2238     append_const_val (ret, "Hypertext");
2239   if (atspi_accessible_is_hyperlink (obj))
2240     append_const_val (ret, "Hyperlink");
2241   if (atspi_accessible_is_image (obj))
2242     append_const_val (ret, "Image");
2243   if (atspi_accessible_is_selection (obj))
2244     append_const_val (ret, "Selection");
2245   if (atspi_accessible_is_table (obj))
2246     append_const_val (ret, "Table");
2247   if (atspi_accessible_is_table_cell (obj))
2248     append_const_val (ret, "TableCell");
2249   if (atspi_accessible_is_text (obj))
2250     append_const_val (ret, "Text");
2251   if (atspi_accessible_is_value (obj))
2252     append_const_val (ret, "Value");
2253
2254   return ret;
2255 }
2256
2257 AtspiAccessible *
2258 _atspi_accessible_new (AtspiApplication *app, const gchar *path)
2259 {
2260   AtspiAccessible *accessible;
2261
2262   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
2263   g_return_val_if_fail (accessible != NULL, NULL);
2264
2265   accessible->parent.app = g_object_ref (app);
2266   accessible->parent.path = g_strdup (path);
2267
2268   return accessible;
2269 }
2270
2271 /**
2272  * atspi_accessible_set_cache_mask:
2273  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
2274  *             the root of an application.
2275  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
2276  *
2277  * Sets the type of data to cache for accessibles.
2278  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
2279  * then the desktop's cache flag will be used.
2280  * If the desktop's cache flag is also undefined, then all possible data will
2281  * be cached.
2282  * This function is intended to work around bugs in toolkits where the proper
2283  * events are not raised / to aid in testing for such bugs.
2284  **/
2285 void
2286 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
2287 {
2288   g_return_if_fail (accessible != NULL);
2289   g_return_if_fail (accessible->parent.app != NULL);
2290   g_return_if_fail (atspi_accessible_is_equal (accessible, accessible->parent.app->root) || accessible->role == ATSPI_ROLE_APPLICATION);
2291   accessible->parent.app->cache = mask;
2292   enable_caching = TRUE;
2293 }
2294
2295 /**
2296  * atspi_accessible_clear_cache:
2297  * @obj: The #AtspiAccessible whose cache to clear.
2298  *
2299  * Clears the cached information for the given accessible and all of its
2300  * descendants.
2301  */
2302 void
2303 atspi_accessible_clear_cache (AtspiAccessible *obj)
2304 {
2305   gint i;
2306
2307   if (obj)
2308   {
2309     obj->cached_properties = ATSPI_CACHE_NONE;
2310     if (obj->children)
2311       for (i = 0; i < obj->children->len; i++)
2312         atspi_accessible_clear_cache (g_ptr_array_index (obj->children, i));
2313   }
2314 }
2315
2316 /**
2317  * atspi_accessible_get_process_id:
2318  * @accessible: The #AtspiAccessible to query.
2319  * @error: a pointer to a %NULL #GError pointer
2320  *
2321  * Returns the process id associated with the given accessible.  Mainly
2322  * added for debugging; it is a shortcut to explicitly querying the
2323  * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
2324  *
2325  * Returns: The process ID or undetermined value if @error is set.
2326  **/
2327 guint
2328 atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
2329 {
2330   DBusMessage *message, *reply;
2331   DBusConnection *bus = _atspi_bus ();
2332   dbus_uint32_t pid = -1;
2333   DBusError d_error;
2334
2335   if (!accessible->parent.app || !accessible->parent.app->bus_name)
2336     {
2337       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
2338       return -1;
2339     }
2340
2341   message = dbus_message_new_method_call ("org.freedesktop.DBus",
2342                                           "/org/freedesktop/DBus",
2343                                           "org.freedesktop.DBus",
2344                                           "GetConnectionUnixProcessID");
2345   dbus_message_append_args (message, DBUS_TYPE_STRING,
2346                             &accessible->parent.app->bus_name,
2347                             DBUS_TYPE_INVALID);
2348   dbus_error_init (&d_error);
2349   reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
2350   dbus_message_unref (message);
2351   if (reply)
2352   {
2353     if (!strcmp (dbus_message_get_signature (reply), "u"))
2354       dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
2355     dbus_message_unref (reply);
2356   }
2357   if (dbus_error_is_set (&d_error))
2358     {
2359       g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
2360       dbus_error_free (&d_error);
2361     }
2362   return pid;
2363 }
2364
2365 AtspiCache
2366 _atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
2367 {
2368   AtspiCache mask;
2369
2370   if (!accessible->parent.app)
2371     return ATSPI_CACHE_NONE;
2372
2373  mask = accessible->parent.app->cache;
2374   if (mask == ATSPI_CACHE_UNDEFINED &&
2375       accessible->parent.app->root &&
2376       accessible->parent.app->root->accessible_parent)
2377   {
2378     AtspiAccessible *desktop = atspi_get_desktop (0);
2379     mask = desktop->parent.app->cache;
2380     g_object_unref (desktop);
2381   }
2382
2383   if (mask == ATSPI_CACHE_UNDEFINED)
2384     mask = ATSPI_CACHE_DEFAULT;
2385
2386   return mask;
2387 }
2388
2389 gboolean
2390 _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
2391 {
2392   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
2393   AtspiCache result = accessible->cached_properties & mask & flag;
2394   if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
2395     return FALSE;
2396   return (result != 0 && (atspi_main_loop || enable_caching ||
2397                           flag == ATSPI_CACHE_INTERFACES) &&
2398           !atspi_no_cache);
2399 }
2400
2401 void
2402 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
2403 {
2404   AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
2405
2406   accessible->cached_properties |= flag & mask;
2407 }
2408
2409 /**
2410  * atspi_accessible_get_locale:
2411  * @accessible: an #AtspiAccessible
2412  *
2413  * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
2414  * of @accessible.
2415  *
2416  * Since: 2.7.91
2417  *
2418  * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
2419  *          locale of @accessible.
2420  **/
2421 const gchar*
2422 atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
2423 {
2424   gchar *locale;
2425
2426   g_return_val_if_fail (accessible != NULL, NULL);
2427
2428   locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
2429   if (!locale)
2430   {
2431     if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
2432                                    "Locale", error, "s", &locale))
2433       return NULL;
2434     if (locale)
2435       g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
2436                                g_free);
2437   }
2438   return locale;
2439 }
2440
2441 /**
2442  * atspi_accessible_get_accessible_id:
2443  * @obj: an #AtspiAccessible
2444  *
2445  * Gets the accessible id of the accessible.  This is not meant to be presented
2446  * to the user, but to be an id which is stable over application development.
2447  * Typically, this is the gtkbuilder id.
2448  *
2449  * Since: 2.34
2450  *
2451  * Returns: a character string representing the accessible id of the
2452  * #AtspiAccessible object or NULL on exception.
2453  **/
2454 gchar*
2455 atspi_accessible_get_accessible_id (AtspiAccessible *obj, GError **error)
2456 {
2457   gchar *accessible_id;
2458
2459   g_return_val_if_fail (obj != NULL, NULL);
2460
2461   if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
2462                                  "AccessibleId", error, "s", &accessible_id))
2463     return NULL;
2464
2465   return accessible_id;
2466 }
2467
2468 gboolean
2469 atspi_accessible_is_equal (AtspiAccessible *obj, AtspiAccessible *other)
2470 {
2471   static const char prefix[] = "/org/a11y/atspi/accessible/";
2472   static const size_t prefix_len = sizeof(prefix)/sizeof(char);
2473
2474   if (obj == other)
2475     return TRUE;
2476   if (!obj || !other)
2477     return FALSE;
2478
2479   /*
2480    * Is it possible to have 2 different objects representing
2481    * the same application? If not we should compare only pointers
2482    * (obj->parent.app and other->parent.app)
2483    */
2484
2485   /* One of them is null  */
2486   if ((obj->parent.app != other->parent.app) && (!obj->parent.app || !other->parent.app))
2487       return FALSE;
2488
2489   /* Both are not null */
2490   if ((obj->parent.app != other->parent.app) && g_strcmp0(obj->parent.app->bus_name, other->parent.app->bus_name))
2491       return FALSE;
2492
2493   const AtspiObject *o1 = ATSPI_OBJECT (obj);
2494   const AtspiObject *o2 = ATSPI_OBJECT (other);
2495
2496   const char *path1 = o1 ? o1->path : "";
2497   const char *path2 = o2 ? o2->path : "";
2498
2499   if (!strncmp(path1, prefix, prefix_len))
2500       path1 += prefix_len;
2501
2502   if (!strncmp(path2, prefix, prefix_len))
2503       path2 += prefix_len;
2504
2505   return !g_strcmp0(path1, path2);
2506 }
2507
2508 void
2509 free_value (gpointer data)
2510 {
2511   GValue *value = data;
2512
2513   g_value_unset (value);
2514   g_free (value);
2515 }
2516
2517 GHashTable *
2518 _atspi_accessible_ref_cache (AtspiAccessible *accessible)
2519 {
2520   AtspiAccessiblePrivate *priv = accessible->priv;
2521
2522   priv->cache_ref_count++;
2523   if (priv->cache)
2524     return g_hash_table_ref (priv->cache);
2525   priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2526                                        free_value);
2527   return priv->cache;
2528 }
2529
2530 void
2531 _atspi_accessible_unref_cache (AtspiAccessible *accessible)
2532 {
2533   AtspiAccessiblePrivate *priv = accessible->priv;
2534
2535   if (priv->cache)
2536   {
2537     g_hash_table_unref (priv->cache);
2538     if (--priv->cache_ref_count == 0)
2539       priv->cache = NULL;
2540   }
2541 }