diff options
author | Benjamin Otte <otte@redhat.com> | 2011-11-21 16:07:52 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2011-11-21 22:33:45 +0100 |
commit | 02671f9ec9388276571a51ce9fbeb30b030bb1f7 (patch) | |
tree | 1a6230b7b3cbc9a41cd1953dc976a5640ea27f9b /gtk/gtkrbtree.c | |
parent | 1dd9dd45c1654f6c13c8eb19f493028636e396b3 (diff) | |
download | gtk+-02671f9ec9388276571a51ce9fbeb30b030bb1f7.tar.gz |
rbtree: Move to an approach where we don't move contents
So instead of copying the children and height to the new node, we keep
the old node and copy all the old stuff to it.
This is necessary so the accessibility code can use the node as a key in
the hash table or store the node as a reference to the row instead of
GtkTreeRowReference. And because it already does that (oops), this fixes
a bunch of segfaults with a11y enabled.
Diffstat (limited to 'gtk/gtkrbtree.c')
-rw-r--r-- | gtk/gtkrbtree.c | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/gtk/gtkrbtree.c b/gtk/gtkrbtree.c index b8f912222d..d327268ff2 100644 --- a/gtk/gtkrbtree.c +++ b/gtk/gtkrbtree.c @@ -1199,37 +1199,54 @@ _gtk_rbtree_remove_node (GtkRBTree *tree, if (y != node) { - gint count_diff, height_diff; + gint node_height, node_total_count; - /* 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. */ - height_diff = y_height - - GTK_RBNODE_GET_HEIGHT (node) - - (node->children ? node->children->root->offset : 0); - count_diff = y->total_count - 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); - if (y->children) - { - node->children = y->children; - node->children->parent_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)) + { + node->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED); + y->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED); + } + + y->left = node->left; + if (y->left != tree->nil) + y->left->parent = y; + y->right = node->right; + if (y->right != tree->nil) + y->right->parent = y; + y->parent = node->parent; + if (y->parent != tree->nil) + { + if (y->parent->left == node) + y->parent->left = y; + else + y->parent->right = y; + } else - { - node->children = NULL; - } + { + tree->root = y; + } + y->count = node->count; + y->total_count = node->total_count; + y->offset = node->offset; - gtk_rbnode_adjust (tree, node, 0, count_diff, height_diff); + 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) + if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK) _gtk_rbtree_remove_node_fixup (tree, x); - _gtk_rbnode_free (y); + _gtk_rbnode_free (node); #ifdef G_ENABLE_DEBUG if (gtk_get_debug_flags () & GTK_DEBUG_TREE) |