[evolution] Make sure message_list_folder_changed() is called from the main/UI thread



commit cc222b59f6004441e480e8ca36441445be61e7e2
Author: Milan Crha <mcrha redhat com>
Date:   Wed Oct 3 16:55:16 2018 +0200

    Make sure message_list_folder_changed() is called from the main/UI thread
    
    The function can call (indirectly) gtk+ functions, which are supposed
    to be run in the main/UI thread only, thus even the CamelFolder::changed
    signal is usually delivered in the main thread it could sometimes
    happen that the signal had been delivered in a different thread, which
    could cause a crash.
    
    Reported downstream at:
    https://bugzilla.redhat.com/show_bug.cgi?id=1635465

 src/mail/message-list.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 72 insertions(+), 3 deletions(-)
---
diff --git a/src/mail/message-list.c b/src/mail/message-list.c
index e364b2d97b..70b6a76f17 100644
--- a/src/mail/message-list.c
+++ b/src/mail/message-list.c
@@ -4898,8 +4898,8 @@ mail_folder_hide_by_flag (CamelFolder *folder,
 
 static void
 message_list_folder_changed (CamelFolder *folder,
-                             CamelFolderChangeInfo *changes,
-                             MessageList *message_list)
+                            CamelFolderChangeInfo *changes,
+                            MessageList *message_list)
 {
        CamelFolderChangeInfo *altered_changes = NULL;
        ETreeModel *tree_model;
@@ -4908,6 +4908,10 @@ message_list_folder_changed (CamelFolder *folder,
        gboolean hide_deleted;
        gint i;
 
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+       g_return_if_fail (changes != NULL);
+       g_return_if_fail (IS_MESSAGE_LIST (message_list));
+
        if (message_list->priv->destroyed)
                return;
 
@@ -4976,6 +4980,71 @@ message_list_folder_changed (CamelFolder *folder,
                camel_folder_change_info_free (altered_changes);
 }
 
+typedef struct _FolderChangedData {
+       GWeakRef *folder; /* CamelFolder * */
+       CamelFolderChangeInfo *changes;
+       GWeakRef *message_list; /* MessageList * */
+} FolderChangedData;
+
+static void
+folder_changed_data_free (gpointer ptr)
+{
+       FolderChangedData *fcd = ptr;
+
+       if (fcd) {
+               e_weak_ref_free (fcd->folder);
+               e_weak_ref_free (fcd->message_list);
+               camel_folder_change_info_free (fcd->changes);
+               g_free (fcd);
+       }
+}
+
+static gboolean
+message_list_folder_changed_timeout_cb (gpointer user_data)
+{
+       FolderChangedData *fcd = user_data;
+       CamelFolder *folder;
+       MessageList *message_list;
+
+       g_return_val_if_fail (fcd != NULL, FALSE);
+
+       folder = g_weak_ref_get (fcd->folder);
+       message_list = g_weak_ref_get (fcd->message_list);
+
+       if (folder && message_list)
+               message_list_folder_changed (folder, fcd->changes, message_list);
+
+       g_clear_object (&message_list);
+       g_clear_object (&folder);
+
+       return FALSE;
+}
+
+static void
+message_list_folder_changed_cb (CamelFolder *folder,
+                               CamelFolderChangeInfo *changes,
+                               MessageList *message_list)
+{
+       if (message_list->priv->destroyed)
+               return;
+
+       if (e_util_is_main_thread (g_thread_self ())) {
+               message_list_folder_changed (folder, changes, message_list);
+       } else {
+               FolderChangedData *fcd;
+
+               fcd = g_new0 (FolderChangedData, 1);
+               fcd->folder = e_weak_ref_new (folder);
+               fcd->changes = camel_folder_change_info_copy (changes);
+               fcd->message_list = e_weak_ref_new (message_list);
+
+               /* Just to have it called in the main/UI thread */
+               g_timeout_add_full (G_PRIORITY_DEFAULT, 1,
+                       message_list_folder_changed_timeout_cb,
+                       fcd, folder_changed_data_free);
+       }
+}
+
 CamelFolder *
 message_list_ref_folder (MessageList *message_list)
 {
@@ -5115,7 +5184,7 @@ message_list_set_folder (MessageList *message_list,
 
                handler_id = g_signal_connect (
                        folder, "changed",
-                       G_CALLBACK (message_list_folder_changed),
+                       G_CALLBACK (message_list_folder_changed_cb),
                        message_list);
                message_list->priv->folder_changed_handler_id = handler_id;
 


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