gtk_tree_model_filter_row_deleted: don't emit signals too early

gtk_tree_model_filter_row_deleted was emitting ::row-deleted while
the internal state of the model was still in disarray, causing
segfaults e.g. when mapping the file chooser with accessibility
turned on. This is just a bandaid fix, and doesn't try address
any of the deeper problems of the filter model code.

I did take the time to reduce rampant variable shadowing in that
function, though.
This commit is contained in:
Matthias Clasen 2011-02-16 18:40:14 -05:00
parent 32298832ed
commit 0c3da06a62

View File

@ -1786,6 +1786,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
FilterElt *elt; FilterElt *elt;
FilterLevel *level, *parent_level = NULL; FilterLevel *level, *parent_level = NULL;
gboolean emit_child_toggled = FALSE; gboolean emit_child_toggled = FALSE;
gboolean emit_row_deleted = FALSE;
gint offset; gint offset;
gint i; gint i;
gint parent_elt_index = -1; gint parent_elt_index = -1;
@ -1798,13 +1799,13 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
!gtk_tree_path_compare (c_path, filter->priv->virtual_root))) !gtk_tree_path_compare (c_path, filter->priv->virtual_root)))
{ {
gint i; gint i;
GtkTreePath *path; GtkTreePath *path2;
FilterLevel *level = FILTER_LEVEL (filter->priv->root); FilterLevel *level2 = FILTER_LEVEL (filter->priv->root);
gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root); gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root);
filter->priv->virtual_root_deleted = TRUE; filter->priv->virtual_root_deleted = TRUE;
if (!level) if (!level2)
return; return;
/* remove everything in the filter model /* remove everything in the filter model
@ -1814,13 +1815,13 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
*/ */
gtk_tree_model_filter_increment_stamp (filter); gtk_tree_model_filter_increment_stamp (filter);
path = gtk_tree_path_new (); path2 = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0); gtk_tree_path_append_index (path2, 0);
for (i = 0; i < level->visible_nodes; i++) for (i = 0; i < level2->visible_nodes; i++)
gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path2);
gtk_tree_path_free (path); gtk_tree_path_free (path2);
gtk_tree_model_filter_free_level (filter, filter->priv->root); gtk_tree_model_filter_free_level (filter, filter->priv->root);
return; return;
@ -1832,23 +1833,23 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
if (gtk_tree_path_get_depth (filter->priv->virtual_root) >= if (gtk_tree_path_get_depth (filter->priv->virtual_root) >=
gtk_tree_path_get_depth (c_path)) gtk_tree_path_get_depth (c_path))
{ {
gint level; gint level2;
gint *v_indices, *c_indices; gint *v_indices, *c_indices;
gboolean common_prefix = TRUE; gboolean common_prefix = TRUE;
level = gtk_tree_path_get_depth (c_path) - 1; level2 = gtk_tree_path_get_depth (c_path) - 1;
v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root); v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root);
c_indices = gtk_tree_path_get_indices (c_path); c_indices = gtk_tree_path_get_indices (c_path);
for (i = 0; i < level; i++) for (i = 0; i < level2; i++)
if (v_indices[i] != c_indices[i]) if (v_indices[i] != c_indices[i])
{ {
common_prefix = FALSE; common_prefix = FALSE;
break; break;
} }
if (common_prefix && v_indices[level] > c_indices[level]) if (common_prefix && v_indices[level2] > c_indices[level2])
(v_indices[level])--; (v_indices[level2])--;
} }
} }
@ -1954,18 +1955,14 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
parent_elt_index = level->parent_elt_index; parent_elt_index = level->parent_elt_index;
} }
/* emit row_deleted */ emit_row_deleted = TRUE;
gtk_tree_model_filter_increment_stamp (filter);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
iter.stamp = filter->priv->stamp;
} }
/* The filter model's reference on the child node is released /* The filter model's reference on the child node is released
* below. * below.
*/ */
while (elt->ref_count > 1) while (elt->ref_count > 1)
gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, FALSE);
FALSE);
if (level->array->len == 1) if (level->array->len == 1)
{ {
@ -2000,24 +1997,32 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
} }
} }
if (emit_row_deleted)
{
/* emit row_deleted */
gtk_tree_model_filter_increment_stamp (filter);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
iter.stamp = filter->priv->stamp;
}
if (emit_child_toggled && parent_level) if (emit_child_toggled && parent_level)
{ {
GtkTreeIter iter; GtkTreeIter iter2;
GtkTreePath *path; GtkTreePath *path2;
iter.stamp = filter->priv->stamp; iter2.stamp = filter->priv->stamp;
iter.user_data = parent_level; iter2.user_data = parent_level;
iter.user_data2 = &g_array_index (parent_level->array, FilterElt, parent_elt_index); iter2.user_data2 = &g_array_index (parent_level->array, FilterElt, parent_elt_index);
/* We set in_row_deleted to TRUE to avoid a level build triggered /* We set in_row_deleted to TRUE to avoid a level build triggered
* by row-has-child-toggled (parent model could call iter_has_child * by row-has-child-toggled (parent model could call iter_has_child
* for example). * for example).
*/ */
filter->priv->in_row_deleted = TRUE; filter->priv->in_row_deleted = TRUE;
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter); path2 = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter2);
gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
path, &iter); path2, &iter2);
gtk_tree_path_free (path); gtk_tree_path_free (path2);
filter->priv->in_row_deleted = FALSE; filter->priv->in_row_deleted = FALSE;
} }