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