diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-10-29 03:28:58 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-10-29 03:40:22 +0800 |
commit | 91e0696b738ecc991f8b6c33442040de4fec1873 (patch) | |
tree | 7a63590e035e8369dc74b17983ce9580e36e6e50 | |
parent | 57712e8456024c5be983f1d934a648034e577208 (diff) | |
download | gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar.gz gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar.bz2 gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar.lz gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar.xz gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.tar.zst gsoc2013-evolution-91e0696b738ecc991f8b6c33442040de4fec1873.zip |
BugĀ 599882 - Crash in em_folder_tree_select_prev_path() when wrapping to bottom
Also fixes a whole bunch of memory leaks caused by unfreed strings and
unfreed GtkTreePaths.
-rw-r--r-- | mail/em-folder-tree.c | 131 |
1 files changed, 82 insertions, 49 deletions
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index b13a47a0e0..3c569673b5 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -2421,31 +2421,55 @@ em_folder_tree_select_next_path (EMFolderTree *emft, gboolean skip_read_folders) return; } -static GtkTreeIter -get_last_child (GtkTreeModel *model, GtkTreeIter *iter) -{ - GtkTreeIter *child = g_new0 (GtkTreeIter, 1); - gboolean has_child = gtk_tree_model_iter_has_child (model, iter); - - if (gtk_tree_model_iter_next (model, iter)) { - return get_last_child (model, iter); - } else if (has_child) { - /* Pick the last one */ - gint nchildren = gtk_tree_model_iter_n_children (model, iter); - gtk_tree_model_iter_nth_child ( model, child, iter, nchildren-1); - return get_last_child (model, child); +static gboolean +folder_tree_descend (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *root) +{ + GtkTreeIter parent; + gint n_children; + + /* Finds the rightmost descendant of the given root. */ + + if (root == NULL) { + n_children = gtk_tree_model_iter_n_children (model, NULL); + + /* This will invalidate the iterator and return FALSE. */ + if (n_children == 0) + return gtk_tree_model_get_iter_first (model, iter); + + gtk_tree_model_iter_nth_child ( + model, &parent, NULL, n_children - 1); + } else + parent = *root; + + n_children = gtk_tree_model_iter_n_children (model, &parent); + + while (n_children > 0) { + GtkTreeIter child; + + gtk_tree_model_iter_nth_child ( + model, &child, &parent, n_children - 1); + + parent = child; + + n_children = gtk_tree_model_iter_n_children (model, &parent); } - return *iter; + *iter = parent; + + return TRUE; } void -em_folder_tree_select_prev_path (EMFolderTree *emft, gboolean skip_read_folders) +em_folder_tree_select_prev_path (EMFolderTree *folder_tree, + gboolean skip_read_folders) { GtkTreeSelection *selection; GtkTreeModel *model; - GtkTreeIter iter, child; - GtkTreePath *path = NULL, *current_path = NULL; + GtkTreePath *path = NULL; + GtkTreePath *sentinel; + GtkTreeIter iter; guint unread = 0; struct _EMFolderTreePrivate *priv = emft->priv; @@ -2453,51 +2477,60 @@ em_folder_tree_select_prev_path (EMFolderTree *emft, gboolean skip_read_folders) selection = gtk_tree_view_get_selection(emft->priv->treeview); - if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + /* Nothing selected means nothing to do. */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + /* This prevents us from looping over the model indefinitely, + * looking for unread messages when there are none. */ + sentinel = gtk_tree_model_get_path (model, &iter); + + do { + GtkTreeIter descendant; + + if (path != NULL) + gtk_tree_path_free (path); - current_path = gtk_tree_model_get_path (model, &iter); - do { path = gtk_tree_model_get_path (model, &iter); - if (!gtk_tree_path_prev (path)) { + + if (gtk_tree_path_prev (path)) { + gtk_tree_model_get_iter (model, &iter, path); + folder_tree_descend (model, &descendant, &iter); + + gtk_tree_path_free (path); + path = gtk_tree_model_get_path (model, &descendant); + + } else if (gtk_tree_path_get_depth (path) > 1) { gtk_tree_path_up (path); - if (!gtk_tree_path_compare (gtk_tree_path_new_first (), path)) - { - gtk_tree_model_get_iter_first (model, &iter); - iter = get_last_child (model,&iter); - path = gtk_tree_model_get_path (model, &iter); - } } else { - gtk_tree_model_get_iter (model, &iter, path); - if (gtk_tree_model_iter_has_child (model, &iter)) { - gint nchildren = gtk_tree_model_iter_n_children (model, &iter); - gtk_tree_model_iter_nth_child ( model, &child, &iter, nchildren-1); - path = gtk_tree_model_get_path (model, &child); - } - } + folder_tree_descend (model, &descendant, NULL); - /* TODO : Flags here for better options */ - gtk_tree_model_get_iter_from_string (model, &iter, gtk_tree_path_to_string (path) ); + gtk_tree_path_free (path); + path = gtk_tree_model_get_path (model, &descendant); + } + gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, COL_UINT_UNREAD, &unread, -1); - } while (skip_read_folders && unread <=0 && gtk_tree_path_compare (current_path, path)); - } + } while (skip_read_folders && unread <= 0 && + gtk_tree_path_compare (path, sentinel) != 0); - if (path) { - if (!gtk_tree_view_row_expanded (priv->treeview, path)) { - gtk_tree_view_expand_to_path (priv->treeview, path); - } + if (!gtk_tree_view_row_expanded (tree_view, path)) + gtk_tree_view_expand_to_path (tree_view, path); - gtk_tree_selection_select_path(selection, path); + gtk_tree_selection_select_path (selection, path); - if (!priv->cursor_set) { - gtk_tree_view_set_cursor (priv->treeview, path, NULL, FALSE); - priv->cursor_set = TRUE; - } - gtk_tree_view_scroll_to_cell (priv->treeview, path, NULL, TRUE, 0.5f, 0.0f); + if (!priv->cursor_set) { + gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE); + priv->cursor_set = TRUE; } - return; + + gtk_tree_view_scroll_to_cell ( + tree_view, path, NULL, TRUE, 0.5f, 0.0f); + + gtk_tree_path_free (sentinel); + gtk_tree_path_free (path); } gchar * |