aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2014-02-21 03:12:30 +0800
committerMilan Crha <mcrha@redhat.com>2014-02-21 03:12:30 +0800
commit967d37373f5e59a46203cd84ee84650928771143 (patch)
treea9fd77c258601035f007a28e1d719dda08e4bdf5
parent197c8e1274f70c035614cbb54c7926901d1b1db5 (diff)
downloadgsoc2013-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.c2
-rw-r--r--mail/em-folder-tree-model.c30
-rw-r--r--mail/em-folder-tree-model.h1
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);