[gtk+/optimize-height-for-width: 1/4] Added GTK_SIZE_REQUEST_CONSTANT_SIZE to GtkSizeRequestMode



commit c20a1c263508559e9efccf0f20a7be6f354fbf3e
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Mar 5 17:49:49 2011 +0900

    Added GTK_SIZE_REQUEST_CONSTANT_SIZE to GtkSizeRequestMode
    
    The constant size request mode defines a request mode where
    height-for-width geometry is unneeded, thus optimizing GTK+
    by reducing the overall amount of requests that need to be
    performed and cached while resizing an interface.

 gtk/gtkbin.c         |   14 -------------
 gtk/gtkbox.c         |   12 -----------
 gtk/gtkcellview.c    |   11 ++++++++++
 gtk/gtkcontainer.c   |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkenums.h       |    4 ++-
 gtk/gtkgrid.c        |   21 +++---------------
 gtk/gtklabel.c       |    8 ++++--
 gtk/gtksizerequest.c |   40 +++++++++++++++++++++++++++++-------
 gtk/gtkwidget.c      |    4 +-
 gtk/gtkwidget.h      |   15 ++++++++-----
 10 files changed, 120 insertions(+), 63 deletions(-)
---
diff --git a/gtk/gtkbin.c b/gtk/gtkbin.c
index af3efea..331ae53 100644
--- a/gtk/gtkbin.c
+++ b/gtk/gtkbin.c
@@ -59,7 +59,6 @@ static void gtk_bin_forall      (GtkContainer   *container,
 static GType gtk_bin_child_type (GtkContainer   *container);
 
 
-static GtkSizeRequestMode gtk_bin_get_request_mode                (GtkWidget           *widget);
 static void               gtk_bin_get_preferred_width_for_height  (GtkWidget           *widget,
                                                                    gint                 height,
                                                                    gint                *minimum_width,
@@ -77,7 +76,6 @@ gtk_bin_class_init (GtkBinClass *class)
   GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
   GtkContainerClass *container_class = (GtkContainerClass*) class;
 
-  widget_class->get_request_mode               = gtk_bin_get_request_mode;
   widget_class->get_preferred_width_for_height = gtk_bin_get_preferred_width_for_height;
   widget_class->get_preferred_height_for_width = gtk_bin_get_preferred_height_for_width;
 
@@ -184,18 +182,6 @@ gtk_bin_forall (GtkContainer *container,
  * deduce a common code path for the get_width_for_height()/get_height_for_width()
  * cases by using the delta of the base size requsts.
  */
-static GtkSizeRequestMode
-gtk_bin_get_request_mode (GtkWidget           *widget)
-{
-  GtkBin *bin = GTK_BIN (widget);
-  GtkBinPrivate *priv = bin->priv;
-
-  if (priv->child)
-    return gtk_widget_get_request_mode (priv->child);
-
-  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
-}
-
 static void
 get_child_padding_delta (GtkBin *bin,
 			 gint   *delta_h,
diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
index f508173..bc9693d 100644
--- a/gtk/gtkbox.c
+++ b/gtk/gtkbox.c
@@ -185,7 +185,6 @@ static void gtk_box_get_child_property (GtkContainer   *container,
 static GType gtk_box_child_type        (GtkContainer   *container);
 
 
-static GtkSizeRequestMode gtk_box_get_request_mode               (GtkWidget           *widget);
 static void               gtk_box_get_preferred_width            (GtkWidget           *widget,
                                                                   gint                *minimum_size,
                                                                   gint                *natural_size);
@@ -216,7 +215,6 @@ gtk_box_class_init (GtkBoxClass *class)
   object_class->get_property = gtk_box_get_property;
 
   widget_class->size_allocate                  = gtk_box_size_allocate;
-  widget_class->get_request_mode               = gtk_box_get_request_mode;
   widget_class->get_preferred_width            = gtk_box_get_preferred_width;
   widget_class->get_preferred_height           = gtk_box_get_preferred_height;
   widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width;
@@ -870,16 +868,6 @@ gtk_box_pack (GtkBox      *box,
   gtk_widget_thaw_child_notify (child);
 }
 
-
-static GtkSizeRequestMode
-gtk_box_get_request_mode  (GtkWidget       *widget)
-{
-  GtkBoxPrivate *private = GTK_BOX (widget)->priv;
-
-  return (private->orientation == GTK_ORIENTATION_VERTICAL) ?
-    GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH : GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
-}
-
 static void
 gtk_box_get_size (GtkWidget      *widget,
 		  GtkOrientation  orientation,
diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c
index d6a87af..051bae5 100644
--- a/gtk/gtkcellview.c
+++ b/gtk/gtkcellview.c
@@ -93,6 +93,7 @@ static void       gtk_cell_view_buildable_custom_tag_end       (GtkBuildable
 								const gchar   	      *tagname,
 								gpointer      	      *data);
 
+static GtkSizeRequestMode gtk_cell_view_get_request_mode       (GtkWidget             *widget);
 static void       gtk_cell_view_get_preferred_width            (GtkWidget             *widget,
 								gint                  *minimum_size,
 								gint                  *natural_size);
@@ -175,6 +176,7 @@ gtk_cell_view_class_init (GtkCellViewClass *klass)
 
   widget_class->draw                           = gtk_cell_view_draw;
   widget_class->size_allocate                  = gtk_cell_view_size_allocate;
+  widget_class->get_request_mode               = gtk_cell_view_get_request_mode;
   widget_class->get_preferred_width            = gtk_cell_view_get_preferred_width;
   widget_class->get_preferred_height           = gtk_cell_view_get_preferred_height;
   widget_class->get_preferred_width_for_height = gtk_cell_view_get_preferred_width_for_height;
@@ -637,6 +639,15 @@ gtk_cell_view_request_model (GtkCellView        *cellview,
     }
 }
 
+static GtkSizeRequestMode 
+gtk_cell_view_get_request_mode (GtkWidget *widget)
+{
+  GtkCellView        *cellview = GTK_CELL_VIEW (widget);
+  GtkCellViewPrivate *priv = cellview->priv;
+
+  return gtk_cell_area_get_request_mode (priv->area);
+}
+
 static void
 gtk_cell_view_get_preferred_width  (GtkWidget *widget,
                                     gint      *minimum_size,
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 61ed85a..4f0d72c 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -239,6 +239,7 @@ struct _GtkContainerPrivate
   guint need_resize        : 1;
   guint reallocate_redraws : 1;
   guint resize_mode        : 2;
+  guint request_mode       : 2;
 };
 
 enum {
@@ -307,6 +308,7 @@ static void     gtk_container_adjust_size_allocation (GtkWidget       *widget,
                                                       gint            *natural_size,
                                                       gint            *allocated_pos,
                                                       gint            *allocated_size);
+static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget   *widget);
 
 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
                                                           GtkWidget    *child);
@@ -437,6 +439,7 @@ gtk_container_class_init (GtkContainerClass *class)
 
   widget_class->adjust_size_request = gtk_container_adjust_size_request;
   widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation;
+  widget_class->get_request_mode = gtk_container_get_request_mode;
 
   class->add = gtk_container_add_unimplemented;
   class->remove = gtk_container_remove_unimplemented;
@@ -1851,6 +1854,57 @@ gtk_container_adjust_size_allocation (GtkWidget         *widget,
                                         allocated_size);
 }
 
+typedef struct {
+  gint hfw;
+  gint wfh;
+} RequestModeCount;
+
+static void
+count_request_modes (GtkWidget        *widget,
+		     RequestModeCount *count)
+{
+  GtkSizeRequestMode mode = gtk_widget_get_request_mode (widget);
+
+  switch (mode)
+    {
+    case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
+      count->hfw++;
+      break;
+    case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
+      count->wfh++;
+      break;
+    case GTK_SIZE_REQUEST_CONSTANT_SIZE:
+    default:
+      break;
+    }
+}
+
+static GtkSizeRequestMode 
+gtk_container_get_request_mode (GtkWidget *widget)
+{
+  GtkContainer        *container = GTK_CONTAINER (widget);
+  GtkContainerPrivate *priv      = container->priv;
+
+  /* Recalculate the request mode of the children by majority
+   * vote whenever the internal content changes */
+  if (_gtk_widget_get_width_request_needed (widget) ||
+      _gtk_widget_get_height_request_needed (widget))
+    {
+      RequestModeCount count = { 0, 0 };
+
+      gtk_container_forall (container, (GtkCallback)count_request_modes, &count);
+
+      if (!count.hfw && !count.wfh)
+	priv->request_mode = GTK_SIZE_REQUEST_CONSTANT_SIZE;
+      else
+	priv->request_mode = count.wfh > count.hfw ? 
+	  GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
+	  GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+    }
+
+  return priv->request_mode;
+}
+
 /**
  * gtk_container_class_handle_border_width:
  * @klass: the class struct of a #GtkContainer subclass
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 78ea40c..2233b00 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -790,6 +790,7 @@ typedef enum
  * GtkSizeRequestMode:
  * @GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH: Prefer height-for-width geometry management
  * @GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT: Prefer width-for-height geometry management
+ * @GTK_SIZE_REQUEST_CONSTANT_SIZE: Dont trade height-for-width or width-for-height
  * 
  * Specifies a preference for height-for-width or
  * width-for-height geometry management.
@@ -797,7 +798,8 @@ typedef enum
 typedef enum
 {
   GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH = 0,
-  GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT
+  GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT,
+  GTK_SIZE_REQUEST_CONSTANT_SIZE
 } GtkSizeRequestMode;
 
 /**
diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c
index bd305f6..4719857 100644
--- a/gtk/gtkgrid.c
+++ b/gtk/gtkgrid.c
@@ -458,17 +458,6 @@ gtk_grid_child_type (GtkContainer *container)
   return GTK_TYPE_WIDGET;
 }
 
-static GtkSizeRequestMode
-gtk_grid_get_request_mode (GtkWidget *widget)
-{
-  GtkGridPrivate *priv = GTK_GRID (widget)->priv;
-
-  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
-    return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
-  else
-    return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
-}
-
 /* Calculates the min and max numbers for both orientations.
  */
 static void
@@ -1104,8 +1093,7 @@ gtk_grid_get_preferred_width (GtkWidget *widget,
 {
   GtkGrid *grid = GTK_GRID (widget);
 
-  if (gtk_grid_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
-
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
     gtk_grid_get_size_for_size (grid, GTK_ORIENTATION_HORIZONTAL, 0, minimum, natural);
   else
     gtk_grid_get_size (grid, GTK_ORIENTATION_HORIZONTAL, minimum, natural);
@@ -1118,7 +1106,7 @@ gtk_grid_get_preferred_height (GtkWidget *widget,
 {
   GtkGrid *grid = GTK_GRID (widget);
 
-  if (gtk_grid_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
     gtk_grid_get_size_for_size (grid, GTK_ORIENTATION_VERTICAL, 0, minimum, natural);
   else
     gtk_grid_get_size (grid, GTK_ORIENTATION_VERTICAL, minimum, natural);
@@ -1132,7 +1120,7 @@ gtk_grid_get_preferred_width_for_height (GtkWidget *widget,
 {
   GtkGrid *grid = GTK_GRID (widget);
 
-  if (gtk_grid_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
     gtk_grid_get_size_for_size (grid, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
   else
     gtk_grid_get_size (grid, GTK_ORIENTATION_HORIZONTAL, minimum, natural);
@@ -1146,7 +1134,7 @@ gtk_grid_get_preferred_height_for_width (GtkWidget *widget,
 {
   GtkGrid *grid = GTK_GRID (widget);
 
-  if (gtk_grid_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
     gtk_grid_get_size_for_size (grid, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
   else
     gtk_grid_get_size (grid, GTK_ORIENTATION_VERTICAL, minimum, natural);
@@ -1258,7 +1246,6 @@ gtk_grid_class_init (GtkGridClass *class)
   widget_class->size_allocate = gtk_grid_size_allocate;
   widget_class->get_preferred_width = gtk_grid_get_preferred_width;
   widget_class->get_preferred_height = gtk_grid_get_preferred_height;
-  widget_class->get_request_mode = gtk_grid_get_request_mode;
   widget_class->get_preferred_width_for_height = gtk_grid_get_preferred_width_for_height;
   widget_class->get_preferred_height_for_width = gtk_grid_get_preferred_height_for_width;
 
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 51fd17f..dc59758 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -3381,10 +3381,12 @@ gtk_label_get_request_mode (GtkWidget *widget)
   GtkLabel *label = GTK_LABEL (widget);
   gdouble   angle = gtk_label_get_angle (label);
 
-  if (angle == 90 || angle == 270)
-    return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+  if (label->priv->wrap)
+    return (angle == 90 || angle == 270) ?
+      GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : 
+      GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
 
-  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+    return GTK_SIZE_REQUEST_CONSTANT_SIZE;
 }
 
 static void
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index ef96ed0..81edba6 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -156,6 +156,11 @@ pop_recursion_check (GtkWidget       *widget,
 #endif
 }
 
+/* This is the main function that checks for a cached size and
+ * possibly queries the widget class to compute the size if it's
+ * not cached. If the for_size here is -1, then get_preferred_width()
+ * or get_preferred_height() will be used.
+ */
 static void
 compute_size_for_orientation (GtkWidget         *widget,
                               GtkSizeGroupMode   orientation,
@@ -168,9 +173,6 @@ compute_size_for_orientation (GtkWidget         *widget,
   gboolean          found_in_cache = FALSE;
   int adjusted_min, adjusted_natural;
 
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (minimum_size != NULL || natural_size != NULL);
-
   cache  = _gtk_widget_peek_request_cache (widget);
 
   if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
@@ -399,6 +401,9 @@ gtk_widget_get_preferred_width (GtkWidget *widget,
                                 gint      *minimum_width,
                                 gint      *natural_width)
 {
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (minimum_width != NULL || natural_width != NULL);
+
   compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL,
                                 -1, minimum_width, natural_width);
 }
@@ -427,6 +432,9 @@ gtk_widget_get_preferred_height (GtkWidget *widget,
                                  gint      *minimum_height,
                                  gint      *natural_height)
 {
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (minimum_height != NULL || natural_height != NULL);
+
   compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL,
                                 -1, minimum_height, natural_height);
 }
@@ -457,8 +465,16 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget,
                                            gint      *minimum_width,
                                            gint      *natural_width)
 {
-  compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL,
-                                height, minimum_width, natural_width);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (minimum_width != NULL || natural_width != NULL);
+  g_return_if_fail (height >= 0);
+
+  if (GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
+    compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL,
+				  -1, minimum_width, natural_width);
+  else
+    compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL,
+				  height, minimum_width, natural_width);
 }
 
 /**
@@ -485,8 +501,16 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
                                            gint      *minimum_height,
                                            gint      *natural_height)
 {
-  compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL,
-                                width, minimum_height, natural_height);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (minimum_height != NULL || natural_height != NULL);
+  g_return_if_fail (width >= 0);
+
+  if (GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
+    compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL,
+				  -1, minimum_height, natural_height);
+  else
+    compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL,
+				  width, minimum_height, natural_height);
 }
 
 /**
@@ -538,7 +562,7 @@ gtk_widget_get_preferred_size (GtkWidget      *widget,
                                                      NULL, &natural_size->height);
 	}
     }
-  else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
+  else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT or CONSTANT_SIZE */
     {
       gtk_widget_get_preferred_height (widget, &min_height, &nat_height);
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 828f857..4f67765 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -13005,8 +13005,8 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
 static GtkSizeRequestMode 
 gtk_widget_real_get_request_mode (GtkWidget *widget)
 { 
-  /* By default widgets are height-for-width. */
-  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+  /* By default widgets dont trade size at all. */
+  return GTK_SIZE_REQUEST_CONSTANT_SIZE;
 }
 
 static void
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index c391b22..ce40385 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -139,12 +139,15 @@ struct _GtkWidget
  *   %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT mode.
  *   %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH means the widget prefers to have
  *   #GtkWidgetClass.get_preferred_width() called and then
- *   #GtkWidgetClass.get_preferred_height_for_width() and is the default
- *   return for unimplemented cases.
- *   However it's important to note (as described below) that any widget
- *   which trades height-for-width must respond properly to both
- *   #GtkSizeRequestModes since it might be queried in either orientation
- *   by its parent container.
+ *   #GtkWidgetClass.get_preferred_height_for_width().
+ *   %GTK_SIZE_REQUEST_CONSTANT_SIZE disables any height-for-width or
+ *   width-for-height geometry management for a said widget and is the
+ *   default return.
+ *   It's important to note (as described below) that any widget
+ *   which trades height-for-width or width-for-height must respond properly 
+ *   to both of the virtual methods #GtkWidgetClass.get_preferred_height_for_width()
+ *   and #GtkWidgetClass.get_preferred_width_for_height() since it might be 
+ *   queried in either #GtkSizeRequestMode by its parent container.
  * @get_preferred_height: This is called by containers to obtain the minimum
  *   and natural height of a widget. A widget that does not actually trade
  *   any height for width or width for height only has to implement these



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