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