3411257e7cda8d95772728fa0e61f0f59e45d2a9
diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c
index 3140cac..622caa1 100644
--- a/gtk/gtkhbox.c
+++ b/gtk/gtkhbox.c
@@ -26,8 +26,10 @@
 
 #include <config.h>
 #include "gtkhbox.h"
+#include "gtkextendedlayout.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
+#include "gtkprivate.h"
 
 
 static void gtk_hbox_size_request  (GtkWidget      *widget,
@@ -35,8 +37,13 @@ static void gtk_hbox_size_request  (GtkWidget      *widget,
 static void gtk_hbox_size_allocate (GtkWidget      *widget,
 				    GtkAllocation  *allocation);
 
+static void gtk_hbox_extended_layout_interface_init (GtkExtendedLayoutIface *iface);
 
-G_DEFINE_TYPE (GtkHBox, gtk_hbox, GTK_TYPE_BOX)
+static void gtk_hbox_extended_layout_interface_init (GtkExtendedLayoutIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkHBox, gtk_hbox, GTK_TYPE_BOX,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
+						gtk_hbox_extended_layout_interface_init))
 
 static void
 gtk_hbox_class_init (GtkHBoxClass *class)
@@ -70,14 +77,36 @@ gtk_hbox_new (gboolean homogeneous,
 
 
 static void
-gtk_hbox_size_request (GtkWidget      *widget,
-		       GtkRequisition *requisition)
+gtk_hbox_natural_size_request (GtkWidget      *child,
+                               GtkRequisition *requisition,
+                               GtkWidget      *widget)
+{
+  GtkExtendedLayoutFeatures features = 0;
+
+  if (GTK_IS_EXTENDED_LAYOUT (child))
+    features = gtk_extended_layout_get_features ((GtkExtendedLayout*) child);
+
+  if (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT)
+    {
+      requisition->width = gtk_extended_layout_get_width_for_height (
+        (GtkExtendedLayout*) child, widget->allocation.height);
+      requisition->height = widget->allocation.height;
+    }
+  else if (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)
+    gtk_extended_layout_get_natural_size ((GtkExtendedLayout*) child, requisition);
+  else
+    gtk_widget_size_request (child, requisition);
+}
+
+static void
+gtk_hbox_real_size_request (GtkWidget      *widget,
+		            GtkRequisition *requisition,
+                            GtkChildSizeRequest  size_request_func)
 {
   GtkBox *box;
   GtkBoxChild *child;
   GList *children;
   gint nvis_children;
-  gint width;
 
   box = GTK_BOX (widget);
   requisition->width = 0;
@@ -93,18 +122,17 @@ gtk_hbox_size_request (GtkWidget      *widget,
       if (GTK_WIDGET_VISIBLE (child->widget))
 	{
 	  GtkRequisition child_requisition;
-
-	  gtk_widget_size_request (child->widget, &child_requisition);
-
-	  if (box->homogeneous)
-	    {
-	      width = child_requisition.width + child->padding * 2;
-	      requisition->width = MAX (requisition->width, width);
-	    }
-	  else
-	    {
-	      requisition->width += child_requisition.width + child->padding * 2;
-	    }
+          size_request_func (child->widget, &child_requisition, widget);
+
+          if (box->homogeneous)
+            {
+              gint width = child_requisition.width + child->padding * 2;
+              requisition->width = MAX (requisition->width, width);
+            }
+          else
+            {
+              requisition->width += child_requisition.width + child->padding * 2;
+            }
 
 	  requisition->height = MAX (requisition->height, child_requisition.height);
 
@@ -124,26 +152,26 @@ gtk_hbox_size_request (GtkWidget      *widget,
 }
 
 static void
+gtk_hbox_size_request (GtkWidget      *widget,
+		       GtkRequisition *requisition)
+{
+  gtk_hbox_real_size_request (widget, requisition, (GtkChildSizeRequest)gtk_widget_size_request);
+}
+
+static void
 gtk_hbox_size_allocate (GtkWidget     *widget,
 			GtkAllocation *allocation)
 {
   GtkBox *box;
-  GtkBoxChild *child;
-  GList *children;
-  GtkAllocation child_allocation;
+
   gint nvis_children;
   gint nexpand_children;
-  gint child_width;
-  gint width;
-  gint extra;
-  gint x;
-  GtkTextDirection direction;
+  GtkBoxChild *child;
+  GList *children;
 
   box = GTK_BOX (widget);
   widget->allocation = *allocation;
 
-  direction = gtk_widget_get_direction (widget);
-  
   nvis_children = 0;
   nexpand_children = 0;
   children = box->children;
@@ -163,148 +191,201 @@ gtk_hbox_size_allocate (GtkWidget     *widget,
 
   if (nvis_children > 0)
     {
-      if (box->homogeneous)
-	{
-	  width = (allocation->width -
-		   GTK_CONTAINER (box)->border_width * 2 -
-		   (nvis_children - 1) * box->spacing);
-	  extra = width / nvis_children;
-	}
-      else if (nexpand_children > 0)
-	{
-	  width = (gint) allocation->width - (gint) widget->requisition.width;
-	  extra = width / nexpand_children;
-	}
-      else
-	{
-	  width = 0;
-	  extra = 0;
-	}
+      GtkTextDirection direction;
+      GtkPackType packing;
+      gint border_width;
 
-      x = allocation->x + GTK_CONTAINER (box)->border_width;
-      child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width;
-      child_allocation.height = MAX (1, (gint) allocation->height - (gint) GTK_CONTAINER (box)->border_width * 2);
+      GtkAllocation child_allocation;
+      gint *natural_requisitions;
+      gint *minimum_requisitions;
 
-      children = box->children;
-      while (children)
-	{
-	  child = children->data;
-	  children = children->next;
-
-	  if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
-	    {
-	      if (box->homogeneous)
-		{
-		  if (nvis_children == 1)
-		    child_width = width;
-		  else
-		    child_width = extra;
-
-		  nvis_children -= 1;
-		  width -= extra;
-		}
-	      else
-		{
-		  GtkRequisition child_requisition;
-
-		  gtk_widget_get_child_requisition (child->widget, &child_requisition);
-
-		  child_width = child_requisition.width + child->padding * 2;
-
-		  if (child->expand)
-		    {
-		      if (nexpand_children == 1)
-			child_width += width;
-		      else
-			child_width += extra;
-
-		      nexpand_children -= 1;
-		      width -= extra;
-		    }
-		}
-
-	      if (child->fill)
-		{
-		  child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
-		  child_allocation.x = x + child->padding;
-		}
-	      else
-		{
-		  GtkRequisition child_requisition;
-
-		  gtk_widget_get_child_requisition (child->widget, &child_requisition);
-		  child_allocation.width = child_requisition.width;
-		  child_allocation.x = x + (child_width - child_allocation.width) / 2;
-		}
-
-	      if (direction == GTK_TEXT_DIR_RTL)
-		child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
-
-	      gtk_widget_size_allocate (child->widget, &child_allocation);
-
-	      x += child_width + box->spacing;
-	    }
-	}
+      gint available, natural, extra;
+      gint minimum_width, natural_width;
+      gint i;
+
+      direction = gtk_widget_get_direction (widget);
+      border_width = GTK_CONTAINER (box)->border_width;
+
+      minimum_width = widget->requisition.width;
+      natural_width = 0;
 
-      x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width;
+      natural_requisitions = g_newa (gint, nvis_children);
+      minimum_requisitions = g_newa (gint, nvis_children);
 
+      i = 0;
       children = box->children;
+
       while (children)
-	{
-	  child = children->data;
-	  children = children->next;
+        {
+          child = children->data;
+          children = children->next;
 
-	  if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
-	    {
-	      GtkRequisition child_requisition;
-	      gtk_widget_get_child_requisition (child->widget, &child_requisition);
+          if (GTK_WIDGET_VISIBLE (child->widget))
+            {
+              GtkRequisition child_requisition;
 
-              if (box->homogeneous)
-                {
-                  if (nvis_children == 1)
-                    child_width = width;
-                  else
-                    child_width = extra;
+              gtk_widget_size_request (child->widget, &child_requisition);
+              minimum_requisitions[i] = child_requisition.width;
+              natural_requisitions[i] = 0;
 
-                  nvis_children -= 1;
-                  width -= extra;
-                }
-              else
+              if (GTK_IS_EXTENDED_LAYOUT (child->widget))
                 {
-		  child_width = child_requisition.width + child->padding * 2;
+                  GtkExtendedLayout *layout = (GtkExtendedLayout*)child->widget;
+                  GtkExtendedLayoutFeatures features = gtk_extended_layout_get_features (layout);
 
-                  if (child->expand)
+                  if (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT)
                     {
-                      if (nexpand_children == 1)
-                        child_width += width;
-                      else
-                        child_width += extra;
-
-                      nexpand_children -= 1;
-                      width -= extra;
+                      gint width = gtk_extended_layout_get_width_for_height (layout, allocation->height);
+                      gint dx = minimum_requisitions[i] - width;
+
+                      if (dx > 0)
+                        {
+                          minimum_requisitions[i] = width;
+                          minimum_width -= dx;
+                        }
+                    }
+                  else if (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)
+                    {
+                      gtk_extended_layout_get_natural_size (layout, &child_requisition);
+                      natural_requisitions[i] = child_requisition.width - minimum_requisitions[i];
                     }
                 }
 
-              if (child->fill)
-                {
-                  child_allocation.width = MAX (1, (gint)child_width - (gint)child->padding * 2);
-                  child_allocation.x = x + child->padding - child_width;
-                }
-              else
+              natural_width += natural_requisitions[i++];
+            }
+        }
+
+      if (box->homogeneous)
+	{
+	  available = (allocation->width - border_width * 2 -
+		      (nvis_children - 1) * box->spacing);
+	  extra = available / nvis_children;
+          natural = 0;
+	}
+      else
+	{
+          if (nexpand_children > 0 || natural_width > 0)
+            {
+              available = (gint)allocation->width - minimum_width;
+              natural = MAX (0, MIN (available, natural_width));
+              available -= natural;
+            }
+          else
+            {
+              available = 0;
+              natural = 0;
+            }
+
+          if (nexpand_children > 0)
+	    extra = MAX (0, available / nexpand_children);
+          else
+            extra = 0;
+	}
+
+      child_allocation.y = allocation->y + border_width;
+      child_allocation.height = MAX (1, (gint) allocation->height - (gint) border_width * 2);
+
+      for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
+        {
+          gint x;
+
+          if (GTK_PACK_START == packing)
+            x = allocation->x + border_width;
+          else
+            x = allocation->x + allocation->width - border_width;
+
+          i = 0;
+          children = box->children;
+          while (children)
+            {
+              child = children->data;
+              children = children->next;
+
+              if (GTK_WIDGET_VISIBLE (child->widget))
                 {
-		  child_allocation.width = child_requisition.width;
-                  child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width;
-                }
+                  if (child->pack == packing)
+                    {
+                      gint child_width;
+
+                      if (box->homogeneous)
+                        {
+                          if (nvis_children == 1)
+                            child_width = available;
+                          else
+                            child_width = extra;
+
+                          nvis_children -= 1;
+                          available -= extra;
+                        }
+                      else
+                        {
+                          child_width = minimum_requisitions[i] + child->padding * 2;
+
+                          if (child->expand)
+                            {
+                              if (nexpand_children == 1)
+                                child_width += available;
+                              else
+                                child_width += extra;
+
+                              nexpand_children -= 1;
+                              available -= extra;
+                            }
+                        }
+
+		      if (natural_width > 0)
+                        child_width += natural * natural_requisitions[i] / natural_width;
+
+                      if (child->fill)
+                        {
+                          child_allocation.width = MAX (1, child_width - (gint)child->padding * 2);
+                          child_allocation.x = x + child->padding;
+                        }
+                      else
+                        {
+                          child_allocation.width = minimum_requisitions[i];
+                          child_allocation.x = x + (child_width - child_allocation.width) / 2;
+                        }
 
-	      if (direction == GTK_TEXT_DIR_RTL)
-		child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
+                      if (GTK_PACK_END == packing)
+                        child_allocation.x -= child_width;
 
-              gtk_widget_size_allocate (child->widget, &child_allocation);
+                      if (GTK_TEXT_DIR_RTL == direction)
+                        child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
 
-              x -= (child_width + box->spacing);
-	    }
-	}
-    }
+                      gtk_widget_size_allocate (child->widget, &child_allocation);
+
+                      if (GTK_PACK_START == packing)
+                        x += child_width + box->spacing;
+                      else
+                        x -= child_width + box->spacing;
+                    } /* packing */
+
+                  ++i;
+                } /* visible */
+            } /* while children */
+        } /* for packing */
+    } /* nvis_children */
+}
+
+static GtkExtendedLayoutFeatures
+gtk_hbox_extended_layout_get_features (GtkExtendedLayout *layout)
+{
+  return GTK_EXTENDED_LAYOUT_NATURAL_SIZE;
+}
+
+static void
+gtk_hbox_extended_layout_get_natural_size (GtkExtendedLayout *layout,
+                                           GtkRequisition    *requisition)
+{
+  gtk_hbox_real_size_request (GTK_WIDGET (layout), requisition, gtk_hbox_natural_size_request);
+}
+
+static void
+gtk_hbox_extended_layout_interface_init (GtkExtendedLayoutIface *iface)
+{
+  iface->get_features = gtk_hbox_extended_layout_get_features;
+  iface->get_natural_size = gtk_hbox_extended_layout_get_natural_size;
 }
 
 #define __GTK_HBOX_C__
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 690cc8a..5399ee5 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -104,6 +104,10 @@ gboolean _gtk_fnmatch (const char *pattern,
 #define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
 
+typedef void (*GtkChildSizeRequest) (GtkWidget      *child,
+			             GtkRequisition *requisition,
+                                     GtkWidget      *widget);
+
 G_END_DECLS
 
 #endif /* __GTK_PRIVATE_H__ */
diff --git a/gtk/gtkvbox.c b/gtk/gtkvbox.c
index 65633d8..51efca1 100644
--- a/gtk/gtkvbox.c
+++ b/gtk/gtkvbox.c
@@ -26,8 +26,10 @@
 
 #include <config.h>
 #include "gtkvbox.h"
+#include "gtkextendedlayout.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
+#include "gtkprivate.h"
 
 
 static void gtk_vbox_size_request  (GtkWidget      *widget,
@@ -35,7 +37,11 @@ static void gtk_vbox_size_request  (GtkWidget      *widget,
 static void gtk_vbox_size_allocate (GtkWidget      *widget,
 				    GtkAllocation  *allocation);
 
-G_DEFINE_TYPE (GtkVBox, gtk_vbox, GTK_TYPE_BOX)
+static void gtk_vbox_extended_layout_interface_init (GtkExtendedLayoutIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkVBox, gtk_vbox, GTK_TYPE_BOX,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
+						gtk_vbox_extended_layout_interface_init))
 
 static void
 gtk_vbox_class_init (GtkVBoxClass *class)
@@ -67,17 +73,37 @@ gtk_vbox_new (gboolean homogeneous,
   return GTK_WIDGET (vbox);
 }
 
+static void
+gtk_vbox_natural_size_request (GtkWidget      *child,
+			       GtkRequisition *requisition,
+                               GtkWidget      *widget)
+{
+  GtkExtendedLayoutFeatures features = 0;
+
+  if (GTK_IS_EXTENDED_LAYOUT (child))
+    features = gtk_extended_layout_get_features ((GtkExtendedLayout*) child);
+
+  if (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH)
+    {
+      requisition->width = widget->allocation.width;
+      requisition->height = gtk_extended_layout_get_height_for_width (
+        (GtkExtendedLayout*) child, widget->allocation.width);
+    }
+  else if (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)
+    gtk_extended_layout_get_natural_size ((GtkExtendedLayout*) child, requisition);
+  else
+    gtk_widget_size_request (child, requisition);
+}
 
 static void
-gtk_vbox_size_request (GtkWidget      *widget,
-		       GtkRequisition *requisition)
+gtk_vbox_real_size_request (GtkWidget           *widget,
+		            GtkRequisition      *requisition,
+                            GtkChildSizeRequest  size_request_func)
 {
   GtkBox *box;
   GtkBoxChild *child;
-  GtkRequisition child_requisition;
   GList *children;
   gint nvis_children;
-  gint height;
 
   box = GTK_BOX (widget);
   requisition->width = 0;
@@ -92,11 +118,12 @@ gtk_vbox_size_request (GtkWidget      *widget,
 
       if (GTK_WIDGET_VISIBLE (child->widget))
 	{
-	  gtk_widget_size_request (child->widget, &child_requisition);
+          GtkRequisition child_requisition;
+          size_request_func (child->widget, &child_requisition, widget);
 
 	  if (box->homogeneous)
 	    {
-	      height = child_requisition.height + child->padding * 2;
+              gint height = child_requisition.height + child->padding * 2;
 	      requisition->height = MAX (requisition->height, height);
 	    }
 	  else
@@ -122,19 +149,22 @@ gtk_vbox_size_request (GtkWidget      *widget,
 }
 
 static void
+gtk_vbox_size_request (GtkWidget      *widget,
+		       GtkRequisition *requisition)
+{
+  gtk_vbox_real_size_request (widget, requisition, (GtkChildSizeRequest)gtk_widget_size_request);
+}
+
+static void
 gtk_vbox_size_allocate (GtkWidget     *widget,
 			GtkAllocation *allocation)
 {
   GtkBox *box;
-  GtkBoxChild *child;
-  GList *children;
-  GtkAllocation child_allocation;
+
   gint nvis_children;
   gint nexpand_children;
-  gint child_height;
-  gint height;
-  gint extra;
-  gint y;
+  GtkBoxChild *child;
+  GList *children;
 
   box = GTK_BOX (widget);
   widget->allocation = *allocation;
@@ -158,141 +188,196 @@ gtk_vbox_size_allocate (GtkWidget     *widget,
 
   if (nvis_children > 0)
     {
-      if (box->homogeneous)
-	{
-	  height = (allocation->height -
-		   GTK_CONTAINER (box)->border_width * 2 -
-		   (nvis_children - 1) * box->spacing);
-	  extra = height / nvis_children;
-	}
-      else if (nexpand_children > 0)
-	{
-	  height = (gint) allocation->height - (gint) widget->requisition.height;
-	  extra = height / nexpand_children;
-	}
-      else
-	{
-	  height = 0;
-	  extra = 0;
-	}
+      GtkPackType packing;
+      gint border_width;
 
-      y = allocation->y + GTK_CONTAINER (box)->border_width;
-      child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width;
-      child_allocation.width = MAX (1, (gint) allocation->width - (gint) GTK_CONTAINER (box)->border_width * 2);
+      GtkAllocation child_allocation;
+      gint *natural_requisitions;
+      gint *minimum_requisitions;
 
-      children = box->children;
-      while (children)
-	{
-	  child = children->data;
-	  children = children->next;
+      gint available, natural, extra;
+      gint minimum_height, natural_height;
+      gint i;
 
-	  if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
-	    {
-	      if (box->homogeneous)
-		{
-		  if (nvis_children == 1)
-		    child_height = height;
-		  else
-		    child_height = extra;
-
-		  nvis_children -= 1;
-		  height -= extra;
-		}
-	      else
-		{
-		  GtkRequisition child_requisition;
-
-		  gtk_widget_get_child_requisition (child->widget, &child_requisition);
-		  child_height = child_requisition.height + child->padding * 2;
-
-		  if (child->expand)
-		    {
-		      if (nexpand_children == 1)
-			child_height += height;
-		      else
-			child_height += extra;
-
-		      nexpand_children -= 1;
-		      height -= extra;
-		    }
-		}
-
-	      if (child->fill)
-		{
-		  child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
-		  child_allocation.y = y + child->padding;
-		}
-	      else
-		{
-		  GtkRequisition child_requisition;
-
-		  gtk_widget_get_child_requisition (child->widget, &child_requisition);
-		  child_allocation.height = child_requisition.height;
-		  child_allocation.y = y + (child_height - child_allocation.height) / 2;
-		}
-
-	      gtk_widget_size_allocate (child->widget, &child_allocation);
-
-	      y += child_height + box->spacing;
-	    }
-	}
+      border_width = GTK_CONTAINER (box)->border_width;
 
-      y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width;
+      minimum_height = widget->requisition.height;
+      natural_height = 0;
 
+      natural_requisitions = g_newa (gint, nvis_children);
+      minimum_requisitions = g_newa (gint, nvis_children);
+
+      i = 0;
       children = box->children;
+
       while (children)
-	{
-	  child = children->data;
-	  children = children->next;
+        {
+          child = children->data;
+          children = children->next;
 
-	  if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
-	    {
-	      GtkRequisition child_requisition;
-	      gtk_widget_get_child_requisition (child->widget, &child_requisition);
+          if (GTK_WIDGET_VISIBLE (child->widget))
+            {
+              GtkRequisition child_requisition;
 
-              if (box->homogeneous)
-                {
-                  if (nvis_children == 1)
-                    child_height = height;
-                  else
-                    child_height = extra;
+              gtk_widget_size_request (child->widget, &child_requisition);
+              minimum_requisitions[i] = child_requisition.height;
+              natural_requisitions[i] = 0;
 
-                  nvis_children -= 1;
-                  height -= extra;
-                }
-              else
+              if (GTK_IS_EXTENDED_LAYOUT (child->widget))
                 {
-		  child_height = child_requisition.height + child->padding * 2;
+                  GtkExtendedLayout *layout = (GtkExtendedLayout*)child->widget;
+                  GtkExtendedLayoutFeatures features = gtk_extended_layout_get_features (layout);
 
-                  if (child->expand)
+                  if (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH)
                     {
-                      if (nexpand_children == 1)
-                        child_height += height;
-                      else
-                        child_height += extra;
-
-                      nexpand_children -= 1;
-                      height -= extra;
+                      gint height = gtk_extended_layout_get_height_for_width (layout, allocation->width);
+                      gint dy = minimum_requisitions[i] - height;
+
+                      if (dy > 0)
+                        {
+                          minimum_requisitions[i] = height;
+                          minimum_height -= dy;
+                        }
+                    }
+                  else if (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)
+                    {
+                      gtk_extended_layout_get_natural_size (layout, &child_requisition);
+                      natural_requisitions[i] = child_requisition.height - minimum_requisitions[i];
                     }
                 }
 
-              if (child->fill)
-                {
-                  child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
-                  child_allocation.y = y + child->padding - child_height;
-                }
-              else
+              natural_height += natural_requisitions[i++];
+            }
+        }
+
+      if (box->homogeneous)
+	{
+	  available = (allocation->height - border_width * 2 -
+		      (nvis_children - 1) * box->spacing);
+	  extra = available / nvis_children;
+          natural = 0;
+	}
+      else
+	{
+          if (nexpand_children > 0 || natural_height > 0)
+            {
+	      available = (gint)allocation->height - minimum_height;
+              natural = MAX (0, MIN (available, natural_height));
+              available -= natural;
+            }
+          else
+            {
+              available = 0;
+              natural = 0;
+            }
+
+          if (nexpand_children > 0)
+	    extra = MAX (0, available / nexpand_children);
+          else
+            extra = 0;
+	}
+
+      child_allocation.x = allocation->x + border_width;
+      child_allocation.width = MAX (1, (gint) allocation->width - (gint) border_width * 2);
+
+      for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
+        {
+          gint y;
+
+          if (GTK_PACK_START == packing)
+            y = allocation->y + border_width;
+          else
+            y = allocation->y + allocation->height - border_width;
+
+          i = 0;
+          children = box->children;
+          while (children)
+            {
+              child = children->data;
+              children = children->next;
+
+              if (GTK_WIDGET_VISIBLE (child->widget))
                 {
-		  child_allocation.height = child_requisition.height;
-                  child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height;
-                }
+                  if (child->pack == packing)
+                    {
+                      gint child_height;
+
+                      if (box->homogeneous)
+                        {
+                          if (nvis_children == 1)
+                            child_height = available;
+                          else
+                            child_height = extra;
+
+                          nvis_children -= 1;
+                          available -= extra;
+                        }
+                      else
+                        {
+                          child_height = minimum_requisitions[i] + child->padding * 2;
+
+                          if (child->expand)
+                            {
+                              if (nexpand_children == 1)
+                                child_height += available;
+                              else
+                                child_height += extra;
+
+                              nexpand_children -= 1;
+                              available -= extra;
+                            }
+                        }
+
+		      if (natural_height > 0)
+                        child_height += natural * natural_requisitions[i] / natural_height;
+
+                      if (child->fill)
+                        {
+                          child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
+                          child_allocation.y = y + child->padding;
+                        }
+                      else
+                        {
+                          child_allocation.height = minimum_requisitions[i];
+                          child_allocation.y = y + (child_height - child_allocation.height) / 2;
+                        }
 
-              gtk_widget_size_allocate (child->widget, &child_allocation);
+                      if (GTK_PACK_END == packing)
+                        child_allocation.y -= child_height;
 
-              y -= (child_height + box->spacing);
-	    }
-	}
-    }
+                      gtk_widget_size_allocate (child->widget, &child_allocation);
+
+                      if (GTK_PACK_START == packing)
+	                y += child_height + box->spacing;
+                      else
+                        y -= child_height + box->spacing;
+                    } /* packing */
+
+                  ++i;
+                } /* visible */
+            } /* while children */
+        } /* for packing */
+    } /* nvis_children */
+}
+
+static GtkExtendedLayoutFeatures
+gtk_vbox_extended_layout_get_features (GtkExtendedLayout *layout)
+{
+  return GTK_EXTENDED_LAYOUT_NATURAL_SIZE;
+}
+
+static void
+gtk_vbox_extended_layout_get_natural_size (GtkExtendedLayout *layout,
+                                           GtkRequisition    *requisition)
+{
+  gtk_vbox_real_size_request (GTK_WIDGET (layout), requisition, gtk_vbox_natural_size_request);
+}
+
+static void
+gtk_vbox_extended_layout_interface_init (GtkExtendedLayoutIface *iface)
+{
+  iface->get_features = gtk_vbox_extended_layout_get_features;
+  iface->get_natural_size = gtk_vbox_extended_layout_get_natural_size;
 }
 
 #define __GTK_VBOX_C__
