]> Pileus Git - ~andy/gtk/commitdiff
Minor fix.
authorJonathan Blandford <jrb@redhat.com>
Tue, 4 Dec 2001 23:49:57 +0000 (23:49 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Tue, 4 Dec 2001 23:49:57 +0000 (23:49 +0000)
Tue Dec  4 18:38:35 2001  Jonathan Blandford  <jrb@redhat.com>

* demos/gtk-demo/main.c: (create_tree): Minor fix.

* docs/tree-column-sizing.txt: Update

* gtk/gtkrbtree.[ch]: Massive work to support validation.

* gtk/gtktreemodel.c: Doc fixes.

* gtk/gtktreeview.c: Incremental reflow added.
* gtk/gtktreeviewcolumn.c: ditto
* gtk/gtktreeviewcolumn.h: ditto

docs/tree-column-sizing.txt
gtk/gtkrbtree.c
gtk/gtkrbtree.h
gtk/gtktreemodel.c
gtk/gtktreeprivate.h
gtk/gtktreeview.c
gtk/gtktreeviewcolumn.c
gtk/gtktreeviewcolumn.h

index 09e872434a038cf8ef36da13eee246246dcf64c0..879b846285ef500c0073df8bfaa96802a4820680 100644 (file)
@@ -1,30 +1,19 @@
 The way that the GtkTreeView calculates sizing is pretty confusing.
 This is written down to help keep track of it in my head, and thus help
 anyone who hopes to work with the code in the future.
+-jrb
 
 HOW THE GTKTREEVIEW CALCULATES SIZE:
 ====================================
-When the view is given a new model, the first thing it does is walk
+ When the view is given a new model, the first thing it does is walk
 through the model at the top level, creating an GtkRBNode for each
 element of the model.  Each node has a height of 0.  The RBTree is kept
 updated as the models structure changes.  Additionally, the user can
 expand, collapse, and select rows at this stage.  The RBTree is accurate
--- it just doesn't have a height for any row.  
-
-When the TreeView is realized, it calculates the actual height of each
-row by walking the tree and measuring them.  While doing so, it gets the
-size of each column.
-
-
-
-Columns are initially marked as 'dirty'.  When sized,
-gtk_tree_view_check_dirty_and_clean () is called on each column.  This
-function walks through all visible columns, and sees if they're dirty or
-not.  If any are dirty, it then walks the tree, calling
-gtk_tree_view_calc_size on each row.  gtk_tree_view_calc_size requests
-the size of every dirty column in the tree.  Finally, it updates the
-size of the widget (including adjustments).
+-- it just has a height of zero for every row.
 
+When the widget is realized, it calls install_presize_handler, to setup
+the first-run function.  This is run before the expose event.
 
 HOW THE GTKTREEVIEWCOLUMN STORES SIZE:
 ======================================
@@ -32,23 +21,46 @@ HOW THE GTKTREEVIEWCOLUMN STORES SIZE:
 There are a number of size related fields in the GtkTreeViewColumn
 structure.  These are all valid after realization:
 
-  sizing           The sizing method to use when calculating the size
-                   of the column.  Can be grow_only, resizable, auto, and fixed.
+  column_type      The sizing method to use when calculating the size
+                   of the column.  Can be GROW_ONLY, AUTO, and FIXED.
 
-  requested_width   The width of the column as requested by the column
+  button_request    The width as requested by the button.
 
-  width             The actual width.  This is requested width for all
-                   columns but possibly the last one.
+  requested_width   The width of the column as requested by the column.
+                   It is the max requested width of the bcells in the
+                   column.  If the column_type is AUTO, then it is
+                   recalculated when a column changes.  Otherwise, it
+                   only grows.
+
+  resized_width     The width after the user has resized the column.
+
+  width             The actual width of the column as displayed.
 
   fixed_width       The requested fixed width for the column iff it's
                    sizing type is set to GTK_TREE_VIEW_COLUMN_FIXED.
+                   Used instead of requested_width in that case.
 
-  min_width        The minimum width the column can be
+  min_width        The minimum width the column can be.  If set to -1,
+                   this field is considered unset.
 
   max_width        The maximum width the column can be.  This can be
                    overridden for the last column, if the tree_view is
                    actually wider than the sum of all of the columns
-                   requested_widths.
+                   requested_widths.  If set to -1, this field is
+                   considered unset.
+
+
+  use_resized_width Use resized_width to determine the size.
+
+
+--
+tree_view->priv->width  = the width the widget wants to be, including headers.
+tree_view->priv->height = the height the widget requests.  It's the sum
+                         of the width of all visible columns.
+
+Both of these are calculated in _gtk_tree_view_update_size
+
+--
 
 The following invariants are true:
 
@@ -56,12 +68,9 @@ min_width is less than or equal to width
 
 max_width is greater than or equal to width
 
-(sizing == GTK_TREE_VIEW_COLUMN_FIXED) => (requested_width == fixed_width)
+min_width <= max_width
 
-(column != last visible column) => width == requested_width 
+(sizing == GTK_TREE_VIEW_COLUMN_FIXED) => (requested_width == fixed_width)
 
+(column != last visible column) => width == CLAMP (requested_width, min_width, max_width)
 
-/* Functions needed by gtktreeview for gtktreeviewcolumn */
-size_request_button
-set_width (for resizing resizable columns)
-calculate_width
index 9b0aaf5047b38787fc37957590a909cb5a659d99..9bba7ab6666fbd6aad579f51b5ea962733f11795 100644 (file)
@@ -571,9 +571,10 @@ _gtk_rbtree_remove (GtkRBTree *tree)
 
 
 GtkRBNode *
-_gtk_rbtree_insert_after (GtkRBTree  *tree,
-                         GtkRBNode  *current,
-                         gint        height)
+_gtk_rbtree_insert_after (GtkRBTree *tree,
+                         GtkRBNode *current,
+                         gint       height,
+                         gboolean   valid)
 {
   GtkRBNode *node;
   gboolean right = TRUE;
@@ -632,14 +633,20 @@ _gtk_rbtree_insert_after (GtkRBTree  *tree,
 
   if (gtk_debug_flags & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
-  
+
+  if (valid)
+    _gtk_rbtree_node_mark_valid (tree, node);
+  else
+    _gtk_rbtree_node_mark_invalid (tree, node);
+
   return node;
 }
 
 GtkRBNode *
-_gtk_rbtree_insert_before (GtkRBTree  *tree,
-                          GtkRBNode  *current,
-                          gint        height)
+_gtk_rbtree_insert_before (GtkRBTree *tree,
+                          GtkRBNode *current,
+                          gint       height,
+                          gboolean   valid)
 {
   GtkRBNode *node;
   gboolean left = TRUE;
@@ -698,7 +705,12 @@ _gtk_rbtree_insert_before (GtkRBTree  *tree,
 
   if (gtk_debug_flags & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
-  
+
+  if (valid)
+    _gtk_rbtree_node_mark_valid (tree, node);
+  else
+    _gtk_rbtree_node_mark_invalid (tree, node);
+
   return node;
 }
 
@@ -775,18 +787,22 @@ void
 _gtk_rbtree_node_mark_valid (GtkRBTree *tree,
                             GtkRBNode *node)
 {
-  if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))
+  if ((!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) &&
+      (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)))
     return;
 
   GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_INVALID);
+  GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_COLUMN_INVALID);
+
   do
     {
-      if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+      if ((GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) ||
+         (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) ||
          (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-         (node->left && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-         (node->right && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)))
+         (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+         (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)))
        return;
-         
+
       GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
       node = node->parent;
       if (node == NULL)
@@ -798,6 +814,34 @@ _gtk_rbtree_node_mark_valid (GtkRBTree *tree,
   while (node);
 }
 
+
+/* Assume tree is the root node as it doesn't set DESCENDANTS_INVALID above.
+ */
+void
+_gtk_rbtree_column_invalid (GtkRBTree *tree)
+{
+  GtkRBNode *node;
+
+  if (tree == NULL)
+    return;
+  node = tree->root;
+  g_assert (node);
+
+  while (node->left != tree->nil)
+    node = node->left;
+
+  do
+    {
+      if (! (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)))
+       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_COLUMN_INVALID);
+      GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+
+      if (node->children)
+       _gtk_rbtree_column_invalid (node->children);
+    }
+  while ((node = _gtk_rbtree_next (tree, node)) != NULL);
+}
+
 typedef struct _GtkRBReorder
 {
   GtkRBTree *children;
@@ -849,6 +893,14 @@ gtk_rbtree_reorder_fixup (GtkRBTree *tree,
       node->offset += node->children->root->offset;
       node->parity += node->children->root->parity;
     }
+  
+  if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+      (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+      (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+      (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)))
+    GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+  else
+    GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
 }
 
 /* It basically pulls everything out of the tree, rearranges it, and puts it
@@ -990,19 +1042,23 @@ _gtk_rbtree_node_find_parity (GtkRBTree *tree,
 }
 
 gint
-_gtk_rbtree_find_offset (GtkRBTree  *tree,
-                        gint        height,
-                        GtkRBTree **new_tree,
-                        GtkRBNode **new_node)
+_gtk_rbtree_real_find_offset (GtkRBTree  *tree,
+                             gint        height,
+                             GtkRBTree **new_tree,
+                             GtkRBNode **new_node)
 {
   GtkRBNode *tmp_node;
 
+  g_assert (tree);
+
   if (height < 0)
     {
       *new_tree = NULL;
       *new_node = NULL;
+
       return 0;
     }
+  
     
   tmp_node = tree->root;
   while (tmp_node != tree->nil &&
@@ -1033,20 +1089,40 @@ _gtk_rbtree_find_offset (GtkRBTree  *tree,
          *new_node = tmp_node;
          return (height - tmp_node->left->offset);
        }
-      return _gtk_rbtree_find_offset (tmp_node->children,
-                                     height - tmp_node->left->offset -
-                                     (tmp_node->offset -
-                                      tmp_node->left->offset -
-                                      tmp_node->right->offset -
-                                      tmp_node->children->root->offset),
-                                     new_tree,
-                                     new_node);
+      return _gtk_rbtree_real_find_offset (tmp_node->children,
+                                          height - tmp_node->left->offset -
+                                          (tmp_node->offset -
+                                           tmp_node->left->offset -
+                                           tmp_node->right->offset -
+                                           tmp_node->children->root->offset),
+                                          new_tree,
+                                          new_node);
     }
   *new_tree = tree;
   *new_node = tmp_node;
   return (height - tmp_node->left->offset);
 }
 
+gint
+_gtk_rbtree_find_offset (GtkRBTree  *tree,
+                             gint        height,
+                             GtkRBTree **new_tree,
+                             GtkRBNode **new_node)
+{
+  GtkRBNode *tmp_node;
+
+  g_assert (tree);
+
+  if ((height < 0) ||
+      (height >= tree->root->offset))
+    {
+      *new_tree = NULL;
+      *new_node = NULL;
+
+      return 0;
+    }
+  _gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
+}
 
 void
 _gtk_rbtree_remove_node (GtkRBTree *tree,
@@ -1069,7 +1145,6 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
   if (gtk_debug_flags & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
 
-
   if (node->left == tree->nil || node->right == tree->nil)
     {
       y = node;
index 793b8691ede499ad8414852b3feb429187ab5627..9db2ae2c26d983298fbe044f0c836ec2ff119b4c 100644 (file)
@@ -37,8 +37,16 @@ typedef enum
   GTK_RBNODE_IS_SEMI_COLLAPSED = 1 << 5,
   GTK_RBNODE_IS_SEMI_EXPANDED = 1 << 6,
   GTK_RBNODE_INVALID = 1 << 7,
-  GTK_RBNODE_DESCENDANTS_INVALID = 1 << 8,
-  GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT | GTK_RBNODE_IS_SELECTED | GTK_RBNODE_IS_PRELIT | GTK_RBNODE_IS_SEMI_COLLAPSED | GTK_RBNODE_IS_SEMI_EXPANDED | GTK_RBNODE_INVALID | GTK_RBNODE_DESCENDANTS_INVALID
+  GTK_RBNODE_COLUMN_INVALID = 1 << 8,
+  GTK_RBNODE_DESCENDANTS_INVALID = 1 << 9,
+  GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT |
+                         GTK_RBNODE_IS_SELECTED |
+                         GTK_RBNODE_IS_PRELIT |
+                          GTK_RBNODE_IS_SEMI_COLLAPSED |
+                          GTK_RBNODE_IS_SEMI_EXPANDED |
+                          GTK_RBNODE_INVALID |
+                          GTK_RBNODE_COLUMN_INVALID |
+                          GTK_RBNODE_DESCENDANTS_INVALID
 } GtkRBNodeColor;
 
 typedef struct _GtkRBTree GtkRBTree;
@@ -93,6 +101,7 @@ struct _GtkRBNode
   GtkRBTree *children;
 };
 
+
 #define GTK_RBNODE_GET_COLOR(node)             (node?(((node->flags&GTK_RBNODE_RED)==GTK_RBNODE_RED)?GTK_RBNODE_RED:GTK_RBNODE_BLACK):GTK_RBNODE_BLACK)
 #define GTK_RBNODE_SET_COLOR(node,color)       if((node->flags&color)!=color)node->flags=node->flags^(GTK_RBNODE_RED|GTK_RBNODE_BLACK)
 #define GTK_RBNODE_GET_HEIGHT(node)            (node->offset-(node->left->offset+node->right->offset+(node->children?node->children->root->offset:0)))
@@ -109,10 +118,12 @@ void       _gtk_rbtree_remove           (GtkRBTree              *tree);
 void       _gtk_rbtree_destroy          (GtkRBTree              *tree);
 GtkRBNode *_gtk_rbtree_insert_before    (GtkRBTree              *tree,
                                         GtkRBNode              *node,
-                                        gint                    height);
+                                        gint                    height,
+                                        gboolean                valid);
 GtkRBNode *_gtk_rbtree_insert_after     (GtkRBTree              *tree,
                                         GtkRBNode              *node,
-                                        gint                    height);
+                                        gint                    height,
+                                        gboolean                valid);
 void       _gtk_rbtree_remove_node      (GtkRBTree              *tree,
                                         GtkRBNode              *node);
 void       _gtk_rbtree_reorder          (GtkRBTree              *tree,
@@ -127,6 +138,7 @@ void       _gtk_rbtree_node_mark_invalid(GtkRBTree              *tree,
                                         GtkRBNode              *node);
 void       _gtk_rbtree_node_mark_valid  (GtkRBTree              *tree,
                                         GtkRBNode              *node);
+void       _gtk_rbtree_column_invalid   (GtkRBTree              *tree);
 gint       _gtk_rbtree_node_find_offset (GtkRBTree              *tree,
                                         GtkRBNode              *node);
 gint       _gtk_rbtree_node_find_parity (GtkRBTree              *tree,
index 05b2c4747e95dbd63750e269cbac52f4c6047e6c..18189d5a2927626d88aa10414d106843176611e4 100644 (file)
@@ -1093,6 +1093,16 @@ gtk_tree_model_row_has_child_toggled (GtkTreeModel *tree_model,
   g_signal_emit_by_name (tree_model, "row_has_child_toggled", path, iter);
 }
 
+/**
+ * gtk_tree_model_row_deleted:
+ * @tree_model: A #GtkTreeModel
+ * @path: A #GtkTreePath pointing to the previous location of the deleted row.
+ * 
+ * Emits the "row_deleted" signal on @tree_model.  This should be called by
+ * models after a row has been removed.  The location pointed to by @path should
+ * be the location that the row previously was at.  It may not be a valid
+ * location anymore.
+ **/
 void
 gtk_tree_model_row_deleted (GtkTreeModel *tree_model,
                            GtkTreePath  *path)
index 241d18793b35d34e811bcfd79a7a540ff88f082f..0ce4ac99406924ea29cb2226f310888f56749479 100644 (file)
@@ -28,8 +28,6 @@ extern "C" {
 #include <gtk/gtktreeview.h>
 #include <gtk/gtktreeselection.h>
 #include <gtk/gtkrbtree.h>
-
-
   
 #define TREE_VIEW_DRAG_WIDTH 6
 
@@ -53,11 +51,12 @@ enum
   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
 };
+  
 #define GTK_TREE_VIEW_SET_FLAG(tree_view, flag)   G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END
 #define GTK_TREE_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END
 #define GTK_TREE_VIEW_FLAG_SET(tree_view, flag)   ((tree_view->priv->flags&flag)==flag)
 #define TREE_VIEW_HEADER_HEIGHT(tree_view)        (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE)?tree_view->priv->header_height:0)
-#define TREE_VIEW_COLUMN_WIDTH(column)             (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width))
+#define TREE_VIEW_COLUMN_REQUESTED_WIDTH(column)  (CLAMP (column->requested_width, (column->min_width!=-1)?column->min_width:column->requested_width, (column->max_width!=-1)?column->max_width:column->requested_width))
 #define TREE_VIEW_DRAW_EXPANDERS(tree_view)       (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST)&&GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
 
  /* This lovely little value is used to determine how far away from the title bar
@@ -108,6 +107,8 @@ struct _GtkTreeViewPrivate
 
   GtkTreeViewColumn *expander_column;
   GtkTreeViewColumn *edited_column;
+  guint presize_handler_timer;
+  guint validate_rows_timer;
 
   /* Focus code */
   GtkTreeViewColumn *focus_column;
@@ -117,7 +118,6 @@ struct _GtkTreeViewPrivate
   GtkTreeRowReference *cursor;
 
   /* Column Resizing */
-  GdkGC *xor_gc;
   gint drag_pos;
   gint x_drag;
 
@@ -173,7 +173,8 @@ struct _GtkTreeViewPrivate
   guint drag_column_window_state : 3;
   /* hint to display rows in alternating colors */
   guint has_rules : 1;
-
+  guint mark_rows_col_dirty : 1;
+  
   /* interactive search */
   guint enable_search : 1;
   gint search_column;
@@ -183,8 +184,6 @@ struct _GtkTreeViewPrivate
   GtkDestroyNotify search_destroy;
 };
 
-#ifdef __GNUC__
-
 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
      if (!(expr))                                                       \
        {                                                                \
@@ -202,7 +201,7 @@ struct _GtkTreeViewPrivate
          return ret;                                                    \
        };                               }G_STMT_END
 
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{             \
+#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
      if (!(expr))                                                       \
        {                                                                \
          g_log (G_LOG_DOMAIN,                                           \
@@ -219,41 +218,6 @@ struct _GtkTreeViewPrivate
          return;                                                        \
        };                               }G_STMT_END
 
-#else
-
-#define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "file %s: line %d: assertion `%s' failed.\n"       \
-               "There is a disparity between the internal view of the GtkTreeView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                __FILE__,                                               \
-                __LINE__,                                               \
-                #expr);                                                 \
-         return ret;                                                    \
-       };                               }G_STMT_END
-
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "file %s: line %d: assertion '%s' failed.\n"            \
-               "There is a disparity between the internal view of the GtkTreeView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                __FILE__,                                               \
-                __LINE__,                                               \
-                #expr);                                                 \
-         return;                                                        \
-       };                               }G_STMT_END
-#endif
-
 
 /* functions that shouldn't be exported */
 void         _gtk_tree_selection_internal_select_node (GtkTreeSelection  *selection,
@@ -268,7 +232,6 @@ gboolean     _gtk_tree_view_find_node                 (GtkTreeView       *tree_v
 GtkTreePath *_gtk_tree_view_find_path                 (GtkTreeView       *tree_view,
                                                       GtkRBTree         *tree,
                                                       GtkRBNode         *node);
-void         _gtk_tree_view_update_size               (GtkTreeView       *tree_view);
 void         _gtk_tree_view_child_move_resize         (GtkTreeView       *tree_view,
                                                       GtkWidget         *widget,
                                                       gint               x,
@@ -296,7 +259,7 @@ gboolean _gtk_tree_view_column_cell_event   (GtkTreeViewColumn  *tree_column,
 void _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
                                          GtkCellEditable   *editable_widget);
 void _gtk_tree_view_column_stop_editing  (GtkTreeViewColumn *tree_column);
-                                        
+void _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view);                                       
 
 GtkTreeSelection* _gtk_tree_selection_new                (void);
 GtkTreeSelection* _gtk_tree_selection_new_with_tree_view (GtkTreeView      *tree_view);
index fdccdab76f37f31186033d46fcf81188398fc84f..f9dfd9964268e9b491a2cb04e1c563b3ac5c9736 100644 (file)
 #include "gtkbindings.h"
 #include "gtkcontainer.h"
 #include "gtkentry.h"
+#include "gtktreemodelsort.h"
 
 #include <string.h>
 #include <gdk/gdkkeysyms.h>
 
 #define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog"
-
+#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
+#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 50
 #define SCROLL_EDGE_SIZE 15
 #define EXPANDER_EXTRA_PADDING 4
 
@@ -249,6 +251,16 @@ static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *mode
                                                           gint            *new_order,
                                                           gpointer         data);
 
+/* Incremental reflow */
+static gboolean validate_row             (GtkTreeView *tree_view,
+                                         GtkRBTree   *tree,
+                                         GtkRBNode   *node,
+                                         GtkTreeIter *iter,
+                                         GtkTreePath *path);
+static void     validate_visible_area    (GtkTreeView *tree_view);
+static gboolean validate_rows_handler    (GtkTreeView *tree_view);
+static gboolean presize_handler_callback (gpointer     data);
+static void     install_presize_handler  (GtkTreeView *tree_view);
 
 
 /* Internal functions */
@@ -286,20 +298,11 @@ static gint     gtk_tree_view_new_column_width               (GtkTreeView
                                                              gint              *x);
 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment     *adjustment,
                                                              GtkTreeView       *tree_view);
-static gint     gtk_tree_view_insert_iter_height             (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkTreeIter       *iter,
-                                                             gint               depth);
 static void     gtk_tree_view_build_tree                     (GtkTreeView       *tree_view,
                                                              GtkRBTree         *tree,
                                                              GtkTreeIter       *iter,
                                                              gint               depth,
-                                                             gboolean           recurse,
-                                                             gboolean           calc_bounds);
-static void     gtk_tree_view_calc_size                      (GtkTreeView       *priv,
-                                                             GtkRBTree         *tree,
-                                                             GtkTreeIter       *iter,
-                                                             gint               depth);
+                                                             gboolean           recurse);
 static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView       *tree_view,
                                                              GtkTreeIter       *iter,
                                                              gint               depth,
@@ -309,7 +312,6 @@ static void     gtk_tree_view_discover_dirty                 (GtkTreeView
                                                              GtkRBTree         *tree,
                                                              GtkTreeIter       *iter,
                                                              gint               depth);
-static void     gtk_tree_view_check_dirty_and_clean          (GtkTreeView       *tree_view);
 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView       *tree_view,
                                                              GtkRBTree         *tree,
                                                              GtkRBNode         *node);
@@ -317,7 +319,6 @@ static void     gtk_tree_view_clamp_column_visible           (GtkTreeView
                                                              GtkTreeViewColumn *column);
 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
                                                              GdkEventMotion    *event);
-static void     _gtk_tree_view_update_col_width              (GtkTreeView       *tree_view);
 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView       *tree_view,
                                                              gint               count);
@@ -908,9 +909,9 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->priv->press_start_x = -1;
   tree_view->priv->press_start_y = -1;
   tree_view->priv->reorderable = FALSE;
+  tree_view->priv->presize_handler_timer = 0;
   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
-  _gtk_tree_view_update_size (tree_view);
   tree_view->priv->enable_search = TRUE;
   tree_view->priv->search_column = -1;
   tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
@@ -969,10 +970,10 @@ gtk_tree_view_set_property (GObject         *object,
 }
 
 static void
-gtk_tree_view_get_property (GObject         *object,
-                           guint            prop_id,
-                           GValue          *value,
-                           GParamSpec      *pspec)
+gtk_tree_view_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
 {
   GtkTreeView *tree_view;
 
@@ -1207,7 +1208,6 @@ gtk_tree_view_realize (GtkWidget *widget)
 
   tree_view = GTK_TREE_VIEW (widget);
 
-  gtk_tree_view_check_dirty_and_clean (GTK_TREE_VIEW (widget));
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
   /* Make the main, clipping window */
@@ -1267,11 +1267,7 @@ gtk_tree_view_realize (GtkWidget *widget)
                       widget->style->black:widget->style->white);
   values.function = GDK_XOR;
   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
-  tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
-                                                   &values,
-                                                   GDK_GC_FOREGROUND |
-                                                   GDK_GC_FUNCTION |
-                                                   GDK_GC_SUBWINDOW);
+
   /* Add them all up. */
   widget->style = gtk_style_attach (widget->style, widget->window);
   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
@@ -1290,9 +1286,9 @@ gtk_tree_view_realize (GtkWidget *widget)
   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
 
-  _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
+  install_presize_handler (tree_view); 
 
-if (GTK_WIDGET_CLASS (parent_class)->map)
+  if (GTK_WIDGET_CLASS (parent_class)->map)
     (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
 }
 
@@ -1323,6 +1319,12 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
       tree_view->priv->expand_collapse_timeout = 0;
     }
+  
+  if (tree_view->priv->presize_handler_timer != 0)
+    {
+      gtk_timeout_remove (tree_view->priv->presize_handler_timer);
+      tree_view->priv->presize_handler_timer = 0;
+    }
 
   for (list = tree_view->priv->columns; list; list = list->next)
     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
@@ -1349,12 +1351,6 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       tree_view->priv->drag_highlight_window = NULL;
     }
 
-  if (tree_view->priv->xor_gc)
-    {
-      gdk_gc_destroy (tree_view->priv->xor_gc);
-      tree_view->priv->xor_gc = NULL;
-    }
-
   /* GtkWidget::unrealize destroys children and widget->window */
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
@@ -1362,11 +1358,11 @@ gtk_tree_view_unrealize (GtkWidget *widget)
 
 /* GtkWidget::size_request helper */
 static void
-gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
+gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
 {
   GList *list;
 
-  tree_view->priv->header_height = 1;
+  tree_view->priv->header_height = 0;
 
   if (tree_view->priv->model)
     {
@@ -1379,15 +1375,69 @@ gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
            continue;
 
           column = list->data;
-
+         
           gtk_widget_size_request (column->button, &requisition);
-
-          _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
+         column->button_request = requisition.width;
           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
         }
     }
 }
 
+
+static void
+gtk_tree_view_update_size (GtkTreeView *tree_view)
+{
+  GList *list;
+  GtkTreeViewColumn *column;
+  gint i;
+
+  if (tree_view->priv->model == NULL)
+    {
+      tree_view->priv->width = 0;
+      tree_view->priv->height = 0;
+      return;
+    }
+
+  tree_view->priv->width = 0;
+  /* keep this in sync with size_allocate below */
+  for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
+    {
+      gint real_requested_width = 0;
+      column = list->data;
+      if (!column->visible)
+       continue;
+
+      if (column->use_resized_width)
+       {
+         real_requested_width = column->resized_width;
+       }
+      else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+       {
+         real_requested_width = column->fixed_width;
+       }
+      else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
+       {
+         real_requested_width = MAX (column->requested_width, column->button_request);
+       }
+      else
+       {
+         real_requested_width = column->requested_width;
+       }
+
+      if (column->min_width != -1)
+       real_requested_width = MAX (real_requested_width, column->min_width);
+      if (column->max_width != -1)
+       real_requested_width = MIN (real_requested_width, column->max_width);
+
+      tree_view->priv->width += real_requested_width;
+    }
+
+  if (tree_view->priv->tree == NULL)
+    tree_view->priv->height = 0;
+  else
+    tree_view->priv->height = tree_view->priv->tree->root->offset;
+}
+
 static void
 gtk_tree_view_size_request (GtkWidget      *widget,
                            GtkRequisition *requisition)
@@ -1399,7 +1449,8 @@ gtk_tree_view_size_request (GtkWidget      *widget,
 
   tree_view = GTK_TREE_VIEW (widget);
 
-  gtk_tree_view_size_request_buttons (tree_view);
+  gtk_tree_view_size_request_columns (tree_view);
+  gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
 
   requisition->width = tree_view->priv->width;
   requisition->height = tree_view->priv->height + tree_view->priv->header_height;
@@ -1420,31 +1471,66 @@ gtk_tree_view_size_request (GtkWidget      *widget,
 
 /* GtkWidget::size_allocate helper */
 static void
-gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
+gtk_tree_view_size_allocate_columns (GtkWidget *widget)
 {
   GtkTreeView *tree_view;
-  GList *list;
+  GList *list, *last_column;
   GtkTreeViewColumn *column;
   GtkAllocation allocation;
   gint width = 0;
 
   tree_view = GTK_TREE_VIEW (widget);
 
+  for (last_column = g_list_last (tree_view->priv->columns);
+       last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
+       last_column = last_column->prev)
+    ;
+  if (last_column == NULL)
+    return;
+
   allocation.y = 0;
   allocation.height = tree_view->priv->header_height;
 
-  for (list = tree_view->priv->columns; list != NULL; list = list->next)
+  for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
     {
+      gint real_requested_width = 0;
       column = list->data;
-
       if (!column->visible)
        continue;
 
+      if (column->use_resized_width)
+       {
+         real_requested_width = column->resized_width;
+       }
+      else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+       {
+         real_requested_width = column->fixed_width;
+       }
+      else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
+       {
+         real_requested_width = MAX (column->requested_width, column->button_request);
+       }
+      else
+       {
+         real_requested_width = column->requested_width;
+       }
+
+      if (column->min_width != -1)
+       real_requested_width = MAX (real_requested_width, column->min_width);
+      if (column->max_width != -1)
+       real_requested_width = MIN (real_requested_width, column->max_width);
+
       allocation.x = width;
+      column->width = real_requested_width;
+      if (list == last_column &&
+         width + real_requested_width < widget->allocation.width)
+       {
+         column->width += (widget->allocation.width - column->width - width);
+       }
+      g_object_notify (G_OBJECT (column), "width");
       allocation.width = column->width;
       width += column->width;
       gtk_widget_size_allocate (column->button, &allocation);
-
       if (column->window)
        gdk_window_move_resize (column->window,
                                 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
@@ -1466,8 +1552,6 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
 
   tree_view = GTK_TREE_VIEW (widget);
 
-  gtk_tree_view_check_dirty_and_clean (tree_view);
-
   tmp_list = tree_view->priv->children;
 
   while (tmp_list)
@@ -1494,12 +1578,11 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
                         MAX (tree_view->priv->width, allocation->width),
                         tree_view->priv->header_height);
       gdk_window_resize (tree_view->priv->bin_window,
-                        tree_view->priv->width,
+                        MAX (tree_view->priv->width, allocation->width),
                         allocation->height);
-      _gtk_tree_view_update_col_width (tree_view);
     }
 
-  gtk_tree_view_size_allocate_buttons (widget);
+  gtk_tree_view_size_allocate_columns (widget);
 
   tree_view->priv->hadjustment->page_size = allocation->width;
   tree_view->priv->hadjustment->page_increment = allocation->width;
@@ -1538,7 +1621,6 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
        }
       tree_view->priv->scroll_to_column = NULL;
     }
-
 }
 
 static gboolean
@@ -1754,6 +1836,8 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 
          gtk_grab_add (widget);
          GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
+         column->resized_width = column->width;
+         column->use_resized_width = TRUE;
 
          /* block attached dnd signal handler */
          drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
@@ -1765,6 +1849,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 
          tree_view->priv->drag_pos = i;
          tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
+         break;
        }
     }
   return TRUE;
@@ -1820,7 +1905,6 @@ gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
 {
   GtkTreeView *tree_view;
   gpointer drag_data;
-  gint width;
   gint x;
   gint i;
 
@@ -1839,9 +1923,6 @@ gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
   gtk_grab_remove (widget);
   gdk_pointer_ungrab (event->time);
 
-  width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
-  _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
-
   return TRUE;
 }
 
@@ -2263,6 +2344,9 @@ gtk_tree_view_motion_resize_column (GtkWidget      *widget,
 {
   gint x;
   gint new_width;
+  GtkTreeViewColumn *column;
+
+  column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos);
 
   if (event->is_hint || event->window != widget->window)
     gtk_widget_get_pointer (widget, &x, NULL);
@@ -2271,11 +2355,13 @@ gtk_tree_view_motion_resize_column (GtkWidget      *widget,
 
   new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
                                              GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
-  if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
-    _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
+  if (x != GTK_TREE_VIEW (widget)->priv->x_drag &&
+      (new_width != column->fixed_width));
+    {
+      column->resized_width = new_width;
+      gtk_widget_queue_resize (widget);
+    }
 
-  /* FIXME: Do we need to scroll */
-  _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
   return FALSE;
 }
 
@@ -2513,9 +2599,9 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
        return TRUE;
     }
 
-  gtk_tree_view_check_dirty_and_clean (GTK_TREE_VIEW (widget));
-
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->area.y);
+  validate_visible_area (tree_view);
+  
+  new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
   if (new_y < 0)
     new_y = 0;
   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
@@ -3023,39 +3109,319 @@ gtk_tree_view_focus_out (GtkWidget     *widget,
   return FALSE;
 }
 
-/* Incremental Reflow */
+
+/* Incremental Reflow
+ */
+
+/* Returns TRUE if it updated the size
+ */
+static gboolean
+validate_row (GtkTreeView *tree_view,
+             GtkRBTree   *tree,
+             GtkRBNode   *node,
+             GtkTreeIter *iter,
+             GtkTreePath *path)
+{
+  GtkTreeViewColumn *column;
+  GList *list;
+  gint height = 0;
+  gint horizontal_separator;
+  gint depth = gtk_tree_path_get_depth (path);
+  gboolean retval = FALSE;
+
+
+  /* double check the row needs validating */
+  if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
+      ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+    return FALSE;
+
+  gtk_widget_style_get (GTK_WIDGET (tree_view),
+                       "horizontal_separator", &horizontal_separator,
+                       NULL);
+
+  for (list = tree_view->priv->columns; list; list = list->next)
+    {
+      gint tmp_width;
+      gint tmp_height;
+
+      column = list->data;
+
+      if (! column->visible)
+       continue;
+
+      if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
+       continue;
+
+      if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+       continue;
+
+      gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
+                                              GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
+                                              node->children?TRUE:FALSE);
+      gtk_tree_view_column_cell_get_size (column,
+                                         NULL, NULL, NULL,
+                                         &tmp_width, &tmp_height);
+      height = MAX (height, tmp_height);
+
+      if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
+       tmp_width = tmp_width + horizontal_separator + depth * tree_view->priv->tab_offset;
+      else
+       tmp_width = tmp_width + horizontal_separator;
+
+      if (tmp_width > column->requested_width)
+       {
+         retval = TRUE;
+         column->requested_width = tmp_width;
+       }
+    }
+
+  if (height != GTK_RBNODE_GET_HEIGHT (node))
+    {
+      retval = TRUE;
+      _gtk_rbtree_node_set_height (tree, node, height);
+    }
+  _gtk_rbtree_node_mark_valid (tree, node);
+
+  return retval;
+}
+
 
 static void
 validate_visible_area (GtkTreeView *tree_view)
 {
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkRBTree *tree;
+  GtkRBNode *node;
+  gint y, height, offset;
+  gboolean validated_area = FALSE;
+
+  
+  if (tree_view->priv->tree == NULL)
+    return;
+  
+  if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
+    return;
+
+  
+  height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
+
+  y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, TREE_VIEW_HEADER_HEIGHT (tree_view));
+
+  offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+                                   &tree, &node);
+  if (node == NULL)
+    {
+      path = gtk_tree_path_new_root ();
+      _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+    }
+  else
+    {
+      path = _gtk_tree_view_find_path (tree_view, tree, node);
+      height += offset;
+    }
+
+  gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+  do
+    {
+      validated_area = validate_row (tree_view, tree, node, &iter, path) || validated_area;
+      height -= GTK_RBNODE_GET_HEIGHT (node);
+      if (node->children)
+       {
+         GtkTreeIter parent = iter;
+         gboolean has_child;
 
+         tree = node->children;
+         node = tree->root;
+
+          g_assert (node != tree->nil);
+
+         while (node->left != tree->nil)
+           node = node->left;
+         has_child = gtk_tree_model_iter_children (tree_view->priv->model,
+                                                   &iter,
+                                                   &parent);
+         TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
+         gtk_tree_path_append_index (path, 0);
+       }
+      else
+       {
+         gboolean done = FALSE;
+         do
+           {
+             node = _gtk_rbtree_next (tree, node);
+             if (node != NULL)
+               {
+                 gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
+                 done = TRUE;
+
+                 /* Sanity Check! */
+                 TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
+               }
+             else
+               {
+                 GtkTreeIter parent_iter = iter;
+                 gboolean has_parent;
+
+                 node = tree->parent_node;
+                 tree = tree->parent_tree;
+                 if (tree == NULL)
+                   break;
+                 has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
+                                                          &iter,
+                                                          &parent_iter);
+
+                 /* Sanity check */
+                 TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
+               }
+           }
+         while (!done);
+       }
+    }
+  while (node && height > 0);
+
+  if (validated_area)
+    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
 }
 
+/* Our strategy for finding nodes to validate is a little convoluted.  We find
+ * the left-most uninvalidated node.  We then try walking right, validating
+ * nodes.  Once we find a valid node, we repeat the previous process of finding
+ * the first invalid node.
+ */
+
 static gboolean
 validate_rows_handler (GtkTreeView *tree_view)
 {
+  GtkRBTree *tree = NULL;
+  GtkRBNode *node = NULL;
+  gboolean validated_area = FALSE;
+  gint retval = TRUE;
+  GtkTreePath *path = NULL;
+  GtkTreeIter iter;
+  gint i = 0;
   g_assert (tree_view);
+  g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
 
-  g_return_val_if_fail (tree_view->priv->tree != NULL, TRUE);
+  GDK_THREADS_ENTER ();
 
-  if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
-    return TRUE;
+  do
+    {
+
+      if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
+       {
+         retval = FALSE;
+         goto done;
+       }
+
+      if (path != NULL)
+       {
+         node = _gtk_rbtree_next (tree, node);
+         if (node != NULL)
+           {
+             TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
+             gtk_tree_path_next (path);
+           }
+         else
+           {
+             gtk_tree_path_free (path);
+             path = NULL;
+           }
+       }
+
+      if (path == NULL)
+       {
+         tree = tree_view->priv->tree;
+         node = tree_view->priv->tree->root;
+
+         g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
+
+         do
+           {
+             if (node->left != tree->nil &&
+                 GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
+               {
+                 node = node->left;
+               }
+             else if (node->right != tree->nil &&
+                      GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
+               {
+                 node = node->right;
+               }
+             else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+                      GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+               {
+                 break;
+               }
+             else
+               {
+                 tree = node->children;
+                 node = tree->root;
+               }
+           }
+         while (TRUE);
+         path = _gtk_tree_view_find_path (tree_view, tree, node);
+         gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+       }
+      validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area;
+      i++;
+    }
+  while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
+  
+ done:
+  if (path) gtk_tree_path_free (path);
+  if (validated_area)
+    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+  if (! retval)
+    tree_view->priv->validate_rows_timer = 0;
 
+  GDK_THREADS_LEAVE ();
 
-  return TRUE;
+  return retval;
 }
 
 static gboolean
 presize_handler_callback (gpointer data)
 {
+  GtkTreeView *tree_view = GTK_TREE_VIEW (data);
 
-  return TRUE;
+  GDK_THREADS_ENTER ();
+
+  if (tree_view->priv->mark_rows_col_dirty)
+    {
+      _gtk_rbtree_column_invalid (tree_view->priv->tree);
+      tree_view->priv->mark_rows_col_dirty = FALSE;
+    }
+  validate_visible_area (tree_view);
+  tree_view->priv->presize_handler_timer = 0;
+                  
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
 }
 
 static void
 install_presize_handler (GtkTreeView *tree_view)
 {
+  if (! tree_view->priv->presize_handler_timer)
+    {
+      tree_view->priv->presize_handler_timer =
+       g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
+    }
+  if (! tree_view->priv->validate_rows_timer)
+    {
+      tree_view->priv->validate_rows_timer =
+       g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
+    }
+}
+
+
+void
+_gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
+{
+  tree_view->priv->mark_rows_col_dirty = TRUE;
 
+  install_presize_handler (tree_view);
 }
 
 /* Drag-and-drop */
@@ -4390,18 +4756,16 @@ _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
 
 static void
 gtk_tree_view_row_changed (GtkTreeModel *model,
-                            GtkTreePath  *path,
-                            GtkTreeIter  *iter,
-                            gpointer      data)
+                          GtkTreePath  *path,
+                          GtkTreeIter  *iter,
+                          gpointer      data)
 {
   GtkTreeView *tree_view = (GtkTreeView *)data;
   GtkRBTree *tree;
   GtkRBNode *node;
-  gint height;
-  gboolean dirty_marked;
   gboolean free_path = FALSE;
   gint vertical_separator;
-
+  GList *list;
 
   g_return_if_fail (path != NULL || iter != NULL);
 
@@ -4425,28 +4789,21 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   if (tree == NULL)
     goto done;
 
-  dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
-                                                   iter,
-                                                   gtk_tree_path_get_depth (path),
-                                                   &height,
-                                                   node);
-
-  if (height != -1 &&
-      GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
-    {
-      _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
-      gtk_widget_queue_resize (GTK_WIDGET (data));
-      _gtk_tree_view_update_size (tree_view);
-      goto done;
-    }
-  if (dirty_marked)
-    {
-      gtk_widget_queue_resize (GTK_WIDGET (data));
-    }
-  else
+  _gtk_rbtree_node_mark_invalid (tree, node);
+  for (list = tree_view->priv->columns; list; list = list->next)
     {
-      gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
+      GtkTreeViewColumn *column;
+
+      column = list->data;
+      if (! column->visible)
+       continue;
+
+      if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
+       {
+         gtk_tree_view_column_cell_set_dirty (column);
+       }
     }
+  install_presize_handler (tree_view);
 
  done:
   if (free_path)
@@ -4463,15 +4820,10 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
   gint *indices;
   GtkRBTree *tmptree, *tree;
   GtkRBNode *tmpnode = NULL;
-  gint max_height;
   gint depth;
   gint i = 0;
   gboolean free_path = FALSE;
 
-  if (tree_view->priv->tree == NULL)
-    tree_view->priv->tree = _gtk_rbtree_new ();
-
-  tmptree = tree = tree_view->priv->tree;
   g_return_if_fail (path != NULL || iter != NULL);
 
   if (path == NULL)
@@ -4482,6 +4834,11 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
   else if (iter == NULL)
     gtk_tree_model_get_iter (model, iter, path);
 
+  if (tree_view->priv->tree == NULL)
+    tree_view->priv->tree = _gtk_rbtree_new ();
+
+  tmptree = tree = tree_view->priv->tree;
+
   /* Update all row-references */
   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
   depth = gtk_tree_path_get_depth (path);
@@ -4528,28 +4885,23 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
 
   /* ref the node */
   gtk_tree_model_ref_node (tree_view->priv->model, iter);
-  max_height = gtk_tree_view_insert_iter_height (tree_view,
-                                                tree,
-                                                iter,
-                                                depth);
   if (indices[depth - 1] == 0)
     {
       tmpnode = _gtk_rbtree_find_count (tree, 1);
-      _gtk_rbtree_insert_before (tree, tmpnode, max_height);
+      _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE);
     }
   else
     {
       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
-      _gtk_rbtree_insert_after (tree, tmpnode, max_height);
+      _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
     }
-
-  _gtk_tree_view_update_size (tree_view);
+  install_presize_handler (tree_view);
 
  done:
   if (free_path)
     gtk_tree_path_free (path);
 }
-#include "gtktreemodelsort.h"
+
 static void
 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
                                     GtkTreePath  *path,
@@ -4699,7 +5051,7 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
       _gtk_rbtree_remove_node (tree, node);
     }
 
-  _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
+  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
 
   if (selection_changed)
     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
@@ -4851,71 +5203,19 @@ gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
     }
 }
 
-static gint
-gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
-                                 GtkRBTree   *tree,
-                                 GtkTreeIter *iter,
-                                 gint         depth)
-{
-  GtkTreeViewColumn *column;
-  GList *list;
-  gint max_height = 0;
-  gint vertical_separator;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view),        "vertical_separator", &vertical_separator, NULL);
-
-  /* do stuff with node */
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      gint height = 0, width = 0;
-      column = list->data;
-
-      if (!column->visible)
-       continue;
-
-      if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
-        continue;
-
-      gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
-                                              gtk_tree_model_iter_has_child (tree_view->priv->model, iter),
-                                              FALSE);
-
-      gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
-      max_height = MAX (max_height, vertical_separator + height);
-
-      if (gtk_tree_view_is_expander_column (tree_view, column) &&
-          TREE_VIEW_DRAW_EXPANDERS (tree_view))
-       _gtk_tree_view_column_set_width (column,
-                                        MAX (column->width, depth * tree_view->priv->tab_offset + width));
-      else
-        _gtk_tree_view_column_set_width (column,
-                                        MAX (column->width, width));
-    }
-  return max_height;
-}
-
 static void
 gtk_tree_view_build_tree (GtkTreeView *tree_view,
                          GtkRBTree   *tree,
                          GtkTreeIter *iter,
                          gint         depth,
-                         gboolean     recurse,
-                         gboolean     calc_bounds)
+                         gboolean     recurse)
 {
   GtkRBNode *temp = NULL;
-  gint max_height;
 
   do
     {
-      max_height = 0;
-      if (calc_bounds)
-       max_height = gtk_tree_view_insert_iter_height (tree_view,
-                                                      tree,
-                                                      iter,
-                                                      depth);
-
       gtk_tree_model_ref_node (tree_view->priv->model, iter);
-      temp = _gtk_rbtree_insert_after (tree, temp, max_height);
+      temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
       if (recurse)
        {
          GtkTreeIter child;
@@ -4925,7 +5225,7 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
              temp->children = _gtk_rbtree_new ();
              temp->children->parent_tree = tree;
              temp->children->parent_node = temp;
-             gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
+             gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
            }
        }
       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
@@ -4938,74 +5238,6 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
 }
 
-static void
-gtk_tree_view_calc_size (GtkTreeView *tree_view,
-                        GtkRBTree   *tree,
-                        GtkTreeIter *iter,
-                        gint         depth)
-{
-  GtkRBNode *temp;
-  GtkTreeIter child;
-  GList *list;
-  GtkTreeViewColumn *column;
-  gint max_height;
-  gint vertical_separator;
-  gint horizontal_separator;
-  TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view),
-                       "vertical_separator", &vertical_separator,
-                       "horizontal_separator", &horizontal_separator,
-                       NULL);
-
-  temp = tree->root;
-  while (temp->left != tree->nil)
-    temp = temp->left;
-
-  do
-    {
-      max_height = 0;
-      /* Do stuff with node */
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         gint height = 0, width = 0;
-         column = list->data;
-
-         if (!column->visible)
-           continue;
-
-         gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
-                                                  GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_IS_PARENT),
-                                                  temp->children?TRUE:FALSE);
-         gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
-         max_height = MAX (max_height, vertical_separator + height);
-
-         /* FIXME: I'm getting the width of all nodes here. )-: */
-         if (column->dirty == FALSE)
-           continue;
-
-         if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
-           {
-             continue;
-           }
-         if (gtk_tree_view_is_expander_column (tree_view, column) &&
-              TREE_VIEW_DRAW_EXPANDERS (tree_view))
-            _gtk_tree_view_column_set_width (column,
-                                            MAX (column->width, depth * tree_view->priv->tab_offset + width + horizontal_separator));
-         else
-            _gtk_tree_view_column_set_width (column, MAX (column->width, width + horizontal_separator));
-       }
-
-      _gtk_rbtree_node_set_height (tree, temp, max_height);
-
-      if (temp->children != NULL &&
-         gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
-       gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
-      temp = _gtk_rbtree_next (tree, temp);
-    }
-  while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
-}
-
 /* If height is non-NULL, then we set it to be the new height.  if it's all
  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
  */
@@ -5129,61 +5361,6 @@ gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
 }
 
 
-/**
- * gtk_tree_view_check_dirty_and_clean:
- * @tree_view: A #GtkTreeView
- *
- * Does all the actual sizing for
- **/
-static void
-gtk_tree_view_check_dirty_and_clean (GtkTreeView *tree_view)
-{
-  GtkTreePath *path;
-  gboolean dirty = FALSE;
-  GList *list;
-  GtkTreeViewColumn *column;
-  GtkTreeIter iter;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      column = list->data;
-      if (column->dirty)
-       {
-         dirty = TRUE;
-         if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
-           {
-              gint w = 1;
-
-              if (column->button)
-                w = MAX (w, column->button->requisition.width);
-
-              _gtk_tree_view_column_set_width (column, w);
-           }
-       }
-    }
-
-  if (dirty == FALSE)
-    return;
-
-  if (tree_view->priv->model == NULL)
-    return;
-
-  path = gtk_tree_path_new_root ();
-  if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
-    {
-      gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
-      _gtk_tree_view_update_size (tree_view);
-    }
-
-  gtk_tree_path_free (path);
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      column = list->data;
-      column->dirty = FALSE;
-    }
-}
-
 /* Make sure the node is visible vertically */
 static void
 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
@@ -5325,6 +5502,9 @@ gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
 {
   GList *list;
 
+  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
+    return FALSE;
+
   if (tree_view->priv->expander_column != NULL)
     {
       if (tree_view->priv->expander_column == column)
@@ -5677,6 +5857,7 @@ gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
 
   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
   rect.height = BACKGROUND_HEIGHT (node);
+  //  g_print ("gtk_tree_view_queue_draw_node: (%d %d) (%d %d)\n", rect.x, rect.y, rect.width, rect.height);
 
   if (clip_rect)
     {
@@ -5777,37 +5958,6 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
                      expander_style);
 }
 
-
-static void
-_gtk_tree_view_update_col_width (GtkTreeView *tree_view)
-{
-  GList *list, *last_column;
-  GtkTreeViewColumn *column;
-  gint width = 0;
-
-  for (last_column = g_list_last (tree_view->priv->columns);
-       last_column &&
-        !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
-        GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
-       last_column = last_column->prev)
-    ;
-
-  if (last_column == NULL)
-    return;
-
-  for (list = tree_view->priv->columns; list != last_column; list = list->next)
-    {
-      column = GTK_TREE_VIEW_COLUMN (list->data);
-      if (! column->visible)
-       continue;
-
-      width += column->width;
-      column->width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
-    }
-  column = GTK_TREE_VIEW_COLUMN (last_column->data);
-  column->width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
-}
-
 static void
 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
 
@@ -6281,64 +6431,6 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
   gtk_tree_view_search_init (entry, tree_view);
 }
 
-void
-_gtk_tree_view_update_size (GtkTreeView *tree_view)
-{
-  gint width, height;
-  GList *list;
-  GtkTreeViewColumn *column;
-  gint vertical_separator;
-  gint i;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
-
-  if (tree_view->priv->model == NULL)
-    {
-      tree_view->priv->width = 0;
-      tree_view->priv->height = 0;
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-      return;
-    }
-
-  width = 0;
-  for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
-    {
-      column = list->data;
-      if (!column->visible)
-       continue;
-      width += TREE_VIEW_COLUMN_WIDTH (column);
-    }
-
-  if (tree_view->priv->tree == NULL)
-    height = 0;
-  else
-    height = tree_view->priv->tree->root->offset + vertical_separator;
-
-  if (tree_view->priv->width != width)
-    {
-      tree_view->priv->width = width;
-      tree_view->priv->hadjustment->upper = width;
-      gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
-    }
-
-  if (tree_view->priv->height != height)
-    {
-      tree_view->priv->height = height;
-      tree_view->priv->vadjustment->upper = tree_view->priv->height;
-      gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
-    }
-
-  if (GTK_WIDGET_REALIZED (tree_view))
-    {
-      gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
-      gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
-
-      _gtk_tree_view_update_col_width (tree_view);
-    }
-
-  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-}
-
 /* this function returns the new width of the column being resized given
  * the column and x position of the cursor; the x cursor position is passed
  * in as a pointer and automagicly corrected if it's beyond min/max limits
@@ -6552,16 +6644,17 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
        {
          tree_view->priv->tree = _gtk_rbtree_new ();
-         gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
+         gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
        }
       gtk_tree_path_free (path);
 
       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
     }
 
-  if (GTK_WIDGET_REALIZED (tree_view))
-    _gtk_tree_view_update_size (tree_view);
   g_object_notify (G_OBJECT (tree_view), "model");
+
+  if (GTK_WIDGET_REALIZED (tree_view))
+    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
 }
 
 /**
@@ -7159,9 +7252,8 @@ gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
 
   if (GTK_WIDGET_REALIZED (tree_view))
     {
-      /*gtk_widget_queue_resize (GTK_WIDGET (tree_view)); */
-      _gtk_tree_view_update_size (tree_view);
-      gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
+      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+      gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
     }
 
   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
@@ -7432,8 +7524,7 @@ gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
                                node->children,
                                &child,
                                gtk_tree_path_get_depth (path) + 1,
-                               TRUE,
-                               GTK_WIDGET_REALIZED (tree_view));
+                               TRUE);
       gtk_tree_path_free (path);
     }
 }
@@ -7455,8 +7546,6 @@ gtk_tree_view_expand_all (GtkTreeView *tree_view)
                        G_PRE_ORDER,
                        gtk_tree_view_expand_all_helper,
                        tree_view);
-
-  _gtk_tree_view_update_size (tree_view);
 }
 
 /* Timeout to animate the expander during expands and collapses */
@@ -7609,8 +7698,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
                            node->children,
                            &temp,
                            gtk_tree_path_get_depth (path) + 1,
-                           open_all,
-                           GTK_WIDGET_REALIZED (tree_view));
+                           open_all);
 
   if (tree_view->priv->expand_collapse_timeout)
     {
@@ -7636,10 +7724,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
     }
 
   if (GTK_WIDGET_MAPPED (tree_view))
-    {
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-      _gtk_tree_view_update_size (tree_view);
-    }
+    install_presize_handler (tree_view);
 
   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
   return TRUE;
@@ -7778,8 +7863,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
   
   if (GTK_WIDGET_MAPPED (tree_view))
     {
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-      _gtk_tree_view_update_size (tree_view);
+      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
     }
 
   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
@@ -9455,4 +9539,3 @@ gtk_tree_view_stop_editing (GtkTreeView *tree_view)
   gtk_cell_editable_editing_done (tree_view->priv->edited_column->editable_widget);
   gtk_cell_editable_remove_widget (tree_view->priv->edited_column->editable_widget);
 }
-
index 849a14d9c77897037b51301876e7347544126599..c66b925b8f8a7f3be2d4afa18c59c5f151df39e8 100644 (file)
@@ -302,6 +302,7 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
   tree_column->requested_width = -1;
   tree_column->min_width = -1;
   tree_column->max_width = -1;
+  tree_column->resized_width = 0;
   tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
   tree_column->visible = TRUE;
   tree_column->resizable = FALSE;
@@ -315,6 +316,7 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
   tree_column->sort_column_id = -1;
   tree_column->reorderable = FALSE;
   tree_column->maybe_reordered = FALSE;
+  tree_column->use_resized_width = FALSE;
 }
 
 static void
@@ -355,6 +357,11 @@ gtk_tree_view_column_set_property (GObject         *object,
                                         g_value_get_boolean (value));
       break;
 
+    case PROP_RESIZABLE:
+      gtk_tree_view_column_set_resizable (tree_column,
+                                         g_value_get_boolean (value));
+      break;
+
     case PROP_SIZING:
       gtk_tree_view_column_set_sizing (tree_column,
                                        g_value_get_enum (value));
@@ -433,6 +440,11 @@ gtk_tree_view_column_get_property (GObject         *object,
                            gtk_tree_view_column_get_visible (tree_column));
       break;
 
+    case PROP_RESIZABLE:
+      g_value_set_boolean (value,
+                           gtk_tree_view_column_get_resizable (tree_column));
+      break;
+
     case PROP_WIDTH:
       g_value_set_int (value,
                        gtk_tree_view_column_get_width (tree_column));
@@ -711,8 +723,6 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
            }
        }
     }
-
-  gtk_tree_view_column_cell_set_dirty (tree_column);
 }
 
 /* Button signal handlers
@@ -787,7 +797,7 @@ gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
 
 static void
 gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
-                                         GtkTreeViewColumn *column)
+                                        GtkTreeViewColumn *column)
 {
   gint sort_column_id;
   GtkSortType order;
@@ -998,29 +1008,6 @@ _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
   column->button = NULL;
 }
 
-void
-_gtk_tree_view_column_set_width (GtkTreeViewColumn *tree_column,
-                                gint               width)
-{
-  if (tree_column->min_width != -1 &&
-      width <= tree_column->min_width)
-    width = tree_column->min_width;
-  else if (tree_column->max_width != -1 &&
-           width > tree_column->max_width)
-    width = tree_column->max_width;
-  
-  if (tree_column->width == width)
-    return;
-  
-  tree_column->width = width;
-
-  g_object_notify (G_OBJECT (tree_column), "width");
-
-  if (tree_column->tree_view != NULL)
-    gtk_widget_queue_resize (tree_column->tree_view);
-
-}
-
 /* Public Functions */
 
 
@@ -1142,6 +1129,12 @@ gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
 }
 
 
+/**
+ * gtk_tree_view_column_clear:
+ * @tree_column: A #GtkTreeViewColumn
+ * 
+ * Unsets all the mappings on all renderers on the @tree_column.
+ **/
 void
 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
 {
@@ -1161,6 +1154,15 @@ gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
   tree_column->cell_list = NULL;
 }
 
+/**
+ * gtk_tree_view_column_get_cell_renderers:
+ * @tree_column: A #GtkTreeViewColumn
+ * 
+ * Returns a newly allocated #GList of all the cell renderers in the column, in no
+ * particular order.  The list must be freed with g_list_free()
+ * 
+ * Return value: A list of #GtkCellRenderers
+ **/
 GList *
 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
 {
@@ -1431,6 +1433,8 @@ gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
   if (tree_column->resizable == resizable)
     return;
 
+  tree_column->resizable = resizable;
+
   if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
     gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
 
@@ -1537,16 +1541,21 @@ gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
     return;
 
   tree_column->fixed_width = fixed_width;
-  tree_column->requested_width = fixed_width;
-  _gtk_tree_view_column_set_width (tree_column, fixed_width);
+
+  if (tree_column->tree_view &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view) &&
+      tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+    {
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
 }
 
 /**
  * gtk_tree_view_column_get_fixed_width:
  * @tree_column: a #GtkTreeViewColumn
  * 
- * Gets the fixed width of the column.  This value is only meaning may not be the
- * actual width of the column on the screen, just what is requested.
+ * Gets the fixed width of the column.  This value is only meaning may not be
+ * the actual width of the column on the screen, just what is requested.
  * 
  * Return value: the fixed width of the column
  **/
@@ -1570,41 +1579,26 @@ void
 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
                                    gint               min_width)
 {
-  gint real_min_width;
-
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
   g_return_if_fail (min_width >= -1);
 
   if (min_width == tree_column->min_width)
     return;
 
-  if (tree_column->tree_view == NULL)
-    {
-      tree_column->min_width = min_width;
-      return;
-    }
-
-  real_min_width = (tree_column->min_width == -1) ?
-    tree_column->button->requisition.width : tree_column->min_width;
-
-  /* We want to queue a resize if the either the old min_size or the
-   * new min_size determined the size of the column */
-  if (GTK_WIDGET_REALIZED (tree_column->tree_view))
+  if (tree_column->visible &&
+      tree_column->tree_view != NULL &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
     {
-      if ((tree_column->min_width > tree_column->width) ||
-         (tree_column->min_width == -1 &&
-          tree_column->button->requisition.width > tree_column->width) ||
-         (min_width > tree_column->width) ||
-         (min_width == -1 &&
-          tree_column->button->requisition.width > tree_column->width))
+      if (min_width > tree_column->width)
        gtk_widget_queue_resize (tree_column->tree_view);
     }
 
-  if (tree_column->max_width != -1 && tree_column->max_width < real_min_width)
-    tree_column->max_width = real_min_width;
-
   tree_column->min_width = min_width;
-
+  if (tree_column->max_width != -1 && tree_column->max_width < min_width)
+    {
+      tree_column->max_width = min_width;
+      g_object_notify (G_OBJECT (tree_column), "max_width");
+    }
   g_object_notify (G_OBJECT (tree_column), "min_width");
 }
 
@@ -1633,40 +1627,32 @@ gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
  * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
  * maximum width is unset.  Note, the column can actually be wider than max
  * width if it's the last column in a view.  In this case, the column expands to
- * fill the view.
+ * fill any extra space.
  **/
 void
 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
                                    gint               max_width)
 {
-  gint real_max_width;
-
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
   g_return_if_fail (max_width >= -1);
 
   if (max_width == tree_column->max_width)
     return;
 
-  if (tree_column->tree_view == NULL)
+  if (tree_column->visible &&
+      tree_column->tree_view != NULL &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
     {
-      tree_column->max_width = max_width;
-      return;
+      if (max_width != -1 && max_width < tree_column->width)
+       gtk_widget_queue_resize (tree_column->tree_view);
     }
 
-  real_max_width = tree_column->max_width == -1 ?
-    tree_column->button->requisition.width : tree_column->max_width;
-
-  if (tree_column->tree_view &&
-      GTK_WIDGET_REALIZED (tree_column->tree_view) &&
-      ((tree_column->max_width < tree_column->width) ||
-       (max_width != -1 && max_width < tree_column->width)))
-    gtk_widget_queue_resize (tree_column->tree_view);
-
   tree_column->max_width = max_width;
-
-  if (real_max_width > max_width)
-    tree_column->max_width = max_width;
-
+  if (max_width != -1 && max_width < tree_column->min_width)
+    {
+      tree_column->min_width = max_width;
+      g_object_notify (G_OBJECT (tree_column), "min_width");
+    }
   g_object_notify (G_OBJECT (tree_column), "max_width");
 }
 
@@ -1692,7 +1678,7 @@ gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
  * @tree_column: a #GtkTreeViewColumn
  * 
  * Emits the "clicked" signal on the column.  This function will only work if
- * the user could have conceivably clicked on the button.
+ * @tree_column is clickable.
  **/
 void
 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
@@ -1759,10 +1745,11 @@ gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
 {
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
-  if (tree_column->clickable == (clickable?TRUE:FALSE))
+  clickable = !! clickable;
+  if (tree_column->clickable == clickable)
     return;
 
-  tree_column->clickable = (clickable?TRUE:FALSE);
+  tree_column->clickable = clickable;
   gtk_tree_view_column_update_button (tree_column);
   g_object_notify (G_OBJECT (tree_column), "clickable");
 }
@@ -1773,7 +1760,7 @@ gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
  * 
  * Returns %TRUE if the user can click on the header for the column.
  * 
- * Return value: whether the user can click the column header
+ * Return value: TRUE if user can click the column header
  **/
 gboolean
 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
@@ -2207,10 +2194,8 @@ gtk_tree_view_column_cell_render_or_focus (GtkTreeViewColumn *tree_column,
   for (list = tree_column->cell_list; list; list = list->next)
     {
       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-      gboolean visible;
 
-      g_object_get (info->cell, "visible", &visible, NULL);
-      if (visible == FALSE)
+      if (! info->cell->visible)
        continue;
 
       if (info->expand == TRUE)
@@ -2225,13 +2210,11 @@ gtk_tree_view_column_cell_render_or_focus (GtkTreeViewColumn *tree_column,
   for (list = tree_column->cell_list; list; list = list->next)
     {
       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-      gboolean visible;
 
       if (info->pack == GTK_PACK_END)
        continue;
 
-      g_object_get (info->cell, "visible", &visible, NULL);
-      if (visible == FALSE)
+      if (! info->cell->visible)
        continue;
 
       real_cell_area.width = info->requested_width +
@@ -2270,13 +2253,11 @@ gtk_tree_view_column_cell_render_or_focus (GtkTreeViewColumn *tree_column,
   for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
     {
       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-      gboolean visible;
 
       if (info->pack == GTK_PACK_START)
        continue;
 
-      g_object_get (info->cell, "visible", &visible, NULL);
-      if (visible == FALSE)
+      if (! info->cell->visible)
        continue;
 
       real_cell_area.width = info->requested_width +
@@ -2462,11 +2443,8 @@ gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
   for (list = tree_column->cell_list; list; list = list->next)
     {
       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-      gboolean visible;
 
-      g_object_get (G_OBJECT (info->cell), "visible", &visible, NULL);
-
-      if (visible)
+      if (info->cell->visible)
        return TRUE;
     }
 
@@ -2485,9 +2463,14 @@ gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column)
       info->requested_width = 0;
     }
   tree_column->dirty = TRUE;
+  tree_column->requested_width = 0;
 
-  if (tree_column->tree_view)
-    gtk_widget_queue_resize (tree_column->tree_view);
+  if (tree_column->tree_view &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
+    {
+      _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
 }
 
 void
index 726a3f7c223748f863eee94c47f64ea7f8f6b038..c81e583f5182ab96f6d7c7f3b50546b6f322ea48 100644 (file)
@@ -66,11 +66,16 @@ struct _GtkTreeViewColumn
   GtkCellEditable *editable_widget;
   gfloat xalign;
   guint property_changed_signal;
-
   gint spacing;
-  gint fixed_width;
-  gint width;
+
+  /* Sizing fields */
+  /* see gtk+/doc/tree-column-sizing.txt for more information on them */
+  GtkTreeViewColumnSizing column_type;
   gint requested_width;
+  gint button_request;
+  gint resized_width;
+  gint width;
+  gint fixed_width;
   gint min_width;
   gint max_width;
 
@@ -80,7 +85,6 @@ struct _GtkTreeViewColumn
 
   gchar *title;
   GList *cell_list;
-  GtkTreeViewColumnSizing column_type;
 
   /* Sorting */
   guint sort_clicked_signal;
@@ -96,6 +100,7 @@ struct _GtkTreeViewColumn
   guint show_sort_indicator : 1;
   guint maybe_reordered     : 1;
   guint reorderable         : 1;
+  guint use_resized_width   : 1;
 };
 
 struct _GtkTreeViewColumnClass