diff --git a/README.in b/README.in
index 9c2cfe5..eea5148 100644
--- a/README.in
+++ b/README.in
@@ -27,6 +27,16 @@ Installation
 See the file 'INSTALL'
 
 
+Release notes for 2.16
+======================
+
+* GtkButton implements the following as virtual functions now:
+  gtk_button_get_label
+  gtk_button_set_image
+  gtk_button_get_image
+  Subclasses can now override these functions to allow developers
+  to use regular button API even with different child widgets.
+
 Release notes for 2.14
 ======================
 
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index 234f036..5eb8445 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -80,6 +80,7 @@ struct _GtkButtonPrivate
   gfloat          xalign;
   gfloat          yalign;
   GtkWidget      *image;
+  GtkWidget      *label_widget;
   guint           align_set      : 1;
   guint           image_is_stock : 1;
   guint           has_grab       : 1;
@@ -125,6 +126,10 @@ static gint gtk_button_leave_notify   (GtkWidget          *widget,
 static void gtk_real_button_pressed   (GtkButton          *button);
 static void gtk_real_button_released  (GtkButton          *button);
 static void gtk_real_button_activate  (GtkButton          *button);
+static GtkWidget* gtk_real_button_get_label (GtkButton  *button);
+static void gtk_real_button_set_image (GtkButton          *button,
+                                       GtkWidget          *image);
+static GtkWidget* gtk_real_button_get_image (GtkButton    *button);
 static void gtk_button_update_state   (GtkButton          *button);
 static void gtk_button_add            (GtkContainer       *container,
 			               GtkWidget          *widget);
@@ -192,6 +197,9 @@ gtk_button_class_init (GtkButtonClass *klass)
   klass->enter = gtk_button_update_state;
   klass->leave = gtk_button_update_state;
   klass->activate = gtk_real_button_activate;
+  klass->get_label = gtk_real_button_get_label;
+  klass->set_image = gtk_real_button_set_image;
+  klass->get_image = gtk_real_button_get_image;
 
   g_object_class_install_property (gobject_class,
                                    PROP_LABEL,
@@ -521,6 +529,7 @@ gtk_button_init (GtkButton *button)
   priv->align_set = 0;
   priv->image_is_stock = TRUE;
   priv->image_position = GTK_POS_LEFT;
+  priv->label_widget = NULL;
 }
 
 static void
@@ -698,7 +707,7 @@ static gboolean
 show_image (GtkButton *button)
 {
   gboolean show;
-  
+
   if (button->label_text)
     {
       GtkSettings *settings;
@@ -742,6 +751,7 @@ gtk_button_construct_child (GtkButton *button)
     }
   
   priv->image = NULL;
+  priv->label_widget = NULL;
 
   if (GTK_BIN (button)->child)
     gtk_container_remove (GTK_CONTAINER (button),
@@ -795,6 +805,8 @@ gtk_button_construct_child (GtkButton *button)
 	    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
 	  else
 	    gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+          priv->label_widget = label;
 	}
       
       gtk_container_add (GTK_CONTAINER (button), align);
@@ -813,7 +825,9 @@ gtk_button_construct_child (GtkButton *button)
     }
   else
     label = gtk_label_new (button->label_text);
-  
+
+  priv->label_widget = label;
+
   if (priv->align_set)
     gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
   
@@ -1573,21 +1587,33 @@ gtk_button_finish_activate (GtkButton *button,
  **/
 void
 gtk_button_set_label (GtkButton   *button,
-		      const gchar *label)
+                      const gchar *label)
 {
   gchar *new_label;
-  
+
   g_return_if_fail (GTK_IS_BUTTON (button));
 
   new_label = g_strdup (label);
   g_free (button->label_text);
   button->label_text = new_label;
-  
-  gtk_button_construct_child (button);
-  
+
+  if (GTK_BUTTON_GET_CLASS (button)->get_label (button))
+    {
+      GtkWidget* label_widget;
+      label_widget = GTK_BUTTON_GET_CLASS (button)->get_label (button);
+      gtk_label_set_text (GTK_LABEL (label_widget), new_label);
+    }
   g_object_notify (G_OBJECT (button), "label");
 }
 
+static GtkWidget *
+gtk_real_button_get_label (GtkButton   *button)
+{
+  GtkButtonPrivate* priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  return priv->label_widget;
+}
+
 /**
  * gtk_button_get_label:
  * @button: a #GtkButton
@@ -1605,7 +1631,7 @@ G_CONST_RETURN gchar *
 gtk_button_get_label (GtkButton *button)
 {
   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
-  
+
   return button->label_text;
 }
 
@@ -1627,10 +1653,14 @@ gtk_button_set_use_underline (GtkButton *button,
 
   if (use_underline != button->use_underline)
     {
+      GtkWidget *label_widget;
+
       button->use_underline = use_underline;
-  
-      gtk_button_construct_child (button);
-      
+
+      label_widget = GTK_BUTTON_GET_CLASS (button)->get_label (button);
+      if (label_widget)
+        gtk_label_set_use_underline (GTK_LABEL (label_widget), use_underline);
+
       g_object_notify (G_OBJECT (button), "use-underline");
     }
 }
@@ -1671,10 +1701,26 @@ gtk_button_set_use_stock (GtkButton *button,
 
   if (use_stock != button->use_stock)
     {
+      GtkWidget *label_widget;
+      GtkStockItem item;
+
       button->use_stock = use_stock;
-  
-      gtk_button_construct_child (button);
-      
+
+      label_widget = GTK_BUTTON_GET_CLASS (button)->get_label (button);
+      if (label_widget)
+        {
+
+          if (button->use_stock && button->label_text &&
+            gtk_stock_lookup (button->label_text, &item))
+            {
+              gtk_label_set_text (GTK_LABEL (label_widget), item.label);
+            }
+          else
+            {
+              gtk_label_set_text (GTK_LABEL (label_widget),
+                button->label_text ? button->label_text : "");
+            }
+        }
       g_object_notify (G_OBJECT (button), "use-stock");
     }
 }
@@ -1856,14 +1902,14 @@ gtk_button_update_state (GtkButton *button)
 static void 
 show_image_change_notify (GtkButton *button)
 {
-  GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
+  GtkWidget *image;
 
-  if (priv->image) 
+  if ((image = GTK_BUTTON_GET_CLASS (button)->get_image (button)))
     {
       if (show_image (button))
-	gtk_widget_show (priv->image);
+	gtk_widget_show (image);
       else
-	gtk_widget_hide (priv->image);
+	gtk_widget_hide (image);
     }
 }
 
@@ -1954,6 +2000,25 @@ gtk_button_grab_notify (GtkWidget *widget,
     }
 }
 
+static void
+gtk_real_button_set_image (GtkButton *button,
+                           GtkWidget *image)
+{
+  GtkButtonPrivate *priv;
+
+  priv = GTK_BUTTON_GET_PRIVATE (button);
+
+  if (priv->image && priv->image->parent)
+    gtk_container_remove (GTK_CONTAINER (priv->image->parent), priv->image);
+
+  priv->image = image;
+  priv->image_is_stock = (image == NULL);
+
+  gtk_button_construct_child (button);
+
+  g_object_notify (G_OBJECT (button), "image");
+}
+
 /**
  * gtk_button_set_image:
  * @button: a #GtkButton
@@ -1961,7 +2026,7 @@ gtk_button_grab_notify (GtkWidget *widget,
  *
  * Set the image of @button to the given widget. Note that
  * it depends on the #GtkSettings:gtk-button-images setting whether the
- * image will be displayed or not, you don't have to call
+ * image will be displayed or not, you shouldn't call
  * gtk_widget_show() on @image yourself.
  *
  * Since: 2.6
@@ -1970,22 +2035,22 @@ void
 gtk_button_set_image (GtkButton *button,
 		      GtkWidget *image)
 {
-  GtkButtonPrivate *priv;
-
   g_return_if_fail (GTK_IS_BUTTON (button));
   g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
 
-  priv = GTK_BUTTON_GET_PRIVATE (button);
+  GTK_BUTTON_GET_CLASS (button)->set_image (button, image);
 
-  if (priv->image && priv->image->parent)
-    gtk_container_remove (GTK_CONTAINER (priv->image->parent), priv->image);
-
-  priv->image = image;
-  priv->image_is_stock = (image == NULL);
+  show_image_change_notify (button);
+}
 
-  gtk_button_construct_child (button);
+static GtkWidget *
+gtk_real_button_get_image (GtkButton *button)
+{
+  GtkButtonPrivate *priv;
 
-  g_object_notify (G_OBJECT (button), "image");
+  priv = GTK_BUTTON_GET_PRIVATE (button);
+  
+  return priv->image;
 }
 
 /**
@@ -2007,9 +2072,7 @@ gtk_button_get_image (GtkButton *button)
 
   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
 
-  priv = GTK_BUTTON_GET_PRIVATE (button);
-  
-  return priv->image;
+  return GTK_BUTTON_GET_CLASS (button)->get_image (button);
 }
 
 /**
@@ -2034,7 +2097,8 @@ gtk_button_set_image_position (GtkButton       *button,
   
   priv = GTK_BUTTON_GET_PRIVATE (button);
 
-  if (priv->image_position != position)
+  if (priv->image_position != position
+    && GTK_BUTTON_GET_CLASS (button)->get_image (button) == priv->image)
     {
       priv->image_position = position;
 
diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h
index a8c1e8e..3107697 100644
--- a/gtk/gtkbutton.h
+++ b/gtk/gtkbutton.h
@@ -81,12 +81,13 @@ struct _GtkButtonClass
   void (* enter)    (GtkButton *button);
   void (* leave)    (GtkButton *button);
   void (* activate) (GtkButton *button);
-  
+  GtkWidget *   (* get_label) (GtkButton   *button);
+  void          (* set_image) (GtkButton   *button,
+                               GtkWidget   *image);
+  GtkWidget *   (* get_image) (GtkButton   *button);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
 };
 
 
