]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
Don't use GTK_WIDGET_STATE in internal code anymore
[~andy/gtk] / gtk / gtkbutton.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 /*
21  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <string.h>
29 #include "gtkalignment.h"
30 #include "gtkbutton.h"
31 #include "gtklabel.h"
32 #include "gtkmain.h"
33 #include "gtkmarshalers.h"
34 #include "gtkimage.h"
35 #include "gtkhbox.h"
36 #include "gtkvbox.h"
37 #include "gtkstock.h"
38 #include "gtkiconfactory.h"
39 #include "gtkactivatable.h"
40 #include "gtkprivate.h"
41 #include "gtkintl.h"
42 #include "gtkalias.h"
43
44 static const GtkBorder default_default_border = { 1, 1, 1, 1 };
45 static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
46 static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
47
48 /* Time out before giving up on getting a key release when animating
49  * the close button.
50  */
51 #define ACTIVATE_TIMEOUT 250
52
53 enum {
54   PRESSED,
55   RELEASED,
56   CLICKED,
57   ENTER,
58   LEAVE,
59   ACTIVATE,
60   LAST_SIGNAL
61 };
62
63 enum {
64   PROP_0,
65   PROP_LABEL,
66   PROP_IMAGE,
67   PROP_RELIEF,
68   PROP_USE_UNDERLINE,
69   PROP_USE_STOCK,
70   PROP_FOCUS_ON_CLICK,
71   PROP_XALIGN,
72   PROP_YALIGN,
73   PROP_IMAGE_POSITION,
74
75   /* activatable properties */
76   PROP_ACTIVATABLE_RELATED_ACTION,
77   PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
78 };
79
80 #define GTK_BUTTON_GET_PRIVATE(o)       (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_BUTTON, GtkButtonPrivate))
81 typedef struct _GtkButtonPrivate GtkButtonPrivate;
82
83 struct _GtkButtonPrivate
84 {
85   gfloat          xalign;
86   gfloat          yalign;
87   GtkWidget      *image;
88   guint           align_set             : 1;
89   guint           image_is_stock        : 1;
90   guint           has_grab              : 1;
91   guint           use_action_appearance : 1;
92   guint32         grab_time;
93   GtkPositionType image_position;
94   GtkAction      *action;
95 };
96
97 static void gtk_button_destroy        (GtkObject          *object);
98 static void gtk_button_dispose        (GObject            *object);
99 static void gtk_button_set_property   (GObject            *object,
100                                        guint               prop_id,
101                                        const GValue       *value,
102                                        GParamSpec         *pspec);
103 static void gtk_button_get_property   (GObject            *object,
104                                        guint               prop_id,
105                                        GValue             *value,
106                                        GParamSpec         *pspec);
107 static void gtk_button_screen_changed (GtkWidget          *widget,
108                                        GdkScreen          *previous_screen);
109 static void gtk_button_realize (GtkWidget * widget);
110 static void gtk_button_unrealize (GtkWidget * widget);
111 static void gtk_button_map (GtkWidget * widget);
112 static void gtk_button_unmap (GtkWidget * widget);
113 static void gtk_button_style_set (GtkWidget * widget, GtkStyle * prev_style);
114 static void gtk_button_size_request (GtkWidget * widget,
115                                      GtkRequisition * requisition);
116 static void gtk_button_size_allocate (GtkWidget * widget,
117                                       GtkAllocation * allocation);
118 static gint gtk_button_expose (GtkWidget * widget, GdkEventExpose * event);
119 static gint gtk_button_button_press (GtkWidget * widget,
120                                      GdkEventButton * event);
121 static gint gtk_button_button_release (GtkWidget * widget,
122                                        GdkEventButton * event);
123 static gint gtk_button_grab_broken (GtkWidget * widget,
124                                     GdkEventGrabBroken * event);
125 static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
126 static gint gtk_button_enter_notify (GtkWidget * widget,
127                                      GdkEventCrossing * event);
128 static gint gtk_button_leave_notify (GtkWidget * widget,
129                                      GdkEventCrossing * event);
130 static void gtk_real_button_pressed (GtkButton * button);
131 static void gtk_real_button_released (GtkButton * button);
132 static void gtk_real_button_clicked (GtkButton * button);
133 static void gtk_real_button_activate  (GtkButton          *button);
134 static void gtk_button_update_state   (GtkButton          *button);
135 static void gtk_button_add            (GtkContainer       *container,
136                                        GtkWidget          *widget);
137 static GType gtk_button_child_type    (GtkContainer       *container);
138 static void gtk_button_finish_activate (GtkButton         *button,
139                                         gboolean           do_it);
140
141 static GObject* gtk_button_constructor (GType                  type,
142                                         guint                  n_construct_properties,
143                                         GObjectConstructParam *construct_params);
144 static void gtk_button_construct_child (GtkButton             *button);
145 static void gtk_button_state_changed   (GtkWidget             *widget,
146                                         GtkStateType           previous_state);
147 static void gtk_button_grab_notify     (GtkWidget             *widget,
148                                         gboolean               was_grabbed);
149
150
151 static void gtk_button_activatable_interface_init         (GtkActivatableIface  *iface);
152 static void gtk_button_update                    (GtkActivatable       *activatable,
153                                                   GtkAction            *action,
154                                                   const gchar          *property_name);
155 static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
156                                                   GtkAction            *action);
157 static void gtk_button_set_related_action        (GtkButton            *button,
158                                                   GtkAction            *action);
159 static void gtk_button_set_use_action_appearance (GtkButton            *button,
160                                                   gboolean              use_appearance);
161
162 static guint button_signals[LAST_SIGNAL] = { 0 };
163
164 G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
165                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
166                                                 gtk_button_activatable_interface_init))
167
168 static void
169 gtk_button_class_init (GtkButtonClass *klass)
170 {
171   GObjectClass *gobject_class;
172   GtkObjectClass *object_class;
173   GtkWidgetClass *widget_class;
174   GtkContainerClass *container_class;
175
176   gobject_class = G_OBJECT_CLASS (klass);
177   object_class = (GtkObjectClass*) klass;
178   widget_class = (GtkWidgetClass*) klass;
179   container_class = (GtkContainerClass*) klass;
180   
181   gobject_class->constructor  = gtk_button_constructor;
182   gobject_class->dispose      = gtk_button_dispose;
183   gobject_class->set_property = gtk_button_set_property;
184   gobject_class->get_property = gtk_button_get_property;
185
186   object_class->destroy = gtk_button_destroy;
187
188   widget_class->screen_changed = gtk_button_screen_changed;
189   widget_class->realize = gtk_button_realize;
190   widget_class->unrealize = gtk_button_unrealize;
191   widget_class->map = gtk_button_map;
192   widget_class->unmap = gtk_button_unmap;
193   widget_class->style_set = gtk_button_style_set;
194   widget_class->size_request = gtk_button_size_request;
195   widget_class->size_allocate = gtk_button_size_allocate;
196   widget_class->expose_event = gtk_button_expose;
197   widget_class->button_press_event = gtk_button_button_press;
198   widget_class->button_release_event = gtk_button_button_release;
199   widget_class->grab_broken_event = gtk_button_grab_broken;
200   widget_class->key_release_event = gtk_button_key_release;
201   widget_class->enter_notify_event = gtk_button_enter_notify;
202   widget_class->leave_notify_event = gtk_button_leave_notify;
203   widget_class->state_changed = gtk_button_state_changed;
204   widget_class->grab_notify = gtk_button_grab_notify;
205
206   container_class->child_type = gtk_button_child_type;
207   container_class->add = gtk_button_add;
208
209   klass->pressed = gtk_real_button_pressed;
210   klass->released = gtk_real_button_released;
211   klass->clicked = NULL;
212   klass->enter = gtk_button_update_state;
213   klass->leave = gtk_button_update_state;
214   klass->activate = gtk_real_button_activate;
215
216   g_object_class_install_property (gobject_class,
217                                    PROP_LABEL,
218                                    g_param_spec_string ("label",
219                                                         P_("Label"),
220                                                         P_("Text of the label widget inside the button, if the button contains a label widget"),
221                                                         NULL,
222                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
223   
224   g_object_class_install_property (gobject_class,
225                                    PROP_USE_UNDERLINE,
226                                    g_param_spec_boolean ("use-underline",
227                                                          P_("Use underline"),
228                                                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
229                                                         FALSE,
230                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
231   
232   g_object_class_install_property (gobject_class,
233                                    PROP_USE_STOCK,
234                                    g_param_spec_boolean ("use-stock",
235                                                          P_("Use stock"),
236                                                          P_("If set, the label is used to pick a stock item instead of being displayed"),
237                                                         FALSE,
238                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
239   
240   g_object_class_install_property (gobject_class,
241                                    PROP_FOCUS_ON_CLICK,
242                                    g_param_spec_boolean ("focus-on-click",
243                                                          P_("Focus on click"),
244                                                          P_("Whether the button grabs focus when it is clicked with the mouse"),
245                                                          TRUE,
246                                                          GTK_PARAM_READWRITE));
247   
248   g_object_class_install_property (gobject_class,
249                                    PROP_RELIEF,
250                                    g_param_spec_enum ("relief",
251                                                       P_("Border relief"),
252                                                       P_("The border relief style"),
253                                                       GTK_TYPE_RELIEF_STYLE,
254                                                       GTK_RELIEF_NORMAL,
255                                                       GTK_PARAM_READWRITE));
256   
257   /**
258    * GtkButton:xalign:
259    *
260    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
261    * can be used to control it's horizontal alignment. 0.0 is left aligned, 
262    * 1.0 is right aligned.
263    * 
264    * Since: 2.4
265    */
266   g_object_class_install_property (gobject_class,
267                                    PROP_XALIGN,
268                                    g_param_spec_float("xalign",
269                                                       P_("Horizontal alignment for child"),
270                                                       P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
271                                                       0.0,
272                                                       1.0,
273                                                       0.5,
274                                                       GTK_PARAM_READWRITE));
275
276   /**
277    * GtkButton:yalign:
278    *
279    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
280    * can be used to control it's vertical alignment. 0.0 is top aligned, 
281    * 1.0 is bottom aligned.
282    * 
283    * Since: 2.4
284    */
285   g_object_class_install_property (gobject_class,
286                                    PROP_YALIGN,
287                                    g_param_spec_float("yalign",
288                                                       P_("Vertical alignment for child"),
289                                                       P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
290                                                       0.0,
291                                                       1.0,
292                                                       0.5,
293                                                       GTK_PARAM_READWRITE));
294
295   /**
296    * GtkButton::image:
297    * 
298    * The child widget to appear next to the button text.
299    * 
300    * Since: 2.6
301    */
302   g_object_class_install_property (gobject_class,
303                                    PROP_IMAGE,
304                                    g_param_spec_object ("image",
305                                                         P_("Image widget"),
306                                                         P_("Child widget to appear next to the button text"),
307                                                         GTK_TYPE_WIDGET,
308                                                         GTK_PARAM_READWRITE));
309
310   /**
311    * GtkButton:image-position:
312    *
313    * The position of the image relative to the text inside the button.
314    * 
315    * Since: 2.10
316    */
317   g_object_class_install_property (gobject_class,
318                                    PROP_IMAGE_POSITION,
319                                    g_param_spec_enum ("image-position",
320                                             P_("Image position"),
321                                                       P_("The position of the image relative to the text"),
322                                                       GTK_TYPE_POSITION_TYPE,
323                                                       GTK_POS_LEFT,
324                                                       GTK_PARAM_READWRITE));
325
326   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
327   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
328
329   /**
330    * GtkButton::pressed:
331    * @button: the object that received the signal
332    *
333    * Emitted when the button is pressed.
334    * 
335    * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
336    */ 
337   button_signals[PRESSED] =
338     g_signal_new (I_("pressed"),
339                   G_OBJECT_CLASS_TYPE (object_class),
340                   G_SIGNAL_RUN_FIRST,
341                   G_STRUCT_OFFSET (GtkButtonClass, pressed),
342                   NULL, NULL,
343                   _gtk_marshal_VOID__VOID,
344                   G_TYPE_NONE, 0);
345
346   /**
347    * GtkButton::released:
348    * @button: the object that received the signal
349    *
350    * Emitted when the button is released.
351    * 
352    * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
353    */ 
354   button_signals[RELEASED] =
355     g_signal_new (I_("released"),
356                   G_OBJECT_CLASS_TYPE (object_class),
357                   G_SIGNAL_RUN_FIRST,
358                   G_STRUCT_OFFSET (GtkButtonClass, released),
359                   NULL, NULL,
360                   _gtk_marshal_VOID__VOID,
361                   G_TYPE_NONE, 0);
362
363   /**
364    * GtkButton::clicked:
365    * @button: the object that received the signal
366    *
367    * Emitted when the button has been activated (pressed and released).
368    */ 
369   button_signals[CLICKED] =
370     g_signal_new (I_("clicked"),
371                   G_OBJECT_CLASS_TYPE (object_class),
372                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
373                   G_STRUCT_OFFSET (GtkButtonClass, clicked),
374                   NULL, NULL,
375                   _gtk_marshal_VOID__VOID,
376                   G_TYPE_NONE, 0);
377
378   /**
379    * GtkButton::enter:
380    * @button: the object that received the signal
381    *
382    * Emitted when the pointer enters the button.
383    * 
384    * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
385    */ 
386   button_signals[ENTER] =
387     g_signal_new (I_("enter"),
388                   G_OBJECT_CLASS_TYPE (object_class),
389                   G_SIGNAL_RUN_FIRST,
390                   G_STRUCT_OFFSET (GtkButtonClass, enter),
391                   NULL, NULL,
392                   _gtk_marshal_VOID__VOID,
393                   G_TYPE_NONE, 0);
394
395   /**
396    * GtkButton::leave:
397    * @button: the object that received the signal
398    *
399    * Emitted when the pointer leaves the button.
400    * 
401    * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
402    */ 
403   button_signals[LEAVE] =
404     g_signal_new (I_("leave"),
405                   G_OBJECT_CLASS_TYPE (object_class),
406                   G_SIGNAL_RUN_FIRST,
407                   G_STRUCT_OFFSET (GtkButtonClass, leave),
408                   NULL, NULL,
409                   _gtk_marshal_VOID__VOID,
410                   G_TYPE_NONE, 0);
411
412   /**
413    * GtkButton::activate:
414    * @widget: the object which received the signal.
415    *
416    * The ::activate signal on GtkButton is an action signal and
417    * emitting it causes the button to animate press then release. 
418    * Applications should never connect to this signal, but use the
419    * #GtkButton::clicked signal.
420    */
421   button_signals[ACTIVATE] =
422     g_signal_new (I_("activate"),
423                   G_OBJECT_CLASS_TYPE (object_class),
424                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
425                   G_STRUCT_OFFSET (GtkButtonClass, activate),
426                   NULL, NULL,
427                   _gtk_marshal_VOID__VOID,
428                   G_TYPE_NONE, 0);
429   widget_class->activate_signal = button_signals[ACTIVATE];
430
431   /**
432    * GtkButton:default-border:
433    *
434    * The "default-border" style property defines the extra space to add
435    * around a button that can become the default widget of its window.
436    * For more information about default widgets, see gtk_widget_grab_default().
437    */
438
439   gtk_widget_class_install_style_property (widget_class,
440                                            g_param_spec_boxed ("default-border",
441                                                                P_("Default Spacing"),
442                                                                P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
443                                                                GTK_TYPE_BORDER,
444                                                                GTK_PARAM_READABLE));
445
446   /**
447    * GtkButton:default-outside-border:
448    *
449    * The "default-outside-border" style property defines the extra outside
450    * space to add around a button that can become the default widget of its
451    * window. Extra outside space is always drawn outside the button border.
452    * For more information about default widgets, see gtk_widget_grab_default().
453    */
454   gtk_widget_class_install_style_property (widget_class,
455                                            g_param_spec_boxed ("default-outside-border",
456                                                                P_("Default Outside Spacing"),
457                                                                P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
458                                                                GTK_TYPE_BORDER,
459                                                                GTK_PARAM_READABLE));
460   gtk_widget_class_install_style_property (widget_class,
461                                            g_param_spec_int ("child-displacement-x",
462                                                              P_("Child X Displacement"),
463                                                              P_("How far in the x direction to move the child when the button is depressed"),
464                                                              G_MININT,
465                                                              G_MAXINT,
466                                                              0,
467                                                              GTK_PARAM_READABLE));
468   gtk_widget_class_install_style_property (widget_class,
469                                            g_param_spec_int ("child-displacement-y",
470                                                              P_("Child Y Displacement"),
471                                                              P_("How far in the y direction to move the child when the button is depressed"),
472                                                              G_MININT,
473                                                              G_MAXINT,
474                                                              0,
475                                                              GTK_PARAM_READABLE));
476
477   /**
478    * GtkButton:displace-focus:
479    *
480    * Whether the child_displacement_x/child_displacement_y properties 
481    * should also affect the focus rectangle.
482    *
483    * Since: 2.6
484    */
485   gtk_widget_class_install_style_property (widget_class,
486                                            g_param_spec_boolean ("displace-focus",
487                                                                  P_("Displace focus"),
488                                                                  P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
489                                                                  FALSE,
490                                                                  GTK_PARAM_READABLE));
491
492   /**
493    * GtkButton:inner-border:
494    *
495    * Sets the border between the button edges and child.
496    *
497    * Since: 2.10
498    */
499   gtk_widget_class_install_style_property (widget_class,
500                                            g_param_spec_boxed ("inner-border",
501                                                                P_("Inner Border"),
502                                                                P_("Border between button edges and child."),
503                                                                GTK_TYPE_BORDER,
504                                                                GTK_PARAM_READABLE));
505
506   /**
507    * GtkButton::image-spacing:
508    * 
509    * Spacing in pixels between the image and label.
510    * 
511    * Since: 2.10
512    */
513   gtk_widget_class_install_style_property (widget_class,
514                                            g_param_spec_int ("image-spacing",
515                                                              P_("Image spacing"),
516                                                              P_("Spacing in pixels between the image and label"),
517                                                              0,
518                                                              G_MAXINT,
519                                                              2,
520                                                              GTK_PARAM_READABLE));
521
522   /**
523    * GtkSettings::gtk-button-images:
524    *
525    * Whether images should be shown on buttons
526    *
527    * Since: 2.4
528    */
529   gtk_settings_install_property (g_param_spec_boolean ("gtk-button-images",
530                                                        P_("Show button images"),
531                                                        P_("Whether images should be shown on buttons"),
532                                                        TRUE,
533                                                        GTK_PARAM_READWRITE));
534
535   g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
536 }
537
538 static void
539 gtk_button_init (GtkButton *button)
540 {
541   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
542
543   gtk_widget_set_can_focus (GTK_WIDGET (button), TRUE);
544   gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
545   gtk_widget_set_has_window (GTK_WIDGET (button), FALSE);
546
547   button->label_text = NULL;
548   
549   button->constructed = FALSE;
550   button->in_button = FALSE;
551   button->button_down = FALSE;
552   button->relief = GTK_RELIEF_NORMAL;
553   button->use_stock = FALSE;
554   button->use_underline = FALSE;
555   button->depressed = FALSE;
556   button->depress_on_activate = TRUE;
557   button->focus_on_click = TRUE;
558
559   priv->xalign = 0.5;
560   priv->yalign = 0.5;
561   priv->align_set = 0;
562   priv->image_is_stock = TRUE;
563   priv->image_position = GTK_POS_LEFT;
564   priv->use_action_appearance = TRUE;
565 }
566
567 static void
568 gtk_button_destroy (GtkObject *object)
569 {
570   GtkButton *button = GTK_BUTTON (object);
571   
572   if (button->label_text)
573     {
574       g_free (button->label_text);
575       button->label_text = NULL;
576     }
577
578   GTK_OBJECT_CLASS (gtk_button_parent_class)->destroy (object);
579 }
580
581 static GObject*
582 gtk_button_constructor (GType                  type,
583                         guint                  n_construct_properties,
584                         GObjectConstructParam *construct_params)
585 {
586   GObject *object;
587   GtkButton *button;
588
589   object = G_OBJECT_CLASS (gtk_button_parent_class)->constructor (type,
590                                                                   n_construct_properties,
591                                                                   construct_params);
592
593   button = GTK_BUTTON (object);
594   button->constructed = TRUE;
595
596   if (button->label_text != NULL)
597     gtk_button_construct_child (button);
598   
599   return object;
600 }
601
602
603 static GType
604 gtk_button_child_type  (GtkContainer     *container)
605 {
606   if (!GTK_BIN (container)->child)
607     return GTK_TYPE_WIDGET;
608   else
609     return G_TYPE_NONE;
610 }
611
612 static void
613 maybe_set_alignment (GtkButton *button,
614                      GtkWidget *widget)
615 {
616   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
617
618   if (GTK_IS_MISC (widget))
619     {
620       GtkMisc *misc = GTK_MISC (widget);
621       
622       if (priv->align_set)
623         gtk_misc_set_alignment (misc, priv->xalign, priv->yalign);
624     }
625   else if (GTK_IS_ALIGNMENT (widget))
626     {
627       GtkAlignment *alignment = GTK_ALIGNMENT (widget);
628
629       if (priv->align_set)
630         gtk_alignment_set (alignment, priv->xalign, priv->yalign, 
631                            alignment->xscale, alignment->yscale);
632     }
633 }
634
635 static void
636 gtk_button_add (GtkContainer *container,
637                 GtkWidget    *widget)
638 {
639   maybe_set_alignment (GTK_BUTTON (container), widget);
640
641   GTK_CONTAINER_CLASS (gtk_button_parent_class)->add (container, widget);
642 }
643
644 static void 
645 gtk_button_dispose (GObject *object)
646 {
647   GtkButton *button = GTK_BUTTON (object);
648   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
649
650   if (priv->action)
651     {
652       gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
653       priv->action = NULL;
654     }
655   G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
656 }
657
658 static void
659 gtk_button_set_property (GObject         *object,
660                          guint            prop_id,
661                          const GValue    *value,
662                          GParamSpec      *pspec)
663 {
664   GtkButton *button = GTK_BUTTON (object);
665   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
666
667   switch (prop_id)
668     {
669     case PROP_LABEL:
670       gtk_button_set_label (button, g_value_get_string (value));
671       break;
672     case PROP_IMAGE:
673       gtk_button_set_image (button, (GtkWidget *) g_value_get_object (value));
674       break;
675     case PROP_RELIEF:
676       gtk_button_set_relief (button, g_value_get_enum (value));
677       break;
678     case PROP_USE_UNDERLINE:
679       gtk_button_set_use_underline (button, g_value_get_boolean (value));
680       break;
681     case PROP_USE_STOCK:
682       gtk_button_set_use_stock (button, g_value_get_boolean (value));
683       break;
684     case PROP_FOCUS_ON_CLICK:
685       gtk_button_set_focus_on_click (button, g_value_get_boolean (value));
686       break;
687     case PROP_XALIGN:
688       gtk_button_set_alignment (button, g_value_get_float (value), priv->yalign);
689       break;
690     case PROP_YALIGN:
691       gtk_button_set_alignment (button, priv->xalign, g_value_get_float (value));
692       break;
693     case PROP_IMAGE_POSITION:
694       gtk_button_set_image_position (button, g_value_get_enum (value));
695       break;
696     case PROP_ACTIVATABLE_RELATED_ACTION:
697       gtk_button_set_related_action (button, g_value_get_object (value));
698       break;
699     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
700       gtk_button_set_use_action_appearance (button, g_value_get_boolean (value));
701       break;
702     default:
703       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
704       break;
705     }
706 }
707
708 static void
709 gtk_button_get_property (GObject         *object,
710                          guint            prop_id,
711                          GValue          *value,
712                          GParamSpec      *pspec)
713 {
714   GtkButton *button = GTK_BUTTON (object);
715   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
716
717   switch (prop_id)
718     {
719     case PROP_LABEL:
720       g_value_set_string (value, button->label_text);
721       break;
722     case PROP_IMAGE:
723       g_value_set_object (value, (GObject *)priv->image);
724       break;
725     case PROP_RELIEF:
726       g_value_set_enum (value, gtk_button_get_relief (button));
727       break;
728     case PROP_USE_UNDERLINE:
729       g_value_set_boolean (value, button->use_underline);
730       break;
731     case PROP_USE_STOCK:
732       g_value_set_boolean (value, button->use_stock);
733       break;
734     case PROP_FOCUS_ON_CLICK:
735       g_value_set_boolean (value, button->focus_on_click);
736       break;
737     case PROP_XALIGN:
738       g_value_set_float (value, priv->xalign);
739       break;
740     case PROP_YALIGN:
741       g_value_set_float (value, priv->yalign);
742       break;
743     case PROP_IMAGE_POSITION:
744       g_value_set_enum (value, priv->image_position);
745       break;
746     case PROP_ACTIVATABLE_RELATED_ACTION:
747       g_value_set_object (value, priv->action);
748       break;
749     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
750       g_value_set_boolean (value, priv->use_action_appearance);
751       break;
752     default:
753       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
754       break;
755     }
756 }
757
758 static void 
759 gtk_button_activatable_interface_init (GtkActivatableIface  *iface)
760 {
761   iface->update = gtk_button_update;
762   iface->sync_action_properties = gtk_button_sync_action_properties;
763 }
764
765 static void
766 activatable_update_stock_id (GtkButton *button,
767                              GtkAction *action)
768 {
769   if (!gtk_button_get_use_stock (button))
770     return;
771
772   gtk_button_set_label (button, gtk_action_get_stock_id (action));
773 }
774
775 static void
776 activatable_update_short_label (GtkButton *button,
777                                 GtkAction *action)
778 {
779   GtkWidget *image;
780
781   if (gtk_button_get_use_stock (button))
782     return;
783
784   image = gtk_button_get_image (button);
785
786   /* Dont touch custom child... */
787   if (GTK_IS_IMAGE (image) ||
788       GTK_BIN (button)->child == NULL || 
789       GTK_IS_LABEL (GTK_BIN (button)->child))
790     {
791       gtk_button_set_label (button, gtk_action_get_short_label (action));
792       gtk_button_set_use_underline (button, TRUE);
793     }
794 }
795
796 static void
797 activatable_update_icon_name (GtkButton *button,
798                               GtkAction *action)
799 {
800   GtkWidget *image;
801               
802   if (gtk_button_get_use_stock (button))
803     return;
804
805   image = gtk_button_get_image (button);
806
807   if (GTK_IS_IMAGE (image) &&
808       (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
809        gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
810     gtk_image_set_from_icon_name (GTK_IMAGE (image),
811                                   gtk_action_get_icon_name (action), GTK_ICON_SIZE_MENU);
812 }
813
814 static void
815 activatable_update_gicon (GtkButton *button,
816                           GtkAction *action)
817 {
818   GtkWidget *image = gtk_button_get_image (button);
819   GIcon *icon = gtk_action_get_gicon (action);
820   
821   if (GTK_IS_IMAGE (image) &&
822       (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
823        gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_GICON))
824     gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_BUTTON);
825 }
826
827 static void 
828 gtk_button_update (GtkActivatable *activatable,
829                    GtkAction      *action,
830                    const gchar    *property_name)
831 {
832   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (activatable);
833
834   if (strcmp (property_name, "visible") == 0)
835     {
836       if (gtk_action_is_visible (action))
837         gtk_widget_show (GTK_WIDGET (activatable));
838       else
839         gtk_widget_hide (GTK_WIDGET (activatable));
840     }
841   else if (strcmp (property_name, "sensitive") == 0)
842     gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
843
844   if (!priv->use_action_appearance)
845     return;
846
847   if (strcmp (property_name, "stock-id") == 0)
848     activatable_update_stock_id (GTK_BUTTON (activatable), action);
849   else if (strcmp (property_name, "gicon") == 0)
850     activatable_update_gicon (GTK_BUTTON (activatable), action);
851   else if (strcmp (property_name, "short-label") == 0)
852     activatable_update_short_label (GTK_BUTTON (activatable), action);
853   else if (strcmp (property_name, "icon-name") == 0)
854     activatable_update_icon_name (GTK_BUTTON (activatable), action);
855 }
856
857 static void
858 gtk_button_sync_action_properties (GtkActivatable *activatable,
859                                    GtkAction      *action)
860 {
861   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (activatable);
862
863   if (!action)
864     return;
865
866   if (gtk_action_is_visible (action))
867     gtk_widget_show (GTK_WIDGET (activatable));
868   else
869     gtk_widget_hide (GTK_WIDGET (activatable));
870   
871   gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
872   
873   if (priv->use_action_appearance)
874     {
875       activatable_update_stock_id (GTK_BUTTON (activatable), action);
876       activatable_update_short_label (GTK_BUTTON (activatable), action);
877       activatable_update_gicon (GTK_BUTTON (activatable), action);
878       activatable_update_icon_name (GTK_BUTTON (activatable), action);
879     }
880 }
881
882 static void
883 gtk_button_set_related_action (GtkButton *button,
884                                GtkAction *action)
885 {
886   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
887
888   if (priv->action == action)
889     return;
890
891   /* This should be a default handler, but for compatibility reasons
892    * we need to support derived classes that don't chain up their
893    * clicked handler.
894    */
895   g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
896   if (action)
897     g_signal_connect_after (button, "clicked",
898                             G_CALLBACK (gtk_real_button_clicked), NULL);
899
900   gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action);
901
902   priv->action = action;
903 }
904
905 static void
906 gtk_button_set_use_action_appearance (GtkButton *button,
907                                       gboolean   use_appearance)
908 {
909   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
910
911   if (priv->use_action_appearance != use_appearance)
912     {
913       priv->use_action_appearance = use_appearance;
914
915       gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (button), priv->action);
916     }
917 }
918
919 GtkWidget*
920 gtk_button_new (void)
921 {
922   return g_object_new (GTK_TYPE_BUTTON, NULL);
923 }
924
925 static gboolean
926 show_image (GtkButton *button)
927 {
928   gboolean show;
929   
930   if (button->label_text)
931     {
932       GtkSettings *settings;
933
934       settings = gtk_widget_get_settings (GTK_WIDGET (button));        
935       g_object_get (settings, "gtk-button-images", &show, NULL);
936     }
937   else
938     show = TRUE;
939
940   return show;
941 }
942
943 static void
944 gtk_button_construct_child (GtkButton *button)
945 {
946   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
947   GtkStockItem item;
948   GtkWidget *label;
949   GtkWidget *box;
950   GtkWidget *align;
951   GtkWidget *image = NULL;
952   gchar *label_text = NULL;
953   gint image_spacing;
954
955   if (!button->constructed)
956     return;
957
958   if (!button->label_text && !priv->image)
959     return;
960
961   gtk_widget_style_get (GTK_WIDGET (button),
962                         "image-spacing", &image_spacing,
963                         NULL);
964
965   if (priv->image && !priv->image_is_stock)
966     {
967       image = g_object_ref (priv->image);
968       if (image->parent)
969         gtk_container_remove (GTK_CONTAINER (image->parent), image);
970     }
971
972   priv->image = NULL;
973
974   if (GTK_BIN (button)->child)
975     gtk_container_remove (GTK_CONTAINER (button),
976                           GTK_BIN (button)->child);
977
978   if (button->use_stock &&
979       button->label_text &&
980       gtk_stock_lookup (button->label_text, &item))
981     {
982       if (!image)
983         image = g_object_ref (gtk_image_new_from_stock (button->label_text, GTK_ICON_SIZE_BUTTON));
984
985       label_text = item.label;
986     }
987   else
988     label_text = button->label_text;
989
990   if (image)
991     {
992       priv->image = image;
993       g_object_set (priv->image,
994                     "visible", show_image (button),
995                     "no-show-all", TRUE,
996                     NULL);
997
998       if (priv->image_position == GTK_POS_LEFT ||
999           priv->image_position == GTK_POS_RIGHT)
1000         box = gtk_hbox_new (FALSE, image_spacing);
1001       else
1002         box = gtk_vbox_new (FALSE, image_spacing);
1003
1004       if (priv->align_set)
1005         align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
1006       else
1007         align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1008
1009       if (priv->image_position == GTK_POS_LEFT ||
1010           priv->image_position == GTK_POS_TOP)
1011         gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1012       else
1013         gtk_box_pack_end (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1014
1015       if (label_text)
1016         {
1017           if (button->use_underline || button->use_stock)
1018             {
1019               label = gtk_label_new_with_mnemonic (label_text);
1020               gtk_label_set_mnemonic_widget (GTK_LABEL (label),
1021                                              GTK_WIDGET (button));
1022             }
1023           else
1024             label = gtk_label_new (label_text);
1025
1026           if (priv->image_position == GTK_POS_RIGHT ||
1027               priv->image_position == GTK_POS_BOTTOM)
1028             gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
1029           else
1030             gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0);
1031         }
1032
1033       gtk_container_add (GTK_CONTAINER (button), align);
1034       gtk_container_add (GTK_CONTAINER (align), box);
1035       gtk_widget_show_all (align);
1036
1037       g_object_unref (image);
1038
1039       return;
1040     }
1041
1042   if (button->use_underline || button->use_stock)
1043     {
1044       label = gtk_label_new_with_mnemonic (button->label_text);
1045       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
1046     }
1047   else
1048     label = gtk_label_new (button->label_text);
1049
1050   if (priv->align_set)
1051     gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
1052
1053   gtk_widget_show (label);
1054   gtk_container_add (GTK_CONTAINER (button), label);
1055 }
1056
1057
1058 GtkWidget*
1059 gtk_button_new_with_label (const gchar *label)
1060 {
1061   return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
1062 }
1063
1064 /**
1065  * gtk_button_new_from_stock:
1066  * @stock_id: the name of the stock item 
1067  *
1068  * Creates a new #GtkButton containing the image and text from a stock item.
1069  * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
1070  * #GTK_STOCK_APPLY.
1071  *
1072  * If @stock_id is unknown, then it will be treated as a mnemonic
1073  * label (as for gtk_button_new_with_mnemonic()).
1074  *
1075  * Returns: a new #GtkButton
1076  **/
1077 GtkWidget*
1078 gtk_button_new_from_stock (const gchar *stock_id)
1079 {
1080   return g_object_new (GTK_TYPE_BUTTON,
1081                        "label", stock_id,
1082                        "use-stock", TRUE,
1083                        "use-underline", TRUE,
1084                        NULL);
1085 }
1086
1087 /**
1088  * gtk_button_new_with_mnemonic:
1089  * @label: The text of the button, with an underscore in front of the
1090  *         mnemonic character
1091  * @returns: a new #GtkButton
1092  *
1093  * Creates a new #GtkButton containing a label.
1094  * If characters in @label are preceded by an underscore, they are underlined.
1095  * If you need a literal underscore character in a label, use '__' (two 
1096  * underscores). The first underlined character represents a keyboard 
1097  * accelerator called a mnemonic.
1098  * Pressing Alt and that key activates the button.
1099  **/
1100 GtkWidget*
1101 gtk_button_new_with_mnemonic (const gchar *label)
1102 {
1103   return g_object_new (GTK_TYPE_BUTTON, "label", label, "use-underline", TRUE,  NULL);
1104 }
1105
1106 void
1107 gtk_button_pressed (GtkButton *button)
1108 {
1109   g_return_if_fail (GTK_IS_BUTTON (button));
1110
1111   
1112   g_signal_emit (button, button_signals[PRESSED], 0);
1113 }
1114
1115 void
1116 gtk_button_released (GtkButton *button)
1117 {
1118   g_return_if_fail (GTK_IS_BUTTON (button));
1119
1120   g_signal_emit (button, button_signals[RELEASED], 0);
1121 }
1122
1123 void
1124 gtk_button_clicked (GtkButton *button)
1125 {
1126   g_return_if_fail (GTK_IS_BUTTON (button));
1127
1128   g_signal_emit (button, button_signals[CLICKED], 0);
1129 }
1130
1131 void
1132 gtk_button_enter (GtkButton *button)
1133 {
1134   g_return_if_fail (GTK_IS_BUTTON (button));
1135
1136   g_signal_emit (button, button_signals[ENTER], 0);
1137 }
1138
1139 void
1140 gtk_button_leave (GtkButton *button)
1141 {
1142   g_return_if_fail (GTK_IS_BUTTON (button));
1143
1144   g_signal_emit (button, button_signals[LEAVE], 0);
1145 }
1146
1147 void
1148 gtk_button_set_relief (GtkButton *button,
1149                        GtkReliefStyle newrelief)
1150 {
1151   g_return_if_fail (GTK_IS_BUTTON (button));
1152
1153   if (newrelief != button->relief) 
1154     {
1155        button->relief = newrelief;
1156        g_object_notify (G_OBJECT (button), "relief");
1157        gtk_widget_queue_draw (GTK_WIDGET (button));
1158     }
1159 }
1160
1161 GtkReliefStyle
1162 gtk_button_get_relief (GtkButton *button)
1163 {
1164   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
1165
1166   return button->relief;
1167 }
1168
1169 static void
1170 gtk_button_realize (GtkWidget *widget)
1171 {
1172   GtkButton *button;
1173   GdkWindowAttr attributes;
1174   gint attributes_mask;
1175   gint border_width;
1176
1177   button = GTK_BUTTON (widget);
1178   gtk_widget_set_realized (widget, TRUE);
1179
1180   border_width = GTK_CONTAINER (widget)->border_width;
1181
1182   attributes.window_type = GDK_WINDOW_CHILD;
1183   attributes.x = widget->allocation.x + border_width;
1184   attributes.y = widget->allocation.y + border_width;
1185   attributes.width = widget->allocation.width - border_width * 2;
1186   attributes.height = widget->allocation.height - border_width * 2;
1187   attributes.wclass = GDK_INPUT_ONLY;
1188   attributes.event_mask = gtk_widget_get_events (widget);
1189   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1190                             GDK_BUTTON_RELEASE_MASK |
1191                             GDK_ENTER_NOTIFY_MASK |
1192                             GDK_LEAVE_NOTIFY_MASK);
1193
1194   attributes_mask = GDK_WA_X | GDK_WA_Y;
1195
1196   widget->window = gtk_widget_get_parent_window (widget);
1197   g_object_ref (widget->window);
1198   
1199   button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1200                                          &attributes, attributes_mask);
1201   gdk_window_set_user_data (button->event_window, button);
1202
1203   widget->style = gtk_style_attach (widget->style, widget->window);
1204 }
1205
1206 static void
1207 gtk_button_unrealize (GtkWidget *widget)
1208 {
1209   GtkButton *button = GTK_BUTTON (widget);
1210
1211   if (button->activate_timeout)
1212     gtk_button_finish_activate (button, FALSE);
1213
1214   if (button->event_window)
1215     {
1216       gdk_window_set_user_data (button->event_window, NULL);
1217       gdk_window_destroy (button->event_window);
1218       button->event_window = NULL;
1219     }
1220   
1221   GTK_WIDGET_CLASS (gtk_button_parent_class)->unrealize (widget);
1222 }
1223
1224 static void
1225 gtk_button_map (GtkWidget *widget)
1226 {
1227   GtkButton *button = GTK_BUTTON (widget);
1228   
1229   GTK_WIDGET_CLASS (gtk_button_parent_class)->map (widget);
1230
1231   if (button->event_window)
1232     gdk_window_show (button->event_window);
1233 }
1234
1235 static void
1236 gtk_button_unmap (GtkWidget *widget)
1237 {
1238   GtkButton *button = GTK_BUTTON (widget);
1239     
1240   if (button->event_window)
1241     gdk_window_hide (button->event_window);
1242
1243   GTK_WIDGET_CLASS (gtk_button_parent_class)->unmap (widget);
1244 }
1245
1246 static void
1247 gtk_button_update_image_spacing (GtkButton *button)
1248 {
1249   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1250   GtkWidget *child; 
1251   gint spacing;
1252
1253   /* Keep in sync with gtk_button_construct_child,
1254    * we only want to update the spacing if the box 
1255    * was constructed there.
1256    */
1257   if (!button->constructed || !priv->image)
1258     return;
1259
1260   child = GTK_BIN (button)->child;
1261   if (GTK_IS_ALIGNMENT (child))
1262     {
1263       child = GTK_BIN (child)->child;
1264       if (GTK_IS_BOX (child))
1265         {
1266           gtk_widget_style_get (GTK_WIDGET (button),
1267                                 "image-spacing", &spacing,
1268                                 NULL);
1269
1270           gtk_box_set_spacing (GTK_BOX (child), spacing);
1271         }
1272     }   
1273 }
1274
1275 static void
1276 gtk_button_style_set (GtkWidget *widget,
1277                       GtkStyle  *prev_style)
1278 {
1279   gtk_button_update_image_spacing (GTK_BUTTON (widget));
1280 }
1281
1282 static void
1283 gtk_button_get_props (GtkButton *button,
1284                       GtkBorder *default_border,
1285                       GtkBorder *default_outside_border,
1286                       GtkBorder *inner_border,
1287                       gboolean  *interior_focus)
1288 {
1289   GtkWidget *widget =  GTK_WIDGET (button);
1290   GtkBorder *tmp_border;
1291
1292   if (default_border)
1293     {
1294       gtk_widget_style_get (widget, "default-border", &tmp_border, NULL);
1295
1296       if (tmp_border)
1297         {
1298           *default_border = *tmp_border;
1299           gtk_border_free (tmp_border);
1300         }
1301       else
1302         *default_border = default_default_border;
1303     }
1304
1305   if (default_outside_border)
1306     {
1307       gtk_widget_style_get (widget, "default-outside-border", &tmp_border, NULL);
1308
1309       if (tmp_border)
1310         {
1311           *default_outside_border = *tmp_border;
1312           gtk_border_free (tmp_border);
1313         }
1314       else
1315         *default_outside_border = default_default_outside_border;
1316     }
1317
1318   if (inner_border)
1319     {
1320       gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
1321
1322       if (tmp_border)
1323         {
1324           *inner_border = *tmp_border;
1325           gtk_border_free (tmp_border);
1326         }
1327       else
1328         *inner_border = default_inner_border;
1329     }
1330
1331   if (interior_focus)
1332     gtk_widget_style_get (widget, "interior-focus", interior_focus, NULL);
1333 }
1334         
1335 static void
1336 gtk_button_size_request (GtkWidget      *widget,
1337                          GtkRequisition *requisition)
1338 {
1339   GtkButton *button = GTK_BUTTON (widget);
1340   GtkBorder default_border;
1341   GtkBorder inner_border;
1342   gint focus_width;
1343   gint focus_pad;
1344
1345   gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
1346   gtk_widget_style_get (GTK_WIDGET (widget),
1347                         "focus-line-width", &focus_width,
1348                         "focus-padding", &focus_pad,
1349                         NULL);
1350  
1351   requisition->width = ((GTK_CONTAINER (widget)->border_width +
1352                          GTK_WIDGET (widget)->style->xthickness) * 2 +
1353                         inner_border.left + inner_border.right);
1354   requisition->height = ((GTK_CONTAINER (widget)->border_width +
1355                           GTK_WIDGET (widget)->style->ythickness) * 2 +
1356                          inner_border.top + inner_border.bottom);
1357
1358   if (gtk_widget_get_can_default (widget))
1359     {
1360       requisition->width += default_border.left + default_border.right;
1361       requisition->height += default_border.top + default_border.bottom;
1362     }
1363
1364   if (GTK_BIN (button)->child && gtk_widget_get_visible (GTK_BIN (button)->child))
1365     {
1366       GtkRequisition child_requisition;
1367
1368       gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
1369
1370       requisition->width += child_requisition.width;
1371       requisition->height += child_requisition.height;
1372     }
1373   
1374   requisition->width += 2 * (focus_width + focus_pad);
1375   requisition->height += 2 * (focus_width + focus_pad);
1376 }
1377
1378 static void
1379 gtk_button_size_allocate (GtkWidget     *widget,
1380                           GtkAllocation *allocation)
1381 {
1382   GtkButton *button = GTK_BUTTON (widget);
1383   GtkAllocation child_allocation;
1384
1385   gint border_width = GTK_CONTAINER (widget)->border_width;
1386   gint xthickness = GTK_WIDGET (widget)->style->xthickness;
1387   gint ythickness = GTK_WIDGET (widget)->style->ythickness;
1388   GtkBorder default_border;
1389   GtkBorder inner_border;
1390   gint focus_width;
1391   gint focus_pad;
1392
1393   gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
1394   gtk_widget_style_get (GTK_WIDGET (widget),
1395                         "focus-line-width", &focus_width,
1396                         "focus-padding", &focus_pad,
1397                         NULL);
1398  
1399                             
1400   widget->allocation = *allocation;
1401
1402   if (gtk_widget_get_realized (widget))
1403     gdk_window_move_resize (button->event_window,
1404                             widget->allocation.x + border_width,
1405                             widget->allocation.y + border_width,
1406                             widget->allocation.width - border_width * 2,
1407                             widget->allocation.height - border_width * 2);
1408
1409   if (GTK_BIN (button)->child && gtk_widget_get_visible (GTK_BIN (button)->child))
1410     {
1411       child_allocation.x = widget->allocation.x + border_width + inner_border.left + xthickness;
1412       child_allocation.y = widget->allocation.y + border_width + inner_border.top + ythickness;
1413       
1414       child_allocation.width = MAX (1, widget->allocation.width -
1415                                     xthickness * 2 -
1416                                     inner_border.left -
1417                                     inner_border.right -
1418                                     border_width * 2);
1419       child_allocation.height = MAX (1, widget->allocation.height -
1420                                      ythickness * 2 -
1421                                      inner_border.top -
1422                                      inner_border.bottom -
1423                                      border_width * 2);
1424
1425       if (gtk_widget_get_can_default (GTK_WIDGET (button)))
1426         {
1427           child_allocation.x += default_border.left;
1428           child_allocation.y += default_border.top;
1429           child_allocation.width =  MAX (1, child_allocation.width - default_border.left - default_border.right);
1430           child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
1431         }
1432
1433       if (gtk_widget_get_can_focus (GTK_WIDGET (button)))
1434         {
1435           child_allocation.x += focus_width + focus_pad;
1436           child_allocation.y += focus_width + focus_pad;
1437           child_allocation.width =  MAX (1, child_allocation.width - (focus_width + focus_pad) * 2);
1438           child_allocation.height = MAX (1, child_allocation.height - (focus_width + focus_pad) * 2);
1439         }
1440
1441       if (button->depressed)
1442         {
1443           gint child_displacement_x;
1444           gint child_displacement_y;
1445           
1446           gtk_widget_style_get (widget,
1447                                 "child-displacement-x", &child_displacement_x, 
1448                                 "child-displacement-y", &child_displacement_y,
1449                                 NULL);
1450           child_allocation.x += child_displacement_x;
1451           child_allocation.y += child_displacement_y;
1452         }
1453
1454       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
1455     }
1456 }
1457
1458 void
1459 _gtk_button_paint (GtkButton          *button,
1460                    const GdkRectangle *area,
1461                    GtkStateType        state_type,
1462                    GtkShadowType       shadow_type,
1463                    const gchar        *main_detail,
1464                    const gchar        *default_detail)
1465 {
1466   GtkWidget *widget;
1467   gint width, height;
1468   gint x, y;
1469   gint border_width;
1470   GtkBorder default_border;
1471   GtkBorder default_outside_border;
1472   gboolean interior_focus;
1473   gint focus_width;
1474   gint focus_pad;
1475
1476   widget = GTK_WIDGET (button);
1477
1478   if (gtk_widget_is_drawable (widget))
1479     {
1480       border_width = GTK_CONTAINER (widget)->border_width;
1481
1482       gtk_button_get_props (button, &default_border, &default_outside_border, NULL, &interior_focus);
1483       gtk_widget_style_get (widget,
1484                             "focus-line-width", &focus_width,
1485                             "focus-padding", &focus_pad,
1486                             NULL); 
1487         
1488       x = widget->allocation.x + border_width;
1489       y = widget->allocation.y + border_width;
1490       width = widget->allocation.width - border_width * 2;
1491       height = widget->allocation.height - border_width * 2;
1492
1493       if (gtk_widget_has_default (widget) &&
1494           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
1495         {
1496           gtk_paint_box (widget->style, widget->window,
1497                          GTK_STATE_NORMAL, GTK_SHADOW_IN,
1498                          area, widget, "buttondefault",
1499                          x, y, width, height);
1500
1501           x += default_border.left;
1502           y += default_border.top;
1503           width -= default_border.left + default_border.right;
1504           height -= default_border.top + default_border.bottom;
1505         }
1506       else if (gtk_widget_get_can_default (widget))
1507         {
1508           x += default_outside_border.left;
1509           y += default_outside_border.top;
1510           width -= default_outside_border.left + default_outside_border.right;
1511           height -= default_outside_border.top + default_outside_border.bottom;
1512         }
1513        
1514       if (!interior_focus && gtk_widget_has_focus (widget))
1515         {
1516           x += focus_width + focus_pad;
1517           y += focus_width + focus_pad;
1518           width -= 2 * (focus_width + focus_pad);
1519           height -= 2 * (focus_width + focus_pad);
1520         }
1521
1522       if (button->relief != GTK_RELIEF_NONE || button->depressed ||
1523           gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT)
1524         gtk_paint_box (widget->style, widget->window,
1525                        state_type,
1526                        shadow_type, area, widget, "button",
1527                        x, y, width, height);
1528        
1529       if (gtk_widget_has_focus (widget))
1530         {
1531           gint child_displacement_x;
1532           gint child_displacement_y;
1533           gboolean displace_focus;
1534           
1535           gtk_widget_style_get (widget,
1536                                 "child-displacement-y", &child_displacement_y,
1537                                 "child-displacement-x", &child_displacement_x,
1538                                 "displace-focus", &displace_focus,
1539                                 NULL);
1540
1541           if (interior_focus)
1542             {
1543               x += widget->style->xthickness + focus_pad;
1544               y += widget->style->ythickness + focus_pad;
1545               width -= 2 * (widget->style->xthickness + focus_pad);
1546               height -=  2 * (widget->style->ythickness + focus_pad);
1547             }
1548           else
1549             {
1550               x -= focus_width + focus_pad;
1551               y -= focus_width + focus_pad;
1552               width += 2 * (focus_width + focus_pad);
1553               height += 2 * (focus_width + focus_pad);
1554             }
1555
1556           if (button->depressed && displace_focus)
1557             {
1558               x += child_displacement_x;
1559               y += child_displacement_y;
1560             }
1561
1562           gtk_paint_focus (widget->style, widget->window, gtk_widget_get_state (widget),
1563                            area, widget, "button",
1564                            x, y, width, height);
1565         }
1566     }
1567 }
1568
1569 static gboolean
1570 gtk_button_expose (GtkWidget      *widget,
1571                    GdkEventExpose *event)
1572 {
1573   if (gtk_widget_is_drawable (widget))
1574     {
1575       GtkButton *button = GTK_BUTTON (widget);
1576       
1577       _gtk_button_paint (button, &event->area,
1578                          gtk_widget_get_state (widget),
1579                          button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
1580                          "button", "buttondefault");
1581
1582       GTK_WIDGET_CLASS (gtk_button_parent_class)->expose_event (widget, event);
1583     }
1584
1585   return FALSE;
1586 }
1587
1588 static gboolean
1589 gtk_button_button_press (GtkWidget      *widget,
1590                          GdkEventButton *event)
1591 {
1592   GtkButton *button;
1593
1594   if (event->type == GDK_BUTTON_PRESS)
1595     {
1596       button = GTK_BUTTON (widget);
1597
1598       if (button->focus_on_click && !gtk_widget_has_focus (widget))
1599         gtk_widget_grab_focus (widget);
1600
1601       if (event->button == 1)
1602         gtk_button_pressed (button);
1603     }
1604
1605   return TRUE;
1606 }
1607
1608 static gboolean
1609 gtk_button_button_release (GtkWidget      *widget,
1610                            GdkEventButton *event)
1611 {
1612   GtkButton *button;
1613
1614   if (event->button == 1)
1615     {
1616       button = GTK_BUTTON (widget);
1617       gtk_button_released (button);
1618     }
1619
1620   return TRUE;
1621 }
1622
1623 static gboolean
1624 gtk_button_grab_broken (GtkWidget          *widget,
1625                         GdkEventGrabBroken *event)
1626 {
1627   GtkButton *button = GTK_BUTTON (widget);
1628   gboolean save_in;
1629   
1630   /* Simulate a button release without the pointer in the button */
1631   if (button->button_down)
1632     {
1633       save_in = button->in_button;
1634       button->in_button = FALSE;
1635       gtk_button_released (button);
1636       if (save_in != button->in_button)
1637         {
1638           button->in_button = save_in;
1639           gtk_button_update_state (button);
1640         }
1641     }
1642
1643   return TRUE;
1644 }
1645
1646 static gboolean
1647 gtk_button_key_release (GtkWidget   *widget,
1648                         GdkEventKey *event)
1649 {
1650   GtkButton *button = GTK_BUTTON (widget);
1651
1652   if (button->activate_timeout)
1653     {
1654       gtk_button_finish_activate (button, TRUE);
1655       return TRUE;
1656     }
1657   else if (GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event)
1658     return GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event (widget, event);
1659   else
1660     return FALSE;
1661 }
1662
1663 static gboolean
1664 gtk_button_enter_notify (GtkWidget        *widget,
1665                          GdkEventCrossing *event)
1666 {
1667   GtkButton *button;
1668   GtkWidget *event_widget;
1669
1670   button = GTK_BUTTON (widget);
1671   event_widget = gtk_get_event_widget ((GdkEvent*) event);
1672
1673   if ((event_widget == widget) &&
1674       (event->detail != GDK_NOTIFY_INFERIOR))
1675     {
1676       button->in_button = TRUE;
1677       gtk_button_enter (button);
1678     }
1679
1680   return FALSE;
1681 }
1682
1683 static gboolean
1684 gtk_button_leave_notify (GtkWidget        *widget,
1685                          GdkEventCrossing *event)
1686 {
1687   GtkButton *button;
1688   GtkWidget *event_widget;
1689
1690   button = GTK_BUTTON (widget);
1691   event_widget = gtk_get_event_widget ((GdkEvent*) event);
1692
1693   if ((event_widget == widget) &&
1694       (event->detail != GDK_NOTIFY_INFERIOR) &&
1695       (gtk_widget_get_sensitive (event_widget)))
1696     {
1697       button->in_button = FALSE;
1698       gtk_button_leave (button);
1699     }
1700
1701   return FALSE;
1702 }
1703
1704 static void
1705 gtk_real_button_pressed (GtkButton *button)
1706 {
1707   if (button->activate_timeout)
1708     return;
1709   
1710   button->button_down = TRUE;
1711   gtk_button_update_state (button);
1712 }
1713
1714 static void
1715 gtk_real_button_released (GtkButton *button)
1716 {
1717   if (button->button_down)
1718     {
1719       button->button_down = FALSE;
1720
1721       if (button->activate_timeout)
1722         return;
1723       
1724       if (button->in_button)
1725         gtk_button_clicked (button);
1726
1727       gtk_button_update_state (button);
1728     }
1729 }
1730
1731 static void 
1732 gtk_real_button_clicked (GtkButton *button)
1733 {
1734   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1735
1736   if (priv->action)
1737     gtk_action_activate (priv->action);
1738 }
1739
1740 static gboolean
1741 button_activate_timeout (gpointer data)
1742 {
1743   gtk_button_finish_activate (data, TRUE);
1744
1745   return FALSE;
1746 }
1747
1748 static void
1749 gtk_real_button_activate (GtkButton *button)
1750 {
1751   GtkWidget *widget = GTK_WIDGET (button);
1752   GtkButtonPrivate *priv;
1753   guint32 time;
1754
1755   priv = GTK_BUTTON_GET_PRIVATE (button);
1756
1757   if (gtk_widget_get_realized (widget) && !button->activate_timeout)
1758     {
1759       time = gtk_get_current_event_time ();
1760       if (gdk_keyboard_grab (button->event_window, TRUE, time) == 
1761           GDK_GRAB_SUCCESS)
1762         {
1763           priv->has_grab = TRUE;
1764           priv->grab_time = time;
1765         }
1766
1767       gtk_grab_add (widget);
1768       
1769       button->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
1770                                                 button_activate_timeout,
1771                                                 button);
1772       button->button_down = TRUE;
1773       gtk_button_update_state (button);
1774       gtk_widget_queue_draw (GTK_WIDGET (button));
1775     }
1776 }
1777
1778 static void
1779 gtk_button_finish_activate (GtkButton *button,
1780                             gboolean   do_it)
1781 {
1782   GtkWidget *widget = GTK_WIDGET (button);
1783   GtkButtonPrivate *priv;
1784   
1785   priv = GTK_BUTTON_GET_PRIVATE (button);
1786
1787   g_source_remove (button->activate_timeout);
1788   button->activate_timeout = 0;
1789
1790   if (priv->has_grab)
1791     {
1792       gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
1793                                    priv->grab_time);
1794     }
1795   gtk_grab_remove (widget);
1796
1797   button->button_down = FALSE;
1798
1799   gtk_button_update_state (button);
1800   gtk_widget_queue_draw (GTK_WIDGET (button));
1801
1802   if (do_it)
1803     gtk_button_clicked (button);
1804 }
1805
1806 /**
1807  * gtk_button_set_label:
1808  * @button: a #GtkButton
1809  * @label: a string
1810  *
1811  * Sets the text of the label of the button to @str. This text is
1812  * also used to select the stock item if gtk_button_set_use_stock()
1813  * is used.
1814  *
1815  * This will also clear any previously set labels.
1816  **/
1817 void
1818 gtk_button_set_label (GtkButton   *button,
1819                       const gchar *label)
1820 {
1821   gchar *new_label;
1822   
1823   g_return_if_fail (GTK_IS_BUTTON (button));
1824
1825   new_label = g_strdup (label);
1826   g_free (button->label_text);
1827   button->label_text = new_label;
1828   
1829   gtk_button_construct_child (button);
1830   
1831   g_object_notify (G_OBJECT (button), "label");
1832 }
1833
1834 /**
1835  * gtk_button_get_label:
1836  * @button: a #GtkButton
1837  *
1838  * Fetches the text from the label of the button, as set by
1839  * gtk_button_set_label(). If the label text has not 
1840  * been set the return value will be %NULL. This will be the 
1841  * case if you create an empty button with gtk_button_new() to 
1842  * use as a container.
1843  *
1844  * Return value: The text of the label widget. This string is owned
1845  * by the widget and must not be modified or freed.
1846  **/
1847 G_CONST_RETURN gchar *
1848 gtk_button_get_label (GtkButton *button)
1849 {
1850   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1851   
1852   return button->label_text;
1853 }
1854
1855 /**
1856  * gtk_button_set_use_underline:
1857  * @button: a #GtkButton
1858  * @use_underline: %TRUE if underlines in the text indicate mnemonics
1859  *
1860  * If true, an underline in the text of the button label indicates
1861  * the next character should be used for the mnemonic accelerator key.
1862  */
1863 void
1864 gtk_button_set_use_underline (GtkButton *button,
1865                               gboolean   use_underline)
1866 {
1867   g_return_if_fail (GTK_IS_BUTTON (button));
1868
1869   use_underline = use_underline != FALSE;
1870
1871   if (use_underline != button->use_underline)
1872     {
1873       button->use_underline = use_underline;
1874   
1875       gtk_button_construct_child (button);
1876       
1877       g_object_notify (G_OBJECT (button), "use-underline");
1878     }
1879 }
1880
1881 /**
1882  * gtk_button_get_use_underline:
1883  * @button: a #GtkButton
1884  *
1885  * Returns whether an embedded underline in the button label indicates a
1886  * mnemonic. See gtk_button_set_use_underline ().
1887  *
1888  * Return value: %TRUE if an embedded underline in the button label
1889  *               indicates the mnemonic accelerator keys.
1890  **/
1891 gboolean
1892 gtk_button_get_use_underline (GtkButton *button)
1893 {
1894   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1895   
1896   return button->use_underline;
1897 }
1898
1899 /**
1900  * gtk_button_set_use_stock:
1901  * @button: a #GtkButton
1902  * @use_stock: %TRUE if the button should use a stock item
1903  *
1904  * If %TRUE, the label set on the button is used as a
1905  * stock id to select the stock item for the button.
1906  */
1907 void
1908 gtk_button_set_use_stock (GtkButton *button,
1909                           gboolean   use_stock)
1910 {
1911   g_return_if_fail (GTK_IS_BUTTON (button));
1912
1913   use_stock = use_stock != FALSE;
1914
1915   if (use_stock != button->use_stock)
1916     {
1917       button->use_stock = use_stock;
1918   
1919       gtk_button_construct_child (button);
1920       
1921       g_object_notify (G_OBJECT (button), "use-stock");
1922     }
1923 }
1924
1925 /**
1926  * gtk_button_get_use_stock:
1927  * @button: a #GtkButton
1928  *
1929  * Returns whether the button label is a stock item.
1930  *
1931  * Return value: %TRUE if the button label is used to
1932  *               select a stock item instead of being
1933  *               used directly as the label text.
1934  */
1935 gboolean
1936 gtk_button_get_use_stock (GtkButton *button)
1937 {
1938   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1939   
1940   return button->use_stock;
1941 }
1942
1943 /**
1944  * gtk_button_set_focus_on_click:
1945  * @button: a #GtkButton
1946  * @focus_on_click: whether the button grabs focus when clicked with the mouse
1947  * 
1948  * Sets whether the button will grab focus when it is clicked with the mouse.
1949  * Making mouse clicks not grab focus is useful in places like toolbars where
1950  * you don't want the keyboard focus removed from the main area of the
1951  * application.
1952  *
1953  * Since: 2.4
1954  **/
1955 void
1956 gtk_button_set_focus_on_click (GtkButton *button,
1957                                gboolean   focus_on_click)
1958 {
1959   g_return_if_fail (GTK_IS_BUTTON (button));
1960   
1961   focus_on_click = focus_on_click != FALSE;
1962
1963   if (button->focus_on_click != focus_on_click)
1964     {
1965       button->focus_on_click = focus_on_click;
1966       
1967       g_object_notify (G_OBJECT (button), "focus-on-click");
1968     }
1969 }
1970
1971 /**
1972  * gtk_button_get_focus_on_click:
1973  * @button: a #GtkButton
1974  * 
1975  * Returns whether the button grabs focus when it is clicked with the mouse.
1976  * See gtk_button_set_focus_on_click().
1977  *
1978  * Return value: %TRUE if the button grabs focus when it is clicked with
1979  *               the mouse.
1980  *
1981  * Since: 2.4
1982  **/
1983 gboolean
1984 gtk_button_get_focus_on_click (GtkButton *button)
1985 {
1986   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1987   
1988   return button->focus_on_click;
1989 }
1990
1991 /**
1992  * gtk_button_set_alignment:
1993  * @button: a #GtkButton
1994  * @xalign: the horizontal position of the child, 0.0 is left aligned, 
1995  *   1.0 is right aligned
1996  * @yalign: the vertical position of the child, 0.0 is top aligned, 
1997  *   1.0 is bottom aligned
1998  *
1999  * Sets the alignment of the child. This property has no effect unless 
2000  * the child is a #GtkMisc or a #GtkAligment.
2001  *
2002  * Since: 2.4
2003  */
2004 void
2005 gtk_button_set_alignment (GtkButton *button,
2006                           gfloat     xalign,
2007                           gfloat     yalign)
2008 {
2009   GtkButtonPrivate *priv;
2010
2011   g_return_if_fail (GTK_IS_BUTTON (button));
2012   
2013   priv = GTK_BUTTON_GET_PRIVATE (button);
2014
2015   priv->xalign = xalign;
2016   priv->yalign = yalign;
2017   priv->align_set = 1;
2018
2019   maybe_set_alignment (button, GTK_BIN (button)->child);
2020
2021   g_object_freeze_notify (G_OBJECT (button));
2022   g_object_notify (G_OBJECT (button), "xalign");
2023   g_object_notify (G_OBJECT (button), "yalign");
2024   g_object_thaw_notify (G_OBJECT (button));
2025 }
2026
2027 /**
2028  * gtk_button_get_alignment:
2029  * @button: a #GtkButton
2030  * @xalign: return location for horizontal alignment
2031  * @yalign: return location for vertical alignment
2032  *
2033  * Gets the alignment of the child in the button.
2034  *
2035  * Since: 2.4
2036  */
2037 void
2038 gtk_button_get_alignment (GtkButton *button,
2039                           gfloat    *xalign,
2040                           gfloat    *yalign)
2041 {
2042   GtkButtonPrivate *priv;
2043
2044   g_return_if_fail (GTK_IS_BUTTON (button));
2045   
2046   priv = GTK_BUTTON_GET_PRIVATE (button);
2047  
2048   if (xalign) 
2049     *xalign = priv->xalign;
2050
2051   if (yalign)
2052     *yalign = priv->yalign;
2053 }
2054
2055 /**
2056  * _gtk_button_set_depressed:
2057  * @button: a #GtkButton
2058  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
2059  * 
2060  * Sets whether the button is currently drawn as down or not. This is 
2061  * purely a visual setting, and is meant only for use by derived widgets
2062  * such as #GtkToggleButton.
2063  **/
2064 void
2065 _gtk_button_set_depressed (GtkButton *button,
2066                            gboolean   depressed)
2067 {
2068   GtkWidget *widget = GTK_WIDGET (button);
2069
2070   depressed = depressed != FALSE;
2071
2072   if (depressed != button->depressed)
2073     {
2074       button->depressed = depressed;
2075       gtk_widget_queue_resize (widget);
2076     }
2077 }
2078
2079 static void
2080 gtk_button_update_state (GtkButton *button)
2081 {
2082   gboolean depressed;
2083   GtkStateType new_state;
2084
2085   if (button->activate_timeout)
2086     depressed = button->depress_on_activate;
2087   else
2088     depressed = button->in_button && button->button_down;
2089
2090   if (button->in_button && (!button->button_down || !depressed))
2091     new_state = GTK_STATE_PRELIGHT;
2092   else
2093     new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
2094
2095   _gtk_button_set_depressed (button, depressed); 
2096   gtk_widget_set_state (GTK_WIDGET (button), new_state);
2097 }
2098
2099 static void 
2100 show_image_change_notify (GtkButton *button)
2101 {
2102   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
2103
2104   if (priv->image) 
2105     {
2106       if (show_image (button))
2107         gtk_widget_show (priv->image);
2108       else
2109         gtk_widget_hide (priv->image);
2110     }
2111 }
2112
2113 static void
2114 traverse_container (GtkWidget *widget,
2115                     gpointer   data)
2116 {
2117   if (GTK_IS_BUTTON (widget))
2118     show_image_change_notify (GTK_BUTTON (widget));
2119   else if (GTK_IS_CONTAINER (widget))
2120     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
2121 }
2122
2123 static void
2124 gtk_button_setting_changed (GtkSettings *settings)
2125 {
2126   GList *list, *l;
2127
2128   list = gtk_window_list_toplevels ();
2129
2130   for (l = list; l; l = l->next)
2131     gtk_container_forall (GTK_CONTAINER (l->data), 
2132                           traverse_container, NULL);
2133
2134   g_list_free (list);
2135 }
2136
2137
2138 static void
2139 gtk_button_screen_changed (GtkWidget *widget,
2140                            GdkScreen *previous_screen)
2141 {
2142   GtkButton *button;
2143   GtkSettings *settings;
2144   guint show_image_connection;
2145
2146   if (!gtk_widget_has_screen (widget))
2147     return;
2148
2149   button = GTK_BUTTON (widget);
2150
2151   /* If the button is being pressed while the screen changes the
2152     release might never occur, so we reset the state. */
2153   if (button->button_down)
2154     {
2155       button->button_down = FALSE;
2156       gtk_button_update_state (button);
2157     }
2158
2159   settings = gtk_widget_get_settings (widget);
2160
2161   show_image_connection = 
2162     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
2163                                          "gtk-button-connection"));
2164   
2165   if (show_image_connection)
2166     return;
2167
2168   show_image_connection =
2169     g_signal_connect (settings, "notify::gtk-button-images",
2170                       G_CALLBACK (gtk_button_setting_changed), NULL);
2171   g_object_set_data (G_OBJECT (settings), 
2172                      I_("gtk-button-connection"),
2173                      GUINT_TO_POINTER (show_image_connection));
2174
2175   show_image_change_notify (button);
2176 }
2177
2178 static void
2179 gtk_button_state_changed (GtkWidget    *widget,
2180                           GtkStateType  previous_state)
2181 {
2182   GtkButton *button = GTK_BUTTON (widget);
2183
2184   if (!gtk_widget_is_sensitive (widget))
2185     {
2186       button->in_button = FALSE;
2187       gtk_real_button_released (button);
2188     }
2189 }
2190
2191 static void
2192 gtk_button_grab_notify (GtkWidget *widget,
2193                         gboolean   was_grabbed)
2194 {
2195   GtkButton *button = GTK_BUTTON (widget);
2196   gboolean save_in;
2197
2198   if (!was_grabbed)
2199     {
2200       save_in = button->in_button;
2201       button->in_button = FALSE; 
2202       gtk_real_button_released (button);
2203       if (save_in != button->in_button)
2204         {
2205           button->in_button = save_in;
2206           gtk_button_update_state (button);
2207         }
2208     }
2209 }
2210
2211 /**
2212  * gtk_button_set_image:
2213  * @button: a #GtkButton
2214  * @image: a widget to set as the image for the button
2215  *
2216  * Set the image of @button to the given widget. Note that
2217  * it depends on the #GtkSettings:gtk-button-images setting whether the
2218  * image will be displayed or not, you don't have to call
2219  * gtk_widget_show() on @image yourself.
2220  *
2221  * Since: 2.6
2222  */ 
2223 void
2224 gtk_button_set_image (GtkButton *button,
2225                       GtkWidget *image)
2226 {
2227   GtkButtonPrivate *priv;
2228
2229   g_return_if_fail (GTK_IS_BUTTON (button));
2230   g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
2231
2232   priv = GTK_BUTTON_GET_PRIVATE (button);
2233
2234   if (priv->image && priv->image->parent)
2235     gtk_container_remove (GTK_CONTAINER (priv->image->parent), priv->image);
2236
2237   priv->image = image;
2238   priv->image_is_stock = (image == NULL);
2239
2240   gtk_button_construct_child (button);
2241
2242   g_object_notify (G_OBJECT (button), "image");
2243 }
2244
2245 /**
2246  * gtk_button_get_image:
2247  * @button: a #GtkButton
2248  *
2249  * Gets the widget that is currenty set as the image of @button.
2250  * This may have been explicitly set by gtk_button_set_image()
2251  * or constructed by gtk_button_new_from_stock().
2252  *
2253  * Return value: a #GtkWidget or %NULL in case there is no image
2254  *
2255  * Since: 2.6
2256  */
2257 GtkWidget *
2258 gtk_button_get_image (GtkButton *button)
2259 {
2260   GtkButtonPrivate *priv;
2261
2262   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2263
2264   priv = GTK_BUTTON_GET_PRIVATE (button);
2265   
2266   return priv->image;
2267 }
2268
2269 /**
2270  * gtk_button_set_image_position:
2271  * @button: a #GtkButton
2272  * @position: the position
2273  *
2274  * Sets the position of the image relative to the text 
2275  * inside the button.
2276  *
2277  * Since: 2.10
2278  */ 
2279 void
2280 gtk_button_set_image_position (GtkButton       *button,
2281                                GtkPositionType  position)
2282 {
2283
2284   GtkButtonPrivate *priv;
2285
2286   g_return_if_fail (GTK_IS_BUTTON (button));
2287   g_return_if_fail (position >= GTK_POS_LEFT && position <= GTK_POS_BOTTOM);
2288   
2289   priv = GTK_BUTTON_GET_PRIVATE (button);
2290
2291   if (priv->image_position != position)
2292     {
2293       priv->image_position = position;
2294
2295       gtk_button_construct_child (button);
2296
2297       g_object_notify (G_OBJECT (button), "image-position");
2298     }
2299 }
2300
2301 /**
2302  * gtk_button_get_image_position:
2303  * @button: a #GtkButton
2304  *
2305  * Gets the position of the image relative to the text 
2306  * inside the button.
2307  *
2308  * Return value: the position
2309  *
2310  * Since: 2.10
2311  */
2312 GtkPositionType
2313 gtk_button_get_image_position (GtkButton *button)
2314 {
2315   GtkButtonPrivate *priv;
2316
2317   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_POS_LEFT);
2318
2319   priv = GTK_BUTTON_GET_PRIVATE (button);
2320   
2321   return priv->image_position;
2322 }
2323
2324
2325 #define __GTK_BUTTON_C__
2326 #include "gtkaliasdef.c"