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