[evolution] EMFolderTreeModel: Fix a circular dependency between model and its data



commit 967d37373f5e59a46203cd84ee84650928771143
Author: Milan Crha <mcrha redhat com>
Date:   Thu Feb 20 20:12:30 2014 +0100

    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.

 mail/e-mail-backend.c       |    2 ++
 mail/em-folder-tree-model.c |   30 ++++++++++++++++++++++++++----
 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 83ee93d..8e45ae1 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 789bb20..3597b6e 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 3684082..60c884a 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]