]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkbutton.c
Use gtk_box_new() instead gtk_[v|h]box_new()
[~andy/gtk] / gtk / gtkbutton.c
index f444addb85021702371104451c9ddb095132b714..3c81cbfca09b81786a6baa09542d12a47b12dbd8 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
+/**
+ * SECTION:gtkbutton
+ * @Short_description: A widget that creates a signal when clicked on
+ * @Title: GtkButton
+ *
+ * The #GtkButton widget is generally used to attach a function to that is
+ * called when the button is pressed.  The various signals and how to use them
+ * are outlined below.
+ *
+ * The #GtkButton widget can hold any valid child widget.  That is it can hold
+ * most any other standard #GtkWidget.  The most commonly used child is the
+ * #GtkLabel.
+ */
+
+#include "config.h"
 #include <string.h>
 #include "gtkalignment.h"
 #include "gtkbutton.h"
 #include "gtkvbox.h"
 #include "gtkstock.h"
 #include "gtkiconfactory.h"
+#include "gtkactivatable.h"
+#include "gtksizerequest.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
-#include "gtkalias.h"
+
 
 static const GtkBorder default_default_border = { 1, 1, 1, 1 };
 static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
@@ -69,7 +85,11 @@ enum {
   PROP_FOCUS_ON_CLICK,
   PROP_XALIGN,
   PROP_YALIGN,
-  PROP_IMAGE_POSITION
+  PROP_IMAGE_POSITION,
+
+  /* activatable properties */
+  PROP_ACTIVATABLE_RELATED_ACTION,
+  PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
 };
 
 #define GTK_BUTTON_GET_PRIVATE(o)       (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_BUTTON, GtkButtonPrivate))
@@ -80,14 +100,17 @@ struct _GtkButtonPrivate
   gfloat          xalign;
   gfloat          yalign;
   GtkWidget      *image;
-  guint           align_set      : 1;
-  guint           image_is_stock : 1;
-  guint           has_grab       : 1;
+  guint           align_set             : 1;
+  guint           image_is_stock        : 1;
+  guint           use_action_appearance : 1;
   guint32         grab_time;
+  GdkDevice      *grab_keyboard;
   GtkPositionType image_position;
+  GtkAction      *action;
 };
 
-static void gtk_button_destroy        (GtkObject          *object);
+static void gtk_button_destroy        (GtkWidget          *widget);
+static void gtk_button_dispose        (GObject            *object);
 static void gtk_button_set_property   (GObject            *object,
                                        guint               prop_id,
                                        const GValue       *value,
@@ -98,32 +121,28 @@ static void gtk_button_get_property   (GObject            *object,
                                        GParamSpec         *pspec);
 static void gtk_button_screen_changed (GtkWidget          *widget,
                                       GdkScreen          *previous_screen);
-static void gtk_button_realize        (GtkWidget          *widget);
-static void gtk_button_unrealize      (GtkWidget          *widget);
-static void gtk_button_map            (GtkWidget          *widget);
-static void gtk_button_unmap          (GtkWidget          *widget);
-static void gtk_button_style_set      (GtkWidget          *widget,
-                                      GtkStyle           *prev_style);
-static void gtk_button_size_request   (GtkWidget          *widget,
-                                      GtkRequisition     *requisition);
-static void gtk_button_size_allocate  (GtkWidget          *widget,
-                                      GtkAllocation      *allocation);
-static gint gtk_button_expose         (GtkWidget          *widget,
-                                      GdkEventExpose     *event);
-static gint gtk_button_button_press   (GtkWidget          *widget,
-                                      GdkEventButton     *event);
-static gint gtk_button_button_release (GtkWidget          *widget,
-                                      GdkEventButton     *event);
-static gint gtk_button_grab_broken    (GtkWidget          *widget,
-                                      GdkEventGrabBroken *event);
-static gint gtk_button_key_release    (GtkWidget          *widget,
-                                      GdkEventKey        *event);
-static gint gtk_button_enter_notify   (GtkWidget          *widget,
-                                      GdkEventCrossing   *event);
-static gint gtk_button_leave_notify   (GtkWidget          *widget,
-                                      GdkEventCrossing   *event);
-static void gtk_real_button_pressed   (GtkButton          *button);
-static void gtk_real_button_released  (GtkButton          *button);
+static void gtk_button_realize (GtkWidget * widget);
+static void gtk_button_unrealize (GtkWidget * widget);
+static void gtk_button_map (GtkWidget * widget);
+static void gtk_button_unmap (GtkWidget * widget);
+static void gtk_button_style_set (GtkWidget * widget, GtkStyle * prev_style);
+static void gtk_button_size_allocate (GtkWidget * widget,
+                                     GtkAllocation * allocation);
+static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
+static gint gtk_button_button_press (GtkWidget * widget,
+                                    GdkEventButton * event);
+static gint gtk_button_button_release (GtkWidget * widget,
+                                      GdkEventButton * event);
+static gint gtk_button_grab_broken (GtkWidget * widget,
+                                   GdkEventGrabBroken * event);
+static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
+static gint gtk_button_enter_notify (GtkWidget * widget,
+                                    GdkEventCrossing * event);
+static gint gtk_button_leave_notify (GtkWidget * widget,
+                                    GdkEventCrossing * event);
+static void gtk_real_button_pressed (GtkButton * button);
+static void gtk_real_button_released (GtkButton * button);
+static void gtk_real_button_clicked (GtkButton * button);
 static void gtk_real_button_activate  (GtkButton          *button);
 static void gtk_button_update_state   (GtkButton          *button);
 static void gtk_button_add            (GtkContainer       *container,
@@ -142,38 +161,57 @@ static void gtk_button_grab_notify     (GtkWidget             *widget,
                                        gboolean               was_grabbed);
 
 
+static void gtk_button_activatable_interface_init(GtkActivatableIface  *iface);
+static void gtk_button_update                    (GtkActivatable       *activatable,
+                                                 GtkAction            *action,
+                                                 const gchar          *property_name);
+static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
+                                                  GtkAction            *action);
+static void gtk_button_set_related_action        (GtkButton            *button,
+                                                 GtkAction            *action);
+static void gtk_button_set_use_action_appearance (GtkButton            *button,
+                                                 gboolean              use_appearance);
+
+static void gtk_button_get_preferred_width       (GtkWidget           *widget,
+                                                 gint                *minimum_size,
+                                                 gint                *natural_size);
+static void gtk_button_get_preferred_height      (GtkWidget           *widget,
+                                                 gint                *minimum_size,
+                                                 gint                *natural_size);
+  
 static guint button_signals[LAST_SIGNAL] = { 0 };
 
-G_DEFINE_TYPE (GtkButton, gtk_button, GTK_TYPE_BIN)
+G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
+                                               gtk_button_activatable_interface_init))
 
 static void
 gtk_button_class_init (GtkButtonClass *klass)
 {
   GObjectClass *gobject_class;
-  GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkContainerClass *container_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
-  object_class = (GtkObjectClass*) klass;
   widget_class = (GtkWidgetClass*) klass;
   container_class = (GtkContainerClass*) klass;
   
-  gobject_class->constructor = gtk_button_constructor;
+  gobject_class->constructor  = gtk_button_constructor;
+  gobject_class->dispose      = gtk_button_dispose;
   gobject_class->set_property = gtk_button_set_property;
   gobject_class->get_property = gtk_button_get_property;
 
-  object_class->destroy = gtk_button_destroy;
-
+  widget_class->get_preferred_width  = gtk_button_get_preferred_width;
+  widget_class->get_preferred_height = gtk_button_get_preferred_height;
+  widget_class->destroy = gtk_button_destroy;
   widget_class->screen_changed = gtk_button_screen_changed;
   widget_class->realize = gtk_button_realize;
   widget_class->unrealize = gtk_button_unrealize;
   widget_class->map = gtk_button_map;
   widget_class->unmap = gtk_button_unmap;
   widget_class->style_set = gtk_button_style_set;
-  widget_class->size_request = gtk_button_size_request;
   widget_class->size_allocate = gtk_button_size_allocate;
-  widget_class->expose_event = gtk_button_expose;
+  widget_class->draw = gtk_button_draw;
   widget_class->button_press_event = gtk_button_button_press;
   widget_class->button_release_event = gtk_button_button_release;
   widget_class->grab_broken_event = gtk_button_grab_broken;
@@ -185,6 +223,7 @@ gtk_button_class_init (GtkButtonClass *klass)
 
   container_class->child_type = gtk_button_child_type;
   container_class->add = gtk_button_add;
+  gtk_container_class_handle_border_width (container_class);
 
   klass->pressed = gtk_real_button_pressed;
   klass->released = gtk_real_button_released;
@@ -240,7 +279,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
    * can be used to control it's horizontal alignment. 0.0 is left aligned, 
    * 1.0 is right aligned.
-   * 
+   *
    * Since: 2.4
    */
   g_object_class_install_property (gobject_class,
@@ -259,7 +298,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
    * can be used to control it's vertical alignment. 0.0 is top aligned, 
    * 1.0 is bottom aligned.
-   * 
+   *
    * Since: 2.4
    */
   g_object_class_install_property (gobject_class,
@@ -274,9 +313,9 @@ gtk_button_class_init (GtkButtonClass *klass)
 
   /**
    * GtkButton::image:
-   * 
+   *
    * The child widget to appear next to the button text.
-   * 
+   *
    * Since: 2.6
    */
   g_object_class_install_property (gobject_class,
@@ -291,7 +330,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    * GtkButton:image-position:
    *
    * The position of the image relative to the text inside the button.
-   * 
+   *
    * Since: 2.10
    */
   g_object_class_install_property (gobject_class,
@@ -303,17 +342,20 @@ gtk_button_class_init (GtkButtonClass *klass)
                                                       GTK_POS_LEFT,
                                                       GTK_PARAM_READWRITE));
 
+  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
+  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
+
   /**
    * GtkButton::pressed:
    * @button: the object that received the signal
    *
    * Emitted when the button is pressed.
-   * 
-   * @Deprecated: Use the #GtkWidget::button-press-event signal.
+   *
+   * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
    */ 
   button_signals[PRESSED] =
     g_signal_new (I_("pressed"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkButtonClass, pressed),
                  NULL, NULL,
@@ -325,12 +367,12 @@ gtk_button_class_init (GtkButtonClass *klass)
    * @button: the object that received the signal
    *
    * Emitted when the button is released.
-   * 
-   * @Deprecated: Use the #GtkWidget::button-release-event signal.
+   *
+   * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
    */ 
   button_signals[RELEASED] =
     g_signal_new (I_("released"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkButtonClass, released),
                  NULL, NULL,
@@ -345,7 +387,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    */ 
   button_signals[CLICKED] =
     g_signal_new (I_("clicked"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkButtonClass, clicked),
                  NULL, NULL,
@@ -357,12 +399,12 @@ gtk_button_class_init (GtkButtonClass *klass)
    * @button: the object that received the signal
    *
    * Emitted when the pointer enters the button.
-   * 
-   * @Deprecated: Use the #GtkWidget::enter-notify-event signal.
+   *
+   * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
    */ 
   button_signals[ENTER] =
     g_signal_new (I_("enter"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkButtonClass, enter),
                  NULL, NULL,
@@ -374,12 +416,12 @@ gtk_button_class_init (GtkButtonClass *klass)
    * @button: the object that received the signal
    *
    * Emitted when the pointer leaves the button.
-   * 
-   * @Deprecated: Use the #GtkWidget::leave-notify-event signal.
+   *
+   * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
    */ 
   button_signals[LEAVE] =
     g_signal_new (I_("leave"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkButtonClass, leave),
                  NULL, NULL,
@@ -397,7 +439,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    */
   button_signals[ACTIVATE] =
     g_signal_new (I_("activate"),
-                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkButtonClass, activate),
                  NULL, NULL,
@@ -405,17 +447,33 @@ gtk_button_class_init (GtkButtonClass *klass)
                  G_TYPE_NONE, 0);
   widget_class->activate_signal = button_signals[ACTIVATE];
 
+  /**
+   * GtkButton:default-border:
+   *
+   * The "default-border" style property defines the extra space to add
+   * around a button that can become the default widget of its window.
+   * For more information about default widgets, see gtk_widget_grab_default().
+   */
+
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boxed ("default-border",
                                                               P_("Default Spacing"),
-                                                              P_("Extra space to add for CAN_DEFAULT buttons"),
+                                                              P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
                                                               GTK_TYPE_BORDER,
                                                               GTK_PARAM_READABLE));
 
+  /**
+   * GtkButton:default-outside-border:
+   *
+   * The "default-outside-border" style property defines the extra outside
+   * space to add around a button that can become the default widget of its
+   * window. Extra outside space is always drawn outside the button border.
+   * For more information about default widgets, see gtk_widget_grab_default().
+   */
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boxed ("default-outside-border",
                                                               P_("Default Outside Spacing"),
-                                                              P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
+                                                              P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
                                                               GTK_TYPE_BORDER,
                                                               GTK_PARAM_READABLE));
   gtk_widget_class_install_style_property (widget_class,
@@ -447,8 +505,8 @@ gtk_button_class_init (GtkButtonClass *klass)
                                           g_param_spec_boolean ("displace-focus",
                                                                 P_("Displace focus"),
                                                                 P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
-                                                      FALSE,
-                                                      GTK_PARAM_READABLE));
+                                                                FALSE,
+                                                                GTK_PARAM_READABLE));
 
   /**
    * GtkButton:inner-border:
@@ -466,9 +524,9 @@ gtk_button_class_init (GtkButtonClass *klass)
 
   /**
    * GtkButton::image-spacing:
-   * 
+   *
    * Spacing in pixels between the image and label.
-   * 
+   *
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (widget_class,
@@ -479,13 +537,6 @@ gtk_button_class_init (GtkButtonClass *klass)
                                                             G_MAXINT,
                                                             2,
                                                             GTK_PARAM_READABLE));
-  
-
-  gtk_settings_install_property (g_param_spec_boolean ("gtk-button-images",
-                                                      P_("Show button images"),
-                                                      P_("Whether stock icons should be shown in buttons"),
-                                                      TRUE,
-                                                      GTK_PARAM_READWRITE));
 
   g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
 }
@@ -495,8 +546,9 @@ gtk_button_init (GtkButton *button)
 {
   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
 
-  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
-  GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
+  gtk_widget_set_can_focus (GTK_WIDGET (button), TRUE);
+  gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
+  gtk_widget_set_has_window (GTK_WIDGET (button), FALSE);
 
   button->label_text = NULL;
   
@@ -515,20 +567,21 @@ gtk_button_init (GtkButton *button)
   priv->align_set = 0;
   priv->image_is_stock = TRUE;
   priv->image_position = GTK_POS_LEFT;
+  priv->use_action_appearance = TRUE;
 }
 
 static void
-gtk_button_destroy (GtkObject *object)
+gtk_button_destroy (GtkWidget *widget)
 {
-  GtkButton *button = GTK_BUTTON (object);
-  
+  GtkButton *button = GTK_BUTTON (widget);
+
   if (button->label_text)
     {
       g_free (button->label_text);
       button->label_text = NULL;
     }
-  
-  (* GTK_OBJECT_CLASS (gtk_button_parent_class)->destroy) (object);
+
+  GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
 }
 
 static GObject*
@@ -539,9 +592,9 @@ gtk_button_constructor (GType                  type,
   GObject *object;
   GtkButton *button;
 
-  object = (* G_OBJECT_CLASS (gtk_button_parent_class)->constructor) (type,
-                                                                     n_construct_properties,
-                                                                     construct_params);
+  object = G_OBJECT_CLASS (gtk_button_parent_class)->constructor (type,
+                                                                  n_construct_properties,
+                                                                  construct_params);
 
   button = GTK_BUTTON (object);
   button->constructed = TRUE;
@@ -556,7 +609,7 @@ gtk_button_constructor (GType                  type,
 static GType
 gtk_button_child_type  (GtkContainer     *container)
 {
-  if (!GTK_BIN (container)->child)
+  if (!gtk_bin_get_child (GTK_BIN (container)))
     return GTK_TYPE_WIDGET;
   else
     return G_TYPE_NONE;
@@ -578,10 +631,17 @@ maybe_set_alignment (GtkButton *button,
   else if (GTK_IS_ALIGNMENT (widget))
     {
       GtkAlignment *alignment = GTK_ALIGNMENT (widget);
+      gfloat xscale, yscale;
+
+      g_object_get (alignment,
+                    "xscale", &xscale,
+                    "yscale", &yscale,
+                    NULL);
 
       if (priv->align_set)
-       gtk_alignment_set (alignment, priv->xalign, priv->yalign, 
-                          alignment->xscale, alignment->yscale);
+        gtk_alignment_set (alignment,
+                           priv->xalign, priv->yalign,
+                           xscale, yscale);
     }
 }
 
@@ -594,6 +654,20 @@ gtk_button_add (GtkContainer *container,
   GTK_CONTAINER_CLASS (gtk_button_parent_class)->add (container, widget);
 }
 
+static void 
+gtk_button_dispose (GObject *object)
+{
+  GtkButton *button = GTK_BUTTON (object);
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  if (priv->action)
+    {
+      gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
+      priv->action = NULL;
+    }
+  G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
+}
+
 static void
 gtk_button_set_property (GObject         *object,
                          guint            prop_id,
@@ -632,6 +706,12 @@ gtk_button_set_property (GObject         *object,
     case PROP_IMAGE_POSITION:
       gtk_button_set_image_position (button, g_value_get_enum (value));
       break;
+    case PROP_ACTIVATABLE_RELATED_ACTION:
+      gtk_button_set_related_action (button, g_value_get_object (value));
+      break;
+    case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
+      gtk_button_set_use_action_appearance (button, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -676,12 +756,189 @@ gtk_button_get_property (GObject         *object,
     case PROP_IMAGE_POSITION:
       g_value_set_enum (value, priv->image_position);
       break;
+    case PROP_ACTIVATABLE_RELATED_ACTION:
+      g_value_set_object (value, priv->action);
+      break;
+    case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
+      g_value_set_boolean (value, priv->use_action_appearance);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
+static void 
+gtk_button_activatable_interface_init (GtkActivatableIface  *iface)
+{
+  iface->update = gtk_button_update;
+  iface->sync_action_properties = gtk_button_sync_action_properties;
+}
+
+static void
+activatable_update_stock_id (GtkButton *button,
+                            GtkAction *action)
+{
+  if (!gtk_button_get_use_stock (button))
+    return;
+
+  gtk_button_set_label (button, gtk_action_get_stock_id (action));
+}
+
+static void
+activatable_update_short_label (GtkButton *button,
+                               GtkAction *action)
+{
+  GtkWidget *child;
+  GtkWidget *image;
+
+  if (gtk_button_get_use_stock (button))
+    return;
+
+  image = gtk_button_get_image (button);
+
+  /* Dont touch custom child... */
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (GTK_IS_IMAGE (image) ||
+      child == NULL ||
+      GTK_IS_LABEL (child))
+    {
+      gtk_button_set_label (button, gtk_action_get_short_label (action));
+      gtk_button_set_use_underline (button, TRUE);
+    }
+}
+
+static void
+activatable_update_icon_name (GtkButton *button,
+                             GtkAction *action)
+{
+  GtkWidget *image;
+             
+  if (gtk_button_get_use_stock (button))
+    return;
+
+  image = gtk_button_get_image (button);
+
+  if (GTK_IS_IMAGE (image) &&
+      (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
+       gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
+    gtk_image_set_from_icon_name (GTK_IMAGE (image),
+                                 gtk_action_get_icon_name (action), GTK_ICON_SIZE_MENU);
+}
+
+static void
+activatable_update_gicon (GtkButton *button,
+                         GtkAction *action)
+{
+  GtkWidget *image = gtk_button_get_image (button);
+  GIcon *icon = gtk_action_get_gicon (action);
+  
+  if (GTK_IS_IMAGE (image) &&
+      (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
+       gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_GICON))
+    gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_BUTTON);
+}
+
+static void 
+gtk_button_update (GtkActivatable *activatable,
+                  GtkAction      *action,
+                  const gchar    *property_name)
+{
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (activatable);
+
+  if (strcmp (property_name, "visible") == 0)
+    {
+      if (gtk_action_is_visible (action))
+       gtk_widget_show (GTK_WIDGET (activatable));
+      else
+       gtk_widget_hide (GTK_WIDGET (activatable));
+    }
+  else if (strcmp (property_name, "sensitive") == 0)
+    gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
+
+  if (!priv->use_action_appearance)
+    return;
+
+  if (strcmp (property_name, "stock-id") == 0)
+    activatable_update_stock_id (GTK_BUTTON (activatable), action);
+  else if (strcmp (property_name, "gicon") == 0)
+    activatable_update_gicon (GTK_BUTTON (activatable), action);
+  else if (strcmp (property_name, "short-label") == 0)
+    activatable_update_short_label (GTK_BUTTON (activatable), action);
+  else if (strcmp (property_name, "icon-name") == 0)
+    activatable_update_icon_name (GTK_BUTTON (activatable), action);
+}
+
+static void
+gtk_button_sync_action_properties (GtkActivatable *activatable,
+                                  GtkAction      *action)
+{
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (activatable);
+
+  if (!action)
+    return;
+
+  if (gtk_action_is_visible (action))
+    gtk_widget_show (GTK_WIDGET (activatable));
+  else
+    gtk_widget_hide (GTK_WIDGET (activatable));
+  
+  gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
+  
+  if (priv->use_action_appearance)
+    {
+      activatable_update_stock_id (GTK_BUTTON (activatable), action);
+      activatable_update_short_label (GTK_BUTTON (activatable), action);
+      activatable_update_gicon (GTK_BUTTON (activatable), action);
+      activatable_update_icon_name (GTK_BUTTON (activatable), action);
+    }
+}
+
+static void
+gtk_button_set_related_action (GtkButton *button,
+                              GtkAction *action)
+{
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  if (priv->action == action)
+    return;
+
+  /* This should be a default handler, but for compatibility reasons
+   * we need to support derived classes that don't chain up their
+   * clicked handler.
+   */
+  g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
+  if (action)
+    g_signal_connect_after (button, "clicked",
+                            G_CALLBACK (gtk_real_button_clicked), NULL);
+
+  gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action);
+
+  priv->action = action;
+}
+
+static void
+gtk_button_set_use_action_appearance (GtkButton *button,
+                                     gboolean   use_appearance)
+{
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  if (priv->use_action_appearance != use_appearance)
+    {
+      priv->use_action_appearance = use_appearance;
+
+      gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (button), priv->action);
+    }
+}
+
+/**
+ * gtk_button_new:
+ *
+ * Creates a new #GtkButton widget. To add a child widget to the button,
+ * use gtk_container_add().
+ *
+ * Returns: The newly created #GtkButton widget.
+ */
 GtkWidget*
 gtk_button_new (void)
 {
@@ -711,35 +968,40 @@ gtk_button_construct_child (GtkButton *button)
 {
   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
   GtkStockItem item;
+  GtkWidget *child;
   GtkWidget *label;
   GtkWidget *box;
   GtkWidget *align;
   GtkWidget *image = NULL;
   gchar *label_text = NULL;
   gint image_spacing;
-  
+
   if (!button->constructed)
     return;
+
   if (!button->label_text && !priv->image)
     return;
-  
-  gtk_widget_style_get (GTK_WIDGET (button), 
-                       "image-spacing", &image_spacing, 
+
+  gtk_widget_style_get (GTK_WIDGET (button),
+                       "image-spacing", &image_spacing,
                        NULL);
 
   if (priv->image && !priv->image_is_stock)
     {
+      GtkWidget *parent;
+
       image = g_object_ref (priv->image);
-      if (image->parent)
-       gtk_container_remove (GTK_CONTAINER (image->parent), image);
+
+      parent = gtk_widget_get_parent (image);
+      if (parent)
+       gtk_container_remove (GTK_CONTAINER (parent), image);
     }
-  
+
   priv->image = NULL;
 
-  if (GTK_BIN (button)->child)
-    gtk_container_remove (GTK_CONTAINER (button),
-                         GTK_BIN (button)->child);
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (child)
+    gtk_container_remove (GTK_CONTAINER (button), child);
 
   if (button->use_stock &&
       button->label_text &&
@@ -756,16 +1018,16 @@ gtk_button_construct_child (GtkButton *button)
   if (image)
     {
       priv->image = image;
-      g_object_set (priv->image, 
+      g_object_set (priv->image,
                    "visible", show_image (button),
                    "no-show-all", TRUE,
                    NULL);
 
       if (priv->image_position == GTK_POS_LEFT ||
          priv->image_position == GTK_POS_RIGHT)
-       box = gtk_hbox_new (FALSE, image_spacing);
+       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, image_spacing);
       else
-       box = gtk_vbox_new (FALSE, image_spacing);
+       box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, image_spacing);
 
       if (priv->align_set)
        align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
@@ -780,9 +1042,14 @@ gtk_button_construct_child (GtkButton *button)
 
       if (label_text)
        {
-         label = gtk_label_new_with_mnemonic (label_text);
-         gtk_label_set_mnemonic_widget (GTK_LABEL (label), 
-                                        GTK_WIDGET (button));
+          if (button->use_underline || button->use_stock)
+            {
+             label = gtk_label_new_with_mnemonic (label_text);
+             gtk_label_set_mnemonic_widget (GTK_LABEL (label),
+                                             GTK_WIDGET (button));
+            }
+          else
+            label = gtk_label_new (label_text);
 
          if (priv->image_position == GTK_POS_RIGHT ||
              priv->image_position == GTK_POS_BOTTOM)
@@ -790,7 +1057,7 @@ gtk_button_construct_child (GtkButton *button)
          else
            gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0);
        }
-      
+
       gtk_container_add (GTK_CONTAINER (button), align);
       gtk_container_add (GTK_CONTAINER (align), box);
       gtk_widget_show_all (align);
@@ -799,23 +1066,32 @@ gtk_button_construct_child (GtkButton *button)
 
       return;
     }
-  
-  if (button->use_underline)
+
+  if (button->use_underline || button->use_stock)
     {
       label = gtk_label_new_with_mnemonic (button->label_text);
       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
     }
   else
     label = gtk_label_new (button->label_text);
-  
+
   if (priv->align_set)
     gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
-  
+
   gtk_widget_show (label);
   gtk_container_add (GTK_CONTAINER (button), label);
 }
 
 
+/**
+ * gtk_button_new_with_label:
+ * @label: The text you want the #GtkLabel to hold.
+ *
+ * Creates a #GtkButton widget with a #GtkLabel child containing the given
+ * text.
+ *
+ * Returns: The newly created #GtkButton widget.
+ */
 GtkWidget*
 gtk_button_new_with_label (const gchar *label)
 {
@@ -864,6 +1140,14 @@ gtk_button_new_with_mnemonic (const gchar *label)
   return g_object_new (GTK_TYPE_BUTTON, "label", label, "use-underline", TRUE,  NULL);
 }
 
+/**
+ * gtk_button_pressed:
+ * @button: The #GtkButton you want to send the signal to.
+ *
+ * Emits a #GtkButton::pressed signal to the given #GtkButton.
+ *
+ * Deprecated: 2.20: Use the #GtkWidget::button-press-event signal.
+ */
 void
 gtk_button_pressed (GtkButton *button)
 {
@@ -873,6 +1157,14 @@ gtk_button_pressed (GtkButton *button)
   g_signal_emit (button, button_signals[PRESSED], 0);
 }
 
+/**
+ * gtk_button_released:
+ * @button: The #GtkButton you want to send the signal to.
+ *
+ * Emits a #GtkButton::released signal to the given #GtkButton.
+ *
+ * Deprecated: 2.20: Use the #GtkWidget::button-release-event signal.
+ */
 void
 gtk_button_released (GtkButton *button)
 {
@@ -881,6 +1173,12 @@ gtk_button_released (GtkButton *button)
   g_signal_emit (button, button_signals[RELEASED], 0);
 }
 
+/**
+ * gtk_button_clicked:
+ * @button: The #GtkButton you want to send the signal to.
+ *
+ * Emits a #GtkButton::clicked signal to the given #GtkButton.
+ */
 void
 gtk_button_clicked (GtkButton *button)
 {
@@ -889,6 +1187,14 @@ gtk_button_clicked (GtkButton *button)
   g_signal_emit (button, button_signals[CLICKED], 0);
 }
 
+/**
+ * gtk_button_enter:
+ * @button: The #GtkButton you want to send the signal to.
+ *
+ * Emits a #GtkButton::enter signal to the given #GtkButton.
+ *
+ * Deprecated: 2.20: Use the #GtkWidget::enter-notify-event signal.
+ */
 void
 gtk_button_enter (GtkButton *button)
 {
@@ -897,6 +1203,14 @@ gtk_button_enter (GtkButton *button)
   g_signal_emit (button, button_signals[ENTER], 0);
 }
 
+/**
+ * gtk_button_leave:
+ * @button: The #GtkButton you want to send the signal to.
+ *
+ * Emits a #GtkButton::leave signal to the given #GtkButton.
+ *
+ * Deprecated: 2.20: Use the #GtkWidget::leave-notify-event signal.
+ */
 void
 gtk_button_leave (GtkButton *button)
 {
@@ -905,6 +1219,17 @@ gtk_button_leave (GtkButton *button)
   g_signal_emit (button, button_signals[LEAVE], 0);
 }
 
+/**
+ * gtk_button_set_relief:
+ * @button: The #GtkButton you want to set relief styles of.
+ * @newstyle: The GtkReliefStyle as described above.
+ *
+ * Sets the relief style of the edges of the given #GtkButton widget.
+ * Three styles exist, GTK_RELIEF_NORMAL, GTK_RELIEF_HALF, GTK_RELIEF_NONE.
+ * The default style is, as one can guess, GTK_RELIEF_NORMAL.
+ *
+ * <!-- FIXME: put pictures of each style -->
+ */
 void
 gtk_button_set_relief (GtkButton *button,
                       GtkReliefStyle newrelief)
@@ -919,6 +1244,14 @@ gtk_button_set_relief (GtkButton *button,
     }
 }
 
+/**
+ * gtk_button_get_relief:
+ * @button: The #GtkButton you want the #GtkReliefStyle from.
+ *
+ * Returns the current relief style of the given #GtkButton.
+ *
+ * Returns: The current #GtkReliefStyle
+ */
 GtkReliefStyle
 gtk_button_get_relief (GtkButton *button)
 {
@@ -930,21 +1263,21 @@ gtk_button_get_relief (GtkButton *button)
 static void
 gtk_button_realize (GtkWidget *widget)
 {
-  GtkButton *button;
+  GtkButton *button = GTK_BUTTON (widget);
+  GtkAllocation allocation;
+  GdkWindow *window;
   GdkWindowAttr attributes;
   gint attributes_mask;
-  gint border_width;
 
-  button = GTK_BUTTON (widget);
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  gtk_widget_get_allocation (widget, &allocation);
 
-  border_width = GTK_CONTAINER (widget)->border_width;
+  gtk_widget_set_realized (widget, TRUE);
 
   attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = widget->allocation.x + border_width;
-  attributes.y = widget->allocation.y + border_width;
-  attributes.width = widget->allocation.width - border_width * 2;
-  attributes.height = widget->allocation.height - border_width * 2;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
   attributes.wclass = GDK_INPUT_ONLY;
   attributes.event_mask = gtk_widget_get_events (widget);
   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
@@ -954,14 +1287,15 @@ gtk_button_realize (GtkWidget *widget)
 
   attributes_mask = GDK_WA_X | GDK_WA_Y;
 
-  widget->window = gtk_widget_get_parent_window (widget);
-  g_object_ref (widget->window);
-  
-  button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+  window = gtk_widget_get_parent_window (widget);
+  gtk_widget_set_window (widget, window);
+  g_object_ref (window);
+
+  button->event_window = gdk_window_new (window,
                                         &attributes, attributes_mask);
   gdk_window_set_user_data (button->event_window, button);
 
-  widget->style = gtk_style_attach (widget->style, widget->window);
+  gtk_widget_style_attach (widget);
 }
 
 static void
@@ -1018,10 +1352,10 @@ gtk_button_update_image_spacing (GtkButton *button)
   if (!button->constructed || !priv->image)
     return;
 
-  child = GTK_BIN (button)->child;
+  child = gtk_bin_get_child (GTK_BIN (button));
   if (GTK_IS_ALIGNMENT (child))
     {
-      child = GTK_BIN (child)->child;
+      child = gtk_bin_get_child (GTK_BIN (child));
       if (GTK_IS_BOX (child))
         {
           gtk_widget_style_get (GTK_WIDGET (button),
@@ -1092,49 +1426,6 @@ gtk_button_get_props (GtkButton *button,
   if (interior_focus)
     gtk_widget_style_get (widget, "interior-focus", interior_focus, NULL);
 }
-       
-static void
-gtk_button_size_request (GtkWidget      *widget,
-                        GtkRequisition *requisition)
-{
-  GtkButton *button = GTK_BUTTON (widget);
-  GtkBorder default_border;
-  GtkBorder inner_border;
-  gint focus_width;
-  gint focus_pad;
-
-  gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                       "focus-line-width", &focus_width,
-                       "focus-padding", &focus_pad,
-                       NULL);
-  requisition->width = ((GTK_CONTAINER (widget)->border_width +
-                         GTK_WIDGET (widget)->style->xthickness) * 2 +
-                        inner_border.left + inner_border.right);
-  requisition->height = ((GTK_CONTAINER (widget)->border_width +
-                          GTK_WIDGET (widget)->style->ythickness) * 2 +
-                         inner_border.top + inner_border.bottom);
-
-  if (GTK_WIDGET_CAN_DEFAULT (widget))
-    {
-      requisition->width += default_border.left + default_border.right;
-      requisition->height += default_border.top + default_border.bottom;
-    }
-
-  if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
-    {
-      GtkRequisition child_requisition;
-
-      gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
-
-      requisition->width += child_requisition.width;
-      requisition->height += child_requisition.height;
-    }
-  
-  requisition->width += 2 * (focus_width + focus_pad);
-  requisition->height += 2 * (focus_width + focus_pad);
-}
 
 static void
 gtk_button_size_allocate (GtkWidget     *widget,
@@ -1142,61 +1433,66 @@ gtk_button_size_allocate (GtkWidget     *widget,
 {
   GtkButton *button = GTK_BUTTON (widget);
   GtkAllocation child_allocation;
+  GtkStyle *style;
+  GtkWidget *child;
 
-  gint border_width = GTK_CONTAINER (widget)->border_width;
-  gint xthickness = GTK_WIDGET (widget)->style->xthickness;
-  gint ythickness = GTK_WIDGET (widget)->style->ythickness;
+  gint xthickness, ythickness;
   GtkBorder default_border;
   GtkBorder inner_border;
   gint focus_width;
   gint focus_pad;
 
+  style = gtk_widget_get_style (widget);
+  xthickness = style->xthickness;
+  ythickness = style->ythickness;
+
   gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
   gtk_widget_style_get (GTK_WIDGET (widget),
                        "focus-line-width", &focus_width,
                        "focus-padding", &focus_pad,
                        NULL);
-                           
-  widget->allocation = *allocation;
 
-  if (GTK_WIDGET_REALIZED (widget))
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (gtk_widget_get_realized (widget))
     gdk_window_move_resize (button->event_window,
-                           widget->allocation.x + border_width,
-                           widget->allocation.y + border_width,
-                           widget->allocation.width - border_width * 2,
-                           widget->allocation.height - border_width * 2);
+                            allocation->x,
+                            allocation->y,
+                            allocation->width,
+                            allocation->height);
 
-  if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (child && gtk_widget_get_visible (child))
     {
-      child_allocation.x = widget->allocation.x + border_width + inner_border.left + xthickness;
-      child_allocation.y = widget->allocation.y + border_width + inner_border.top + ythickness;
-      
-      child_allocation.width = MAX (1, widget->allocation.width -
-                                    xthickness * 2 -
-                                    inner_border.left -
-                                    inner_border.right -
-                                   border_width * 2);
-      child_allocation.height = MAX (1, widget->allocation.height -
-                                     ythickness * 2 -
-                                     inner_border.top -
-                                     inner_border.bottom -
-                                    border_width * 2);
-
-      if (GTK_WIDGET_CAN_DEFAULT (button))
+      child_allocation.x = allocation->x + inner_border.left + xthickness;
+      child_allocation.y = allocation->y + inner_border.top + ythickness;
+
+      child_allocation.width =
+       allocation->width -
+       xthickness * 2 -
+       inner_border.left -
+       inner_border.right;
+
+      child_allocation.height = 
+       allocation->height -
+       ythickness * 2 -
+       inner_border.top -
+       inner_border.bottom;
+
+      if (gtk_widget_get_can_default (GTK_WIDGET (button)))
        {
          child_allocation.x += default_border.left;
          child_allocation.y += default_border.top;
-         child_allocation.width =  MAX (1, child_allocation.width - default_border.left - default_border.right);
-         child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
+         child_allocation.width =  child_allocation.width - default_border.left - default_border.right;
+         child_allocation.height = child_allocation.height - default_border.top - default_border.bottom;
        }
 
-      if (GTK_WIDGET_CAN_FOCUS (button))
+      if (gtk_widget_get_can_focus (GTK_WIDGET (button)))
        {
          child_allocation.x += focus_width + focus_pad;
          child_allocation.y += focus_width + focus_pad;
-         child_allocation.width =  MAX (1, child_allocation.width - (focus_width + focus_pad) * 2);
-         child_allocation.height = MAX (1, child_allocation.height - (focus_width + focus_pad) * 2);
+         child_allocation.width =  child_allocation.width - (focus_width + focus_pad) * 2;
+         child_allocation.height = child_allocation.height - (focus_width + focus_pad) * 2;
        }
 
       if (button->depressed)
@@ -1212,136 +1508,140 @@ gtk_button_size_allocate (GtkWidget     *widget,
          child_allocation.y += child_displacement_y;
        }
 
-      gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
+      child_allocation.width  = MAX (1, child_allocation.width);
+      child_allocation.height = MAX (1, child_allocation.height);
+
+      gtk_widget_size_allocate (child, &child_allocation);
     }
 }
 
 void
 _gtk_button_paint (GtkButton          *button,
-                  const GdkRectangle *area,
+                  cairo_t            *cr,
+                   int                 width,
+                   int                 height,
                   GtkStateType        state_type,
                   GtkShadowType       shadow_type,
                   const gchar        *main_detail,
                   const gchar        *default_detail)
 {
   GtkWidget *widget;
-  gint width, height;
   gint x, y;
-  gint border_width;
   GtkBorder default_border;
   GtkBorder default_outside_border;
   gboolean interior_focus;
   gint focus_width;
   gint focus_pad;
+  GtkAllocation allocation;
+  GdkWindow *window;
+  GtkStyle *style;
+
+  widget = GTK_WIDGET (button);
+
+  gtk_button_get_props (button, &default_border, &default_outside_border, NULL, &interior_focus);
+  gtk_widget_style_get (widget,
+                        "focus-line-width", &focus_width,
+                        "focus-padding", &focus_pad,
+                        NULL); 
+
+  gtk_widget_get_allocation (widget, &allocation);
+  style = gtk_widget_get_style (widget);
+  window = gtk_widget_get_window (widget);
+
+  x = 0;
+  y = 0;
+
+  if (gtk_widget_has_default (widget) &&
+      GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
+    {
+      gtk_paint_box (style, cr,
+                     GTK_STATE_NORMAL, GTK_SHADOW_IN,
+                     widget, "buttondefault",
+                     x, y, width, height);
+
+      x += default_border.left;
+      y += default_border.top;
+      width -= default_border.left + default_border.right;
+      height -= default_border.top + default_border.bottom;
+    }
+  else if (gtk_widget_get_can_default (widget))
+    {
+      x += default_outside_border.left;
+      y += default_outside_border.top;
+      width -= default_outside_border.left + default_outside_border.right;
+      height -= default_outside_border.top + default_outside_border.bottom;
+    }
    
-  if (GTK_WIDGET_DRAWABLE (button))
+  if (!interior_focus && gtk_widget_has_focus (widget))
     {
-      widget = GTK_WIDGET (button);
-      border_width = GTK_CONTAINER (widget)->border_width;
-
-      gtk_button_get_props (button, &default_border, &default_outside_border, NULL, &interior_focus);
-      gtk_widget_style_get (GTK_WIDGET (widget),
-                           "focus-line-width", &focus_width,
-                           "focus-padding", &focus_pad,
-                           NULL); 
-       
-      x = widget->allocation.x + border_width;
-      y = widget->allocation.y + border_width;
-      width = widget->allocation.width - border_width * 2;
-      height = widget->allocation.height - border_width * 2;
-
-      if (GTK_WIDGET_HAS_DEFAULT (widget) &&
-         GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
-       {
-         gtk_paint_box (widget->style, widget->window,
-                        GTK_STATE_NORMAL, GTK_SHADOW_IN,
-                        area, widget, "buttondefault",
-                        x, y, width, height);
-
-         x += default_border.left;
-         y += default_border.top;
-         width -= default_border.left + default_border.right;
-         height -= default_border.top + default_border.bottom;
-       }
-      else if (GTK_WIDGET_CAN_DEFAULT (widget))
-       {
-         x += default_outside_border.left;
-         y += default_outside_border.top;
-         width -= default_outside_border.left + default_outside_border.right;
-         height -= default_outside_border.top + default_outside_border.bottom;
-       }
-       
-      if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget))
-       {
-         x += focus_width + focus_pad;
-         y += focus_width + focus_pad;
-         width -= 2 * (focus_width + focus_pad);
-         height -= 2 * (focus_width + focus_pad);
-       }
+      x += focus_width + focus_pad;
+      y += focus_width + focus_pad;
+      width -= 2 * (focus_width + focus_pad);
+      height -= 2 * (focus_width + focus_pad);
+    }
 
-      if (button->relief != GTK_RELIEF_NONE || button->depressed ||
-         GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT)
-       gtk_paint_box (widget->style, widget->window,
-                      state_type,
-                      shadow_type, area, widget, "button",
-                      x, y, width, height);
-       
-      if (GTK_WIDGET_HAS_FOCUS (widget))
-       {
-         gint child_displacement_x;
-         gint child_displacement_y;
-         gboolean displace_focus;
-         
-         gtk_widget_style_get (GTK_WIDGET (widget),
-                               "child-displacement-y", &child_displacement_y,
-                               "child-displacement-x", &child_displacement_x,
-                               "displace-focus", &displace_focus,
-                               NULL);
+  if (button->relief != GTK_RELIEF_NONE || button->depressed ||
+      gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT)
+    gtk_paint_box (style, cr,
+                   state_type,
+                   shadow_type, widget, "button",
+                   x, y, width, height);
+   
+  if (gtk_widget_has_focus (widget))
+    {
+      gint child_displacement_x;
+      gint child_displacement_y;
+      gboolean displace_focus;
+      
+      gtk_widget_style_get (widget,
+                            "child-displacement-y", &child_displacement_y,
+                            "child-displacement-x", &child_displacement_x,
+                            "displace-focus", &displace_focus,
+                            NULL);
 
-         if (interior_focus)
-           {
-             x += widget->style->xthickness + focus_pad;
-             y += widget->style->ythickness + focus_pad;
-             width -= 2 * (widget->style->xthickness + focus_pad);
-             height -=  2 * (widget->style->ythickness + focus_pad);
-           }
-         else
-           {
-             x -= focus_width + focus_pad;
-             y -= focus_width + focus_pad;
-             width += 2 * (focus_width + focus_pad);
-             height += 2 * (focus_width + focus_pad);
-           }
-
-         if (button->depressed && displace_focus)
-           {
-             x += child_displacement_x;
-             y += child_displacement_y;
-           }
-
-         gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
-                          area, widget, "button",
-                          x, y, width, height);
-       }
+      if (interior_focus)
+        {
+          x += style->xthickness + focus_pad;
+          y += style->ythickness + focus_pad;
+          width -= 2 * (style->xthickness + focus_pad);
+          height -=  2 * (style->ythickness + focus_pad);
+        }
+      else
+        {
+          x -= focus_width + focus_pad;
+          y -= focus_width + focus_pad;
+          width += 2 * (focus_width + focus_pad);
+          height += 2 * (focus_width + focus_pad);
+        }
+
+      if (button->depressed && displace_focus)
+        {
+          x += child_displacement_x;
+          y += child_displacement_y;
+        }
+
+      gtk_paint_focus (style, cr,
+                       gtk_widget_get_state (widget),
+                       widget, "button",
+                       x, y, width, height);
     }
 }
 
 static gboolean
-gtk_button_expose (GtkWidget      *widget,
-                  GdkEventExpose *event)
+gtk_button_draw (GtkWidget *widget,
+                cairo_t   *cr)
 {
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      GtkButton *button = GTK_BUTTON (widget);
-      
-      _gtk_button_paint (button, &event->area,
-                        GTK_WIDGET_STATE (widget),
-                        button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
-                        "button", "buttondefault");
-      
-      (* GTK_WIDGET_CLASS (gtk_button_parent_class)->expose_event) (widget, event);
-    }
+  GtkButton *button = GTK_BUTTON (widget);
   
+  _gtk_button_paint (button, cr, 
+                     gtk_widget_get_allocated_width (widget),
+                     gtk_widget_get_allocated_height (widget),
+                     gtk_widget_get_state (widget),
+                     button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
+                     "button", "buttondefault");
+
+  GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
+
   return FALSE;
 }
 
@@ -1355,7 +1655,7 @@ gtk_button_button_press (GtkWidget      *widget,
     {
       button = GTK_BUTTON (widget);
 
-      if (button->focus_on_click && !GTK_WIDGET_HAS_FOCUS (widget))
+      if (button->focus_on_click && !gtk_widget_has_focus (widget))
        gtk_widget_grab_focus (widget);
 
       if (event->button == 1)
@@ -1425,12 +1725,10 @@ gtk_button_enter_notify (GtkWidget        *widget,
                         GdkEventCrossing *event)
 {
   GtkButton *button;
-  GtkWidget *event_widget;
 
   button = GTK_BUTTON (widget);
-  event_widget = gtk_get_event_widget ((GdkEvent*) event);
 
-  if ((event_widget == widget) &&
+  if ((event->window == button->event_window) &&
       (event->detail != GDK_NOTIFY_INFERIOR))
     {
       button->in_button = TRUE;
@@ -1445,13 +1743,12 @@ gtk_button_leave_notify (GtkWidget        *widget,
                         GdkEventCrossing *event)
 {
   GtkButton *button;
-  GtkWidget *event_widget;
 
   button = GTK_BUTTON (widget);
-  event_widget = gtk_get_event_widget ((GdkEvent*) event);
 
-  if ((event_widget == widget) &&
-      (event->detail != GDK_NOTIFY_INFERIOR))
+  if ((event->window == button->event_window) &&
+      (event->detail != GDK_NOTIFY_INFERIOR) &&
+      (gtk_widget_get_sensitive (widget)))
     {
       button->in_button = FALSE;
       gtk_button_leave (button);
@@ -1487,6 +1784,15 @@ gtk_real_button_released (GtkButton *button)
     }
 }
 
+static void 
+gtk_real_button_clicked (GtkButton *button)
+{
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  if (priv->action)
+    gtk_action_activate (priv->action);
+}
+
 static gboolean
 button_activate_timeout (gpointer data)
 {
@@ -1500,22 +1806,31 @@ gtk_real_button_activate (GtkButton *button)
 {
   GtkWidget *widget = GTK_WIDGET (button);
   GtkButtonPrivate *priv;
+  GdkDevice *device;
   guint32 time;
 
   priv = GTK_BUTTON_GET_PRIVATE (button);
+  device = gtk_get_current_event_device ();
+
+  if (device && device->source != GDK_SOURCE_KEYBOARD)
+    device = gdk_device_get_associated_device (device);
+
+  g_return_if_fail (device && device->source == GDK_SOURCE_KEYBOARD);
 
-  if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
+  if (gtk_widget_get_realized (widget) && !button->activate_timeout)
     {
       time = gtk_get_current_event_time ();
-      if (gdk_keyboard_grab (button->event_window, TRUE, time) == 
-         GDK_GRAB_SUCCESS)
-       {
-         priv->has_grab = TRUE;
+
+      if (gdk_device_grab (device, button->event_window,
+                           GDK_OWNERSHIP_WINDOW, TRUE,
+                           GDK_KEY_PRESS | GDK_KEY_RELEASE,
+                           NULL, time) == GDK_GRAB_SUCCESS)
+        {
+          gtk_device_grab_add (widget, device, TRUE);
+         priv->grab_keyboard = device;
          priv->grab_time = time;
        }
 
-      gtk_grab_add (widget);
-      
       button->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
                                                button_activate_timeout,
                                                button);
@@ -1537,12 +1852,12 @@ gtk_button_finish_activate (GtkButton *button,
   g_source_remove (button->activate_timeout);
   button->activate_timeout = 0;
 
-  if (priv->has_grab)
+  if (priv->grab_keyboard)
     {
-      gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
-                                  priv->grab_time);
+      gdk_device_ungrab (priv->grab_keyboard, priv->grab_time);
+      gtk_device_grab_remove (widget, priv->grab_keyboard);
+      priv->grab_keyboard = NULL;
     }
-  gtk_grab_remove (widget);
 
   button->button_down = FALSE;
 
@@ -1553,6 +1868,87 @@ gtk_button_finish_activate (GtkButton *button,
     gtk_button_clicked (button);
 }
 
+
+static void
+gtk_button_get_size (GtkWidget      *widget,
+                    GtkOrientation  orientation,
+                    gint           *minimum_size,
+                    gint           *natural_size)
+{
+  GtkButton *button = GTK_BUTTON (widget);
+  GtkStyle *style;
+  GtkWidget *child;
+  GtkBorder default_border;
+  GtkBorder inner_border;
+  gint focus_width;
+  gint focus_pad;
+  gint minimum, natural;
+
+  gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
+  gtk_widget_style_get (GTK_WIDGET (widget),
+                       "focus-line-width", &focus_width,
+                       "focus-padding", &focus_pad,
+                       NULL);
+
+  style = gtk_widget_get_style (GTK_WIDGET (widget));
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      minimum = (style->xthickness * 2 +
+                inner_border.left + inner_border.right);
+
+      if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
+       minimum += default_border.left + default_border.right;
+    }
+  else
+    {
+      minimum = (style->ythickness * 2 +
+                inner_border.top + inner_border.bottom);
+
+      if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
+       minimum += default_border.top + default_border.bottom;
+    }  
+
+  minimum += 2 * (focus_width + focus_pad);
+  natural = minimum;
+
+  if ((child = gtk_bin_get_child (GTK_BIN (button))) && 
+      gtk_widget_get_visible (child))
+    {
+      gint child_min, child_nat;
+
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+       gtk_widget_get_preferred_width (child, &child_min, &child_nat);
+      else
+       gtk_widget_get_preferred_height (child, &child_min, &child_nat);
+
+      minimum += child_min;
+      natural += child_nat;
+    }
+
+  if (minimum_size)
+    *minimum_size = minimum;
+
+  if (natural_size)
+    *natural_size = natural;
+}
+
+static void 
+gtk_button_get_preferred_width (GtkWidget *widget,
+                                gint      *minimum_size,
+                                gint      *natural_size)
+{
+  gtk_button_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+}
+
+static void 
+gtk_button_get_preferred_height (GtkWidget *widget,
+                                 gint      *minimum_size,
+                                 gint      *natural_size)
+{
+  gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+}
+
 /**
  * gtk_button_set_label:
  * @button: a #GtkButton
@@ -1694,7 +2090,7 @@ gtk_button_get_use_stock (GtkButton *button)
  * gtk_button_set_focus_on_click:
  * @button: a #GtkButton
  * @focus_on_click: whether the button grabs focus when clicked with the mouse
- * 
+ *
  * Sets whether the button will grab focus when it is clicked with the mouse.
  * Making mouse clicks not grab focus is useful in places like toolbars where
  * you don't want the keyboard focus removed from the main area of the
@@ -1721,7 +2117,7 @@ gtk_button_set_focus_on_click (GtkButton *button,
 /**
  * gtk_button_get_focus_on_click:
  * @button: a #GtkButton
- * 
+ *
  * Returns whether the button grabs focus when it is clicked with the mouse.
  * See gtk_button_set_focus_on_click().
  *
@@ -1766,7 +2162,7 @@ gtk_button_set_alignment (GtkButton *button,
   priv->yalign = yalign;
   priv->align_set = 1;
 
-  maybe_set_alignment (button, GTK_BIN (button)->child);
+  maybe_set_alignment (button, gtk_bin_get_child (GTK_BIN (button)));
 
   g_object_freeze_notify (G_OBJECT (button));
   g_object_notify (G_OBJECT (button), "xalign");
@@ -1806,7 +2202,7 @@ gtk_button_get_alignment (GtkButton *button,
  * _gtk_button_set_depressed:
  * @button: a #GtkButton
  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
- * 
+ *
  * Sets whether the button is currently drawn as down or not. This is 
  * purely a visual setting, and is meant only for use by derived widgets
  * such as #GtkToggleButton.
@@ -1889,29 +2285,36 @@ static void
 gtk_button_screen_changed (GtkWidget *widget,
                           GdkScreen *previous_screen)
 {
+  GtkButton *button;
   GtkSettings *settings;
-  guint show_image_connection;
+  gulong show_image_connection;
 
   if (!gtk_widget_has_screen (widget))
     return;
 
+  button = GTK_BUTTON (widget);
+
+  /* If the button is being pressed while the screen changes the
+    release might never occur, so we reset the state. */
+  if (button->button_down)
+    {
+      button->button_down = FALSE;
+      gtk_button_update_state (button);
+    }
+
   settings = gtk_widget_get_settings (widget);
 
   show_image_connection = 
-    GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
-                                        "gtk-button-connection"));
+    g_signal_handler_find (settings, G_SIGNAL_MATCH_FUNC, 0, 0,
+                           NULL, gtk_button_setting_changed, NULL);
   
   if (show_image_connection)
     return;
 
-  show_image_connection =
-    g_signal_connect (settings, "notify::gtk-button-images",
-                     G_CALLBACK (gtk_button_setting_changed), NULL);
-  g_object_set_data (G_OBJECT (settings), 
-                    I_("gtk-button-connection"),
-                    GUINT_TO_POINTER (show_image_connection));
+  g_signal_connect (settings, "notify::gtk-button-images",
+                    G_CALLBACK (gtk_button_setting_changed), NULL);
 
-  show_image_change_notify (GTK_BUTTON (widget));
+  show_image_change_notify (button);
 }
 
 static void
@@ -1920,7 +2323,7 @@ gtk_button_state_changed (GtkWidget    *widget,
 {
   GtkButton *button = GTK_BUTTON (widget);
 
-  if (!GTK_WIDGET_IS_SENSITIVE (widget))
+  if (!gtk_widget_is_sensitive (widget))
     {
       button->in_button = FALSE;
       gtk_real_button_released (button);
@@ -1932,8 +2335,14 @@ gtk_button_grab_notify (GtkWidget *widget,
                        gboolean   was_grabbed)
 {
   GtkButton *button = GTK_BUTTON (widget);
+  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
   gboolean save_in;
 
+  if (button->activate_timeout &&
+      priv->grab_keyboard &&
+      gtk_widget_device_is_shadowed (widget, priv->grab_keyboard))
+    gtk_button_finish_activate (button, FALSE);
+
   if (!was_grabbed)
     {
       save_in = button->in_button;
@@ -1964,14 +2373,19 @@ gtk_button_set_image (GtkButton *button,
                      GtkWidget *image)
 {
   GtkButtonPrivate *priv;
+  GtkWidget *parent;
 
   g_return_if_fail (GTK_IS_BUTTON (button));
   g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
 
   priv = GTK_BUTTON_GET_PRIVATE (button);
 
-  if (priv->image && priv->image->parent)
-    gtk_container_remove (GTK_CONTAINER (priv->image->parent), priv->image);
+  if (priv->image)
+    {
+      parent = gtk_widget_get_parent (priv->image);
+      if (parent)
+        gtk_container_remove (GTK_CONTAINER (parent), priv->image);
+    }
 
   priv->image = image;
   priv->image_is_stock = (image == NULL);
@@ -1989,7 +2403,7 @@ gtk_button_set_image (GtkButton *button,
  * This may have been explicitly set by gtk_button_set_image()
  * or constructed by gtk_button_new_from_stock().
  *
- * Return value: a #GtkWidget or %NULL in case there is no image
+ * Return value: (transfer none): a #GtkWidget or %NULL in case there is no image
  *
  * Since: 2.6
  */
@@ -2061,5 +2475,21 @@ gtk_button_get_image_position (GtkButton *button)
 }
 
 
-#define __GTK_BUTTON_C__
-#include "gtkaliasdef.c"  
+/**
+ * gtk_button_get_event_window:
+ * @button: a #GtkButton
+ *
+ * Returns the button's event window if it is realized, %NULL otherwise.
+ * This function should be rarely needed.
+ *
+ * Return value: (transfer none): @button's event window.
+ *
+ * Since: 2.22
+ */
+GdkWindow*
+gtk_button_get_event_window (GtkButton *button)
+{
+  g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
+
+  return button->event_window;
+}