Considerably speed up GtkUIManager, by changing the semantics of the dirty

2004-11-11  Matthias Clasen  <mclasen@redhat.com>

	Considerably speed up GtkUIManager, by changing the semantics
	of the dirty flag. It is now propagated up the tree, and
	update_node() doesn't descend into clean subtrees.  (#143668,
	Dave Neary, Michael Natterer, Sven Neumann, fix proposed
	by Soeren Sandmann)

	* gtk/gtkuimanager.c (node_prepend_ui_reference): Only prepend
	a new node reference if the merge_id is different. Take a GNode,
	so we can walk up the tree, adjust all callers.
	(node_remove_ui_reference): Only mark a node dirty if the first
	ui reference is removed. Take a GNode here as well for
	consistency.
	(update_node): Don't descend into clean subtrees.
	(mark_node_dirty): New function to mark a node and its
	predecessors dirty.
This commit is contained in:
Matthias Clasen 2004-11-11 18:13:19 +00:00 committed by Matthias Clasen
parent 7b1c2c1bea
commit 41628edebb
5 changed files with 547 additions and 471 deletions

View File

@ -1,3 +1,21 @@
2004-11-11 Matthias Clasen <mclasen@redhat.com>
Considerably speed up GtkUIManager, by changing the semantics
of the dirty flag. It is now propagated up the tree, and
update_node() doesn't descend into clean subtrees. (#143668,
Dave Neary, Michael Natterer, Sven Neumann, fix proposed
by Soeren Sandmann)
* gtk/gtkuimanager.c (node_prepend_ui_reference): Only prepend
a new node reference if the merge_id is different. Take a GNode,
so we can walk up the tree, adjust all callers.
(node_remove_ui_reference): Only mark a node dirty if the first
ui reference is removed. Take a GNode here as well for
consistency.
(update_node): Don't descend into clean subtrees.
(mark_node_dirty): New function to mark a node and its
predecessors dirty.
Thu Nov 11 11:34:32 2004 Jonathan Blandford <jrb@redhat.com>
* gtk/gtkfilechooserbutton.c (update_idler): return FALSE instead

View File

@ -1,3 +1,21 @@
2004-11-11 Matthias Clasen <mclasen@redhat.com>
Considerably speed up GtkUIManager, by changing the semantics
of the dirty flag. It is now propagated up the tree, and
update_node() doesn't descend into clean subtrees. (#143668,
Dave Neary, Michael Natterer, Sven Neumann, fix proposed
by Soeren Sandmann)
* gtk/gtkuimanager.c (node_prepend_ui_reference): Only prepend
a new node reference if the merge_id is different. Take a GNode,
so we can walk up the tree, adjust all callers.
(node_remove_ui_reference): Only mark a node dirty if the first
ui reference is removed. Take a GNode here as well for
consistency.
(update_node): Don't descend into clean subtrees.
(mark_node_dirty): New function to mark a node and its
predecessors dirty.
Thu Nov 11 11:34:32 2004 Jonathan Blandford <jrb@redhat.com>
* gtk/gtkfilechooserbutton.c (update_idler): return FALSE instead

View File

@ -1,3 +1,21 @@
2004-11-11 Matthias Clasen <mclasen@redhat.com>
Considerably speed up GtkUIManager, by changing the semantics
of the dirty flag. It is now propagated up the tree, and
update_node() doesn't descend into clean subtrees. (#143668,
Dave Neary, Michael Natterer, Sven Neumann, fix proposed
by Soeren Sandmann)
* gtk/gtkuimanager.c (node_prepend_ui_reference): Only prepend
a new node reference if the merge_id is different. Take a GNode,
so we can walk up the tree, adjust all callers.
(node_remove_ui_reference): Only mark a node dirty if the first
ui reference is removed. Take a GNode here as well for
consistency.
(update_node): Don't descend into clean subtrees.
(mark_node_dirty): New function to mark a node and its
predecessors dirty.
Thu Nov 11 11:34:32 2004 Jonathan Blandford <jrb@redhat.com>
* gtk/gtkfilechooserbutton.c (update_idler): return FALSE instead

View File

@ -1,3 +1,21 @@
2004-11-11 Matthias Clasen <mclasen@redhat.com>
Considerably speed up GtkUIManager, by changing the semantics
of the dirty flag. It is now propagated up the tree, and
update_node() doesn't descend into clean subtrees. (#143668,
Dave Neary, Michael Natterer, Sven Neumann, fix proposed
by Soeren Sandmann)
* gtk/gtkuimanager.c (node_prepend_ui_reference): Only prepend
a new node reference if the merge_id is different. Take a GNode,
so we can walk up the tree, adjust all callers.
(node_remove_ui_reference): Only mark a node dirty if the first
ui reference is removed. Take a GNode here as well for
consistency.
(update_node): Don't descend into clean subtrees.
(mark_node_dirty): New function to mark a node and its
predecessors dirty.
Thu Nov 11 11:34:32 2004 Jonathan Blandford <jrb@redhat.com>
* gtk/gtkfilechooserbutton.c (update_idler): return FALSE instead

View File

@ -117,6 +117,7 @@ static void gtk_ui_manager_get_property (GObject *object,
GParamSpec *pspec);
static void queue_update (GtkUIManager *self);
static void dirty_all_nodes (GtkUIManager *self);
static void mark_node_dirty (GNode *node);
static GNode * get_child_node (GtkUIManager *self,
GNode *parent,
const gchar *childname,
@ -129,10 +130,10 @@ static GNode * get_node (GtkUIManager *self,
NodeType node_type,
gboolean create);
static gboolean free_node (GNode *node);
static void node_prepend_ui_reference (Node *node,
static void node_prepend_ui_reference (GNode *node,
guint merge_id,
GQuark action_quark);
static void node_remove_ui_reference (Node *node,
static void node_remove_ui_reference (GNode *node,
guint merge_id);
@ -395,7 +396,7 @@ gtk_ui_manager_init (GtkUIManager *self)
merge_id = gtk_ui_manager_new_merge_id (self);
node = get_child_node (self, NULL, "ui", 2,
NODE_TYPE_ROOT, TRUE, FALSE);
node_prepend_ui_reference (NODE_INFO (node), merge_id, 0);
node_prepend_ui_reference (node, merge_id, 0);
}
static void
@ -869,12 +870,13 @@ get_child_node (GtkUIManager *self,
mnode = g_chunk_new0 (Node, merge_node_chunk);
mnode->type = node_type;
mnode->name = g_strndup (childname, childname_length);
mnode->dirty = TRUE;
if (top)
child = g_node_prepend_data (parent, mnode);
else
child = g_node_append_data (parent, mnode);
mark_node_dirty (child);
}
}
else
@ -986,26 +988,33 @@ gtk_ui_manager_new_merge_id (GtkUIManager *self)
}
static void
node_prepend_ui_reference (Node *node,
node_prepend_ui_reference (GNode *gnode,
guint merge_id,
GQuark action_quark)
{
NodeUIReference *reference;
Node *node = NODE_INFO (gnode);
NodeUIReference *reference = NULL;
if (node->uifiles &&
((NodeUIReference *)node->uifiles->data)->merge_id == merge_id)
reference = node->uifiles->data;
else
{
reference = g_new (NodeUIReference, 1);
reference->action_quark = action_quark;
reference->merge_id = merge_id;
/* Prepend the reference */
node->uifiles = g_list_prepend (node->uifiles, reference);
}
node->dirty = TRUE;
reference->merge_id = merge_id;
reference->action_quark = action_quark;
mark_node_dirty (gnode);
}
static void
node_remove_ui_reference (Node *node,
node_remove_ui_reference (GNode *gnode,
guint merge_id)
{
Node *node = NODE_INFO (gnode);
GList *p;
for (p = node->uifiles; p != NULL; p = p->next)
@ -1014,8 +1023,9 @@ node_remove_ui_reference (Node *node,
if (reference->merge_id == merge_id)
{
if (p == node->uifiles)
mark_node_dirty (gnode);
node->uifiles = g_list_delete_link (node->uifiles, p);
node->dirty = TRUE;
g_free (reference);
break;
@ -1128,9 +1138,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (ctx->current)->action_name == 0)
NODE_INFO (ctx->current)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1142,8 +1150,7 @@ start_element_handler (GMarkupParseContext *context,
ctx->current = self->private_data->root_node;
raise_error = FALSE;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
}
break;
case 'm':
@ -1157,9 +1164,8 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (ctx->current)->action_name == 0)
NODE_INFO (ctx->current)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
mark_node_dirty (ctx->current);
raise_error = FALSE;
}
@ -1172,9 +1178,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (ctx->current)->action_name == 0)
NODE_INFO (ctx->current)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1190,9 +1194,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (node)->action_name == 0)
NODE_INFO (node)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (node),
ctx->merge_id, action_quark);
NODE_INFO (node)->dirty = TRUE;
node_prepend_ui_reference (node, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1208,9 +1210,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (ctx->current)->action_name == 0)
NODE_INFO (ctx->current)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1228,9 +1228,7 @@ start_element_handler (GMarkupParseContext *context,
NODE_TYPE_MENU_PLACEHOLDER,
TRUE, top);
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1261,9 +1259,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (node)->action_name == 0)
NODE_INFO (node)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (node),
ctx->merge_id, action_quark);
NODE_INFO (node)->dirty = TRUE;
node_prepend_ui_reference (node, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1279,9 +1275,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (ctx->current)->action_name == 0)
NODE_INFO (ctx->current)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (ctx->current),
ctx->merge_id, action_quark);
NODE_INFO (ctx->current)->dirty = TRUE;
node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1297,9 +1291,7 @@ start_element_handler (GMarkupParseContext *context,
if (NODE_INFO (node)->action_name == 0)
NODE_INFO (node)->action_name = action_quark;
node_prepend_ui_reference (NODE_INFO (node),
ctx->merge_id, action_quark);
NODE_INFO (node)->dirty = TRUE;
node_prepend_ui_reference (node, ctx->merge_id, action_quark);
raise_error = FALSE;
}
@ -1671,14 +1663,11 @@ gtk_ui_manager_add_ui (GtkUIManager *self,
if (action != NULL)
action_quark = g_quark_from_string (action);
node_prepend_ui_reference (NODE_INFO (child),
merge_id, action_quark);
node_prepend_ui_reference (child, merge_id, action_quark);
if (NODE_INFO (child)->action_name == 0)
NODE_INFO (child)->action_name = action_quark;
NODE_INFO (child)->dirty = TRUE;
queue_update (self);
g_object_notify (G_OBJECT (self), "ui");
@ -1690,7 +1679,7 @@ remove_ui (GNode *node,
{
guint merge_id = GPOINTER_TO_UINT (user_data);
node_remove_ui_reference (NODE_INFO (node), merge_id);
node_remove_ui_reference (node, merge_id);
return FALSE; /* continue */
}
@ -2026,7 +2015,12 @@ update_smart_separators (GtkWidget *proxy)
if (GTK_IS_MENU_ITEM (item))
_gtk_action_sync_menu_visible (NULL, item, empty);
if (GTK_IS_WIDGET (filler))
g_object_set (G_OBJECT (filler), "visible", empty, NULL);
{
if (empty)
gtk_widget_show (filler);
else
gtk_widget_hide (filler);
}
}
g_list_free (children);
@ -2051,6 +2045,9 @@ update_node (GtkUIManager *self,
info = NODE_INFO (node);
if (!info->dirty)
return;
in_popup = in_popup || (info->type == NODE_TYPE_POPUP);
#ifdef DEBUG_UI_MANAGER
@ -2066,8 +2063,6 @@ update_node (GtkUIManager *self,
g_print (")\n");
#endif
if (info->dirty)
{
const gchar *action_name;
NodeUIReference *ref;
@ -2501,7 +2496,6 @@ update_node (GtkUIManager *self,
if (info->action)
g_object_unref (info->action);
info->action = action;
}
recurse_children:
/* process children */
@ -2631,6 +2625,16 @@ dirty_all_nodes (GtkUIManager *self)
queue_update (self);
}
static void
mark_node_dirty (GNode *node)
{
GNode *p;
/* FIXME could optimize this */
for (p = node; p; p = p->parent)
NODE_INFO (p)->dirty = TRUE;
}
static const gchar *open_tag_format[] = {
"%*s<UNDECIDED",
"%*s<ui",