[evolution] MessageList: Add a "folder" property.



commit 9c4500a9b5b030e6fb2b8c02e518254d94c10add
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Jun 14 13:45:08 2013 -0400

    MessageList: Add a "folder" property.
    
    Also move the CamelFolder pointer into the private structure.
    
    New functions:
    
      message_list_ref_folder()

 mail/e-mail-paned-view.c                 |   13 +-
 mail/e-mail-reader.c                     |   10 +-
 mail/message-list.c                      |  358 +++++++++++++++++++++---------
 mail/message-list.h                      |    4 +-
 modules/mail/e-mail-shell-view-private.c |   13 +-
 5 files changed, 279 insertions(+), 119 deletions(-)
---
diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c
index 9f39347..440c83b 100644
--- a/mail/e-mail-paned-view.c
+++ b/mail/e-mail-paned-view.c
@@ -126,10 +126,13 @@ mail_paned_view_message_list_built_cb (EMailView *view,
        EMailPanedViewPrivate *priv;
        EShellView *shell_view;
        EShellWindow *shell_window;
+       CamelFolder *folder;
        GKeyFile *key_file;
 
        priv = E_MAIL_PANED_VIEW_GET_PRIVATE (view);
 
+       folder = message_list_ref_folder (message_list);
+
        g_signal_handler_disconnect (
                message_list, priv->message_list_built_id);
        priv->message_list_built_id = 0;
@@ -142,20 +145,18 @@ mail_paned_view_message_list_built_cb (EMailView *view,
        if (message_list->cursor_uid != NULL)
                ;  /* do nothing */
 
-       else if (message_list->folder == NULL)
+       else if (folder == NULL)
                ;  /* do nothing */
 
        else if (e_shell_window_get_safe_mode (shell_window))
                e_shell_window_set_safe_mode (shell_window, FALSE);
 
        else {
-               CamelFolder *folder;
                const gchar *key;
                gchar *folder_uri;
                gchar *group_name;
                gchar *uid;
 
-               folder = message_list->folder;
                folder_uri = e_mail_folder_uri_from_folder (folder);
 
                key = STATE_KEY_SELECTED_MESSAGE;
@@ -170,6 +171,8 @@ mail_paned_view_message_list_built_cb (EMailView *view,
 
                g_free (uid);
        }
+
+       g_clear_object (&folder);
 }
 
 static void
@@ -184,7 +187,7 @@ mail_paned_view_message_selected_cb (EMailView *view,
        gchar *folder_uri;
        gchar *group_name;
 
-       folder = message_list->folder;
+       folder = message_list_ref_folder (message_list);
 
        /* This also gets triggered when selecting a store name on
         * the sidebar such as "On This Computer", in which case
@@ -208,6 +211,8 @@ mail_paned_view_message_selected_cb (EMailView *view,
 
        g_free (group_name);
        g_free (folder_uri);
+
+       g_object_unref (folder);
 }
 
 static void
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index a93d726..18d71b3 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2993,10 +2993,18 @@ static CamelFolder *
 mail_reader_get_folder (EMailReader *reader)
 {
        GtkWidget *message_list;
+       CamelFolder *folder;
 
        message_list = e_mail_reader_get_message_list (reader);
 
-       return MESSAGE_LIST (message_list)->folder;
+       /* FIXME This is dangerous.  EMailReader should return a
+        *       new CamelFolder reference and rename this method
+        *       to "ref_folder()" instead of "get_folder()". */
+       folder = message_list_ref_folder (MESSAGE_LIST (message_list));
+       if (folder != NULL)
+               g_object_unref (folder);
+
+       return folder;
 }
 
 static void
diff --git a/mail/message-list.c b/mail/message-list.c
index 2619ebf..f7c58d2 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -91,6 +91,9 @@ struct _MessageListPrivate {
 
        EMailSession *session;
 
+       CamelFolder *folder;
+       gulong folder_changed_handler_id;
+
        /* For message list regeneration. */
        GMutex regen_lock;
        RegenData *regen_data;
@@ -150,6 +153,7 @@ struct _RegenData {
 enum {
        PROP_0,
        PROP_COPY_TARGET_LIST,
+       PROP_FOLDER,
        PROP_PASTE_TARGET_LIST,
        PROP_SESSION,
        PROP_THREAD_LATEST,
@@ -241,10 +245,6 @@ static void mail_regen_cancel (MessageList *ml);
 
 static void clear_info (gchar *key, ETreePath *node, MessageList *ml);
 
-static void    folder_changed                  (CamelFolder *folder,
-                                                CamelFolderChangeInfo *info,
-                                                MessageList *ml);
-
 enum {
        MESSAGE_SELECTED,
        MESSAGE_LIST_BUILT,
@@ -308,7 +308,7 @@ regen_data_new (MessageList *message_list,
        regen_data->last_row = -1;
 
        /* Capture MessageList state to use for this regen. */
-       regen_data->folder = g_object_ref (message_list->folder);
+       regen_data->folder = message_list_ref_folder (message_list);
        regen_data->threaded = message_list->threaded;
        regen_data->hide_deleted = message_list->hidedeleted;
        regen_data->hide_junk = message_list->hidejunk;
@@ -735,7 +735,7 @@ message_list_select_uid (MessageList *message_list,
        priv = message_list->priv;
        uid_nodemap = message_list->uid_nodemap;
 
-       if (message_list->folder == NULL)
+       if (message_list->priv->folder == NULL)
                return;
 
        /* Try to find the requested message UID. */
@@ -1012,22 +1012,28 @@ message_list_copy (MessageList *ml,
 
        if (uids->len > 0) {
                if (cut) {
+                       CamelFolder *folder;
                        gint i;
 
-                       camel_folder_freeze (ml->folder);
+                       folder = message_list_ref_folder (ml);
+
+                       camel_folder_freeze (folder);
+
                        for (i = 0; i < uids->len; i++)
                                camel_folder_set_message_flags (
-                                       ml->folder, uids->pdata[i],
+                                       folder, uids->pdata[i],
                                        CAMEL_MESSAGE_SEEN |
                                        CAMEL_MESSAGE_DELETED,
                                        CAMEL_MESSAGE_SEEN |
                                        CAMEL_MESSAGE_DELETED);
 
-                       camel_folder_thaw (ml->folder);
+                       camel_folder_thaw (folder);
+
+                       g_object_unref (folder);
                }
 
                p->clipboard.uids = uids;
-               p->clipboard.folder = g_object_ref (ml->folder);
+               p->clipboard.folder = message_list_ref_folder (ml);
                gtk_selection_owner_set (p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time 
());
        } else {
                em_utils_uids_free (uids);
@@ -1759,7 +1765,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
                const gchar *store_name;
                const gchar *folder_name;
 
-               folder = message_list->folder;
+               folder = message_list->priv->folder;
 
                if (CAMEL_IS_VEE_FOLDER (folder))
                        folder = camel_vee_folder_get_location (
@@ -2120,14 +2126,18 @@ message_list_create_extras (void)
 }
 
 static void
-save_tree_state (MessageList *ml)
+save_tree_state (MessageList *ml,
+                 CamelFolder *folder)
 {
        gchar *filename;
 
-       if (ml->folder == NULL || (ml->search && *ml->search))
+       if (folder == NULL)
                return;
 
-       filename = mail_config_folder_to_cachename (ml->folder, "et-expanded-");
+       if (ml->search != NULL && *ml->search != '\0')
+               return;
+
+       filename = mail_config_folder_to_cachename (folder, "et-expanded-");
        e_tree_save_expanded_state (E_TREE (ml), filename);
        g_free (filename);
 
@@ -2136,9 +2146,10 @@ save_tree_state (MessageList *ml)
 
 static void
 load_tree_state (MessageList *ml,
+                 CamelFolder *folder,
                  xmlDoc *expand_state)
 {
-       if (ml->folder == NULL)
+       if (folder == NULL)
                return;
 
        if (expand_state) {
@@ -2147,7 +2158,8 @@ load_tree_state (MessageList *ml,
                /* only when not searching */
                gchar *filename;
 
-               filename = mail_config_folder_to_cachename (ml->folder, "et-expanded-");
+               filename = mail_config_folder_to_cachename (
+                       folder, "et-expanded-");
                e_tree_load_expanded_state (E_TREE (ml), filename);
                g_free (filename);
        }
@@ -2158,25 +2170,41 @@ load_tree_state (MessageList *ml,
 void
 message_list_save_state (MessageList *ml)
 {
-       save_tree_state (ml);
+       CamelFolder *folder;
+
+       folder = message_list_ref_folder (ml);
+
+       if (folder != NULL) {
+               save_tree_state (ml, folder);
+               g_object_unref (folder);
+       }
 }
 
 static void
 message_list_setup_etree (MessageList *message_list)
 {
-       /* build the spec based on the folder, and possibly from a saved file */
-       /* otherwise, leave default */
-       if (message_list->folder) {
+       CamelFolder *folder;
+
+       /* Build the spec based on the folder, and possibly
+        * from a saved file.   Otherwise, leave default. */
+
+       folder = message_list_ref_folder (message_list);
+
+       if (folder != NULL) {
                gint data = 1;
                ETableItem *item;
 
                item = e_tree_get_item (E_TREE (message_list));
 
                g_object_set (message_list, "uniform_row_height", TRUE, NULL);
-               g_object_set_data (G_OBJECT (((GnomeCanvasItem *) item)->canvas), "freeze-cursor", &data);
+               g_object_set_data (
+                       G_OBJECT (((GnomeCanvasItem *) item)->canvas),
+                       "freeze-cursor", &data);
 
                /* build based on saved file */
-               load_tree_state (message_list, NULL);
+               load_tree_state (message_list, folder, NULL);
+
+               g_object_unref (folder);
        }
 }
 
@@ -2224,6 +2252,7 @@ ml_selection_received (GtkWidget *widget,
                        MessageList *message_list)
 {
        EMailSession *session;
+       CamelFolder *folder;
        GdkAtom target;
 
        target = gtk_selection_data_get_target (selection_data);
@@ -2233,12 +2262,14 @@ ml_selection_received (GtkWidget *widget,
                return;
        }
 
+       folder = message_list_ref_folder (message_list);
        session = message_list_get_session (message_list);
 
        /* FIXME Not passing a GCancellable or GError here. */
        em_utils_selection_get_uidlist (
-               selection_data, session, message_list->folder,
-               FALSE, NULL, NULL);
+               selection_data, session, folder, FALSE, NULL, NULL);
+
+       g_clear_object (&folder);
 }
 
 static void
@@ -2252,21 +2283,24 @@ ml_tree_drag_data_get (ETree *tree,
                        guint time,
                        MessageList *ml)
 {
+       CamelFolder *folder;
        GPtrArray *uids;
 
+       folder = message_list_ref_folder (ml);
        uids = message_list_get_selected (ml);
 
        if (uids->len > 0) {
                switch (info) {
                case DND_X_UID_LIST:
-                       em_utils_selection_set_uidlist (data, ml->folder, uids);
+                       em_utils_selection_set_uidlist (data, folder, uids);
                        break;
                case DND_TEXT_URI_LIST:
-                       em_utils_selection_set_urilist (data, ml->folder, uids);
+                       em_utils_selection_set_urilist (data, folder, uids);
                        break;
                }
        }
 
+       g_clear_object (&folder);
        em_utils_uids_free (uids);
 }
 
@@ -2383,20 +2417,22 @@ ml_tree_drag_data_received (ETree *tree,
                             guint time,
                             MessageList *ml)
 {
+       CamelFolder *folder;
        struct _drop_msg *m;
 
-       if (ml->folder == NULL)
-               return;
-
        if (gtk_selection_data_get_data (selection_data) == NULL)
                return;
 
        if (gtk_selection_data_get_length (selection_data) == -1)
                return;
 
+       folder = message_list_ref_folder (ml);
+       if (folder == NULL)
+               return;
+
        m = mail_msg_new (&ml_drop_async_info);
        m->context = g_object_ref (context);
-       m->folder = g_object_ref (ml->folder);
+       m->folder = g_object_ref (folder);
        m->message_list = g_object_ref (ml);
        m->action = gdk_drag_context_get_selected_action (context);
        m->info = info;
@@ -2405,6 +2441,8 @@ ml_tree_drag_data_received (ETree *tree,
        m->selection = gtk_selection_data_copy (selection_data);
 
        ml_drop_action (m);
+
+       g_object_unref (folder);
 }
 
 struct search_child_struct {
@@ -2447,8 +2485,9 @@ ml_tree_drag_motion (ETree *tree,
        GdkDragAction action, actions = 0;
        GtkWidget *source_widget;
 
-       /* If drop target is name of the account/store and not actual folder, don't allow any action */
-       if (!ml->folder) {
+       /* If drop target is name of the account/store
+        * and not actual folder, don't allow any action. */
+       if (ml->priv->folder == NULL) {
                gdk_drag_status (context, 0, time);
                return TRUE;
        }
@@ -2463,7 +2502,7 @@ ml_tree_drag_motion (ETree *tree,
 
        if (EM_IS_FOLDER_TREE (source_widget)) {
                EMFolderTree *folder_tree;
-               CamelFolder *folder = NULL;
+               CamelFolder *selected_folder = NULL;
                CamelStore *selected_store;
                gchar *selected_folder_name;
                gboolean has_selection;
@@ -2482,14 +2521,14 @@ ml_tree_drag_motion (ETree *tree,
                        (!has_selection && selected_folder_name == NULL));
 
                if (has_selection) {
-                       folder = camel_store_get_folder_sync (
+                       selected_folder = camel_store_get_folder_sync (
                                selected_store, selected_folder_name,
                                CAMEL_STORE_FOLDER_INFO_FAST, NULL, NULL);
                        g_object_unref (selected_store);
                        g_free (selected_folder_name);
                }
 
-               if (folder == ml->folder) {
+               if (selected_folder == ml->priv->folder) {
                        gdk_drag_status (context, 0, time);
                        return TRUE;
                }
@@ -2640,6 +2679,12 @@ message_list_set_property (GObject *object,
                            GParamSpec *pspec)
 {
        switch (property_id) {
+               case PROP_FOLDER:
+                       message_list_set_folder (
+                               MESSAGE_LIST (object),
+                               g_value_get_object (value));
+                       return;
+
                case PROP_SESSION:
                        message_list_set_session (
                                MESSAGE_LIST (object),
@@ -2676,6 +2721,13 @@ message_list_get_property (GObject *object,
                                MESSAGE_LIST (object)));
                        return;
 
+               case PROP_FOLDER:
+                       g_value_take_object (
+                               value,
+                               message_list_ref_folder (
+                               MESSAGE_LIST (object)));
+                       return;
+
                case PROP_PASTE_TARGET_LIST:
                        g_value_set_boxed (
                                value,
@@ -2716,6 +2768,13 @@ message_list_dispose (GObject *object)
 
        priv = message_list->priv;
 
+       if (priv->folder_changed_handler_id > 0) {
+               g_signal_handler_disconnect (
+                       priv->folder,
+                       priv->folder_changed_handler_id);
+               priv->folder_changed_handler_id = 0;
+       }
+
        if (priv->session != NULL) {
                g_object_unref (priv->session);
                priv->session = NULL;
@@ -2733,7 +2792,7 @@ message_list_dispose (GObject *object)
 
        priv->destroyed = TRUE;
 
-       if (message_list->folder)
+       if (message_list->priv->folder != NULL)
                mail_regen_cancel (message_list);
 
        if (message_list->uid_nodemap) {
@@ -2742,11 +2801,9 @@ message_list_dispose (GObject *object)
                message_list->uid_nodemap = NULL;
        }
 
-       if (message_list->folder) {
-               g_signal_handlers_disconnect_by_func (
-                       message_list->folder, folder_changed, message_list);
-               g_object_unref (message_list->folder);
-               message_list->folder = NULL;
+       if (message_list->priv->folder) {
+               g_object_unref (message_list->priv->folder);
+               message_list->priv->folder = NULL;
        }
 
        if (priv->invisible) {
@@ -2856,6 +2913,17 @@ message_list_class_init (MessageListClass *class)
                PROP_COPY_TARGET_LIST,
                "copy-target-list");
 
+       g_object_class_install_property (
+               object_class,
+               PROP_FOLDER,
+               g_param_spec_object (
+                       "folder",
+                       "Folder",
+                       "The source folder",
+                       CAMEL_TYPE_FOLDER,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS));
+
        /* Inherited from ESelectableInterface */
        g_object_class_override_property (
                object_class,
@@ -3037,7 +3105,7 @@ clear_info (gchar *key,
        CamelMessageInfo *info;
 
        info = e_tree_memory_node_get_data ((ETreeMemory *) ml->model, node);
-       camel_folder_free_message_info (ml->folder, info);
+       camel_folder_free_message_info (ml->priv->folder, info);
        e_tree_memory_node_set_data ((ETreeMemory *) ml->model, node, NULL);
 }
 
@@ -3046,6 +3114,7 @@ clear_tree (MessageList *ml,
             gboolean tfree)
 {
        ETreeModel *etm = ml->model;
+       CamelFolder *folder;
 
 #ifdef TIMEIT
        struct timeval start, end;
@@ -3056,10 +3125,12 @@ clear_tree (MessageList *ml,
 #endif
 
        /* we also reset the uid_rowmap since it is no longer useful/valid anyway */
-       if (ml->folder)
+       folder = message_list_ref_folder (ml);
+       if (folder != NULL)
                g_hash_table_foreach (ml->uid_nodemap, (GHFunc) clear_info, ml);
        g_hash_table_destroy (ml->uid_nodemap);
        ml->uid_nodemap = g_hash_table_new (g_str_hash, g_str_equal);
+       g_clear_object (&folder);
 
        ml->priv->newest_read_date = 0;
        ml->priv->newest_read_uid = NULL;
@@ -3103,6 +3174,7 @@ static gboolean
 is_node_selectable (MessageList *ml,
                     CamelMessageInfo *info)
 {
+       CamelFolder *folder;
        gboolean is_junk_folder;
        gboolean is_trash_folder;
        guint32 flags;
@@ -3110,15 +3182,20 @@ is_node_selectable (MessageList *ml,
        gboolean flag_deleted;
        gboolean store_has_vjunk;
 
-       g_return_val_if_fail (ml != NULL, FALSE);
-       g_return_val_if_fail (ml->folder != NULL, FALSE);
        g_return_val_if_fail (info != NULL, FALSE);
 
-       store_has_vjunk = folder_store_supports_vjunk_folder (ml->folder);
+       folder = message_list_ref_folder (ml);
+       g_return_val_if_fail (folder != NULL, FALSE);
+
+       store_has_vjunk = folder_store_supports_vjunk_folder (folder);
 
        /* check folder type */
-       is_junk_folder = store_has_vjunk && (ml->folder->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0;
-       is_trash_folder = ml->folder->folder_flags & CAMEL_FOLDER_IS_TRASH;
+       is_junk_folder =
+               store_has_vjunk &&
+               (folder->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0;
+       is_trash_folder = folder->folder_flags & CAMEL_FOLDER_IS_TRASH;
+
+       g_object_unref (folder);
 
        /* check flags set on current message */
        flags = camel_message_info_flags (info);
@@ -3207,12 +3284,16 @@ ml_uid_nodemap_insert (MessageList *message_list,
                        ETreePath *parent_node,
                        gint row)
 {
+       CamelFolder *folder;
        ETreeMemory *tree;
        ETreePath *node;
        const gchar *uid;
        time_t date;
        guint flags;
 
+       folder = message_list_ref_folder (message_list);
+       g_return_val_if_fail (folder != NULL, NULL);
+
        if (parent_node == NULL)
                parent_node = message_list->tree_root;
 
@@ -3223,7 +3304,7 @@ ml_uid_nodemap_insert (MessageList *message_list,
        flags = camel_message_info_flags (info);
        date = camel_message_info_date_received (info);
 
-       camel_folder_ref_message_info (message_list->folder, info);
+       camel_folder_ref_message_info (folder, info);
        g_hash_table_insert (message_list->uid_nodemap, (gpointer) uid, node);
 
        /* Track the latest seen and unseen messages shown, used in
@@ -3243,6 +3324,8 @@ ml_uid_nodemap_insert (MessageList *message_list,
                }
        }
 
+       g_object_unref (folder);
+
        return node;
 }
 
@@ -3250,8 +3333,12 @@ static void
 ml_uid_nodemap_remove (MessageList *message_list,
                        CamelMessageInfo *info)
 {
+       CamelFolder *folder;
        const gchar *uid;
 
+       folder = message_list_ref_folder (message_list);
+       g_return_if_fail (folder != NULL);
+
        uid = camel_message_info_uid (info);
 
        if (uid == message_list->priv->newest_read_uid) {
@@ -3265,7 +3352,9 @@ ml_uid_nodemap_remove (MessageList *message_list,
        }
 
        g_hash_table_remove (message_list->uid_nodemap, uid);
-       camel_folder_free_message_info (message_list->folder, info);
+       camel_folder_free_message_info (folder, info);
+
+       g_object_unref (folder);
 }
 
 /* only call if we have a tree model */
@@ -3701,9 +3790,9 @@ mail_folder_hide_by_flag (CamelFolder *folder,
 }
 
 static void
-folder_changed (CamelFolder *folder,
-                CamelFolderChangeInfo *changes,
-                MessageList *ml)
+message_list_folder_changed (CamelFolder *folder,
+                             CamelFolderChangeInfo *changes,
+                             MessageList *ml)
 {
        CamelFolderChangeInfo *altered_changes = NULL;
        gboolean need_list_regen = TRUE;
@@ -3754,6 +3843,21 @@ folder_changed (CamelFolder *folder,
                camel_folder_change_info_free (altered_changes);
 }
 
+CamelFolder *
+message_list_ref_folder (MessageList *message_list)
+{
+       CamelFolder *folder = NULL;
+
+       /* XXX Do we need a property lock to guard this? */
+
+       g_return_val_if_fail (IS_MESSAGE_LIST (message_list), NULL);
+
+       if (message_list->priv->folder != NULL)
+               folder = g_object_ref (message_list->priv->folder);
+
+       return folder;
+}
+
 /**
  * message_list_set_folder:
  * @message_list: Message List widget
@@ -3769,11 +3873,18 @@ message_list_set_folder (MessageList *message_list,
        gboolean hide_deleted;
        GSettings *settings;
 
+       /* XXX Do we need a property lock to guard this? */
+
        g_return_if_fail (IS_MESSAGE_LIST (message_list));
 
-       if (message_list->folder == folder)
+       if (folder == message_list->priv->folder)
                return;
 
+       if (folder != NULL) {
+               g_return_if_fail (CAMEL_IS_FOLDER (folder));
+               g_object_ref (folder);
+       }
+
        g_free (message_list->search);
        message_list->search = NULL;
 
@@ -3790,9 +3901,8 @@ message_list_set_folder (MessageList *message_list,
 
        mail_regen_cancel (message_list);
 
-       if (message_list->folder != NULL) {
-               save_tree_state (message_list);
-       }
+       if (message_list->priv->folder != NULL)
+               save_tree_state (message_list, message_list->priv->folder);
 
        e_tree_memory_freeze (E_TREE_MEMORY (etm));
        clear_tree (message_list, TRUE);
@@ -3804,39 +3914,42 @@ message_list_set_folder (MessageList *message_list,
                message_list->idle_id = 0;
        }
 
-       if (message_list->folder) {
-               g_signal_handlers_disconnect_by_func (
-                       message_list->folder, folder_changed, message_list);
+       if (message_list->priv->folder != NULL) {
+               g_signal_handler_disconnect (
+                       message_list->priv->folder,
+                       message_list->priv->folder_changed_handler_id);
+               message_list->priv->folder_changed_handler_id = 0;
 
-               if (message_list->uid_nodemap)
-                       g_hash_table_foreach (message_list->uid_nodemap, (GHFunc) clear_info, message_list);
+               if (message_list->uid_nodemap != NULL)
+                       g_hash_table_foreach (
+                               message_list->uid_nodemap,
+                               (GHFunc) clear_info, message_list);
 
-               g_object_unref (message_list->folder);
-               message_list->folder = NULL;
+               g_clear_object (&message_list->priv->folder);
        }
 
-       if (message_list->thread_tree) {
+       if (message_list->thread_tree != NULL) {
                camel_folder_thread_messages_unref (message_list->thread_tree);
                message_list->thread_tree = NULL;
        }
 
-       if (message_list->cursor_uid) {
-               g_free (message_list->cursor_uid);
-               message_list->cursor_uid = NULL;
-       }
+       g_free (message_list->cursor_uid);
+       message_list->cursor_uid = NULL;
 
        /* Always emit message-selected, event when an account node
         * (folder == NULL) is selected, so that views know what happened and
         * can stop all running operations etc. */
-       g_signal_emit (message_list, message_list_signals[MESSAGE_SELECTED], 0, NULL);
+       g_signal_emit (
+               message_list, message_list_signals[MESSAGE_SELECTED], 0, NULL);
 
-       if (CAMEL_IS_FOLDER (folder)) {
+       if (folder != NULL) {
                CamelStore *store;
                gboolean non_trash_folder;
                gint strikeout_col;
                ECell *cell;
+               gulong handler_id;
 
-               message_list->folder = g_object_ref (folder);
+               message_list->priv->folder = folder;
                message_list->just_set_folder = TRUE;
 
                store = camel_folder_get_parent_store (folder);
@@ -3866,9 +3979,11 @@ message_list_set_folder (MessageList *message_list,
                /* Build the etree suitable for this folder */
                message_list_setup_etree (message_list);
 
-               g_signal_connect (
+               handler_id = g_signal_connect (
                        folder, "changed",
-                       G_CALLBACK (folder_changed), message_list);
+                       G_CALLBACK (message_list_folder_changed),
+                       message_list);
+               message_list->priv->folder_changed_handler_id = handler_id;
 
                settings = g_settings_new ("org.gnome.evolution.mail");
                hide_deleted = !g_settings_get_boolean (settings, "show-deleted");
@@ -3877,7 +3992,7 @@ message_list_set_folder (MessageList *message_list,
                message_list->hidedeleted =
                        hide_deleted && non_trash_folder;
                message_list->hidejunk =
-                       folder_store_supports_vjunk_folder (message_list->folder) &&
+                       folder_store_supports_vjunk_folder (folder) &&
                        !(folder->folder_flags & CAMEL_FOLDER_IS_JUNK) &&
                        !(folder->folder_flags & CAMEL_FOLDER_IS_TRASH);
 
@@ -4046,6 +4161,7 @@ on_click (ETree *tree,
           GdkEvent *event,
           MessageList *list)
 {
+       CamelFolder *folder;
        CamelMessageInfo *info;
        gboolean folder_is_trash;
        const gchar *uid;
@@ -4062,6 +4178,9 @@ on_click (ETree *tree,
        if (!(info = get_message_info (list, path)))
                return FALSE;
 
+       folder = message_list_ref_folder (list);
+       g_return_val_if_fail (folder != NULL, FALSE);
+
        if (col == COL_FOLLOWUP_FLAG_STATUS) {
                const gchar *tag, *cmp;
 
@@ -4091,7 +4210,7 @@ on_click (ETree *tree,
        flags = camel_message_info_flags (info);
 
        folder_is_trash =
-               ((list->folder->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0);
+               ((folder->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0);
 
        /* If a message was marked as deleted and the user flags it as
         * important or unread in a non-Trash folder, then undelete the
@@ -4108,7 +4227,7 @@ on_click (ETree *tree,
        }
 
        uid = camel_message_info_uid (info);
-       camel_folder_set_message_flags (list->folder, uid, flag, ~flags);
+       camel_folder_set_message_flags (folder, uid, flag, ~flags);
 
        /* Notify the folder tree model that the user has marked a message
         * as unread so it doesn't mistake the event as new mail arriving. */
@@ -4116,8 +4235,7 @@ on_click (ETree *tree,
                EMFolderTreeModel *model;
 
                model = em_folder_tree_model_get_default ();
-               em_folder_tree_model_user_marked_unread (
-                       model, list->folder, 1);
+               em_folder_tree_model_user_marked_unread (model, folder, 1);
        }
 
        if (flag == CAMEL_MESSAGE_SEEN && list->seen_id) {
@@ -4125,6 +4243,8 @@ on_click (ETree *tree,
                list->seen_id = 0;
        }
 
+       g_object_unref (folder);
+
        return TRUE;
 }
 
@@ -4151,6 +4271,8 @@ ml_getselected_cb (ETreePath path,
 GPtrArray *
 message_list_get_uids (MessageList *ml)
 {
+       CamelFolder *folder;
+
        struct _ml_selected_data data = {
                ml,
                g_ptr_array_new ()
@@ -4158,8 +4280,12 @@ message_list_get_uids (MessageList *ml)
 
        e_tree_path_foreach (E_TREE (ml), ml_getselected_cb, &data);
 
-       if (ml->folder && data.uids->len)
-               camel_folder_sort_uids (ml->folder, data.uids);
+       folder = message_list_ref_folder (ml);
+
+       if (folder != NULL && data.uids->len > 0)
+               camel_folder_sort_uids (folder, data.uids);
+
+       g_clear_object (&folder);
 
        return data.uids;
 }
@@ -4167,6 +4293,8 @@ message_list_get_uids (MessageList *ml)
 GPtrArray *
 message_list_get_selected (MessageList *ml)
 {
+       CamelFolder *folder;
+
        struct _ml_selected_data data = {
                ml,
                g_ptr_array_new ()
@@ -4174,8 +4302,12 @@ message_list_get_selected (MessageList *ml)
 
        e_tree_selected_path_foreach (E_TREE (ml), ml_getselected_cb, &data);
 
-       if (ml->folder && data.uids->len)
-               camel_folder_sort_uids (ml->folder, data.uids);
+       folder = message_list_ref_folder (ml);
+
+       if (folder != NULL && data.uids->len > 0)
+               camel_folder_sort_uids (folder, data.uids);
+
+       g_clear_object (&folder);
 
        return data.uids;
 }
@@ -4448,9 +4580,7 @@ cmp_array_uids (gconstpointer a,
        g_return_val_if_fail (md2 != NULL, 0);
        g_return_val_if_fail (md2->mi != NULL, 0);
 
-       if (!sort_data->ml ||
-           sort_data->folder != sort_data->ml->folder ||
-           g_cancellable_is_cancelled (sort_data->cancellable))
+       if (g_cancellable_is_cancelled (sort_data->cancellable))
                return 0;
 
        for (i = 0;
@@ -4514,16 +4644,18 @@ ml_sort_uids_by_tree (MessageList *ml,
        ETreeTableAdapter *adapter;
        ETableSortInfo *sort_info;
        ETableHeader *full_header;
+       CamelFolder *folder;
        struct sort_array_data sort_data;
        guint i, len;
 
        if (g_cancellable_is_cancelled (cancellable))
                return;
 
-       g_return_if_fail (ml != NULL);
-       g_return_if_fail (ml->folder != NULL);
        g_return_if_fail (uids != NULL);
 
+       folder = message_list_ref_folder (ml);
+       g_return_if_fail (folder != NULL);
+
        adapter = e_tree_get_table_adapter (E_TREE (ml));
        g_return_if_fail (adapter != NULL);
 
@@ -4531,14 +4663,15 @@ ml_sort_uids_by_tree (MessageList *ml,
        full_header = e_tree_table_adapter_get_header (adapter);
 
        if (!sort_info || uids->len == 0 || !full_header || e_table_sort_info_sorting_get_count (sort_info) 
== 0) {
-               camel_folder_sort_uids (ml->folder, uids);
+               camel_folder_sort_uids (folder, uids);
+               g_object_unref (folder);
                return;
        }
 
        len = e_table_sort_info_sorting_get_count (sort_info);
 
        sort_data.ml = ml;
-       sort_data.folder = g_object_ref (ml->folder);
+       sort_data.folder = folder;
        sort_data.sort_columns = g_ptr_array_sized_new (len);
        sort_data.message_infos = g_hash_table_new (g_str_hash, g_str_equal);
        sort_data.cmp_cache = e_table_sorting_utils_create_cmp_cache ();
@@ -4546,7 +4679,6 @@ ml_sort_uids_by_tree (MessageList *ml,
 
        for (i = 0;
             i < len
-            && ml->folder == sort_data.folder
             && !g_cancellable_is_cancelled (cancellable);
             i++) {
                ETableSortColumn scol;
@@ -4562,11 +4694,10 @@ ml_sort_uids_by_tree (MessageList *ml,
                g_ptr_array_add (sort_data.sort_columns, data);
        }
 
-       camel_folder_summary_prepare_fetch_all (ml->folder->summary, NULL);
+       camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
 
        for (i = 0;
             i < uids->len
-            && ml->folder == sort_data.folder
             && !g_cancellable_is_cancelled (cancellable);
             i++) {
                gchar *uid;
@@ -4574,9 +4705,12 @@ ml_sort_uids_by_tree (MessageList *ml,
                struct sort_message_info_data *md;
 
                uid = g_ptr_array_index (uids, i);
-               mi = camel_folder_get_message_info (sort_data.folder, uid);
-               if (!mi) {
-                       g_warning ("%s: Cannot find uid '%s' in folder '%s'", G_STRFUNC, uid, 
camel_folder_get_full_name (sort_data.folder));
+               mi = camel_folder_get_message_info (folder, uid);
+               if (mi == NULL) {
+                       g_warning (
+                               "%s: Cannot find uid '%s' in folder '%s'",
+                               G_STRFUNC, uid,
+                               camel_folder_get_full_name (folder));
                        continue;
                }
 
@@ -4587,12 +4721,21 @@ ml_sort_uids_by_tree (MessageList *ml,
                g_hash_table_insert (sort_data.message_infos, uid, md);
        }
 
-       if (sort_data.folder == ml->folder && !g_cancellable_is_cancelled (cancellable))
-               g_qsort_with_data (uids->pdata, uids->len, sizeof (gpointer), cmp_array_uids, &sort_data);
+       if (!g_cancellable_is_cancelled (cancellable))
+               g_qsort_with_data (
+                       uids->pdata,
+                       uids->len,
+                       sizeof (gpointer),
+                       cmp_array_uids,
+                       &sort_data);
 
-       camel_folder_summary_unlock (sort_data.folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+       camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
-       g_hash_table_foreach (sort_data.message_infos, (GHFunc) free_message_info_data, &sort_data);
+       /* FIXME Teach the hash table to destroy its own data. */
+       g_hash_table_foreach (
+               sort_data.message_infos,
+               (GHFunc) free_message_info_data,
+               &sort_data);
        g_hash_table_destroy (sort_data.message_infos);
 
        g_ptr_array_foreach (sort_data.sort_columns, (GFunc) g_free, NULL);
@@ -4600,7 +4743,7 @@ ml_sort_uids_by_tree (MessageList *ml,
 
        e_table_sorting_utils_free_cmp_cache (sort_data.cmp_cache);
 
-       g_object_unref (sort_data.folder);
+       g_object_unref (folder);
 }
 
 static void
@@ -4897,13 +5040,18 @@ message_list_regen_done_cb (GObject *source_object,
                regen_data->tree = NULL;
 
                if (forcing_expand_state || searching) {
-                       if (message_list->folder != NULL && tree != NULL && !searching)
-                               save_tree_state (message_list);
+                       if (message_list->priv->folder != NULL &&
+                           tree != NULL && !searching)
+                               save_tree_state (
+                                       message_list,
+                                       regen_data->folder);
                        /* do not forget to set this back to use the default value... */
                        e_tree_force_expanded_state (tree, 0);
                } else {
                        load_tree_state (
-                               message_list, regen_data->expand_state);
+                               message_list,
+                               regen_data->folder,
+                               regen_data->expand_state);
                }
 
                message_list->expand_all = 0;
@@ -5047,7 +5195,7 @@ mail_regen_list (MessageList *message_list,
                search = NULL;
 
        /* Can't list messages in a folder until we have a folder. */
-       if (message_list->folder == NULL) {
+       if (message_list->priv->folder == NULL) {
                g_free (message_list->search);
                message_list->search = g_strdup (search);
                return;
diff --git a/mail/message-list.h b/mail/message-list.h
index 829e3c9..ec76cc6 100644
--- a/mail/message-list.h
+++ b/mail/message-list.h
@@ -104,9 +104,6 @@ struct _MessageList {
        ETreePath     tree_root;
        ETableExtras *extras;
 
-       /* The folder being shown. */
-       CamelFolder *folder;
-
        GHashTable *uid_nodemap; /* uid (from info) -> tree node mapping */
 
        GHashTable *normalised_hash;
@@ -167,6 +164,7 @@ typedef enum {
 GType          message_list_get_type           (void);
 GtkWidget *    message_list_new                (EMailSession *session);
 EMailSession * message_list_get_session        (MessageList *message_list);
+CamelFolder *  message_list_ref_folder         (MessageList *message_list);
 void           message_list_set_folder         (MessageList *message_list,
                                                 CamelFolder *folder);
 GtkTargetList *        message_list_get_copy_target_list
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index 54f4d58..aa9addf 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -200,7 +200,7 @@ mail_shell_view_folder_tree_selection_done_cb (EMailShellView *mail_shell_view,
        EMailReader *reader;
        EMailView *mail_view;
        CamelFolder *folder;
-       gchar *list_uri;
+       gchar *list_uri = NULL;
        gchar *tree_uri;
 
        mail_shell_content = mail_shell_view->priv->mail_shell_content;
@@ -216,16 +216,17 @@ mail_shell_view_folder_tree_selection_done_cb (EMailShellView *mail_shell_view,
         * method gets the folder from the message list is supposed to be
         * a hidden implementation detail, and we want to explicitly get
         * the folder URI from the message list here. */
-       folder = MESSAGE_LIST (message_list)->folder;
-       if (folder)
+       folder = message_list_ref_folder (MESSAGE_LIST (message_list));
+       if (folder != NULL) {
                list_uri = e_mail_folder_uri_from_folder (folder);
-       else
-               list_uri = NULL;
+               g_object_unref (folder);
+       }
+
        tree_uri = em_folder_tree_get_selected_uri (folder_tree);
 
        /* If the folder tree and message list disagree on the current
         * folder, reset the folder tree to match the message list. */
-       if (list_uri && g_strcmp0 (tree_uri, list_uri) != 0)
+       if (list_uri != NULL && g_strcmp0 (tree_uri, list_uri) != 0)
                em_folder_tree_set_selected (folder_tree, list_uri, FALSE);
 
        g_free (list_uri);


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