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