]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrbtree.c
Do without GtkSelectionWindow
[~andy/gtk] / gtk / gtkrbtree.c
index 9b50a1747d1bd039577baa4ee84cf5672df75cfc..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"
@@ -658,8 +656,8 @@ _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)) ||
-         (!_gtk_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-         (!_gtk_rbtree_is_nil (node->right) && 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);
@@ -767,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;
-  guint total_count;
-} 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 (_gtk_rbtree_is_nil (node))
-    return;
-
-  node->total_count = 1;
-
-  if (!_gtk_rbtree_is_nil (node->left))
-    {
-      gtk_rbtree_reorder_fixup (tree, node->left);
-      node->offset += node->left->offset;
-      node->total_count += node->left->total_count;
-    }
-  if (!_gtk_rbtree_is_nil (node->right))
-    {
-      gtk_rbtree_reorder_fixup (tree, node->right);
-      node->offset += node->right->offset;
-      node->total_count += node->right->total_count;
-    }
-      
-  if (node->children)
-    {
-      node->offset += node->children->root->offset;
-      node->total_count += node->children->root->total_count;
-    }
-  
-  if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
-      (!_gtk_rbtree_is_nil (node->right) && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-      (!_gtk_rbtree_is_nil (node->left) && 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
@@ -839,61 +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 = _gtk_rbtree_first (tree);
+  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 (!_gtk_rbtree_is_nil (node));
-      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 = _gtk_rbtree_first (tree);
+      /* 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,
@@ -964,11 +973,11 @@ _gtk_rbtree_node_get_index (GtkRBTree *tree,
   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;
 
@@ -1012,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;
@@ -1028,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);
 
@@ -1042,7 +1051,7 @@ _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
@@ -1444,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) ||
-      (!_gtk_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-      (!_gtk_rbtree_is_nil (node->right) && 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);
@@ -1563,8 +1572,8 @@ _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) ||
-               (!_gtk_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-               (!_gtk_rbtree_is_nil (node->right) && 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