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-accessible-private.h"
26
#include "atspi-private.h"
27
#include <string.h>
28

            
29
/**
30
 * AtspiAccessible:
31
 *
32
 * The base interface which is implemented by all accessible objects.
33
 *
34
 * All objects support interfaces for querying their contained 'children'
35
 * and position in the accessible-object hierarchy, whether or not they
36
 * actually have children.
37
 */
38

            
39
enum
40
{
41
  REGION_CHANGED,
42
  MODE_CHANGED,
43
  LAST_SIGNAL
44
};
45

            
46
static gboolean enable_caching = FALSE;
47
static guint quark_locale;
48

            
49
static guint atspi_accessible_signals[LAST_SIGNAL] = {
50
  0,
51
};
52

            
53
static gboolean
54
screen_reader_signal_watcher (GSignalInvocationHint *signal_hint,
55
                              guint n_param_values,
56
                              const GValue *param_values,
57
                              gpointer data)
58
{
59
  GObject *object;
60
  AtspiAccessible *accessible;
61
  GSignalQuery signal_query;
62
  const char *name;
63
  DBusMessage *signal;
64
  DBusMessageIter iter, iter_struct, iter_variant, iter_array;
65
  dbus_int32_t detail1 = 0, detail2 = 0;
66
  const char *detail = "";
67
  gchar *dbus_name;
68

            
69
  object = g_value_get_object (param_values + 0);
70
  g_return_val_if_fail (ATSPI_IS_ACCESSIBLE (object), FALSE);
71

            
72
  g_signal_query (signal_hint->signal_id, &signal_query);
73
  name = signal_query.signal_name;
74
  if (signal_hint->detail)
75
    detail = g_quark_to_string (signal_hint->detail);
76
  if (n_param_values > 1)
77
    detail1 = g_value_get_int (param_values + 1);
78
  if (n_param_values > 2 && G_VALUE_HOLDS_INT (param_values + 2))
79
    detail2 = g_value_get_int (param_values + 2);
80
  accessible = ATSPI_ACCESSIBLE (object);
81
  g_return_val_if_fail (accessible->parent.app != NULL, FALSE);
82

            
83
  dbus_name = _atspi_strdup_and_adjust_for_dbus (name);
84
  signal = dbus_message_new_signal (ATSPI_DBUS_PATH_SCREEN_READER,
85
                                    ATSPI_DBUS_INTERFACE_EVENT_SCREEN_READER,
86
                                    dbus_name);
87
  g_free (dbus_name);
88
  dbus_message_iter_init_append (signal, &iter);
89
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &detail);
90
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail1);
91
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail2);
92
  dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)",
93
                                    &iter_variant);
94
  dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
95
                                    &iter_struct);
96
  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &accessible->parent.app->bus_name);
97
  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &accessible->parent.path);
98
  dbus_message_iter_close_container (&iter_variant, &iter_struct);
99
  dbus_message_iter_close_container (&iter, &iter_variant);
100
  dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}",
101
                                    &iter_array);
102
  dbus_message_iter_close_container (&iter, &iter_array);
103
  dbus_connection_send (_atspi_bus (), signal, NULL);
104
  dbus_message_unref (signal);
105
  return TRUE;
106
}
107

            
108
static void
109
2
atspi_action_interface_init (AtspiAction *action)
110
{
111
2
}
112

            
113
static void
114
2
atspi_collection_interface_init (AtspiCollection *component)
115
{
116
2
}
117

            
118
static void
119
2
atspi_component_interface_init (AtspiComponent *component)
120
{
121
2
}
122

            
123
static void
124
2
atspi_document_interface_init (AtspiDocument *document)
125
{
126
2
}
127

            
128
static void
129
2
atspi_editable_text_interface_init (AtspiEditableText *editable_text)
130
{
131
2
}
132

            
133
static void
134
2
atspi_hypertext_interface_init (AtspiHypertext *hypertext)
135
{
136
2
}
137

            
138
static void
139
2
atspi_image_interface_init (AtspiImage *image)
140
{
141
2
}
142

            
143
static void
144
2
atspi_selection_interface_init (AtspiSelection *selection)
145
{
146
2
}
147

            
148
static void
149
2
atspi_table_interface_init (AtspiTable *table)
150
{
151
2
}
152

            
153
static void
154
2
atspi_table_cell_interface_init (AtspiTableCell *cell)
155
{
156
2
}
157

            
158
static void
159
2
atspi_text_interface_init (AtspiText *text)
160
{
161
2
}
162

            
163
static void
164
2
atspi_value_interface_init (AtspiValue *value)
165
{
166
2
}
167

            
168
2
G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT, G_ADD_PRIVATE (AtspiAccessible) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE_CELL, atspi_table_cell_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init) G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
169

            
170
#ifdef DEBUG_REF_COUNTS
171
static gint accessible_count = 0;
172
#endif
173

            
174
static void
175
1583
atspi_accessible_unref (GObject *accessible)
176
{
177
1583
  if (accessible != NULL)
178
1583
    g_object_unref (accessible);
179
1583
}
180

            
181
static void
182
1586
atspi_accessible_init (AtspiAccessible *accessible)
183
{
184
#ifdef DEBUG_REF_COUNTS
185
  accessible_count++;
186
  g_hash_table_insert (_atspi_get_live_refs (), accessible, NULL);
187
  g_print ("at-spi: init: %d objects\n", accessible_count);
188
#endif
189

            
190
1586
  accessible->priv = atspi_accessible_get_instance_private (accessible);
191

            
192
1586
  accessible->children = g_ptr_array_new_with_free_func ((GDestroyNotify) atspi_accessible_unref);
193
1586
}
194

            
195
static void
196
3167
atspi_accessible_dispose (GObject *object)
197
{
198
3167
  AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
199
  AtspiEvent e;
200
  AtspiAccessible *parent;
201
  gint i;
202

            
203
  /* TODO: Only fire if object not already marked defunct */
204
3167
  memset (&e, 0, sizeof (e));
205
3167
  e.type = "object:state-changed:defunct";
206
3167
  e.source = accessible;
207
3167
  e.detail1 = 1;
208
3167
  e.detail2 = 0;
209
3167
  _atspi_send_event (&e);
210

            
211
3167
  g_clear_object (&accessible->states);
212

            
213
3167
  parent = accessible->accessible_parent;
214
3167
  if (parent)
215
    {
216
660
      accessible->accessible_parent = NULL;
217
660
      if (parent->children)
218
660
        g_ptr_array_remove (parent->children, accessible);
219
660
      g_object_unref (parent);
220
    }
221

            
222
3167
  if (accessible->children)
223
2509
    for (i = accessible->children->len - 1; i >= 0; i--)
224
      {
225
923
        AtspiAccessible *child = g_ptr_array_index (accessible->children, i);
226
923
        if (child && child->accessible_parent == accessible)
227
          {
228
791
            child->accessible_parent = NULL;
229
791
            g_object_unref (accessible);
230
          }
231
      }
232

            
233
3167
  if (accessible->children)
234
    {
235
1586
      g_ptr_array_free (accessible->children, TRUE);
236
1586
      accessible->children = NULL;
237
    }
238

            
239
3167
  G_OBJECT_CLASS (atspi_accessible_parent_class)->dispose (object);
240
3167
}
241

            
242
static void
243
1581
atspi_accessible_finalize (GObject *object)
244
{
245
1581
  AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
246

            
247
1581
  g_free (accessible->description);
248
1581
  g_free (accessible->name);
249

            
250
1581
  if (accessible->attributes)
251
1
    g_hash_table_unref (accessible->attributes);
252

            
253
1581
  if (accessible->priv->cache)
254
    g_hash_table_destroy (accessible->priv->cache);
255

            
256
#ifdef DEBUG_REF_COUNTS
257
  accessible_count--;
258
  g_hash_table_remove (_atspi_get_live_refs (), accessible);
259
  g_print ("at-spi: finalize: %d objects\n", accessible_count);
260
#endif
261

            
262
1581
  G_OBJECT_CLASS (atspi_accessible_parent_class)->finalize (object);
263

            
264
  /* TODO: remove emission hook */
265
1581
}
266

            
267
static void
268
2
atspi_accessible_class_init (AtspiAccessibleClass *klass)
269
{
270
2
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
271

            
272
2
  object_class->dispose = atspi_accessible_dispose;
273
2
  object_class->finalize = atspi_accessible_finalize;
274

            
275
2
  quark_locale = g_quark_from_string ("accessible-locale");
276

            
277
  /**
278
   * AtspiAccessible::region-changed:
279
   * @atspiaccessible: the object which received the signal
280
   * @arg1: an integer specifying the current offset of the text being read,
281
   *        if the object is textual.
282
   * @arg2: an integer specifying the ending offset of the text being read,
283
   *        if the object is textual.
284
   *
285
   * The signal "region-changed" is emitted by a screen reader to indicate
286
   * that it is now reading or tracking a new object, or, a new piece of
287
   * text within an object. This allows a magnifier to gain the information
288
   * needed to highlight the object that the screen reader is reading.
289
   */
290
2
  atspi_accessible_signals[REGION_CHANGED] =
291
2
      g_signal_new ("region_changed",
292
                    G_TYPE_FROM_CLASS (klass),
293
                    G_SIGNAL_RUN_LAST,
294
                    G_STRUCT_OFFSET (AtspiAccessibleClass, region_changed),
295
                    NULL, NULL,
296
                    atspi_marshal_VOID__INT_INT,
297
                    G_TYPE_NONE,
298
                    2, G_TYPE_INT, G_TYPE_INT);
299

            
300
  /**
301
   * AtspiAccessible::mode-changed:
302
   * @atspiaccessible: the object which received the signal
303
   * @arg1: a boolean specifying whether the mode is being toggled on or off.
304
   * @why: an optional string explaining why the mode changed.
305
   *
306
   * The signal "mode-changed" is emitted by a screen reader to indicate
307
   * that its mode has changed. This signal supports the following details:
308
   * focus-tracking
309
   * flat-review
310
   * mouse-review
311
   * say-all
312
   * caret-tracking
313
   */
314
2
  atspi_accessible_signals[MODE_CHANGED] =
315
2
      g_signal_new ("mode_changed",
316
                    G_TYPE_FROM_CLASS (klass),
317
                    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
318
                    G_STRUCT_OFFSET (AtspiAccessibleClass, mode_changed),
319
                    NULL, NULL,
320
                    atspi_marshal_VOID__INT_STRING,
321
                    G_TYPE_NONE,
322
                    2, G_TYPE_INT, G_TYPE_STRING);
323

            
324
2
  g_signal_add_emission_hook (atspi_accessible_signals[REGION_CHANGED], 0,
325
                              screen_reader_signal_watcher, NULL,
326
                              (GDestroyNotify) NULL);
327
2
  g_signal_add_emission_hook (atspi_accessible_signals[MODE_CHANGED], 0,
328
                              screen_reader_signal_watcher, NULL,
329
                              (GDestroyNotify) NULL);
330
2
}
331

            
332
/**
333
 * atspi_accessible_get_name:
334
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
335
 *
336
 * Gets the name of an #AtspiAccessible object.
337
 *
338
 * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object
339
 * or NULL on exception.
340
 **/
341
gchar *
342
195
atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
343
{
344
195
  g_return_val_if_fail (obj != NULL, g_strdup (""));
345
195
  gchar *name = NULL;
346

            
347
195
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME))
348
    {
349
165
      g_free (obj->name);
350
165
      obj->name = NULL;
351
165
      if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error,
352
                                     "s", &name))
353
        return g_strdup ("");
354
165
      _atspi_accessible_add_cache (obj, ATSPI_CACHE_NAME);
355
165
      if (!obj->name)
356
164
        obj->name = name;
357
      else
358
1
        free (name);
359
    }
360
390
  return g_strdup (obj->name);
361
}
362

            
363
/**
364
 * atspi_accessible_get_description:
365
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
366
 *
367
 * Gets the description of an #AtspiAccessible object.
368
 *
369
 * Returns: a UTF-8 string describing the #AtspiAccessible object
370
 * or NULL on exception.
371
 **/
372
gchar *
373
1
atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
374
{
375
1
  g_return_val_if_fail (obj != NULL, g_strdup (""));
376
1
  gchar *description = NULL;
377

            
378
1
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION))
379
    {
380
1
      g_free (obj->description);
381
1
      obj->description = NULL;
382
1
      if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
383
                                     "Description", error, "s",
384
1
                                     &obj->description))
385
        return g_strdup ("");
386
1
      _atspi_accessible_add_cache (obj, ATSPI_CACHE_DESCRIPTION);
387
1
      if (!obj->description)
388
        obj->description = description;
389
      else
390
1
        free (description);
391
    }
392
2
  return g_strdup (obj->description);
393
}
394

            
395
const char *str_parent = "Parent";
396

            
397
/**
398
 * atspi_accessible_get_parent:
399
 * @obj: a pointer to the #AtspiAccessible object to query.
400
 *
401
 * Gets an #AtspiAccessible object's parent container.
402
 *
403
 * Returns: (nullable) (transfer full): a pointer to the
404
 *          #AtspiAccessible object which contains the given
405
 *          #AtspiAccessible instance, or NULL if the @obj has no
406
 *          parent container.
407
 *
408
 **/
409
AtspiAccessible *
410
3
atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
411
{
412
3
  g_return_val_if_fail (obj != NULL, NULL);
413

            
414
3
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
415
    {
416
      DBusMessage *message, *reply;
417
      DBusMessageIter iter, iter_variant;
418
3
      if (!obj->parent.app)
419
        return NULL;
420
3
      message = dbus_message_new_method_call (obj->parent.app->bus_name,
421
3
                                              obj->parent.path,
422
                                              DBUS_INTERFACE_PROPERTIES, "Get");
423
3
      if (!message)
424
        return NULL;
425
3
      dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
426
                                DBUS_TYPE_STRING, &str_parent,
427
                                DBUS_TYPE_INVALID);
428
3
      reply = _atspi_dbus_send_with_reply_and_block (message, error);
429
3
      if (!reply)
430
        return NULL;
431
3
      if (strcmp (dbus_message_get_signature (reply), "v") != 0)
432
        {
433
          dbus_message_unref (reply);
434
          return NULL;
435
        }
436
3
      dbus_message_iter_init (reply, &iter);
437
3
      dbus_message_iter_recurse (&iter, &iter_variant);
438
3
      g_clear_object (&obj->accessible_parent);
439
3
      obj->accessible_parent = _atspi_dbus_consume_accessible (&iter_variant);
440
3
      dbus_message_unref (reply);
441
3
      _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
442
    }
443
3
  if (!obj->accessible_parent)
444
2
    return NULL;
445
1
  return g_object_ref (obj->accessible_parent);
446
}
447

            
448
/**
449
 * atspi_accessible_get_child_count:
450
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
451
 *
452
 * Gets the number of children contained by an #AtspiAccessible object.
453
 *
454
 * Returns: a #long indicating the number of #AtspiAccessible children
455
 *          contained by an #AtspiAccessible object or -1 on exception.
456
 *
457
 **/
458
gint
459
163
atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
460
{
461
163
  g_return_val_if_fail (obj != NULL, -1);
462

            
463
163
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
464
    {
465
      dbus_int32_t ret;
466
163
      if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
467
                                     "ChildCount", error, "i", &ret))
468
        return -1;
469
163
      return ret;
470
    }
471

            
472
  if (!obj->children)
473
    return 0; /* assume it's disposed */
474

            
475
  return obj->children->len;
476
}
477

            
478
/**
479
 * atspi_accessible_get_child_at_index:
480
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
481
 * @child_index: a #long indicating which child is specified.
482
 *
483
 * Gets the #AtspiAccessible child of an #AtspiAccessible object at a given index.
484
 *
485
 * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
486
 * index @child_index or NULL on exception.
487
 **/
488
AtspiAccessible *
489
304
atspi_accessible_get_child_at_index (AtspiAccessible *obj,
490
                                     gint child_index,
491
                                     GError **error)
492
{
493
  AtspiAccessible *child;
494
  DBusMessage *reply;
495

            
496
304
  g_return_val_if_fail (obj != NULL, NULL);
497

            
498
304
  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
499
    {
500
4
      if (!obj->children)
501
        return NULL; /* assume disposed */
502

            
503
4
      if (child_index < obj->children->len)
504
        {
505
4
          child = g_ptr_array_index (obj->children, child_index);
506
4
          if (child)
507
4
            return g_object_ref (child);
508
        }
509
    }
510

            
511
300
  reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
512
                                    "GetChildAtIndex", error, "i", child_index);
513
300
  child = _atspi_dbus_return_accessible_from_message (reply);
514

            
515
300
  if (!child)
516
1
    return NULL;
517

            
518
299
  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_CHILDREN))
519
    {
520
9
      if (child_index >= obj->children->len)
521
        g_ptr_array_set_size (obj->children, child_index + 1);
522
9
      else if (g_ptr_array_index (obj->children, child_index))
523
9
        g_object_unref (g_ptr_array_index (obj->children, child_index));
524
9
      g_ptr_array_index (obj->children, child_index) = g_object_ref (child);
525
    }
526
299
  return child;
527
}
528

            
529
/**
530
 * atspi_accessible_get_index_in_parent:
531
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
532
 *
533
 * Gets the index of an #AtspiAccessible object within its parent's
534
 * #AtspiAccessible children list.
535
 *
536
 * Returns: a #glong indicating the index of the #AtspiAccessible object
537
 *          in its parent,
538
 *          or -1 if @obj has no containing parent or on exception.
539
 **/
540
gint
541
1
atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
542
{
543
1
  gint i = 0;
544
1
  dbus_int32_t ret = -1;
545

            
546
1
  g_return_val_if_fail (obj != NULL, -1);
547
1
  if (_atspi_accessible_test_cache (obj, ATSPI_CACHE_PARENT))
548
    {
549
      if (!obj->accessible_parent)
550
        return -1;
551

            
552
      if (!_atspi_accessible_test_cache (obj->accessible_parent, ATSPI_CACHE_CHILDREN) || !obj->accessible_parent->children)
553
        goto dbus;
554

            
555
      for (i = 0; i < obj->accessible_parent->children->len; i++)
556
        if (g_ptr_array_index (obj->accessible_parent->children, i) == obj)
557
          return i;
558
    }
559

            
560
1
dbus:
561
1
  _atspi_dbus_call (obj, atspi_interface_accessible,
562
                    "GetIndexInParent", NULL, "=>i", &ret);
563
1
  return ret;
564
}
565

            
566
typedef struct
567
{
568
  dbus_uint32_t type;
569
  GArray *targets;
570
} Accessibility_Relation;
571

            
572
/**
573
 * atspi_accessible_get_relation_set:
574
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
575
 *
576
 * Gets the set of #AtspiRelation objects which describes this #AtspiAccessible object's
577
 * relationships with other #AtspiAccessible objects.
578
 *
579
 * Returns: (element-type AtspiRelation*) (transfer full): a #GArray of
580
 *          #AtspiRelation pointers or NULL on exception.
581
 **/
582
GArray *
583
2
atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
584
{
585
  DBusMessage *reply;
586
  DBusMessageIter iter, iter_array;
587
  GArray *ret;
588

            
589
2
  g_return_val_if_fail (obj != NULL, NULL);
590

            
591
2
  reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
592
2
  if (!reply)
593
    return NULL;
594
2
  _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
595

            
596
2
  ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
597
2
  dbus_message_iter_init (reply, &iter);
598
2
  dbus_message_iter_recurse (&iter, &iter_array);
599
4
  while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
600
    {
601
      AtspiRelation *relation;
602
2
      relation = _atspi_relation_new_from_iter (&iter_array);
603
2
      ret = g_array_append_val (ret, relation);
604
2
      dbus_message_iter_next (&iter_array);
605
    }
606
2
  dbus_message_unref (reply);
607
2
  return ret;
608
}
609

            
610
/**
611
 * atspi_accessible_get_role:
612
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
613
 *
614
 * Gets the UI role played by an #AtspiAccessible object.
615
 * This role's name can be obtained via atspi_accessible_get_role_name ().
616
 *
617
 * Returns: the #AtspiRole of an #AtspiAccessible object.
618
 *
619
 **/
620
AtspiRole
621
328
atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
622
{
623
328
  g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
624

            
625
328
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ROLE))
626
    {
627
      dbus_uint32_t role;
628
      /* TODO: Make this a property */
629
9
      if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
630
        {
631
9
          obj->role = role;
632
9
          _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
633
        }
634
    }
635
328
  return obj->role;
636
}
637

            
638
/**
639
 * atspi_accessible_get_role_name:
640
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
641
 *
642
 * Gets a UTF-8 string corresponding to the name of the role played by an object.
643
 * This method will return useful values for roles that fall outside the
644
 * enumeration used in atspi_accessible_get_role ().
645
 *
646
 * Returns: a UTF-8 string specifying the type of UI role played by an
647
 * #AtspiAccessible object.
648
 *
649
 **/
650
gchar *
651
1
atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
652
{
653
1
  gchar *retval = NULL;
654
  AtspiRole role;
655

            
656
1
  g_return_val_if_fail (obj != NULL, NULL);
657

            
658
1
  role = atspi_accessible_get_role (obj, error);
659
1
  if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
660
1
    return atspi_role_get_name (role);
661

            
662
  _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
663

            
664
  if (!retval)
665
    retval = g_strdup ("");
666

            
667
  return retval;
668
}
669

            
670
/**
671
 * atspi_accessible_get_localized_role_name:
672
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
673
 *
674
 * Gets a UTF-8 string corresponding to the name of the role played by an
675
 * object, translated to the current locale.
676
 * This method will return useful values for roles that fall outside the
677
 * enumeration used in atspi_accessible_getRole ().
678
 *
679
 * Returns: a localized, UTF-8 string specifying the type of UI role played
680
 * by an #AtspiAccessible object.
681
 *
682
 **/
683
gchar *
684
1
atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
685
{
686
1
  char *retval = NULL;
687
  AtspiRole role;
688

            
689
1
  g_return_val_if_fail (obj != NULL, NULL);
690

            
691
1
  role = atspi_accessible_get_role (obj, error);
692
1
  if (role >= 0 && role < ATSPI_ROLE_COUNT && role != ATSPI_ROLE_EXTENDED)
693
1
    return atspi_role_get_localized_name (role);
694

            
695
  _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
696

            
697
  if (!retval)
698
    return g_strdup ("");
699

            
700
  return retval;
701
}
702

            
703
static AtspiStateSet *
704
defunct_set ()
705
{
706
  AtspiStateSet *set = atspi_state_set_new (NULL);
707
  atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
708
  return set;
709
}
710

            
711
/**
712
 * atspi_accessible_get_state_set:
713
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
714
 *
715
 * Gets the states currently held by an object.
716
 *
717
 * Returns: (transfer full): a pointer to an #AtspiStateSet representing an
718
 * object's current state set.
719
 **/
720
AtspiStateSet *
721
15
atspi_accessible_get_state_set (AtspiAccessible *obj)
722
{
723
  /* TODO: Should take a GError **, but would be an API break */
724
15
  if (!obj->parent.app || !obj->parent.app->bus)
725
    return defunct_set ();
726

            
727
15
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_STATES))
728
    {
729
      DBusMessage *reply;
730
      DBusMessageIter iter;
731
11
      reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
732
                                        "GetState", NULL, "");
733
11
      _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
734
11
      dbus_message_iter_init (reply, &iter);
735
11
      _atspi_dbus_set_state (obj, &iter);
736
11
      dbus_message_unref (reply);
737
11
      _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
738
    }
739

            
740
15
  return g_object_ref (obj->states);
741
}
742

            
743
/**
744
 * atspi_accessible_get_attributes:
745
 * @obj: The #AtspiAccessible being queried.
746
 *
747
 * Gets the #AttributeSet representing any assigned
748
 * name-value pair attributes or annotations for this object.
749
 * For typographic, textual, or textually-semantic attributes, see
750
 * atspi_text_get_attributes instead.
751
 *
752
 * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
753
 * attributes assigned to this object.
754
 */
755
GHashTable *
756
1
atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
757
{
758
  DBusMessage *message;
759

            
760
1
  g_return_val_if_fail (obj != NULL, NULL);
761

            
762
1
  if (obj->priv->cache)
763
    {
764
      GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
765
      if (val)
766
        return g_value_dup_boxed (val);
767
    }
768

            
769
1
  if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
770
    {
771
1
      message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
772
                                          "GetAttributes", error, "");
773
1
      g_clear_pointer (&(obj->attributes), g_hash_table_unref);
774

            
775
1
      obj->attributes = _atspi_dbus_return_hash_from_message (message);
776
1
      _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES);
777
    }
778

            
779
1
  if (!obj->attributes)
780
    return NULL;
781
1
  return g_hash_table_ref (obj->attributes);
782
}
783

            
784
static void
785
add_to_attribute_array (gpointer key, gpointer value, gpointer data)
786
{
787
  GArray **array = (GArray **) data;
788
  gchar *str = g_strconcat (key, ":", value, NULL);
789
  *array = g_array_append_val (*array, str);
790
}
791

            
792
/**
793
 * atspi_accessible_get_attributes_as_array:
794
 * @obj: The #AtspiAccessible being queried.
795
 *
796
 * Gets a #GArray representing any assigned
797
 * name-value pair attributes or annotations for this object.
798
 * For typographic, textual, or textually-semantic attributes, see
799
 * atspi_text_get_attributes_as_array instead.
800
 *
801
 * Returns: (element-type gchar*) (transfer full): The name-value-pair
802
 *          attributes assigned to this object.
803
 */
804
GArray *
805
1
atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
806
{
807
  DBusMessage *message;
808

            
809
1
  g_return_val_if_fail (obj != NULL, NULL);
810

            
811
1
  if (obj->priv->cache)
812
    {
813
      GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
814
      if (val)
815
        {
816
          GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
817
          GHashTable *attributes = g_value_get_boxed (val);
818
          g_hash_table_foreach (attributes, add_to_attribute_array, &array);
819
          return array;
820
        }
821
    }
822

            
823
1
  message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
824
1
  return _atspi_dbus_return_attribute_array_from_message (message);
825
}
826

            
827
/**
828
 * atspi_accessible_get_application:
829
 * @obj: The #AtspiAccessible being queried.
830
 *
831
 * Gets the containing #AtspiApplication for an object.
832
 *
833
 * Returns: (transfer full): the containing #AtspiApplication instance for
834
 *          this object.
835
 */
836
AtspiAccessible *
837
1
atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
838
{
839
  AtspiAccessible *parent;
840

            
841
1
  g_object_ref (obj);
842
  for (;;)
843
    {
844
1
      parent = atspi_accessible_get_parent (obj, NULL);
845
2
      if (!parent && obj->parent.app &&
846
1
          atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
847
        {
848
1
          AtspiAccessible *root = g_object_ref (obj->parent.app->root);
849
1
          if (root)
850
            {
851
1
              g_object_unref (obj);
852
1
              if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
853
                {
854
                  g_object_unref (root);
855
                  return NULL;
856
                }
857
1
              return root;
858
            }
859
        }
860
      if (!parent || parent == obj ||
861
          atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
862
        {
863
          if (parent)
864
            g_object_unref (parent);
865
          return obj;
866
        }
867
      g_object_unref (obj);
868
      obj = parent;
869
    }
870
}
871

            
872
/* Application-specific methods */
873

            
874
/**
875
 * atspi_accessible_get_toolkit_name:
876
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
877
 *
878
 * Gets the toolkit name for an #AtspiAccessible object.
879
 * Only works on application root objects.
880
 *
881
 * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object or NULL on exception.
882
 **/
883
gchar *
884
1
atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
885
{
886
1
  g_return_val_if_fail (obj != NULL, NULL);
887

            
888
1
  if (!obj->parent.app)
889
    return NULL;
890

            
891
1
  if (!obj->parent.app->toolkit_name)
892
1
    _atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName",
893
1
                              error, "s", &obj->parent.app->toolkit_name);
894

            
895
2
  return g_strdup (obj->parent.app->toolkit_name);
896
}
897

            
898
/**
899
 * atspi_accessible_get_toolkit_version:
900
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
901
 *
902
 * Gets the toolkit version for an #AtspiAccessible object.
903
 * Only works on application root objects.
904
 *
905
 * Returns: a UTF-8 string indicating the toolkit version for the #AtspiAccessible object or NULL on exception.
906
 **/
907
gchar *
908
1
atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
909
{
910
1
  g_return_val_if_fail (obj != NULL, NULL);
911

            
912
1
  if (!obj->parent.app)
913
    return NULL;
914

            
915
1
  if (!obj->parent.app->toolkit_version)
916
1
    _atspi_dbus_get_property (obj, atspi_interface_application, "Version",
917
1
                              error, "s", &obj->parent.app->toolkit_version);
918

            
919
2
  return g_strdup (obj->parent.app->toolkit_version);
920
}
921

            
922
/**
923
 * atspi_accessible_get_atspi_version:
924
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
925
 *
926
 * Gets the AT-SPI IPC specification version supported by the application
927
 * pointed to by the #AtspiAccessible object.
928
 * Only works on application root objects.
929
 *
930
 * Returns: a UTF-8 string indicating the AT-SPI version for the #AtspiAccessible object or NULL on exception.
931
 **/
932
gchar *
933
1
atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
934
{
935
1
  g_return_val_if_fail (obj != NULL, NULL);
936

            
937
1
  if (!obj->parent.app)
938
    return NULL;
939

            
940
1
  if (!obj->parent.app->atspi_version)
941
1
    _atspi_dbus_get_property (obj, atspi_interface_application, "AtspiVersion",
942
1
                              error, "s", &obj->parent.app->atspi_version);
943

            
944
2
  return g_strdup (obj->parent.app->atspi_version);
945
}
946

            
947
/**
948
 * atspi_accessible_get_id:
949
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
950
 *
951
 * Gets the application id for a #AtspiAccessible object.
952
 * Only works on application root objects.
953
 *
954
 * Returns: a positive #gint indicating the id for the #AtspiAccessible object
955
 * or -1 on exception.
956
 **/
957
gint
958
1
atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
959
{
960
1
  gint ret = -1;
961

            
962
1
  g_return_val_if_fail (obj != NULL, -1);
963

            
964
1
  if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
965
    return -1;
966
1
  return ret;
967
}
968

            
969
/* Interface query methods */
970

            
971
static gboolean
972
142
_atspi_accessible_is_a (AtspiAccessible *accessible,
973
                        const char *interface_name)
974
{
975
  int n;
976

            
977
142
  if (accessible == NULL)
978
    {
979
      return FALSE;
980
    }
981

            
982
142
  if (!_atspi_accessible_test_cache (accessible, ATSPI_CACHE_INTERFACES))
983
    {
984
      DBusMessage *reply;
985
      DBusMessageIter iter;
986
122
      reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
987
                                        "GetInterfaces", NULL, "");
988
122
      _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
989
122
      dbus_message_iter_init (reply, &iter);
990
122
      _atspi_dbus_set_interfaces (accessible, &iter);
991
122
      dbus_message_unref (reply);
992
    }
993

            
994
142
  n = _atspi_get_iface_num (interface_name);
995
142
  if (n == -1)
996
    return FALSE;
997
142
  return (gboolean) ((accessible->interfaces & (1 << n)) ? TRUE : FALSE);
998
}
999

            
/**
 * atspi_accessible_is_action:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiAction interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiAction interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_action (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_action);
}
/**
 * atspi_accessible_is_application:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiApplication interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiApplication interface,
 *          #FALSE otherwise.
 **/
gboolean
atspi_accessible_is_application (AtspiAccessible *obj)
{
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_application);
}
/**
 * atspi_accessible_is_collection:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiCollection interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiCollection interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_collection (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_collection);
}
/**
 * atspi_accessible_is_component:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements #AtspiComponent.
 *
 * Returns: #TRUE if @obj implements the #AtspiComponent interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_component (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_component);
}
/**
 * atspi_accessible_is_document:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiDocument interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiDocument interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_document (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_document);
}
/**
 * atspi_accessible_is_editable_text:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiEditableText interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_editable_text (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_editable_text);
}
/**
 * atspi_accessible_is_hypertext:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiHypertext interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_hypertext (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_hypertext);
}
/**
 * atspi_accessible_is_hyperlink:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiHyperlink interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_hyperlink (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_hyperlink);
}
/**
 * atspi_accessible_is_image:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiImage interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiImage interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_image (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_image);
}
/**
 * atspi_accessible_is_selection:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiSelection interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiSelection interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_selection (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_selection);
}
/**
 * atspi_accessible_is_table:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiTable interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiTable interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_table (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_table);
}
/**
 * atspi_accessible_is_table_cell:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiTableCell interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiTable interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_table_cell (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_table_cell);
}
/**
 * atspi_accessible_is_streamable_content:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiStreamableContent interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
 *          #FALSE otherwise.
 **/
gboolean
atspi_accessible_is_streamable_content (AtspiAccessible *obj)
{
#if 0
  return _atspi_accessible_is_a (obj,
			      atspi_interface_streamable_content);
#else
  g_warning ("Streamable content not implemented");
  return FALSE;
#endif
}
/**
 * atspi_accessible_is_text:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiText interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiText interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_text (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_text);
}
/**
 * atspi_accessible_is_value:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Query whether the specified #AtspiAccessible implements the
 * #AtspiValue interface.
 *
 * Returns: #TRUE if @obj implements the #AtspiValue interface,
 *          #FALSE otherwise.
 **/
gboolean
1
atspi_accessible_is_value (AtspiAccessible *obj)
{
1
  return _atspi_accessible_is_a (obj,
                                 atspi_interface_value);
}
/**
 * atspi_accessible_get_action:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiAction interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiAction interface
 *          instance, or NULL if @obj does not implement #AtspiAction.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_action_iface instead.
 **/
AtspiAction *
atspi_accessible_get_action (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_action) ? g_object_ref (ATSPI_ACTION (accessible)) : NULL);
}
/**
 * atspi_accessible_get_action_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiAction interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiAction interface
 *          instance, or NULL if @obj does not implement #AtspiAction.
 **/
AtspiAction *
8
atspi_accessible_get_action_iface (AtspiAccessible *accessible)
{
8
  return (_atspi_accessible_is_a (accessible, atspi_interface_action) ? g_object_ref (ATSPI_ACTION (accessible)) : NULL);
}
/**
 * atspi_accessible_get_collection:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiCollection interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiCollection interface
 *          instance, or NULL if @obj does not implement #AtspiCollection.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_collection_iface instead.
 **/
AtspiCollection *
atspi_accessible_get_collection (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ? g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
}
/**
 * atspi_accessible_get_collection_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiCollection interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiCollection interface
 *          instance, or NULL if @obj does not implement #AtspiCollection.
 **/
AtspiCollection *
5
atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
{
5
  return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ? g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
}
/**
 * atspi_accessible_get_component:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiComponent interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiComponent interface
 *          instance, or NULL if @obj does not implement #AtspiComponent.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_component_iface instead.
 **/
AtspiComponent *
atspi_accessible_get_component (AtspiAccessible *obj)
{
  return (_atspi_accessible_is_a (obj, atspi_interface_component) ? g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
}
/**
 * atspi_accessible_get_component_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiComponent interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiComponent interface
 *          instance, or NULL if @obj does not implement #AtspiComponent.
 **/
AtspiComponent *
10
atspi_accessible_get_component_iface (AtspiAccessible *obj)
{
10
  return (_atspi_accessible_is_a (obj, atspi_interface_component) ? g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
}
/**
 * atspi_accessible_get_document:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiDocument interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiDocument interface
 *          instance, or NULL if @obj does not implement #AtspiDocument.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_document_iface instead.
 **/
AtspiDocument *
atspi_accessible_get_document (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_document) ? g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_document_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiDocument interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiDocument interface
 *          instance, or NULL if @obj does not implement #AtspiDocument.
 **/
AtspiDocument *
6
atspi_accessible_get_document_iface (AtspiAccessible *accessible)
{
6
  return (_atspi_accessible_is_a (accessible, atspi_interface_document) ? g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_editable_text:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiEditableText interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiEditableText interface
 *          instance, or NULL if @obj does not implement #AtspiEditableText.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_editable_text_iface instead.
 **/
AtspiEditableText *
atspi_accessible_get_editable_text (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ? g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_editable_text_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiEditableText interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiEditableText interface
 *          instance, or NULL if @obj does not implement #AtspiEditableText.
 **/
AtspiEditableText *
7
atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
{
7
  return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ? g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_hyperlink:
 * @obj: a pointer to the #AtspiAccessible object on which to operate.
 *
 * Gets the #AtspiHyperlink interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): the #AtspiHyperlink object associated with
 *          the given #AtspiAccessible, or NULL if not supported.
 **/
AtspiHyperlink *
atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ? _atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
}
/**
 * atspi_accessible_get_hypertext:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiHypertext interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiHypertext interface
 *          instance, or NULL if @obj does not implement #AtspiHypertext.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_hypertext_iface instead.
 **/
AtspiHypertext *
atspi_accessible_get_hypertext (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ? g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_hypertext_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiHypertext interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiHypertext interface
 *          instance, or NULL if @obj does not implement #AtspiHypertext.
 **/
AtspiHypertext *
11
atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
{
11
  return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ? g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
}
/**
 * atspi_accessible_get_image:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiImage interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
 *          NULL if @obj does not implement #AtspiImage.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_image_iface instead.
 **/
AtspiImage *
atspi_accessible_get_image (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_image) ? g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
}
/**
 * atspi_accessible_get_image_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiImage interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
 *          NULL if @obj does not implement #AtspiImage.
 **/
AtspiImage *
7
atspi_accessible_get_image_iface (AtspiAccessible *accessible)
{
7
  return (_atspi_accessible_is_a (accessible, atspi_interface_image) ? g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
}
/**
 * atspi_accessible_get_selection:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiSelection interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiSelection interface
 *          instance, or NULL if @obj does not implement #AtspiSelection.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_selection_iface instead.
 **/
AtspiSelection *
atspi_accessible_get_selection (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ? g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
}
/**
 * atspi_accessible_get_selection_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiSelection interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiSelection interface
 *          instance, or NULL if @obj does not implement #AtspiSelection.
 **/
AtspiSelection *
10
atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
{
10
  return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ? g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
}
#if 0
/**
 * atspi_accessible_get_streamable_content:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiStreamableContent interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
 *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
 **/
AtspiStreamableContent *
atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
          accessible : NULL);  
}
#endif
/**
 * atspi_accessible_get_table:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
 *          NULL if @obj does not implement #AtspiTable.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_table_iface instead.
 **/
AtspiTable *
atspi_accessible_get_table (AtspiAccessible *obj)
{
  return (_atspi_accessible_is_a (obj, atspi_interface_table) ? g_object_ref (ATSPI_TABLE (obj)) : NULL);
}
/**
 * atspi_accessible_get_table_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
 *          NULL if @obj does not implement #AtspiTable.
 **/
AtspiTable *
27
atspi_accessible_get_table_iface (AtspiAccessible *obj)
{
27
  return (_atspi_accessible_is_a (obj, atspi_interface_table) ? g_object_ref (ATSPI_TABLE (obj)) : NULL);
}
/**
 * atspi_accessible_get_table_cell:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTableCell interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiTableCell interface instance,
 *          or NULL if @obj does not implement #AtspiTable.
 **/
AtspiTableCell *
8
atspi_accessible_get_table_cell (AtspiAccessible *obj)
{
8
  return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ? g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
}
/**
 * atspi_accessible_get_text:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
 *          NULL if @obj does not implement #AtspiText.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_text_iface instead.
 **/
AtspiText *
atspi_accessible_get_text (AtspiAccessible *obj)
{
  return (_atspi_accessible_is_a (obj, atspi_interface_text) ? g_object_ref (ATSPI_TEXT (obj)) : NULL);
}
/**
 * atspi_accessible_get_text_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
 *          NULL if @obj does not implement #AtspiText.
 **/
AtspiText *
22
atspi_accessible_get_text_iface (AtspiAccessible *obj)
{
22
  return (_atspi_accessible_is_a (obj, atspi_interface_text) ? g_object_ref (ATSPI_TEXT (obj)) : NULL);
}
/**
 * atspi_accessible_get_value:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
 *          NULL if @obj does not implement #AtspiValue.
 *
 * Deprecated: 2.10: Use atspi_accessible_get_value_iface instead.
 **/
AtspiValue *
atspi_accessible_get_value (AtspiAccessible *accessible)
{
  return (_atspi_accessible_is_a (accessible, atspi_interface_value) ? g_object_ref (ATSPI_VALUE (accessible)) : NULL);
}
/**
 * atspi_accessible_get_value_iface:
 * @obj: a pointer to the #AtspiAccessible instance to query.
 *
 * Gets the #AtspiTable interface for an #AtspiAccessible.
 *
 * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
 *          NULL if @obj does not implement #AtspiValue.
 **/
AtspiValue *
8
atspi_accessible_get_value_iface (AtspiAccessible *accessible)
{
8
  return (_atspi_accessible_is_a (accessible, atspi_interface_value) ? g_object_ref (ATSPI_VALUE (accessible)) : NULL);
}
static void
2
append_const_val (GArray *array, const gchar *val)
{
2
  gchar *dup = g_strdup (val);
2
  if (dup)
2
    g_array_append_val (array, dup);
2
}
/**
 * atspi_accessible_get_interfaces:
 * @obj: The #AtspiAccessible to query.
 *
 * A set of pointers to all interfaces supported by an #AtspiAccessible.
 *
 * Returns: (element-type gchar*) (transfer full): A #GArray of strings
 *          describing the interfaces supported by the object.  Interfaces are
 *          denoted in short-hand (i.e. "Component", "Text" etc.).
 **/
GArray *
1
atspi_accessible_get_interfaces (AtspiAccessible *obj)
{
1
  GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1
  g_return_val_if_fail (obj != NULL, NULL);
1
  append_const_val (ret, "Accessible");
1
  if (atspi_accessible_is_action (obj))
    append_const_val (ret, "Action");
1
  if (atspi_accessible_is_collection (obj))
1
    append_const_val (ret, "Collection");
1
  if (atspi_accessible_is_component (obj))
    append_const_val (ret, "Component");
1
  if (atspi_accessible_is_document (obj))
    append_const_val (ret, "Document");
1
  if (atspi_accessible_is_editable_text (obj))
    append_const_val (ret, "EditableText");
1
  if (atspi_accessible_is_hypertext (obj))
    append_const_val (ret, "Hypertext");
1
  if (atspi_accessible_is_hyperlink (obj))
    append_const_val (ret, "Hyperlink");
1
  if (atspi_accessible_is_image (obj))
    append_const_val (ret, "Image");
1
  if (atspi_accessible_is_selection (obj))
    append_const_val (ret, "Selection");
1
  if (atspi_accessible_is_table (obj))
    append_const_val (ret, "Table");
1
  if (atspi_accessible_is_table_cell (obj))
    append_const_val (ret, "TableCell");
1
  if (atspi_accessible_is_text (obj))
    append_const_val (ret, "Text");
1
  if (atspi_accessible_is_value (obj))
    append_const_val (ret, "Value");
1
  return ret;
}
AtspiAccessible *
1586
_atspi_accessible_new (AtspiApplication *app, const gchar *path)
{
  AtspiAccessible *accessible;
1586
  accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1586
  accessible->parent.app = g_object_ref (app);
1586
  accessible->parent.path = g_strdup (path);
1586
  return accessible;
}
/**
 * atspi_accessible_set_cache_mask:
 * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
 *             the root of an application.
 * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
 *
 * Sets the type of data to cache for accessibles.
 * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
 * then the desktop's cache flag will be used.
 * If the desktop's cache flag is also undefined, then all possible data will
 * be cached.
 * This function is intended to work around bugs in toolkits where the proper
 * events are not raised / to aid in testing for such bugs.
 **/
void
1
atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
{
1
  g_return_if_fail (accessible != NULL);
1
  g_return_if_fail (accessible->parent.app != NULL);
1
  g_return_if_fail (accessible == accessible->parent.app->root || accessible->role == ATSPI_ROLE_APPLICATION);
1
  accessible->parent.app->cache = mask;
1
  enable_caching = TRUE;
}
static void
5
atspi_accessible_clear_cache_internal (AtspiAccessible *obj, guint iteration_stamp)
{
  gint i;
5
  if (obj && obj->priv->iteration_stamp != iteration_stamp)
    {
5
      obj->priv->iteration_stamp = iteration_stamp;
5
      atspi_accessible_clear_cache_single (obj);
5
      if (obj->children)
8
        for (i = 0; i < obj->children->len; i++)
3
          atspi_accessible_clear_cache_internal (g_ptr_array_index (obj->children, i), iteration_stamp);
    }
5
}
/**
 * atspi_accessible_clear_cache_single:
 * @obj: The #AtspiAccessible whose cache to clear.
 *
 * Clears the cached information only for the given accessible.
 */
void
5
atspi_accessible_clear_cache_single (AtspiAccessible *obj)
{
5
  if (obj)
5
    obj->cached_properties = ATSPI_CACHE_NONE;
5
}
/**
 * atspi_accessible_clear_cache:
 * @obj: The #AtspiAccessible whose cache to clear.
 *
 * Clears the cached information for the given accessible and all of its
 * descendants.
 */
void
2
atspi_accessible_clear_cache (AtspiAccessible *obj)
{
  static guint iteration_stamp = 0;
2
  atspi_accessible_clear_cache_internal (obj, ++iteration_stamp);
2
}
/**
 * atspi_accessible_get_process_id:
 * @accessible: The #AtspiAccessible to query.
 * @error: a pointer to a %NULL #GError pointer
 *
 * Returns the process id associated with the given accessible.  Mainly
 * added for debugging; it is a shortcut to explicitly querying the
 * accessible's app->bus_name and then calling GetConnectionUnixProcessID.
 *
 * Returns: The process ID or undetermined value if @error is set.
 **/
guint
1
atspi_accessible_get_process_id (AtspiAccessible *accessible, GError **error)
{
  DBusMessage *message, *reply;
1
  DBusConnection *bus = _atspi_bus ();
1
  dbus_uint32_t pid = -1;
  DBusError d_error;
1
  if (!accessible->parent.app || !accessible->parent.app->bus_name)
    {
      g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
      return -1;
    }
1
  message = dbus_message_new_method_call ("org.freedesktop.DBus",
                                          "/org/freedesktop/DBus",
                                          "org.freedesktop.DBus",
                                          "GetConnectionUnixProcessID");
1
  dbus_message_append_args (message, DBUS_TYPE_STRING,
1
                            &accessible->parent.app->bus_name,
                            DBUS_TYPE_INVALID);
1
  dbus_error_init (&d_error);
1
  reply = dbus_connection_send_with_reply_and_block (bus, message, -1, &d_error);
1
  dbus_message_unref (message);
1
  if (reply)
    {
1
      if (!strcmp (dbus_message_get_signature (reply), "u"))
1
        dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
1
      dbus_message_unref (reply);
    }
1
  if (dbus_error_is_set (&d_error))
    {
      g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_IPC, "Process is defunct");
      dbus_error_free (&d_error);
    }
1
  return pid;
}
AtspiCache
7339
_atspi_accessible_get_cache_mask (AtspiAccessible *accessible)
{
  AtspiCache mask;
7339
  if (!accessible->parent.app)
    return ATSPI_CACHE_NONE;
7339
  mask = accessible->parent.app->cache;
7339
  if (mask == ATSPI_CACHE_UNDEFINED &&
7339
      accessible->parent.app->root &&
7339
      accessible->parent.app->root->accessible_parent)
    {
3163
      AtspiAccessible *desktop = atspi_get_desktop (0);
3163
      mask = desktop->parent.app->cache;
3163
      g_object_unref (desktop);
    }
7339
  if (mask == ATSPI_CACHE_UNDEFINED)
7339
    mask = ATSPI_CACHE_DEFAULT;
7339
  return mask;
}
gboolean
1452
_atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
{
1452
  AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
1452
  AtspiCache result = accessible->cached_properties & mask & flag;
1452
  if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
    return FALSE;
1838
  return (result != 0 && (atspi_main_loop || enable_caching || flag == ATSPI_CACHE_INTERFACES) &&
386
          !atspi_no_cache);
}
void
5887
_atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
{
5887
  AtspiCache mask = _atspi_accessible_get_cache_mask (accessible);
5887
  accessible->cached_properties |= flag & mask;
5887
}
/**
 * atspi_accessible_get_locale:
 * @accessible: an #AtspiAccessible
 *
 * Gets a UTF-8 string indicating the POSIX-style LC_MESSAGES locale
 * of @accessible.
 *
 * Since: 2.7.91
 *
 * Returns: a UTF-8 string indicating the POSIX-style LC_MESSAGES
 *          locale of @accessible.
 **/
const gchar *
1
atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
{
  gchar *locale;
1
  g_return_val_if_fail (accessible != NULL, NULL);
1
  locale = g_object_get_qdata (G_OBJECT (accessible), quark_locale);
1
  if (!locale)
    {
1
      if (!_atspi_dbus_get_property (accessible, atspi_interface_accessible,
                                     "Locale", error, "s", &locale))
        return NULL;
1
      if (locale)
1
        g_object_set_qdata_full (G_OBJECT (accessible), quark_locale, locale,
                                 g_free);
    }
1
  return locale;
}
/**
 * atspi_accessible_get_accessible_id:
 * @obj: an #AtspiAccessible
 *
 * Gets the accessible id of the accessible.  This is not meant to be presented
 * to the user, but to be an id which is stable over application development.
 * Typically, this is the gtkbuilder id.
 *
 * Since: 2.34
 *
 * Returns: a character string representing the accessible id of the
 * #AtspiAccessible object or NULL on exception.
 **/
gchar *
atspi_accessible_get_accessible_id (AtspiAccessible *obj, GError **error)
{
  gchar *accessible_id;
  g_return_val_if_fail (obj != NULL, NULL);
  if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
                                 "AccessibleId", error, "s", &accessible_id))
    return NULL;
  return accessible_id;
}
/**
 * atspi_accessible_get_help_text:
 * @obj: an #AtspiAccessible
 *
 * Gets the help text associated with the accessible, if set. When this is
 * present, it provides information that a screen reader can relay to the user
 * to explain how to interact with the object.
 *
 * Since: 2.52
 *
 * Returns: a character string representing the help text for the
 * #AtspiAccessible object or NULL on exception.
 **/
gchar *
1
atspi_accessible_get_help_text (AtspiAccessible *obj, GError **error)
{
  gchar *help_text;
1
  g_return_val_if_fail (obj != NULL, NULL);
1
  if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
                                 "HelpText", error, "s", &help_text))
    return NULL;
1
  return help_text;
}
void
free_value (gpointer data)
{
  GValue *value = data;
  g_value_unset (value);
  g_free (value);
}
GHashTable *
323
_atspi_accessible_ref_cache (AtspiAccessible *accessible)
{
323
  AtspiAccessiblePrivate *priv = accessible->priv;
323
  priv->cache_ref_count++;
323
  if (priv->cache)
    return g_hash_table_ref (priv->cache);
323
  priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
                                       free_value);
323
  return priv->cache;
}
void
323
_atspi_accessible_unref_cache (AtspiAccessible *accessible)
{
323
  AtspiAccessiblePrivate *priv = accessible->priv;
323
  if (priv->cache)
    {
323
      g_hash_table_unref (priv->cache);
323
      if (--priv->cache_ref_count == 0)
323
        priv->cache = NULL;
    }
323
}