Remove some redundant out-of-memory checks
[platform/upstream/at-spi2-core.git] / atspi / atspi-accessible.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  * Copyright 2010, 2011 Novell, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "atspi-private.h"
26 #include <string.h>
27
28 static void
29 atspi_action_interface_init (AtspiAction *action)
30 {
31 }
32
33 static void
34 atspi_collection_interface_init (AtspiCollection *component)
35 {
36 }
37
38 static void
39 atspi_component_interface_init (AtspiComponent *component)
40 {
41 }
42
43 static void
44 atspi_document_interface_init (AtspiDocument *document)
45 {
46 }
47
48 static void
49 atspi_editable_text_interface_init (AtspiEditableText *editable_text)
50 {
51 }
52
53 static void
54 atspi_hypertext_interface_init (AtspiHypertext *hypertext)
55 {
56 }
57
58 static void
59 atspi_image_interface_init (AtspiImage *image)
60 {
61 }
62
63 static void
64 atspi_selection_interface_init (AtspiSelection *selection)
65 {
66 }
67
68 static void
69 atspi_table_interface_init (AtspiTable *table)
70 {
71 }
72
73 static void
74 atspi_text_interface_init (AtspiText *text)
75 {
76 }
77
78 static void
79 atspi_value_interface_init (AtspiValue *value)
80 {
81 }
82
83 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
84                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
85                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
86                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
87                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init)
88                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init)
89                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init)
90                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
91                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
92                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
93                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
94                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
95
96 #ifdef DEBUG_REF_COUNTS
97 static gint accessible_count = 0;
98 #endif
99
100 static void
101 atspi_accessible_init (AtspiAccessible *accessible)
102 {
103 #ifdef DEBUG_REF_COUNTS
104   accessible_count++;
105   printf("at-spi: init: %d objects\n", accessible_count);
106 #endif
107 }
108
109 static void
110 atspi_accessible_dispose (GObject *object)
111 {
112   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
113   AtspiEvent e;
114   AtspiAccessible *parent;
115
116   /* TODO: Only fire if object not already marked defunct */
117   memset (&e, 0, sizeof (e));
118   e.type = "object:state-change:defunct";
119   e.source = accessible;
120   e.detail1 = 1;
121   e.detail2 = 0;
122   _atspi_send_event (&e);
123
124   if (accessible->states)
125   {
126     g_object_unref (accessible->states);
127     accessible->states = NULL;
128   }
129
130   parent = accessible->accessible_parent;
131   if (parent && parent->children)
132   {
133     GList*ls = g_list_find (parent->children, accessible);
134     if(ls)
135     {
136       gboolean replace = (ls == parent->children);
137       ls = g_list_remove (ls, accessible);
138       if (replace)
139         parent->children = ls;
140       g_object_unref (object);
141     }
142   }
143
144   if (parent)
145   {
146     g_object_unref (parent);
147     accessible->accessible_parent = NULL;
148   }
149
150   G_OBJECT_CLASS (atspi_accessible_parent_class) ->dispose (object);
151 }
152
153 static void
154 atspi_accessible_finalize (GObject *object)
155 {
156   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
157
158     g_free (accessible->description);
159     g_free (accessible->name);
160
161 #ifdef DEBUG_REF_COUNTS
162   accessible_count--;
163   printf("at-spi: finalize: %d objects\n", accessible_count);
164 #endif
165
166   G_OBJECT_CLASS (atspi_accessible_parent_class)
167     ->finalize (object);
168 }
169
170 static void
171 atspi_accessible_class_init (AtspiAccessibleClass *klass)
172 {
173   GObjectClass *object_class = G_OBJECT_CLASS (klass);
174
175   object_class->dispose = atspi_accessible_dispose;
176   object_class->finalize = atspi_accessible_finalize;
177 }
178
179 /* TODO: Generate following from spec? */
180 static const char *role_names [] =
181 {
182   "invalid",
183   "accel-label",
184   "alert",
185   "animation",
186   "arrow",
187   "calendar",
188   "canvas",
189   "check-box",
190   "check-menu-item",
191   "color-chooser",
192   "column-header",
193   "combo-box",
194   "date-editor",
195   "desktop-icon",
196   "desktop-frame",
197   "dial",
198   "dialog",
199   "directory-pane",
200   "drawing-area",
201   "file-chooser",
202   "filler",
203   "font-chooser",
204   "frame",
205   "glass-pane",
206   "html-container",
207   "icon",
208   "image",
209   "internalframe",
210   "label",
211   "layered-pane",
212   "list",
213   "list-item",
214   "menu",
215   "menu-bar",
216   "menu-item",
217   "option-pane",
218   "page-tab",
219   "page-tab-list",
220   "panel",
221   "password-text",
222   "popup-menu",
223   "progress-bar",
224   "push-button",
225   "radio-button",
226   "radio-menu-item",
227   "root-pane",
228   "row-header",
229   "scroll-bar",
230   "scroll-pane",
231   "separator",
232   "slider",
233   "spin-button",
234   "split-pane",
235   "statusbar",
236   "table",
237   "table-cell",
238   "table-column-header",
239   "table-row-header",
240   "tear-off-menu-item",
241   "terminal",
242   "text",
243   "toggle-button",
244   "tool-bar",
245   "tool-tip",
246   "tree",
247   "tree-table",
248   "unknown",
249   "viewport",
250   "window",
251   NULL,
252   "header",
253   "fooler",
254   "paragraph",
255   "ruler",
256   "application",
257   "autocomplete",
258   "editbar",
259   "embedded",
260   "entry",
261   "chart",
262   "caption",
263   "document_frame",
264   "heading",
265   "page",
266   "section",
267   "form",
268   "redundant object",
269   "link",
270   "input method window"
271 };
272
273 #define MAX_ROLES (sizeof (role_names) / sizeof (char *))
274
275 /**
276  * atspi_role_get_name
277  * @role: an #AtspiAccessibleRole object to query.
278  *
279  * Get a localizeable string that indicates the name of an #AtspiAccessibleRole.
280  * <em>DEPRECATED.</em>
281  *
282  * Returns: a localizable string name for an #AtspiAccessibleRole enumerated type.
283  **/
284 gchar *
285 atspi_role_get_name (AtspiRole role)
286 {
287   if (role < MAX_ROLES && role_names [(int) role])
288     {
289       return g_strdup (role_names [(int) role]);
290     }
291   else
292     {
293       return g_strdup ("");
294     }
295 }
296
297 /**
298  * atspi_accessible_get_name:
299  * @obj: a pointer to the #AtspiAccessible object on which to operate.
300  *
301  * Get the name of an #AtspiAccessible object.
302  *
303  * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object.
304  * or NULL on exception
305  **/
306 gchar *
307 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
308 {
309   g_return_val_if_fail (obj != NULL, g_strdup (""));
310   if (!(obj->cached_properties & ATSPI_CACHE_NAME))
311   {
312     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error,
313                                    "s", &obj->name))
314       return g_strdup ("");
315     _atspi_accessible_add_cache (obj, ATSPI_CACHE_NAME);
316   }
317   return g_strdup (obj->name);
318 }
319
320 /**
321  * atspi_accessible_get_description:
322  * @obj: a pointer to the #AtspiAccessible object on which to operate.
323  *
324  * Get the description of an #AtspiAccessible object.
325  *
326  * Returns: a UTF-8 string describing the #AtspiAccessible object.
327  * or NULL on exception
328  **/
329 gchar *
330 atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
331 {
332   g_return_val_if_fail (obj != NULL, g_strdup (""));
333
334   if (!(obj->cached_properties & ATSPI_CACHE_DESCRIPTION))
335   {
336     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
337                                    "Description", error, "s",
338                                    &obj->description))
339       return g_strdup ("");
340     _atspi_accessible_add_cache (obj, ATSPI_CACHE_DESCRIPTION);
341   }
342   return g_strdup (obj->description);
343 }
344
345 const char *str_parent = "Parent";
346
347 /**
348  * atspi_accessible_get_parent:
349  * @obj: a pointer to the #AtspiAccessible object to query.
350  *
351  * Get an #AtspiAccessible object's parent container.
352  *
353  * Returns: (transfer full): a pointer to the #AtspiAccessible object which
354  *          contains the given #AtspiAccessible instance, or NULL if the @obj
355  *          has no parent container.
356  *
357  **/
358 AtspiAccessible *
359 atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
360 {
361   g_return_val_if_fail (obj != NULL, NULL);
362
363   if (obj->parent.app && !(obj->cached_properties & ATSPI_CACHE_PARENT))
364   {
365     DBusMessage *message, *reply;
366     DBusMessageIter iter, iter_variant;
367     message = dbus_message_new_method_call (obj->parent.app->bus_name,
368                                             obj->parent.path,
369                                             DBUS_INTERFACE_PROPERTIES, "Get");
370     if (!message)
371       return NULL;
372     dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
373                                DBUS_TYPE_STRING, &str_parent,
374                               DBUS_TYPE_INVALID);
375     reply = _atspi_dbus_send_with_reply_and_block (message, error);
376     if (!reply)
377       return NULL;
378     if (strcmp (dbus_message_get_signature (reply), "v") != 0)
379     {
380       dbus_message_unref (reply);
381       return NULL;
382     }
383     dbus_message_iter_init (reply, &iter);
384     dbus_message_iter_recurse (&iter, &iter_variant);
385     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
386     dbus_message_unref (reply);
387     _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
388   }
389   if (!obj->accessible_parent)
390     return NULL;
391   return g_object_ref (obj->accessible_parent);
392 }
393
394 /**
395  * atspi_accessible_get_child_count:
396  * @obj: a pointer to the #AtspiAccessible object on which to operate.
397  *
398  * Get the number of children contained by an #AtspiAccessible object.
399  *
400  * Returns: a #long indicating the number of #AtspiAccessible children
401  *          contained by an #AtspiAccessible object. or -1 on exception
402  *
403  **/
404 gint
405 atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
406 {
407   g_return_val_if_fail (obj != NULL, -1);
408
409   if (!(obj->cached_properties & ATSPI_CACHE_CHILDREN))
410   {
411     dbus_int32_t ret;
412     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
413                                    "ChildCount", error, "i", &ret))
414       return -1;
415     return ret;
416   }
417
418   return g_list_length (obj->children);
419 }
420
421 /**
422  * atspi_accessible_get_child_at_index:
423  * @obj: a pointer to the #AtspiAccessible object on which to operate.
424  * @child_index: a #long indicating which child is specified.
425  *
426  * Get the #AtspiAccessible child of an #AtspiAccessible object at a given index.
427  *
428  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
429  * index @child_index. or NULL on exception
430  **/
431 AtspiAccessible *
432 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
433                             gint    child_index,
434                             GError **error)
435 {
436   AtspiAccessible *child;
437
438   g_return_val_if_fail (obj != NULL, NULL);
439
440   if (!(obj->cached_properties & ATSPI_CACHE_CHILDREN))
441   {
442     DBusMessage *reply;
443     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
444                                      "GetChildAtIndex", error, "i",
445                                      child_index);
446     return _atspi_dbus_return_accessible_from_message (reply);
447   }
448
449   child = g_list_nth_data (obj->children, child_index);
450   if (!child)
451     return NULL;
452   return g_object_ref (child);
453 }
454
455 /**
456  * atspi_accessible_get_index_in_parent
457  * @obj: a pointer to the #AtspiAccessible object on which to operate.
458  *
459  * Get the index of an #AtspiAccessible object in its containing #AtspiAccessible.
460  *
461  * Returns: a #glong indicating the index of the #AtspiAccessible object
462  *          in its parent (i.e. containing) #AtspiAccessible instance,
463  *          or -1 if @obj has no containing parent or on exception.
464  **/
465 gint
466 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
467 {
468   GList *l;
469   gint i = 0;
470
471   g_return_val_if_fail (obj != NULL, -1);
472   if (!obj->accessible_parent) return -1;
473   if (!(obj->accessible_parent->cached_properties & ATSPI_CACHE_CHILDREN))
474   {
475     dbus_uint32_t ret = -1;
476     _atspi_dbus_call (obj, atspi_interface_accessible,
477                       "GetIndexInParent", NULL, "=>u", &ret);
478     return ret;
479   }
480
481   l = obj->accessible_parent->children;
482   while (l)
483   {
484     if (l->data == obj) return i;
485     l = g_list_next (l);
486     i++;
487   }
488   return -1;
489 }
490
491 typedef struct
492 {
493   dbus_uint32_t type;
494   GArray *targets;
495 } Accessibility_Relation;
496
497 /**
498  * atspi_accessible_get_relation_set:
499  * @obj: a pointer to the #AtspiAccessible object on which to operate.
500  *
501  * Get the set of #AtspiRelation objects which describe this #AtspiAccessible object's
502  *       relationships with other #AtspiAccessible objects.
503  *
504  * Returns: (element-type AtspiAccessible*) (transfer full): an array of
505  *          #AtspiAccessibleRelation pointers. or NULL on exception
506  **/
507 GArray *
508 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
509 {
510   DBusMessage *reply;
511   DBusMessageIter iter, iter_array;
512   GArray *ret;
513
514   g_return_val_if_fail (obj != NULL, NULL);
515
516   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
517   if (!reply)
518     return NULL;
519   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
520
521   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
522   dbus_message_iter_init (reply, &iter);
523   dbus_message_iter_recurse (&iter, &iter_array);
524   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
525   {
526     AtspiRelation *relation;
527     relation = _atspi_relation_new_from_iter (&iter_array);
528     ret = g_array_append_val (ret, relation);
529     dbus_message_iter_next (&iter_array);
530   }
531   dbus_message_unref (reply);
532   return ret;
533 }
534
535 /**
536  * atspi_accessible_get_role:
537  * @obj: a pointer to the #AtspiAccessible object on which to operate.
538  *
539  * Get the UI role of an #AtspiAccessible object.
540  * A UTF-8 string describing this role can be obtained via atspi_accessible_getRoleName ().
541  *
542  * Returns: the #AtspiRole of the object.
543  *
544  **/
545 AtspiRole
546 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
547 {
548   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
549
550   if (!(obj->cached_properties & ATSPI_CACHE_ROLE))
551   {
552     dbus_uint32_t role;
553     /* TODO: Make this a property */
554     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
555     {
556       obj->role = role;
557     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
558     }
559   }
560   return obj->role;
561 }
562
563 /**
564  * atspi_accessible_get_role_name:
565  * @obj: a pointer to the #AtspiAccessible object on which to operate.
566  *
567  * Get a UTF-8 string describing the role this object plays in the UI.
568  * This method will return useful values for roles that fall outside the
569  * enumeration used in atspi_accessible_getRole ().
570  *
571  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
572  *
573  **/
574 gchar *
575 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
576 {
577   char *retval = NULL;
578
579   g_return_val_if_fail (obj != NULL, NULL);
580
581   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
582
583   if (!retval)
584     retval = g_strdup ("");
585
586   return retval;
587 }
588
589 /**
590  * atspi_accessible_get_localized_role_name:
591  * @obj: a pointer to the #AtspiAccessible object on which to operate.
592  *
593  * Get a UTF-8 string describing the (localized) role this object plays in the UI.
594  * This method will return useful values for roles that fall outside the
595  * enumeration used in atspi_accessible_getRole ().
596  *
597  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
598  *
599  **/
600 gchar *
601 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
602 {
603   char *retval = NULL;
604
605   g_return_val_if_fail (obj != NULL, NULL);
606
607   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
608
609   if (!retval)
610     return g_strdup ("");
611
612   return retval;
613 }
614
615 static AtspiStateSet *
616 defunct_set ()
617 {
618   AtspiStateSet *set = atspi_state_set_new (NULL);
619   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
620   return set;
621 }
622
623 /**
624  * atspi_accessible_get_state_set:
625  * @obj: a pointer to the #AtspiAccessible object on which to operate.
626  *
627  * Gets the current state of an object.
628  *
629  * Returns: (transfer full): a pointer to an #AtspiStateSet representing the
630  *          object's current state.
631  **/
632 AtspiStateSet *
633 atspi_accessible_get_state_set (AtspiAccessible *obj)
634 {
635   if (!obj->parent.app || !obj->parent.app->bus)
636     return defunct_set ();
637
638
639   if (!(obj->cached_properties & ATSPI_CACHE_STATES))
640   {
641     DBusMessage *reply;
642     DBusMessageIter iter;
643     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
644                                       "GetState", NULL, "");
645     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
646     dbus_message_iter_init (reply, &iter);
647     _atspi_dbus_set_state (obj, &iter);
648     dbus_message_unref (reply);
649     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
650   }
651
652   return g_object_ref (obj->states);
653 }
654
655 /**
656  * atspi_accessible_get_attributes:
657  * @obj: The #AtspiAccessible being queried.
658  *
659  * Get the #AttributeSet representing any assigned 
660  * name-value pair attributes or annotations for this object.
661  * For typographic, textual, or textually-semantic attributes, see
662  * atspi_text_get_attributes instead.
663  *
664  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
665  *          attributes assigned to this object.
666  */
667 GHashTable *
668 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
669 {
670   DBusMessage *message;
671
672     g_return_val_if_fail (obj != NULL, NULL);
673
674   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
675   return _atspi_dbus_return_hash_from_message (message);
676 }
677
678 /**
679  * atspi_accessible_get_attributes_as_array:
680  * @obj: The #AtspiAccessible being queried.
681  *
682  * Get the #AttributeSet representing any assigned 
683  * name-value pair attributes or annotations for this object.
684  * For typographic, textual, or textually-semantic attributes, see
685  * atspi_text_get_attributes_as_array instead.
686  *
687  * Returns: (element-type gchar*) (transfer full): The name-value-pair
688  *          attributes assigned to this object.
689  */
690 GArray *
691 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
692 {
693   DBusMessage *message;
694
695     g_return_val_if_fail (obj != NULL, NULL);
696
697   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
698   return _atspi_dbus_return_attribute_array_from_message (message);
699 }
700
701 /**
702  * atspi_accessible_get_application:
703  * @obj: The #AtspiAccessible being queried.
704  *
705  * Get the containing #AtspiApplication for an object.
706  *
707  * Returns: (transfer full): the containing AtspiApplication instance for
708  *          this object.
709  */
710 AtspiAccessible *
711 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
712 {
713   AtspiAccessible *parent;
714
715   g_object_ref (obj);
716   for (;;)
717   {
718     parent = atspi_accessible_get_parent (obj, NULL);
719     if (!parent && obj->parent.app &&
720         atspi_accessible_get_role (obj, NULL) != ATSPI_ROLE_APPLICATION)
721     {
722       AtspiAccessible *root = g_object_ref (obj->parent.app->root);
723       if (root)
724       {
725         g_object_unref (obj);
726         if (atspi_accessible_get_role (root, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
727         {
728           g_object_unref (root);
729           return NULL;
730         }
731         return root;
732       }
733     }
734     if (!parent || parent == obj ||
735         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
736     return obj;
737     g_object_unref (obj);
738     obj = parent;
739   }
740 }
741
742 /* Application-specific methods */
743
744 /**
745  * atspi_accessible_get_toolkit_name:
746  * @obj: a pointer to the #AtspiAccessible object on which to operate.
747  *
748  * Get the toolkit for a #AtspiAccessible object.
749  * Only works on application root objects.
750  *
751  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object.
752  * or NULL on exception
753  **/
754 gchar *
755 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
756 {
757   gchar *ret = NULL;
758
759   g_return_val_if_fail (obj != NULL, NULL);
760
761   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName", error, "s", &ret))
762       return NULL;
763   return g_strdup (ret);
764 }
765
766 /**
767  * atspi_accessible_get_toolkit_version:
768  * @obj: a pointer to the #AtspiAccessible object on which to operate.
769  *
770  * Get the toolkit version for a #AtspiAccessible object.
771  * Only works on application root objects.
772  *
773  * Returns: a UTF-8 string indicating the toolkit ersion for the #AtspiAccessible object.
774  * or NULL on exception
775  **/
776 gchar *
777 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
778 {
779   gchar *ret = NULL;
780
781   g_return_val_if_fail (obj != NULL, NULL);
782
783   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitVersion", error, "s", &ret))
784       return NULL;
785   return g_strdup (ret);
786 }
787
788 /**
789  * atspi_accessible_get_toolkit_version:
790  * @obj: a pointer to the #AtspiAccessible object on which to operate.
791  *
792  * Get the application id for a #AtspiAccessible object.
793  * Only works on application root objects.
794  *
795  * Returns: a gint indicating the id for the #AtspiAccessible object.
796  * or -1 on exception
797  **/
798 gint
799 atspi_accessible_get_id (AtspiAccessible *obj, GError **error)
800 {
801   gint ret = -1;
802
803   g_return_val_if_fail (obj != NULL, -1);
804
805   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "Id", error, "i", &ret))
806       return -1;
807   return ret;
808 }
809
810
811 /* Interface query methods */
812
813 static gboolean
814 _atspi_accessible_is_a (AtspiAccessible *accessible,
815                       const char *interface_name)
816 {
817   int n;
818
819   if (accessible == NULL)
820     {
821       return FALSE;
822     }
823
824   if (!(accessible->cached_properties & ATSPI_CACHE_INTERFACES))
825   {
826     DBusMessage *reply;
827     DBusMessageIter iter;
828     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
829                                       "GetInterfaces", NULL, "");
830     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
831     dbus_message_iter_init (reply, &iter);
832     _atspi_dbus_set_interfaces (accessible, &iter);
833     dbus_message_unref (reply);
834     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
835   }
836
837   n = _atspi_get_iface_num (interface_name);
838   if (n == -1) return FALSE;
839   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
840 }
841
842 /**
843  * atspi_accessible_is_action:
844  * @obj: a pointer to the #AtspiAccessible instance to query.
845  *
846  * Query whether the specified #AtspiAccessible implements #AtspiAction.
847  *
848  * Returns: #TRUE if @obj implements the #AtspiAction interface,
849  *          #FALSE otherwise.
850  **/
851 gboolean
852 atspi_accessible_is_action (AtspiAccessible *obj)
853 {
854   return _atspi_accessible_is_a (obj,
855                               atspi_interface_action);
856 }
857
858 /**
859  * atspi_accessible_is_application:
860  * @obj: a pointer to the #AtspiAccessible instance to query.
861  *
862  * Query whether the specified #AtspiAccessible implements #AtspiApplication.
863  *
864  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
865  *          #FALSE otherwise.
866  **/
867 gboolean
868 atspi_accessible_is_application (AtspiAccessible *obj)
869 {
870   return _atspi_accessible_is_a (obj,
871                               atspi_interface_application);
872 }
873
874 /**                      
875  * atspi_accessible_is_collection:                                                                                                                                                                          * @obj: a pointer to the #AtspiAccessible instance to query.                                                                                                                                          
876  *                          
877  * Query whether the specified #AtspiAccessible implements #AtspiCollection.    
878  * Returns: #TRUE if @obj implements the #AtspiCollection interface,                                                                                                               
879  *          #FALSE otherwise.
880  **/
881 gboolean
882 atspi_accessible_is_collection (AtspiAccessible *obj)
883 {
884      return _atspi_accessible_is_a (obj,
885                               atspi_interface_collection);
886 }
887
888 /**
889  * atspi_accessible_is_component:
890  * @obj: a pointer to the #AtspiAccessible instance to query.
891  *
892  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
893  *
894  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
895  *          #FALSE otherwise.
896  **/
897 gboolean
898 atspi_accessible_is_component (AtspiAccessible *obj)
899 {
900   return _atspi_accessible_is_a (obj,
901                               atspi_interface_component);
902 }
903
904 /**
905  * atspi_accessible_is_document:
906  * @obj: a pointer to the #AtspiAccessible instance to query.
907  *
908  * Query whether the specified #AtspiAccessible implements #AtspiDocument.
909  *
910  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
911  *          #FALSE otherwise.
912  **/
913 gboolean
914 atspi_accessible_is_document (AtspiAccessible *obj)
915 {
916   return _atspi_accessible_is_a (obj,
917                               atspi_interface_document);
918 }
919
920 /**
921  * atspi_accessible_is_editable_text:
922  * @obj: a pointer to the #AtspiAccessible instance to query.
923  *
924  * Query whether the specified #AtspiAccessible implements #AtspiEditableText.
925  *
926  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
927  *          #FALSE otherwise.
928  **/
929 gboolean
930 atspi_accessible_is_editable_text (AtspiAccessible *obj)
931 {
932   return _atspi_accessible_is_a (obj,
933                               atspi_interface_editable_text);
934 }
935                                                                                                                                                                         
936 /**
937  * atspi_accessible_is_hypertext:
938  * @obj: a pointer to the #AtspiAccessible instance to query.
939  *
940  * Query whether the specified #AtspiAccessible implements #AtspiHypertext.
941  *
942  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
943  *          #FALSE otherwise.
944  **/
945 gboolean
946 atspi_accessible_is_hypertext (AtspiAccessible *obj)
947 {
948   return _atspi_accessible_is_a (obj,
949                               atspi_interface_hypertext);
950 }
951
952 /**
953  * atspi_accessible_is_hyperlink:
954  * @obj: a pointer to the #AtspiAccessible instance to query.
955  *
956  * Query whether the specified #AtspiAccessible implements #AtspiHyperlink.
957  *
958  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
959  *          #FALSE otherwise.
960  **/
961 gboolean
962 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
963 {
964   return _atspi_accessible_is_a (obj,
965                               atspi_interface_hyperlink);
966 }
967
968 /**
969  * atspi_accessible_is_image:
970  * @obj: a pointer to the #AtspiAccessible instance to query.
971  *
972  * Query whether the specified #AtspiAccessible implements #AtspiImage.
973  *
974  * Returns: #TRUE if @obj implements the #AtspiImage interface,
975  *          #FALSE otherwise.
976 **/
977 gboolean
978 atspi_accessible_is_image (AtspiAccessible *obj)
979 {
980   return _atspi_accessible_is_a (obj,
981                               atspi_interface_image);
982 }
983
984 /**
985  * atspi_accessible_is_selection:
986  * @obj: a pointer to the #AtspiAccessible instance to query.
987  *
988  * Query whether the specified #AtspiAccessible implements #AtspiSelection.
989  *
990  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
991  *          #FALSE otherwise.
992 **/
993 gboolean
994 atspi_accessible_is_selection (AtspiAccessible *obj)
995 {
996   return _atspi_accessible_is_a (obj,
997                               atspi_interface_selection);
998 }
999
1000 /**
1001  * atspi_accessible_is_table:
1002  * @obj: a pointer to the #AtspiAccessible instance to query.
1003  *
1004  * Query whether the specified #AtspiAccessible implements #AtspiTable.
1005  *
1006  * Returns: #TRUE if @obj implements the #AtspiTable interface,
1007  *          #FALSE otherwise.
1008 **/
1009 gboolean
1010 atspi_accessible_is_table (AtspiAccessible *obj)
1011 {
1012   return _atspi_accessible_is_a (obj,
1013                               atspi_interface_table);
1014 }
1015
1016 /**
1017  * atspi_accessible_is_streamable_content:
1018  * @obj: a pointer to the #AtspiAccessible instance to query.
1019  *
1020  * Query whether the specified #AtspiAccessible implements
1021  *          #AtspiStreamableContent.
1022  *
1023  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
1024  *          #FALSE otherwise.
1025 **/
1026 gboolean
1027 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
1028 {
1029 #if 0
1030   return _atspi_accessible_is_a (obj,
1031                               atspi_interface_streamable_content);
1032 #else
1033   g_warning ("Streamable content not implemented");
1034   return FALSE;
1035 #endif
1036 }
1037
1038 /**
1039  * atspi_accessible_is_text:
1040  * @obj: a pointer to the #AtspiAccessible instance to query.
1041  *
1042  * Query whether the specified #AtspiAccessible implements #AtspiText.
1043  *
1044  * Returns: #TRUE if @obj implements the #AtspiText interface,
1045  *          #FALSE otherwise.
1046 **/
1047 gboolean
1048 atspi_accessible_is_text (AtspiAccessible *obj)
1049 {
1050   return _atspi_accessible_is_a (obj,
1051                               atspi_interface_text);
1052 }
1053
1054 /**
1055  * atspi_accessible_is_value:
1056  * @obj: a pointer to the #AtspiAccessible instance to query.
1057  *
1058  * Query whether the specified #AtspiAccessible implements #AtspiValue.
1059  *
1060  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1061  *          #FALSE otherwise.
1062 **/
1063 gboolean
1064 atspi_accessible_is_value (AtspiAccessible *obj)
1065 {
1066   return _atspi_accessible_is_a (obj,
1067                               atspi_interface_value);
1068 }
1069
1070 /**
1071  * atspi_accessible_get_action:
1072  * @obj: a pointer to the #AtspiAccessible instance to query.
1073  *
1074  * Get the #AtspiAction interface for an #AtspiAccessible.
1075  *
1076  * Returns: (transfer full): a pointer to an #AtspiAction interface
1077  *          instance, or NULL if @obj does not implement #AtspiAction.
1078  **/
1079 AtspiAction *
1080 atspi_accessible_get_action (AtspiAccessible *accessible)
1081 {
1082   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1083           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1084 }
1085
1086 /**
1087  * atspi_accessible_get_collection:
1088  * @obj: a pointer to the #AtspiAccessible instance to query.
1089  *
1090  * Get the #AtspiCollection interface for an #AtspiAccessible.
1091  *
1092  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1093  *          instance, or NULL if @obj does not implement #AtspiCollection.
1094  **/
1095 AtspiCollection *
1096 atspi_accessible_get_collection (AtspiAccessible *accessible)
1097 {
1098   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1099           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1100 }
1101
1102 /**
1103  * atspi_accessible_get_component:
1104  * @obj: a pointer to the #AtspiAccessible instance to query.
1105  *
1106  * Get the #AtspiComponent interface for an #AtspiAccessible.
1107  *
1108  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1109  *          instance, or NULL if @obj does not implement #AtspiComponent.
1110  **/
1111 AtspiComponent *
1112 atspi_accessible_get_component (AtspiAccessible *obj)
1113 {
1114   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1115           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1116 }
1117
1118 /**
1119  * atspi_accessible_get_document:
1120  * @obj: a pointer to the #AtspiAccessible instance to query.
1121  *
1122  * Get the #AtspiDocument interface for an #AtspiAccessible.
1123  *
1124  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1125  *          instance, or NULL if @obj does not implement #AtspiDocument.
1126  **/
1127 AtspiDocument *
1128 atspi_accessible_get_document (AtspiAccessible *accessible)
1129 {
1130   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1131           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1132 }
1133
1134 /**
1135  * atspi_accessible_get_editable_text:
1136  * @obj: a pointer to the #AtspiAccessible instance to query.
1137  *
1138  * Get the #AtspiEditableText interface for an #AtspiAccessible.
1139  *
1140  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1141  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1142  **/
1143 AtspiEditableText *
1144 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1145 {
1146   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1147           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1148 }
1149
1150 /**
1151  * atspi_accessible_get_hyperlink:
1152  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1153  *
1154  * Get the #AtspiHyperlink associated with the given #AtspiAccessible, if
1155  * supported.
1156  *
1157  * Returns: (transfer full): the #AtspiHyperlink object associated with
1158  *          the given #AtspiAccessible, or NULL if not supported.
1159  **/
1160 AtspiHyperlink *
1161 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1162 {
1163   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1164           atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1165 }
1166
1167 /**
1168  * atspi_accessible_get_hypertext:
1169  * @obj: a pointer to the #AtspiAccessible instance to query.
1170  *
1171  * Get the #AtspiHypertext interface for an #AtspiAccessible.
1172  *
1173  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1174  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1175  **/
1176 AtspiHypertext *
1177 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1178 {
1179   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1180           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1181 }
1182
1183 /**
1184  * atspi_accessible_get_image:
1185  * @obj: a pointer to the #AtspiAccessible instance to query.
1186  *
1187  * Get the #AtspiImage interface for an #AtspiAccessible.
1188  *
1189  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1190  *          NULL if @obj does not implement #AtspiImage.
1191  **/
1192 AtspiImage *
1193 atspi_accessible_get_image (AtspiAccessible *accessible)
1194 {
1195   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1196           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1197 }
1198
1199 /**
1200  * atspi_accessible_get_selection:
1201  * @obj: a pointer to the #AtspiAccessible instance to query.
1202  *
1203  * Get the #AtspiSelection interface for an #AtspiAccessible.
1204  *
1205  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1206  *          instance, or NULL if @obj does not implement #AtspiSelection.
1207  **/
1208 AtspiSelection *
1209 atspi_accessible_get_selection (AtspiAccessible *accessible)
1210 {
1211   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1212           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1213 }
1214
1215 #if 0
1216 /**
1217  * atspi_accessible_get_streamable_content:
1218  * @obj: a pointer to the #AtspiAccessible instance to query.
1219  *
1220  * Get the #AtspiStreamableContent interface for an #AtspiAccessible.
1221  *
1222  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1223  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1224  **/
1225 AtspiStreamableContent *
1226 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1227 {
1228   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1229           accessible : NULL);  
1230 }
1231 #endif
1232
1233 /**
1234  * atspi_accessible_get_table:
1235  * @obj: a pointer to the #AtspiAccessible instance to query.
1236  *
1237  * Get the #AtspiTable interface for an #AtspiAccessible.
1238  *
1239  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1240  *          NULL if @obj does not implement #AtspiTable.
1241  **/
1242 AtspiTable *
1243 atspi_accessible_get_table (AtspiAccessible *obj)
1244 {
1245   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1246           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1247 }
1248
1249 /**
1250  * atspi_accessible_get_text:
1251  * @obj: a pointer to the #AtspiAccessible instance to query.
1252  *
1253  * Get the #AtspiTable interface for an #AtspiAccessible.
1254  *
1255  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1256  *          NULL if @obj does not implement #AtspiText.
1257  **/
1258 AtspiText *
1259 atspi_accessible_get_text (AtspiAccessible *obj)
1260 {
1261   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1262           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1263 }
1264
1265 /**
1266  * atspi_accessible_get_value:
1267  * @obj: a pointer to the #AtspiAccessible instance to query.
1268  *
1269  * Get the #AtspiTable interface for an #AtspiAccessible.
1270  *
1271  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1272  *          NULL if @obj does not implement #AtspiValue.
1273  **/
1274 AtspiValue *
1275 atspi_accessible_get_value (AtspiAccessible *accessible)
1276 {
1277   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1278           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1279 }
1280
1281 static void
1282 append_const_val (GArray *array, const gchar *val)
1283 {
1284   gchar *dup = g_strdup (val);
1285
1286   if (dup)
1287     g_array_append_val (array, dup);
1288 }
1289
1290 /**
1291  * atspi_accessible_get_interfaces:
1292  *
1293  * #obj: The #AtspiAccessible to query.
1294  *
1295  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
1296  *          describing the interfaces supported by the object.  Interfaces are
1297  *          denoted in short-hand (ie, "Component", "Text", etc.)
1298  **/
1299 GArray *
1300 atspi_accessible_get_interfaces (AtspiAccessible *obj)
1301 {
1302   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1303
1304   g_return_val_if_fail (obj != NULL, NULL);
1305
1306   append_const_val (ret, "Accessible");
1307   if (atspi_accessible_is_action (obj))
1308     append_const_val (ret, "Action");
1309   if (atspi_accessible_is_collection (obj))
1310     append_const_val (ret, "Collection");
1311   if (atspi_accessible_is_component (obj))
1312     append_const_val (ret, "Component");
1313   if (atspi_accessible_is_document (obj))
1314     append_const_val (ret, "Document");
1315   if (atspi_accessible_is_editable_text (obj))
1316     append_const_val (ret, "EditableText");
1317   if (atspi_accessible_is_hypertext (obj))
1318     append_const_val (ret, "Hypertext");
1319   if (atspi_accessible_is_hyperlink (obj))
1320     append_const_val (ret, "Hyperlink");
1321   if (atspi_accessible_is_image (obj))
1322     append_const_val (ret, "Image");
1323   if (atspi_accessible_is_selection (obj))
1324     append_const_val (ret, "Selection");
1325   if (atspi_accessible_is_table (obj))
1326     append_const_val (ret, "Table");
1327   if (atspi_accessible_is_text (obj))
1328     append_const_val (ret, "Text");
1329   if (atspi_accessible_is_value (obj))
1330     append_const_val (ret, "Value");
1331
1332   return ret;
1333 }
1334
1335 AtspiAccessible *
1336 atspi_accessible_new (AtspiApplication *app, const gchar *path)
1337 {
1338   AtspiAccessible *accessible;
1339   
1340   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1341   g_return_val_if_fail (accessible != NULL, NULL);
1342
1343   accessible->parent.app = g_object_ref (app);
1344   accessible->parent.path = g_strdup (path);
1345
1346   return accessible;
1347 }
1348
1349 /**
1350  * atspi_accessible_set_cache_mask:
1351  *
1352  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
1353  *             the root of an application.
1354  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
1355  *
1356  * Sets the type of data to cache for accessibles.
1357  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
1358  * then the desktop's cache flag will be used.
1359  * If the desktop's cache flag is also undefined, then all possible data will
1360  * be cached.
1361  * This function is intended to work around bugs in toolkits where the proper
1362  * events are not raised / to aid in testing for such bugs.
1363  *
1364  * Note: This function has no effect on data that has already been cached.
1365  **/
1366 void
1367 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
1368 {
1369   g_return_if_fail (accessible != NULL);
1370   g_return_if_fail (accessible->parent.app != NULL);
1371   g_return_if_fail (accessible == accessible->parent.app->root);
1372   accessible->parent.app->cache = mask;
1373 }
1374
1375 void
1376 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
1377 {
1378   AtspiCache mask = accessible->parent.app->cache;
1379
1380   if (mask == ATSPI_CACHE_UNDEFINED &&
1381       accessible->parent.app->root &&
1382       accessible->parent.app->root->accessible_parent)
1383   {
1384     AtspiAccessible *desktop = atspi_get_desktop (0);
1385     mask = desktop->parent.app->cache;
1386     g_object_unref (desktop);
1387   }
1388
1389   if (mask == ATSPI_CACHE_UNDEFINED)
1390     mask = ATSPI_CACHE_ALL;
1391
1392   accessible->cached_properties |= flag & mask;
1393 }