Add atspi_accessible_set_cache_mask
[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 static void
48 atspi_editable_text_interface_init (AtspiEditableText *editable_text)
49 {
50 }
51
52 static void
53 atspi_hypertext_interface_init (AtspiHypertext *hypertext)
54 {
55 }
56
57 static void
58 atspi_image_interface_init (AtspiImage *image)
59 {
60 }
61
62 static void
63 atspi_selection_interface_init (AtspiSelection *selection)
64 {
65 }
66
67 static void
68 atspi_table_interface_init (AtspiTable *table)
69 {
70 }
71
72 static void
73 atspi_text_interface_init (AtspiText *text)
74 {
75 }
76
77 static void
78 atspi_value_interface_init (AtspiValue *value)
79 {
80 }
81
82 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
83                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
84                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
85                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
86                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_DOCUMENT, atspi_document_interface_init)
87                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_EDITABLE_TEXT, atspi_editable_text_interface_init)
88                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_HYPERTEXT, atspi_hypertext_interface_init)
89                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_IMAGE, atspi_image_interface_init)
90                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_SELECTION, atspi_selection_interface_init)
91                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TABLE, atspi_table_interface_init)
92                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_TEXT, atspi_text_interface_init)
93                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_VALUE, atspi_value_interface_init))
94
95 #ifdef DEBUG_REF_COUNTS
96 static gint accessible_count = 0;
97 #endif
98
99 static void
100 atspi_accessible_init (AtspiAccessible *accessible)
101 {
102 #ifdef DEBUG_REF_COUNTS
103   accessible_count++;
104   printf("at-spi: init: %d objects\n", accessible_count);
105 #endif
106 }
107
108 static void
109 atspi_accessible_dispose (GObject *object)
110 {
111   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (object);
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     _atspi_accessible_add_cache (obj, 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     _atspi_accessible_add_cache (obj, 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->parent.app && !(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, error);
375     if (!reply)
376       return NULL;
377     if (strcmp (dbus_message_get_signature (reply), "v") != 0)
378     {
379       dbus_message_unref (reply);
380       return NULL;
381     }
382     dbus_message_iter_init (reply, &iter);
383     dbus_message_iter_recurse (&iter, &iter_variant);
384     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
385     dbus_message_unref (reply);
386     _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT);
387   }
388   if (!obj->accessible_parent)
389     return NULL;
390   return g_object_ref (obj->accessible_parent);
391 }
392
393 /**
394  * atspi_accessible_get_child_count:
395  * @obj: a pointer to the #AtspiAccessible object on which to operate.
396  *
397  * Get the number of children contained by an #AtspiAccessible object.
398  *
399  * Returns: a #long indicating the number of #AtspiAccessible children
400  *          contained by an #AtspiAccessible object. or -1 on exception
401  *
402  **/
403 gint
404 atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error)
405 {
406   g_return_val_if_fail (obj != NULL, -1);
407
408   if (!(obj->cached_properties & ATSPI_CACHE_CHILDREN))
409   {
410     dbus_int32_t ret;
411     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible,
412                                    "ChildCount", error, "i", &ret))
413       return -1;
414     return ret;
415   }
416
417   return g_list_length (obj->children);
418 }
419
420 /**
421  * atspi_accessible_get_child_at_index:
422  * @obj: a pointer to the #AtspiAccessible object on which to operate.
423  * @child_index: a #long indicating which child is specified.
424  *
425  * Get the #AtspiAccessible child of an #AtspiAccessible object at a given index.
426  *
427  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
428  * index @child_index. or NULL on exception
429  **/
430 AtspiAccessible *
431 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
432                             gint    child_index,
433                             GError **error)
434 {
435   AtspiAccessible *child;
436
437   g_return_val_if_fail (obj != NULL, NULL);
438
439   if (!(obj->cached_properties & ATSPI_CACHE_CHILDREN))
440   {
441     DBusMessage *reply;
442     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
443                                      "GetChildAtIndex", error, "i",
444                                      child_index);
445     return _atspi_dbus_return_accessible_from_message (reply);
446   }
447
448   child = g_list_nth_data (obj->children, child_index);
449   if (!child)
450     return NULL;
451   return g_object_ref (child);
452 }
453
454 /**
455  * atspi_accessible_get_index_in_parent
456  * @obj: a pointer to the #AtspiAccessible object on which to operate.
457  *
458  * Get the index of an #AtspiAccessible object in its containing #AtspiAccessible.
459  *
460  * Returns: a #glong indicating the index of the #AtspiAccessible object
461  *          in its parent (i.e. containing) #AtspiAccessible instance,
462  *          or -1 if @obj has no containing parent or on exception.
463  **/
464 gint
465 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
466 {
467   GList *l;
468   gint i = 0;
469
470   g_return_val_if_fail (obj != NULL, -1);
471   if (!obj->accessible_parent) return -1;
472   if (!(obj->accessible_parent->cached_properties & ATSPI_CACHE_CHILDREN))
473   {
474     dbus_uint32_t ret = -1;
475     _atspi_dbus_call (obj, atspi_interface_accessible,
476                       "GetIndexInParent", NULL, "=>u", &ret);
477     return ret;
478   }
479
480   l = obj->accessible_parent->children;
481   while (l)
482   {
483     if (l->data == obj) return i;
484     l = g_list_next (l);
485     i++;
486   }
487   return -1;
488 }
489
490 typedef struct
491 {
492   dbus_uint32_t type;
493   GArray *targets;
494 } Accessibility_Relation;
495
496 /**
497  * atspi_accessible_get_relation_set:
498  * @obj: a pointer to the #AtspiAccessible object on which to operate.
499  *
500  * Get the set of #AtspiRelation objects which describe this #AtspiAccessible object's
501  *       relationships with other #AtspiAccessible objects.
502  *
503  * Returns: (element-type AtspiAccessible*) (transfer full): an array of
504  *          #AtspiAccessibleRelation pointers. or NULL on exception
505  **/
506 GArray *
507 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
508 {
509   DBusMessage *reply;
510   DBusMessageIter iter, iter_array;
511   GArray *ret;
512
513   g_return_val_if_fail (obj != NULL, NULL);
514
515   reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetRelationSet", error, "");
516   if (!reply)
517     return NULL;
518   _ATSPI_DBUS_CHECK_SIG (reply, "a(ua(so))", error, NULL);
519
520   ret = g_array_new (TRUE, TRUE, sizeof (AtspiRelation *));
521   dbus_message_iter_init (reply, &iter);
522   dbus_message_iter_recurse (&iter, &iter_array);
523   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
524   {
525     GArray *new_array;
526     AtspiRelation *relation;
527     relation = _atspi_relation_new_from_iter (&iter_array);
528     new_array = g_array_append_val (ret, relation);
529     if (new_array)
530       ret = new_array;
531     dbus_message_iter_next (&iter_array);
532   }
533   dbus_message_unref (reply);
534   return ret;
535 }
536
537 /**
538  * atspi_accessible_get_role:
539  * @obj: a pointer to the #AtspiAccessible object on which to operate.
540  *
541  * Get the UI role of an #AtspiAccessible object.
542  * A UTF-8 string describing this role can be obtained via atspi_accessible_getRoleName ().
543  *
544  * Returns: the #AtspiRole of the object.
545  *
546  **/
547 AtspiRole
548 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
549 {
550   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
551
552   if (!(obj->cached_properties & ATSPI_CACHE_ROLE))
553   {
554     dbus_uint32_t role;
555     /* TODO: Make this a property */
556     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", error, "=>u", &role))
557     {
558       obj->role = role;
559     _atspi_accessible_add_cache (obj, ATSPI_CACHE_ROLE);
560     }
561   }
562   return obj->role;
563 }
564
565 /**
566  * atspi_accessible_get_role_name:
567  * @obj: a pointer to the #AtspiAccessible object on which to operate.
568  *
569  * Get a UTF-8 string describing the role this object plays in the UI.
570  * This method will return useful values for roles that fall outside the
571  * enumeration used in atspi_accessible_getRole ().
572  *
573  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
574  *
575  **/
576 gchar *
577 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
578 {
579   char *retval = NULL;
580
581   g_return_val_if_fail (obj != NULL, NULL);
582
583   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
584
585   if (!retval)
586     retval = g_strdup ("");
587
588   return retval;
589 }
590
591 /**
592  * atspi_accessible_get_localized_role_name:
593  * @obj: a pointer to the #AtspiAccessible object on which to operate.
594  *
595  * Get a UTF-8 string describing the (localized) role this object plays in the UI.
596  * This method will return useful values for roles that fall outside the
597  * enumeration used in atspi_accessible_getRole ().
598  *
599  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
600  *
601  **/
602 gchar *
603 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
604 {
605   char *retval = NULL;
606
607   g_return_val_if_fail (obj != NULL, NULL);
608
609   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
610
611   if (!retval)
612     return g_strdup ("");
613
614   return retval;
615 }
616
617 static AtspiStateSet *
618 defunct_set ()
619 {
620   AtspiStateSet *set = atspi_state_set_new (NULL);
621   atspi_state_set_add (set, ATSPI_STATE_DEFUNCT);
622   return set;
623 }
624
625 /**
626  * atspi_accessible_get_state_set:
627  * @obj: a pointer to the #AtspiAccessible object on which to operate.
628  *
629  * Gets the current state of an object.
630  *
631  * Returns: (transfer full): a pointer to an #AtspiStateSet representing the
632  *          object's current state.
633  **/
634 AtspiStateSet *
635 atspi_accessible_get_state_set (AtspiAccessible *obj)
636 {
637   if (!obj->parent.app || !obj->parent.app->bus)
638     return defunct_set ();
639
640
641   if (!(obj->cached_properties & ATSPI_CACHE_STATES))
642   {
643     DBusMessage *reply;
644     DBusMessageIter iter;
645     reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
646                                       "GetState", NULL, "");
647     _ATSPI_DBUS_CHECK_SIG (reply, "au", NULL, defunct_set ());
648     dbus_message_iter_init (reply, &iter);
649     _atspi_dbus_set_state (obj, &iter);
650     dbus_message_unref (reply);
651     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
652   }
653
654   return g_object_ref (obj->states);
655 }
656
657 /**
658  * atspi_accessible_get_attributes:
659  * @obj: The #AtspiAccessible being queried.
660  *
661  * Get the #AttributeSet representing any assigned 
662  * name-value pair attributes or annotations for this object.
663  * For typographic, textual, or textually-semantic attributes, see
664  * atspi_text_get_attributes instead.
665  *
666  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
667  *          attributes assigned to this object.
668  */
669 GHashTable *
670 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
671 {
672   DBusMessage *message;
673
674     g_return_val_if_fail (obj != NULL, NULL);
675
676   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
677   return _atspi_dbus_return_hash_from_message (message);
678 }
679
680 /**
681  * atspi_accessible_get_attributes_as_array:
682  * @obj: The #AtspiAccessible being queried.
683  *
684  * Get the #AttributeSet representing any assigned 
685  * name-value pair attributes or annotations for this object.
686  * For typographic, textual, or textually-semantic attributes, see
687  * atspi_text_get_attributes_as_array instead.
688  *
689  * Returns: (element-type gchar*) (transfer full): The name-value-pair
690  *          attributes assigned to this object.
691  */
692 GArray *
693 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
694 {
695   DBusMessage *message;
696
697     g_return_val_if_fail (obj != NULL, NULL);
698
699   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
700   return _atspi_dbus_return_attribute_array_from_message (message);
701 }
702
703 /**
704  * atspi_accessible_get_application:
705  * @obj: The #AtspiAccessible being queried.
706  *
707  * Get the containing #AtspiApplication for an object.
708  *
709  * Returns: (transfer full): the containing AtspiApplication instance for
710  *          this object.
711  */
712 AtspiAccessible *
713 atspi_accessible_get_application (AtspiAccessible *obj, GError **error)
714 {
715   AtspiAccessible *parent;
716
717   g_object_ref (obj);
718   for (;;)
719   {
720     parent = atspi_accessible_get_parent (obj, NULL);
721     if (!parent || parent == obj ||
722         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
723     return obj;
724     g_object_unref (obj);
725     obj = parent;
726   }
727 }
728
729 /* Application-specific methods */
730
731 /**
732  * atspi_accessible_get_toolkit_name:
733  * @obj: a pointer to the #AtspiAccessible object on which to operate.
734  *
735  * Get the toolkit for a #AtspiAccessible object.
736  * Only works on application root objects.
737  *
738  * Returns: a UTF-8 string indicating the toolkit name for the #AtspiAccessible object.
739  * or NULL on exception
740  **/
741 gchar *
742 atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error)
743 {
744   gchar *ret = NULL;
745
746   g_return_val_if_fail (obj != NULL, NULL);
747
748   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitName", error, "s", &ret))
749       return NULL;
750   return g_strdup (ret);
751 }
752
753 /**
754  * atspi_accessible_get_toolkit_version:
755  * @obj: a pointer to the #AtspiAccessible object on which to operate.
756  *
757  * Get the toolkit version for a #AtspiAccessible object.
758  * Only works on application root objects.
759  *
760  * Returns: a UTF-8 string indicating the toolkit ersion for the #AtspiAccessible object.
761  * or NULL on exception
762  **/
763 gchar *
764 atspi_accessible_get_toolkit_version (AtspiAccessible *obj, GError **error)
765 {
766   gchar *ret = NULL;
767
768   g_return_val_if_fail (obj != NULL, NULL);
769
770   if (!_atspi_dbus_get_property (obj, atspi_interface_application, "ToolkitVersion", error, "s", &ret))
771       return NULL;
772   return g_strdup (ret);
773 }
774 /* Interface query methods */
775
776 static gboolean
777 _atspi_accessible_is_a (AtspiAccessible *accessible,
778                       const char *interface_name)
779 {
780   int n;
781
782   if (accessible == NULL)
783     {
784       return FALSE;
785     }
786
787   if (!(accessible->cached_properties & ATSPI_CACHE_INTERFACES))
788   {
789     DBusMessage *reply;
790     DBusMessageIter iter;
791     reply = _atspi_dbus_call_partial (accessible, atspi_interface_accessible,
792                                       "GetInterfaces", NULL, "");
793     _ATSPI_DBUS_CHECK_SIG (reply, "as", NULL, FALSE);
794     dbus_message_iter_init (reply, &iter);
795     _atspi_dbus_set_interfaces (accessible, &iter);
796     dbus_message_unref (reply);
797     _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES);
798   }
799
800   n = _atspi_get_iface_num (interface_name);
801   if (n == -1) return FALSE;
802   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
803 }
804
805 /**
806  * atspi_accessible_is_action:
807  * @obj: a pointer to the #AtspiAccessible instance to query.
808  *
809  * Query whether the specified #AtspiAccessible implements #AtspiAction.
810  *
811  * Returns: #TRUE if @obj implements the #AtspiAction interface,
812  *          #FALSE otherwise.
813  **/
814 gboolean
815 atspi_accessible_is_action (AtspiAccessible *obj)
816 {
817   return _atspi_accessible_is_a (obj,
818                               atspi_interface_action);
819 }
820
821 /**
822  * atspi_accessible_is_application:
823  * @obj: a pointer to the #AtspiAccessible instance to query.
824  *
825  * Query whether the specified #AtspiAccessible implements #AtspiApplication.
826  *
827  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
828  *          #FALSE otherwise.
829  **/
830 gboolean
831 atspi_accessible_is_application (AtspiAccessible *obj)
832 {
833   return _atspi_accessible_is_a (obj,
834                               atspi_interface_application);
835 }
836
837 /**                      
838  * atspi_accessible_is_collection:                                                                                                                                                                          * @obj: a pointer to the #AtspiAccessible instance to query.                                                                                                                                          
839  *                          
840  * Query whether the specified #AtspiAccessible implements #AtspiCollection.    
841  * Returns: #TRUE if @obj implements the #AtspiCollection interface,                                                                                                               
842  *          #FALSE otherwise.
843  **/
844 gboolean
845 atspi_accessible_is_collection (AtspiAccessible *obj)
846 {
847      return _atspi_accessible_is_a (obj,
848                               atspi_interface_collection);
849 }
850
851 /**
852  * atspi_accessible_is_component:
853  * @obj: a pointer to the #AtspiAccessible instance to query.
854  *
855  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
856  *
857  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
858  *          #FALSE otherwise.
859  **/
860 gboolean
861 atspi_accessible_is_component (AtspiAccessible *obj)
862 {
863   return _atspi_accessible_is_a (obj,
864                               atspi_interface_component);
865 }
866
867 /**
868  * atspi_accessible_is_document:
869  * @obj: a pointer to the #AtspiAccessible instance to query.
870  *
871  * Query whether the specified #AtspiAccessible implements #AtspiDocument.
872  *
873  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
874  *          #FALSE otherwise.
875  **/
876 gboolean
877 atspi_accessible_is_document (AtspiAccessible *obj)
878 {
879   return _atspi_accessible_is_a (obj,
880                               atspi_interface_document);
881 }
882
883 /**
884  * atspi_accessible_is_editable_text:
885  * @obj: a pointer to the #AtspiAccessible instance to query.
886  *
887  * Query whether the specified #AtspiAccessible implements #AtspiEditableText.
888  *
889  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
890  *          #FALSE otherwise.
891  **/
892 gboolean
893 atspi_accessible_is_editable_text (AtspiAccessible *obj)
894 {
895   return _atspi_accessible_is_a (obj,
896                               atspi_interface_editable_text);
897 }
898                                                                                                                                                                         
899 /**
900  * atspi_accessible_is_hypertext:
901  * @obj: a pointer to the #AtspiAccessible instance to query.
902  *
903  * Query whether the specified #AtspiAccessible implements #AtspiHypertext.
904  *
905  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
906  *          #FALSE otherwise.
907  **/
908 gboolean
909 atspi_accessible_is_hypertext (AtspiAccessible *obj)
910 {
911   return _atspi_accessible_is_a (obj,
912                               atspi_interface_hypertext);
913 }
914
915 /**
916  * atspi_accessible_is_hyperlink:
917  * @obj: a pointer to the #AtspiAccessible instance to query.
918  *
919  * Query whether the specified #AtspiAccessible implements #AtspiHyperlink.
920  *
921  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
922  *          #FALSE otherwise.
923  **/
924 gboolean
925 atspi_accessible_is_hyperlink (AtspiAccessible *obj)
926 {
927   return _atspi_accessible_is_a (obj,
928                               atspi_interface_hyperlink);
929 }
930
931 /**
932  * atspi_accessible_is_image:
933  * @obj: a pointer to the #AtspiAccessible instance to query.
934  *
935  * Query whether the specified #AtspiAccessible implements #AtspiImage.
936  *
937  * Returns: #TRUE if @obj implements the #AtspiImage interface,
938  *          #FALSE otherwise.
939 **/
940 gboolean
941 atspi_accessible_is_image (AtspiAccessible *obj)
942 {
943   return _atspi_accessible_is_a (obj,
944                               atspi_interface_image);
945 }
946
947 /**
948  * atspi_accessible_is_selection:
949  * @obj: a pointer to the #AtspiAccessible instance to query.
950  *
951  * Query whether the specified #AtspiAccessible implements #AtspiSelection.
952  *
953  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
954  *          #FALSE otherwise.
955 **/
956 gboolean
957 atspi_accessible_is_selection (AtspiAccessible *obj)
958 {
959   return _atspi_accessible_is_a (obj,
960                               atspi_interface_selection);
961 }
962
963 /**
964  * atspi_accessible_is_table:
965  * @obj: a pointer to the #AtspiAccessible instance to query.
966  *
967  * Query whether the specified #AtspiAccessible implements #AtspiTable.
968  *
969  * Returns: #TRUE if @obj implements the #AtspiTable interface,
970  *          #FALSE otherwise.
971 **/
972 gboolean
973 atspi_accessible_is_table (AtspiAccessible *obj)
974 {
975   return _atspi_accessible_is_a (obj,
976                               atspi_interface_table);
977 }
978
979 /**
980  * atspi_accessible_is_streamable_content:
981  * @obj: a pointer to the #AtspiAccessible instance to query.
982  *
983  * Query whether the specified #AtspiAccessible implements
984  *          #AtspiStreamableContent.
985  *
986  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
987  *          #FALSE otherwise.
988 **/
989 gboolean
990 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
991 {
992 #if 0
993   return _atspi_accessible_is_a (obj,
994                               atspi_interface_streamable_content);
995 #else
996   g_warning (_("Streamable content not implemented"));
997   return FALSE;
998 #endif
999 }
1000
1001 /**
1002  * atspi_accessible_is_text:
1003  * @obj: a pointer to the #AtspiAccessible instance to query.
1004  *
1005  * Query whether the specified #AtspiAccessible implements #AtspiText.
1006  *
1007  * Returns: #TRUE if @obj implements the #AtspiText interface,
1008  *          #FALSE otherwise.
1009 **/
1010 gboolean
1011 atspi_accessible_is_text (AtspiAccessible *obj)
1012 {
1013   return _atspi_accessible_is_a (obj,
1014                               atspi_interface_text);
1015 }
1016
1017 /**
1018  * atspi_accessible_is_value:
1019  * @obj: a pointer to the #AtspiAccessible instance to query.
1020  *
1021  * Query whether the specified #AtspiAccessible implements #AtspiValue.
1022  *
1023  * Returns: #TRUE if @obj implements the #AtspiValue interface,
1024  *          #FALSE otherwise.
1025 **/
1026 gboolean
1027 atspi_accessible_is_value (AtspiAccessible *obj)
1028 {
1029   return _atspi_accessible_is_a (obj,
1030                               atspi_interface_value);
1031 }
1032
1033 /**
1034  * atspi_accessible_get_action:
1035  * @obj: a pointer to the #AtspiAccessible instance to query.
1036  *
1037  * Get the #AtspiAction interface for an #AtspiAccessible.
1038  *
1039  * Returns: (transfer full): a pointer to an #AtspiAction interface
1040  *          instance, or NULL if @obj does not implement #AtspiAction.
1041  **/
1042 AtspiAction *
1043 atspi_accessible_get_action (AtspiAccessible *accessible)
1044 {
1045   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
1046           g_object_ref (ATSPI_ACTION (accessible)) : NULL);  
1047 }
1048
1049 /**
1050  * atspi_accessible_get_collection:
1051  * @obj: a pointer to the #AtspiAccessible instance to query.
1052  *
1053  * Get the #AtspiCollection interface for an #AtspiAccessible.
1054  *
1055  * Returns: (transfer full): a pointer to an #AtspiCollection interface
1056  *          instance, or NULL if @obj does not implement #AtspiCollection.
1057  **/
1058 AtspiCollection *
1059 atspi_accessible_get_collection (AtspiAccessible *accessible)
1060 {
1061   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
1062           g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);  
1063 }
1064
1065 /**
1066  * atspi_accessible_get_component:
1067  * @obj: a pointer to the #AtspiAccessible instance to query.
1068  *
1069  * Get the #AtspiComponent interface for an #AtspiAccessible.
1070  *
1071  * Returns: (transfer full): a pointer to an #AtspiComponent interface
1072  *          instance, or NULL if @obj does not implement #AtspiComponent.
1073  **/
1074 AtspiComponent *
1075 atspi_accessible_get_component (AtspiAccessible *obj)
1076 {
1077   return (_atspi_accessible_is_a (obj, atspi_interface_component) ?
1078           g_object_ref (ATSPI_COMPONENT (obj)) : NULL);
1079 }
1080
1081 /**
1082  * atspi_accessible_get_document:
1083  * @obj: a pointer to the #AtspiAccessible instance to query.
1084  *
1085  * Get the #AtspiDocument interface for an #AtspiAccessible.
1086  *
1087  * Returns: (transfer full): a pointer to an #AtspiDocument interface
1088  *          instance, or NULL if @obj does not implement #AtspiDocument.
1089  **/
1090 AtspiDocument *
1091 atspi_accessible_get_document (AtspiAccessible *accessible)
1092 {
1093   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
1094           g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);  
1095 }
1096
1097 /**
1098  * atspi_accessible_get_editable_text:
1099  * @obj: a pointer to the #AtspiAccessible instance to query.
1100  *
1101  * Get the #AtspiEditableText interface for an #AtspiAccessible.
1102  *
1103  * Returns: (transfer full): a pointer to an #AtspiEditableText interface
1104  *          instance, or NULL if @obj does not implement #AtspiEditableText.
1105  **/
1106 AtspiEditableText *
1107 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
1108 {
1109   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
1110           g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);  
1111 }
1112
1113 /**
1114  * atspi_accessible_get_hyperlink:
1115  * @obj: a pointer to the #AtspiAccessible object on which to operate.
1116  *
1117  * Get the #AtspiHyperlink associated with the given #AtspiAccessible, if
1118  * supported.
1119  *
1120  * Returns: (transfer full): the #AtspiHyperlink object associated with
1121  *          the given #AtspiAccessible, or NULL if not supported.
1122  **/
1123 AtspiHyperlink *
1124 atspi_accessible_get_hyperlink (AtspiAccessible *accessible)
1125 {
1126   return (_atspi_accessible_is_a (accessible, atspi_interface_hyperlink) ?
1127           atspi_hyperlink_new (accessible->parent.app, accessible->parent.path) : NULL);
1128 }
1129
1130 /**
1131  * atspi_accessible_get_hypertext:
1132  * @obj: a pointer to the #AtspiAccessible instance to query.
1133  *
1134  * Get the #AtspiHypertext interface for an #AtspiAccessible.
1135  *
1136  * Returns: (transfer full): a pointer to an #AtspiHypertext interface
1137  *          instance, or NULL if @obj does not implement #AtspiHypertext.
1138  **/
1139 AtspiHypertext *
1140 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
1141 {
1142   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
1143           g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);  
1144 }
1145
1146 /**
1147  * atspi_accessible_get_image:
1148  * @obj: a pointer to the #AtspiAccessible instance to query.
1149  *
1150  * Get the #AtspiImage interface for an #AtspiAccessible.
1151  *
1152  * Returns: (transfer full): a pointer to an #AtspiImage interface instance, or
1153  *          NULL if @obj does not implement #AtspiImage.
1154  **/
1155 AtspiImage *
1156 atspi_accessible_get_image (AtspiAccessible *accessible)
1157 {
1158   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
1159           g_object_ref (ATSPI_IMAGE (accessible)) : NULL);  
1160 }
1161
1162 /**
1163  * atspi_accessible_get_selection:
1164  * @obj: a pointer to the #AtspiAccessible instance to query.
1165  *
1166  * Get the #AtspiSelection interface for an #AtspiAccessible.
1167  *
1168  * Returns: (transfer full): a pointer to an #AtspiSelection interface
1169  *          instance, or NULL if @obj does not implement #AtspiSelection.
1170  **/
1171 AtspiSelection *
1172 atspi_accessible_get_selection (AtspiAccessible *accessible)
1173 {
1174   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
1175           g_object_ref (ATSPI_SELECTION (accessible)) : NULL);  
1176 }
1177
1178 #if 0
1179 /**
1180  * atspi_accessible_get_streamable_content:
1181  * @obj: a pointer to the #AtspiAccessible instance to query.
1182  *
1183  * Get the #AtspiStreamableContent interface for an #AtspiAccessible.
1184  *
1185  * Returns: (transfer full): a pointer to an #AtspiStreamableContent interface
1186  *          instance, or NULL if @obj does not implement #AtspiStreamableContent.
1187  **/
1188 AtspiStreamableContent *
1189 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
1190 {
1191   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
1192           accessible : NULL);  
1193 }
1194 #endif
1195
1196 /**
1197  * atspi_accessible_get_table:
1198  * @obj: a pointer to the #AtspiAccessible instance to query.
1199  *
1200  * Get the #AtspiTable interface for an #AtspiAccessible.
1201  *
1202  * Returns: (transfer full): a pointer to an #AtspiTable interface instance, or
1203  *          NULL if @obj does not implement #AtspiTable.
1204  **/
1205 AtspiTable *
1206 atspi_accessible_get_table (AtspiAccessible *obj)
1207 {
1208   return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
1209           g_object_ref (ATSPI_TABLE (obj)) : NULL);  
1210 }
1211
1212 /**
1213  * atspi_accessible_get_text:
1214  * @obj: a pointer to the #AtspiAccessible instance to query.
1215  *
1216  * Get the #AtspiTable interface for an #AtspiAccessible.
1217  *
1218  * Returns: (transfer full): a pointer to an #AtspiText interface instance, or
1219  *          NULL if @obj does not implement #AtspiText.
1220  **/
1221 AtspiText *
1222 atspi_accessible_get_text (AtspiAccessible *obj)
1223 {
1224   return (_atspi_accessible_is_a (obj, atspi_interface_text) ?
1225           g_object_ref (ATSPI_TEXT (obj)) : NULL);
1226 }
1227
1228 /**
1229  * atspi_accessible_get_value:
1230  * @obj: a pointer to the #AtspiAccessible instance to query.
1231  *
1232  * Get the #AtspiTable interface for an #AtspiAccessible.
1233  *
1234  * Returns: (transfer full): a pointer to an #AtspiValue interface instance, or
1235  *          NULL if @obj does not implement #AtspiValue.
1236  **/
1237 AtspiValue *
1238 atspi_accessible_get_value (AtspiAccessible *accessible)
1239 {
1240   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
1241           g_object_ref (ATSPI_VALUE (accessible)) : NULL);  
1242 }
1243
1244 static void
1245 append_const_val (GArray *array, const gchar *val)
1246 {
1247   gchar *dup = g_strdup (val);
1248
1249   if (dup)
1250     g_array_append_val (array, dup);
1251 }
1252
1253 /**
1254  * atspi_accessible_get_interfaces:
1255  *
1256  * #obj: The #AtspiAccessible to query.
1257  *
1258  * Returns: (element-type gchar*) (transfer full): A #GArray of strings
1259  *          describing the interfaces supported by the object.  Interfaces are
1260  *          denoted in short-hand (ie, "Component", "Text", etc.)
1261  **/
1262 GArray *
1263 atspi_accessible_get_interfaces (AtspiAccessible *obj)
1264 {
1265   GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
1266
1267   if (!ret)
1268     return NULL;
1269
1270   g_return_val_if_fail (obj != NULL, NULL);
1271
1272   if (atspi_accessible_is_action (obj))
1273     append_const_val (ret, "Action");
1274   if (atspi_accessible_is_collection (obj))
1275     append_const_val (ret, "Collection");
1276   if (atspi_accessible_is_component (obj))
1277     append_const_val (ret, "Component");
1278   if (atspi_accessible_is_document (obj))
1279     append_const_val (ret, "Document");
1280   if (atspi_accessible_is_editable_text (obj))
1281     append_const_val (ret, "EditableText");
1282   if (atspi_accessible_is_hypertext (obj))
1283     append_const_val (ret, "Hypertext");
1284   if (atspi_accessible_is_hyperlink (obj))
1285     append_const_val (ret, "Hyperlink");
1286   if (atspi_accessible_is_image (obj))
1287     append_const_val (ret, "Image");
1288   if (atspi_accessible_is_selection (obj))
1289     append_const_val (ret, "Selection");
1290   if (atspi_accessible_is_table (obj))
1291     append_const_val (ret, "Table");
1292   if (atspi_accessible_is_text (obj))
1293     append_const_val (ret, "Text");
1294   if (atspi_accessible_is_value (obj))
1295     append_const_val (ret, "Value");
1296
1297   return ret;
1298 }
1299
1300 AtspiAccessible *
1301 atspi_accessible_new (AtspiApplication *app, const gchar *path)
1302 {
1303   AtspiAccessible *accessible;
1304   
1305   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1306   g_return_val_if_fail (accessible != NULL, NULL);
1307
1308   accessible->parent.app = g_object_ref (app);
1309   accessible->parent.path = g_strdup (path);
1310
1311   return accessible;
1312 }
1313
1314 /**
1315  * atspi_accessible_set_cache_mask:
1316  *
1317  * @accessible: The #AtspiAccessible to operate on.  Must be the desktop or
1318  *             the root of an application.
1319  * @mask: An #AtspiCache specifying a bit mask of the types of data to cache.
1320  *
1321  * Sets the type of data to cache for accessibles.
1322  * If this is not set for an application or is reset to ATSPI_CACHE_UNDEFINED,
1323  * then the desktop's cache flag will be used.
1324  * If the desktop's cache flag is also undefined, then all possible data will
1325  * be cached.
1326  * This function is intended to work around bugs in toolkits where the proper
1327  * events are not raised / to aid in testing for such bugs.
1328  *
1329  * Note: This function has no effect on data that has already been cached.
1330  **/
1331 void
1332 atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask)
1333 {
1334   g_return_if_fail (accessible != NULL);
1335   g_return_if_fail (accessible->parent.app != NULL);
1336   g_return_if_fail (accessible == accessible->parent.app->root);
1337   accessible->parent.app->cache = mask;
1338 }
1339
1340 void
1341 _atspi_accessible_add_cache (AtspiAccessible *accessible, AtspiCache flag)
1342 {
1343   AtspiCache mask = accessible->parent.app->cache;
1344
1345   if (mask == ATSPI_CACHE_UNDEFINED &&
1346       accessible->parent.app->root->accessible_parent)
1347   {
1348     AtspiAccessible *desktop = atspi_get_desktop (0);
1349     mask = desktop->parent.app->cache;
1350     g_object_unref (desktop);
1351   }
1352
1353   if (mask == ATSPI_CACHE_UNDEFINED)
1354     mask = ATSPI_CACHE_ALL;
1355
1356   accessible->cached_properties |= flag & mask;
1357 }