Commit 6988f9b8 authored by Benjamin Otte's avatar Benjamin Otte

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.
parent c7fba52a
......@@ -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 (old_parent != NULL)
{
g_signal_emit (old_parent, cssnode_signals[NODE_REMOVED], 0, node, node->previous_sibling);
}
if (node->parent != parent)
if (old_parent != new_parent)
{
if (node->parent == NULL)
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);
gtk_css_node_set_children_changed (old_parent);
}
node->parent = 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 (parent)
if (new_parent)
{
if (node->visible)
gtk_css_node_set_children_changed (parent);
gtk_css_node_set_children_changed (new_parent);
g_object_ref (node);
if (node->pending_changes)
parent->needs_propagation = TRUE;
new_parent->needs_propagation = TRUE;
if (node->invalid && node->visible)
gtk_css_node_set_invalid (parent, TRUE);
gtk_css_node_set_invalid (new_parent, TRUE);
}
else
{
gtk_css_node_parent_was_unset (node);
}
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 (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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment