]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailbutton.c
3a1ac3d4686c79c76cd535b3722696fb1e092438
[~andy/gtk] / modules / other / gail / gailbutton.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001, 2002, 2003 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 "config.h"
21
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 #include "gailbutton.h"
26 #include <libgail-util/gailmisc.h>
27
28 #define GAIL_BUTTON_ATTACHED_MENUS "gtk-attached-menus"
29
30 static void                  gail_button_class_init       (GailButtonClass *klass);
31 static void                  gail_button_init             (GailButton      *button);
32
33 static G_CONST_RETURN gchar* gail_button_get_name         (AtkObject       *obj);
34 static gint                  gail_button_get_n_children   (AtkObject       *obj);
35 static AtkObject*            gail_button_ref_child        (AtkObject       *obj,
36                                                            gint            i);
37 static AtkStateSet*          gail_button_ref_state_set    (AtkObject       *obj);
38 static void                  gail_button_notify_label_gtk (GObject         *obj,
39                                                            GParamSpec      *pspec,
40                                                            gpointer        data);
41 static void                  gail_button_label_map_gtk    (GtkWidget       *widget,
42                                                            gpointer        data);
43
44 static void                  gail_button_real_initialize  (AtkObject       *obj,
45                                                            gpointer        data);
46 static void                  gail_button_finalize         (GObject        *object);
47 static void                  gail_button_init_textutil    (GailButton     *button,
48                                                            GtkWidget      *label);
49
50 static void                  gail_button_pressed_enter_handler  (GtkWidget       *widget);
51 static void                  gail_button_released_leave_handler (GtkWidget       *widget);
52 static gint                  gail_button_real_add_gtk           (GtkContainer    *container,
53                                                                  GtkWidget       *widget,
54                                                                  gpointer        data);
55
56
57 static void                  atk_action_interface_init  (AtkActionIface *iface);
58 static gboolean              gail_button_do_action      (AtkAction      *action,
59                                                          gint           i);
60 static gboolean              idle_do_action             (gpointer       data);
61 static gint                  gail_button_get_n_actions  (AtkAction      *action);
62 static G_CONST_RETURN gchar* gail_button_get_description(AtkAction      *action,
63                                                          gint           i);
64 static G_CONST_RETURN gchar* gail_button_get_keybinding (AtkAction      *action,
65                                                          gint           i);
66 static G_CONST_RETURN gchar* gail_button_action_get_name(AtkAction      *action,
67                                                          gint           i);
68 static gboolean              gail_button_set_description(AtkAction      *action,
69                                                          gint           i,
70                                                          const gchar    *desc);
71 static void                  gail_button_notify_label_weak_ref (gpointer data,
72                                                                 GObject  *obj);
73 static void                  gail_button_notify_weak_ref       (gpointer data,
74                                                                 GObject  *obj);
75
76
77 /* AtkImage.h */
78 static void                  atk_image_interface_init   (AtkImageIface  *iface);
79 static G_CONST_RETURN gchar* gail_button_get_image_description 
80                                                         (AtkImage       *image);
81 static void                  gail_button_get_image_position
82                                                         (AtkImage       *image,
83                                                          gint           *x,
84                                                          gint           *y,
85                                                          AtkCoordType   coord_type);
86 static void                  gail_button_get_image_size (AtkImage       *image,
87                                                          gint           *width,
88                                                          gint           *height);
89 static gboolean              gail_button_set_image_description 
90                                                         (AtkImage       *image,
91                                                          const gchar    *description);
92
93 /* atktext.h */ 
94 static void       atk_text_interface_init          (AtkTextIface        *iface);
95
96 static gchar*     gail_button_get_text             (AtkText           *text,
97                                                     gint              start_pos,
98                                                     gint              end_pos);
99 static gunichar   gail_button_get_character_at_offset(AtkText         *text,
100                                                     gint              offset);
101 static gchar*     gail_button_get_text_before_offset(AtkText          *text,
102                                                     gint              offset,
103                                                     AtkTextBoundary   boundary_type,
104                                                     gint              *start_offset,
105                                                     gint              *end_offset);
106 static gchar*     gail_button_get_text_at_offset   (AtkText           *text,
107                                                     gint              offset,
108                                                     AtkTextBoundary   boundary_type,
109                                                     gint              *start_offset,
110                                                     gint              *end_offset);
111 static gchar*     gail_button_get_text_after_offset(AtkText           *text,
112                                                     gint              offset,
113                                                     AtkTextBoundary   boundary_type,
114                                                     gint              *start_offset,
115                                                     gint              *end_offset);
116 static gint       gail_button_get_character_count  (AtkText           *text);
117 static void gail_button_get_character_extents      (AtkText           *text,
118                                                     gint              offset,
119                                                     gint              *x,
120                                                     gint              *y,
121                                                     gint              *width,
122                                                     gint              *height,
123                                                     AtkCoordType      coords);
124 static gint gail_button_get_offset_at_point        (AtkText           *text,
125                                                     gint              x,
126                                                     gint              y,
127                                                     AtkCoordType      coords);
128 static AtkAttributeSet* gail_button_get_run_attributes 
129                                                    (AtkText           *text,
130                                                     gint              offset,
131                                                     gint              *start_offset,
132                                                     gint              *end_offset);
133 static AtkAttributeSet* gail_button_get_default_attributes
134                                                    (AtkText           *text);
135 static GtkImage*             get_image_from_button      (GtkWidget      *button);
136 static GtkWidget*            get_label_from_button      (GtkWidget      *button,
137                                                          gint           index,
138                                                          gboolean       allow_many);
139 static gint                  get_n_labels_from_button   (GtkWidget      *button);
140 static void                  set_role_for_button        (AtkObject      *accessible,
141                                                          GtkWidget      *button);
142
143 static gint                  get_n_attached_menus       (GtkWidget      *widget);
144 static GtkWidget*            get_nth_attached_menu      (GtkWidget      *widget,
145                                                          gint           index);
146
147 G_DEFINE_TYPE_WITH_CODE (GailButton, gail_button, GAIL_TYPE_CONTAINER,
148                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
149                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, atk_image_interface_init)
150                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
151
152 static void
153 gail_button_class_init (GailButtonClass *klass)
154 {
155   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
156   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
157   GailContainerClass *container_class;
158
159   container_class = (GailContainerClass*)klass;
160
161   gobject_class->finalize = gail_button_finalize;
162
163   class->get_name = gail_button_get_name;
164   class->get_n_children = gail_button_get_n_children;
165   class->ref_child = gail_button_ref_child;
166   class->ref_state_set = gail_button_ref_state_set;
167   class->initialize = gail_button_real_initialize;
168
169   container_class->add_gtk = gail_button_real_add_gtk;
170   container_class->remove_gtk = NULL;
171 }
172
173 static void
174 gail_button_init (GailButton *button)
175 {
176   button->click_description = NULL;
177   button->press_description = NULL;
178   button->release_description = NULL;
179   button->click_keybinding = NULL;
180   button->action_queue = NULL;
181   button->action_idle_handler = 0;
182   button->textutil = NULL;
183 }
184
185 static G_CONST_RETURN gchar*
186 gail_button_get_name (AtkObject *obj)
187 {
188   G_CONST_RETURN gchar* name = NULL;
189
190   g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
191
192   name = ATK_OBJECT_CLASS (gail_button_parent_class)->get_name (obj);
193   if (name == NULL)
194     {
195       /*
196        * Get the text on the label
197        */
198       GtkWidget *widget;
199       GtkWidget *child;
200
201       widget = GTK_ACCESSIBLE (obj)->widget;
202       if (widget == NULL)
203         /*
204          * State is defunct
205          */
206         return NULL;
207
208       g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
209
210       child = get_label_from_button (widget, 0, FALSE);
211       if (GTK_IS_LABEL (child))
212         name = gtk_label_get_text (GTK_LABEL (child)); 
213       else
214         {
215           GtkImage *image;
216
217           image = get_image_from_button (widget);
218           if (GTK_IS_IMAGE (image))
219             {
220               AtkObject *atk_obj;
221
222               atk_obj = gtk_widget_get_accessible (GTK_WIDGET (image));
223               name = atk_object_get_name (atk_obj);
224             }
225         }
226     }
227   return name;
228 }
229
230 /*
231  * A DownArrow in a GtkToggltButton whose parent is not a ColorCombo
232  * has press as default action.
233  */
234 static gboolean
235 gail_button_is_default_press (GtkWidget *widget)
236 {
237   GtkWidget  *child;
238   GtkWidget  *parent;
239   gboolean ret = FALSE;
240   const gchar *parent_type_name;
241
242   child = GTK_BIN (widget)->child;
243   if (GTK_IS_ARROW (child) &&
244       GTK_ARROW (child)->arrow_type == GTK_ARROW_DOWN)
245     {
246       parent = gtk_widget_get_parent (widget);
247       if (parent)
248         {
249           parent_type_name = g_type_name (G_OBJECT_TYPE (parent));
250           if (strcmp (parent_type_name, "ColorCombo"))
251             return TRUE;
252         }
253     }
254
255   return ret;
256 }
257
258 static void
259 gail_button_real_initialize (AtkObject *obj,
260                              gpointer   data)
261 {
262   GailButton *button = GAIL_BUTTON (obj);
263   GtkWidget  *label;
264   GtkWidget  *widget;
265
266   ATK_OBJECT_CLASS (gail_button_parent_class)->initialize (obj, data);
267
268   button->state = GTK_STATE_NORMAL;
269
270   g_signal_connect (data,
271                     "pressed",
272                     G_CALLBACK (gail_button_pressed_enter_handler),
273                     NULL);
274   g_signal_connect (data,
275                     "enter",
276                     G_CALLBACK (gail_button_pressed_enter_handler),
277                     NULL);
278   g_signal_connect (data,
279                     "released",
280                     G_CALLBACK (gail_button_released_leave_handler),
281                     NULL);
282   g_signal_connect (data,
283                     "leave",
284                     G_CALLBACK (gail_button_released_leave_handler),
285                     NULL);
286
287
288   widget = GTK_WIDGET (data);
289   label = get_label_from_button (widget, 0, FALSE);
290   if (GTK_IS_LABEL (label))
291     {
292       if (GTK_WIDGET_MAPPED (label))
293         gail_button_init_textutil (button, label);
294       else 
295         g_signal_connect (label,
296                           "map",
297                           G_CALLBACK (gail_button_label_map_gtk),
298                           button);
299     }
300   button->default_is_press = gail_button_is_default_press (widget);
301     
302   set_role_for_button (obj, data);
303 }
304
305 static void
306 gail_button_label_map_gtk (GtkWidget *widget,
307                            gpointer data)
308 {
309   GailButton *button; 
310
311   button = GAIL_BUTTON (data);
312   gail_button_init_textutil (button, widget);
313 }
314
315 static void
316 gail_button_notify_label_gtk (GObject           *obj,
317                               GParamSpec        *pspec,
318                               gpointer           data)
319 {
320   AtkObject* atk_obj = ATK_OBJECT (data);
321   GtkLabel *label;
322   GailButton *gail_button;
323
324   if (strcmp (pspec->name, "label") == 0)
325     {
326       const gchar* label_text;
327
328       label = GTK_LABEL (obj);
329
330       label_text = gtk_label_get_text (label);
331
332       gail_button = GAIL_BUTTON (atk_obj);
333       gail_text_util_text_setup (gail_button->textutil, label_text);
334
335       if (atk_obj->name == NULL)
336       {
337         /*
338          * The label has changed so notify a change in accessible-name
339          */
340         g_object_notify (G_OBJECT (atk_obj), "accessible-name");
341       }
342       /*
343        * The label is the only property which can be changed
344        */
345       g_signal_emit_by_name (atk_obj, "visible_data_changed");
346     }
347 }
348
349 static void
350 gail_button_notify_weak_ref (gpointer data, GObject* obj)
351 {
352   GtkLabel *label = NULL;
353
354   AtkObject* atk_obj = ATK_OBJECT (obj);
355   if (data && GTK_IS_WIDGET (data))
356     {
357       label = GTK_LABEL (data);
358       if (label)
359         {
360           g_signal_handlers_disconnect_by_func (label,
361                                                 (GCallback) gail_button_notify_label_gtk,
362                                                 GAIL_BUTTON (atk_obj));
363           g_object_weak_unref (G_OBJECT (label),
364                                gail_button_notify_label_weak_ref,
365                                GAIL_BUTTON (atk_obj));
366         }
367     }
368 }
369
370 static void
371 gail_button_notify_label_weak_ref (gpointer data, GObject* obj)
372 {
373   GtkLabel *label = NULL;
374   GailButton *button = NULL;
375
376   label = GTK_LABEL (obj);
377   if (data && GAIL_IS_BUTTON (data))
378     {
379       button = GAIL_BUTTON (ATK_OBJECT (data));
380       if (button)
381         g_object_weak_unref (G_OBJECT (button), gail_button_notify_weak_ref,
382                              label);
383     }
384 }
385
386
387 static void
388 gail_button_init_textutil (GailButton  *button,
389                            GtkWidget   *label)
390 {
391   const gchar *label_text;
392
393   if (button->textutil)
394     g_object_unref (button->textutil);
395   button->textutil = gail_text_util_new ();
396   label_text = gtk_label_get_text (GTK_LABEL (label));
397   gail_text_util_text_setup (button->textutil, label_text);
398   g_object_weak_ref (G_OBJECT (button),
399                      gail_button_notify_weak_ref, label);
400   g_object_weak_ref (G_OBJECT (label),
401                      gail_button_notify_label_weak_ref, button);
402   g_signal_connect (label,
403                     "notify",
404                     (GCallback) gail_button_notify_label_gtk,
405                     button);     
406 }
407
408 static gint
409 gail_button_real_add_gtk (GtkContainer *container,
410                           GtkWidget    *widget,
411                           gpointer     data)
412 {
413   GtkLabel *label;
414   GailButton *button;
415
416   if (GTK_IS_LABEL (widget))
417     {
418       const gchar* label_text;
419
420       label = GTK_LABEL (widget);
421
422
423       button = GAIL_BUTTON (data);
424       if (!button->textutil)
425         gail_button_init_textutil (button, widget);
426       else
427         {
428           label_text = gtk_label_get_text (label);
429           gail_text_util_text_setup (button->textutil, label_text);
430         }
431     }
432
433   return 1;
434 }
435
436 static void
437 atk_action_interface_init (AtkActionIface *iface)
438 {
439   iface->do_action = gail_button_do_action;
440   iface->get_n_actions = gail_button_get_n_actions;
441   iface->get_description = gail_button_get_description;
442   iface->get_keybinding = gail_button_get_keybinding;
443   iface->get_name = gail_button_action_get_name;
444   iface->set_description = gail_button_set_description;
445 }
446
447 static gboolean
448 gail_button_do_action (AtkAction *action,
449                        gint      i)
450 {
451   GtkWidget *widget;
452   GailButton *button;
453   gboolean return_value = TRUE;
454
455   widget = GTK_ACCESSIBLE (action)->widget;
456   if (widget == NULL)
457     /*
458      * State is defunct
459      */
460     return FALSE;
461
462   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
463     return FALSE;
464
465   button = GAIL_BUTTON (action); 
466
467   switch (i)
468     {
469     case 0:
470     case 1:
471     case 2:
472       if (!button->action_queue) 
473         {
474           button->action_queue = g_queue_new ();
475         }
476       g_queue_push_head (button->action_queue, GINT_TO_POINTER(i));
477       if (!button->action_idle_handler)
478         button->action_idle_handler = gdk_threads_add_idle (idle_do_action, button);
479       break;
480     default:
481       return_value = FALSE;
482       break;
483     }
484   return return_value; 
485 }
486
487 static gboolean
488 idle_do_action (gpointer data)
489 {
490   GtkButton *button; 
491   GtkWidget *widget;
492   GailButton *gail_button;
493   GdkEvent tmp_event;
494
495   gail_button = GAIL_BUTTON (data);
496   gail_button->action_idle_handler = 0;
497   widget = GTK_ACCESSIBLE (gail_button)->widget;
498   tmp_event.button.type = GDK_BUTTON_RELEASE;
499   tmp_event.button.window = widget->window;
500   tmp_event.button.button = 1;
501   tmp_event.button.send_event = TRUE;
502   tmp_event.button.time = GDK_CURRENT_TIME;
503   tmp_event.button.axes = NULL;
504
505   g_object_ref (gail_button);
506
507   if (widget == NULL /* State is defunct */ ||
508       !gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
509     {
510       g_object_unref (gail_button);
511       return FALSE;
512     }
513   else
514     gtk_widget_event (widget, &tmp_event);
515
516   button = GTK_BUTTON (widget); 
517   while (!g_queue_is_empty (gail_button->action_queue)) 
518     {
519       gint action_number = GPOINTER_TO_INT(g_queue_pop_head (gail_button->action_queue));
520       if (gail_button->default_is_press)
521         {
522           if (action_number == 0)
523             action_number = 1;
524           else if (action_number == 1)
525             action_number = 0;
526         }
527       switch (action_number)
528         {
529         case 0:
530           /* first a press */ 
531
532           button->in_button = TRUE;
533           g_signal_emit_by_name (button, "enter");
534           /*
535            * Simulate a button press event. calling gtk_button_pressed() does
536            * not get the job done for a GtkOptionMenu.  
537            */
538           tmp_event.button.type = GDK_BUTTON_PRESS;
539           tmp_event.button.window = widget->window;
540           tmp_event.button.button = 1;
541           tmp_event.button.send_event = TRUE;
542           tmp_event.button.time = GDK_CURRENT_TIME;
543           tmp_event.button.axes = NULL;
544           
545           gtk_widget_event (widget, &tmp_event);
546
547           /* then a release */
548           tmp_event.button.type = GDK_BUTTON_RELEASE;
549           gtk_widget_event (widget, &tmp_event);
550           button->in_button = FALSE;
551           g_signal_emit_by_name (button, "leave");
552           break;
553         case 1:
554           button->in_button = TRUE;
555           g_signal_emit_by_name (button, "enter");
556           /*
557            * Simulate a button press event. calling gtk_button_pressed() does
558            * not get the job done for a GtkOptionMenu.  
559            */
560           tmp_event.button.type = GDK_BUTTON_PRESS;
561           tmp_event.button.window = widget->window;
562           tmp_event.button.button = 1;
563           tmp_event.button.send_event = TRUE;
564           tmp_event.button.time = GDK_CURRENT_TIME;
565           tmp_event.button.axes = NULL;
566           
567           gtk_widget_event (widget, &tmp_event);
568           break;
569         case 2:
570           button->in_button = FALSE;
571           g_signal_emit_by_name (button, "leave");
572           break;
573         default:
574           g_assert_not_reached ();
575           break;
576         }
577     }
578   g_object_unref (gail_button);
579   return FALSE;
580 }
581
582 static gint
583 gail_button_get_n_actions (AtkAction *action)
584 {
585   return 3;
586 }
587
588 static G_CONST_RETURN gchar*
589 gail_button_get_description (AtkAction *action,
590                              gint      i)
591 {
592   GailButton *button;
593   G_CONST_RETURN gchar *return_value;
594
595   button = GAIL_BUTTON (action);
596
597   if (button->default_is_press)
598     {
599       if (i == 0)
600         i = 1;
601       else if (i == 1)
602         i = 0;
603     }
604   switch (i)
605     {
606     case 0:
607       return_value = button->click_description;
608       break;
609     case 1:
610       return_value = button->press_description;
611       break;
612     case 2:
613       return_value = button->release_description;
614       break;
615     default:
616       return_value = NULL;
617       break;
618     }
619   return return_value; 
620 }
621
622 static G_CONST_RETURN gchar*
623 gail_button_get_keybinding (AtkAction *action,
624                             gint      i)
625 {
626   GailButton *button;
627   gchar *return_value = NULL;
628
629   button = GAIL_BUTTON (action);
630   if (button->default_is_press)
631     {
632       if (i == 0)
633         i = 1;
634       else if (i == 1)
635         i = 0;
636     }
637   switch (i)
638     {
639     case 0:
640       {
641         /*
642          * We look for a mnemonic on the label
643          */
644         GtkWidget *widget;
645         GtkWidget *label;
646         guint key_val; 
647
648         widget = GTK_ACCESSIBLE (button)->widget;
649         if (widget == NULL)
650           /*
651            * State is defunct
652            */
653           return NULL;
654
655         g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
656
657         label = get_label_from_button (widget, 0, FALSE);
658         if (GTK_IS_LABEL (label))
659           {
660             key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
661             if (key_val != GDK_VoidSymbol)
662               return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
663           }
664         if (return_value == NULL)
665           {
666             /* Find labelled-by relation */
667             AtkRelationSet *set;
668             AtkRelation *relation;
669             GPtrArray *target;
670             gpointer target_object;
671
672             set = atk_object_ref_relation_set (ATK_OBJECT (action));
673             if (set)
674               {
675                 relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
676                 if (relation)
677                   {              
678                     target = atk_relation_get_target (relation);
679             
680                     target_object = g_ptr_array_index (target, 0);
681                     if (GTK_IS_ACCESSIBLE (target_object))
682                       {
683                         label = GTK_ACCESSIBLE (target_object)->widget;
684                       } 
685                   }
686                 g_object_unref (set);
687               }
688
689             if (GTK_IS_LABEL (label))
690               {
691                 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
692                 if (key_val != GDK_VoidSymbol)
693                   return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
694               }
695           }
696         g_free (button->click_keybinding);
697         button->click_keybinding = return_value;
698         break;
699       }
700     default:
701       break;
702     }
703   return return_value; 
704 }
705
706 static G_CONST_RETURN gchar*
707 gail_button_action_get_name (AtkAction *action,
708                              gint      i)
709 {
710   G_CONST_RETURN gchar *return_value;
711   GailButton *button;
712
713   button = GAIL_BUTTON (action);
714
715   if (button->default_is_press)
716     {
717       if (i == 0)
718         i = 1;
719       else if (i == 1)
720         i = 0;
721     }
722   switch (i)
723     {
724     case 0:
725       /*
726        * This action is a "click" to activate a button or "toggle" to change
727        * the state of a toggle button check box or radio button.
728        */ 
729       return_value = "click";
730       break;
731     case 1:
732       /*
733        * This action simulates a button press by simulating moving the
734        * mouse into the button followed by pressing the left mouse button.
735        */
736       return_value = "press";
737       break;
738     case 2:
739       /*
740        * This action simulates releasing the left mouse button outside the 
741        * button.
742        *
743        * To simulate releasing the left mouse button inside the button use
744        * the click action.
745        */
746       return_value = "release";
747       break;
748     default:
749       return_value = NULL;
750       break;
751     }
752   return return_value; 
753 }
754
755 static gboolean
756 gail_button_set_description (AtkAction      *action,
757                              gint           i,
758                              const gchar    *desc)
759 {
760   GailButton *button;
761   gchar **value;
762
763   button = GAIL_BUTTON (action);
764
765   if (button->default_is_press)
766     {
767       if (i == 0)
768         i = 1;
769       else if (i == 1)
770         i = 0;
771     }
772   switch (i)
773     {
774     case 0:
775       value = &button->click_description;
776       break;
777     case 1:
778       value = &button->press_description;
779       break;
780     case 2:
781       value = &button->release_description;
782       break;
783     default:
784       value = NULL;
785       break;
786     }
787   if (value)
788     {
789       g_free (*value);
790       *value = g_strdup (desc);
791       return TRUE;
792     }
793   else
794     return FALSE;
795 }
796
797 static gint
798 gail_button_get_n_children (AtkObject* obj)
799 {
800   GtkWidget *widget;
801   gint n_children;
802
803   g_return_val_if_fail (GAIL_IS_BUTTON (obj), 0);
804
805   widget = GTK_ACCESSIBLE (obj)->widget;
806   if (widget == NULL)
807     /*
808      * State is defunct
809      */
810     return 0;
811
812   /*
813    * Check whether we have an attached menus for PanelMenuButton
814    */
815   n_children = get_n_attached_menus (widget);
816   if (n_children > 0)
817     return n_children;
818
819   n_children = get_n_labels_from_button (widget);
820   if (n_children <= 1)
821     n_children = 0;
822
823   return n_children;
824 }
825
826 static AtkObject*
827 gail_button_ref_child (AtkObject *obj,
828                        gint      i)
829 {
830   GtkWidget *widget;
831   GtkWidget *child_widget;
832   AtkObject *child;
833
834   g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
835
836   widget = GTK_ACCESSIBLE (obj)->widget;
837   if (widget == NULL)
838     /*
839      * State is defunct
840      */
841     return NULL;
842
843   if (i >= gail_button_get_n_children (obj))
844     return NULL;
845
846   if (get_n_attached_menus (widget) > 0)
847   {
848     child_widget = get_nth_attached_menu (widget, i);
849   }
850   else
851     child_widget = NULL;    
852
853   if (!child_widget) 
854     {
855       if (get_n_labels_from_button (widget) > 1)
856         {
857           child_widget = get_label_from_button (widget, i, TRUE);
858         }
859     }
860
861   if (child_widget)
862     {
863       child = gtk_widget_get_accessible (child_widget);
864       g_object_ref (child);
865     }
866   else
867     child = NULL;
868
869   return child;
870 }
871
872 static AtkStateSet*
873 gail_button_ref_state_set (AtkObject *obj)
874 {
875   AtkStateSet *state_set;
876   GtkWidget *widget;
877
878   state_set = ATK_OBJECT_CLASS (gail_button_parent_class)->ref_state_set (obj);
879   widget = GTK_ACCESSIBLE (obj)->widget;
880
881   if (widget == NULL)
882     return state_set;
883
884   if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
885     atk_state_set_add_state (state_set, ATK_STATE_ARMED);
886
887   if (!gtk_widget_get_can_focus (widget))
888     atk_state_set_remove_state (state_set, ATK_STATE_SELECTABLE);
889
890
891   return state_set;
892 }
893
894 /*
895  * This is the signal handler for the "pressed" or "enter" signal handler
896  * on the GtkButton.
897  *
898  * If the state is now GTK_STATE_ACTIVE we notify a property change
899  */
900 static void
901 gail_button_pressed_enter_handler (GtkWidget       *widget)
902 {
903   AtkObject *accessible;
904
905   if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
906     {
907       accessible = gtk_widget_get_accessible (widget);
908       atk_object_notify_state_change (accessible, ATK_STATE_ARMED, TRUE);
909       GAIL_BUTTON (accessible)->state = GTK_STATE_ACTIVE;
910     }
911 }
912
913 /*
914  * This is the signal handler for the "released" or "leave" signal handler
915  * on the GtkButton.
916  *
917  * If the state was GTK_STATE_ACTIVE we notify a property change
918  */
919 static void
920 gail_button_released_leave_handler (GtkWidget       *widget)
921 {
922   AtkObject *accessible;
923
924   accessible = gtk_widget_get_accessible (widget);
925   if (GAIL_BUTTON (accessible)->state == GTK_STATE_ACTIVE)
926     {
927       atk_object_notify_state_change (accessible, ATK_STATE_ARMED, FALSE);
928       GAIL_BUTTON (accessible)->state = GTK_STATE_NORMAL;
929     }
930 }
931
932 static void
933 atk_image_interface_init (AtkImageIface *iface)
934 {
935   iface->get_image_description = gail_button_get_image_description;
936   iface->get_image_position = gail_button_get_image_position;
937   iface->get_image_size = gail_button_get_image_size;
938   iface->set_image_description = gail_button_set_image_description;
939 }
940
941 static GtkImage*
942 get_image_from_button (GtkWidget *button)
943 {
944   GtkWidget *child;
945   GList *list;
946   GtkImage *image = NULL;
947
948   child = gtk_bin_get_child (GTK_BIN (button));
949   if (GTK_IS_IMAGE (child))
950     image = GTK_IMAGE (child);
951   else
952     {
953       if (GTK_IS_ALIGNMENT (child))
954         child = gtk_bin_get_child (GTK_BIN (child));
955       if (GTK_IS_CONTAINER (child))
956         {
957           list = gtk_container_get_children (GTK_CONTAINER (child));
958           if (!list)
959             return NULL;
960           if (GTK_IS_IMAGE (list->data))
961             image = GTK_IMAGE (list->data);
962           g_list_free (list);
963         }
964     }
965
966   return image;
967 }
968
969 static G_CONST_RETURN gchar* 
970 gail_button_get_image_description (AtkImage *image) {
971
972   GtkWidget *widget;
973   GtkImage  *button_image;
974   AtkObject *obj;
975
976   widget = GTK_ACCESSIBLE (image)->widget;
977
978   if (widget == NULL)
979     /*
980      * State is defunct
981      */
982     return NULL;
983
984   button_image = get_image_from_button (widget);
985
986   if (button_image != NULL)
987     {
988       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
989       return atk_image_get_image_description (ATK_IMAGE (obj));
990     }
991   else 
992     return NULL;
993 }
994
995 static void
996 gail_button_get_image_position (AtkImage     *image,
997                                 gint         *x,
998                                 gint         *y,
999                                 AtkCoordType coord_type)
1000 {
1001   GtkWidget *widget;
1002   GtkImage  *button_image;
1003   AtkObject *obj;
1004
1005   widget = GTK_ACCESSIBLE (image)->widget;
1006
1007   if (widget == NULL)
1008     {
1009     /*
1010      * State is defunct
1011      */
1012       *x = G_MININT;
1013       *y = G_MININT;
1014       return;
1015     }
1016
1017   button_image = get_image_from_button (widget);
1018
1019   if (button_image != NULL)
1020     {
1021       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1022       atk_component_get_position (ATK_COMPONENT (obj), x, y, coord_type); 
1023     }
1024   else
1025     {
1026       *x = G_MININT;
1027       *y = G_MININT;
1028     }
1029 }
1030
1031 static void
1032 gail_button_get_image_size (AtkImage *image,
1033                             gint     *width,
1034                             gint     *height)
1035 {
1036   GtkWidget *widget;
1037   GtkImage  *button_image;
1038   AtkObject *obj;
1039
1040   widget = GTK_ACCESSIBLE (image)->widget;
1041
1042   if (widget == NULL)
1043     {
1044     /*
1045      * State is defunct
1046      */
1047       *width = -1;
1048       *height = -1;
1049       return;
1050     }
1051
1052   button_image = get_image_from_button (widget);
1053
1054   if (button_image != NULL)
1055     {
1056       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1057       atk_image_get_image_size (ATK_IMAGE (obj), width, height); 
1058     }
1059   else
1060     {
1061       *width = -1;
1062       *height = -1;
1063     }
1064 }
1065
1066 static gboolean
1067 gail_button_set_image_description (AtkImage    *image,
1068                                    const gchar *description)
1069 {
1070   GtkWidget *widget;
1071   GtkImage  *button_image;
1072   AtkObject *obj;
1073
1074   widget = GTK_ACCESSIBLE (image)->widget;
1075
1076   if (widget == NULL)
1077     /*
1078      * State is defunct
1079      */
1080     return FALSE;
1081
1082   button_image = get_image_from_button (widget);
1083
1084   if (button_image != NULL) 
1085     {
1086       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1087       return atk_image_set_image_description (ATK_IMAGE (obj), description);
1088     }
1089   else 
1090     return FALSE;
1091 }
1092
1093 /* atktext.h */
1094
1095 static void
1096 atk_text_interface_init (AtkTextIface *iface)
1097 {
1098   iface->get_text = gail_button_get_text;
1099   iface->get_character_at_offset = gail_button_get_character_at_offset;
1100   iface->get_text_before_offset = gail_button_get_text_before_offset;
1101   iface->get_text_at_offset = gail_button_get_text_at_offset;
1102   iface->get_text_after_offset = gail_button_get_text_after_offset;
1103   iface->get_character_count = gail_button_get_character_count;
1104   iface->get_character_extents = gail_button_get_character_extents;
1105   iface->get_offset_at_point = gail_button_get_offset_at_point;
1106   iface->get_run_attributes = gail_button_get_run_attributes;
1107   iface->get_default_attributes = gail_button_get_default_attributes;
1108 }
1109
1110 static gchar*
1111 gail_button_get_text (AtkText *text,
1112                       gint    start_pos,
1113                       gint    end_pos)
1114 {
1115   GtkWidget *widget;
1116   GtkWidget  *label;
1117   GailButton *button;
1118   const gchar *label_text;
1119
1120   widget = GTK_ACCESSIBLE (text)->widget;
1121   if (widget == NULL)
1122     /* State is defunct */
1123     return NULL;
1124
1125   label = get_label_from_button (widget, 0, FALSE);
1126
1127   if (!GTK_IS_LABEL (label))
1128     return NULL;
1129
1130   button = GAIL_BUTTON (text);
1131   if (!button->textutil) 
1132     gail_button_init_textutil (button, label);
1133
1134   label_text = gtk_label_get_text (GTK_LABEL (label));
1135
1136   if (label_text == NULL)
1137     return NULL;
1138   else
1139   {
1140     return gail_text_util_get_substring (button->textutil, 
1141                                          start_pos, end_pos);
1142   }
1143 }
1144
1145 static gchar*
1146 gail_button_get_text_before_offset (AtkText         *text,
1147                                     gint            offset,
1148                                     AtkTextBoundary boundary_type,
1149                                     gint            *start_offset,
1150                                     gint            *end_offset)
1151 {
1152   GtkWidget *widget;
1153   GtkWidget *label;
1154   GailButton *button;
1155   
1156   widget = GTK_ACCESSIBLE (text)->widget;
1157   
1158   if (widget == NULL)
1159     /* State is defunct */
1160     return NULL;
1161   
1162   /* Get label */
1163   label = get_label_from_button (widget, 0, FALSE);
1164
1165   if (!GTK_IS_LABEL(label))
1166     return NULL;
1167
1168   button = GAIL_BUTTON (text);
1169   if (!button->textutil)
1170     gail_button_init_textutil (button, label);
1171
1172   return gail_text_util_get_text (button->textutil,
1173                            gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
1174                            boundary_type, offset, start_offset, end_offset); 
1175 }
1176
1177 static gchar*
1178 gail_button_get_text_at_offset (AtkText         *text,
1179                                 gint            offset,
1180                                 AtkTextBoundary boundary_type,
1181                                 gint            *start_offset,
1182                                 gint            *end_offset)
1183 {
1184   GtkWidget *widget;
1185   GtkWidget *label;
1186   GailButton *button;
1187  
1188   widget = GTK_ACCESSIBLE (text)->widget;
1189   
1190   if (widget == NULL)
1191     /* State is defunct */
1192     return NULL;
1193   
1194   /* Get label */
1195   label = get_label_from_button (widget, 0, FALSE);
1196
1197   if (!GTK_IS_LABEL(label))
1198     return NULL;
1199
1200   button = GAIL_BUTTON (text);
1201   if (!button->textutil)
1202     gail_button_init_textutil (button, label);
1203
1204   return gail_text_util_get_text (button->textutil,
1205                               gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
1206                               boundary_type, offset, start_offset, end_offset);
1207 }
1208
1209 static gchar*
1210 gail_button_get_text_after_offset (AtkText         *text,
1211                                    gint            offset,
1212                                    AtkTextBoundary boundary_type,
1213                                    gint            *start_offset,
1214                                    gint            *end_offset)
1215 {
1216   GtkWidget *widget;
1217   GtkWidget *label;
1218   GailButton *button;
1219
1220   widget = GTK_ACCESSIBLE (text)->widget;
1221   
1222   if (widget == NULL)
1223   {
1224     /* State is defunct */
1225     return NULL;
1226   }
1227   
1228   /* Get label */
1229   label = get_label_from_button (widget, 0, FALSE);
1230
1231   if (!GTK_IS_LABEL(label))
1232     return NULL;
1233
1234   button = GAIL_BUTTON (text);
1235   if (!button->textutil)
1236     gail_button_init_textutil (button, label);
1237
1238   return gail_text_util_get_text (button->textutil,
1239                            gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
1240                            boundary_type, offset, start_offset, end_offset);
1241 }
1242
1243 static gint
1244 gail_button_get_character_count (AtkText *text)
1245 {
1246   GtkWidget *widget;
1247   GtkWidget *label;
1248
1249   widget = GTK_ACCESSIBLE (text)->widget;
1250   if (widget == NULL)
1251     /* State is defunct */
1252     return 0;
1253
1254   label = get_label_from_button (widget, 0, FALSE);
1255
1256   if (!GTK_IS_LABEL(label))
1257     return 0;
1258
1259   return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
1260 }
1261
1262 static void
1263 gail_button_get_character_extents (AtkText      *text,
1264                                    gint         offset,
1265                                    gint         *x,
1266                                    gint         *y,
1267                                    gint         *width,
1268                                    gint         *height,
1269                                    AtkCoordType coords)
1270 {
1271   GtkWidget *widget;
1272   GtkWidget *label;
1273   PangoRectangle char_rect;
1274   gint index, x_layout, y_layout;
1275   const gchar *label_text;
1276  
1277   widget = GTK_ACCESSIBLE (text)->widget;
1278
1279   if (widget == NULL)
1280     /* State is defunct */
1281     return;
1282
1283   label = get_label_from_button (widget, 0, FALSE);
1284
1285   if (!GTK_IS_LABEL(label))
1286     return;
1287   
1288   gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
1289   label_text = gtk_label_get_text (GTK_LABEL (label));
1290   index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
1291   pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
1292   
1293   gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
1294                     x_layout, y_layout, x, y, width, height, coords);
1295
1296
1297 static gint 
1298 gail_button_get_offset_at_point (AtkText      *text,
1299                                  gint         x,
1300                                  gint         y,
1301                                  AtkCoordType coords)
1302
1303   GtkWidget *widget;
1304   GtkWidget *label;
1305   gint index, x_layout, y_layout;
1306   const gchar *label_text;
1307
1308   widget = GTK_ACCESSIBLE (text)->widget;
1309   if (widget == NULL)
1310     /* State is defunct */
1311     return -1;
1312   label = get_label_from_button (widget, 0, FALSE);
1313
1314   if (!GTK_IS_LABEL(label))
1315     return -1;
1316   
1317   gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
1318   
1319   index = gail_misc_get_index_at_point_in_layout (label, 
1320                                               gtk_label_get_layout (GTK_LABEL (label)), 
1321                                               x_layout, y_layout, x, y, coords);
1322   label_text = gtk_label_get_text (GTK_LABEL (label));
1323   if (index == -1)
1324     {
1325       if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
1326         return g_utf8_strlen (label_text, -1);
1327
1328       return index;  
1329     }
1330   else
1331     return g_utf8_pointer_to_offset (label_text, label_text + index);  
1332 }
1333
1334 static AtkAttributeSet*
1335 gail_button_get_run_attributes (AtkText        *text,
1336                                 gint          offset,
1337                                 gint          *start_offset,
1338                                 gint          *end_offset)
1339 {
1340   GtkWidget *widget;
1341   GtkWidget *label;
1342   AtkAttributeSet *at_set = NULL;
1343   GtkJustification justify;
1344   GtkTextDirection dir;
1345
1346   widget = GTK_ACCESSIBLE (text)->widget;
1347   if (widget == NULL)
1348     /* State is defunct */
1349     return NULL;
1350
1351   label = get_label_from_button (widget, 0, FALSE);
1352
1353   if (!GTK_IS_LABEL(label))
1354     return NULL;
1355   
1356   /* Get values set for entire label, if any */
1357   justify = gtk_label_get_justify (GTK_LABEL (label));
1358   if (justify != GTK_JUSTIFY_CENTER)
1359     {
1360       at_set = gail_misc_add_attribute (at_set, 
1361                                         ATK_TEXT_ATTR_JUSTIFICATION,
1362      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
1363     }
1364   dir = gtk_widget_get_direction (label);
1365   if (dir == GTK_TEXT_DIR_RTL)
1366     {
1367       at_set = gail_misc_add_attribute (at_set, 
1368                                         ATK_TEXT_ATTR_DIRECTION,
1369      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
1370     }
1371
1372   at_set = gail_misc_layout_get_run_attributes (at_set,
1373                                                 gtk_label_get_layout (GTK_LABEL (label)),
1374                                                 (gchar *) gtk_label_get_text (GTK_LABEL (label)),
1375                                                 offset,
1376                                                 start_offset,
1377                                                 end_offset);
1378   return at_set;
1379 }
1380
1381 static AtkAttributeSet*
1382 gail_button_get_default_attributes (AtkText        *text)
1383 {
1384   GtkWidget *widget;
1385   GtkWidget *label;
1386   AtkAttributeSet *at_set = NULL;
1387
1388   widget = GTK_ACCESSIBLE (text)->widget;
1389   if (widget == NULL)
1390     /* State is defunct */
1391     return NULL;
1392
1393   label = get_label_from_button (widget, 0, FALSE);
1394
1395   if (!GTK_IS_LABEL(label))
1396     return NULL;
1397
1398   at_set = gail_misc_get_default_attributes (at_set,
1399                                              gtk_label_get_layout (GTK_LABEL (label)),
1400                                              widget);
1401   return at_set;
1402 }
1403
1404 static gunichar 
1405 gail_button_get_character_at_offset (AtkText             *text,
1406                                      gint                offset)
1407 {
1408   GtkWidget *widget;
1409   GtkWidget *label;
1410   const gchar *string;
1411   gchar *index;
1412
1413   widget = GTK_ACCESSIBLE (text)->widget;
1414   if (widget == NULL)
1415     /* State is defunct */
1416     return '\0';
1417
1418   label = get_label_from_button (widget, 0, FALSE);
1419
1420   if (!GTK_IS_LABEL(label))
1421     return '\0';
1422   string = gtk_label_get_text (GTK_LABEL (label));
1423   if (offset >= g_utf8_strlen (string, -1))
1424     return '\0';
1425   index = g_utf8_offset_to_pointer (string, offset);
1426
1427   return g_utf8_get_char (index);
1428 }
1429
1430 static void
1431 gail_button_finalize (GObject            *object)
1432 {
1433   GailButton *button = GAIL_BUTTON (object);
1434
1435   g_free (button->click_description);
1436   g_free (button->press_description);
1437   g_free (button->release_description);
1438   g_free (button->click_keybinding);
1439   if (button->action_idle_handler)
1440     {
1441       g_source_remove (button->action_idle_handler);
1442       button->action_idle_handler = 0;
1443     }
1444   if (button->action_queue)
1445     {
1446       g_queue_free (button->action_queue);
1447     }
1448   if (button->textutil)
1449     {
1450       g_object_unref (button->textutil);
1451     }
1452   G_OBJECT_CLASS (gail_button_parent_class)->finalize (object);
1453 }
1454
1455 static GtkWidget*
1456 find_label_child (GtkContainer *container,
1457                   gint         *index,
1458                   gboolean     allow_many)
1459 {
1460   GList *children, *tmp_list;
1461   GtkWidget *child;
1462  
1463   children = gtk_container_get_children (container);
1464
1465   child = NULL;
1466   for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next) 
1467     {
1468       if (GTK_IS_LABEL (tmp_list->data))
1469         {
1470           if (!allow_many)
1471             {
1472               if (child)
1473                 {
1474                   child = NULL;
1475                   break;
1476                 }
1477               child = GTK_WIDGET (tmp_list->data);
1478             }
1479           else
1480             {
1481               if (*index == 0)
1482                 {
1483                   child = GTK_WIDGET (tmp_list->data);
1484                   break;
1485                 }
1486               (*index)--;
1487             }
1488         }
1489        /*
1490         * Label for button which are GtkTreeView column headers are in a 
1491         * GtkHBox in a GtkAlignment.
1492         */
1493       else if (GTK_IS_ALIGNMENT (tmp_list->data))
1494         {
1495           GtkWidget *widget;
1496
1497           widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
1498           if (GTK_IS_LABEL (widget))
1499             {
1500               if (!allow_many)
1501                 {
1502                   if (child)
1503                     {
1504                       child = NULL;
1505                       break;
1506                     }
1507                   child = widget;
1508                 }
1509               else
1510                 {
1511                   if (*index == 0)
1512                     {
1513                       child = widget;
1514                       break;
1515                     }
1516                   (*index)--;
1517                 }
1518             }
1519         }
1520       else if (GTK_IS_CONTAINER (tmp_list->data))
1521         {
1522           child = find_label_child (GTK_CONTAINER (tmp_list->data), index, allow_many);
1523           if (child)
1524             break;
1525         } 
1526     }
1527   g_list_free (children);
1528   return child;
1529 }
1530
1531 static GtkWidget*
1532 get_label_from_button (GtkWidget *button,
1533                        gint      index,
1534                        gboolean  allow_many)
1535 {
1536   GtkWidget *child;
1537
1538   if (index > 0 && !allow_many)
1539     g_warning ("Inconsistent values passed to get_label_from_button");
1540
1541   child = gtk_bin_get_child (GTK_BIN (button));
1542   if (GTK_IS_ALIGNMENT (child))
1543     child = gtk_bin_get_child (GTK_BIN (child));
1544
1545   if (GTK_IS_CONTAINER (child))
1546     child = find_label_child (GTK_CONTAINER (child), &index, allow_many);
1547   else if (!GTK_IS_LABEL (child))
1548     child = NULL;
1549
1550   return child;
1551 }
1552
1553 static void
1554 count_labels (GtkContainer *container,
1555               gint         *n_labels)
1556 {
1557   GList *children, *tmp_list;
1558  
1559   children = gtk_container_get_children (container);
1560
1561   for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next) 
1562     {
1563       if (GTK_IS_LABEL (tmp_list->data))
1564         {
1565           (*n_labels)++;
1566         }
1567        /*
1568         * Label for button which are GtkTreeView column headers are in a 
1569         * GtkHBox in a GtkAlignment.
1570         */
1571       else if (GTK_IS_ALIGNMENT (tmp_list->data))
1572         {
1573           GtkWidget *widget;
1574
1575           widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
1576           if (GTK_IS_LABEL (widget))
1577             (*n_labels)++;
1578         }
1579       else if (GTK_IS_CONTAINER (tmp_list->data))
1580         {
1581           count_labels (GTK_CONTAINER (tmp_list->data), n_labels);
1582         } 
1583     }
1584   g_list_free (children);
1585 }
1586
1587 static gint
1588 get_n_labels_from_button (GtkWidget *button)
1589 {
1590   GtkWidget *child;
1591   gint n_labels;
1592
1593   n_labels = 0;
1594
1595   child = gtk_bin_get_child (GTK_BIN (button));
1596   if (GTK_IS_ALIGNMENT (child))
1597     child = gtk_bin_get_child (GTK_BIN (child));
1598
1599   if (GTK_IS_CONTAINER (child))
1600     count_labels (GTK_CONTAINER (child), &n_labels);
1601
1602   return n_labels;
1603 }
1604
1605 static void
1606 set_role_for_button (AtkObject *accessible,
1607                      GtkWidget *button)
1608 {
1609   GtkWidget *parent;
1610   AtkRole role;
1611
1612   parent = gtk_widget_get_parent (button);
1613   if (GTK_IS_TREE_VIEW (parent))
1614     {
1615       role = ATK_ROLE_TABLE_COLUMN_HEADER;
1616       /*
1617        * Even though the accessible parent of the column header will
1618        * be reported as the table because the parent widget of the
1619        * GtkTreeViewColumn's button is the GtkTreeView we set
1620        * the accessible parent for column header to be the table
1621        * to ensure that atk_object_get_index_in_parent() returns
1622        * the correct value; see gail_widget_get_index_in_parent().
1623        */
1624       atk_object_set_parent (accessible, gtk_widget_get_accessible (parent));
1625     }
1626   else
1627     role = ATK_ROLE_PUSH_BUTTON;
1628
1629   accessible->role =  role;
1630 }
1631
1632 static gint
1633 get_n_attached_menus (GtkWidget  *widget)
1634 {
1635   GList *list_menus;
1636   
1637   if (widget == NULL)
1638     return 0;
1639
1640   list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
1641   if (list_menus == NULL)
1642     return 0;
1643
1644   return g_list_length (list_menus);
1645 }
1646
1647 static GtkWidget*
1648 get_nth_attached_menu (GtkWidget  *widget,
1649                        gint       index)
1650 {
1651   GtkWidget *attached_menu;
1652   GList *list_menus;
1653
1654   if (widget == NULL)
1655     return NULL;
1656
1657   list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
1658   if (list_menus == NULL ||
1659       index >= g_list_length (list_menus))
1660     return NULL;
1661
1662   attached_menu = (GtkWidget *) g_list_nth_data (list_menus, index);
1663
1664   return attached_menu;
1665 }