Various fixes
[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 G_DEFINE_TYPE (AtspiAccessible, atspi_accessible, G_TYPE_OBJECT)
28
29 static void
30 atspi_accessible_init (AtspiAccessible *accessible)
31 {
32 }
33
34 static void
35 atspi_accessible_finalize (GObject *obj)
36 {
37   AtspiAccessible *accessible = ATSPI_ACCESSIBLE (obj);
38
39   if (accessible->app)
40     g_object_unref (accessible->app);
41
42   g_free (accessible->path);
43 }
44
45 static void
46 atspi_accessible_class_init (AtspiAccessibleClass *klass)
47 {
48   GObjectClass *object_class = G_OBJECT_CLASS (klass);
49
50   object_class->finalize = atspi_accessible_finalize;
51 }
52
53 /* TODO: Generate following from spec? */
54 static const char *role_names [] =
55 {
56   "invalid",
57   "accel-label",
58   "alert",
59   "animation",
60   "arrow",
61   "calendar",
62   "canvas",
63   "check-box",
64   "check-menu-item",
65   "color-chooser",
66   "column-header",
67   "combo-box",
68   "date-editor",
69   "desktop-icon",
70   "desktop-frame",
71   "dial",
72   "dialog",
73   "directory-pane",
74   "drawing-area",
75   "file-chooser",
76   "filler",
77   "font-chooser",
78   "frame",
79   "glass-pane",
80   "html-container",
81   "icon",
82   "image",
83   "internalframe",
84   "label",
85   "layered-pane",
86   "list",
87   "list-item",
88   "menu",
89   "menu-bar",
90   "menu-item",
91   "option-pane",
92   "page-tab",
93   "page-tab-list",
94   "panel",
95   "password-text",
96   "popup-menu",
97   "progress-bar",
98   "push-button",
99   "radio-button",
100   "radio-menu-item",
101   "root-pane",
102   "row-header",
103   "scroll-bar",
104   "scroll-pane",
105   "separator",
106   "slider",
107   "spin-button",
108   "split-pane",
109   "statusbar",
110   "table",
111   "table-cell",
112   "table-column-header",
113   "table-row-header",
114   "tear-off-menu-item",
115   "terminal",
116   "text",
117   "toggle-button",
118   "tool-bar",
119   "tool-tip",
120   "tree",
121   "tree-table",
122   "unknown",
123   "viewport",
124   "window",
125   NULL,
126   "header",
127   "fooler",
128   "paragraph",
129   "ruler",
130   "application",
131   "autocomplete",
132   "editbar",
133   "embedded",
134   "entry",
135   "chart",
136   "caption",
137   "document_frame",
138   "heading",
139   "page",
140   "section",
141   "form",
142   "redundant object",
143   "link",
144   "input method window"
145 };
146
147 #define MAX_ROLES (sizeof (role_names) / sizeof (char *))
148
149 /**
150  * atspi_role_get_name
151  * @role: an #AtspiAccessibleRole object to query.
152  *
153  * Get a localizeable string that indicates the name of an #AtspiAccessibleRole.
154  * <em>DEPRECATED.</em>
155  *
156  * Returns: a localizable string name for an #AtspiAccessibleRole enumerated type.
157  **/
158 gchar *
159 atspi_role_get_name (AtspiRole role)
160 {
161   if (role < MAX_ROLES && role_names [(int) role])
162     {
163       return g_strdup (role_names [(int) role]);
164     }
165   else
166     {
167       return g_strdup ("");
168     }
169 }
170
171 /**
172  * atspi_accessible_get_name:
173  * @obj: a pointer to the #AtspiAccessible object on which to operate.
174  *
175  * Get the name of an #AtspiAccessible object.
176  *
177  * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object.
178  * or NULL on exception
179  **/
180 gchar *
181 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
182 {
183   g_return_val_if_fail (obj != NULL, NULL);
184   if (!(obj->cached_properties & ATSPI_CACHE_NAME))
185   {
186     if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", NULL, "s", &obj->name))
187       return NULL;
188     obj->cached_properties |= ATSPI_CACHE_NAME;
189   }
190   return g_strdup (obj->name);
191 }
192
193 /**
194  * atspi_accessible_get_description:
195  * @obj: a pointer to the #AtspiAccessible object on which to operate.
196  *
197  * Get the description of an #AtspiAccessible object.
198  *
199  * Returns: a UTF-8 string describing the #AtspiAccessible object.
200  * or NULL on exception
201  **/
202 gchar *
203 atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
204 {
205   g_return_val_if_fail (obj != NULL, NULL);
206
207   if (!(obj->cached_properties & ATSPI_CACHE_DESCRIPTION))
208   {
209     if (!_atspi_dbus_call (obj, atspi_interface_accessible, "GetDescription", NULL, "=>s", &obj->description))
210       return NULL;
211     obj->cached_properties |= ATSPI_CACHE_DESCRIPTION;
212   }
213   return g_strdup (obj->description);
214 }
215
216 const char *str_parent = "Parent";
217
218 /**
219  * atspi_accessible_get_parent:
220  * @obj: a pointer to the #AtspiAccessible object to query.
221  *
222  * Get an #AtspiAccessible object's parent container.
223  *
224  * Returns: (transfer full): a pointer to the #AtspiAccessible object which
225  *          contains the given #AtspiAccessible instance, or NULL if the @obj
226  *          has no parent container.
227  *
228  **/
229 AtspiAccessible *
230 atspi_accessible_get_parent (AtspiAccessible *obj, GError **error)
231 {
232   g_return_val_if_fail (obj != NULL, NULL);
233
234   if (!(obj->cached_properties & ATSPI_CACHE_PARENT))
235   {
236     DBusMessage *message, *reply;
237     DBusMessageIter iter, iter_variant;
238     message = dbus_message_new_method_call (obj->app->bus_name, obj->path,
239                                             DBUS_INTERFACE_PROPERTIES, "Get");
240     if (!message)
241       return NULL;
242     dbus_message_append_args (message, DBUS_TYPE_STRING, &atspi_interface_accessible,
243                                DBUS_TYPE_STRING, &str_parent,
244                               DBUS_TYPE_INVALID);
245     reply = _atspi_dbus_send_with_reply_and_block (message);
246     if (!reply ||
247        (strcmp (dbus_message_get_signature (reply), "v") != 0))
248       return NULL;
249     dbus_message_iter_init (reply, &iter);
250     dbus_message_iter_recurse (&iter, &iter_variant);
251     obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant);
252     dbus_message_unref (reply);
253     obj->cached_properties |= ATSPI_CACHE_PARENT;
254   }
255   if (!obj->accessible_parent)
256     return NULL;
257   return g_object_ref (obj->accessible_parent);
258 }
259
260 /**
261  * atspi_accessible_get_child_count:
262  * @obj: a pointer to the #AtspiAccessible object on which to operate.
263  *
264  * Get the number of children contained by an #AtspiAccessible object.
265  *
266  * Returns: a #long indicating the number of #AtspiAccessible children
267  *          contained by an #AtspiAccessible object. or -1 on exception
268  *
269  **/
270 gint
271 atspi_accessible_get_child_count (AtspiAccessible *obj, GError *error)
272 {
273   g_return_val_if_fail (obj != NULL, -1);
274
275   /* TODO: MANAGES_DESCENDANTS */
276   return g_list_length (obj->children);
277 }
278
279 /**
280  * atspi_accessible_get_child_at_index:
281  * @obj: a pointer to the #AtspiAccessible object on which to operate.
282  * @child_index: a #long indicating which child is specified.
283  *
284  * Get the #AtspiAccessible child of an #AtspiAccessible object at a given index.
285  *
286  * Returns: (transfer full): a pointer to the #AtspiAccessible child object at
287  * index @child_index. or NULL on exception
288  **/
289 AtspiAccessible *
290 atspi_accessible_get_child_at_index (AtspiAccessible *obj,
291                             gint    child_index,
292                             GError **error)
293 {
294   AtspiAccessible *child;
295
296   g_return_val_if_fail (obj != NULL, NULL);
297
298   /* TODO: ManagesDescendants */
299   child = g_list_nth_data (obj->children, child_index);
300   if (!child)
301     return NULL;
302   return g_object_ref (child);
303 }
304
305 /**
306  * atspi_accessible_get_index_in_parent
307  * @obj: a pointer to the #AtspiAccessible object on which to operate.
308  *
309  * Get the index of an #AtspiAccessible object in its containing #AtspiAccessible.
310  *
311  * Returns: a #glong indicating the index of the #AtspiAccessible object
312  *          in its parent (i.e. containing) #AtspiAccessible instance,
313  *          or -1 if @obj has no containing parent or on exception.
314  **/
315 gint
316 atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error)
317 {
318   GList *l;
319   gint i;
320
321   g_return_val_if_fail (obj != NULL, -1);
322   if (!obj->accessible_parent) return -1;
323   l = obj->accessible_parent->children;
324   while (l)
325   {
326     if (l->data == obj) return i;
327     l = g_list_next (l);
328     i++;
329   }
330   return -1;
331 }
332
333 typedef struct
334 {
335   dbus_uint32_t type;
336   GArray *targets;
337 } Accessibility_Relation;
338
339 /**
340  * atspi_accessible_get_relation_set:
341  * @obj: a pointer to the #AtspiAccessible object on which to operate.
342  *
343  * Get the set of #AtspiRelation objects which describe this #AtspiAccessible object's
344  *       relationships with other #AtspiAccessible objects.
345  *
346  * Returns: an array of #AtspiAccessibleRelation pointers. or NULL on exception
347  * TODO:: Annotate array type
348  **/
349 GArray *
350 atspi_accessible_get_relation_set (AtspiAccessible *obj, GError **error)
351 {
352   int i;
353   int n_relations;
354   GArray *relation_set;
355
356   g_return_val_if_fail (obj != NULL, NULL);
357
358   if (!_atspi_dbus_call (obj, atspi_interface_accessible, "GetRelationSet", error, "=>a(uao)", &relation_set))
359     return NULL;
360
361   return relation_set;
362 }
363
364 /**
365  * atspi_accessible_get_role:
366  * @obj: a pointer to the #AtspiAccessible object on which to operate.
367  *
368  * Get the UI role of an #AtspiAccessible object.
369  * A UTF-8 string describing this role can be obtained via atspi_accessible_getRoleName ().
370  *
371  * Returns: the #AtspiRole of the object.
372  *
373  **/
374 AtspiRole
375 atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
376 {
377   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
378
379   if (!(obj->cached_properties & ATSPI_CACHE_ROLE))
380   {
381     dbus_uint32_t role;
382     /* TODO: Make this a property */
383     if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", NULL, "=>u", &role))
384     {
385       obj->cached_properties |= ATSPI_CACHE_ROLE;
386       obj->role = role;
387     }
388   }
389   return obj->role;
390 }
391
392 /**
393  * atspi_accessible_get_role_name:
394  * @obj: a pointer to the #AtspiAccessible object on which to operate.
395  *
396  * Get a UTF-8 string describing the role this object plays in the UI.
397  * This method will return useful values for roles that fall outside the
398  * enumeration used in atspi_accessible_getRole ().
399  *
400  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
401  *
402  **/
403 gchar *
404 atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
405 {
406   char *retval = NULL;
407
408   g_return_val_if_fail (obj != NULL, g_strdup ("invalid"));
409
410   _atspi_dbus_call (obj, atspi_interface_accessible, "GetRoleName", error, "=>s", &retval);
411
412   return retval;
413 }
414
415 /**
416  * atspi_accessible_get_localized_role_name:
417  * @obj: a pointer to the #AtspiAccessible object on which to operate.
418  *
419  * Get a UTF-8 string describing the (localized) role this object plays in the UI.
420  * This method will return useful values for roles that fall outside the
421  * enumeration used in atspi_accessible_getRole ().
422  *
423  * Returns: a UTF-8 string specifying the role of this #AtspiAccessible object.
424  *
425  **/
426 gchar *
427 atspi_accessible_get_localized_role_name (AtspiAccessible *obj, GError **error)
428 {
429   char *retval = NULL;
430
431   g_return_val_if_fail (obj != NULL, g_strdup ("invalid"));
432
433   _atspi_dbus_call (obj, atspi_interface_accessible, "GetLocalizedRoleName", error, "=>s", &retval);
434
435   return retval;
436 }
437
438 /**
439  * atspi_accessible_get_state_set:
440  * @obj: a pointer to the #AtspiAccessible object on which to operate.
441  *
442  * Gets the current state of an object.
443  *
444  * Returns: (transfer full): a pointer to an #AtspiStateSet representing the
445  *          object's current state.
446  **/
447 AtspiStateSet *
448 atspi_accessible_get_state_set (AtspiAccessible *obj)
449 {
450   return obj->states;
451 }
452
453 /**
454  * atspi_accessible_get_attributes:
455  * @obj: The #AtspiAccessible being queried.
456  *
457  * Get the #AttributeSet representing any assigned 
458  * name-value pair attributes or annotations for this object.
459  * For typographic, textual, or textually-semantic attributes, see
460  * atspi_text_get_attributes instead.
461  *
462  * Returns: (element-type gchar* gchar*) (transfer full): The name-value-pair
463  *          attributes assigned to this object.
464  */
465 GHashTable *
466 atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
467 {
468   DBusMessage *message;
469   GHashTable *ret;
470
471     g_return_val_if_fail (obj != NULL, NULL);
472
473   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
474   ret = _atspi_dbus_hash_from_message (message);
475   dbus_message_unref (message);
476   return ret;
477 }
478
479 /**
480  * atspi_accessible_get_attributes_as_array:
481  * @obj: The #AtspiAccessible being queried.
482  *
483  * Get the #AttributeSet representing any assigned 
484  * name-value pair attributes or annotations for this object.
485  * For typographic, textual, or textually-semantic attributes, see
486  * atspi_text_get_attributes_as_array instead.
487  *
488  * Returns: (element-type gchar*) (transfer full): The name-value-pair
489  *          attributes assigned to this object.
490  */
491 GArray *
492 atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
493 {
494   DBusMessage *message;
495   GArray *ret;
496
497     g_return_val_if_fail (obj != NULL, NULL);
498
499   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
500   ret = _atspi_dbus_attribute_array_from_message (message);
501   dbus_message_unref (message);
502   return ret;
503 }
504
505 /**
506  * atspi_accessible_get_host_application:
507  * @obj: The #AtspiAccessible being queried.
508  *
509  * Get the containing #AtspiApplication for an object.
510  *
511  * Returns: (transfer full): the containing AtspiApplication instance for
512  *          this object.
513  */
514 AtspiAccessible *
515 atspi_accessible_get_host_application (AtspiAccessible *obj, GError **error)
516 {
517   AtspiAccessible *parent;
518
519   for (;;)
520   {
521     parent = atspi_accessible_get_parent (obj, NULL);
522     if (!parent || parent == obj ||
523         atspi_accessible_get_role (parent, NULL) == ATSPI_ROLE_DESKTOP_FRAME)
524     return obj;
525     obj = parent;
526   }
527 }
528
529 #if 0   // TODO: interfaces */
530 /* Interface query methods */
531
532 /**
533  * atspi_accessible_is_action:
534  * @obj: a pointer to the #AtspiAccessible instance to query.
535  *
536  * Query whether the specified #AtspiAccessible implements #AtspiAction.
537  *
538  * Returns: #TRUE if @obj implements the #AtspiAction interface,
539  *          #FALSE otherwise.
540  **/
541 gboolean
542 atspi_accessible_is_action (AtspiAccessible *obj)
543 {
544   return _atspi_accessible_is_a (obj,
545                               atspi_interface_action);
546 }
547
548 /**
549  * atspi_accessible_is_application:
550  * @obj: a pointer to the #AtspiAccessible instance to query.
551  *
552  * Query whether the specified #AtspiAccessible implements #AtspiApplication.
553  *
554  * Returns: #TRUE if @obj implements the #AtspiApplication interface,
555  *          #FALSE otherwise.
556  **/
557 gboolean
558 atspi_accessible_is_application (AtspiAccessible *obj)
559 {
560   return _atspi_accessible_is_a (obj,
561                               atspi_interface_application);
562 }
563
564 /**                      
565  * atspi_accessible_is_collection:                                                                                                                                                                          * @obj: a pointer to the #AtspiAccessible instance to query.                                                                                                                                          
566  *                          
567  * Query whether the specified #AtspiAccessible implements #AtspiCollection.    
568  * Returns: #TRUE if @obj implements the #AtspiCollection interface,                                                                                                               
569  *          #FALSE otherwise.
570  **/
571 gboolean
572 atspi_accessible_is_collection (AtspiAccessible *obj)
573 {
574 #if 0
575      g_warning ("Collections not implemented");
576      return _atspi_accessible_is_a (obj,
577                               atspi_interface_collection);
578 #else
579      return FALSE;
580 #endif
581 }
582
583 /**
584  * atspi_accessible_is_component:
585  * @obj: a pointer to the #AtspiAccessible instance to query.
586  *
587  * Query whether the specified #AtspiAccessible implements #AtspiComponent.
588  *
589  * Returns: #TRUE if @obj implements the #AtspiComponent interface,
590  *          #FALSE otherwise.
591  **/
592 gboolean
593 atspi_accessible_is_component (AtspiAccessible *obj)
594 {
595   return _atspi_accessible_is_a (obj,
596                               atspi_interface_component);
597 }
598
599 /**
600  * atspi_accessible_is_document:
601  * @obj: a pointer to the #AtspiAccessible instance to query.
602  *
603  * Query whether the specified #AtspiAccessible implements #AtspiDocument.
604  *
605  * Returns: #TRUE if @obj implements the #AtspiDocument interface,
606  *          #FALSE otherwise.
607  **/
608 gboolean
609 atspi_accessible_is_document (AtspiAccessible *obj)
610 {
611   return _atspi_accessible_is_a (obj,
612                               atspi_interface_document);
613 }
614
615 /**
616  * atspi_accessible_is_editable_text:
617  * @obj: a pointer to the #AtspiAccessible instance to query.
618  *
619  * Query whether the specified #AtspiAccessible implements #AtspiEditableText.
620  *
621  * Returns: #TRUE if @obj implements the #AtspiEditableText interface,
622  *          #FALSE otherwise.
623  **/
624 gboolean
625 atspi_accessible_is_editable_text (AtspiAccessible *obj)
626 {
627   return _atspi_accessible_is_a (obj,
628                               atspi_interface_editable_text);
629 }
630                                                                                                                                                                         
631 /**
632  * atspi_accessible_is_hypertext:
633  * @obj: a pointer to the #AtspiAccessible instance to query.
634  *
635  * Query whether the specified #AtspiAccessible implements #AtspiHypertext.
636  *
637  * Returns: #TRUE if @obj implements the #AtspiHypertext interface,
638  *          #FALSE otherwise.
639  **/
640 gboolean
641 atspi_accessible_is_hypertext (AtspiAccessible *obj)
642 {
643   return _atspi_accessible_is_a (obj,
644                               atspi_interface_hypertext);
645 }
646
647 /**
648  * atspi_accessible_is_image:
649  * @obj: a pointer to the #AtspiAccessible instance to query.
650  *
651  * Query whether the specified #AtspiAccessible implements #AtspiImage.
652  *
653  * Returns: #TRUE if @obj implements the #AtspiImage interface,
654  *          #FALSE otherwise.
655 **/
656 gboolean
657 atspi_accessible_is_image (AtspiAccessible *obj)
658 {
659   return _atspi_accessible_is_a (obj,
660                               atspi_interface_image);
661 }
662
663 /**
664  * atspi_accessible_is_selection:
665  * @obj: a pointer to the #AtspiAccessible instance to query.
666  *
667  * Query whether the specified #AtspiAccessible implements #AtspiSelection.
668  *
669  * Returns: #TRUE if @obj implements the #AtspiSelection interface,
670  *          #FALSE otherwise.
671 **/
672 gboolean
673 atspi_accessible_is_selection (AtspiAccessible *obj)
674 {
675   return _atspi_accessible_is_a (obj,
676                               atspi_interface_selection);
677 }
678
679 /**
680  * atspi_accessible_is_table:
681  * @obj: a pointer to the #AtspiAccessible instance to query.
682  *
683  * Query whether the specified #AtspiAccessible implements #AtspiTable.
684  *
685  * Returns: #TRUE if @obj implements the #AtspiTable interface,
686  *          #FALSE otherwise.
687 **/
688 gboolean
689 atspi_accessible_is_table (AtspiAccessible *obj)
690 {
691   return _atspi_accessible_is_a (obj,
692                               atspi_interface_table);
693 }
694
695 /**
696  * atspi_accessible_is_streamable_content:
697  * @obj: a pointer to the #AtspiAccessible instance to query.
698  *
699  * Query whether the specified #AtspiAccessible implements
700  *          #AtspiStreamableContent.
701  *
702  * Returns: #TRUE if @obj implements the #AtspiStreamableContent interface,
703  *          #FALSE otherwise.
704 **/
705 gboolean
706 atspi_accessible_is_streamable_content (AtspiAccessible *obj)
707 {
708 #if 0
709   return _atspi_accessible_is_a (obj,
710                               atspi_interface_streamable_content);
711 #else
712   g_warning ("Streamable content not implemented");
713   return FALSE;
714 #endif
715 }
716
717 /**
718  * atspi_accessible_is_text:
719  * @obj: a pointer to the #AtspiAccessible instance to query.
720  *
721  * Query whether the specified #AtspiAccessible implements #AtspiText.
722  *
723  * Returns: #TRUE if @obj implements the #AtspiText interface,
724  *          #FALSE otherwise.
725 **/
726 gboolean
727 atspi_accessible_is_text (AtspiAccessible *obj)
728 {
729   return _atspi_accessible_is_a (obj,
730                               atspi_interface_text);
731 }
732
733 /**
734  * atspi_accessible_is_value:
735  * @obj: a pointer to the #AtspiAccessible instance to query.
736  *
737  * Query whether the specified #AtspiAccessible implements #AtspiValue.
738  *
739  * Returns: #TRUE if @obj implements the #AtspiValue interface,
740  *          #FALSE otherwise.
741 **/
742 gboolean
743 atspi_accessible_is_value (AtspiAccessible *obj)
744 {
745   return _atspi_accessible_is_a (obj,
746                               atspi_interface_value);
747 }
748
749 /**
750  * atspi_accessible_get_application:
751  * @obj: a pointer to the #AtspiAccessible instance to query.
752  *
753  * Get the #AtspiApplication interface for an #AtspiAccessible.
754  *
755  * Returns: a pointer to an #AtspiApplication interface instance, or
756  *          NULL if @obj does not implement #AtspiApplication.
757  **/
758 AtspiApplication *
759 atspi_accessible_get_application (AtspiAccessible *accessible)
760 {
761   return (_atspi_accessible_is_a (accessible, atspi_interface_application) ?
762           accessible : NULL);  
763 }
764
765 /**
766  * atspi_accessible_get_action:
767  * @obj: a pointer to the #AtspiAccessible instance to query.
768  *
769  * Get the #AtspiAction interface for an #AtspiAccessible.
770  *
771  * Returns: a pointer to an #AtspiAction interface instance, or
772  *          NULL if @obj does not implement #AtspiAction.
773  **/
774 AtspiAction *
775 atspi_accessible_get_action (AtspiAccessible *accessible)
776 {
777   return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
778           accessible : NULL);  
779 }
780
781 /**
782  * atspi_accessible_get_collection:
783  * @obj: a pointer to the #AtspiAccessible instance to query.
784  *
785  * Get the #AtspiCollection interface for an #AtspiAccessible.
786  *
787  * Returns: a pointer to an #AtspiCollection interface instance, or
788  *          NULL if @obj does not implement #AtspiCollection.
789  **/
790 AtspiCollection *
791 atspi_accessible_get_collection (AtspiAccessible *accessible)
792 {
793   return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
794           accessible : NULL);  
795 }
796 #endif
797
798 /**
799  * atspi_accessible_get_component:
800  * @obj: a pointer to the #AtspiAccessible instance to query.
801  *
802  * Get the #AtspiComponent interface for an #AtspiAccessible.
803  *
804  * Returns: a pointer to an #AtspiComponent interface instance, or
805  *          NULL if @obj does not implement #AtspiComponent.
806  **/
807 AtspiComponent *
808 atspi_accessible_get_component (AtspiAccessible *accessible)
809 {
810   return (_atspi_accessible_is_a (accessible, atspi_interface_component) ?
811           ATSPI_COMPONENT (accessible) : NULL);  
812 }
813
814 #if 0
815 /**
816  * atspi_accessible_get_document:
817  * @obj: a pointer to the #AtspiAccessible instance to query.
818  *
819  * Get the #AtspiDocument interface for an #AtspiAccessible.
820  *
821  * Returns: a pointer to an #AtspiDocument interface instance, or
822  *          NULL if @obj does not implement #AtspiDocument.
823  **/
824 AtspiDocument *
825 atspi_accessible_get_document (AtspiAccessible *accessible)
826 {
827   return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
828           accessible : NULL);  
829 }
830
831 /**
832  * atspi_accessible_get_editable_text:
833  * @obj: a pointer to the #AtspiAccessible instance to query.
834  *
835  * Get the #AtspiEditableText interface for an #AtspiAccessible.
836  *
837  * Returns: a pointer to an #AtspiEditableText interface instance, or
838  *          NULL if @obj does not implement #AtspiEditableText.
839  **/
840 AtspiEditableText *
841 atspi_accessible_get_editable_text (AtspiAccessible *accessible)
842 {
843   return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
844           accessible : NULL);  
845 }
846
847 /**
848  * atspi_accessible_get_hypertext:
849  * @obj: a pointer to the #AtspiAccessible instance to query.
850  *
851  * Get the #AtspiHypertext interface for an #AtspiAccessible.
852  *
853  * Returns: a pointer to an #AtspiHypertext interface instance, or
854  *          NULL if @obj does not implement #AtspiHypertext.
855  **/
856 AtspiHypertext *
857 atspi_accessible_get_hypertext (AtspiAccessible *accessible)
858 {
859   return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
860           accessible : NULL);  
861 }
862
863 /**
864  * atspi_accessible_get_image:
865  * @obj: a pointer to the #AtspiAccessible instance to query.
866  *
867  * Get the #AtspiImage interface for an #AtspiAccessible.
868  *
869  * Returns: a pointer to an #AtspiImage interface instance, or
870  *          NULL if @obj does not implement #AtspiImage.
871  **/
872 AtspiImage *
873 atspi_accessible_get_image (AtspiAccessible *accessible)
874 {
875   return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
876           accessible : NULL);  
877 }
878
879 /**
880  * atspi_accessible_get_selection:
881  * @obj: a pointer to the #AtspiAccessible instance to query.
882  *
883  * Get the #AtspiSelection interface for an #AtspiAccessible.
884  *
885  * Returns: a pointer to an #AtspiSelection interface instance, or
886  *          NULL if @obj does not implement #AtspiSelection.
887  **/
888 AtspiSelection *
889 atspi_accessible_get_selection (AtspiAccessible *accessible)
890 {
891   return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
892           accessible : NULL);  
893 }
894
895 /**
896  * atspi_accessible_get_streamable_content:
897  * @obj: a pointer to the #AtspiAccessible instance to query.
898  *
899  * Get the #AtspiStreamableContent interface for an #AtspiAccessible.
900  *
901  * Returns: a pointer to an #AtspiStreamableContent interface instance, or
902  *          NULL if @obj does not implement #AtspiStreamableContent.
903  **/
904 AtspiStreamableContent *
905 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
906 {
907   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
908           accessible : NULL);  
909 }
910
911 /**
912  * atspi_accessible_get_table:
913  * @obj: a pointer to the #AtspiAccessible instance to query.
914  *
915  * Get the #AtspiTable interface for an #AtspiAccessible.
916  *
917  * Returns: a pointer to an #AtspiTable interface instance, or
918  *          NULL if @obj does not implement #AtspiTable.
919  **/
920 AtspiTable *
921 atspi_accessible_get_table (AtspiAccessible *accessible)
922 {
923   return (_atspi_accessible_is_a (accessible, atspi_interface_table) ?
924           accessible : NULL);  
925 }
926
927 /**
928  * atspi_accessible_get_text:
929  * @obj: a pointer to the #AtspiAccessible instance to query.
930  *
931  * Get the #AtspiTable interface for an #AtspiAccessible.
932  *
933  * Returns: a pointer to an #AtspiTable interface instance, or
934  *          NULL if @obj does not implement #AtspiTable.
935  **/
936 AtspiTable *
937 atspi_accessible_get_text (AtspiAccessible *accessible)
938 {
939   return (_atspi_accessible_is_a (accessible, atspi_interface_text) ?
940           accessible : NULL);  
941 }
942
943 /**
944  * atspi_accessible_get_value:
945  * @obj: a pointer to the #AtspiAccessible instance to query.
946  *
947  * Get the #AtspiTable interface for an #AtspiAccessible.
948  *
949  * Returns: a pointer to an #AtspiTable interface instance, or
950  *          NULL if @obj does not implement #AtspiTable.
951  **/
952 AtspiTable *
953 atspi_accessible_get_value (AtspiAccessible *accessible)
954 {
955   return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
956           accessible : NULL);  
957 }
958
959 static gboolean
960 cspi_init_relation_type_table (AccessibleRelationType *relation_type_table)
961 {
962   int i;
963   for (i = 0; i < Accessibility_RELATION_LAST_DEFINED; ++i)
964     {
965       relation_type_table [i] = SPI_RELATION_NULL;
966     }
967   relation_type_table [Accessibility_RELATION_NULL] = SPI_RELATION_NULL;
968   relation_type_table [Accessibility_RELATION_LABEL_FOR] = SPI_RELATION_LABEL_FOR;
969   relation_type_table [Accessibility_RELATION_LABELLED_BY] = SPI_RELATION_LABELED_BY;
970   relation_type_table [Accessibility_RELATION_CONTROLLER_FOR] = SPI_RELATION_CONTROLLER_FOR;
971   relation_type_table [Accessibility_RELATION_CONTROLLED_BY] = SPI_RELATION_CONTROLLED_BY;
972   relation_type_table [Accessibility_RELATION_MEMBER_OF] = SPI_RELATION_MEMBER_OF;
973   relation_type_table [Accessibility_RELATION_TOOLTIP_FOR] = SPI_RELATION_NULL;
974   relation_type_table [Accessibility_RELATION_NODE_CHILD_OF] = SPI_RELATION_NODE_CHILD_OF;
975   relation_type_table [Accessibility_RELATION_EXTENDED] = SPI_RELATION_EXTENDED;
976   relation_type_table [Accessibility_RELATION_FLOWS_TO] = SPI_RELATION_FLOWS_TO;
977   relation_type_table [Accessibility_RELATION_FLOWS_FROM] = SPI_RELATION_FLOWS_FROM;
978   relation_type_table [Accessibility_RELATION_SUBWINDOW_OF] = SPI_RELATION_SUBWINDOW_OF;
979   relation_type_table [Accessibility_RELATION_EMBEDS] = SPI_RELATION_EMBEDS;
980   relation_type_table [Accessibility_RELATION_EMBEDDED_BY] = SPI_RELATION_EMBEDDED_BY;
981   relation_type_table [Accessibility_RELATION_POPUP_FOR] = SPI_RELATION_POPUP_FOR;
982   relation_type_table [Accessibility_RELATION_PARENT_WINDOW_OF] = SPI_RELATION_PARENT_WINDOW_OF;
983   relation_type_table [Accessibility_RELATION_DESCRIBED_BY] = SPI_RELATION_DESCRIBED_BY;
984   relation_type_table [Accessibility_RELATION_DESCRIPTION_FOR] = SPI_RELATION_DESCRIPTION_FOR;
985   return TRUE;
986 }
987
988 static AccessibleRelationType
989 cspi_relation_type_from_spi_relation_type (Accessibility_RelationType type)
990 {
991   /* array is sized according to IDL RelationType because IDL RelationTypes are the index */    
992   static AccessibleRelationType cspi_relation_type_table [Accessibility_RELATION_LAST_DEFINED];
993   static gboolean is_initialized = FALSE;
994   AccessibleRelationType cspi_type;
995   if (!is_initialized)
996     {
997       is_initialized = cspi_init_relation_type_table (cspi_relation_type_table);            
998     }
999   if (type >= 0 && type < Accessibility_RELATION_LAST_DEFINED)
1000     {
1001       cspi_type = cspi_relation_type_table [type];          
1002     }
1003   else
1004     {
1005       cspi_type = SPI_RELATION_NULL;
1006     }
1007   return cspi_type; 
1008 }
1009 /**
1010  * AccessibleRelation_getRelationType:
1011  * @obj: a pointer to the #AtspiAccessibleRelation object to query.
1012  *
1013  * Get the type of relationship represented by an #AtspiAccessibleRelation.
1014  *
1015  * Returns: an #AtspiAccessibleRelationType indicating the type of relation
1016  *         encapsulated in this #AtspiAccessibleRelation object.
1017  *
1018  **/
1019 AccessibleRelationType
1020 AccessibleRelation_getRelationType (AccessibleRelation *obj)
1021 {
1022   cspi_return_val_if_fail (obj, SPI_RELATION_NULL);
1023   return cspi_relation_type_from_spi_relation_type (obj->type);
1024 }
1025
1026 /**
1027  * AccessibleRelation_getNTargets:
1028  * @obj: a pointer to the #AtspiAccessibleRelation object to query.
1029  *
1030  * Get the number of objects which this relationship has as its
1031  *       target objects (the subject is the #AtspiAccessible from which this
1032  *       #AtspiAccessibleRelation originated).
1033  *
1034  * Returns: a short integer indicating how many target objects which the
1035  *       originating #AtspiAccessible object has the #AtspiAccessibleRelation
1036  *       relationship with.
1037  **/
1038 int
1039 AccessibleRelation_getNTargets (AccessibleRelation *obj)
1040 {
1041   cspi_return_val_if_fail (obj, -1);
1042   return obj->targets->len;
1043 }
1044
1045 /**
1046  * AccessibleRelation_getTarget:
1047  * @obj: a pointer to the #AtspiAccessibleRelation object to query.
1048  * @i: a (zero-index) integer indicating which (of possibly several) target is requested.
1049  *
1050  * Get the @i-th target of a specified #AtspiAccessibleRelation relationship.
1051  *
1052  * Returns: an #AtspiAccessible which is the @i-th object with which the
1053  *      originating #AtspiAccessible has relationship specified in the
1054  *      #AtspiAccessibleRelation object.
1055  *
1056  **/
1057 Accessible *
1058 AccessibleRelation_getTarget (AccessibleRelation *obj, int i)
1059 {
1060   cspi_return_val_if_fail (obj, NULL);
1061
1062   if (i < 0 || i >= obj->targets->len) return NULL;
1063   return cspi_object_add (
1064                          g_array_index (obj->targets, Accessible *, i));
1065 }
1066
1067 /**
1068  * AccessibleStateSet_ref:
1069  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1070  *
1071  * Increment the reference count for an #AtspiAccessibleStateSet object.
1072  *
1073  **/
1074 void
1075 AccessibleStateSet_ref (AccessibleStateSet *obj)
1076 {
1077   spi_state_set_cache_ref (obj);
1078 }
1079
1080 /**
1081  * AccessibleStateSet_unref:
1082  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1083  *
1084  * Decrement the reference count for an #AtspiAccessibleStateSet object.
1085  *
1086  **/
1087 void
1088 AccessibleStateSet_unref (AccessibleStateSet *obj)
1089 {
1090   spi_state_set_cache_unref (obj);
1091 }
1092
1093 static Accessibility_StateType
1094 spi_state_to_dbus (AccessibleState state)
1095 {
1096 #define MAP_STATE(a) \
1097   case SPI_STATE_##a: \
1098     return Accessibility_STATE_##a
1099
1100   switch (state)
1101     {
1102       MAP_STATE (INVALID);
1103       MAP_STATE (ACTIVE);
1104       MAP_STATE (ARMED);
1105       MAP_STATE (BUSY);
1106       MAP_STATE (CHECKED);
1107       MAP_STATE (DEFUNCT);
1108       MAP_STATE (EDITABLE);
1109       MAP_STATE (ENABLED);
1110       MAP_STATE (EXPANDABLE);
1111       MAP_STATE (EXPANDED);
1112       MAP_STATE (FOCUSABLE);
1113       MAP_STATE (FOCUSED);
1114       MAP_STATE (HORIZONTAL);
1115       MAP_STATE (ICONIFIED);
1116       MAP_STATE (MODAL);
1117       MAP_STATE (MULTI_LINE);
1118       MAP_STATE (MULTISELECTABLE);
1119       MAP_STATE (OPAQUE);
1120       MAP_STATE (PRESSED);
1121       MAP_STATE (RESIZABLE);
1122       MAP_STATE (SELECTABLE);
1123       MAP_STATE (SELECTED);
1124       MAP_STATE (SENSITIVE);
1125       MAP_STATE (SHOWING);
1126       MAP_STATE (SINGLE_LINE);
1127       MAP_STATE (STALE);
1128       MAP_STATE (TRANSIENT);
1129       MAP_STATE (VERTICAL);
1130       MAP_STATE (VISIBLE);
1131       MAP_STATE (MANAGES_DESCENDANTS);
1132       MAP_STATE (INDETERMINATE);
1133       MAP_STATE (TRUNCATED);
1134       MAP_STATE (REQUIRED);
1135       MAP_STATE (INVALID_ENTRY);
1136       MAP_STATE (SUPPORTS_AUTOCOMPLETION);
1137       MAP_STATE (SELECTABLE_TEXT);
1138       MAP_STATE (IS_DEFAULT);
1139       MAP_STATE (VISITED);
1140     default:
1141       return Accessibility_STATE_INVALID;
1142   }
1143 #undef MAP_STATE
1144 }             
1145
1146 /**
1147  * AccessibleStateSet_contains:
1148  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1149  * @state: an #AtspiAccessibleState for which the specified #AtspiAccessibleStateSet
1150  *       will be queried.
1151  *
1152  * Determine whether a given #AtspiAccessibleStateSet includes a given state; that is,
1153  *       whether @state is true for the stateset in question.
1154  *
1155  * Returns: #TRUE if @state is true/included in the given #AtspiAccessibleStateSet,
1156  *          otherwise #FALSE.
1157  *
1158  **/
1159 gboolean
1160 AccessibleStateSet_contains (AccessibleStateSet *obj,
1161                              AccessibleState state)
1162 {
1163   return spi_state_set_cache_contains (obj, spi_state_to_dbus (state));
1164 }
1165
1166 /**
1167  * AccessibleStateSet_add:
1168  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1169  * @state: an #AtspiAccessibleState to be added to the specified #AtspiAccessibleStateSet
1170  *
1171  * Add a particular #AtspiAccessibleState to an #AtspiAccessibleStateSet (i.e. set the
1172  *       given state to #TRUE in the stateset.
1173  *
1174  **/
1175 void
1176 AccessibleStateSet_add (AccessibleStateSet *obj,
1177                         AccessibleState state)
1178 {
1179   spi_state_set_cache_add (obj, spi_state_to_dbus (state));
1180 }
1181
1182 /**
1183  * AccessibleStateSet_remove:
1184  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1185  * @state: an #AtspiAccessibleState to be removed from the specified #AtspiAccessibleStateSet
1186  *
1187  * Remove a particular #AtspiAccessibleState to an #AtspiAccessibleStateSet (i.e. set the
1188  *       given state to #FALSE in the stateset.)
1189  *
1190  **/
1191 void
1192 AccessibleStateSet_remove (AccessibleStateSet *obj,
1193                            AccessibleState state)
1194 {
1195   spi_state_set_cache_remove (obj, spi_state_to_dbus (state));
1196 }
1197
1198 /**
1199  * AccessibleStateSet_equals:
1200  * @obj: a pointer to the first #AtspiAccessibleStateSet object on which to operate.
1201  * @obj2: a pointer to the second #AtspiAccessibleStateSet object on which to operate.
1202  *
1203  * Determine whether two instances of #AtspiAccessibleStateSet are equivalent (i.e.
1204  *         consist of the same #AtspiAccessibleStates).  Useful for checking multiple
1205  *         state variables at once; construct the target state then compare against it.
1206  *
1207  * @see AccessibleStateSet_compare().
1208  *
1209  * Returns: #TRUE if the two #AtspiAccessibleStateSets are equivalent,
1210  *          otherwise #FALSE.
1211  *
1212  **/
1213 gboolean
1214 AccessibleStateSet_equals (AccessibleStateSet *obj,
1215                            AccessibleStateSet *obj2)
1216 {
1217   gboolean   eq;
1218   AtkStateSet *cmp;
1219
1220   if (obj == obj2)
1221     {
1222       return TRUE;
1223     }
1224
1225   cmp = spi_state_set_cache_xor (obj, obj2);
1226   eq = spi_state_set_cache_is_empty (cmp);
1227   spi_state_set_cache_unref (cmp);
1228
1229   return eq;
1230 }
1231
1232 /**
1233  * AccessibleStateSet_compare:
1234  * @obj: a pointer to the first #AtspiAccessibleStateSet object on which to operate.
1235  * @obj2: a pointer to the second #AtspiAccessibleStateSet object on which to operate.
1236  *
1237  * Determine the differences between two instances of #AtspiAccessibleStateSet.
1238  * Not Yet Implemented.
1239  *.
1240  * @see AccessibleStateSet_equals().
1241  *
1242  * Returns: an #AtspiAccessibleStateSet object containing all states contained on one of
1243  *          the two sets but not the other.
1244  *
1245  **/
1246 AccessibleStateSet *
1247 AccessibleStateSet_compare (AccessibleStateSet *obj,
1248                             AccessibleStateSet *obj2)
1249 {
1250   return spi_state_set_cache_xor (obj, obj2);
1251 }
1252
1253 /**
1254  * AccessibleStateSet_isEmpty:
1255  * @obj: a pointer to the #AtspiAccessibleStateSet object on which to operate.
1256  *
1257  * Determine whether a given #AtspiAccessibleStateSet is the empty set.
1258  *
1259  * Returns: #TRUE if the given #AtspiAccessibleStateSet contains no (true) states,
1260  *          otherwise #FALSE.
1261  *
1262  **/
1263 gboolean
1264 AccessibleStateSet_isEmpty (AccessibleStateSet *obj)
1265 {
1266   return spi_state_set_cache_is_empty (obj);
1267 }
1268 #endif
1269
1270 gboolean
1271 _atspi_accessible_is_a (AtspiAccessible *accessible,
1272                       const char *interface_name)
1273 {
1274   int n;
1275
1276   if (accessible == NULL)
1277     {
1278       return FALSE;
1279     }
1280
1281   n = _atspi_get_iface_num (interface_name);
1282   if (n == -1) return FALSE;
1283   return (gboolean) ((accessible->interfaces & (1 << n))? TRUE: FALSE);
1284 }
1285
1286 /* TODO: Move to a finalizer */
1287 static void
1288 cspi_object_destroyed (AtspiAccessible *accessible)
1289 {
1290   gboolean cached;
1291   AtspiEvent e;
1292
1293   /* TODO: Only fire if object not already marked defunct */
1294   memset (&e, 0, sizeof (e));
1295   e.type = "object:state-change:defunct";
1296   e.source = accessible;
1297   e.detail1 = 1;
1298   e.detail2 = 0;
1299   _atspi_send_event (&e);
1300
1301     g_free (accessible->path);
1302
1303     if (accessible->states)
1304       g_object_unref (accessible->states);
1305     g_free (accessible->description);
1306     g_free (accessible->name);
1307 }
1308
1309 AtspiAccessible *
1310 atspi_accessible_new (AtspiApplication *app, const gchar *path)
1311 {
1312   AtspiAccessible *accessible;
1313   
1314   accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
1315   g_return_val_if_fail (accessible != NULL, NULL);
1316
1317   accessible->app = g_object_ref (app);
1318   accessible->path = g_strdup (path);
1319
1320   return accessible;
1321 }