[gtk+] Fixed problems with combination of height-for-width apis and alignment/margin vfuncs adjust_size_req



commit d26ac6421b7163bccbd635ee0b1b7745263a3f9d
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Oct 23 00:04:46 2010 +0900

    Fixed problems with combination of height-for-width apis and
    alignment/margin vfuncs adjust_size_request/allocation
    
    Now get_height_for_width() will internally update the for_width
    before passing it to the real height_for_width() vfunc, allowing
    margins and extra space for alignments to be stripped, thus requesting
    sufficient height for greater than natural widths (and also accounting
    for margins properly). Test case adjusted in testadjustsize to ensure
    proper behavior.

 gtk/gtkcontainer.c     |   51 ++++++++-----
 gtk/gtksizerequest.c   |   49 +++++++++++--
 gtk/gtkwidget.c        |  191 ++++++++++++++++++++----------------------------
 gtk/gtkwidget.h        |   11 ++-
 tests/testadjustsize.c |    5 +-
 5 files changed, 164 insertions(+), 143 deletions(-)
---
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 0cfedfb..5b2d3ba 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -323,11 +323,13 @@ static void     gtk_container_map                  (GtkWidget         *widget);
 static void     gtk_container_unmap                (GtkWidget         *widget);
 static void     gtk_container_adjust_size_request  (GtkWidget         *widget,
                                                     GtkOrientation     orientation,
-                                                    gint               for_size,
                                                     gint              *minimum_size,
                                                     gint              *natural_size);
 static void     gtk_container_adjust_size_allocation (GtkWidget       *widget,
-                                                      GtkAllocation   *allocation);
+                                                      GtkOrientation   orientation,
+                                                      gint            *natural_size,
+                                                      gint            *allocated_pos,
+                                                      gint            *allocated_size);
 
 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
 							  GtkWidget    *child);
@@ -1776,7 +1778,6 @@ gtk_container_resize_children (GtkContainer *container)
 static void
 gtk_container_adjust_size_request (GtkWidget         *widget,
                                    GtkOrientation     orientation,
-                                   gint               for_size,
                                    gint              *minimum_size,
                                    gint              *natural_size)
 {
@@ -1797,28 +1798,33 @@ gtk_container_adjust_size_request (GtkWidget         *widget,
   /* chain up last so gtk_widget_set_size_request() values
    * will have a chance to overwrite our border width.
    */
-  parent_class->adjust_size_request (widget, orientation, for_size,
+  parent_class->adjust_size_request (widget, orientation, 
                                      minimum_size, natural_size);
 }
 
 static void
 gtk_container_adjust_size_allocation (GtkWidget         *widget,
-                                      GtkAllocation     *allocation)
+                                      GtkOrientation     orientation,
+                                      gint              *natural_size,
+                                      gint              *allocated_pos,
+                                      gint              *allocated_size)
 {
   GtkContainer *container;
   int border_width;
 
   container = GTK_CONTAINER (widget);
 
-  parent_class->adjust_size_allocation (widget, allocation);
-
   if (!GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
-    return;
+    {
+      parent_class->adjust_size_allocation (widget, orientation,
+					    natural_size, allocated_pos,
+					    allocated_size);
+      return;
+    }
 
   border_width = container->priv->border_width;
 
-  allocation->width -= border_width * 2;
-  allocation->height -= border_width * 2;
+  *allocated_size -= border_width * 2;
 
   /* If we get a pathological too-small allocation to hold
    * even the border width, leave all allocation to the actual
@@ -1828,23 +1834,26 @@ gtk_container_adjust_size_allocation (GtkWidget         *widget,
    * As long as we have space, set x,y properly.
    */
 
-  if (allocation->width < 1)
+  if (*allocated_size < 1)
     {
-      allocation->width += border_width * 2;
+      *allocated_size += border_width * 2;
     }
   else
     {
-      allocation->x += border_width;
+      *allocated_pos += border_width;
+      *natural_size -= border_width * 2;
     }
 
-  if (allocation->height < 1)
-    {
-      allocation->height += border_width * 2;
-    }
-  else
-    {
-      allocation->y += border_width;
-    }
+  /* Chain up to GtkWidgetClass *after* removing our border width from
+   * the proposed allocation size. This is because it's possible that the
+   * widget was allocated more space than it needs in a said orientation,
+   * if GtkWidgetClass does any alignments and thus limits the size to the 
+   * natural size... then we need that to be done *after* removing any margins 
+   * and padding values.
+   */
+  parent_class->adjust_size_allocation (widget, orientation,
+					natural_size, allocated_pos,
+					allocated_size);
 }
 
 /**
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index 55979f4..da91d0c 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -226,20 +226,56 @@ compute_size_for_orientation (GtkWidget         *request,
           requisition_size = requisition.width;
 
           if (for_size < 0)
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
+            {
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
+            }
           else
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size, 
-                                                                                  &min_size, &nat_size);
+            {
+              int ignored_position = 0;
+              int natural_height;
+
+	      /* Pull the base natural height from the cache as it's needed to adjust 
+	       * the proposed 'for_size' */
+	      gtk_widget_get_preferred_height (widget, NULL, &natural_height);
+
+              /* convert for_size to unadjusted height (for_size is a proposed allocation) */
+              GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
+                                                                      GTK_ORIENTATION_VERTICAL,
+                                                                      &natural_height,
+                                                                      &ignored_position,
+                                                                      &for_size);
+
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size,
+                                                                              &min_size, &nat_size);
+            }
         }
       else
         {
           requisition_size = requisition.height;
 
           if (for_size < 0)
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
+            {
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
+            }
           else
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size, 
-                                                                                  &min_size, &nat_size);
+            {
+              int ignored_position = 0;
+              int natural_width;
+
+	      /* Pull the base natural width from the cache as it's needed to adjust 
+	       * the proposed 'for_size' */
+	      gtk_widget_get_preferred_width (widget, NULL, &natural_width);
+
+              /* convert for_size to unadjusted width (for_size is a proposed allocation) */
+              GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
+                                                                      GTK_ORIENTATION_HORIZONTAL,
+                                                                      &natural_width,
+                                                                      &ignored_position,
+                                                                      &for_size);
+
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size,
+                                                                              &min_size, &nat_size);
+            }
         }
       pop_recursion_check (request, orientation);
 
@@ -270,7 +306,6 @@ compute_size_for_orientation (GtkWidget         *request,
                                                            orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                                                            GTK_ORIENTATION_HORIZONTAL :
                                                            GTK_ORIENTATION_VERTICAL,
-                                                           cached_size->for_size,
                                                            &adjusted_min,
                                                            &adjusted_natural);
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 6d7faf8..43f8c37 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -685,11 +685,13 @@ static void             gtk_widget_queue_tooltip_query          (GtkWidget *widg
 
 static void             gtk_widget_real_adjust_size_request     (GtkWidget         *widget,
                                                                  GtkOrientation     orientation,
-                                                                 gint               for_size,
                                                                  gint              *minimum_size,
                                                                  gint              *natural_size);
 static void             gtk_widget_real_adjust_size_allocation  (GtkWidget         *widget,
-                                                                 GtkAllocation     *allocation);
+                                                                 GtkOrientation     orientation,
+                                                                 gint              *natural_size,
+                                                                 gint              *allocated_pos,
+                                                                 gint              *allocated_size);
 
 static void gtk_widget_set_usize_internal (GtkWidget          *widget,
 					   gint                width,
@@ -4609,6 +4611,8 @@ gtk_widget_size_allocate (GtkWidget	*widget,
   gboolean alloc_needed;
   gboolean size_changed;
   gboolean position_changed;
+  gint natural_width, natural_height;
+  gint min_width, min_height;
 
   priv = widget->priv;
 
@@ -4645,7 +4649,37 @@ gtk_widget_size_allocate (GtkWidget	*widget,
   real_allocation = *allocation;
 
   adjusted_allocation = real_allocation;
-  GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, &adjusted_allocation);
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+    {
+      /* Go ahead and request the height for allocated width, note that the internals
+       * of get_height_for_width will internally limit the for_size to natural size
+       * when aligning implicitly.
+       */
+      gtk_widget_get_preferred_width (widget, &min_width, &natural_width);
+      gtk_widget_get_preferred_height_for_width (widget, real_allocation.width, NULL, &natural_height);
+    }
+  else
+    {
+      /* Go ahead and request the width for allocated height, note that the internals
+       * of get_width_for_height will internally limit the for_size to natural size
+       * when aligning implicitly.
+       */
+      gtk_widget_get_preferred_height (widget, &min_height, &natural_height);
+      gtk_widget_get_preferred_width_for_height (widget, real_allocation.height, NULL, &natural_width);
+    }
+
+  /* Now that we have the right natural height and width, go ahead and remove any margins from the 
+   * allocated sizes and possibly limit them to the natural sizes */
+  GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
+							 GTK_ORIENTATION_HORIZONTAL,
+							 &natural_width,
+							 &adjusted_allocation.x,
+							 &adjusted_allocation.width);
+  GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
+							 GTK_ORIENTATION_VERTICAL,
+							 &natural_height,
+							 &adjusted_allocation.y,
+							 &adjusted_allocation.height);
 
   if (adjusted_allocation.x < real_allocation.x ||
       adjusted_allocation.y < real_allocation.y ||
@@ -4920,140 +4954,76 @@ gtk_widget_real_size_allocate (GtkWidget     *widget,
 }
 
 static void
-get_span_inside_border (GtkWidget              *widget,
-                        GtkAlign                align,
-                        int                     start_pad,
-                        int                     end_pad,
-                        int                     allocated_outside_size,
-                        int                     natural_inside_size,
-                        int                    *coord_inside_p,
-                        int                    *size_inside_p)
+adjust_for_align(GtkAlign           align,
+                 gint              *natural_size,
+                 gint              *allocated_pos,
+                 gint              *allocated_size)
 {
-  int inside_allocated;
-  int content_size;
-  int coord, size;
-
-  inside_allocated = allocated_outside_size - start_pad - end_pad;
-
-  content_size = natural_inside_size;
-  if (content_size > inside_allocated)
-    {
-      /* didn't get full natural size */
-      content_size = inside_allocated;
-    }
-
-  coord = size = 0; /* silence compiler */
   switch (align)
     {
     case GTK_ALIGN_FILL:
-      coord = start_pad;
-      size = inside_allocated;
+      /* change nothing */
       break;
     case GTK_ALIGN_START:
-      coord = start_pad;
-      size = content_size;
+      /* keep *allocated_pos where it is */
+      *allocated_size = MIN (*allocated_size, *natural_size);
       break;
     case GTK_ALIGN_END:
-      coord = allocated_outside_size - end_pad - content_size;
-      size = content_size;
+      if (*allocated_size > *natural_size)
+	{
+	  *allocated_pos += (*allocated_size - *natural_size);
+	  *allocated_size = *natural_size;
+	}
       break;
     case GTK_ALIGN_CENTER:
-      coord = start_pad + (inside_allocated - content_size) / 2;
-      size = content_size;
+      if (*allocated_size > *natural_size)
+	{
+	  *allocated_pos += (*allocated_size - *natural_size) / 2;
+	  *allocated_size = MIN (*allocated_size, *natural_size);
+	}
       break;
     }
-
-  if (coord_inside_p)
-    *coord_inside_p = coord;
-
-  if (size_inside_p)
-    *size_inside_p = size;
-}
-
-static void
-get_span_inside_border_horizontal (GtkWidget              *widget,
-                                   const GtkWidgetAuxInfo *aux_info,
-                                   int                     allocated_outside_width,
-                                   int                     natural_inside_width,
-                                   int                    *x_inside_p,
-                                   int                    *width_inside_p)
-{
-  get_span_inside_border (widget,
-                          aux_info->halign,
-                          aux_info->margin.left,
-                          aux_info->margin.right,
-                          allocated_outside_width,
-                          natural_inside_width,
-                          x_inside_p,
-                          width_inside_p);
 }
 
 static void
-get_span_inside_border_vertical (GtkWidget              *widget,
-                                 const GtkWidgetAuxInfo *aux_info,
-                                 int                     allocated_outside_height,
-                                 int                     natural_inside_height,
-                                 int                    *y_inside_p,
-                                 int                    *height_inside_p)
-{
-  get_span_inside_border (widget,
-                          aux_info->valign,
-                          aux_info->margin.top,
-                          aux_info->margin.bottom,
-                          allocated_outside_height,
-                          natural_inside_height,
-                          y_inside_p,
-                          height_inside_p);
+adjust_for_margin(gint               start_margin,
+                  gint               end_margin,
+                  gint              *natural_size,
+                  gint              *allocated_pos,
+                  gint              *allocated_size)
+{
+  *natural_size -= (start_margin + end_margin);
+  *allocated_pos += start_margin;
+  *allocated_size -= (start_margin + end_margin);
 }
 
 static void
 gtk_widget_real_adjust_size_allocation (GtkWidget         *widget,
-                                        GtkAllocation     *allocation)
+                                        GtkOrientation     orientation,
+                                        gint              *natural_size,
+                                        gint              *allocated_pos,
+                                        gint              *allocated_size)
 {
   const GtkWidgetAuxInfo *aux_info;
-  gint natural_width;
-  gint natural_height;
-  int x, y, w, h;
 
   aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
 
-  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      gtk_widget_get_preferred_width (widget, NULL, &natural_width);
-      get_span_inside_border_horizontal (widget,
-					 aux_info,
-					 allocation->width,
-					 natural_width,
-					 &x, &w);
-
-      gtk_widget_get_preferred_height_for_width (widget, w, NULL, &natural_height);
-      get_span_inside_border_vertical (widget,
-				       aux_info,
-				       allocation->height,
-				       natural_height,
-				       &y, &h);
+      adjust_for_margin (aux_info->margin.left,
+                         aux_info->margin.right,
+                         natural_size, allocated_pos, allocated_size);
+      adjust_for_align (aux_info->halign,
+                        natural_size, allocated_pos, allocated_size);
     }
-  else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
+  else
     {
-      gtk_widget_get_preferred_height (widget, NULL, &natural_height);
-      get_span_inside_border_vertical (widget,
-				       aux_info,
-				       allocation->height,
-				       natural_height,
-				       &y, &h);
-
-      gtk_widget_get_preferred_width_for_height (widget, h, NULL, &natural_width);
-      get_span_inside_border_horizontal (widget,
-					 aux_info,
-					 allocation->width,
-					 natural_width,
-					 &x, &w);
+      adjust_for_margin (aux_info->margin.top,
+                         aux_info->margin.bottom,
+                         natural_size, allocated_pos, allocated_size);
+      adjust_for_align (aux_info->valign,
+                        natural_size, allocated_pos, allocated_size);
     }
-
-  allocation->x += x;
-  allocation->y += y;
-  allocation->width = w;
-  allocation->height = h;
 }
 
 static gboolean
@@ -9960,7 +9930,6 @@ gtk_widget_real_size_request (GtkWidget         *widget,
 static void
 gtk_widget_real_adjust_size_request (GtkWidget         *widget,
                                      GtkOrientation     orientation,
-                                     gint               for_size,
                                      gint              *minimum_size,
                                      gint              *natural_size)
 {
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 576f085..6e5b020 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -157,7 +157,10 @@ struct _GtkWidget
  *   and alignment properties of #GtkWidget. Chain up
  *   <emphasis>before</emphasis> performing your own adjustments so your
  *   own adjustments remove more allocation after the #GtkWidget base
- *   class has already removed margin and alignment.
+ *   class has already removed margin and alignment. The natural size
+ *   passed in should be adjusted in the same way as the allocated size,
+ *   which allows adjustments to perform alignments or other changes
+ *   based on natural size.
  */
 struct _GtkWidgetClass
 {
@@ -372,11 +375,13 @@ struct _GtkWidgetClass
 
   void         (* adjust_size_request)    (GtkWidget         *widget,
                                            GtkOrientation     orientation,
-                                           gint               for_size,
                                            gint              *minimum_size,
                                            gint              *natural_size);
   void         (* adjust_size_allocation) (GtkWidget         *widget,
-                                           GtkAllocation     *allocation);
+                                           GtkOrientation     orientation,
+                                           gint              *natural_size,
+                                           gint              *allocated_pos,
+                                           gint              *allocated_size);
 
   /*< private >*/
 
diff --git a/tests/testadjustsize.c b/tests/testadjustsize.c
index 889ea52..13ec944 100644
--- a/tests/testadjustsize.c
+++ b/tests/testadjustsize.c
@@ -408,6 +408,9 @@ open_valigned_label_window (void)
   gtk_widget_show (box);
   gtk_container_add (GTK_CONTAINER (window), box);
 
+  label = gtk_label_new ("Both labels expand");
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
 
   label = gtk_label_new ("Some wrapping text with width-chars = 15 and max-width-chars = 35");
   gtk_label_set_line_wrap  (GTK_LABEL (label), TRUE);
@@ -421,7 +424,7 @@ open_valigned_label_window (void)
   gtk_container_add (GTK_CONTAINER (frame), label);
 
   gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
-  gtk_widget_set_halign (frame, GTK_ALIGN_FILL);
+  gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
 
   gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]