[balsa/gtk3] Call Gtk from only the main thread to open mailbox



commit ca88b30387d3aaf9dbeef149d6ca3e758742146a
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Sun Jun 3 13:07:13 2012 -0400

    Call Gtk from only the main thread to open mailbox
    
    	* libbalsa/mailbox.c (lbm_cache_message): avoid infinite
    	recursion.
    	* libbalsa/mailbox.h: do not export
    	libbalsa_mailbox_index_entry_new_from_msg.
    	* src/balsa-index.c (bndx_set_mailbox), (bndx_open_mailbox),
    	(balsa_index_load_mailbox_node): open mailbox in a subthread.
    	* src/balsa-index.h: do not export balsa_index_load_mailbox_node
    	and balsa_index_scroll_on_open.
    	* src/main-window.c: start opening mailbox in the main thread.

 ChangeLog          |   14 +++++
 libbalsa/mailbox.c |   19 +++----
 libbalsa/mailbox.h |    2 -
 src/balsa-index.c  |  157 ++++++++++++++++++++++++++++++++++++----------------
 src/balsa-index.h  |    6 +-
 src/main-window.c  |  114 +++-----------------------------------
 6 files changed, 141 insertions(+), 171 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index cabe47f..0d1c50e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2012-06-03  Peter Bloomfield
+
+	Call Gtk from only the main thread when opening a mailbox
+
+	* libbalsa/mailbox.c (lbm_cache_message): avoid infinite
+	recursion.
+	* libbalsa/mailbox.h: do not export
+	libbalsa_mailbox_index_entry_new_from_msg.
+	* src/balsa-index.c (bndx_set_mailbox), (bndx_open_mailbox),
+	(balsa_index_load_mailbox_node): open mailbox in a subthread.
+	* src/balsa-index.h: do not export balsa_index_load_mailbox_node
+	and balsa_index_scroll_on_open.
+	* src/main-window.c: start opening mailbox in the main thread.
+
 2012-05-28  Peter Bloomfield
 
 	* src/balsa-index.c (bi_view_on_open,
diff --git a/libbalsa/mailbox.c b/libbalsa/mailbox.c
index be4a732..073222e 100644
--- a/libbalsa/mailbox.c
+++ b/libbalsa/mailbox.c
@@ -367,14 +367,6 @@ lbm_index_entry_populate_from_msg(LibBalsaMailboxIndexEntry * entry,
     libbalsa_mailbox_msgno_changed(msg->mailbox, msg->msgno);
 }
 
-LibBalsaMailboxIndexEntry*
-libbalsa_mailbox_index_entry_new_from_msg(LibBalsaMessage *msg)
-{
-    LibBalsaMailboxIndexEntry *entry = g_new(LibBalsaMailboxIndexEntry,1);
-    lbm_index_entry_populate_from_msg(entry, msg);
-    return entry;
-}
-
 #ifdef BALSA_USE_THREADS
 static LibBalsaMailboxIndexEntry*
 lbm_index_entry_new_pending(void)
@@ -1913,13 +1905,18 @@ lbm_cache_message(LibBalsaMailbox * mailbox, guint msgno,
 
     entry = g_ptr_array_index(mailbox->mindex, msgno - 1);
 
-    if (!entry)
+    if (!entry) {
+        /* Assign pointer in mailbox->mindex before populating the
+         * entry, because we may recursively enter lbm_cache_message
+         * while populating it. */
         g_ptr_array_index(mailbox->mindex, msgno - 1) =
-            libbalsa_mailbox_index_entry_new_from_msg(message);
+            entry = g_new0(LibBalsaMailboxIndexEntry, 1);
+        lbm_index_entry_populate_from_msg(entry, message);
 #if BALSA_USE_THREADS
-    else if (entry->idle_pending)
+    } else if (entry->idle_pending) {
         lbm_index_entry_populate_from_msg(entry, message);
 #endif                          /* BALSA_USE_THREADS */
+    }
 }
 
 LibBalsaMessage *
diff --git a/libbalsa/mailbox.h b/libbalsa/mailbox.h
index c90a1a0..fd217f3 100644
--- a/libbalsa/mailbox.h
+++ b/libbalsa/mailbox.h
@@ -502,8 +502,6 @@ gint libbalsa_mailbox_move_duplicates(LibBalsaMailbox * mailbox,
  * Mailbox views-related functions.
  */
 typedef struct LibBalsaMailboxIndexEntry_ LibBalsaMailboxIndexEntry;
-LibBalsaMailboxIndexEntry* libbalsa_mailbox_index_entry_new_from_msg
-                           (LibBalsaMessage *msg);
 void libbalsa_mailbox_index_entry_set_no(LibBalsaMailboxIndexEntry *entry,
                                          unsigned no);
 void libbalsa_mailbox_index_entry_clear(LibBalsaMailbox * mailbox,
diff --git a/src/balsa-index.c b/src/balsa-index.c
index 5627d73..c52396d 100644
--- a/src/balsa-index.c
+++ b/src/balsa-index.c
@@ -885,7 +885,7 @@ bi_view_on_open(struct view_on_open_data *data)
     return FALSE;
 }
 
-void
+static void
 balsa_index_scroll_on_open(BalsaIndex *index)
 {
     LibBalsaMailbox *mailbox = index->mailbox_node->mailbox;
@@ -1006,90 +1006,151 @@ bndx_mailbox_message_expunged_cb(LibBalsaMailbox * mailbox, guint msgno,
         --bindex->next_msgno;
 }
 
-/* balsa_index_load_mailbox_node:
-   open mailbox_node, the opening is done in thread to keep UI alive.
-
-   Called NOT holding the gdk lock, so we must wrap gtk calls in
-   gdk_threads_{enter,leave}.
-*/
+/*
+ * balsa_index_load_mailbox_node:
+ */
 
-gboolean
-balsa_index_load_mailbox_node (BalsaIndex * index,
-                               BalsaMailboxNode* mbnode, GError **err)
-{
-    GtkTreeView *tree_view;
-    LibBalsaMailbox* mailbox;
+typedef struct {
+    BalsaIndex *index;
+    BalsaMailboxNode *mbnode;
+    GError *err;
     gboolean successp;
-    gint try_cnt;
-
-    g_return_val_if_fail(BALSA_IS_INDEX(index), TRUE);
-    g_return_val_if_fail(index->mailbox_node == NULL, TRUE);
-    g_return_val_if_fail(BALSA_IS_MAILBOX_NODE(mbnode), TRUE);
-    g_return_val_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox), TRUE);
+} bndx_open_mailbox_info;
 
-    mailbox = mbnode->mailbox;
+/* Idle callback to complete opening a mailbox */
 
-    try_cnt = 0;
-    do {
-        g_clear_error(err);
-        successp = libbalsa_mailbox_open(mailbox, err);
-        if (!balsa_app.main_window)
-            return FALSE;
+static gboolean
+bndx_set_mailbox(bndx_open_mailbox_info * info)
+{
+    GtkTreeView *tree_view;
+    LibBalsaMailbox *mailbox;
 
-        if(successp) break;
-        if(*err && (*err)->code != LIBBALSA_MAILBOX_TOOMANYOPEN_ERROR)
-            break;
-        balsa_mblist_close_lru_peer_mbx(balsa_app.mblist, mailbox);
-    } while(try_cnt++<3);
+    if (!info->successp) {
+        libbalsa_information(LIBBALSA_INFORMATION_ERROR,
+                             _("Unable to Open Mailbox!\n%s."),
+                             info->err ?
+                             info->err->message : _("Unknown error"));
+        g_error_free(info->err);
+        g_object_unref(g_object_ref_sink(info->index));
+        g_free(info);
 
-    if (!successp)
-	return TRUE;
+        return FALSE;
+    }
 
     /*
      * set the new mailbox
      */
-    index->mailbox_node = mbnode;
-    g_object_weak_ref(G_OBJECT(mbnode),
-                      (GWeakNotify) bndx_mbnode_weak_notify, index);
+    info->index->mailbox_node = info->mbnode;
+    g_object_weak_ref(G_OBJECT(info->mbnode),
+                      (GWeakNotify) bndx_mbnode_weak_notify, info->index);
     /*
      * rename "from" column to "to" for outgoing mail
      */
-    gdk_threads_enter();
-    tree_view = GTK_TREE_VIEW(index);
+    tree_view = GTK_TREE_VIEW(info->index);
+    mailbox = info->mbnode->mailbox;
     if (libbalsa_mailbox_get_show(mailbox) == LB_MAILBOX_SHOW_TO) {
         GtkTreeViewColumn *column =
-	    gtk_tree_view_get_column(tree_view, LB_MBOX_FROM_COL);
-        index->filter_no = 1; /* FIXME: this is hack! */
+            gtk_tree_view_get_column(tree_view, LB_MBOX_FROM_COL);
+        info->index->filter_no = 1;     /* FIXME: this is hack! */
         gtk_tree_view_column_set_title(column, _("To"));
     }
 
     g_signal_connect_swapped(G_OBJECT(mailbox), "changed",
-			     G_CALLBACK(bndx_mailbox_changed_cb),
-			     (gpointer) index);
+                             G_CALLBACK(bndx_mailbox_changed_cb),
+                             info->index);
     g_signal_connect(mailbox, "row-inserted",
-	    	     G_CALLBACK(bndx_mailbox_row_inserted_cb), index);
+                     G_CALLBACK(bndx_mailbox_row_inserted_cb),
+                     info->index);
     g_signal_connect(mailbox, "message-expunged",
-	    	     G_CALLBACK(bndx_mailbox_message_expunged_cb), index);
+                     G_CALLBACK(bndx_mailbox_message_expunged_cb),
+                     info->index);
 
-    /* Set the tree store*/
+    /* Set the tree store */
 #ifndef GTK2_FETCHES_ONLY_VISIBLE_CELLS
     g_object_set_data(G_OBJECT(mailbox), "tree-view", tree_view);
 #endif
     gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(mailbox));
-    gdk_threads_leave();
 
     /* Create a search-iter for SEARCH UNDELETED. */
     if (!cond_undeleted)
         cond_undeleted =
             libbalsa_condition_new_flag_enum(TRUE,
                                              LIBBALSA_MESSAGE_FLAG_DELETED);
-    index->search_iter = libbalsa_mailbox_search_iter_new(cond_undeleted);
+    info->index->search_iter =
+        libbalsa_mailbox_search_iter_new(cond_undeleted);
     /* Note when this mailbox was opened, for use in auto-closing. */
-    time(&index->mailbox_node->last_use);
+    time(&info->index->mailbox_node->last_use);
+
+    balsa_index_scroll_on_open(info->index);
+
+    g_free(info);
 
     return FALSE;
 }
 
+/*
+ * Subthread to do the actual opening
+ */
+static void
+bndx_open_mailbox(bndx_open_mailbox_info * info)
+{
+    gint try_cnt;
+    LibBalsaMailbox *mailbox;
+
+    mailbox = info->mbnode->mailbox;
+
+    info->err = NULL;
+    try_cnt = 0;
+    do {
+        g_clear_error(&info->err);
+        info->successp = libbalsa_mailbox_open(mailbox, &info->err);
+        if (!balsa_app.main_window)
+            return;
+
+        if (info->successp)
+            break;
+        if (info->err &&
+            info->err->code != LIBBALSA_MAILBOX_TOOMANYOPEN_ERROR)
+            break;
+        balsa_mblist_close_lru_peer_mbx(balsa_app.mblist, mailbox);
+    } while (try_cnt++ < 3);
+
+#ifdef BALSA_USE_THREADS
+    gdk_threads_add_idle((GSourceFunc) bndx_set_mailbox, info);
+
+    pthread_exit(0);
+#else                           /* BALSA_USE_THREADS */
+    bndx_set_mailbox(info);
+#endif                          /* BALSA_USE_THREADS */
+}
+
+void
+balsa_index_load_mailbox_node (BalsaIndex * index,
+                               BalsaMailboxNode* mbnode)
+{
+    bndx_open_mailbox_info *info;
+#ifdef BALSA_USE_THREADS
+    pthread_t open_thread;
+#endif                          /* BALSA_USE_THREADS */
+
+    g_return_if_fail(BALSA_IS_INDEX(index));
+    g_return_if_fail(index->mailbox_node == NULL);
+    g_return_if_fail(BALSA_IS_MAILBOX_NODE(mbnode));
+    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
+
+    info = g_new(bndx_open_mailbox_info, 1);
+    info->index = index;
+    info->mbnode = mbnode;
+
+#ifdef BALSA_USE_THREADS
+    pthread_create(&open_thread, NULL,
+                   (void*(*)(void*))bndx_open_mailbox, info);
+    pthread_detach(open_thread);
+#else                           /* BALSA_USE_THREADS */
+    bndx_open_mailbox(info);
+#endif                          /* BALSA_USE_THREADS */
+}
+
 void
 balsa_index_set_width_preference(BalsaIndex *bindex,
                                  BalsaIndexWidthPreference pref)
diff --git a/src/balsa-index.h b/src/balsa-index.h
index dc5ab15..f69f679 100644
--- a/src/balsa-index.h
+++ b/src/balsa-index.h
@@ -105,12 +105,10 @@ extern "C" {
 
 /* sets the mail stream; if it's a new stream, then it's 
  * contents is loaded into the index */
-    gboolean balsa_index_load_mailbox_node(BalsaIndex * bindex,
-                                           BalsaMailboxNode * mbnode,
-					   GError **err);
+    void balsa_index_load_mailbox_node(BalsaIndex * bindex,
+                                       BalsaMailboxNode * mbnode);
     void balsa_index_set_width_preference(BalsaIndex *bindex,
                                           BalsaIndexWidthPreference pref);
-    void balsa_index_scroll_on_open(BalsaIndex *index);
     void balsa_index_update_tree(BalsaIndex *bindex, gboolean expand);
     void balsa_index_set_threading_type(BalsaIndex * bindex, int thtype);
     void balsa_index_set_view_filter(BalsaIndex *bindex,
diff --git a/src/main-window.c b/src/main-window.c
index 5064868..a90ba6a 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -2322,22 +2322,20 @@ bw_notebook_label_new(BalsaMailboxNode * mbnode)
     return box;
 }
 
-/* Called with the gdk lock held (when threads are enabled). */
+/* Class method */
 static void
-bw_real_open_mbnode(BalsaWindow *window, BalsaMailboxNode * mbnode,
-                    gboolean set_current)
+balsa_window_real_open_mbnode(BalsaWindow * window,
+                              BalsaMailboxNode * mbnode,
+                              gboolean set_current)
 {
     BalsaIndex * index;
     GtkWidget *label;
     GtkWidget *scroll;
     gint page_num;
-    gboolean failurep;
-    GError *err = NULL;
     gchar *message;
     LibBalsaMailbox *mailbox;
 
-    /* FIXME: the check is not needed in non-MT-mode */
-    if (!window || bw_is_open_mailbox(mailbox = mbnode->mailbox))
+    if (bw_is_open_mailbox(mailbox = mbnode->mailbox))
         return;
 
     index = BALSA_INDEX(balsa_index_new());
@@ -2346,36 +2344,16 @@ bw_real_open_mbnode(BalsaWindow *window, BalsaMailboxNode * mbnode,
          (balsa_app.layout_type == LAYOUT_WIDE_SCREEN)
          ? BALSA_INDEX_NARROW : BALSA_INDEX_WIDE);
 
-    g_object_add_weak_pointer(G_OBJECT(window), (gpointer) &window);
     message = g_strdup_printf(_("Opening %s"), mailbox->name);
     balsa_window_increase_activity(window, message);
-
-    /* Call balsa_index_load_mailbox_node NOT holding the gdk lock. */
-    gdk_threads_leave();
-    failurep = balsa_index_load_mailbox_node(index, mbnode, &err);
-    gdk_threads_enter();
-
-    if (window) {
-        balsa_window_decrease_activity(window, message);
-        g_object_remove_weak_pointer(G_OBJECT(window), (gpointer) &window);
-    }
+    balsa_index_load_mailbox_node(index, mbnode);
+    balsa_window_decrease_activity(window, message);
     g_free(message);
 
-    if (!window || failurep) {
-        libbalsa_information(
-            LIBBALSA_INFORMATION_ERROR,
-            _("Unable to Open Mailbox!\n%s."),
-	    err ? err->message : _("Unknown error"));
-	g_clear_error(&err);
-        g_object_unref(g_object_ref_sink(index));
-        return;
-    }
-    g_assert(index->mailbox_node);
+    index->mailbox_node = mbnode;
     g_signal_connect(G_OBJECT (index), "index-changed",
                      G_CALLBACK (bw_index_changed_cb), window);
 
-    /* if(config_short_label) label = gtk_label_new(mbnode->mailbox->name);
-       else */
     label = bw_notebook_label_new(mbnode);
 
     /* store for easy access */
@@ -2406,82 +2384,6 @@ bw_real_open_mbnode(BalsaWindow *window, BalsaMailboxNode * mbnode,
     libbalsa_mailbox_set_threading(mailbox,
                                    libbalsa_mailbox_get_threading_type
                                    (mailbox));
-    balsa_index_scroll_on_open(index);
-}
-
-#ifdef BALSA_USE_THREADS
-static pthread_mutex_t open_lock = PTHREAD_MUTEX_INITIALIZER;
-
-struct bw_open_mbnode_info {
-    BalsaWindow *window;
-    BalsaMailboxNode * mbnode;
-    gboolean set_current;
-};
-
-static void
-bw_real_open_mbnode_thread(GPtrArray *info_array)
-{
-    guint i;
-
-    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-    pthread_mutex_lock(&open_lock);
-
-    for (i = 0; i < info_array->len; i++) {
-        struct bw_open_mbnode_info *info =
-            g_ptr_array_index(info_array, i);
-
-        pthread_mutex_unlock(&open_lock);
-        gdk_threads_enter();
-
-        bw_real_open_mbnode(info->window, info->mbnode, info->set_current);
-
-	if (info->window)
-            g_object_remove_weak_pointer(G_OBJECT(info->window),
-                                         (gpointer) &info->window);
-        g_object_unref(info->mbnode);
-
-        gdk_threads_leave();
-        g_free(info);
-        pthread_mutex_lock(&open_lock);
-    }
-
-    info_array->len = 0;
-    pthread_mutex_unlock(&open_lock);
-}
-#endif
-
-static void
-balsa_window_real_open_mbnode(BalsaWindow * window,
-                              BalsaMailboxNode * mbnode,
-                              gboolean set_current)
-{
-#ifdef BALSA_USE_THREADS
-    struct bw_open_mbnode_info *info;
-    static GPtrArray *info_array;
-
-    info = g_new(struct bw_open_mbnode_info, 1);
-    info->window = window;
-    g_object_add_weak_pointer(G_OBJECT(window), (gpointer) &info->window);
-    info->mbnode = g_object_ref(mbnode);
-    info->set_current = set_current;
-
-    pthread_mutex_lock(&open_lock);
-
-    if (!info_array)
-        info_array = g_ptr_array_new();
-    if (!info_array->len) {
-        pthread_t open_thread;
-        pthread_create(&open_thread, NULL,
-                       (void*(*)(void*))bw_real_open_mbnode_thread,
-                       info_array);
-        pthread_detach(open_thread);
-    }
-
-    g_ptr_array_add(info_array, info);
-    pthread_mutex_unlock(&open_lock);
-#else
-    bw_real_open_mbnode(window, mbnode, set_current);
-#endif
 }
 
 /* balsa_window_real_close_mbnode:



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