diff options
author | Milan Crha <mcrha@redhat.com> | 2014-02-21 03:12:30 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2014-02-21 03:12:30 +0800 |
commit | 967d37373f5e59a46203cd84ee84650928771143 (patch) | |
tree | a9fd77c258601035f007a28e1d719dda08e4bdf5 | |
parent | 197c8e1274f70c035614cbb54c7926901d1b1db5 (diff) | |
download | gsoc2013-evolution-967d37373f5e59a46203cd84ee84650928771143.tar.gz gsoc2013-evolution-967d37373f5e59a46203cd84ee84650928771143.tar.zst gsoc2013-evolution-967d37373f5e59a46203cd84ee84650928771143.zip |
EMFolderTreeModel: Fix a circular dependency between model and its data
The model stores GtkTreeRowReference-s in its private data, but these
references ref the model, thus there is a circular dependency between
internal data and the object itself, effectively causing memory leaks.
With this fixed, the CamelSession is correctly freed at the end of
the application.
-rw-r--r-- | mail/e-mail-backend.c | 2 | ||||
-rw-r--r-- | mail/em-folder-tree-model.c | 30 | ||||
-rw-r--r-- | mail/em-folder-tree-model.h | 1 |
3 files changed, 29 insertions, 4 deletions
diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c index 83ee93d45e..8e45ae101f 100644 --- a/mail/e-mail-backend.c +++ b/mail/e-mail-backend.c @@ -923,6 +923,8 @@ mail_backend_dispose (GObject *object) priv = E_MAIL_BACKEND_GET_PRIVATE (object); if (priv->session != NULL) { + em_folder_tree_model_free_default (); + g_signal_handlers_disconnect_matched ( priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index 789bb20e38..3597b6ec6c 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -844,17 +844,39 @@ em_folder_tree_model_new (void) return g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL); } -EMFolderTreeModel * -em_folder_tree_model_get_default (void) +static EMFolderTreeModel * +em_folder_tree_manage_default (gboolean do_create) { - static EMFolderTreeModel *default_folder_tree_model; + static EMFolderTreeModel *default_folder_tree_model = NULL; - if (G_UNLIKELY (default_folder_tree_model == NULL)) + if (do_create && G_UNLIKELY (default_folder_tree_model == NULL)) { default_folder_tree_model = em_folder_tree_model_new (); + } else if (!do_create && G_UNLIKELY (default_folder_tree_model != NULL)) { + /* This is necessary, due to circular dependency between stored GtkTreeRwoReference + and the model itself. */ + g_mutex_lock (&default_folder_tree_model->priv->store_index_lock); + g_hash_table_remove_all (default_folder_tree_model->priv->store_index); + g_mutex_unlock (&default_folder_tree_model->priv->store_index_lock); + + g_object_unref (default_folder_tree_model); + default_folder_tree_model = NULL; + } return default_folder_tree_model; } +EMFolderTreeModel * +em_folder_tree_model_get_default (void) +{ + return em_folder_tree_manage_default (TRUE); +} + +void +em_folder_tree_model_free_default (void) +{ + em_folder_tree_manage_default (FALSE); +} + GtkTreeSelection * em_folder_tree_model_get_selection (EMFolderTreeModel *model) { diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h index 3684082e98..60c884a872 100644 --- a/mail/em-folder-tree-model.h +++ b/mail/em-folder-tree-model.h @@ -101,6 +101,7 @@ EMFolderTreeModel * em_folder_tree_model_new (void); EMFolderTreeModel * em_folder_tree_model_get_default (void); +void em_folder_tree_model_free_default (void); GtkTreeSelection * em_folder_tree_model_get_selection (EMFolderTreeModel *model); |