From 6988f9b818c398511378de5a28cd68b53745110b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 1 Mar 2015 21:33:54 +0100 Subject: [PATCH] cssnode: Add node-added and node-removed signal This allows monitoring the CSS tree. For now, moving a child to a different position relative to its siblings while keeping the same parent will cause a child-added + child-removed emission. --- gtk/gtkcssnode.c | 176 +++++++++++++++++++++++++--------------- gtk/gtkcssnodeprivate.h | 7 ++ 2 files changed, 117 insertions(+), 66 deletions(-) diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c index 462d55039b..e31690a97e 100644 --- a/gtk/gtkcssnode.c +++ b/gtk/gtkcssnode.c @@ -21,6 +21,8 @@ #include "gtkcssanimatedstyleprivate.h" #include "gtkdebug.h" +#include "gtkintl.h" +#include "gtkmarshalers.h" #include "gtksettingsprivate.h" /* When these change we do a full restyling. Otherwise we try to figure out @@ -29,6 +31,14 @@ G_DEFINE_TYPE (GtkCssNode, gtk_css_node, G_TYPE_OBJECT) +enum { + NODE_ADDED, + NODE_REMOVED, + LAST_SIGNAL +}; + +static guint cssnode_signals[LAST_SIGNAL] = { 0 }; + static GtkStyleProviderPrivate * gtk_css_node_get_style_provider_or_null (GtkCssNode *cssnode) { @@ -332,6 +342,51 @@ gtk_css_node_real_get_frame_clock (GtkCssNode *cssnode) return NULL; } +static void +gtk_css_node_real_node_removed (GtkCssNode *parent, + GtkCssNode *node, + GtkCssNode *previous) +{ + if (node->previous_sibling) + node->previous_sibling->next_sibling = node->next_sibling; + else + node->parent->first_child = node->next_sibling; + + 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; + node->parent = NULL; +} + +static void +gtk_css_node_real_node_added (GtkCssNode *parent, + GtkCssNode *node, + GtkCssNode *new_previous) +{ + if (new_previous) + { + node->previous_sibling = new_previous; + node->next_sibling = new_previous->next_sibling; + new_previous->next_sibling = node; + } + else + { + node->next_sibling = parent->first_child; + parent->first_child = node; + } + + if (node->next_sibling) + node->next_sibling->previous_sibling = node; + else + parent->last_child = node; + + node->parent = parent; +} + static void gtk_css_node_class_init (GtkCssNodeClass *klass) { @@ -350,6 +405,28 @@ gtk_css_node_class_init (GtkCssNodeClass *klass) klass->get_widget_path = gtk_css_node_real_get_widget_path; klass->get_style_provider = gtk_css_node_real_get_style_provider; klass->get_frame_clock = gtk_css_node_real_get_frame_clock; + + klass->node_added = gtk_css_node_real_node_added; + klass->node_removed = gtk_css_node_real_node_removed; + + cssnode_signals[NODE_ADDED] = + g_signal_new (I_("node-added"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCssNodeClass, node_added), + NULL, NULL, + _gtk_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + GTK_TYPE_CSS_NODE, GTK_TYPE_CSS_NODE); + cssnode_signals[NODE_REMOVED] = + g_signal_new (I_("node-removed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCssNodeClass, node_removed), + NULL, NULL, + _gtk_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + GTK_TYPE_CSS_NODE, GTK_TYPE_CSS_NODE); } static void @@ -397,44 +474,6 @@ gtk_css_node_parent_will_be_set (GtkCssNode *node) GTK_CSS_NODE_GET_CLASS (node)->dequeue_validate (node); } -static void -gtk_css_node_unlink_from_siblings (GtkCssNode *node) -{ - if (node->previous_sibling) - node->previous_sibling->next_sibling = node->next_sibling; - else - node->parent->first_child = node->next_sibling; - - 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 (new_previous) - { - 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; -} static void gtk_css_node_set_children_changed (GtkCssNode *node) @@ -464,23 +503,28 @@ gtk_css_node_invalidate_style (GtkCssNode *cssnode) static void gtk_css_node_reposition (GtkCssNode *node, - GtkCssNode *parent, + GtkCssNode *new_parent, GtkCssNode *previous) { - g_assert (! (parent == NULL && previous != NULL)); + GtkCssNode *old_parent; + g_assert (! (new_parent == NULL && previous != NULL)); + + old_parent = node->parent; /* Take a reference here so the whole function has a reference */ g_object_ref (node); if (node->next_sibling) gtk_css_node_invalidate_style (node->next_sibling); - if (node->parent != NULL) - gtk_css_node_unlink_from_siblings (node); - - if (node->parent != parent) + if (old_parent != NULL) { - if (node->parent == NULL) + g_signal_emit (old_parent, cssnode_signals[NODE_REMOVED], 0, node, node->previous_sibling); + } + + if (old_parent != new_parent) + { + if (old_parent == NULL) { gtk_css_node_parent_will_be_set (node); } @@ -488,34 +532,34 @@ gtk_css_node_reposition (GtkCssNode *node, { g_object_unref (node); if (node->visible) - gtk_css_node_set_children_changed (node->parent); - } - - node->parent = parent; - - if (parent) - { - if (node->visible) - gtk_css_node_set_children_changed (parent); - g_object_ref (node); - - if (node->pending_changes) - parent->needs_propagation = TRUE; - if (node->invalid && node->visible) - gtk_css_node_set_invalid (parent, TRUE); - } - else - { - gtk_css_node_parent_was_unset (node); + gtk_css_node_set_children_changed (old_parent); } if (gtk_css_node_get_style_provider_or_null (node) == NULL) gtk_css_node_invalidate_style_provider (node); gtk_css_node_invalidate (node, GTK_CSS_CHANGE_TIMESTAMP | GTK_CSS_CHANGE_ANIMATIONS); + + if (new_parent) + { + if (node->visible) + gtk_css_node_set_children_changed (new_parent); + g_object_ref (node); + + if (node->pending_changes) + new_parent->needs_propagation = TRUE; + if (node->invalid && node->visible) + gtk_css_node_set_invalid (new_parent, TRUE); + } + else + { + gtk_css_node_parent_was_unset (node); + } } - if (parent) - gtk_css_node_link_to_siblings (node, previous); + if (new_parent) + { + g_signal_emit (new_parent, cssnode_signals[NODE_ADDED], 0, node, previous); + } if (node->next_sibling) gtk_css_node_invalidate_style (node->next_sibling); diff --git a/gtk/gtkcssnodeprivate.h b/gtk/gtkcssnodeprivate.h index 611bc71b14..6cc9f72eba 100644 --- a/gtk/gtkcssnodeprivate.h +++ b/gtk/gtkcssnodeprivate.h @@ -65,6 +65,13 @@ struct _GtkCssNodeClass { GObjectClass object_class; + void (* node_added) (GtkCssNode *cssnode, + GtkCssNode *child, + GtkCssNode *previous); + void (* node_removed) (GtkCssNode *cssnode, + GtkCssNode *child, + GtkCssNode *previous); + gboolean (* init_matcher) (GtkCssNode *cssnode, GtkCssMatcher *matcher); GtkWidgetPath * (* create_widget_path) (GtkCssNode *cssnode);