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