Added state-change signal to AtkObject (will deprecate accessible-state property)
[platform/upstream/atk.git] / atk / atkobject.c
1 /* ATK -  Accessibility Toolkit
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <string.h>
21
22 #include <glib-object.h>
23
24 #include "atk.h"
25
26 /* New GObject properties registered by AtkObject */
27 enum
28 {
29   PROP_0,  /* gobject convention */
30
31   PROP_NAME,
32   PROP_DESCRIPTION,
33   PROP_PARENT,      /* ancestry has changed */
34   PROP_STATE,       /* AtkStateSet for the object has changed */
35   PROP_VALUE,
36   PROP_ROLE,
37   PROP_TABLE_CAPTION,
38   PROP_TABLE_COLUMN_DESCRIPTION,
39   PROP_TABLE_COLUMN_HEADER,
40   PROP_TABLE_ROW_DESCRIPTION,
41   PROP_TABLE_ROW_HEADER,
42   PROP_TABLE_SUMMARY,
43   PROP_LAST         /* gobject convention */
44 };
45
46 enum {
47   CHILDREN_CHANGED,
48   FOCUS_EVENT,
49   PROPERTY_CHANGE,
50   VISIBLE_DATA_CHANGED,
51   STATE_CHANGE,
52   
53   LAST_SIGNAL
54 };
55
56 static void            atk_object_class_init        (AtkObjectClass  *klass);
57 static void            atk_object_init              (AtkObject       *accessible,
58                                                      AtkObjectClass  *klass);
59 static AtkRelationSet* atk_object_real_ref_relation_set 
60                                                     (AtkObject       *accessible);
61
62 static void            atk_object_real_set_property (GObject         *object,
63                                                      guint            prop_id,
64                                                      const GValue    *value,
65                                                      GParamSpec      *pspec);
66 static void            atk_object_real_get_property (GObject         *object,
67                                                      guint            prop_id,
68                                                      GValue          *value,
69                                                      GParamSpec      *pspec);
70 static void            atk_object_finalize          (GObject         *object);
71 static G_CONST_RETURN gchar*
72                        atk_object_real_get_name     (AtkObject       *object);
73 static G_CONST_RETURN gchar*
74                        atk_object_real_get_description    
75                                                    (AtkObject       *object);
76 static AtkObject*      atk_object_real_get_parent  (AtkObject       *object);
77 static AtkRole         atk_object_real_get_role    (AtkObject       *object);
78 static AtkStateSet*    atk_object_real_ref_state_set
79                                                    (AtkObject       *object);
80 static void            atk_object_real_set_name    (AtkObject       *object,
81                                                     const gchar     *name);
82 static void            atk_object_real_set_description
83                                                    (AtkObject       *object,
84                                                     const gchar     *description);
85 static void            atk_object_real_set_parent  (AtkObject       *object,
86                                                     AtkObject       *parent);
87 static void            atk_object_real_set_role    (AtkObject       *object,
88                                                     AtkRole         role);
89 static guint           atk_object_real_connect_property_change_handler
90                                                    (AtkObject       *obj,
91                                                     AtkPropertyChangeHandler
92                                                                     *handler);
93 static void            atk_object_real_remove_property_change_handler
94                                                    (AtkObject       *obj,
95                                                     guint           handler_id);
96 static void            atk_object_notify           (GObject         *obj,
97                                                     GParamSpec      *pspec);
98
99
100 static guint atk_object_signals[LAST_SIGNAL] = { 0, };
101
102 static gpointer parent_class = NULL;
103
104 static const gchar* atk_object_name_property_name = "accessible-name";
105 static const gchar* atk_object_name_property_state = "accessible-state";
106 static const gchar* atk_object_name_property_description = "accessible-description";
107 static const gchar* atk_object_name_property_parent = "accessible-parent";
108 static const gchar* atk_object_name_property_value = "accessible-value";
109 static const gchar* atk_object_name_property_role = "accessible-role";
110 static const gchar* atk_object_name_property_table_caption = "accessible-table-caption";
111 static const gchar* atk_object_name_property_table_column_description = "accessible-table-column-description";
112 static const gchar* atk_object_name_property_table_column_header = "accessible-table-column-header";
113 static const gchar* atk_object_name_property_table_row_description = "accessible-table-row-description";
114 static const gchar* atk_object_name_property_table_row_header = "accessible-table-row-header";
115 static const gchar* atk_object_name_property_table_summary = "accessible-table-summary";
116
117 GType
118 atk_object_get_type (void)
119 {
120   static GType type = 0;
121
122   if (!type)
123     {
124       static const GTypeInfo typeInfo =
125       {
126         sizeof (AtkObjectClass),
127         (GBaseInitFunc) NULL,
128         (GBaseFinalizeFunc) NULL,
129         (GClassInitFunc) atk_object_class_init,
130         (GClassFinalizeFunc) NULL,
131         NULL,
132         sizeof (AtkObject),
133         0,
134         (GInstanceInitFunc) atk_object_init,
135       } ;
136       type = g_type_register_static (G_TYPE_OBJECT, "AtkObject", &typeInfo, 0) ;
137     }
138   return type;
139 }
140
141 static void
142 atk_object_class_init (AtkObjectClass *klass)
143 {
144   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
145
146   parent_class = g_type_class_ref (G_TYPE_OBJECT);
147
148   gobject_class->set_property = atk_object_real_set_property;
149   gobject_class->get_property = atk_object_real_get_property;
150   gobject_class->finalize = atk_object_finalize;
151   gobject_class->notify = atk_object_notify;
152
153   klass->get_name = atk_object_real_get_name;
154   klass->get_description = atk_object_real_get_description;
155   klass->get_parent = atk_object_real_get_parent;
156   klass->get_n_children = NULL;
157   klass->ref_child = NULL;
158   klass->get_index_in_parent = NULL;
159   klass->ref_relation_set = atk_object_real_ref_relation_set;
160   klass->get_role = atk_object_real_get_role;
161   klass->ref_state_set = atk_object_real_ref_state_set;
162   klass->set_name = atk_object_real_set_name;
163   klass->set_description = atk_object_real_set_description;
164   klass->set_parent = atk_object_real_set_parent;
165   klass->set_role = atk_object_real_set_role;
166   klass->connect_property_change_handler = 
167          atk_object_real_connect_property_change_handler;
168   klass->remove_property_change_handler = 
169          atk_object_real_remove_property_change_handler;
170
171   /*
172    * We do not define default signal handlers here
173    */
174   klass->children_changed = NULL;
175   klass->focus_event = NULL;
176   klass->property_change = NULL;
177   klass->visible_data_changed = NULL;
178
179   g_object_class_install_property (gobject_class,
180                                    PROP_NAME,
181                                    g_param_spec_string (atk_object_name_property_name,
182                                                         "Accessible Name",
183                                                         "Object instance\'s name formatted for "
184                                                            "assistive technology access",
185                                                         NULL,
186                                                         G_PARAM_READWRITE));
187   g_object_class_install_property (gobject_class,
188                                    PROP_DESCRIPTION,
189                                    g_param_spec_string (atk_object_name_property_description,
190                                                         "Accessible Description",
191                                                         "Description of an object, formatted for "
192                                                         "assistive technology access",
193                                                         NULL,
194                                                         G_PARAM_READWRITE));
195   g_object_class_install_property (gobject_class,
196                                    PROP_STATE,
197                                    g_param_spec_int    (atk_object_name_property_state,
198                                                         "Accessible State Set",
199                                                         "The accessible state set of this object "
200                                                         "or its UI component",
201                                                         0,
202                                                         G_MAXINT,
203                                                         0,
204                                                         G_PARAM_READWRITE));
205   g_object_class_install_property (gobject_class,
206                                    PROP_PARENT,
207                                    g_param_spec_object (atk_object_name_property_parent,
208                                                         "Accessible Parent",
209                                                         "Is used to notify that the parent has changed ",
210                                                         ATK_TYPE_OBJECT,
211                                                         G_PARAM_READWRITE));
212   g_object_class_install_property (gobject_class,
213                                    PROP_VALUE,
214                                    g_param_spec_double (atk_object_name_property_value,
215                                                         "Accessible Value",
216                                                         "Is used to notify that the value has changed ",
217                                                         0.0,
218                                                         G_MAXDOUBLE,
219                                                         0.0,
220                                                         G_PARAM_READWRITE));
221   g_object_class_install_property (gobject_class,
222                                    PROP_ROLE,
223                                    g_param_spec_int    (atk_object_name_property_role,
224                                                         "Accessible Role",
225                                                         "The accessible role this object ",
226                                                         0,
227                                                         G_MAXINT,
228                                                         0,
229                                                         G_PARAM_READWRITE));
230   g_object_class_install_property (gobject_class,
231                                    PROP_TABLE_CAPTION,
232                                    g_param_spec_string (atk_object_name_property_table_caption,
233                                                         "Accessible Table Caption",
234                                                         "Is used to notify that the table caption has changed ",
235                                                         NULL,
236                                                         G_PARAM_READWRITE));
237   g_object_class_install_property (gobject_class,
238                                    PROP_TABLE_COLUMN_HEADER,
239                                    g_param_spec_object (atk_object_name_property_table_column_header,
240                                                         "Accessible Table Column Header",
241                                                         "Is used to notify that the table column header has changed ",
242                                                         ATK_TYPE_OBJECT,
243                                                         G_PARAM_READWRITE));
244   g_object_class_install_property (gobject_class,
245                                    PROP_TABLE_COLUMN_DESCRIPTION,
246                                    g_param_spec_string (atk_object_name_property_table_column_description,
247                                                         "Accessible Table Column Description",
248                                                         "Is used to notify that the table columnscription has changed ",
249                                                         NULL,
250                                                         G_PARAM_READWRITE));
251   g_object_class_install_property (gobject_class,
252                                    PROP_TABLE_ROW_HEADER,
253                                    g_param_spec_object (atk_object_name_property_table_row_header,
254                                                         "Accessible Table Row Header",
255                                                         "Is used to notify that the table row header has changed ",
256                                                         ATK_TYPE_OBJECT,
257                                                         G_PARAM_READWRITE));
258   g_object_class_install_property (gobject_class,
259                                    PROP_TABLE_ROW_DESCRIPTION,
260                                    g_param_spec_string (atk_object_name_property_table_row_description,
261                                                         "Accessible Table Row Description",
262                                                         "Is used to notify that the table row description has changed ",
263                                                         NULL,
264                                                         G_PARAM_READWRITE));
265   g_object_class_install_property (gobject_class,
266                                    PROP_TABLE_SUMMARY,
267                                    g_param_spec_object (atk_object_name_property_table_summary,
268                                                         "Accessible Table Summary",
269                                                         "Is used to notify that the table summary has changed ",
270                                                         ATK_TYPE_OBJECT,
271                                                         G_PARAM_READWRITE));
272   /*
273    * The signal "children_changed" supports two details:
274    * "add" and "remove"
275    */
276   atk_object_signals[CHILDREN_CHANGED] =
277     g_signal_new ("children_changed",
278                   G_TYPE_FROM_CLASS (klass),
279                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
280                   G_STRUCT_OFFSET (AtkObjectClass, children_changed),
281                   NULL, NULL,
282                   g_cclosure_marshal_VOID__UINT_POINTER,
283                   G_TYPE_NONE,
284                   2, G_TYPE_UINT, G_TYPE_POINTER);
285   atk_object_signals[FOCUS_EVENT] =
286     g_signal_new ("focus_event",
287                   G_TYPE_FROM_CLASS (klass),
288                   G_SIGNAL_RUN_LAST,
289                   G_STRUCT_OFFSET (AtkObjectClass, focus_event), 
290                   NULL, NULL,
291                   g_cclosure_marshal_VOID__BOOLEAN,
292                   G_TYPE_NONE,
293                   1, G_TYPE_BOOLEAN);
294   atk_object_signals[PROPERTY_CHANGE] =
295     g_signal_new ("property_change",
296                   G_TYPE_FROM_CLASS (klass),
297                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
298                   G_STRUCT_OFFSET (AtkObjectClass, property_change),
299                   (GSignalAccumulator) NULL, NULL,
300                   g_cclosure_marshal_VOID__POINTER,
301                   G_TYPE_NONE, 1,
302                   G_TYPE_POINTER);
303   /*
304    * The "state_change" signal supports details, one for each accessible state type
305    * (see atkstate.c).
306    */
307     g_signal_new ("state_change",
308                   G_TYPE_FROM_CLASS (klass),
309                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
310                   G_STRUCT_OFFSET (AtkObjectClass, state_change),
311                   (GSignalAccumulator) NULL, NULL,
312                   g_cclosure_marshal_VOID__POINTER,
313                   G_TYPE_NONE, 1,
314                   G_TYPE_POINTER);
315   atk_object_signals[VISIBLE_DATA_CHANGED] =
316     g_signal_new ("visible_data_changed",
317                   G_TYPE_FROM_CLASS (klass),
318                   G_SIGNAL_RUN_LAST,
319                   G_STRUCT_OFFSET (AtkObjectClass, visible_data_changed),
320                   (GSignalAccumulator) NULL, NULL,
321                   g_cclosure_marshal_VOID__VOID,
322                   G_TYPE_NONE, 0);
323 }
324
325 static void
326 atk_object_init  (AtkObject        *accessible,
327                   AtkObjectClass   *klass)
328 {
329   accessible->name = NULL;
330   accessible->description = NULL;
331   accessible->accessible_parent = NULL;
332   accessible->relation_set = atk_relation_set_new();
333   accessible->role = ATK_ROLE_UNKNOWN;
334 }
335
336 GType
337 atk_implementor_get_type (void)
338 {
339   static GType type = 0;
340
341   if (!type)
342     {
343       static const GTypeInfo typeInfo =
344       {
345         sizeof (AtkImplementorIface),
346         (GBaseInitFunc) NULL,
347         (GBaseFinalizeFunc) NULL,
348       } ;
349
350       type = g_type_register_static (G_TYPE_INTERFACE, "AtkImplementorIface", &typeInfo, 0) ;
351     }
352
353   return type;
354 }
355
356 /**
357  * atk_object_get_name:
358  * @accessible: an #AtkObject
359  *
360  * Gets the accessible name of the accessible.
361  *
362  * Returns: a character string representing the accessible name of the object.
363  **/
364 G_CONST_RETURN gchar*
365 atk_object_get_name (AtkObject *accessible)
366 {
367   AtkObjectClass *klass;
368
369   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
370
371   klass = ATK_OBJECT_GET_CLASS (accessible);
372   if (klass->get_name)
373     return (klass->get_name) (accessible);
374   else
375     return NULL;
376 }
377
378 /**
379  * atk_object_get_description:
380  * @accessible: an #AtkObject
381  *
382  * Gets the accessible description of the accessible.
383  *
384  * Returns: a character string representing the accessible description
385  * of the accessible.
386  *
387  **/
388 G_CONST_RETURN gchar*
389 atk_object_get_description (AtkObject *accessible)
390 {
391   AtkObjectClass *klass;
392
393   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
394
395   klass = ATK_OBJECT_GET_CLASS (accessible);
396   if (klass->get_description)
397     return (klass->get_description) (accessible);
398   else
399     return NULL;
400 }
401
402 /**
403  * atk_object_get_parent:
404  * @accessible: an #AtkObject
405  *
406  * Gets the accessible parent of the accessible.
407  *
408  * Returns: a #AtkObject representing the accessible parent of the accessible
409  **/
410 AtkObject*
411 atk_object_get_parent (AtkObject *accessible)
412 {
413   AtkObjectClass *klass;
414
415   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
416
417   klass = ATK_OBJECT_GET_CLASS (accessible);
418   if (klass->get_parent)
419     return (klass->get_parent) (accessible);
420   else
421     return NULL;
422 }
423
424 /**
425  * atk_object_get_n_accessible_children:
426  * @accessible: an #AtkObject
427  *
428  * Gets the number of accessible children of the accessible.
429  *
430  * Returns: an integer representing the number of accessible children
431  * of the accessible.
432  **/
433 gint
434 atk_object_get_n_accessible_children (AtkObject *accessible)
435 {
436   AtkObjectClass *klass;
437
438   g_return_val_if_fail (ATK_IS_OBJECT (accessible), 0);
439
440   klass = ATK_OBJECT_GET_CLASS (accessible);
441   if (klass->get_n_children)
442     return (klass->get_n_children) (accessible);
443   else
444     return 0;
445 }
446
447 /**
448  * atk_object_ref_accessible_child:
449  * @accessible: an #AtkObject
450  * @i: a gint representing the position of the child, starting from 0
451  *
452  * Gets a reference to the specified accessible child of the object.
453  * The accessible children are 0-based so the first accessible child is
454  * at index 0, the second at index 1 and so on.
455  *
456  * Returns: an #AtkObject representing the specified accessible child
457  * of the accessible.
458  **/
459 AtkObject*
460 atk_object_ref_accessible_child (AtkObject   *accessible,
461                                  gint        i)
462 {
463   AtkObjectClass *klass;
464
465   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
466
467   klass = ATK_OBJECT_GET_CLASS (accessible);
468   if (klass->ref_child)
469     return (klass->ref_child) (accessible, i);
470   else
471     return NULL;
472 }
473
474 /**
475  * atk_object_ref_relation_set:
476  * @accessible: an #AtkObject
477  *
478  * Gets the #AtkRelationSet associated with the object.
479  *
480  * Returns: an #AtkRelationSet representing the relation set of the object.
481  **/
482 AtkRelationSet*
483 atk_object_ref_relation_set (AtkObject *accessible)
484 {
485   AtkObjectClass *klass;
486
487   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
488
489   klass = ATK_OBJECT_GET_CLASS (accessible);
490   if (klass->ref_relation_set)
491     return (klass->ref_relation_set) (accessible);
492   else
493     return NULL;
494 }
495
496 /**
497  * atk_role_register:
498  * @name: a character string describing the new role.
499  *
500  * Registers the role specified by @name.
501  *
502  * Returns: an #AtkRole for the new role.
503  **/
504 AtkRole
505 atk_role_register (const gchar *name)
506 {
507   /* TODO: associate name with new type */
508   static guint type = ATK_ROLE_LAST_DEFINED;
509   return (++type);
510 }
511
512 /**
513  * atk_object_get_role:
514  * @accessible: an #AtkObject
515  *
516  * Gets the role of the accessible.
517  *
518  * Returns: an #AtkRole which is the role of the accessible
519  **/
520 AtkRole
521 atk_object_get_role (AtkObject *accessible) 
522 {
523   AtkObjectClass *klass;
524
525   g_return_val_if_fail (ATK_IS_OBJECT (accessible), ATK_ROLE_UNKNOWN);
526
527   klass = ATK_OBJECT_GET_CLASS (accessible);
528   if (klass->get_role)
529     return (klass->get_role) (accessible);
530   else
531     return ATK_ROLE_UNKNOWN;
532 }
533
534 /**
535  * atk_object_ref_state_set:
536  * @accessible: an #AtkObject
537  *
538  * Gets a reference to the state set of the accessible; the caller must
539  * unreference it when it is no longer needed.
540  *
541  * Returns: a reference to an #AtkStateSet which is the state
542  * set of the accessible
543  **/
544 AtkStateSet*
545 atk_object_ref_state_set (AtkObject *accessible) 
546 {
547   AtkObjectClass *klass;
548
549   g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
550
551   klass = ATK_OBJECT_GET_CLASS (accessible);
552   if (klass->ref_state_set)
553     return (klass->ref_state_set) (accessible);
554   else
555     return NULL;
556 }
557
558 /**
559  * atk_object_get_index_in_parent:
560  * @accessible: an #AtkObject
561  *
562  * Gets the 0-based index of this accessible in its parent; returns -1 if the
563  * accessible does not have an accessible parent.
564  *
565  * Returns: an integer which is the index of the accessible in its parent
566  **/
567 gint
568 atk_object_get_index_in_parent (AtkObject *accessible)
569 {
570   AtkObjectClass *klass;
571
572   g_return_val_if_fail (ATK_OBJECT (accessible), -1);
573
574   klass = ATK_OBJECT_GET_CLASS (accessible);
575   if (klass->get_index_in_parent)
576     return (klass->get_index_in_parent) (accessible);
577   else
578     return -1;
579 }
580
581 /**
582  * atk_object_set_name:
583  * @accessible: an #AtkObject
584  * @name: a character string to be set as the accessible name
585  *
586  * Sets the accessible name of the accessible.
587  **/
588 void
589 atk_object_set_name (AtkObject    *accessible,
590                      const gchar  *name)
591 {
592   AtkObjectClass *klass;
593
594   g_return_if_fail (ATK_IS_OBJECT (accessible));
595   g_return_if_fail (name != NULL);
596
597   klass = ATK_OBJECT_GET_CLASS (accessible);
598   if (klass->set_name)
599     {
600       (klass->set_name) (accessible, name);
601       g_object_notify (G_OBJECT (accessible), atk_object_name_property_name);
602     }
603 }
604
605 /**
606  * atk_object_set_description:
607  * @accessible: an #AtkObject
608  * @description : a character string to be set as the accessible description
609  *
610  * Sets the accessible description of the accessible.
611  **/
612 void
613 atk_object_set_description (AtkObject   *accessible,
614                             const gchar *description)
615 {
616   AtkObjectClass *klass;
617
618   g_return_if_fail (ATK_IS_OBJECT (accessible));
619   g_return_if_fail (description != NULL);
620
621   klass = ATK_OBJECT_GET_CLASS (accessible);
622   if (klass->set_description)
623     {
624       (klass->set_description) (accessible, description);
625       g_object_notify (G_OBJECT (accessible), atk_object_name_property_description);
626     }
627 }
628
629 /**
630  * atk_object_set_parent:
631  * @accessible: an #AtkObject
632  * @parent : an #AtkObject to be set as the accessible parent
633  *
634  * Sets the accessible parent of the accessible.
635  **/
636 void
637 atk_object_set_parent (AtkObject *accessible,
638                        AtkObject *parent)
639 {
640   AtkObjectClass *klass;
641
642   g_return_if_fail (ATK_IS_OBJECT (accessible));
643
644   klass = ATK_OBJECT_GET_CLASS (accessible);
645   if (klass->set_parent)
646     {
647       (klass->set_parent) (accessible, parent);
648       g_object_notify (G_OBJECT (accessible), atk_object_name_property_parent);
649     }
650 }
651
652 /**
653  * atk_object_set_role:
654  * @accessible: an #AtkObject
655  * @role : an #AtkRole to be set as the role
656  *
657  * Sets the role of the accessible.
658  **/
659 void
660 atk_object_set_role (AtkObject *accessible, 
661                      AtkRole   role)
662 {
663   AtkObjectClass *klass;
664
665   g_return_if_fail (ATK_IS_OBJECT (accessible));
666
667   klass = ATK_OBJECT_GET_CLASS (accessible);
668   if (klass->set_role)
669     {
670       (klass->set_role) (accessible, role);
671       g_object_notify (G_OBJECT (accessible), atk_object_name_property_role);
672     }
673 }
674
675 /**
676  * atk_object_connect_property_change_handler:
677  * @accessible: an #AtkObject
678  * @handler : a function to be called when a property changes its value
679  *
680  * Specifies a function to be called when a property changes value.
681  *
682  * Returns: a #guint which is the handler id used in 
683  * atk_object_remove_property_change_handler()
684  **/
685 guint
686 atk_object_connect_property_change_handler (AtkObject *accessible,
687                                             AtkPropertyChangeHandler *handler)
688 {
689   AtkObjectClass *klass;
690
691   g_return_val_if_fail (ATK_IS_OBJECT (accessible), 0);
692   g_return_val_if_fail ((handler != NULL), 0);
693
694   klass = ATK_OBJECT_GET_CLASS (accessible);
695   if (klass->connect_property_change_handler)
696     return (klass->connect_property_change_handler) (accessible, handler);
697   else
698     return 0;
699 }
700
701 /**
702  * atk_object_remove_property_change_handler:
703  * @accessible: an #AtkObject
704  * @handler_id : a guint which identifies the handler to be removed.
705  * 
706  * Removes a property change handler.
707  **/
708 void
709 atk_object_remove_property_change_handler  (AtkObject *accessible,
710                                             guint      handler_id)
711 {
712   AtkObjectClass *klass;
713
714   g_return_if_fail (ATK_IS_OBJECT (accessible));
715
716   klass = ATK_OBJECT_GET_CLASS (accessible);
717   if (klass->remove_property_change_handler)
718     (klass->remove_property_change_handler) (accessible, handler_id);
719 }
720
721 /**
722  * atk_object_notify_state_change:
723  * @accessible: an #AtkObject
724  * @state: an #AtkState whose state is changed
725  * @value : a gboolean which indicates whether the state is being set on or off
726  * 
727  * Emits a property_change signal for the specified state. 
728  * This signal is caught by an #AtkPropertyChangeHandler
729  **/
730 void
731 atk_object_notify_state_change (AtkObject *accessible,
732                                 AtkState  state,
733                                 gboolean  value)
734 {
735 #define N_TOGGLE_STATES 2
736   AtkPropertyValues  values = { 0, };
737   AtkState toggle_states[N_TOGGLE_STATES] = { ATK_STATE_EXPANDED, 
738                                               ATK_STATE_COLLAPSED };
739   AtkState toggled_states[N_TOGGLE_STATES] = { ATK_STATE_COLLAPSED, 
740                                                ATK_STATE_EXPANDED };
741
742   values.property_name = atk_object_name_property_state;
743   if (value)
744     {
745        gint i;
746
747        g_value_init (&values.new_value, G_TYPE_INT);
748        g_value_set_int (&values.new_value, state);
749
750        for (i = 0; i < N_TOGGLE_STATES; i++)
751          {
752            if (toggle_states[i] == state)
753              {
754                g_value_init (&values.old_value, G_TYPE_INT);
755                g_value_set_int (&values.old_value, toggled_states[i]);
756                break;
757              }
758          }
759     }
760     else
761     {
762        g_value_init (&values.old_value, G_TYPE_INT);
763        g_value_set_int (&values.old_value, state);
764     }
765   g_signal_emit (accessible, atk_object_signals[PROPERTY_CHANGE],
766                  g_quark_from_string (atk_object_name_property_state),
767                  &values, NULL);
768 }
769
770 /**
771  * atk_implementor_ref_accessible:
772  * @implementor: The #GObject instance which should implement #AtkImplementorIface
773  * if a non-null return value is required.
774  * 
775  * Gets a reference to an object's #AtkObject implementation, if
776  * the object implements #AtkObjectIface
777  *
778  * Returns: a reference to an object's #AtkObject implementation
779  */
780 AtkObject *
781 atk_implementor_ref_accessible (AtkImplementor *object)
782 {
783   AtkImplementorIface *iface;
784   AtkObject           *accessible = NULL;
785
786   g_return_val_if_fail (ATK_IS_IMPLEMENTOR (object), NULL);
787
788   iface = ATK_IMPLEMENTOR_GET_IFACE (object);
789
790   if (iface != NULL) 
791     accessible =  iface->ref_accessible (object);
792
793   g_return_val_if_fail ((accessible != NULL), NULL);
794
795   return accessible;
796 }
797
798 static AtkRelationSet*
799 atk_object_real_ref_relation_set (AtkObject *accessible)
800 {
801   g_return_val_if_fail (accessible->relation_set, NULL);
802   g_object_ref (accessible->relation_set); 
803
804   return accessible->relation_set;
805 }
806
807 static void
808 atk_object_real_set_property (GObject      *object,
809                               guint         prop_id,
810                               const GValue *value,
811                               GParamSpec   *pspec)
812 {
813   AtkObject *accessible;
814
815   accessible = ATK_OBJECT (object);
816
817   switch (prop_id)
818     {
819     case PROP_NAME:
820       atk_object_set_name (accessible, g_value_get_string (value));
821       break;
822     case PROP_DESCRIPTION:
823       atk_object_set_description (accessible, g_value_get_string (value));
824       break;
825     case PROP_ROLE:
826       atk_object_set_role (accessible, g_value_get_int (value));
827       break;
828     case PROP_PARENT:
829       atk_object_set_parent (accessible, g_value_get_object (value));
830       break;
831     case PROP_VALUE:
832       if (ATK_IS_VALUE (accessible))
833         atk_value_set_current_value (ATK_VALUE (accessible), value);
834       break;
835     default:
836       break;
837     }
838 }
839
840 static void
841 atk_object_real_get_property (GObject      *object,
842                               guint         prop_id,
843                               GValue       *value,
844                               GParamSpec   *pspec)
845 {
846   AtkObject *accessible;
847
848   accessible = ATK_OBJECT (object);
849
850   switch (prop_id)
851     {
852     case PROP_NAME:
853       g_value_set_string (value, atk_object_get_name (accessible));
854       break;
855     case PROP_DESCRIPTION:
856       g_value_set_string (value, atk_object_get_description (accessible));
857     case PROP_ROLE:
858       g_value_set_int (value, atk_object_get_role (accessible));
859       break;
860     case PROP_PARENT:
861       g_value_set_object (value, atk_object_get_parent (accessible));
862       break;
863     case PROP_VALUE:
864       if (ATK_IS_VALUE (accessible))
865         atk_value_get_current_value (ATK_VALUE (accessible), value);
866       break;
867     default:
868       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
869       break;
870     }
871 }
872
873 static void
874 atk_object_finalize (GObject *object)
875 {
876   AtkObject        *accessible;
877
878   g_return_if_fail (ATK_IS_OBJECT (object));
879
880   accessible = ATK_OBJECT (object);
881
882   g_free (accessible->name);
883   g_free (accessible->description);
884
885   /*
886    * Free memory allocated for relation set if it have been allocated.
887    */
888   if (accessible->relation_set)
889     g_object_unref (accessible->relation_set);
890
891   if (accessible->accessible_parent)
892     g_object_unref (accessible->accessible_parent);
893
894   G_OBJECT_CLASS (parent_class)->finalize (object);
895 }
896
897 static G_CONST_RETURN gchar*
898 atk_object_real_get_name (AtkObject *object)
899 {
900   return object->name;
901 }
902
903 static G_CONST_RETURN gchar*
904 atk_object_real_get_description (AtkObject *object)
905 {
906   return object->description;
907 }
908
909 static AtkObject*
910 atk_object_real_get_parent (AtkObject       *object)
911 {
912   return object->accessible_parent;
913 }
914
915 static AtkRole
916 atk_object_real_get_role (AtkObject       *object)
917 {
918   return object->role;
919 }
920
921 static AtkStateSet*
922 atk_object_real_ref_state_set (AtkObject *accessible) 
923 {
924   AtkStateSet *state_set;
925   AtkObject *ap;
926
927   state_set = atk_state_set_new ();
928
929   ap = atk_object_get_parent (accessible);
930   if (ap)
931     if (ATK_IS_SELECTION (ap))
932       {
933         int i;
934
935         atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
936
937         i = atk_object_get_index_in_parent (accessible);
938         if (i >= 0)
939           if (atk_selection_is_child_selected(ATK_SELECTION (ap), i))
940             atk_state_set_add_state (state_set, ATK_STATE_SELECTED);
941       } 
942
943   return state_set; 
944 }
945
946 static void
947 atk_object_real_set_name (AtkObject       *object,
948                           const gchar     *name)
949 {
950   g_free (object->name);
951   object->name = g_strdup (name);
952 }
953
954 static void
955 atk_object_real_set_description (AtkObject       *object,
956                                  const gchar     *description)
957 {
958   g_free (object->description);
959   object->description = g_strdup (description);
960 }
961
962 static void
963 atk_object_real_set_parent (AtkObject       *object,
964                             AtkObject       *parent)
965 {
966   if (object->accessible_parent)
967     g_object_unref (object->accessible_parent);
968
969   object->accessible_parent = parent;
970   if (object->accessible_parent)
971     g_object_ref (object->accessible_parent);
972 }
973
974 static void
975 atk_object_real_set_role (AtkObject *object,
976                           AtkRole   role)
977 {
978   object->role = role;
979 }
980
981 static guint
982 atk_object_real_connect_property_change_handler (AtkObject                *obj,
983                                                  AtkPropertyChangeHandler *handler)
984 {
985   return g_signal_connect_closure_by_id (obj,
986                                          atk_object_signals[PROPERTY_CHANGE],
987                                          0,
988                                          g_cclosure_new (
989                                          G_CALLBACK (handler), NULL,
990                                          (GClosureNotify) NULL),
991                                          FALSE);
992 }
993
994 static void
995 atk_object_real_remove_property_change_handler (AtkObject           *obj,
996                                           guint               handler_id)
997 {
998   g_signal_handler_disconnect (obj, handler_id);
999 }
1000
1001 /*
1002  * This function is a signal handler for notify signal which gets emitted
1003  * when a property changes value.
1004  *
1005  * It constructs an AtkPropertyValues structure and emits a "property_changed"
1006  * signal which causes the user specified AtkPropertyChangeHandler
1007  * to be called.
1008  */
1009 static void
1010 atk_object_notify (GObject     *obj,
1011                    GParamSpec  *pspec)
1012 {
1013   AtkPropertyValues values = { 0, };
1014
1015   g_value_init (&values.new_value, pspec->value_type);
1016   g_object_get_property (obj, pspec->name, &values.new_value);
1017   values.property_name = pspec->name;
1018   g_signal_emit (obj, atk_object_signals[PROPERTY_CHANGE],
1019                  g_quark_from_string (pspec->name),
1020                  &values, NULL);
1021 }