Index: gtk/gtkhbbox.c
===================================================================
--- gtk/gtkhbbox.c	(Revision 20677)
+++ gtk/gtkhbbox.c	(Arbeitskopie)
@@ -96,7 +96,6 @@ gtk_hbutton_box_get_spacing_default (voi
   return default_spacing;
 }
 
-
 /* get default value for layout style */
 
 GtkButtonBoxStyle
@@ -105,157 +104,305 @@ gtk_hbutton_box_get_layout_default (void
   return default_layout_style;
 }
 
+/* This function is pretty much an abomination against reason.
+   More or less it's supposed to:
+   - If an homogeneous layout is possible:
+   + primary_width and secondary_width will be the sizes of the primary and
+     secondary groups (basically the homogeneous width times the number of items).
+   + children_widths will contain the homogeneous width for all items
+
+   - If an homogeneous layout is NOT possible:
+   + primary_width and secondary_width will contain the sum of the widths for each
+     group
+   + children_width will contain the heterogeneous width of each button, being this
+     its requisition plus any possible extra width added
+
+   All the other parameters come straight from _gtk_button_box_child_requisition
+*/
+static gint*
+gtk_hbutton_box_get_children_sizes (GtkWidget     *widget,
+                                    GtkAllocation *allocation,
+                                    gint          *primary_width,
+                                    gint          *secondary_width,
+                                    gint          *child_height,
+                                    gint          *nvis_children,
+                                    gint          *n_secondaries)
+{
+  gint *children_widths;
+  gint child_width;
+  gint total_width;
+  gint total_spacing;
+  gint i;
+
+  _gtk_button_box_child_requisition (widget,
+                                     nvis_children,
+                                     n_secondaries,
+                                     &child_width,
+                                     child_height);
+  if (*nvis_children == 0)
+    {
+      *primary_width = *secondary_width = *n_secondaries = 0;
+      return NULL;
+    }
+
+  children_widths = g_slice_alloc (sizeof (gint) * (*nvis_children));
+
+  total_width = *nvis_children * child_width;
+  total_spacing = (*nvis_children - 1) * GTK_BOX (widget)->spacing;
+
+  if (!gtk_box_get_homogeneous (GTK_BOX (widget)) ||
+      (allocation != NULL && total_width + total_spacing > allocation->width))
+    {
+      /* want heterogeneous allocation, or homogeneous allocation too wide to
+       * fit container, shrink the buttons to their size requisition
+       */
+      GList *children;
+      gint extra_space;
+      gint child_min_width, ipad_width;
+
+      _gtk_button_box_child_size_props (GTK_BUTTON_BOX (widget),
+                                        &child_min_width, NULL,
+                                        &ipad_width, NULL);
+
+      *primary_width = 0;
+      *secondary_width = 0;
+      children = GTK_BOX (widget)->children;
+      i = 0;
+
+      while (children)
+        {
+          GtkBoxChild *child = children->data;
+          GtkWidget *child_widget = child->widget;
+          children = children->next;
+
+          if (GTK_WIDGET_VISIBLE (child_widget))
+            {
+              GtkRequisition req;
+
+              gtk_widget_size_request (child_widget, &req);
+              req.width = MAX (req.width + ipad_width, child_min_width);
+
+              if (!child->is_secondary)
+                *primary_width += req.width;
+              else
+                *secondary_width += req.width;
+
+              children_widths[i++] = req.width;
+            }
+        }
+
+      total_width = *primary_width + *secondary_width;
+
+      /* Distribute the extra space between children when wanting to have
+       * homogeneous allocation
+       */
+      if (allocation && gtk_box_get_homogeneous (GTK_BOX (widget)))
+        extra_space = allocation->width - (total_width + total_spacing);
+      else
+        extra_space = 0;
+
+      /* If extra space available, distribute it evenly to the buttons.
+       * XXX: Smallest buttons should probably get the biggest share instead,
+       *      to maximize button sizes and approximate homogeneous allocation.
+       *
+       * XXX: If extra_space is < 0 the layout will be broken (label truncation
+       *      etc.) but we should still shrink the children
+       */
+      if (extra_space > 0)
+        {
+          gint extra;
+
+          extra = extra_space / *nvis_children;
+          children = GTK_BOX (widget)->children;
+          i = 0;
+
+          while (children)
+            {
+              GtkBoxChild *child = children->data;
+              GtkWidget *child_widget = child->widget;
+              children = children->next;
+
+              if (GTK_WIDGET_VISIBLE (child_widget))
+                {
+                  children_widths[i++] += extra;
+
+                  if (! child->is_secondary)
+                    *primary_width += extra;
+                  else
+                    *secondary_width += extra;
+                }
+            }
+        }
+    }
+  else
+    {
+      /* homogeneous allocation */
+      *primary_width = child_width * (*nvis_children - *n_secondaries);
+      *secondary_width = child_width * *n_secondaries;
+      for (i = 0; i < *nvis_children; i++)
+        children_widths[i] = child_width;
+    }
+
+  return children_widths;
+}
 
-  
 static void
 gtk_hbutton_box_size_request (GtkWidget      *widget,
 			      GtkRequisition *requisition)
 {
   GtkBox *box;
   GtkButtonBox *bbox;
-  gint nvis_children;
-  gint child_width;
+  gint primary_width;
+  gint secondary_width;
   gint child_height;
+  gint nvis_children;
+  gint n_secondaries;
+  gint *children_widths;
   gint spacing;
   GtkButtonBoxStyle layout;
-  
+
   box = GTK_BOX (widget);
   bbox = GTK_BUTTON_BOX (widget);
 
   spacing = box->spacing;
   layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
-	  ? bbox->layout_style : default_layout_style;
-  
-  _gtk_button_box_child_requisition (widget,
-                                     &nvis_children,
-				     NULL,
-                                     &child_width,
-                                     &child_height);
+         ? bbox->layout_style : default_layout_style;
+
+  children_widths = gtk_hbutton_box_get_children_sizes (widget,
+                                                        NULL,
+                                                        &primary_width,
+                                                        &secondary_width,
+                                                        &child_height,
+                                                        &nvis_children,
+                                                        &n_secondaries);
+  g_slice_free1 (sizeof (gint) * nvis_children, children_widths);
 
   if (nvis_children == 0)
-  {
-    requisition->width = 0; 
-    requisition->height = 0;
-  }
+    {
+      requisition->width = 0;
+      requisition->height = 0;
+    }
   else
-  {
-    switch (layout)
     {
-    case GTK_BUTTONBOX_SPREAD:
-      requisition->width =
-	      nvis_children*child_width + ((nvis_children+1)*spacing);
-      break;
-    case GTK_BUTTONBOX_EDGE:
-    case GTK_BUTTONBOX_START:
-    case GTK_BUTTONBOX_END:
-    case GTK_BUTTONBOX_CENTER:
-      requisition->width = nvis_children*child_width + ((nvis_children-1)*spacing);
-      break;
-    default:
-      g_assert_not_reached();
-      break;
+      switch (layout)
+        {
+        case GTK_BUTTONBOX_SPREAD:
+          requisition->width = primary_width + secondary_width + ((nvis_children + 1) * spacing);
+          break;
+        case GTK_BUTTONBOX_EDGE:
+        case GTK_BUTTONBOX_START:
+        case GTK_BUTTONBOX_END:
+        case GTK_BUTTONBOX_CENTER:
+          requisition->width = primary_width + secondary_width + ((nvis_children - 1) * spacing);
+          break;
+        default:
+          g_assert_not_reached();
+          break;
+        }
+
+      requisition->height = child_height;
     }
-	  
-    requisition->height = child_height;
-  }
-	  
+
   requisition->width += GTK_CONTAINER (box)->border_width * 2;
   requisition->height += GTK_CONTAINER (box)->border_width * 2;
 }
 
-
-
 static void
 gtk_hbutton_box_size_allocate (GtkWidget     *widget,
 			       GtkAllocation *allocation)
 {
-  GtkBox *base_box;
-  GtkButtonBox *box;
-  GtkBoxChild *child;
+  gint primary_width, secondary_width, child_height;
+  gint *children_widths;
+  gint x, y;
+  gint secondary_x;
+  gint nvis_children, n_secondaries, childspacing;
+  gint primary_spacing, secondary_spacing;
+  gint n_primaries, inner_width;
   GList *children;
-  GtkAllocation child_allocation;
-  gint nvis_children;
-  gint n_secondaries;
-  gint child_width;
-  gint child_height;
-  gint x = 0;
-  gint secondary_x = 0;
-  gint y = 0;
-  gint width;
-  gint childspace;
-  gint childspacing = 0;
+  GtkBoxChild *child;
+  gint i;
   GtkButtonBoxStyle layout;
-  gint spacing;
-  
-  base_box = GTK_BOX (widget);
-  box = GTK_BUTTON_BOX (widget);
-  spacing = base_box->spacing;
-  layout = box->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
-	  ? box->layout_style : default_layout_style;
-  _gtk_button_box_child_requisition (widget,
-                                     &nvis_children,
-				     &n_secondaries,
-                                     &child_width,
-                                     &child_height);
+
   widget->allocation = *allocation;
-  width = allocation->width - GTK_CONTAINER (box)->border_width*2;
+
+  children_widths = gtk_hbutton_box_get_children_sizes (widget,
+                                                        &widget->allocation,
+							&primary_width,
+							&secondary_width,
+							&child_height,
+							&nvis_children,
+							&n_secondaries);
+  if (nvis_children == 0)
+    return;
+
+  n_primaries = nvis_children - n_secondaries;
+  inner_width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
+
+  layout = GTK_BUTTON_BOX (widget)->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
+    ? GTK_BUTTON_BOX (widget)->layout_style : default_layout_style;
+
   switch (layout)
-  {
-  case GTK_BUTTONBOX_SPREAD:
-    childspacing = (width - (nvis_children * child_width)) / (nvis_children + 1);
-    x = allocation->x + GTK_CONTAINER (box)->border_width + childspacing;
-    secondary_x = x + ((nvis_children - n_secondaries) * (child_width + childspacing));
-    break;
-  case GTK_BUTTONBOX_EDGE:
-    if (nvis_children >= 2)
-      {
-	childspacing = (width - (nvis_children * child_width)) / (nvis_children - 1);
-	x = allocation->x + GTK_CONTAINER (box)->border_width;
-	secondary_x = x + ((nvis_children - n_secondaries) * (child_width + childspacing));
-      }
-    else
-      {
-	/* one or zero children, just center */
-        childspacing = width;
-	x = secondary_x = allocation->x + (allocation->width - child_width) / 2;
-      }
-    break;
-  case GTK_BUTTONBOX_START:
-    childspacing = spacing;
-    x = allocation->x + GTK_CONTAINER (box)->border_width;
-    secondary_x = allocation->x + allocation->width 
-      - child_width * n_secondaries
-      - spacing * (n_secondaries - 1)
-      - GTK_CONTAINER (box)->border_width;
-    break;
-  case GTK_BUTTONBOX_END:
-    childspacing = spacing;
-    x = allocation->x + allocation->width 
-      - child_width * (nvis_children - n_secondaries)
-      - spacing * (nvis_children - n_secondaries - 1)
-      - GTK_CONTAINER (box)->border_width;
-    secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
-    break;
-  case GTK_BUTTONBOX_CENTER:
-    childspacing = spacing;
-    x = allocation->x + 
-      (allocation->width
-       - (child_width * (nvis_children - n_secondaries)
-	  + spacing * (nvis_children - n_secondaries - 1)))/2
-      + (n_secondaries * child_width + n_secondaries * spacing)/2;
-    secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
-    break;
-  default:
-    g_assert_not_reached();
-    break;
-  }
+    {
+    case GTK_BUTTONBOX_SPREAD:
+      childspacing = (inner_width
+                      - (primary_width + secondary_width)) / (nvis_children + 1);
+      primary_spacing = childspacing * (n_primaries - 1);
+      x = allocation->x + GTK_CONTAINER (widget)->border_width + childspacing;
+      secondary_x = x + primary_width + primary_spacing + childspacing;
+      break;
+    case GTK_BUTTONBOX_EDGE:
+      if (nvis_children >= 2)
+        {
+          childspacing = (inner_width
+                          - (primary_width + secondary_width)) / (nvis_children - 1);
+          primary_spacing = childspacing * (n_primaries - 1);
+          x = allocation->x + GTK_CONTAINER (widget)->border_width;
+          secondary_x = x + primary_width + primary_spacing + childspacing;
+        }
+      else
+        {
+          /* one or zero children, just center */
+          childspacing = inner_width;
+          x = secondary_x = allocation->x + (allocation->width - primary_width) / 2;
+        }
+      break;
+    case GTK_BUTTONBOX_START:
+      childspacing = GTK_BOX (widget)->spacing;
+      secondary_spacing = childspacing * (n_secondaries - 1);
+      x = allocation->x + GTK_CONTAINER (widget)->border_width;
+      secondary_x = allocation->x + allocation->width
+        - secondary_width
+        - secondary_spacing
+        - GTK_CONTAINER (widget)->border_width;
+      break;
+    case GTK_BUTTONBOX_END:
+      childspacing = GTK_BOX (widget)->spacing;
+      primary_spacing = childspacing * (n_primaries - 1);
+      x = allocation->x + allocation->width
+        - primary_width
+        - primary_spacing
+        - GTK_CONTAINER (widget)->border_width;
+      secondary_x = allocation->x + GTK_CONTAINER (widget)->border_width;
+      break;
+    case GTK_BUTTONBOX_CENTER:
+      childspacing = GTK_BOX (widget)->spacing;
+      primary_spacing = childspacing * (n_primaries - 1);
+      secondary_spacing = childspacing * (n_secondaries - 1);
+      x = allocation->x +
+        (allocation->width
+         - (primary_width + primary_spacing))/2
+         + (secondary_width + secondary_spacing + childspacing)/2;
+      secondary_x = allocation->x + GTK_CONTAINER (widget)->border_width;
+      break;
+    default:
+      g_assert_not_reached();
+      break;
+    }
 
-		  
   y = allocation->y + (allocation->height - child_height) / 2;
-  childspace = child_width + childspacing;
 
-  children = GTK_BOX (box)->children;
-	  
+  children = GTK_BOX (widget)->children;
+  i = 0;
   while (children)
     {
       child = children->data;
@@ -263,28 +410,33 @@ gtk_hbutton_box_size_allocate (GtkWidget
 
       if (GTK_WIDGET_VISIBLE (child->widget))
 	{
+          GtkAllocation child_allocation;
+          gint child_width = children_widths[i++];
+
 	  child_allocation.width = child_width;
 	  child_allocation.height = child_height;
 	  child_allocation.y = y;
-	  
+
 	  if (child->is_secondary)
 	    {
 	      child_allocation.x = secondary_x;
-	      secondary_x += childspace;
+	      secondary_x += child_width + childspacing;
 	    }
 	  else
 	    {
 	      child_allocation.x = x;
-	      x += childspace;
+	      x += child_width + childspacing;
 	    }
 
 	  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
 	    child_allocation.x = (allocation->x + allocation->width) - (child_allocation.x + child_width - allocation->x);
-	  
+
 	  gtk_widget_size_allocate (child->widget, &child_allocation);
 	}
     }
+
+  g_slice_free1 (sizeof (gint) * nvis_children, children_widths);
 }
-  
+
 #define __GTK_HBUTTON_BOX_C__
 #include "gtkaliasdef.c"
Index: gtk/gtkbbox.c
===================================================================
--- gtk/gtkbbox.c	(Revision 20677)
+++ gtk/gtkbbox.c	(Arbeitskopie)
@@ -384,6 +384,45 @@ gtk_button_box_set_child_secondary (GtkB
     gtk_widget_queue_resize (child);
 }
 
+void
+_gtk_button_box_child_size_props (GtkButtonBox *bbox,
+                                  gint         *child_min_width,
+                                  gint         *child_min_height,
+                                  gint         *ipad_width,
+                                  gint         *ipad_height)
+{
+  gint width_default;
+  gint height_default;
+  gint ipad_x_default;
+  gint ipad_y_default;
+  gint ipad_x;
+  gint ipad_y;
+
+  gtk_widget_style_get (GTK_WIDGET (bbox),
+                        "child-min-width", &width_default,
+                        "child-min-height", &height_default,
+                        "child-internal-pad-x", &ipad_x_default,
+                        "child-internal-pad-y", &ipad_y_default,
+                        NULL);
+
+  if (child_min_width)
+    *child_min_width = bbox->child_min_width != GTK_BUTTONBOX_DEFAULT
+                       ? bbox->child_min_width : width_default;
+  if (child_min_height)
+    *child_min_height = bbox->child_min_height != GTK_BUTTONBOX_DEFAULT
+                        ? bbox->child_min_height : height_default;
+
+  ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
+           ? bbox->child_ipad_x : ipad_x_default;
+  ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
+           ? bbox->child_ipad_y : ipad_y_default;
+
+  if (ipad_width)
+    *ipad_width = 2 * ipad_x;
+  if (ipad_height)
+    *ipad_height = 2 * ipad_y;
+}
+
 /* Ask children how much space they require and round up 
    to match minimum size and internal padding.
    Returns the size each single child should have. */
@@ -404,44 +443,22 @@ _gtk_button_box_child_requisition (GtkWi
   GtkRequisition child_requisition;
   gint ipad_w;
   gint ipad_h;
-  gint width_default;
-  gint height_default;
-  gint ipad_x_default;
-  gint ipad_y_default;
-  
   gint child_min_width;
   gint child_min_height;
-  gint ipad_x;
-  gint ipad_y;
-  
+
   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
 
   bbox = GTK_BUTTON_BOX (widget);
 
-  gtk_widget_style_get (widget,
-                        "child-min-width", &width_default,
-                        "child-min-height", &height_default,
-                        "child-internal-pad-x", &ipad_x_default,
-                        "child-internal-pad-y", &ipad_y_default, 
-			NULL);
-  
-  child_min_width = bbox->child_min_width   != GTK_BUTTONBOX_DEFAULT
-	  ? bbox->child_min_width : width_default;
-  child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
-	  ? bbox->child_min_height : height_default;
-  ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
-	  ? bbox->child_ipad_x : ipad_x_default;
-  ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
-	  ? bbox->child_ipad_y : ipad_y_default;
+  _gtk_button_box_child_size_props (bbox, &child_min_width, &child_min_height,
+                                    &ipad_w, &ipad_h);
 
   nchildren = 0;
   nsecondaries = 0;
   children = GTK_BOX(bbox)->children;
   needed_width = child_min_width;
-  needed_height = child_min_height;  
-  ipad_w = ipad_x * 2;
-  ipad_h = ipad_y * 2;
-  
+  needed_height = child_min_height;
+
   while (children)
     {
       child = children->data;
