summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2015-02-09 22:03:13 +0100
committerBenjamin Otte <otte@redhat.com>2015-03-18 15:23:31 +0100
commit507016cafc407b2c47aea3fd1483df75e9757f29 (patch)
treeccc744f661a37d0c21cf75e3b402ab1ffa6a40be /gtk
parent310f9f40dac12471197e33d745ae46dd0d8aeb22 (diff)
downloadgtk+-507016cafc407b2c47aea3fd1483df75e9757f29.tar.gz
cssnode: Refactor node tree modification code
This allows adding more API for it. It also includes code that tracks modifications and invalidates siblings and their positions whenever nodes get added or removed.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkcssnode.c142
-rw-r--r--gtk/gtkcssnodeprivate.h2
2 files changed, 97 insertions, 47 deletions
diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c
index 816c667d3d..92b165dfa3 100644
--- a/gtk/gtkcssnode.c
+++ b/gtk/gtkcssnode.c
@@ -359,73 +359,118 @@ gtk_css_node_parent_will_be_set (GtkCssNode *node)
GTK_CSS_NODE_GET_CLASS (node)->dequeue_validate (node);
}
-void
-gtk_css_node_set_parent (GtkCssNode *node,
- GtkCssNode *parent)
+static void
+gtk_css_node_unlink_from_siblings (GtkCssNode *node)
{
- if (node->parent == parent)
+ if (GTK_IS_CSS_TRANSIENT_NODE (node))
return;
- /* Take a reference here so the whole function has a reference */
- g_object_ref (node);
+ if (node->previous_sibling)
+ node->previous_sibling->next_sibling = node->next_sibling;
+ else
+ node->parent->first_child = node->next_sibling;
- if (node->parent != NULL)
+ if (node->next_sibling)
+ node->next_sibling->previous_sibling = node->previous_sibling;
+ else
+ node->parent->last_child = node->previous_sibling;
+
+ node->previous_sibling = NULL;
+ node->next_sibling = NULL;
+}
+
+static void
+gtk_css_node_link_to_siblings (GtkCssNode *node,
+ GtkCssNode *new_previous)
+{
+ if (GTK_IS_CSS_TRANSIENT_NODE (node))
+ return;
+
+ if (new_previous)
{
- if (!GTK_IS_CSS_TRANSIENT_NODE (node))
- {
- if (node->previous_sibling)
- node->previous_sibling->next_sibling = node->next_sibling;
- else
- node->parent->first_child = node->next_sibling;
+ node->previous_sibling = new_previous;
+ node->next_sibling = new_previous->next_sibling;
+ new_previous->next_sibling = node;
+ }
+ else
+ {
+ node->next_sibling = node->parent->first_child;
+ node->parent->first_child = node;
+ }
+
+ if (node->next_sibling)
+ node->next_sibling->previous_sibling = node;
+ else
+ node->parent->last_child = node;
+}
- if (node->next_sibling)
- node->next_sibling->previous_sibling = node->previous_sibling;
- else
- node->parent->last_child = node->previous_sibling;
+static void
+gtk_css_node_set_children_changed (GtkCssNode *node)
+{
+ if (node->children_changed)
+ return;
- node->parent->n_children--;
- }
+ node->children_changed = TRUE;
+ gtk_css_node_set_invalid (node, TRUE);
+}
- node->parent = NULL;
- node->next_sibling = NULL;
- node->previous_sibling = NULL;
+static void
+gtk_css_node_reposition (GtkCssNode *node,
+ GtkCssNode *parent,
+ GtkCssNode *previous)
+{
+ g_assert (! (parent == NULL && previous != NULL));
- g_object_unref (node);
+ /* Take a reference here so the whole function has a reference */
+ g_object_ref (node);
- if (parent == NULL)
- gtk_css_node_parent_was_unset (node);
- }
+ if (node->parent != NULL)
+ gtk_css_node_unlink_from_siblings (node);
- if (parent)
+ if (node->parent != parent)
{
if (node->parent == NULL)
- gtk_css_node_parent_will_be_set (node);
+ {
+ gtk_css_node_parent_will_be_set (node);
+ }
+ else
+ {
+ g_object_unref (node);
+ gtk_css_node_set_children_changed (node->parent);
+ }
node->parent = parent;
- if (!GTK_IS_CSS_TRANSIENT_NODE (node))
+ if (parent)
{
- parent->n_children++;
+ gtk_css_node_set_children_changed (parent);
+ g_object_ref (node);
- if (parent->last_child)
- {
- parent->last_child->next_sibling = node;
- node->previous_sibling = parent->last_child;
- }
- parent->last_child = node;
-
- if (parent->first_child == NULL)
- parent->first_child = node;
+ if (node->invalid)
+ gtk_css_node_set_invalid (parent, TRUE);
+ }
+ else
+ {
+ gtk_css_node_parent_was_unset (node);
}
-
- if (node->invalid)
- gtk_css_node_set_invalid (parent, TRUE);
}
+ if (parent)
+ gtk_css_node_link_to_siblings (node, previous);
+
gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
- if (node->parent == NULL)
- g_object_unref (node);
+ g_object_unref (node);
+}
+
+void
+gtk_css_node_set_parent (GtkCssNode *node,
+ GtkCssNode *parent)
+{
+ if (node->parent == parent)
+ return;
+
+ gtk_css_node_reposition (node, parent, parent ? parent->last_child : NULL);
}
GtkCssNode *
@@ -638,6 +683,11 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode)
return;
change = _gtk_css_change_for_child (cssnode->pending_changes);
+ if (cssnode->children_changed)
+ {
+ change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_ANY_SIBLING;
+ cssnode->children_changed = FALSE;
+ }
for (child = gtk_css_node_get_first_child (cssnode);
child;
@@ -671,11 +721,11 @@ gtk_css_node_validate (GtkCssNode *cssnode,
if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE))
change = GTK_CSS_CHANGE_ANY;
+ gtk_css_node_propagate_pending_changes (cssnode);
+
if (!cssnode->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes))
return;
- gtk_css_node_propagate_pending_changes (cssnode);
-
gtk_css_node_set_invalid (cssnode, FALSE);
change = cssnode->pending_changes;
diff --git a/gtk/gtkcssnodeprivate.h b/gtk/gtkcssnodeprivate.h
index 4207d2ff56..b1339b0b9c 100644
--- a/gtk/gtkcssnodeprivate.h
+++ b/gtk/gtkcssnodeprivate.h
@@ -43,7 +43,6 @@ struct _GtkCssNode
GtkCssNode *next_sibling;
GtkCssNode *first_child;
GtkCssNode *last_child;
- guint n_children;
GtkCssNodeDeclaration *decl;
GtkCssStyle *style;
@@ -51,6 +50,7 @@ struct _GtkCssNode
GtkCssChange pending_changes; /* changes that accumulated since the style was last computed */
guint invalid :1; /* node or a child needs to be validated (even if just for animation) */
+ guint children_changed :1; /* the children changed since last validation */
};
struct _GtkCssNodeClass