]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrbtree.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkrbtree.c
index fdd45ad81223e95d04b9a199205bda1cebb2baed..d3e1fef7a61b37624aac786e780daa1db567e56d 100644 (file)
@@ -12,9 +12,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -31,13 +29,29 @@ static void        _gtk_rbnode_rotate_right       (GtkRBTree  *tree,
 static void        _gtk_rbtree_insert_fixup       (GtkRBTree  *tree,
                                                   GtkRBNode  *node);
 static void        _gtk_rbtree_remove_node_fixup  (GtkRBTree  *tree,
-                                                  GtkRBNode  *node);
+                                                  GtkRBNode  *node,
+                                                   GtkRBNode  *parent);
 static inline void _fixup_validation              (GtkRBTree  *tree,
                                                   GtkRBNode  *node);
-static inline void _fixup_parity                  (GtkRBTree  *tree,
+static inline void _fixup_total_count             (GtkRBTree  *tree,
                                                   GtkRBNode  *node);
+#ifdef G_ENABLE_DEBUG  
+static void        _gtk_rbtree_test               (const gchar *where,
+                                                   GtkRBTree  *tree);
+static void        _gtk_rbtree_debug_spew         (GtkRBTree  *tree);
+#endif
 
+static const GtkRBNode nil = {
+  /* .flags = */ GTK_RBNODE_BLACK,
 
+  /* rest is NULL */
+};
+
+gboolean
+_gtk_rbtree_is_nil (GtkRBNode *node)
+{
+  return node == &nil;
+}
 
 static GtkRBNode *
 _gtk_rbnode_new (GtkRBTree *tree,
@@ -45,11 +59,11 @@ _gtk_rbnode_new (GtkRBTree *tree,
 {
   GtkRBNode *node = g_slice_new (GtkRBNode);
 
-  node->left = tree->nil;
-  node->right = tree->nil;
-  node->parent = tree->nil;
+  node->left = (GtkRBNode *) &nil;
+  node->right = (GtkRBNode *) &nil;
+  node->parent = (GtkRBNode *) &nil;
   node->flags = GTK_RBNODE_RED;
-  node->parity = 1;
+  node->total_count = 1;
   node->count = 1;
   node->children = NULL;
   node->offset = height;
@@ -59,15 +73,18 @@ _gtk_rbnode_new (GtkRBTree *tree,
 static void
 _gtk_rbnode_free (GtkRBNode *node)
 {
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+#ifdef G_ENABLE_DEBUG
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       node->left = (gpointer) 0xdeadbeef;
       node->right = (gpointer) 0xdeadbeef;
       node->parent = (gpointer) 0xdeadbeef;
+      node->total_count = 56789;
       node->offset = 56789;
       node->count = 56789;
       node->flags = 0;
     }
+#endif
   g_slice_free (GtkRBNode, node);
 }
 
@@ -76,25 +93,21 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
                         GtkRBNode *node)
 {
   gint node_height, right_height;
-  GtkRBNode *right = node->right;
-
-  g_return_if_fail (node != tree->nil);
-
-  node_height = node->offset -
-    (node->left?node->left->offset:0) -
-    (node->right?node->right->offset:0) -
-    (node->children?node->children->root->offset:0);
-  right_height = right->offset -
-    (right->left?right->left->offset:0) -
-    (right->right?right->right->offset:0) -
-    (right->children?right->children->root->offset:0);
+  GtkRBNode *right;
+
+  g_return_if_fail (!_gtk_rbtree_is_nil (node));
+  g_return_if_fail (!_gtk_rbtree_is_nil (node->right));
+
+  right = node->right;
+
+  node_height = GTK_RBNODE_GET_HEIGHT (node);
+  right_height = GTK_RBNODE_GET_HEIGHT (right);
   node->right = right->left;
-  if (right->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (right->left))
     right->left->parent = node;
 
-  if (right != tree->nil)
-    right->parent = node->parent;
-  if (node->parent != tree->nil)
+  right->parent = node->parent;
+  if (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node == node->parent->left)
        node->parent->left = right;
@@ -105,27 +118,20 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
     }
 
   right->left = node;
-  if (node != tree->nil)
-    node->parent = right;
-
-  node->count = 1 + (node->left?node->left->count:0) +
-    (node->right?node->right->count:0);
-  right->count = 1 + (right->left?right->left->count:0) +
-    (right->right?right->right->count:0);
-
-  node->offset = node_height +
-    (node->left?node->left->offset:0) +
-    (node->right?node->right->offset:0) +
-    (node->children?node->children->root->offset:0);
-  right->offset = right_height +
-    (right->left?right->left->offset:0) +
-    (right->right?right->right->offset:0) +
-    (right->children?right->children->root->offset:0);
+  node->parent = right;
+
+  node->count = 1 + node->left->count + node->right->count;
+  right->count = 1 + right->left->count + right->right->count;
+
+  node->offset = node_height + node->left->offset + node->right->offset +
+                 (node->children ? node->children->root->offset : 0);
+  right->offset = right_height + right->left->offset + right->right->offset +
+                  (right->children ? right->children->root->offset : 0);
 
   _fixup_validation (tree, node);
   _fixup_validation (tree, right);
-  _fixup_parity (tree, node);
-  _fixup_parity (tree, right);
+  _fixup_total_count (tree, node);
+  _fixup_total_count (tree, right);
 }
 
 static void
@@ -133,26 +139,22 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
                          GtkRBNode *node)
 {
   gint node_height, left_height;
-  GtkRBNode *left = node->left;
-
-  g_return_if_fail (node != tree->nil);
-
-  node_height = node->offset -
-    (node->left?node->left->offset:0) -
-    (node->right?node->right->offset:0) -
-    (node->children?node->children->root->offset:0);
-  left_height = left->offset -
-    (left->left?left->left->offset:0) -
-    (left->right?left->right->offset:0) -
-    (left->children?left->children->root->offset:0);
+  GtkRBNode *left;
+
+  g_return_if_fail (!_gtk_rbtree_is_nil (node));
+  g_return_if_fail (!_gtk_rbtree_is_nil (node->left));
+
+  left = node->left;
+
+  node_height = GTK_RBNODE_GET_HEIGHT (node);
+  left_height = GTK_RBNODE_GET_HEIGHT (left);
   
   node->left = left->right;
-  if (left->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (left->right))
     left->right->parent = node;
 
-  if (left != tree->nil)
-    left->parent = node->parent;
-  if (node->parent != tree->nil)
+  left->parent = node->parent;
+  if (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node == node->parent->right)
        node->parent->right = left;
@@ -166,27 +168,20 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
 
   /* link node and left */
   left->right = node;
-  if (node != tree->nil)
-    node->parent = left;
-
-  node->count = 1 + (node->left?node->left->count:0) +
-    (node->right?node->right->count:0);
-  left->count = 1 + (left->left?left->left->count:0) +
-    (left->right?left->right->count:0);
-
-  node->offset = node_height +
-    (node->left?node->left->offset:0) +
-    (node->right?node->right->offset:0) +
-    (node->children?node->children->root->offset:0);
-  left->offset = left_height +
-    (left->left?left->left->offset:0) +
-    (left->right?left->right->offset:0) +
-    (left->children?left->children->root->offset:0);
+  node->parent = left;
+
+  node->count = 1 + node->left->count + node->right->count;
+  left->count = 1 + left->left->count + left->right->count;
+
+  node->offset = node_height + node->left->offset + node->right->offset +
+                 (node->children ? node->children->root->offset : 0);
+  left->offset = left_height + left->left->offset + left->right->offset +
+                 (left->children?left->children->root->offset:0);
 
   _fixup_validation (tree, node);
   _fixup_validation (tree, left);
-  _fixup_parity (tree, node);
-  _fixup_parity (tree, left);
+  _fixup_total_count (tree, node);
+  _fixup_total_count (tree, left);
 }
 
 static void
@@ -256,24 +251,25 @@ _gtk_rbtree_insert_fixup (GtkRBTree *tree,
 
 static void
 _gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
-                              GtkRBNode *node)
+                              GtkRBNode *node,
+                               GtkRBNode *parent)
 {
   while (node != tree->root && GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
     {
-      if (node == node->parent->left)
+      if (node == parent->left)
        {
-         GtkRBNode *w = node->parent->right;
+         GtkRBNode *w = parent->right;
          if (GTK_RBNODE_GET_COLOR (w) == GTK_RBNODE_RED)
            {
              GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_BLACK);
-             GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_RED);
-             _gtk_rbnode_rotate_left (tree, node->parent);
-             w = node->parent->right;
+             GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_RED);
+             _gtk_rbnode_rotate_left (tree, parent);
+             w = parent->right;
            }
          if (GTK_RBNODE_GET_COLOR (w->left) == GTK_RBNODE_BLACK && GTK_RBNODE_GET_COLOR (w->right) == GTK_RBNODE_BLACK)
            {
              GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
-             node = node->parent;
+             node = parent;
            }
          else
            {
@@ -282,29 +278,29 @@ _gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
                  GTK_RBNODE_SET_COLOR (w->left, GTK_RBNODE_BLACK);
                  GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
                  _gtk_rbnode_rotate_right (tree, w);
-                 w = node->parent->right;
+                 w = parent->right;
                }
-             GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (node->parent));
-             GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_BLACK);
+             GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (parent));
+             GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_BLACK);
              GTK_RBNODE_SET_COLOR (w->right, GTK_RBNODE_BLACK);
-             _gtk_rbnode_rotate_left (tree, node->parent);
+             _gtk_rbnode_rotate_left (tree, parent);
              node = tree->root;
            }
        }
       else
        {
-         GtkRBNode *w = node->parent->left;
+         GtkRBNode *w = parent->left;
          if (GTK_RBNODE_GET_COLOR (w) == GTK_RBNODE_RED)
            {
              GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_BLACK);
-             GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_RED);
-             _gtk_rbnode_rotate_right (tree, node->parent);
-             w = node->parent->left;
+             GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_RED);
+             _gtk_rbnode_rotate_right (tree, parent);
+             w = parent->left;
            }
          if (GTK_RBNODE_GET_COLOR (w->right) == GTK_RBNODE_BLACK && GTK_RBNODE_GET_COLOR (w->left) == GTK_RBNODE_BLACK)
            {
              GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
-             node = node->parent;
+             node = parent;
            }
          else
            {
@@ -313,15 +309,17 @@ _gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
                  GTK_RBNODE_SET_COLOR (w->right, GTK_RBNODE_BLACK);
                  GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
                  _gtk_rbnode_rotate_left (tree, w);
-                 w = node->parent->left;
+                 w = parent->left;
                }
-             GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (node->parent));
-             GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_BLACK);
+             GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (parent));
+             GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_BLACK);
              GTK_RBNODE_SET_COLOR (w->left, GTK_RBNODE_BLACK);
-             _gtk_rbnode_rotate_right (tree, node->parent);
+             _gtk_rbnode_rotate_right (tree, parent);
              node = tree->root;
            }
        }
+
+      parent = node->parent;
     }
   GTK_RBNODE_SET_COLOR (node, GTK_RBNODE_BLACK);
 }
@@ -335,16 +333,8 @@ _gtk_rbtree_new (void)
   retval->parent_tree = NULL;
   retval->parent_node = NULL;
 
-  retval->nil = g_slice_new (GtkRBNode);
-  retval->nil->left = NULL;
-  retval->nil->right = NULL;
-  retval->nil->parent = NULL;
-  retval->nil->flags = GTK_RBNODE_BLACK;
-  retval->nil->count = 0;
-  retval->nil->offset = 0;
-  retval->nil->parity = 0;
+  retval->root = (GtkRBNode *) &nil;
 
-  retval->root = retval->nil;
   return retval;
 }
 
@@ -371,53 +361,61 @@ _gtk_rbtree_free (GtkRBTree *tree)
   if (tree->parent_node &&
       tree->parent_node->children == tree)
     tree->parent_node->children = NULL;
-  _gtk_rbnode_free (tree->nil);
   g_free (tree);
 }
 
+static void
+gtk_rbnode_adjust (GtkRBTree *tree,
+                   GtkRBNode *node,
+                   int        count_diff,
+                   int        total_count_diff,
+                   int        offset_diff)
+{
+  while (tree && node && !_gtk_rbtree_is_nil (node))
+    {
+      _fixup_validation (tree, node);
+      node->offset += offset_diff;
+      node->count += count_diff;
+      node->total_count += total_count_diff;
+      
+      node = node->parent;
+      if (_gtk_rbtree_is_nil (node))
+       {
+         node = tree->parent_node;
+         tree = tree->parent_tree;
+          count_diff = 0;
+       }
+    }
+}
+
 void
 _gtk_rbtree_remove (GtkRBTree *tree)
 {
+#ifdef G_ENABLE_DEBUG  
   GtkRBTree *tmp_tree;
-  GtkRBNode *tmp_node;
-
-  gint height = tree->root->offset;
 
-#ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
 #endif
   
-  tmp_tree = tree->parent_tree;
-  tmp_node = tree->parent_node;
-
   /* ugly hack to make _fixup_validation work in the first iteration of the
    * loop below */
   GTK_RBNODE_UNSET_FLAG (tree->root, GTK_RBNODE_DESCENDANTS_INVALID);
   
-  while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-    {
-      _fixup_validation (tmp_tree, tmp_node);
-      tmp_node->offset -= height;
-
-      /* If the removed tree was odd, flip all parents */
-      if (tree->root->parity)
-        tmp_node->parity = !tmp_node->parity;
-      
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
-    }
+  gtk_rbnode_adjust (tree->parent_tree, 
+                     tree->parent_node,
+                     0,
+                     - (int) tree->root->total_count,
+                     - tree->root->offset);
 
+#ifdef G_ENABLE_DEBUG  
   tmp_tree = tree->parent_tree;
-  tmp_node = tree->parent_node;
+#endif
+
   _gtk_rbtree_free (tree);
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tmp_tree);
 #endif
 }
@@ -431,11 +429,9 @@ _gtk_rbtree_insert_after (GtkRBTree *tree,
 {
   GtkRBNode *node;
   gboolean right = TRUE;
-  GtkRBNode *tmp_node;
-  GtkRBTree *tmp_tree;  
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("\n\n_gtk_rbtree_insert_after: %p\n", current);
       _gtk_rbtree_debug_spew (tree);
@@ -443,49 +439,33 @@ _gtk_rbtree_insert_after (GtkRBTree *tree,
     }
 #endif /* G_ENABLE_DEBUG */  
 
-  if (current != NULL && current->right != tree->nil)
+  if (current != NULL && !_gtk_rbtree_is_nil (current->right))
     {
       current = current->right;
-      while (current->left != tree->nil)
+      while (!_gtk_rbtree_is_nil (current->left))
        current = current->left;
       right = FALSE;
     }
   /* setup new node */
   node = _gtk_rbnode_new (tree, height);
-  node->parent = (current?current:tree->nil);
 
   /* insert node in tree */
   if (current)
     {
+      node->parent = current;
       if (right)
        current->right = node;
       else
        current->left = node;
-      tmp_node = node->parent;
-      tmp_tree = tree;
+      gtk_rbnode_adjust (tree, node->parent,
+                         1, 1, height);
     }
   else
     {
+      g_assert (_gtk_rbtree_is_nil (tree->root));
       tree->root = node;
-      tmp_node = tree->parent_node;
-      tmp_tree = tree->parent_tree;
-    }
-
-  while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-    {
-      /* We only want to propagate the count if we are in the tree we
-       * started in. */
-      if (tmp_tree == tree)
-       tmp_node->count++;
-
-      tmp_node->parity += 1;
-      tmp_node->offset += height;
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
+      gtk_rbnode_adjust (tree->parent_tree, tree->parent_node,
+                         0, 1, height);
     }
 
   if (valid)
@@ -496,7 +476,7 @@ _gtk_rbtree_insert_after (GtkRBTree *tree,
   _gtk_rbtree_insert_fixup (tree, node);
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("_gtk_rbtree_insert_after finished...\n");
       _gtk_rbtree_debug_spew (tree);
@@ -516,11 +496,9 @@ _gtk_rbtree_insert_before (GtkRBTree *tree,
 {
   GtkRBNode *node;
   gboolean left = TRUE;
-  GtkRBNode *tmp_node;
-  GtkRBTree *tmp_tree;
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("\n\n_gtk_rbtree_insert_before: %p\n", current);
       _gtk_rbtree_debug_spew (tree);
@@ -528,50 +506,34 @@ _gtk_rbtree_insert_before (GtkRBTree *tree,
     }
 #endif /* G_ENABLE_DEBUG */
   
-  if (current != NULL && current->left != tree->nil)
+  if (current != NULL && !_gtk_rbtree_is_nil (current->left))
     {
       current = current->left;
-      while (current->right != tree->nil)
+      while (!_gtk_rbtree_is_nil (current->right))
        current = current->right;
       left = FALSE;
     }
 
   /* setup new node */
   node = _gtk_rbnode_new (tree, height);
-  node->parent = (current?current:tree->nil);
 
   /* insert node in tree */
   if (current)
     {
+      node->parent = current;
       if (left)
        current->left = node;
       else
        current->right = node;
-      tmp_node = node->parent;
-      tmp_tree = tree;
+      gtk_rbnode_adjust (tree, node->parent,
+                         1, 1, height);
     }
   else
     {
+      g_assert (_gtk_rbtree_is_nil (tree->root));
       tree->root = node;
-      tmp_node = tree->parent_node;
-      tmp_tree = tree->parent_tree;
-    }
-
-  while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-    {
-      /* We only want to propagate the count if we are in the tree we
-       * started in. */
-      if (tmp_tree == tree)
-       tmp_node->count++;
-
-      tmp_node->parity += 1;
-      tmp_node->offset += height;
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
+      gtk_rbnode_adjust (tree->parent_tree, tree->parent_node,
+                         0, 1, height);
     }
 
   if (valid)
@@ -582,7 +544,7 @@ _gtk_rbtree_insert_before (GtkRBTree *tree,
   _gtk_rbtree_insert_fixup (tree, node);
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("_gtk_rbtree_insert_before finished...\n");
       _gtk_rbtree_debug_spew (tree);
@@ -601,7 +563,7 @@ _gtk_rbtree_find_count (GtkRBTree *tree,
   GtkRBNode *node;
 
   node = tree->root;
-  while (node != tree->nil && (node->left->count + 1 != count))
+  while (!_gtk_rbtree_is_nil (node) && (node->left->count + 1 != count))
     {
       if (node->left->count >= count)
        node = node->left;
@@ -611,7 +573,7 @@ _gtk_rbtree_find_count (GtkRBTree *tree,
          node = node->right;
        }
     }
-  if (node == tree->nil)
+  if (_gtk_rbtree_is_nil (node))
     return NULL;
   return node;
 }
@@ -622,24 +584,14 @@ _gtk_rbtree_node_set_height (GtkRBTree *tree,
                             gint       height)
 {
   gint diff = height - GTK_RBNODE_GET_HEIGHT (node);
-  GtkRBNode *tmp_node = node;
-  GtkRBTree *tmp_tree = tree;
 
   if (diff == 0)
     return;
 
-  while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-    {
-      tmp_node->offset += diff;
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
-    }
+  gtk_rbnode_adjust (tree, node, 0, 0, diff);
+
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
 #endif
 }
@@ -658,7 +610,7 @@ _gtk_rbtree_node_mark_invalid (GtkRBTree *tree,
        return;
       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
       node = node->parent;
-      if (node == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
@@ -678,7 +630,7 @@ _gtk_rbtree_node_mark_invalid (GtkRBTree *tree,
     {
       _fixup_validation (tree, node);
       node = node->parent;
-      if (node == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
@@ -704,13 +656,13 @@ _gtk_rbtree_node_mark_valid (GtkRBTree *tree,
       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 != 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)))
+         (GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+         (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 == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
@@ -732,7 +684,7 @@ _gtk_rbtree_node_mark_valid (GtkRBTree *tree,
     {
       _fixup_validation (tree, node);
       node = node->parent;
-      if (node == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
@@ -750,11 +702,8 @@ _gtk_rbtree_column_invalid (GtkRBTree *tree)
 
   if (tree == NULL)
     return;
-  node = tree->root;
-  g_assert (node);
 
-  while (node->left != tree->nil)
-    node = node->left;
+  node = _gtk_rbtree_first (tree);
 
   do
     {
@@ -775,11 +724,8 @@ _gtk_rbtree_mark_invalid (GtkRBTree *tree)
 
   if (tree == NULL)
     return;
-  node = tree->root;
-  g_assert (node);
 
-  while (node->left != tree->nil)
-    node = node->left;
+  node = _gtk_rbtree_first (tree);
 
   do
     {
@@ -802,11 +748,7 @@ _gtk_rbtree_set_fixed_height (GtkRBTree *tree,
   if (tree == NULL)
     return;
 
-  node = tree->root;
-  g_assert (node);
-
-  while (node->left != tree->nil)
-    node = node->left;
+  node = _gtk_rbtree_first (tree);
 
   do
     {
@@ -823,65 +765,48 @@ _gtk_rbtree_set_fixed_height (GtkRBTree *tree,
   while ((node = _gtk_rbtree_next (tree, node)) != NULL);
 }
 
-typedef struct _GtkRBReorder
-{
-  GtkRBTree *children;
-  gint height;
-  gint flags;
-  gint order;
-  gint invert_order;
-  gint parity;
-} GtkRBReorder;
-
-static int
-gtk_rbtree_reorder_sort_func (gconstpointer a,
-                             gconstpointer b)
+static void
+reorder_prepare (GtkRBTree *tree,
+                 GtkRBNode *node,
+                 gpointer   data)
 {
-  return ((GtkRBReorder *) a)->order - ((GtkRBReorder *) b)->order;
+  node->offset -= node->left->offset + node->right->offset;
+  GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
 }
 
-static int
-gtk_rbtree_reorder_invert_func (gconstpointer a,
-                               gconstpointer b)
+static void
+reorder_fixup (GtkRBTree *tree,
+               GtkRBNode *node,
+               gpointer   data)
 {
-  return ((GtkRBReorder *) a)->invert_order - ((GtkRBReorder *) b)->invert_order;
+  node->offset += node->left->offset + node->right->offset;
+  node->count = 1 + node->left->count + node->right->count;
+  _fixup_validation (tree, node);
+  _fixup_total_count (tree, node);
 }
 
 static void
-gtk_rbtree_reorder_fixup (GtkRBTree *tree,
-                         GtkRBNode *node)
+reorder_copy_node (GtkRBTree *tree,
+                   GtkRBNode *to,
+                   GtkRBNode *from)
 {
-  if (node == tree->nil)
-    return;
-
-  node->parity = 1;
-
-  if (node->left != tree->nil)
-    {
-      gtk_rbtree_reorder_fixup (tree, node->left);
-      node->offset += node->left->offset;
-      node->parity += node->left->parity;
-    }
-  if (node->right != tree->nil)
-    {
-      gtk_rbtree_reorder_fixup (tree, node->right);
-      node->offset += node->right->offset;
-      node->parity += node->right->parity;
-    }
-      
-  if (node->children)
-    {
-      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);
+  to->flags = (to->flags & GTK_RBNODE_NON_COLORS) | GTK_RBNODE_GET_COLOR (from);
+
+  to->left = from->left;
+  if (!_gtk_rbtree_is_nil (to->left))
+    to->left->parent = to;
+
+  to->right = from->right;
+  if (!_gtk_rbtree_is_nil (to->right))
+    to->right->parent = to;
+
+  to->parent = from->parent;
+  if (_gtk_rbtree_is_nil (to->parent))
+    tree->root = to;
+  else if (to->parent->left == from)
+    to->parent->left = to;
+  else if (to->parent->right == from)
+    to->parent->right = to;
 }
 
 /* It basically pulls everything out of the tree, rearranges it, and puts it
@@ -895,65 +820,89 @@ _gtk_rbtree_reorder (GtkRBTree *tree,
                     gint      *new_order,
                     gint       length)
 {
-  GtkRBReorder reorder = { NULL };
-  GArray *array;
+  GtkRBNode **nodes;
   GtkRBNode *node;
-  gint i;
+  gint i, j;
   
   g_return_if_fail (tree != NULL);
   g_return_if_fail (length > 0);
   g_return_if_fail (tree->root->count == length);
   
-  /* Sort the trees values in the new tree. */
-  array = g_array_sized_new (FALSE, FALSE, sizeof (GtkRBReorder), length);
-  for (i = 0; i < length; i++)
-    {
-      reorder.order = new_order[i];
-      reorder.invert_order = i;
-      g_array_append_val (array, reorder);
-    }
+  nodes = g_new (GtkRBNode *, length);
 
-  g_array_sort(array, gtk_rbtree_reorder_sort_func);
+  _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, reorder_prepare, NULL);
 
-  /* rewind node*/
-  node = tree->root;
-  while (node && node->left != tree->nil)
-    node = node->left;
+  for (node = _gtk_rbtree_first (tree), i = 0;
+       node;
+       node = _gtk_rbtree_next (tree, node), i++)
+    {
+      nodes[i] = node;
+    }
 
   for (i = 0; i < length; i++)
     {
-      g_assert (node != tree->nil);
-      g_array_index (array, GtkRBReorder, i).children = node->children;
-      g_array_index (array, GtkRBReorder, i).flags = GTK_RBNODE_NON_COLORS & node->flags;
-      g_array_index (array, GtkRBReorder, i).height = GTK_RBNODE_GET_HEIGHT (node);
+      GtkRBNode tmp = { 0, };
+      GSList *l, *cycle = NULL;
 
-      node = _gtk_rbtree_next (tree, node);
-    }
+      tmp.offset = -1;
 
-  g_array_sort (array, gtk_rbtree_reorder_invert_func);
-  /* rewind node*/
-  node = tree->root;
-  while (node && node->left != tree->nil)
-    node = node->left;
+      /* already swapped */
+      if (nodes[i] == NULL)
+        continue;
+      /* no need to swap */
+      if (new_order[i] == i)
+        continue;
 
-  /* Go through the tree and change the values to the new ones. */
-  for (i = 0; i < length; i++)
-    {
-      reorder = g_array_index (array, GtkRBReorder, i);
-      node->children = reorder.children;
-      if (node->children)
-       node->children->parent_node = node;
-      node->flags = GTK_RBNODE_GET_COLOR (node) | reorder.flags;
-      /* We temporarily set the height to this. */
-      node->offset = reorder.height;
-      node = _gtk_rbtree_next (tree, node);
+      /* make a list out of the pending nodes */
+      for (j = i; new_order[j] != i; j = new_order[j])
+        {
+          cycle = g_slist_prepend (cycle, nodes[j]);
+          nodes[j] = NULL;
+        }
+
+      node = nodes[j];
+      reorder_copy_node (tree, &tmp, node);
+      for (l = cycle; l; l = l->next)
+        {
+          reorder_copy_node (tree, node, l->data);
+          node = l->data;
+        }
+
+      reorder_copy_node (tree, node, &tmp);
+      nodes[j] = NULL;
+      g_slist_free (cycle);
     }
-  gtk_rbtree_reorder_fixup (tree, tree->root);
 
-  g_array_free (array, TRUE);
+  _gtk_rbtree_traverse (tree, tree->root, G_POST_ORDER, reorder_fixup, NULL);
+
+  g_free (nodes);
 }
 
+/**
+ * _gtk_rbtree_contains:
+ * @tree: a tree
+ * @potential_child: a potential child of @tree
+ *
+ * Checks if @potential_child is a child (direct or via intermediate
+ * trees) of @tree.
+ *
+ * Returns: %TRUE if @potentitial_child is a child of @tree.
+ **/
+gboolean
+_gtk_rbtree_contains (GtkRBTree *tree,
+                      GtkRBTree *potential_child)
+{
+  g_return_val_if_fail (tree != NULL, FALSE);
+  g_return_val_if_fail (potential_child != NULL, FALSE);
+
+  do {
+    potential_child = potential_child->parent_tree;
+    if (potential_child == tree)
+      return TRUE;
+  } while (potential_child != NULL);
+
+  return FALSE;
+}
 
 gint
 _gtk_rbtree_node_find_offset (GtkRBTree *tree,
@@ -967,7 +916,7 @@ _gtk_rbtree_node_find_offset (GtkRBTree *tree,
   
   retval = node->left->offset;
 
-  while (tree && node && node != tree->nil)
+  while (tree && node && !_gtk_rbtree_is_nil (node))
     {
       last = node;
       node = node->parent;
@@ -976,7 +925,7 @@ _gtk_rbtree_node_find_offset (GtkRBTree *tree,
       if (node->right == last)
        retval += node->offset - node->right->offset;
       
-      if (node == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
@@ -989,46 +938,46 @@ _gtk_rbtree_node_find_offset (GtkRBTree *tree,
   return retval;
 }
 
-gint
-_gtk_rbtree_node_find_parity (GtkRBTree *tree,
-                              GtkRBNode *node)
+guint
+_gtk_rbtree_node_get_index (GtkRBTree *tree,
+                            GtkRBNode *node)
 {
   GtkRBNode *last;
-  gint retval;  
+  guint retval;  
   
   g_assert (node);
   g_assert (node->left);
   
-  retval = node->left->parity;
+  retval = node->left->total_count;
 
-  while (tree && node && node != tree->nil)
+  while (tree && node && !_gtk_rbtree_is_nil (node))
     {
       last = node;
       node = node->parent;
 
       /* Add left branch, plus children, iff we came from the right */
       if (node->right == last)
-       retval += node->parity - node->right->parity;
+       retval += node->total_count - node->right->total_count;
       
-      if (node == tree->nil)
+      if (_gtk_rbtree_is_nil (node))
        {
          node = tree->parent_node;
          tree = tree->parent_tree;
 
           /* Add the parent node, plus the left branch. */
          if (node)
-           retval += node->left->parity + 1; /* 1 == GTK_RBNODE_GET_PARITY() */
+           retval += node->left->total_count + 1; /* 1 == GTK_RBNODE_GET_PARITY() */
        }
     }
   
-  return retval % 2;
+  return retval;
 }
 
-gint
-_gtk_rbtree_real_find_offset (GtkRBTree  *tree,
-                             gint        height,
-                             GtkRBTree **new_tree,
-                             GtkRBNode **new_node)
+static gint
+gtk_rbtree_real_find_offset (GtkRBTree  *tree,
+                            gint        height,
+                            GtkRBTree **new_tree,
+                            GtkRBNode **new_node)
 {
   GtkRBNode *tmp_node;
 
@@ -1044,7 +993,7 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
   
     
   tmp_node = tree->root;
-  while (tmp_node != tree->nil &&
+  while (!_gtk_rbtree_is_nil (tmp_node) &&
         (tmp_node->left->offset > height ||
          (tmp_node->offset - tmp_node->right->offset) < height))
     {
@@ -1056,7 +1005,7 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
          tmp_node = tmp_node->right;
        }
     }
-  if (tmp_node == tree->nil)
+  if (_gtk_rbtree_is_nil (tmp_node))
     {
       *new_tree = NULL;
       *new_node = NULL;
@@ -1072,14 +1021,14 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
          *new_node = tmp_node;
          return (height - tmp_node->left->offset);
        }
-      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);
+      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;
@@ -1088,9 +1037,9 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
 
 gint
 _gtk_rbtree_find_offset (GtkRBTree  *tree,
-                             gint        height,
-                             GtkRBTree **new_tree,
-                             GtkRBNode **new_node)
+                        gint        height,
+                        GtkRBTree **new_tree,
+                        GtkRBNode **new_node)
 {
   g_assert (tree);
 
@@ -1102,7 +1051,57 @@ _gtk_rbtree_find_offset (GtkRBTree  *tree,
 
       return 0;
     }
-  return _gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
+  return gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
+}
+
+gboolean
+_gtk_rbtree_find_index (GtkRBTree  *tree,
+                        guint       index,
+                        GtkRBTree **new_tree,
+                        GtkRBNode **new_node)
+{
+  GtkRBNode *tmp_node;
+
+  g_assert (tree);
+
+  tmp_node = tree->root;
+  while (!_gtk_rbtree_is_nil (tmp_node))
+    {
+      if (tmp_node->left->total_count > index)
+        {
+          tmp_node = tmp_node->left;
+        }
+      else if (tmp_node->total_count - tmp_node->right->total_count <= index)
+        {
+          index -= tmp_node->total_count - tmp_node->right->total_count;
+          tmp_node = tmp_node->right;
+        }
+      else
+        {
+          index -= tmp_node->left->total_count;
+          break;
+        }
+    }
+  if (_gtk_rbtree_is_nil (tmp_node))
+    {
+      *new_tree = NULL;
+      *new_node = NULL;
+      return FALSE;
+    }
+
+  if (index > 0)
+    {
+      g_assert (tmp_node->children);
+
+      return _gtk_rbtree_find_index (tmp_node->children,
+                                     index - 1,
+                                     new_tree,
+                                     new_node);
+    }
+
+  *new_tree = tree;
+  *new_node = tmp_node;
+  return TRUE;
 }
 
 void
@@ -1110,16 +1109,15 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
                         GtkRBNode *node)
 {
   GtkRBNode *x, *y;
-  GtkRBTree *tmp_tree;
-  GtkRBNode *tmp_node;
   gint y_height;
+  guint y_total_count;
   
   g_return_if_fail (tree != NULL);
   g_return_if_fail (node != NULL);
 
   
 #ifdef G_ENABLE_DEBUG
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("\n\n_gtk_rbtree_remove_node: %p\n", node);
       _gtk_rbtree_debug_spew (tree);
@@ -1128,16 +1126,17 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
 #endif /* G_ENABLE_DEBUG */
   
   /* make sure we're deleting a node that's actually in the tree */
-  for (x = node; x->parent != tree->nil; x = x->parent)
+  for (x = node; !_gtk_rbtree_is_nil (x->parent); x = x->parent)
     ;
   g_return_if_fail (x == tree->root);
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     _gtk_rbtree_test (G_STRLOC, tree);
 #endif
   
-  if (node->left == tree->nil || node->right == tree->nil)
+  if (_gtk_rbtree_is_nil (node->left) ||
+      _gtk_rbtree_is_nil (node->right))
     {
       y = node;
     }
@@ -1145,43 +1144,24 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
     {
       y = node->right;
 
-      while (y->left != tree->nil)
+      while (!_gtk_rbtree_is_nil (y->left))
        y = y->left;
     }
 
-  /* adjust count only beneath tree */
-  for (x = y; x != tree->nil; x = x->parent)
-    {
-      x->count--;
-    }
-
-  /* offsets and parity adjust all the way up through parent trees */
-  y_height = GTK_RBNODE_GET_HEIGHT (y);
-
-  tmp_tree = tree;
-  tmp_node = y;
-  while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-    {
-      tmp_node->offset -= (y_height + (y->children?y->children->root->offset:0));
-      _fixup_validation (tmp_tree, tmp_node);
-      _fixup_parity (tmp_tree, tmp_node);
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
-    }
+  y_height = GTK_RBNODE_GET_HEIGHT (y) 
+             + (y->children ? y->children->root->offset : 0);
+  y_total_count = 1 + (y->children ? y->children->root->total_count : 0);
 
   /* x is y's only child, or nil */
-  if (y->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (y->left))
     x = y->left;
   else
     x = y->right;
 
   /* remove y from the parent chain */
-  x->parent = y->parent;
-  if (y->parent != tree->nil)
+  if (!_gtk_rbtree_is_nil (x))
+    x->parent = y->parent;
+  if (!_gtk_rbtree_is_nil (y->parent))
     {
       if (y == y->parent->left)
        y->parent->left = x;
@@ -1195,74 +1175,59 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
 
   /* We need to clean up the validity of the tree.
    */
+  gtk_rbnode_adjust (tree, y, -1, - y_total_count, - y_height);
 
-  tmp_tree = tree;
-  tmp_node = x;
-  do
-    {
-      /* We skip the first time, iff x is nil */
-      if (tmp_node != tmp_tree->nil)
-       {
-         _fixup_validation (tmp_tree, tmp_node);
-         _fixup_parity (tmp_tree, tmp_node);
-       }
-      tmp_node = tmp_node->parent;
-      if (tmp_node == tmp_tree->nil)
-       {
-         tmp_node = tmp_tree->parent_node;
-         tmp_tree = tmp_tree->parent_tree;
-       }
-    }
-  while (tmp_tree != NULL);
+  if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK)
+    _gtk_rbtree_remove_node_fixup (tree, x, y->parent);
 
   if (y != node)
     {
-      gint diff;
+      gint node_height, node_total_count;
 
-      /* Copy the node over */
-      if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
-       node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_BLACK);
-      else
-       node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_RED);
-      node->children = y->children;
-      if (y->children)
-       {
-         node->children = y->children;
-         node->children->parent_node = node;
-       }
-      else
-       {
-         node->children = NULL;
-       }
-      _fixup_validation (tree, node);
-      _fixup_parity (tree, node);
-      /* We want to see how different our height is from the previous node.
-       * To do this, we compare our current height with our supposed height.
+      /* We want to see how much we remove from the aggregate values.
+       * This is all the children we remove plus the node's values.
        */
-      diff = y_height - GTK_RBNODE_GET_HEIGHT (node);
-      tmp_tree = tree;
-      tmp_node = node;
+      node_height = GTK_RBNODE_GET_HEIGHT (node)
+                    + (node->children ? node->children->root->offset : 0);
+      node_total_count = 1
+                         + (node->children ? node->children->root->total_count : 0);
+
+      /* Move the node over */
+      if (GTK_RBNODE_GET_COLOR (node) != GTK_RBNODE_GET_COLOR (y))
+       y->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED);
+
+      y->left = node->left;
+      if (!_gtk_rbtree_is_nil (y->left))
+        y->left->parent = y;
+      y->right = node->right;
+      if (!_gtk_rbtree_is_nil (y->right))
+        y->right->parent = y;
+      y->parent = node->parent;
+      if (!_gtk_rbtree_is_nil (y->parent))
+        {
+          if (y->parent->left == node)
+            y->parent->left = y;
+          else
+            y->parent->right = y;
+        }
+      else
+        {
+          tree->root = y;
+        }
+      y->count = node->count;
+      y->total_count = node->total_count;
+      y->offset = node->offset;
 
-      while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
-       {
-         tmp_node->offset += diff;
-         _fixup_validation (tmp_tree, tmp_node);
-         _fixup_parity (tmp_tree, tmp_node);
-         tmp_node = tmp_node->parent;
-         if (tmp_node == tmp_tree->nil)
-           {
-             tmp_node = tmp_tree->parent_node;
-             tmp_tree = tmp_tree->parent_tree;
-           }
-       }
+      gtk_rbnode_adjust (tree, y, 
+                         0,
+                         y_total_count - node_total_count,
+                         y_height - node_height);
     }
 
-  if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK)
-    _gtk_rbtree_remove_node_fixup (tree, x);
-  _gtk_rbnode_free (y);
+  _gtk_rbnode_free (node);
 
 #ifdef G_ENABLE_DEBUG  
-  if (gtk_debug_flags & GTK_DEBUG_TREE)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
     {
       g_print ("_gtk_rbtree_remove_node finished...\n");
       _gtk_rbtree_debug_spew (tree);
@@ -1272,6 +1237,22 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
 #endif /* G_ENABLE_DEBUG */  
 }
 
+GtkRBNode *
+_gtk_rbtree_first (GtkRBTree *tree)
+{
+  GtkRBNode *node;
+
+  node = tree->root;
+
+  if (_gtk_rbtree_is_nil (node))
+    return NULL;
+
+  while (!_gtk_rbtree_is_nil (node->left))
+    node = node->left;
+
+  return node;
+}
+
 GtkRBNode *
 _gtk_rbtree_next (GtkRBTree *tree,
                  GtkRBNode *node)
@@ -1280,16 +1261,16 @@ _gtk_rbtree_next (GtkRBTree *tree,
   g_return_val_if_fail (node != NULL, NULL);
 
   /* Case 1: the node's below us. */
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     {
       node = node->right;
-      while (node->left != tree->nil)
+      while (!_gtk_rbtree_is_nil (node->left))
        node = node->left;
       return node;
     }
 
   /* Case 2: it's an ancestor */
-  while (node->parent != tree->nil)
+  while (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node->parent->right == node)
        node = node->parent;
@@ -1309,16 +1290,16 @@ _gtk_rbtree_prev (GtkRBTree *tree,
   g_return_val_if_fail (node != NULL, NULL);
 
   /* Case 1: the node's below us. */
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     {
       node = node->left;
-      while (node->right != tree->nil)
+      while (!_gtk_rbtree_is_nil (node->right))
        node = node->right;
       return node;
     }
 
   /* Case 2: it's an ancestor */
-  while (node->parent != tree->nil)
+  while (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node->parent->left == node)
        node = node->parent;
@@ -1345,7 +1326,7 @@ _gtk_rbtree_next_full (GtkRBTree  *tree,
     {
       *new_tree = node->children;
       *new_node = (*new_tree)->root;
-      while ((*new_node)->left != (*new_tree)->nil)
+      while (!_gtk_rbtree_is_nil ((*new_node)->left))
        *new_node = (*new_node)->left;
       return;
     }
@@ -1388,7 +1369,7 @@ _gtk_rbtree_prev_full (GtkRBTree  *tree,
        {
          *new_tree = (*new_node)->children;
          *new_node = (*new_tree)->root;
-         while ((*new_node)->right != (*new_tree)->nil)
+          while (!_gtk_rbtree_is_nil ((*new_node)->right))
            *new_node = (*new_node)->right;
        }
     }
@@ -1416,7 +1397,7 @@ _gtk_rbtree_traverse_pre_order (GtkRBTree             *tree,
                                GtkRBTreeTraverseFunc  func,
                                gpointer               data)
 {
-  if (node == tree->nil)
+  if (_gtk_rbtree_is_nil (node))
     return;
 
   (* func) (tree, node, data);
@@ -1430,7 +1411,7 @@ _gtk_rbtree_traverse_post_order (GtkRBTree             *tree,
                                 GtkRBTreeTraverseFunc  func,
                                 gpointer               data)
 {
-  if (node == tree->nil)
+  if (_gtk_rbtree_is_nil (node))
     return;
 
   _gtk_rbtree_traverse_post_order (tree, node->left, func, data);
@@ -1472,8 +1453,8 @@ void _fixup_validation (GtkRBTree *tree,
 {
   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
       GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_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)) ||
+      GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID) ||
+      GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID) ||
       (node->children != NULL && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)))
     {
       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
@@ -1485,67 +1466,49 @@ void _fixup_validation (GtkRBTree *tree,
 }
 
 static inline
-void _fixup_parity (GtkRBTree *tree,
+void _fixup_total_count (GtkRBTree *tree,
                    GtkRBNode *node)
 {
-  node->parity = 1 +
-    ((node->children != NULL && node->children->root != node->children->nil) ? node->children->root->parity : 0) + 
-    ((node->left != tree->nil) ? node->left->parity : 0) + 
-    ((node->right != tree->nil) ? node->right->parity : 0);
+  node->total_count = 1 +
+    (node->children != NULL ? node->children->root->total_count : 0) + 
+    node->left->total_count + node->right->total_count;
 }
 
 #ifdef G_ENABLE_DEBUG
 static guint
-get_parity (GtkRBNode *node)
+get_total_count (GtkRBNode *node)
 {
   guint child_total = 0;
-  guint rem;
-
-  /* The parity of a node is node->parity minus
-   * the parity of left, right, and children.
-   *
-   * This is equivalent to saying that if left, right, children
-   * sum to 0 parity, then node->parity is the parity of node,
-   * and if left, right, children are odd parity, then
-   * node->parity is the reverse of the node's parity.
-   */
-  
-  child_total += (guint) node->left->parity;
-  child_total += (guint) node->right->parity;
+
+  child_total += (guint) node->left->total_count;
+  child_total += (guint) node->right->total_count;
 
   if (node->children)
-    child_total += (guint) node->children->root->parity;
+    child_total += (guint) node->children->root->total_count;
 
-  rem = child_total % 2;
-  
-  if (rem == 0)
-    return node->parity;
-  else
-    return !node->parity;
+  return child_total + 1;
 }
 
 static guint
-count_parity (GtkRBTree *tree,
-              GtkRBNode *node)
+count_total (GtkRBTree *tree,
+             GtkRBNode *node)
 {
   guint res;
   
-  if (node == tree->nil)
+  if (_gtk_rbtree_is_nil (node))
     return 0;
   
   res =
-    count_parity (tree, node->left) +
-    count_parity (tree, node->right) +
+    count_total (tree, node->left) +
+    count_total (tree, node->right) +
     (guint)1 +
-    (node->children ? count_parity (node->children, node->children->root) : 0);
+    (node->children ? count_total (node->children, node->children->root) : 0);
 
-  res = res % (guint)2;
-  
-  if (res != node->parity)
-    g_print ("parity incorrect for node\n");
+  if (res != node->total_count)
+    g_print ("total count incorrect for node\n");
 
-  if (get_parity (node) != 1)
-    g_error ("Node has incorrect parity %u", get_parity (node));
+  if (get_total_count (node) != node->total_count)
+    g_error ("Node has incorrect total count %u, should be %u", node->total_count, get_total_count (node));
   
   return res;
 }
@@ -1555,7 +1518,7 @@ _count_nodes (GtkRBTree *tree,
               GtkRBNode *node)
 {
   gint res;
-  if (node == tree->nil)
+  if (_gtk_rbtree_is_nil (node))
     return 0;
 
   g_assert (node->left);
@@ -1577,25 +1540,25 @@ _gtk_rbtree_test_height (GtkRBTree *tree,
 
   /* This whole test is sort of a useless truism. */
   
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     computed_offset += node->left->offset;
 
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     computed_offset += node->right->offset;
 
-  if (node->children && node->children->root != node->children->nil)
+  if (node->children && !_gtk_rbtree_is_nil (node->children->root))
     computed_offset += node->children->root->offset;
 
   if (GTK_RBNODE_GET_HEIGHT (node) + computed_offset != node->offset)
     g_error ("node has broken offset\n");
 
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     _gtk_rbtree_test_height (tree, node->left);
 
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     _gtk_rbtree_test_height (tree, node->right);
 
-  if (node->children && node->children->root != node->children->nil)
+  if (node->children && !_gtk_rbtree_is_nil (node->children->root))
     _gtk_rbtree_test_height (node->children, node->children->root);
 }
 
@@ -1609,27 +1572,27 @@ _gtk_rbtree_test_dirty (GtkRBTree *tree,
     {
       g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_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)) ||
+               GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID) ||
+               GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID) ||
                (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)));
     }
   else
     {
       g_assert (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) &&
                ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID));
-      if (node->left != tree->nil)
+      if (!_gtk_rbtree_is_nil (node->left))
        g_assert (! GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
-      if (node->right != tree->nil)
+      if (!_gtk_rbtree_is_nil (node->right))
        g_assert (! GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID));
       if (node->children != NULL)
        g_assert (! GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID));
     }
 
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     _gtk_rbtree_test_dirty (tree, node->left, GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     _gtk_rbtree_test_dirty (tree, node->right, GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID));
-  if (node->children != NULL && node->children->root != node->children->nil)
+  if (node->children != NULL && !_gtk_rbtree_is_nil (node->children->root))
     _gtk_rbtree_test_dirty (node->children, node->children->root, GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID));
 }
 
@@ -1639,18 +1602,18 @@ static void
 _gtk_rbtree_test_structure_helper (GtkRBTree *tree,
                                   GtkRBNode *node)
 {
-  g_assert (node != tree->nil);
+  g_assert (!_gtk_rbtree_is_nil (node));
 
   g_assert (node->left != NULL);
   g_assert (node->right != NULL);
   g_assert (node->parent != NULL);
 
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     {
       g_assert (node->left->parent == node);
       _gtk_rbtree_test_structure_helper (tree, node->left);
     }
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     {
       g_assert (node->right->parent == node);
       _gtk_rbtree_test_structure_helper (tree, node->right);
@@ -1668,14 +1631,14 @@ static void
 _gtk_rbtree_test_structure (GtkRBTree *tree)
 {
   g_assert (tree->root);
-  if (tree->root == tree->nil)
+  if (_gtk_rbtree_is_nil (tree->root))
     return;
 
-  g_assert (tree->root->parent == tree->nil);
+  g_assert (_gtk_rbtree_is_nil (tree->root->parent));
   _gtk_rbtree_test_structure_helper (tree, tree->root);
 }
 
-void
+static void
 _gtk_rbtree_test (const gchar *where,
                   GtkRBTree   *tree)
 {
@@ -1689,9 +1652,7 @@ _gtk_rbtree_test (const gchar *where,
   while (tmp_tree->parent_tree)
     tmp_tree = tmp_tree->parent_tree;
   
-  g_assert (tmp_tree->nil != NULL);
-
-  if (tmp_tree->root == tmp_tree->nil)
+  if (_gtk_rbtree_is_nil (tmp_tree->root))
     return;
 
   _gtk_rbtree_test_structure (tmp_tree);
@@ -1702,7 +1663,7 @@ _gtk_rbtree_test (const gchar *where,
       
   _gtk_rbtree_test_height (tmp_tree, tmp_tree->root);
   _gtk_rbtree_test_dirty (tmp_tree, tmp_tree->root, GTK_RBNODE_FLAG_SET (tmp_tree->root, GTK_RBNODE_DESCENDANTS_INVALID));
-  g_assert (count_parity (tmp_tree, tmp_tree->root) == tmp_tree->root->parity);
+  g_assert (count_total (tmp_tree, tmp_tree->root) == tmp_tree->root->total_count);
 }
 
 static void
@@ -1718,7 +1679,7 @@ _gtk_rbtree_debug_spew_helper (GtkRBTree *tree,
           node,
           (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)?"BLACK":" RED ",
           node->offset,
-          node->parity?1:0,
+          node->total_count,
           (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID))?1:0,
           (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))?1:0,
           (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))?1:0);
@@ -1728,22 +1689,22 @@ _gtk_rbtree_debug_spew_helper (GtkRBTree *tree,
       _gtk_rbtree_debug_spew (node->children);
       g_print ("Done looking at child.\n");
     }
-  if (node->left != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->left))
     {
       _gtk_rbtree_debug_spew_helper (tree, node->left, depth+1);
     }
-  if (node->right != tree->nil)
+  if (!_gtk_rbtree_is_nil (node->right))
     {
       _gtk_rbtree_debug_spew_helper (tree, node->right, depth+1);
     }
 }
 
-void
+static void
 _gtk_rbtree_debug_spew (GtkRBTree *tree)
 {
   g_return_if_fail (tree != NULL);
 
-  if (tree->root == tree->nil)
+  if (_gtk_rbtree_is_nil (tree->root))
     g_print ("Empty tree...\n");
   else
     _gtk_rbtree_debug_spew_helper (tree, tree->root, 0);