[gtk+/combo-refactor] Revert "Removed tons of api that we dont absolutely need in GtkCellAreaContext:"



commit a3cc22ce30d2ec39def2a5aaadac7d5036de2fcb
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Fri Nov 26 13:23:01 2010 +0900

    Revert "Removed tons of api that we dont absolutely need in GtkCellAreaContext:"
    
    This reverts commit 5f7787ab2ead2cdd11ebe17b16dd9498daaaf9c5.

 gtk/gtkcellareabox.c        |   57 +++++--
 gtk/gtkcellareaboxcontext.c |  303 ++++++++++++++++++++++++++++++++++++
 gtk/gtkcellareaboxcontext.h |   27 ++++
 gtk/gtkcellareacontext.c    |  363 ++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkcellareacontext.h    |   32 ++++
 5 files changed, 762 insertions(+), 20 deletions(-)
---
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index 8950c53..02ec53f 100644
--- a/gtk/gtkcellareabox.c
+++ b/gtk/gtkcellareabox.c
@@ -1284,7 +1284,8 @@ compute_size (GtkCellAreaBox        *box,
   for (i = 0; i < priv->groups->len; i++)
     {
       CellGroup *group = &g_array_index (priv->groups, CellGroup, i);
-      gint       group_min = 0, group_nat = 0;
+      gint       group_min_size = 0;
+      gint       group_nat_size = 0;
 
       for (list = group->cells; list; list = list->next)
 	{
@@ -1304,33 +1305,42 @@ compute_size (GtkCellAreaBox        *box,
 		  min_size += priv->spacing;
 		  nat_size += priv->spacing;
 		}
-
-	      if (group_min > 0)
+	      
+	      if (group_min_size > 0)
 		{
-		  group_min += priv->spacing;
-		  group_nat += priv->spacing;
+		  group_min_size += priv->spacing;
+		  group_nat_size += priv->spacing;
 		}
-
-	      min_size  += renderer_min_size;
-	      nat_size  += renderer_nat_size;
-	      group_min += renderer_min_size;
-	      group_nat += renderer_nat_size;
+	      
+	      min_size       += renderer_min_size;
+	      nat_size       += renderer_nat_size;
+	      group_min_size += renderer_min_size;
+	      group_nat_size += renderer_nat_size;
 	    }
 	  else
 	    {
-	      min_size  = MAX (min_size, renderer_min_size);
-	      nat_size  = MAX (nat_size, renderer_nat_size);
-	      group_min = MAX (group_min, renderer_min_size);
-	      group_nat = MAX (group_nat, renderer_nat_size);
+	      min_size       = MAX (min_size, renderer_min_size);
+	      nat_size       = MAX (nat_size, renderer_nat_size);
+	      group_min_size = MAX (group_min_size, renderer_min_size);
+	      group_nat_size = MAX (group_nat_size, renderer_nat_size);
 	    }
 	}
 
-      if (for_size < 0)
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+	  if (for_size < 0)
+	    gtk_cell_area_box_context_push_group_width (context, group->id, group_min_size, group_nat_size);
+	  else
+	    gtk_cell_area_box_context_push_group_width_for_height (context, group->id, for_size,
+								   group_min_size, group_nat_size);
+	}
+      else
 	{
-	  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-	    gtk_cell_area_box_context_push_group_width (context, group->id, group_min, group_nat);
+	  if (for_size < 0)
+	    gtk_cell_area_box_context_push_group_height (context, group->id, group_min_size, group_nat_size);
 	  else
-	    gtk_cell_area_box_context_push_group_height (context, group->id, group_min, group_nat);
+	    gtk_cell_area_box_context_push_group_height_for_width (context, group->id, for_size,
+								   group_min_size, group_nat_size);
 	}
     }
 
@@ -1519,6 +1529,17 @@ compute_size_for_opposing_orientation (GtkCellAreaBox        *box,
 
       min_size = MAX (min_size, group_min);
       nat_size = MAX (nat_size, group_nat);
+
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+	  gtk_cell_area_box_context_push_group_height_for_width (context, group_idx, for_size,
+								 group_min, group_nat);
+	}
+      else
+	{
+	  gtk_cell_area_box_context_push_group_width_for_height (context, group_idx, for_size,
+								 group_min, group_nat);
+	}
     }
 
   *minimum_size = min_size;
diff --git a/gtk/gtkcellareaboxcontext.c b/gtk/gtkcellareaboxcontext.c
index b344fa8..0a8406c 100644
--- a/gtk/gtkcellareaboxcontext.c
+++ b/gtk/gtkcellareaboxcontext.c
@@ -32,15 +32,31 @@ static void      gtk_cell_area_box_context_finalize                         (GOb
 
 /* GtkCellAreaContextClass */
 static void      gtk_cell_area_box_context_flush_preferred_width            (GtkCellAreaContext *context);
+static void      gtk_cell_area_box_context_flush_preferred_height_for_width (GtkCellAreaContext *context,
+									     gint                width);
 static void      gtk_cell_area_box_context_flush_preferred_height           (GtkCellAreaContext *context);
+static void      gtk_cell_area_box_context_flush_preferred_width_for_height (GtkCellAreaContext *context,
+									     gint                height);
 static void      gtk_cell_area_box_context_flush_allocation                 (GtkCellAreaContext *context);
 static void      gtk_cell_area_box_context_sum_preferred_width              (GtkCellAreaContext *context);
+static void      gtk_cell_area_box_context_sum_preferred_height_for_width   (GtkCellAreaContext *context,
+									     gint                width);
 static void      gtk_cell_area_box_context_sum_preferred_height             (GtkCellAreaContext *context);
+static void      gtk_cell_area_box_context_sum_preferred_width_for_height   (GtkCellAreaContext *context,
+									     gint                height);
 static void      gtk_cell_area_box_context_allocate_width                   (GtkCellAreaContext *context,
 									     gint                width);
 static void      gtk_cell_area_box_context_allocate_height                  (GtkCellAreaContext *context,
 									     gint                height);
 
+static void      free_cache_array                                           (GArray          *array);
+
+/* CachedSize management */
+typedef struct {
+  gint     min_size;
+  gint     nat_size;
+} CachedSize;
+
 typedef struct {
   gint     min_size;
   gint     nat_size;
@@ -53,6 +69,10 @@ struct _GtkCellAreaBoxContextPrivate
   GArray *base_widths;
   GArray *base_heights;
 
+  /* Table of per height/width hash tables of per renderer CachedSizes */
+  GHashTable *widths;
+  GHashTable *heights;
+
   /* Allocation info for this context if any */
   gint                      alloc_width;
   gint                      alloc_height;
@@ -63,6 +83,12 @@ struct _GtkCellAreaBoxContextPrivate
 G_DEFINE_TYPE (GtkCellAreaBoxContext, gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT);
 
 static void
+free_cache_array (GArray *array)
+{
+  g_array_free (array, TRUE);
+}
+
+static void
 gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context)
 {
   GtkCellAreaBoxContextPrivate *priv;
@@ -75,6 +101,11 @@ gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context)
   priv->base_widths  = g_array_new (FALSE, TRUE, sizeof (BaseSize));
   priv->base_heights = g_array_new (FALSE, TRUE, sizeof (BaseSize));
 
+  priv->widths       = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+					      NULL, (GDestroyNotify)free_cache_array);
+  priv->heights      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+					      NULL, (GDestroyNotify)free_cache_array);
+
   priv->alloc_width  = 0;
   priv->alloc_height = 0;
   priv->orientation_allocs   = NULL;
@@ -91,11 +122,15 @@ gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class)
   object_class->finalize = gtk_cell_area_box_context_finalize;
 
   context_class->flush_preferred_width            = gtk_cell_area_box_context_flush_preferred_width;
+  context_class->flush_preferred_height_for_width = gtk_cell_area_box_context_flush_preferred_height_for_width;
   context_class->flush_preferred_height           = gtk_cell_area_box_context_flush_preferred_height;
+  context_class->flush_preferred_width_for_height = gtk_cell_area_box_context_flush_preferred_width_for_height;
   context_class->flush_allocation                 = gtk_cell_area_box_context_flush_allocation;
 
   context_class->sum_preferred_width            = gtk_cell_area_box_context_sum_preferred_width;
+  context_class->sum_preferred_height_for_width = gtk_cell_area_box_context_sum_preferred_height_for_width;
   context_class->sum_preferred_height           = gtk_cell_area_box_context_sum_preferred_height;
+  context_class->sum_preferred_width_for_height = gtk_cell_area_box_context_sum_preferred_width_for_height;
 
   context_class->allocate_width  = gtk_cell_area_box_context_allocate_width;
   context_class->allocate_height = gtk_cell_area_box_context_allocate_height;
@@ -114,6 +149,8 @@ gtk_cell_area_box_context_finalize (GObject *object)
 
   g_array_free (priv->base_widths, TRUE);
   g_array_free (priv->base_heights, TRUE);
+  g_hash_table_destroy (priv->widths);
+  g_hash_table_destroy (priv->heights);
 
   g_free (priv->orientation_allocs);
 
@@ -143,6 +180,23 @@ gtk_cell_area_box_context_flush_preferred_width (GtkCellAreaContext *context)
 }
 
 static void
+gtk_cell_area_box_context_flush_preferred_height_for_width (GtkCellAreaContext *context,
+							    gint                width)
+{
+  GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
+  GtkCellAreaBoxContextPrivate *priv        = box_context->priv;
+
+  /* Flush all sizes for special -1 value */
+  if (width < 0)
+    g_hash_table_remove_all (priv->heights);
+  else
+    g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
+
+  GTK_CELL_AREA_CONTEXT_CLASS
+    (gtk_cell_area_box_context_parent_class)->flush_preferred_height_for_width (context, width);
+}
+
+static void
 gtk_cell_area_box_context_flush_preferred_height (GtkCellAreaContext *context)
 {
   GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
@@ -162,6 +216,23 @@ gtk_cell_area_box_context_flush_preferred_height (GtkCellAreaContext *context)
 }
 
 static void
+gtk_cell_area_box_context_flush_preferred_width_for_height (GtkCellAreaContext *context,
+							    gint                height)
+{
+  GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
+  GtkCellAreaBoxContextPrivate *priv        = box_context->priv;
+
+  /* Flush all sizes for special -1 value */
+  if (height < 0)
+    g_hash_table_remove_all (priv->widths);
+  else
+    g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
+
+  GTK_CELL_AREA_CONTEXT_CLASS
+    (gtk_cell_area_box_context_parent_class)->flush_preferred_width_for_height (context, height);
+}
+
+static void
 gtk_cell_area_box_context_flush_allocation (GtkCellAreaContext *context)
 {
   GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
@@ -218,6 +289,55 @@ gtk_cell_area_box_context_sum_preferred_width (GtkCellAreaContext *context)
 }
 
 static void
+gtk_cell_area_box_context_sum_preferred_height_for_width (GtkCellAreaContext *context,
+							  gint                width)
+{
+  GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
+  GtkCellAreaBoxContextPrivate *priv        = box_context->priv;
+  GArray                    *group_array;
+  GtkCellArea               *area;
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
+
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width));
+
+  if (group_array)
+    {
+      area        = gtk_cell_area_context_get_area (context);
+      spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+      
+      for (i = 0; i < group_array->len; i++)
+	{
+	  CachedSize *size = &g_array_index (group_array, CachedSize, i);
+	  
+	  if (orientation == GTK_ORIENTATION_VERTICAL)
+	    {
+	      /* Dont add spacing for 0 size groups, they can be 0 size because
+	       * they contain only invisible cells for this round of requests 
+	       */
+	      if (min_size > 0 && size->nat_size > 0)
+		{
+		  min_size += spacing;
+		  nat_size += spacing;
+		}
+	      
+	      min_size += size->min_size;
+	      nat_size += size->nat_size;
+	    }
+	  else
+	    {
+	      min_size = MAX (min_size, size->min_size);
+	      nat_size = MAX (nat_size, size->nat_size);
+	    }
+	}
+
+      gtk_cell_area_context_push_preferred_height_for_width (context, width, min_size, nat_size);
+    }
+}
+
+static void
 gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context)
 {
   GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
@@ -259,6 +379,55 @@ gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context)
   gtk_cell_area_context_push_preferred_height (context, min_size, nat_size);
 }
 
+static void
+gtk_cell_area_box_context_sum_preferred_width_for_height (GtkCellAreaContext *context,
+							  gint                height)
+{
+  GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
+  GtkCellAreaBoxContextPrivate *priv        = box_context->priv;
+  GArray                    *group_array;
+  GtkCellArea               *area;
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
+
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height));
+
+  if (group_array)
+    {
+      area        = gtk_cell_area_context_get_area (context);
+      spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+      
+      for (i = 0; i < group_array->len; i++)
+	{
+	  CachedSize *size = &g_array_index (group_array, CachedSize, i);
+	  
+	  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+	    {
+	      /* Dont add spacing for 0 size groups, they can be 0 size because
+	       * they contain only invisible cells for this round of requests 
+	       */
+	      if (min_size > 0 && size->nat_size > 0)
+		{
+		  min_size += spacing;
+		  nat_size += spacing;
+		}
+	      
+	      min_size += size->min_size;
+	      nat_size += size->nat_size;
+	    }
+	  else
+	    {
+	      min_size = MAX (min_size, size->min_size);
+	      nat_size = MAX (nat_size, size->nat_size);
+	    }
+	}
+
+      gtk_cell_area_context_push_preferred_width_for_height (context, height, min_size, nat_size);
+    }
+}
+
 static GtkRequestedSize *
 gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context,
 					GtkOrientation         orientation,
@@ -493,6 +662,36 @@ gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context,
 }
 
 void
+gtk_cell_area_box_context_push_group_height_for_width  (GtkCellAreaBoxContext *box_context,
+							gint                   group_idx,
+							gint                   for_width,
+							gint                   minimum_height,
+							gint                   natural_height)
+{
+  GtkCellAreaBoxContextPrivate *priv;
+  GArray                       *group_array;
+  CachedSize                   *size;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
+
+  priv = box_context->priv;
+  g_return_if_fail (group_idx < priv->base_widths->len);
+
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  if (!group_array)
+    {
+      group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize));
+      g_array_set_size (group_array, priv->base_heights->len);
+
+      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_array);
+    }
+
+  size = &g_array_index (group_array, CachedSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_height);
+  size->nat_size = MAX (size->nat_size, natural_height);
+}
+
+void
 gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context,
 					     gint                   group_idx,
 					     gint                   minimum_height,
@@ -512,6 +711,36 @@ gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context,
 }
 
 void
+gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *box_context,
+						       gint                   group_idx,
+						       gint                   for_height,
+						       gint                   minimum_width,
+						       gint                   natural_width)
+{
+  GtkCellAreaBoxContextPrivate *priv;
+  GArray                    *group_array;
+  CachedSize                *size;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
+
+  priv        = box_context->priv;
+  g_return_if_fail (group_idx < priv->base_widths->len);
+
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  if (!group_array)
+    {
+      group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize));
+      g_array_set_size (group_array, priv->base_heights->len);
+
+      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_array);
+    }
+
+  size = &g_array_index (group_array, CachedSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_width);
+  size->nat_size = MAX (size->nat_size, natural_width);
+}
+
+void
 gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context,
 					   gint                   group_idx,
 					   gint                  *minimum_width,
@@ -535,6 +764,43 @@ gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context,
 }
 
 void
+gtk_cell_area_box_context_get_group_height_for_width (GtkCellAreaBoxContext *box_context,
+						      gint                   group_idx,
+						      gint                   for_width,
+						      gint                  *minimum_height,
+						      gint                  *natural_height)
+{
+  GtkCellAreaBoxContextPrivate *priv;
+  GArray                    *group_array;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
+
+  priv        = box_context->priv;
+  g_return_if_fail (group_idx < priv->base_widths->len);
+
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+
+  if (group_array)
+    {
+      CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
+
+      if (minimum_height)
+	*minimum_height = size->min_size;
+
+      if (natural_height)
+	*natural_height = size->nat_size;
+    }
+  else
+    {
+      if (minimum_height)
+	*minimum_height = -1;
+
+      if (natural_height)
+	*natural_height = -1;      
+    }
+}
+
+void
 gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context,
 					    gint                   group_idx,
 					    gint                  *minimum_height,
@@ -557,6 +823,43 @@ gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context,
     *natural_height = size->nat_size;
 }
 
+void
+gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box_context,
+						      gint                   group_idx,
+						      gint                   for_height,
+						      gint                  *minimum_width,
+						      gint                  *natural_width)
+{
+  GtkCellAreaBoxContextPrivate *priv;
+  GArray                       *group_array;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
+
+  priv = box_context->priv;
+  g_return_if_fail (group_idx < priv->base_widths->len);
+
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+
+  if (group_array)
+    {
+      CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
+
+      if (minimum_width)
+	*minimum_width = size->min_size;
+
+      if (natural_width)
+	*natural_width = size->nat_size;
+    }
+  else
+    {
+      if (minimum_width)
+	*minimum_width = -1;
+
+      if (natural_width)
+	*natural_width = -1;      
+    }
+}
+
 GtkRequestedSize *
 gtk_cell_area_box_context_get_widths (GtkCellAreaBoxContext *box_context,
 				      gint                  *n_widths)
diff --git a/gtk/gtkcellareaboxcontext.h b/gtk/gtkcellareaboxcontext.h
index 29d9f80..01f7dc6 100644
--- a/gtk/gtkcellareaboxcontext.h
+++ b/gtk/gtkcellareaboxcontext.h
@@ -72,20 +72,47 @@ void    gtk_cell_area_box_context_push_group_width             (GtkCellAreaBoxCo
 								gint                   group_idx,
 								gint                   minimum_width,
 								gint                   natural_width);
+
+void    gtk_cell_area_box_context_push_group_height_for_width  (GtkCellAreaBoxContext *box_context,
+								gint                   group_idx,
+								gint                   for_width,
+								gint                   minimum_height,
+								gint                   natural_height);
+
 void    gtk_cell_area_box_context_push_group_height            (GtkCellAreaBoxContext *box_context,
 								gint                   group_idx,
 								gint                   minimum_height,
 								gint                   natural_height);
 
+void    gtk_cell_area_box_context_push_group_width_for_height  (GtkCellAreaBoxContext *box_context,
+								gint                   group_idx,
+								gint                   for_height,
+								gint                   minimum_width,
+								gint                   natural_width);
+
 /* Fetch cell-group sizes */
 void    gtk_cell_area_box_context_get_group_width              (GtkCellAreaBoxContext *box_context,
 								gint                   group_idx,
 								gint                  *minimum_width,
 								gint                  *natural_width);
+
+void    gtk_cell_area_box_context_get_group_height_for_width   (GtkCellAreaBoxContext *box_context,
+								gint                   group_idx,
+								gint                   for_width,
+								gint                  *minimum_height,
+								gint                  *natural_height);
+
 void    gtk_cell_area_box_context_get_group_height             (GtkCellAreaBoxContext *box_context,
 								gint                   group_idx,
 								gint                  *minimum_height,
 								gint                  *natural_height);
+
+void    gtk_cell_area_box_context_get_group_width_for_height   (GtkCellAreaBoxContext *box_context,
+								gint                   group_idx,
+								gint                   for_height,
+								gint                  *minimum_width,
+								gint                  *natural_width);
+
 GtkRequestedSize *gtk_cell_area_box_context_get_widths         (GtkCellAreaBoxContext *box_context,
 								gint                  *n_widths);
 GtkRequestedSize *gtk_cell_area_box_context_get_heights        (GtkCellAreaBoxContext *box_context,
diff --git a/gtk/gtkcellareacontext.c b/gtk/gtkcellareacontext.c
index 1d0598f..6164670 100644
--- a/gtk/gtkcellareacontext.c
+++ b/gtk/gtkcellareacontext.c
@@ -28,6 +28,7 @@
 #include "gtkprivate.h"
 
 /* GObjectClass */
+static void      gtk_cell_area_context_finalize                       (GObject            *object);
 static void      gtk_cell_area_context_dispose                        (GObject            *object);
 static void      gtk_cell_area_context_get_property                   (GObject            *object,
 								       guint               prop_id,
@@ -40,13 +41,26 @@ static void      gtk_cell_area_context_set_property                   (GObject
 
 /* GtkCellAreaContextClass */
 static void      gtk_cell_area_context_real_flush_preferred_width            (GtkCellAreaContext *context);
+static void      gtk_cell_area_context_real_flush_preferred_height_for_width (GtkCellAreaContext *context,
+									      gint                width);
 static void      gtk_cell_area_context_real_flush_preferred_height           (GtkCellAreaContext *context);
+static void      gtk_cell_area_context_real_flush_preferred_width_for_height (GtkCellAreaContext *context,
+									      gint                height);
 static void      gtk_cell_area_context_real_flush_allocation                 (GtkCellAreaContext *context);
 static void      gtk_cell_area_context_real_allocate_width                   (GtkCellAreaContext *context,
 									      gint                width);
 static void      gtk_cell_area_context_real_allocate_height                  (GtkCellAreaContext *context,
 									      gint                height);
 
+/* CachedSize management */
+typedef struct {
+  gint min_size;
+  gint nat_size;
+} CachedSize;
+
+static CachedSize *cached_size_new  (gint min_size, gint nat_size);
+static void        cached_size_free (CachedSize *size);
+
 struct _GtkCellAreaContextPrivate
 {
   GtkCellArea *cell_area;
@@ -57,6 +71,9 @@ struct _GtkCellAreaContextPrivate
   gint         nat_height;
   gint         alloc_width;
   gint         alloc_height;
+
+  GHashTable  *widths;
+  GHashTable  *heights;
 };
 
 enum {
@@ -68,6 +85,14 @@ enum {
   PROP_NAT_HEIGHT
 };
 
+enum {
+  SIGNAL_WIDTH_CHANGED,
+  SIGNAL_HEIGHT_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint cell_area_context_signals[LAST_SIGNAL] = { 0 };
+
 G_DEFINE_TYPE (GtkCellAreaContext, gtk_cell_area_context, G_TYPE_OBJECT);
 
 static void
@@ -84,6 +109,10 @@ gtk_cell_area_context_init (GtkCellAreaContext *context)
   priv->nat_width  = -1;
   priv->min_height = -1;
   priv->nat_height = -1;
+  priv->widths     = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+					    NULL, (GDestroyNotify)cached_size_free);
+  priv->heights    = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+					    NULL, (GDestroyNotify)cached_size_free);
 }
 
 static void 
@@ -92,21 +121,46 @@ gtk_cell_area_context_class_init (GtkCellAreaContextClass *class)
   GObjectClass     *object_class = G_OBJECT_CLASS (class);
 
   /* GObjectClass */
+  object_class->finalize     = gtk_cell_area_context_finalize;
   object_class->dispose      = gtk_cell_area_context_dispose;
   object_class->get_property = gtk_cell_area_context_get_property;
   object_class->set_property = gtk_cell_area_context_set_property;
 
   /* GtkCellAreaContextClass */
   class->flush_preferred_width            = gtk_cell_area_context_real_flush_preferred_width;
+  class->flush_preferred_height_for_width = gtk_cell_area_context_real_flush_preferred_height_for_width;
   class->flush_preferred_height           = gtk_cell_area_context_real_flush_preferred_height;
+  class->flush_preferred_width_for_height = gtk_cell_area_context_real_flush_preferred_width_for_height;
   class->flush_allocation                 = gtk_cell_area_context_real_flush_allocation;
 
-  class->sum_preferred_width   = NULL;
-  class->sum_preferred_height  = NULL;
+  class->sum_preferred_width            = NULL;
+  class->sum_preferred_height_for_width = NULL;
+  class->sum_preferred_height           = NULL;
+  class->sum_preferred_width_for_height = NULL;
 
   class->allocate_width  = gtk_cell_area_context_real_allocate_width;
   class->allocate_height = gtk_cell_area_context_real_allocate_height;
 
+  cell_area_context_signals[SIGNAL_HEIGHT_CHANGED] =
+    g_signal_new (I_("height-changed"),
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  0, /* Class offset (just a notification, no class handler) */
+		  NULL, NULL,
+		  _gtk_marshal_VOID__INT_INT_INT,
+		  G_TYPE_NONE, 3,
+		  G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+
+  cell_area_context_signals[SIGNAL_WIDTH_CHANGED] =
+    g_signal_new (I_("width-changed"),
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  0, /* Class offset (just a notification, no class handler) */
+		  NULL, NULL,
+		  _gtk_marshal_VOID__INT_INT_INT,
+		  G_TYPE_NONE, 3,
+		  G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+
   g_object_class_install_property (object_class,
                                    PROP_CELL_AREA,
                                    g_param_spec_object ("area",
@@ -158,10 +212,45 @@ gtk_cell_area_context_class_init (GtkCellAreaContextClass *class)
   g_type_class_add_private (object_class, sizeof (GtkCellAreaContextPrivate));
 }
 
+
+
+/*************************************************************
+ *                      Cached Sizes                         *
+ *************************************************************/
+static CachedSize *
+cached_size_new (gint min_size, 
+		 gint nat_size)
+{
+  CachedSize *size = g_slice_new (CachedSize);
+
+  size->min_size = min_size;
+  size->nat_size = nat_size;
+
+  return size;
+}
+
+static void
+cached_size_free (CachedSize *size)
+{
+  g_slice_free (CachedSize, size);
+}
+
 /*************************************************************
  *                      GObjectClass                         *
  *************************************************************/
 static void
+gtk_cell_area_context_finalize (GObject *object)
+{
+  GtkCellAreaContext        *context = GTK_CELL_AREA_CONTEXT (object);
+  GtkCellAreaContextPrivate *priv = context->priv;
+
+  g_hash_table_destroy (priv->widths);
+  g_hash_table_destroy (priv->heights);
+
+  G_OBJECT_CLASS (gtk_cell_area_context_parent_class)->finalize (object);
+}
+
+static void
 gtk_cell_area_context_dispose (GObject *object)
 {
   GtkCellAreaContext        *context = GTK_CELL_AREA_CONTEXT (object);
@@ -247,6 +336,40 @@ gtk_cell_area_context_real_flush_preferred_width (GtkCellAreaContext *context)
 }
 
 static void
+notify_invalid_height (gpointer            width_ptr,
+		       CachedSize         *size,
+		       GtkCellAreaContext *context)
+{
+  gint width = GPOINTER_TO_INT (width_ptr);
+
+  /* Notify size invalidated */
+  g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], 
+		 0, width, -1, -1);
+}
+
+static void
+gtk_cell_area_context_real_flush_preferred_height_for_width (GtkCellAreaContext *context,
+							     gint                width)
+{
+  GtkCellAreaContextPrivate *priv = context->priv;
+
+  /* Flush all sizes for special -1 value */
+  if (width < 0)
+    {
+      g_hash_table_foreach (priv->heights, (GHFunc)notify_invalid_height, context);
+      g_hash_table_remove_all (priv->heights);
+    }
+  else
+    {
+      g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
+
+      /* Notify size invalidated */
+      g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], 
+		     0, width, -1, -1);
+    }
+}
+
+static void
 gtk_cell_area_context_real_flush_preferred_height (GtkCellAreaContext *context)
 {
   GtkCellAreaContextPrivate *priv = context->priv;
@@ -261,6 +384,40 @@ gtk_cell_area_context_real_flush_preferred_height (GtkCellAreaContext *context)
 }
 
 static void
+notify_invalid_width (gpointer            height_ptr,
+		      CachedSize         *size,
+		      GtkCellAreaContext *context)
+{
+  gint height = GPOINTER_TO_INT (height_ptr);
+
+  /* Notify size invalidated */
+  g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], 
+		 0, height, -1, -1);
+}
+
+static void
+gtk_cell_area_context_real_flush_preferred_width_for_height (GtkCellAreaContext *context,
+							     gint                height)
+{
+  GtkCellAreaContextPrivate *priv = context->priv;
+
+  /* Flush all sizes for special -1 value */
+  if (height < 0)
+    {
+      g_hash_table_foreach (priv->widths, (GHFunc)notify_invalid_width, context);
+      g_hash_table_remove_all (priv->widths);
+    }
+  else
+    {
+      g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
+
+      /* Notify size invalidated */
+      g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], 
+		     0, height, -1, -1);
+    }
+}
+
+static void
 gtk_cell_area_context_real_flush_allocation (GtkCellAreaContext *context)
 {
   GtkCellAreaContextPrivate *priv = context->priv;
@@ -309,7 +466,9 @@ gtk_cell_area_context_flush (GtkCellAreaContext *context)
   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
 
   gtk_cell_area_context_flush_preferred_width (context);
+  gtk_cell_area_context_flush_preferred_height_for_width (context, -1);
   gtk_cell_area_context_flush_preferred_height (context);
+  gtk_cell_area_context_flush_preferred_width_for_height (context, -1);
   gtk_cell_area_context_flush_allocation (context);
 }
 
@@ -322,6 +481,15 @@ gtk_cell_area_context_flush_preferred_width (GtkCellAreaContext *context)
 }
 
 void
+gtk_cell_area_context_flush_preferred_height_for_width (GtkCellAreaContext *context,
+							gint                for_width)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->flush_preferred_height_for_width (context, for_width);
+}
+
+void
 gtk_cell_area_context_flush_preferred_height (GtkCellAreaContext *context)
 {
   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
@@ -330,6 +498,15 @@ gtk_cell_area_context_flush_preferred_height (GtkCellAreaContext *context)
 }
 
 void
+gtk_cell_area_context_flush_preferred_width_for_height (GtkCellAreaContext *context,
+							gint                for_height)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->flush_preferred_width_for_height (context, for_height);
+}
+
+void
 gtk_cell_area_context_flush_allocation (GtkCellAreaContext *context)
 {
   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
@@ -351,6 +528,20 @@ gtk_cell_area_context_sum_preferred_width (GtkCellAreaContext *context)
 }
 
 void
+gtk_cell_area_context_sum_preferred_height_for_width (GtkCellAreaContext *context,
+						      gint                for_width)
+{
+  GtkCellAreaContextClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  class = GTK_CELL_AREA_CONTEXT_GET_CLASS (context);
+
+  if (class->sum_preferred_height_for_width)
+    class->sum_preferred_height_for_width (context, for_width);
+}
+
+void
 gtk_cell_area_context_sum_preferred_height (GtkCellAreaContext *context)
 {
   GtkCellAreaContextClass *class;
@@ -364,6 +555,20 @@ gtk_cell_area_context_sum_preferred_height (GtkCellAreaContext *context)
 }
 
 void
+gtk_cell_area_context_sum_preferred_width_for_height (GtkCellAreaContext *context,
+						      gint                for_height)
+{
+  GtkCellAreaContextClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  class = GTK_CELL_AREA_CONTEXT_GET_CLASS (context);
+
+  if (class->sum_preferred_width_for_height)
+    class->sum_preferred_width_for_height (context, for_height);
+}
+
+void
 gtk_cell_area_context_allocate_width (GtkCellAreaContext *context,
 				      gint                width)
 {
@@ -408,6 +613,39 @@ gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context,
 }
 
 void
+gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context,
+						      gint                for_width,
+						      gint               *minimum_height,
+						      gint               *natural_height)
+{
+  GtkCellAreaContextPrivate *priv;
+  CachedSize                *size;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  priv = context->priv;
+
+  size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+
+  if (size)
+    {
+      if (minimum_height)
+	*minimum_height = size->min_size;
+
+      if (natural_height)
+	*natural_height = size->nat_size;
+    }
+  else
+    {
+      if (minimum_height)
+	*minimum_height = -1;
+
+      if (natural_height)
+	*natural_height = -1;
+    }
+}
+
+void
 gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context,
 					    gint               *minimum_height,
 					    gint               *natural_height)
@@ -426,6 +664,39 @@ gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context,
 }
 
 void
+gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context,
+						      gint                for_height,
+						      gint               *minimum_width,
+						      gint               *natural_width)
+{
+  GtkCellAreaContextPrivate *priv;
+  CachedSize                *size;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  priv = context->priv;
+
+  size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+
+  if (size)
+    {
+      if (minimum_width)
+	*minimum_width = size->min_size;
+
+      if (natural_width)
+	*natural_width = size->nat_size;
+    }
+  else
+    {
+      if (minimum_width)
+	*minimum_width = -1;
+
+      if (natural_width)
+	*natural_width = -1;
+    }
+}
+
+void
 gtk_cell_area_context_get_allocation (GtkCellAreaContext *context,
 				      gint               *width,
 				      gint               *height)
@@ -474,6 +745,50 @@ gtk_cell_area_context_push_preferred_width (GtkCellAreaContext *context,
 }
 
 void
+gtk_cell_area_context_push_preferred_height_for_width (GtkCellAreaContext *context,
+						       gint                for_width,
+						       gint                minimum_height,
+						       gint                natural_height)
+{
+  GtkCellAreaContextPrivate *priv;
+  CachedSize             *size;
+  gboolean                changed = FALSE;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  priv = context->priv;
+
+  size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+
+  if (!size)
+    {
+      size = cached_size_new (minimum_height, natural_height);
+
+      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size);
+
+      changed = TRUE;
+    }
+  else
+    {
+      if (minimum_height > size->min_size)
+	{
+	  size->min_size = minimum_height;
+	  changed = TRUE;
+	}
+
+      if (natural_height > size->nat_size)
+	{
+	  size->nat_size = natural_height;
+	  changed = TRUE;
+	}
+    }
+  
+  if (changed)
+    g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], 0, 
+		   for_width, size->min_size, size->nat_size);
+}
+
+void
 gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context,
 					     gint                minimum_height,
 					     gint                natural_height)
@@ -502,3 +817,47 @@ gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context,
 
   g_object_thaw_notify (G_OBJECT (context));
 }
+
+void
+gtk_cell_area_context_push_preferred_width_for_height (GtkCellAreaContext *context,
+						       gint                for_height,
+						       gint                minimum_width,
+						       gint                natural_width)
+{
+  GtkCellAreaContextPrivate *priv;
+  CachedSize             *size;
+  gboolean                changed = FALSE;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+
+  priv = context->priv;
+
+  size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+
+  if (!size)
+    {
+      size = cached_size_new (minimum_width, natural_width);
+
+      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size);
+
+      changed = TRUE;
+    }
+  else
+    {
+      if (minimum_width > size->min_size)
+	{
+	  size->min_size = minimum_width;
+	  changed = TRUE;
+	}
+
+      if (natural_width > size->nat_size)
+	{
+	  size->nat_size = natural_width;
+	  changed = TRUE;
+	}
+    }
+  
+  if (changed)
+    g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], 0, 
+		   for_height, size->min_size, size->nat_size);
+}
diff --git a/gtk/gtkcellareacontext.h b/gtk/gtkcellareacontext.h
index 0782f78..8e3621f 100644
--- a/gtk/gtkcellareacontext.h
+++ b/gtk/gtkcellareacontext.h
@@ -55,14 +55,22 @@ struct _GtkCellAreaContextClass
 
   /* Subclasses can use this to flush their alignments/allocations */
   void    (* flush_preferred_width)              (GtkCellAreaContext *context);
+  void    (* flush_preferred_height_for_width)   (GtkCellAreaContext *context,
+						  gint                width);
   void    (* flush_preferred_height)             (GtkCellAreaContext *context);
+  void    (* flush_preferred_width_for_height)   (GtkCellAreaContext *context,
+						  gint                height);
   void    (* flush_allocation)                   (GtkCellAreaContext *context);
 
   /* These must be invoked after a series of requests before consulting 
    * the context values, implementors use this to push the overall
    * requests while acconting for any internal alignments */
   void    (* sum_preferred_width)                (GtkCellAreaContext *context);
+  void    (* sum_preferred_height_for_width)     (GtkCellAreaContext *context,
+						  gint                width);
   void    (* sum_preferred_height)               (GtkCellAreaContext *context);
+  void    (* sum_preferred_width_for_height)     (GtkCellAreaContext *context,
+						  gint                height);
 
   /* Store an allocation value for a GtkCellArea contextual to a range of
    * treemodel rows */
@@ -85,13 +93,21 @@ GtkCellArea *gtk_cell_area_context_get_area                         (GtkCellArea
 /* Apis for GtkCellArea clients to flush the cache */
 void         gtk_cell_area_context_flush                            (GtkCellAreaContext *context);
 void         gtk_cell_area_context_flush_preferred_width            (GtkCellAreaContext *context);
+void         gtk_cell_area_context_flush_preferred_height_for_width (GtkCellAreaContext *context,
+								     gint                for_width);
 void         gtk_cell_area_context_flush_preferred_height           (GtkCellAreaContext *context);
+void         gtk_cell_area_context_flush_preferred_width_for_height (GtkCellAreaContext *context,
+								     gint                for_height);
 void         gtk_cell_area_context_flush_allocation                 (GtkCellAreaContext *context);
 
 /* Apis for GtkCellArea clients to sum up the results of a series of requests, this
  * call is required to reduce the processing while calculating the size of each row */
 void         gtk_cell_area_context_sum_preferred_width              (GtkCellAreaContext *context);
+void         gtk_cell_area_context_sum_preferred_height_for_width   (GtkCellAreaContext *context,
+								     gint                for_width);
 void         gtk_cell_area_context_sum_preferred_height             (GtkCellAreaContext *context);
+void         gtk_cell_area_context_sum_preferred_width_for_height   (GtkCellAreaContext *context,
+								     gint                for_height);
 
 /* Apis to set an allocation size in one dimension or another, the subclass specific context
  * will store allocated positions/sizes for individual cells or groups of cells */
@@ -104,9 +120,17 @@ void         gtk_cell_area_context_allocate_height                  (GtkCellArea
 void         gtk_cell_area_context_get_preferred_width              (GtkCellAreaContext *context,
 								     gint               *minimum_width,
 								     gint               *natural_width);
+void         gtk_cell_area_context_get_preferred_height_for_width   (GtkCellAreaContext *context,
+								     gint                for_width,
+								     gint               *minimum_height,
+								     gint               *natural_height);
 void         gtk_cell_area_context_get_preferred_height             (GtkCellAreaContext *context,
 								     gint               *minimum_height,
 								     gint               *natural_height);
+void         gtk_cell_area_context_get_preferred_width_for_height   (GtkCellAreaContext *context,
+								     gint                for_height,
+								     gint               *minimum_width,
+								     gint               *natural_width);
 void         gtk_cell_area_context_get_allocation                   (GtkCellAreaContext *context,
 								     gint               *width,
 								     gint               *height);
@@ -115,9 +139,17 @@ void         gtk_cell_area_context_get_allocation                   (GtkCellArea
 void         gtk_cell_area_context_push_preferred_width             (GtkCellAreaContext *context,
 								     gint                minimum_width,
 								     gint                natural_width);
+void         gtk_cell_area_context_push_preferred_height_for_width  (GtkCellAreaContext *context,
+								     gint                for_width,
+								     gint                minimum_height,
+								     gint                natural_height);
 void         gtk_cell_area_context_push_preferred_height            (GtkCellAreaContext *context,
 								     gint                minimum_height,
 								     gint                natural_height);
+void         gtk_cell_area_context_push_preferred_width_for_height  (GtkCellAreaContext *context,
+								     gint                for_height,
+								     gint                minimum_width,
+								     gint                natural_width);
 
 G_END_DECLS
 



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