[balsa] Enable multi-threaded POP3 retrieval



commit ba206693c53ab3b6b3103f2271adea2de4801032
Author: Albrecht Dreß <albrecht dress arcor de>
Date:   Fri Jan 5 17:24:15 2018 -0500

    Enable multi-threaded POP3 retrieval
    
        * libbalsa/libbalsa-marshal.list, libbalsa/mailbox.[ch]:
        new simplified signature for the mailbox 'progress-notify' signal
        and the related helper libbalsa_mailbox_progress_notify()
        * libbalsa/libbalsa-progress.[ch]: heavy re-factoring of the progress dialogue,
        including a fully thread-safe interface, simplified access functions,
        and a new activity mode
        * libbalsa/mailbox_pop3.c, libbalsa/send.[ch]:
        use new progress dialogue interface,
        pass option to disable send progress dialogue
        * src/balsa-app.[ch]: define and initialise enable progress dialogue settings,
        use changed send function signature
        * src/balsa-message.c, src/balsa-mime-widget-message.c,
        src/balsa-mime-widget-vcalendar.c, src/sendmsg-window.c:
        use changed send function signature
        * src/main-window.[ch]: implement multi-threaded POP3 retrieval,
        remove old progress implementation, use changed send function signature,
        replace two-state enum by bool
        * src/main.c: remove old progress implementation stuff
        * src/pref-manager.c: replace progress dialogue settings
        by two new bool values and related check boxes
        * src/save-restore.c: save/restore new progress dialogue bool values
        * src/threads.h: completely remove the file
    
    Signed-off-by: Peter Bloomfield <PeterBloomfield bellsouth net>

 ChangeLog                         |   27 +++
 libbalsa/libbalsa-marshal.list    |    3 +-
 libbalsa/libbalsa-progress.c      |  400 +++++++++++++++++++++++++------------
 libbalsa/libbalsa-progress.h      |   60 ++++---
 libbalsa/mailbox.c                |   28 ++-
 libbalsa/mailbox.h                |   21 +-
 libbalsa/mailbox_pop3.c           |   34 ++--
 libbalsa/send.c                   |   69 +++----
 libbalsa/send.h                   |   23 +-
 src/balsa-app.c                   |    7 +-
 src/balsa-app.h                   |    3 +-
 src/balsa-message.c               |    2 +
 src/balsa-mime-widget-message.c   |    1 +
 src/balsa-mime-widget-vcalendar.c |    1 +
 src/main-window.c                 |  394 ++++++++++++-------------------------
 src/main-window.h                 |    8 +-
 src/main.c                        |   39 +----
 src/pref-manager.c                |   41 +---
 src/save-restore.c                |   34 +---
 src/sendmsg-window.c              |    2 +-
 src/threads.h                     |   60 ------
 21 files changed, 578 insertions(+), 679 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f82dffc..3e4466f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2018-01-05  Albrecht Dreß <albrecht dress arcor de>
+
+       Enable multi-threaded POP3 retrieval
+
+       * libbalsa/libbalsa-marshal.list, libbalsa/mailbox.[ch]:
+       new simplified signature for the mailbox '' signal
+       and the related helper libbalsa_mailbox_progress_notify()
+       * libbalsa/libbalsa-progress.[ch]: heavy re-factoring of the progress dialogue,
+       including a fully thread-safe interface, simplified access functions,
+       and a new activity mode
+       * libbalsa/mailbox_pop3.c, libbalsa/send.[ch]:
+       use new progress dialogue interface,
+       pass option to disable send progress dialogue
+       * src/balsa-app.[ch]: define and initialise enable progress dialogue settings,
+       use changed send function signature
+       * src/balsa-message.c, src/balsa-mime-widget-message.c,
+       src/balsa-mime-widget-vcalendar.c, src/sendmsg-window.c:
+       use changed send function signature
+       * src/main-window.[ch]: implement multi-threaded POP3 retrieval,
+       remove old progress implementation, use changed send function signature,
+       replace two-state enum by bool
+       * src/main.c: remove old progress implementation stuff
+       * src/pref-manager.c: replace progress dialogue settings
+       by two new bool values and related check boxes
+       * src/save-restore.c: save/restore new progress dialogue bool values
+       * src/threads.h: completely remove the file
+
 2018-01-04  Peter Bloomfield  <pbloomfield bellsouth net>
 
        Fix a use-after-free bug
diff --git a/libbalsa/libbalsa-marshal.list b/libbalsa/libbalsa-marshal.list
index b670324..a382dfb 100644
--- a/libbalsa/libbalsa-marshal.list
+++ b/libbalsa/libbalsa-marshal.list
@@ -12,6 +12,7 @@ POINTER:OBJECT
 POINTER:POINTER,POINTER
 POINTER:VOID
 VOID:INT,INT,INT
-VOID:INT,INT,INT,STRING
+VOID:INT,DOUBLE,STRING
+# VOID:INT,INT,INT,STRING
 VOID:OBJECT,BOOLEAN
 VOID:POINTER,INT
diff --git a/libbalsa/libbalsa-progress.c b/libbalsa/libbalsa-progress.c
index a7034e7..2192114 100644
--- a/libbalsa/libbalsa-progress.c
+++ b/libbalsa/libbalsa-progress.c
@@ -25,130 +25,202 @@
 
 /* note: this value is forced as minimum and maximum width of the dialogue, which may be wrong for /very/ 
high-resolution screens */
 #define PROGRESS_DIALOG_WIDTH          320
+#define FADER_DURATION                         500U
+#define ACTIVITY_DURATION                      100U
 
 
+typedef struct {
+       ProgressDialog *dialog;
+       const gchar    *title;
+       GtkWindow      *parent;
+       const gchar    *id;
+       gboolean        done;
+       GCond           cond;
+} create_progress_dlg_t;
+
+
+typedef struct {
+       ProgressDialog *dialog;
+       gchar          *id;
+       gboolean        finished;
+       gchar              *message;
+       gdouble         fraction;
+} update_progress_data_t;
+
+
+typedef struct {
+       GtkWidget *revealer;
+       GtkWidget *progress;
+       GtkWidget *label;
+       guint      activity_id;
+       guint      fadeout_id;
+} progress_widget_data_t;
+
+
+static void libbalsa_progress_dialog_ensure_real(ProgressDialog *progress_dialog,
+                                                                                    const gchar    
*dialog_title,
+                                                                                                GtkWindow    
  *parent,
+                                                                                                const gchar  
  *progress_id);
+static gboolean libbalsa_progress_dialog_create_cb(create_progress_dlg_t *dlg_data);
+
 static void progress_dialog_response_cb(GtkWidget *dialog,
                                            gint       response);
 static void progress_dialog_destroy_cb(GtkWidget G_GNUC_UNUSED *widget,
-                                                                          gpointer                 
user_data);
-static GtkWidget *find_widget_by_name(GtkContainer *container,
-                                                                         const gchar  *id);
-static GtkWidget *create_progress_widget(const gchar *progress_id,
-                                                                            const gchar *title);
-static gboolean remove_progress_widget(gpointer user_data);
-static void send_progress_data_free(LibbalsaProgressData *progress_data);
+                                                                          ProgressDialog          
*progress_dialog);
+static progress_widget_data_t *find_progress_data_by_name(GtkContainer *container,
+                                                                                                             
    const gchar  *id);
+static GtkWidget *create_progress_widget(const gchar *progress_id)
+       G_GNUC_WARN_UNUSED_RESULT;
+static gboolean remove_progress_widget(progress_widget_data_t *progress_data);
+static void libbalsa_progress_dialog_update_real(ProgressDialog *progress_dialog,
+                                                                                                const gchar  
  *progress_id,
+                                                                                                gboolean     
   finished,
+                                                                                                gdouble      
   fraction,
+                                                                                                const gchar  
  *message);
+static gboolean libbalsa_progress_dialog_update_cb(update_progress_data_t *upd_data);
+static gboolean progress_activity(GtkProgressBar *progress);
+
+
+void
+libbalsa_progress_dialog_ensure(ProgressDialog *progress_dialog,
+                                                               const gchar    *dialog_title,
+                                                               GtkWindow      *parent,
+                                                               const gchar    *progress_id)
+{
+       g_return_if_fail((progress_dialog != NULL) && (dialog_title != NULL) && (progress_id != NULL));
+
+       g_mutex_lock(&progress_dialog->mutex);
 
+       if (libbalsa_am_i_subthread()) {
+               create_progress_dlg_t dlgdata;
+
+               /* shift the work to an idle callback, and return only after it has been run */
+               dlgdata.dialog = progress_dialog;
+               dlgdata.title = dialog_title;
+               dlgdata.parent = parent;
+               dlgdata.id = progress_id;
+               dlgdata.done = FALSE;
+               g_cond_init(&dlgdata.cond);
+               gdk_threads_add_idle((GSourceFunc) libbalsa_progress_dialog_create_cb, &dlgdata);
+
+               while (!dlgdata.done) {
+                       g_cond_wait(&dlgdata.cond, &progress_dialog->mutex);
+               }
+               g_cond_clear(&dlgdata.cond);
+       } else {
+               libbalsa_progress_dialog_ensure_real(progress_dialog, dialog_title, parent, progress_id);
+       }
 
-/* While libbalsa_progress_dialog_update() will always be called from the main context (typically from an 
idle callback),
- * libbalsa_progress_dialog_ensure /may/ also be called from a thread, so we must ensure the integrity of 
the progress dialogue
- * widget.  As both functions should be really fast, one big common progress dialogue mutex is sufficient. */
-static GMutex progress_mutex;
+       g_mutex_unlock(&progress_dialog->mutex);
+}
 
 
 void
-libbalsa_progress_dialog_ensure(GtkWidget   **progress_dialog,
-                                                               const gchar  *dialog_title,
-                                                               GtkWindow    *parent,
-                                                               const gchar  *progress_id)
+libbalsa_progress_dialog_update(ProgressDialog *progress_dialog,
+                                                               const gchar    *progress_id,
+                                                               gboolean        finished,
+                                                               gdouble         fraction,
+                                                               const gchar    *message,
+                                                               ...)
 {
-       GtkWidget *progress_widget;
-       GtkWidget *content_box;
+       g_return_if_fail((progress_dialog != NULL) && (progress_id != NULL));
 
-       g_return_if_fail((progress_dialog != NULL) && (dialog_title != NULL) && (progress_id != NULL));
+       g_mutex_lock(&progress_dialog->mutex);
+
+       /* nothing to do if the progress dialogue has been closed */
+       if (progress_dialog->dialog != NULL) {
+               gchar *real_msg;
 
-       g_mutex_lock(&progress_mutex);
+               if (message != NULL) {
+                       va_list args;
 
-    if (*progress_dialog == NULL) {
+                       va_start(args, message);
+                       real_msg = g_strdup_vprintf(message, args);
+                       va_end(args);
+               } else {
+                       real_msg = NULL;
+               }
+
+               if (libbalsa_am_i_subthread()) {
+                       update_progress_data_t *update_data;
+
+                       update_data = g_malloc(sizeof(update_progress_data_t));
+                       update_data->dialog = progress_dialog;
+                       update_data->id = g_strdup(progress_id);
+                       update_data->finished = finished;
+                       update_data->fraction = fraction;
+                       update_data->message = real_msg;
+                       gdk_threads_add_idle((GSourceFunc) libbalsa_progress_dialog_update_cb, update_data);
+               } else {
+                       libbalsa_progress_dialog_update_real(progress_dialog, progress_id, finished, 
fraction, real_msg);
+                       g_free(real_msg);
+               }
+       }
+
+       g_mutex_unlock(&progress_dialog->mutex);
+}
+
+
+/* --- local functions --- */
+
+/* note: the mutex ProgressDialog::mutex is always locked when this function is called */
+static void
+libbalsa_progress_dialog_ensure_real(ProgressDialog *progress_dialog,
+                                                                    const gchar    *dialog_title,
+                                                                    GtkWindow      *parent,
+                                                                    const gchar    *progress_id)
+{
+       GtkWidget *content_box;
+       const progress_widget_data_t *progress_data;
+
+    if (progress_dialog->dialog == NULL) {
        GdkGeometry hints;
 
-       *progress_dialog = gtk_dialog_new_with_buttons(dialog_title, parent,
+       progress_dialog->dialog = gtk_dialog_new_with_buttons(dialog_title, parent,
                GTK_DIALOG_DESTROY_WITH_PARENT | libbalsa_dialog_flags(), _("_Hide"), GTK_RESPONSE_CLOSE, 
NULL);
-       gtk_window_set_role(GTK_WINDOW(*progress_dialog), "progress_dialog");
+       gtk_window_set_role(GTK_WINDOW(progress_dialog->dialog), "progress_dialog");
         hints.min_width = PROGRESS_DIALOG_WIDTH;
         hints.min_height = 1;
         hints.max_width = PROGRESS_DIALOG_WIDTH;
         hints.max_height = -1;
-        gtk_window_set_geometry_hints(GTK_WINDOW(*progress_dialog), NULL, &hints, GDK_HINT_MIN_SIZE + 
GDK_HINT_MAX_SIZE);
-        gtk_window_set_resizable(GTK_WINDOW(*progress_dialog), FALSE);
-        g_signal_connect(G_OBJECT(*progress_dialog), "response", G_CALLBACK(progress_dialog_response_cb), 
NULL);
-        g_signal_connect(G_OBJECT(*progress_dialog), "destroy", G_CALLBACK(progress_dialog_destroy_cb), 
progress_dialog);
+        gtk_window_set_geometry_hints(GTK_WINDOW(progress_dialog->dialog), NULL, &hints, GDK_HINT_MIN_SIZE + 
GDK_HINT_MAX_SIZE);
+        gtk_window_set_resizable(GTK_WINDOW(progress_dialog->dialog), FALSE);
+        g_signal_connect(G_OBJECT(progress_dialog->dialog), "response", 
G_CALLBACK(progress_dialog_response_cb), NULL);
+        g_signal_connect(G_OBJECT(progress_dialog->dialog), "destroy", 
G_CALLBACK(progress_dialog_destroy_cb), progress_dialog);
 
-       content_box = gtk_dialog_get_content_area(GTK_DIALOG(*progress_dialog));
+       content_box = gtk_dialog_get_content_area(GTK_DIALOG(progress_dialog->dialog));
        gtk_box_set_spacing(GTK_BOX(content_box), 6);
 
-        gtk_widget_show_all(*progress_dialog);
+        gtk_widget_show_all(progress_dialog->dialog);
     } else {
-       content_box = gtk_dialog_get_content_area(GTK_DIALOG(*progress_dialog));
+       content_box = gtk_dialog_get_content_area(GTK_DIALOG(progress_dialog->dialog));
     }
 
-    progress_widget = find_widget_by_name(GTK_CONTAINER(content_box), progress_id);
-    if (progress_widget != NULL) {
-       if (!gtk_revealer_get_child_revealed(GTK_REVEALER(progress_widget))) {
-               gtk_revealer_set_reveal_child(GTK_REVEALER(progress_widget), TRUE);
+    progress_data = find_progress_data_by_name(GTK_CONTAINER(content_box), progress_id);
+    if (progress_data != NULL) {
+       if (!gtk_revealer_get_child_revealed(GTK_REVEALER(progress_data->revealer))) {
+               gtk_revealer_set_reveal_child(GTK_REVEALER(progress_data->revealer), TRUE);
        }
     } else {
-       progress_widget = create_progress_widget(progress_id, progress_id);
+       GtkWidget *progress_widget;
+
+       progress_widget = create_progress_widget(progress_id);
        gtk_revealer_set_reveal_child(GTK_REVEALER(progress_widget), TRUE);
        gtk_box_pack_start(GTK_BOX(content_box), progress_widget, FALSE, FALSE, 0);
        gtk_widget_show_all(progress_widget);
     }
-
-       g_mutex_unlock(&progress_mutex);
 }
 
-static void
-revealer_destroy_notify(gpointer timer_id)
-{
-    g_source_remove(GPOINTER_TO_UINT(timer_id));
-}
 
-gboolean
-libbalsa_progress_dialog_update(gpointer user_data)
+/* note: the mutex ProgressDialog::mutex is never locked when this function is called */
+static gboolean
+libbalsa_progress_dialog_create_cb(create_progress_dlg_t *dlg_data)
 {
-       LibbalsaProgressData *ctrl_data = (LibbalsaProgressData *) user_data;
-
-       g_return_val_if_fail(ctrl_data != NULL, FALSE);
-
-       g_mutex_lock(&progress_mutex);
-
-       if (ctrl_data->progress_dialog == NULL) {
-               if (ctrl_data->finished) {
-                       libbalsa_information(LIBBALSA_INFORMATION_MESSAGE, "%s:\n%s", ctrl_data->progress_id, 
ctrl_data->message);
-               }
-       } else {
-               GtkWidget *progress_widget;
-               GtkWidget *content_box;
-
-               content_box = gtk_dialog_get_content_area(GTK_DIALOG(ctrl_data->progress_dialog));
-               progress_widget = find_widget_by_name(GTK_CONTAINER(content_box), ctrl_data->progress_id);
-               if (progress_widget != NULL) {
-                       if (ctrl_data->message != NULL) {
-                               GtkLabel *label;
-
-                               label = GTK_LABEL(g_object_get_data(G_OBJECT(progress_widget), "label"));
-                               gtk_label_set_text(label, ctrl_data->message);
-                       }
-                       if (isnan(ctrl_data->fraction) != 1) {
-                               GtkProgressBar *progress;
-
-                               progress = GTK_PROGRESS_BAR(g_object_get_data(G_OBJECT(progress_widget), 
"progress"));
-                               gtk_progress_bar_set_fraction(progress, ctrl_data->fraction);
-                       }
-                       if (ctrl_data->finished) {
-                               guint timer_id;
-
-                               gtk_revealer_set_reveal_child(GTK_REVEALER(progress_widget), FALSE);
-
-                               /* set a timer and remember it's id so we can remove it properly if the user 
destroys the whole dialogue */
-                                timer_id = g_timeout_add(500, remove_progress_widget, progress_widget);
-                                g_object_set_data_full(G_OBJECT(progress_widget), "timer", 
GUINT_TO_POINTER(timer_id),
-                                                       revealer_destroy_notify);
-                       }
-               }
-       }
-
-       g_mutex_unlock(&progress_mutex);
-       send_progress_data_free(ctrl_data);
+       g_mutex_lock(&dlg_data->dialog->mutex);
+       libbalsa_progress_dialog_ensure_real(dlg_data->dialog, dlg_data->title, dlg_data->parent, 
dlg_data->id);
+       dlg_data->done = TRUE;
+       g_cond_signal(&dlg_data->cond);
+       g_mutex_unlock(&dlg_data->dialog->mutex);
 
        return FALSE;
 }
@@ -166,69 +238,83 @@ progress_dialog_response_cb(GtkWidget *dialog,
 
 static void
 progress_dialog_destroy_cb(GtkWidget G_GNUC_UNUSED *widget,
-                                                  gpointer                 user_data)
+                                                  ProgressDialog          *progress_dialog)
 {
-       g_mutex_lock(&progress_mutex);
-       *((gpointer *) user_data) = NULL;
-       g_mutex_unlock(&progress_mutex);
+       g_mutex_lock(&progress_dialog->mutex);
+       progress_dialog->dialog = NULL;
+       g_mutex_unlock(&progress_dialog->mutex);
 }
 
 
-static GtkWidget *
-find_widget_by_name(GtkContainer *container,
-                                       const gchar  *id)
+static void
+progress_data_destroy_cb(GtkWidget G_GNUC_UNUSED *widget,
+                                                progress_widget_data_t  *progress_data)
+{
+       if (progress_data->activity_id != 0U) {
+               g_source_remove(progress_data->activity_id);
+               progress_data->activity_id = 0U;
+       }
+       if (progress_data->fadeout_id != 0U) {
+               g_source_remove(progress_data->fadeout_id);
+               progress_data->fadeout_id = 0U;
+       }
+}
+
+
+static progress_widget_data_t *
+find_progress_data_by_name(GtkContainer *container,
+                                                  const gchar  *id)
 {
        GList *children;
        GList *this_child;
-       GtkWidget *widget;
+       progress_widget_data_t *data;
 
        children = gtk_container_get_children(container);
-       widget = NULL;
+       data = NULL;
        this_child = children;
-       while ((widget == NULL) && (this_child != NULL)) {
+       while ((data == NULL) && (this_child != NULL)) {
                if (strcmp(gtk_widget_get_name(GTK_WIDGET(this_child->data)), id) == 0) {
-                       widget = GTK_WIDGET(this_child->data);
+                       data = g_object_get_data(G_OBJECT(this_child->data), "data");
                } else {
                        this_child = this_child->next;
                }
        }
        g_list_free(children);
 
-       return widget;
+       return data;
 }
 
 
 static GtkWidget *
-create_progress_widget(const gchar *progress_id,
-                                          const gchar *title)
+create_progress_widget(const gchar *progress_id)
 {
-       GtkWidget *result;
        GtkWidget *box;
        GtkWidget *label;
-       GtkWidget *progress;
+       progress_widget_data_t *widget_data;
 
-       result = gtk_revealer_new();
-       gtk_revealer_set_transition_type(GTK_REVEALER(result), GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
-       gtk_revealer_set_transition_duration(GTK_REVEALER(result), 500);
-       gtk_revealer_set_reveal_child(GTK_REVEALER(result), FALSE);
-       gtk_widget_set_name(result, progress_id);
+       widget_data = g_malloc0(sizeof(progress_widget_data_t));
+       widget_data->revealer = gtk_revealer_new();
+       gtk_revealer_set_transition_type(GTK_REVEALER(widget_data->revealer), 
GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+       gtk_revealer_set_transition_duration(GTK_REVEALER(widget_data->revealer), FADER_DURATION);
+       gtk_revealer_set_reveal_child(GTK_REVEALER(widget_data->revealer), FALSE);
+       gtk_widget_set_name(widget_data->revealer, progress_id);
+       g_object_set_data_full(G_OBJECT(widget_data->revealer), "data", widget_data, g_free);
+    g_signal_connect(G_OBJECT(widget_data->revealer), "destroy", G_CALLBACK(progress_data_destroy_cb), 
widget_data);
 
        box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
-       gtk_container_add(GTK_CONTAINER(result), box);
+       gtk_container_add(GTK_CONTAINER(widget_data->revealer), box);
 
-       label = gtk_label_new(title);
+       label = gtk_label_new(progress_id);
        gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
 
-       label = gtk_label_new(" ");
-       gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-       g_object_set_data(G_OBJECT(result), "label", label);
-       gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
+       widget_data->label = gtk_label_new(" ");
+       gtk_label_set_line_wrap(GTK_LABEL(widget_data->label), TRUE);
+       gtk_box_pack_start(GTK_BOX(box), widget_data->label, FALSE, FALSE, 0);
 
-       progress = gtk_progress_bar_new();
-       g_object_set_data(G_OBJECT(result), "progress", progress);
-       gtk_box_pack_start(GTK_BOX(box), progress, FALSE, FALSE, 0);
+       widget_data->progress = gtk_progress_bar_new();
+       gtk_box_pack_start(GTK_BOX(box), widget_data->progress, FALSE, FALSE, 0);
 
-       return result;
+       return widget_data->revealer;
 }
 
 
@@ -245,17 +331,15 @@ count_revealers(GtkWidget *widget,
 
 
 static gboolean
-remove_progress_widget(gpointer user_data)
+remove_progress_widget(progress_widget_data_t *progress_data)
 {
-       GtkWidget *progress = GTK_WIDGET(user_data);
        GtkWidget *parent_dialog;
        GtkWidget *content_box;
        guint rev_children = 0U;
 
-        (void) g_object_steal_data(G_OBJECT(progress), "timer");
-
-       parent_dialog = gtk_widget_get_toplevel(progress);
-       gtk_widget_destroy(progress);
+       progress_data->fadeout_id = 0U;
+       parent_dialog = gtk_widget_get_toplevel(progress_data->revealer);
+       gtk_widget_destroy(progress_data->revealer);
 
        /* count the GtkRevealer children left, so we can just destroy the dialogue if there is none */
        content_box = gtk_dialog_get_content_area(GTK_DIALOG(parent_dialog));
@@ -269,10 +353,70 @@ remove_progress_widget(gpointer user_data)
 }
 
 
+/* note: the mutex ProgressDialog::mutex is never locked when this function is called */
+static gboolean
+libbalsa_progress_dialog_update_cb(update_progress_data_t *upd_data)
+{
+       g_mutex_lock(&upd_data->dialog->mutex);
+       libbalsa_progress_dialog_update_real(upd_data->dialog, upd_data->id, upd_data->finished, 
upd_data->fraction, upd_data->message);
+       g_mutex_unlock(&upd_data->dialog->mutex);
+       g_free(upd_data->id);
+       g_free(upd_data->message);
+       g_free(upd_data);
+       return FALSE;
+}
+
+
+/* note: the mutex ProgressDialog::mutex is always locked when this function is called */
 static void
-send_progress_data_free(LibbalsaProgressData *progress_data)
+libbalsa_progress_dialog_update_real(ProgressDialog *progress_dialog,
+                                                                        const gchar    *progress_id,
+                                                                        gboolean        finished,
+                                                                        gdouble         fraction,
+                                                                        const gchar    *message)
+{
+       if (progress_dialog->dialog == NULL) {
+               if (finished) {
+                       libbalsa_information(LIBBALSA_INFORMATION_MESSAGE, "%s:\n%s", progress_id, message);
+               }
+       } else {
+               GtkWidget *content_box;
+               progress_widget_data_t *progress_data;
+
+               content_box = gtk_dialog_get_content_area(GTK_DIALOG(progress_dialog->dialog));
+               progress_data = find_progress_data_by_name(GTK_CONTAINER(content_box), progress_id);
+               if (progress_data != NULL) {
+                       if (message != NULL) {
+                               gtk_label_set_text(GTK_LABEL(progress_data->label), message);
+                       }
+                       if (isnan(fraction) != 1) {
+                               if (isinf(fraction) != 0) {
+                                       if (progress_data->activity_id == 0U) {
+                                               
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress_data->progress));
+                                               progress_data->activity_id =
+                                                       g_timeout_add(ACTIVITY_DURATION, (GSourceFunc) 
progress_activity, progress_data->progress);
+                                       }
+                               } else {
+                                       if (progress_data->activity_id != 0U) {
+                                               g_source_remove(progress_data->activity_id);
+                                               progress_data->activity_id = 0U;
+                                       }
+                                       
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_data->progress), fraction);
+                               }
+                       }
+                       if (finished) {
+                               gtk_revealer_set_reveal_child(GTK_REVEALER(progress_data->revealer), FALSE);
+                               gtk_widget_set_name(progress_data->revealer, "_none_");
+                               progress_data->fadeout_id = g_timeout_add(FADER_DURATION, (GSourceFunc) 
remove_progress_widget, progress_data);
+                       }
+               }
+       }
+}
+
+
+static gboolean
+progress_activity(GtkProgressBar *progress)
 {
-       g_free(progress_data->progress_id);
-       g_free(progress_data->message);
-       g_free(progress_data);
+       gtk_progress_bar_pulse(progress);
+       return TRUE;
 }
diff --git a/libbalsa/libbalsa-progress.h b/libbalsa/libbalsa-progress.h
index 5790512..ce33105 100644
--- a/libbalsa/libbalsa-progress.h
+++ b/libbalsa/libbalsa-progress.h
@@ -28,50 +28,60 @@
 #include <gtk/gtk.h>
 
 
-typedef struct _LibbalsaProgressData LibbalsaProgressData;
-
-/** \brief Progress update data
+/** \brief Progress dialogue
  *
- * The data which shall be passed to libbalsa_progress_dialog_update() in order to update a progress 
dialogue.
+ * Structure containing the actual progress dialogue widget and a mutex for protecting concurrent accesses.  
As to initialise a
+ * variable of this type, put it either in static memory, or set the \ref ProgressDialog::dialog to NULL and 
initialise \ref
+ * ProgressDialog::mutex.
  */
-struct _LibbalsaProgressData {
-       GtkWidget *progress_dialog;             /**< Progress dialogue as created by 
libbalsa_progress_dialog_ensure(). */
-       gchar     *progress_id;                 /**< Progress identifier. */
-       gboolean   finished;                    /**< Indicates whether the progress element shall be removed 
from the dialogue.  When no
-                                                                        * progress elements are left, the 
dialogue is destroyed. */
-       gchar     *message;                             /**< Message which shall be printed above the 
progress bar, or NULL to keep the current
-                                                                        * message. */
-       gdouble    fraction;                    /**< Progress bar value, between 0.0 and 1.0, or NAN to keep 
the current value. */
-};
+typedef struct {
+       GtkWidget *dialog;
+       GMutex     mutex;
+} ProgressDialog;
 
 
 /** \brief Ensure that a progress dialogue and progress section exists
  *
- * \param progress_dialog address of an existing progress dialogue, shall be filled with NULL to create a 
new one
+ * \param progress_dialog properly initialised progress dialogue
  * \param dialog_title dialogue title, used only if a new dialogue is created
  * \param parent parent window
  * \param progress_id progress identifier, also used as section title, \em must be unique
  *
- * If the passed progress dialogue address is NULL, a new dialogue is created.
+ * If the passed progress dialogue \ref ProgressDialog::dialog is NULL, a new dialogue is created.
  *
  * If no progress section with the passed id exists, it is appended.  An already existing section is 
revealed if necessary.
+ *
+ * \note This function may be called from a thread.  In this case, the function will block in the thread 
until the "real" work has
+ *       been done in the main thread.
  */
-void libbalsa_progress_dialog_ensure(GtkWidget   **progress_dialog,
-                                                                        const gchar  *dialog_title,
-                                                                        GtkWindow    *parent,
-                                                                        const gchar  *progress_id);
+void libbalsa_progress_dialog_ensure(ProgressDialog *progress_dialog,
+                                                                        const gchar    *dialog_title,
+                                                                        GtkWindow      *parent,
+                                                                        const gchar    *progress_id);
 
 
-/** \brief Progress dialogue update callback
+/** \brief Progress dialogue update
  *
- * \param user_data progress update information, cast'ed to LibbalsaProgressData *
- * \return always FALSE
+ * \param progress_dialog progress dialogue, initialised by libbalsa_progress_dialog_ensure()
+ * \param progress_id progress identifier passed to libbalsa_progress_dialog_ensure()
+ * \param finished indicates whether the progress element shall be removed from the dialogue.  When no 
progress elements are left,
+ *                 the dialogue is destroyed
+ * \param fraction progress bar value between 0.0 and 1.0, or INF to switch to activity mode, or NAN to keep 
the current value
+ * \param message printf-like format string which shall be printed above the progress bar, or NULL to keep 
the current message
+ * \param ... additional arguments for the message format string
  *
- * This function shall be called with a pointer to an update information structure, typically from an idle 
callback.
+ * Update the information of the passed progress dialogue.
  *
- * \note The function will free the passed data.
+ * \note This function may be called from a thread.  In this case, the "real" work is done in an idle 
callback and may therefore
+ *       be performed only after this function returns.
  */
-gboolean libbalsa_progress_dialog_update(gpointer user_data);
+void libbalsa_progress_dialog_update(ProgressDialog *progress_dialog,
+                                                                        const gchar    *progress_id,
+                                                                        gboolean        finished,
+                                                                        gdouble         fraction,
+                                                                        const gchar    *message,
+                                                                        ...)
+       G_GNUC_PRINTF(5, 6);
 
 
 #endif /* LIBBALSA_PROGRESS_H_ */
diff --git a/libbalsa/mailbox.c b/libbalsa/mailbox.c
index df907af..3ce0f9a 100644
--- a/libbalsa/mailbox.c
+++ b/libbalsa/mailbox.c
@@ -194,8 +194,8 @@ libbalsa_mailbox_class_init(LibBalsaMailboxClass * klass)
                      G_STRUCT_OFFSET(LibBalsaMailboxClass,
                                      progress_notify),
                      NULL, NULL,
-                     libbalsa_VOID__INT_INT_INT_STRING, G_TYPE_NONE,
-                     4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
+                     libbalsa_VOID__INT_DOUBLE_STRING, G_TYPE_NONE,
+                     3U, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_STRING);
 
     object_class->dispose = libbalsa_mailbox_dispose;
     object_class->finalize = libbalsa_mailbox_finalize;
@@ -667,16 +667,28 @@ libbalsa_mailbox_set_unread_messages_flag(LibBalsaMailbox * mailbox,
    there has been a progress in current operation.
 */
 void
-libbalsa_mailbox_progress_notify(LibBalsaMailbox * mailbox,
-                                 int type, int prog, int tot, const gchar* msg)
+libbalsa_mailbox_progress_notify(LibBalsaMailbox       *mailbox,
+                                                                LibBalsaMailboxNotify  action,
+                                                                gdouble                        fraction,
+                                                                const gchar           *message,
+                                                                ...)
 {
+       gchar *full_msg;
+
     g_return_if_fail(mailbox != NULL);
     g_return_if_fail(LIBBALSA_IS_MAILBOX(mailbox));
 
-    /* OK to emit in a subthread, because the handler expects it. */
-    g_signal_emit(G_OBJECT(mailbox),
-                  libbalsa_mailbox_signals[PROGRESS_NOTIFY],
-                  0, type, prog, tot, msg);
+    if (message != NULL) {
+       va_list args;
+
+       va_start(args, message);
+       full_msg = g_strdup_vprintf(message, args);
+       va_end(args);
+    } else {
+       full_msg = NULL;
+    }
+    g_signal_emit(G_OBJECT(mailbox), libbalsa_mailbox_signals[PROGRESS_NOTIFY], 0, (gint) action, fraction, 
full_msg);
+       g_free(full_msg);
 }
 
 void
diff --git a/libbalsa/mailbox.h b/libbalsa/mailbox.h
index 58b6ba9..834c41a 100644
--- a/libbalsa/mailbox.h
+++ b/libbalsa/mailbox.h
@@ -90,12 +90,9 @@ typedef enum {
 } LibBalsaMailboxSortType;
 
 typedef enum {
-    LIBBALSA_NTFY_SOURCE,
-    LIBBALSA_NTFY_FINISHED,
-    LIBBALSA_NTFY_MSGINFO,
-    LIBBALSA_NTFY_PROGRESS,
-    LIBBALSA_NTFY_UPDATECONFIG,
-    LIBBALSA_NTFY_ERROR
+       LIBBALSA_NTFY_INIT,
+       LIBBALSA_NTFY_UPDATE,
+       LIBBALSA_NTFY_FINISHED
 } LibBalsaMailboxNotify;
 
 
@@ -272,8 +269,7 @@ struct _LibBalsaMailboxClass {
     /* Signals */
     void (*changed) (LibBalsaMailbox * mailbox);
     void (*message_expunged) (LibBalsaMailbox * mailbox, guint seqno);
-    void (*progress_notify) (LibBalsaMailbox * mailbox, int type,
-                             int prog, int tot, const gchar* msg);
+    void (*progress_notify) (LibBalsaMailbox * mailbox, gint action, gdouble fraction, gchar *message);
 
     /* Virtual Functions */
     gboolean (*open_mailbox) (LibBalsaMailbox * mailbox, GError **err);
@@ -351,9 +347,12 @@ void libbalsa_mailbox_check(LibBalsaMailbox * mailbox);
 void libbalsa_mailbox_changed(LibBalsaMailbox * mailbox);
 void libbalsa_mailbox_set_unread_messages_flag(LibBalsaMailbox * mailbox,
                                               gboolean has_unread);
-void libbalsa_mailbox_progress_notify(LibBalsaMailbox * mailbox,
-                                      int type, int prog, int tot,
-                                      const gchar* msg);
+void libbalsa_mailbox_progress_notify(LibBalsaMailbox       *mailbox,
+                                                                         LibBalsaMailboxNotify  action,
+                                                                         gdouble                        
fraction,
+                                                                         const gchar           *message,
+                                                                         ...)
+       G_GNUC_PRINTF(4, 5);
 
 /** Message access functions.
  */
diff --git a/libbalsa/mailbox_pop3.c b/libbalsa/mailbox_pop3.c
index b3bf0ae..199a7da 100644
--- a/libbalsa/mailbox_pop3.c
+++ b/libbalsa/mailbox_pop3.c
@@ -25,6 +25,7 @@
 
 #include <glib.h>
 #include <string.h>
+#include <math.h>
 
 #include "libbalsa.h"
 #include "libbalsa-conf.h"
@@ -356,7 +357,7 @@ pop_handler_close(pop_handler_t *handler,
 
 
 /* ===================================================================
-   Functions supporting asynchronous retrival of messages.
+   Functions supporting asynchronous retrieval of messages.
 */
 struct fetch_data {
     LibBalsaMailbox *mailbox;
@@ -373,15 +374,14 @@ struct fetch_data {
 static void
 notify_progress(const struct fetch_data *fd)
 {
+    gdouble fraction;
        gchar *recvbuf;
-       gchar *msgbuf;
 
+       fraction = (gdouble) fd->received / (gdouble) fd->total_size;
        recvbuf = libbalsa_size_to_gchar(fd->received);
-       msgbuf = g_strdup_printf(_("Message %lu of %lu (%s of %s)"), (unsigned long) fd->msgno, (unsigned 
long) fd->total_messages,
-               recvbuf, fd->total_size_msg);
+       libbalsa_mailbox_progress_notify(fd->mailbox, LIBBALSA_NTFY_UPDATE, fraction, _("Message %lu of %lu 
(%s of %s)"),
+               (unsigned long) fd->msgno, (unsigned long) fd->total_messages, recvbuf, fd->total_size_msg);
        g_free(recvbuf);
-       libbalsa_mailbox_progress_notify(LIBBALSA_MAILBOX(fd->mailbox), LIBBALSA_NTFY_PROGRESS, fd->received, 
fd->total_size, msgbuf);
-       g_free(msgbuf);
 }
 
 static gboolean
@@ -505,6 +505,7 @@ libbalsa_mailbox_pop3_startup(LibBalsaServer            *server,
        g_signal_connect(G_OBJECT(pop), "auth", G_CALLBACK(libbalsa_server_get_auth), server);
 
        /* connect server */
+       libbalsa_mailbox_progress_notify(LIBBALSA_MAILBOX(mbox), LIBBALSA_NTFY_INIT, INFINITY, _("Connecting 
%s…"), server->host);
        if (!net_client_pop_connect(pop, NULL, &error)) {
                libbalsa_information(LIBBALSA_INFORMATION_ERROR, _("POP3 mailbox %s: cannot connect %s: %s"), 
name, server->host,
                        error->message);
@@ -514,6 +515,7 @@ libbalsa_mailbox_pop3_startup(LibBalsaServer            *server,
        }
 
        /* load message list */
+       libbalsa_mailbox_progress_notify(LIBBALSA_MAILBOX(mbox), LIBBALSA_NTFY_UPDATE, INFINITY, _("List 
messages…"));
        if (!net_client_pop_list(pop, msg_list, !mbox->delete_from_server, &error)) {
                libbalsa_information(LIBBALSA_INFORMATION_ERROR, _("POP3 mailbox %s error: %s"), name, 
error->message);
                g_error_free(error);
@@ -613,7 +615,6 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
 {
        LibBalsaMailboxPop3 *mbox = LIBBALSA_MAILBOX_POP3(mailbox);
        LibBalsaServer *server;
-       gchar *msgbuf;
        NetClientPop *pop;
        GList *msg_list;
 
@@ -623,10 +624,6 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
 
        server = LIBBALSA_MAILBOX_REMOTE_SERVER(mbox);
 
-       msgbuf = g_strdup_printf("POP3: %s", mailbox->name);
-       libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_SOURCE, 0, 0, msgbuf);
-       g_free(msgbuf);
-
        /* open the mailbox connection and get the messages list */
        pop = libbalsa_mailbox_pop3_startup(server, mbox, mailbox->name, &msg_list);
 
@@ -637,7 +634,8 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
                gboolean result = TRUE;
                GError *err = NULL;
 
-               libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_PROGRESS, 0, 1, _("Connected"));
+               libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_UPDATE, INFINITY,
+                       _("Connected to %s"), net_client_get_host(NET_CLIENT(pop)));
                memset(&fd, 0, sizeof(fd));
 
                /* nothing to do if no messages are on the server */
@@ -651,10 +649,9 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
                        fd.mailbox = mailbox;
                        fd.total_size_msg = libbalsa_size_to_gchar(fd.total_size);
 
-                       msgbuf = g_strdup_printf(ngettext("%lu new message (%s)", "%lu new messages (%s)", 
fd.total_messages),
-                                                (unsigned long) fd.total_messages, fd.total_size_msg);
-                       libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_PROGRESS, 0, 1, msgbuf);
-                       g_free(msgbuf);
+                       libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_UPDATE, 0.0,
+                               ngettext("%lu new message (%s)", "%lu new messages (%s)", fd.total_messages),
+                               (unsigned long) fd.total_messages, fd.total_size_msg);
 
                        if (mbox->filter) {
                                fd.filter_path = mbox->filter_cmd;
@@ -663,7 +660,8 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
                        if (result) {
                                result = net_client_pop_retr(pop, msg_list, message_cb, &fd, &err);
                                if (result && mbox->delete_from_server) {
-                                       libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_PROGRESS, 1, 
1, _("Deleting messages on server…"));
+                                       libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_UPDATE, 
INFINITY,
+                                               _("Deleting messages on server…"));
                                        result = net_client_pop_dele(pop, msg_list, &err);
                                }
                        }
@@ -692,8 +690,8 @@ libbalsa_mailbox_pop3_check(LibBalsaMailbox * mailbox)
                }
 
                /* done - clean up */
-               libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_PROGRESS, 0, 1, _("Finished"));
                g_object_unref(G_OBJECT(pop));
+               libbalsa_mailbox_progress_notify(mailbox, LIBBALSA_NTFY_FINISHED, 1.0, _("Finished"));
        }
 }
 
diff --git a/libbalsa/send.c b/libbalsa/send.c
index 892cd16..75eca44 100644
--- a/libbalsa/send.c
+++ b/libbalsa/send.c
@@ -94,7 +94,7 @@ static guint send_mail_time = 0U;
 static guint send_mail_timer_id = 0U;
 static gint retrigger_send = 0;                /* # of messages added to outbox while the smtp server was 
locked, access via g_atomic_* */
 
-static GtkWidget *send_progress_dialog;
+static ProgressDialog send_progress_dialog;
 
 
 /* end of state variables section */
@@ -538,6 +538,7 @@ libbalsa_message_send(LibBalsaMessage     *message,
                       LibBalsaMailbox     *fccbox,
                       LibBalsaFccboxFinder finder,
                       LibBalsaSmtpServer  *smtp_server,
+                                         gboolean                         show_progress,
                       GtkWindow           *parent,
                       gboolean             flow,
                       GError             **error)
@@ -555,7 +556,7 @@ libbalsa_message_send(LibBalsaMessage     *message,
 
         if (result == LIBBALSA_MESSAGE_CREATE_OK) {
                if (libbalsa_smtp_server_trylock(smtp_server)) {
-                       lbs_process_queue(outbox, finder, smtp_server, parent);
+                       lbs_process_queue(outbox, finder, smtp_server, show_progress ? parent : NULL);
                } else {
                        g_atomic_int_inc(&retrigger_send);
                }
@@ -620,21 +621,15 @@ send_message_data_cb(gchar   *buffer,
         gint ipercent;
 
        smi->total_sent += read_res;
-       fraction = (gfloat) smi->total_sent / (gfloat) smi->total_size;
+       fraction = (gdouble) smi->total_sent / (gdouble) smi->total_size;
        g_debug("%s: s=%lu t=%lu %g", __func__, (unsigned long) smi->total_sent, (unsigned long) 
smi->total_size, fraction);
        if (fraction > 1.0) {
             fraction = 1.0;
         }
        ipercent = (gint) (100.0 * (fraction + 0.5));
-       if (ipercent > smi->last_report) {
-               LibbalsaProgressData *progress;
-
-               progress = g_new0(LibbalsaProgressData, 1U);
-               progress->progress_id = g_strdup(smi->progress_id);
-               progress->progress_dialog = send_progress_dialog;
-               progress->message = g_strdup_printf(_("Message %u of %u"), smi->curr_msg, smi->msg_count);
-               progress->fraction = fraction;
-               g_idle_add(libbalsa_progress_dialog_update, progress);
+       if (!smi->no_dialog && (ipercent > smi->last_report)) {
+               libbalsa_progress_dialog_update(&send_progress_dialog, smi->progress_id, FALSE, fraction,
+                       _("Message %u of %u"), smi->curr_msg, smi->msg_count);
                smi->last_report = ipercent;
         }
     }
@@ -675,7 +670,8 @@ lbs_check_reachable_cb(GObject  *object,
 }
 
 
-/* note: the following function is called with the passed smtp server being locked */
+/* note: the following function is called with the passed smtp server being locked
+ * parent != NULL indicates that the progress dialogue shall be shown */
 static void
 lbs_process_queue(LibBalsaMailbox      *outbox,
                          LibBalsaFccboxFinder  finder,
@@ -849,6 +845,7 @@ lbs_process_queue_real(LibBalsaSmtpServer *smtp_server, SendQueueInfo *send_info
                        if (send_info->parent != NULL) {
                                libbalsa_progress_dialog_ensure(&send_progress_dialog, _("Sending Mail"), 
send_info->parent,
                                        send_message_info->progress_id);
+                               send_message_info->no_dialog = FALSE;
                        } else {
                                send_message_info->no_dialog = TRUE;
                        }
@@ -876,6 +873,7 @@ void
 libbalsa_process_queue(LibBalsaMailbox     *outbox,
                        LibBalsaFccboxFinder finder,
                        GSList              *smtp_servers,
+                                          gboolean                             show_progress,
                        GtkWindow           *parent)
 {
        if (libbalsa_mailbox_open(outbox, NULL)) {
@@ -896,7 +894,7 @@ libbalsa_process_queue(LibBalsaMailbox     *outbox,
                                LibBalsaSmtpServer *smtp_server = LIBBALSA_SMTP_SERVER(smtp_servers->data);
 
                                if (libbalsa_smtp_server_trylock(smtp_server)) {
-                                       lbs_process_queue(outbox, finder, smtp_server, parent);
+                                       lbs_process_queue(outbox, finder, smtp_server, show_progress ? parent 
: NULL);
                                }
                        }
                } else {
@@ -947,14 +945,11 @@ balsa_send_message_success(MessageQueueItem *mqi,
                if (fccurl != NULL) {
                        LibBalsaMailbox *fccbox = info->finder(fccurl);
                        GError *err = NULL;
-                       LibbalsaProgressData *progress;
 
-                       progress = g_new0(LibbalsaProgressData, 1U);
-                       progress->progress_id = g_strdup(info->progress_id);
-                       progress->progress_dialog = send_progress_dialog;
-                       progress->message = g_strdup_printf(_("Save message in %s…"), fccbox->name);
-                       progress->fraction = NAN;
-                       g_idle_add(libbalsa_progress_dialog_update, progress);
+                       if (!info->no_dialog) {
+                               libbalsa_progress_dialog_update(&send_progress_dialog, info->progress_id, 
FALSE, NAN,
+                                       _("Save message in %s…"), fccbox->name);
+                       }
 
                        libbalsa_message_change_flags(mqi->orig, 0, LIBBALSA_MESSAGE_FLAG_NEW | 
LIBBALSA_MESSAGE_FLAG_FLAGGED);
                        libbalsa_mailbox_sync_storage(mqi->orig->mailbox, FALSE);
@@ -1005,23 +1000,19 @@ balsa_send_message_real(SendMessageInfo *info)
     g_debug("%s: starting", __func__);
 
     /* connect the SMTP server */
+    if (!info->no_dialog) {
+               libbalsa_progress_dialog_update(&send_progress_dialog, info->progress_id, FALSE, INFINITY,
+                       _("Connecting %s…"), net_client_get_host(NET_CLIENT(info->session)));
+    }
     result = net_client_smtp_connect(info->session, &greeting, &error);
     g_debug("%s: connect = %d [%p]: '%s'", __func__, result, info->items, greeting);
     g_free(greeting);
     if (result) {
         GList *this_msg;
 
-        if (info->no_dialog) {
-               libbalsa_information(LIBBALSA_INFORMATION_MESSAGE, _("Sending queued messages to %s"),
-                       libbalsa_smtp_server_get_name(info->smtp_server));
-        } else {
-               LibbalsaProgressData *progress;
-
-               progress = g_new0(LibbalsaProgressData, 1U);
-               progress->progress_id = g_strdup(info->progress_id);
-               progress->progress_dialog = send_progress_dialog;
-               progress->message = g_strdup_printf(_("Connected to %s"), 
net_client_get_host(NET_CLIENT(info->session)));
-               g_idle_add(libbalsa_progress_dialog_update, progress);
+        if (!info->no_dialog) {
+               libbalsa_progress_dialog_update(&send_progress_dialog, info->progress_id, FALSE, 0.0,
+                       _("Connected to %s"), net_client_get_host(NET_CLIENT(info->session)));
         }
 
         for (this_msg = info->items; this_msg != NULL; this_msg = this_msg->next) {
@@ -1084,17 +1075,13 @@ balsa_send_message_real(SendMessageInfo *info)
     /* close outbox in an idle callback, as it might affect the display */
     g_idle_add((GSourceFunc) balsa_send_message_real_idle_cb, g_object_ref(info->outbox));
 
+    /* finalise the SMTP session (which may be slow) */
+    g_object_unref(G_OBJECT(info->session));
+    info->session = NULL;
+
     /* clean up */
     if (!info->no_dialog) {
-       LibbalsaProgressData *progress;
-
-       progress = g_new0(LibbalsaProgressData, 1U);
-       progress->progress_id = g_strdup(info->progress_id);
-       progress->progress_dialog = send_progress_dialog;
-       progress->message = g_strdup_printf(_("Finished"));
-       progress->fraction = 1.0;
-       progress->finished = TRUE;
-       g_idle_add(libbalsa_progress_dialog_update, progress);
+               libbalsa_progress_dialog_update(&send_progress_dialog, info->progress_id, TRUE, 1.0, 
_("Finished"));
     } else if (result) {
        libbalsa_information(LIBBALSA_INFORMATION_MESSAGE,
                ngettext("Transmitted %u message to %s", "Transmitted %u messages to %s", info->msg_count),
diff --git a/libbalsa/send.h b/libbalsa/send.h
index 48a38b8..93381e9 100644
--- a/libbalsa/send.h
+++ b/libbalsa/send.h
@@ -57,19 +57,20 @@ LibBalsaMsgCreateResult libbalsa_message_queue(LibBalsaMessage* message,
                                                smtp_server,
                                               gboolean flow,
                                               GError ** error);
-LibBalsaMsgCreateResult libbalsa_message_send(LibBalsaMessage * message,
-                                              LibBalsaMailbox * outbox,
-                                              LibBalsaMailbox * fccbox,
+LibBalsaMsgCreateResult libbalsa_message_send(LibBalsaMessage     *message,
+                                              LibBalsaMailbox     *outbox,
+                                              LibBalsaMailbox     *fccbox,
                                               LibBalsaFccboxFinder finder,
-                                              LibBalsaSmtpServer *
-                                              smtp_server,
-                                              GtkWindow * parent,
-                                              gboolean flow,
-                                             GError ** error);
-void libbalsa_process_queue(LibBalsaMailbox * outbox,
+                                              LibBalsaSmtpServer  *smtp_server,
+                                                                                         gboolean            
             show_progress,
+                                              GtkWindow           *parent,
+                                              gboolean             flow,
+                                                                 GError             **error);
+void libbalsa_process_queue(LibBalsaMailbox     *outbox,
                             LibBalsaFccboxFinder finder,
-                                                       GSList * smtp_servers,
-                                                       GtkWindow * parent);
+                                                       GSList              *smtp_servers,
+                                                       gboolean                         show_progress,
+                                                       GtkWindow           *parent);
 
 void libbalsa_auto_send_init(GSourceFunc auto_send_cb);
 void libbalsa_auto_send_config(gboolean enable,
diff --git a/src/balsa-app.c b/src/balsa-app.c
index 9f9782a..8e9f9c8 100644
--- a/src/balsa-app.c
+++ b/src/balsa-app.c
@@ -253,7 +253,7 @@ static gboolean
 send_queued_messages_auto_cb(gpointer data)
 {
        g_debug("%s: %p", __func__, data);
-       libbalsa_process_queue(balsa_app.outbox, balsa_find_sentbox_by_url, balsa_app.smtp_servers, NULL);
+       libbalsa_process_queue(balsa_app.outbox, balsa_find_sentbox_by_url, balsa_app.smtp_servers, FALSE, 
NULL);
     return (data == NULL);
 }
 
@@ -299,7 +299,8 @@ balsa_app_init(void)
     balsa_app.sw_maximized = FALSE;
 
     balsa_app.toolbar_wrap_button_text = TRUE;
-    balsa_app.pwindow_option = WHILERETR;
+    balsa_app.send_progress_dialog = TRUE;
+    balsa_app.recv_progress_dialog = TRUE;
     balsa_app.wordwrap = FALSE; /* default to format=flowed. */
     balsa_app.wraplength = 72;
     balsa_app.browse_wrap = FALSE; /* GtkTextView will wrap for us. */
@@ -441,7 +442,7 @@ balsa_app_destroy(void)
 static gboolean
 check_new_messages_auto_cb(gpointer data)
 {
-    check_new_messages_real(balsa_app.main_window, TYPE_BACKGROUND);
+    check_new_messages_real(balsa_app.main_window, TRUE);
 
     if (balsa_app.debug)
         fprintf(stderr, "Auto-checked for new messages…\n");
diff --git a/src/balsa-app.h b/src/balsa-app.h
index d63e26c..27a401d 100644
--- a/src/balsa-app.h
+++ b/src/balsa-app.h
@@ -237,7 +237,8 @@ extern struct BalsaApplication {
     /* text color of URL's */
     GdkRGBA url_color;
 
-    guint pwindow_option;
+    gboolean send_progress_dialog;
+    gboolean recv_progress_dialog;
     gboolean wordwrap;
     gint wraplength;
     gboolean browse_wrap;
diff --git a/src/balsa-message.c b/src/balsa-message.c
index d557ff3..1c13276 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -2478,6 +2478,7 @@ handle_mdn_request(GtkWindow *parent, LibBalsaMessage *message)
         result = libbalsa_message_send(mdn, balsa_app.outbox, NULL,
                                       balsa_find_sentbox_by_url,
                                       mdn_ident->smtp_server,
+                                          balsa_app.send_progress_dialog,
                                        parent,
                                       TRUE, &error);
        if (result != LIBBALSA_MESSAGE_CREATE_OK)
@@ -2618,6 +2619,7 @@ mdn_dialog_response(GtkWidget * dialog, gint response, gpointer user_data)
             libbalsa_message_send(send_msg, balsa_app.outbox, NULL,
                                   balsa_find_sentbox_by_url,
                                   mdn_ident->smtp_server,
+                                                                 balsa_app.send_progress_dialog,
                                   gtk_window_get_transient_for
                                   ((GtkWindow *) dialog),
                                   TRUE, &error);
diff --git a/src/balsa-mime-widget-message.c b/src/balsa-mime-widget-message.c
index 9a023d8..7f581f8 100644
--- a/src/balsa-mime-widget-message.c
+++ b/src/balsa-mime-widget-message.c
@@ -378,6 +378,7 @@ extbody_send_mail(GtkWidget * button, LibBalsaMessageBody * mime_body)
     result = libbalsa_message_send(message, balsa_app.outbox, NULL,
                                   balsa_find_sentbox_by_url,
                                   balsa_app.current_ident->smtp_server,
+                                  balsa_app.send_progress_dialog,
                                    GTK_WINDOW(gtk_widget_get_toplevel
                                               (button)),
                                   FALSE, &err);
diff --git a/src/balsa-mime-widget-vcalendar.c b/src/balsa-mime-widget-vcalendar.c
index 4438fe0..34e70cb 100644
--- a/src/balsa-mime-widget-vcalendar.c
+++ b/src/balsa-mime-widget-vcalendar.c
@@ -325,6 +325,7 @@ vevent_reply(GObject * button, GtkWidget * box)
     result = libbalsa_message_send(message, balsa_app.outbox, NULL,
                                   balsa_find_sentbox_by_url,
                                   ident->smtp_server,
+                                  balsa_app.send_progress_dialog,
                                    GTK_WINDOW(gtk_widget_get_toplevel
                                               ((GtkWidget *) button)),
                                   FALSE, &error);
diff --git a/src/main-window.c b/src/main-window.c
index a935b75..5d1f461 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -31,6 +31,7 @@
 #include "main-window.h"
 
 #include <string.h>
+#include <math.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
@@ -65,7 +66,7 @@
 #include "save-restore.h"
 #include "toolbar-prefs.h"
 #include "toolbar-factory.h"
-#include "threads.h"
+#include "libbalsa-progress.h"
 
 #include "filter.h"
 #include "filter-funcs.h"
@@ -91,14 +92,12 @@ static GtkTargetEntry notebook_drop_types[NUM_DROP_TYPES] = {
 };
 
 /* Define thread-related globals, including dialogs */
-GtkWidget *progress_dialog = NULL;
-GtkWidget *progress_dialog_source = NULL;
-GtkWidget *progress_dialog_message = NULL;
-GtkWidget *progress_dialog_bar = NULL;
-static int quiet_check=0;
+static ProgressDialog progress_dialog;
 
 struct check_messages_thread_info {
     BalsaWindow *window;
+    gboolean with_progress_dialog;
+    gboolean with_activity_bar;
     GSList *list;
 };
 static void bw_check_messages_thread(struct check_messages_thread_info
@@ -123,7 +122,7 @@ static void bw_idle_remove(BalsaWindow * window);
 static gboolean bw_idle_cb(BalsaWindow * window);
 
 
-static void bw_check_mailbox_list(BalsaWindow * window, GList * list);
+static void bw_check_mailbox_list(struct check_messages_thread_info *info, GList * list);
 static gboolean bw_add_mbox_to_checklist(GtkTreeModel * model,
                                          GtkTreePath * path,
                                          GtkTreeIter * iter,
@@ -192,6 +191,9 @@ G_DEFINE_TYPE (BalsaWindow, balsa_window, GTK_TYPE_APPLICATION_WINDOW)
 
 static guint window_signals[LAST_SIGNAL] = { 0 };
 
+/* note: access with g_atomic_* functions, not checking mail when 1 */
+static gint checking_mail = 1;
+
 static void
 balsa_window_class_init(BalsaWindowClass * klass)
 {
@@ -1040,7 +1042,7 @@ get_new_mail_activated(GSimpleAction * action,
 {
     BalsaWindow *window = BALSA_WINDOW(user_data);
 
-    check_new_messages_real(window, TYPE_CALLBACK);
+    check_new_messages_real(window, FALSE);
 
     if (balsa_app.check_mail_auto) {
         /* restart the timer */
@@ -1055,6 +1057,7 @@ send_queued_mail_activated(GSimpleAction * action,
 {
     libbalsa_process_queue(balsa_app.outbox, balsa_find_sentbox_by_url,
                            balsa_app.smtp_servers,
+                                                  balsa_app.send_progress_dialog,
                            (GtkWindow *) balsa_app.main_window);
 }
 
@@ -2360,7 +2363,7 @@ balsa_window_new()
                      G_CALLBACK(bw_is_active_notify), NULL);
 
     /* set initial state of Get-New-Mail button */
-    bw_action_set_enabled(window, "get-new-mail", !checking_mail);
+    bw_action_set_enabled(window, "get-new-mail", g_atomic_int_get(&checking_mail) == 1);
 
     g_timeout_add_seconds(30, (GSourceFunc) bw_close_mailbox_on_timer, window);
 
@@ -3183,20 +3186,75 @@ bw_is_open_mailbox(LibBalsaMailbox *m)
  *
  */
 static void
-bw_check_mailbox_list(BalsaWindow * window, GList * mailbox_list)
+bw_check_mailbox_progress_cb(LibBalsaMailbox* mailbox, gint action, gdouble fraction, const gchar *message)
+{
+       gchar *progress_id;
+
+       progress_id = g_strdup_printf("POP3: %s", mailbox->name);
+       if (action == LIBBALSA_NTFY_INIT) {
+               libbalsa_progress_dialog_ensure(&progress_dialog, _("Checking Mail…"), 
GTK_WINDOW(balsa_app.main_window), progress_id);
+       }
+       libbalsa_progress_dialog_update(&progress_dialog, progress_id, action == LIBBALSA_NTFY_FINISHED, 
fraction, "%s", message);
+       g_free(progress_id);
+}
+
+static void
+bw_check_mailbox(LibBalsaMailbox *mailbox)
+{
+       libbalsa_mailbox_check(mailbox);
+       g_thread_exit(NULL);
+}
+
+typedef struct {
+       GObject *object;
+       GThread *thread;
+       gulong notify;
+} bw_pop_mbox_t;
+
+static void
+bw_check_mailbox_done(bw_pop_mbox_t *bw_pop_mbox)
 {
-    if (window && !window->network_available) {
+       if (bw_pop_mbox->thread != NULL) {
+               g_thread_join(bw_pop_mbox->thread);
+               g_debug("joined thread %p", bw_pop_mbox->thread);
+       }
+       if (bw_pop_mbox->notify > 0U) {
+               g_signal_handler_disconnect(bw_pop_mbox->object, bw_pop_mbox->notify);
+       }
+       g_object_unref(bw_pop_mbox->object);
+}
+
+static void
+bw_check_mailbox_list(struct check_messages_thread_info *info, GList *mailbox_list)
+{
+       GList *check_mbx = NULL;
+
+    if ((info->window != NULL) && !info->window->network_available) {
         return;
     }
 
     for ( ; mailbox_list; mailbox_list = mailbox_list->next) {
-        LibBalsaMailbox *mailbox =
-            BALSA_MAILBOX_NODE(mailbox_list->data)->mailbox;
+        LibBalsaMailbox *mailbox = BALSA_MAILBOX_NODE(mailbox_list->data)->mailbox;
+        LibBalsaMailboxPop3 *pop3 = LIBBALSA_MAILBOX_POP3(mailbox);
+        bw_pop_mbox_t *bw_pop_mbox;
+
+        bw_pop_mbox = g_malloc0(sizeof(bw_pop_mbox_t));
+        bw_pop_mbox->object = g_object_ref(mailbox);
         libbalsa_mailbox_pop3_set_inbox(mailbox, balsa_app.inbox);
-        libbalsa_mailbox_pop3_set_msg_size_limit
-            (LIBBALSA_MAILBOX_POP3(mailbox), balsa_app.msg_size_limit*1024);
-        libbalsa_mailbox_check(mailbox);
+        libbalsa_mailbox_pop3_set_msg_size_limit(pop3, balsa_app.msg_size_limit * 1024);
+        if (info->with_progress_dialog) {
+               bw_pop_mbox->notify =
+                       g_signal_connect(G_OBJECT(mailbox), "progress-notify", 
G_CALLBACK(bw_check_mailbox_progress_cb), mailbox);
+        }
+        bw_pop_mbox->thread = g_thread_new(NULL, (GThreadFunc) bw_check_mailbox, mailbox);
+        g_debug("launched thread %p for checking POP3 mailbox %s", bw_pop_mbox->thread, mailbox->name);
+        check_mbx = g_list_prepend(check_mbx, bw_pop_mbox);
     }
+
+    /* join all threads, i.e. proceed only after all threads have finished, and disconnect progress notify 
handlers */
+    g_list_foreach(check_mbx, (GFunc) bw_check_mailbox_done, NULL);
+    g_debug("all POP3 mailbox threads done");
+    g_list_free_full(check_mbx, (GDestroyNotify) g_free);
 }
 
 /*Callback to check a mailbox in a balsa-mblist */
@@ -3233,69 +3291,6 @@ bw_imap_check_test(const gchar * path)
         strcmp(path, "INBOX") == 0 : balsa_app.check_imap;
 }
 
-static void
-bw_mailbox_check(LibBalsaMailbox * mailbox, BalsaWindow * window);
-
-static void
-bw_progress_dialog_destroy_cb(GtkWidget * widget, gpointer data)
-{
-    progress_dialog = NULL;
-    progress_dialog_source = NULL;
-    progress_dialog_message = NULL;
-    progress_dialog_bar = NULL;
-}
-static void
-bw_progress_dialog_response_cb(GtkWidget* dialog, gint response)
-{
-    if(response == GTK_RESPONSE_CLOSE)
-        /* this should never be done in response handler, but... */
-        gtk_widget_destroy(dialog);
-}
-
-/* ensure_check_mail_dialog:
-   make sure that mail checking dialog exists.
-*/
-static void
-ensure_check_mail_dialog(BalsaWindow * window)
-{
-    GtkBox *content_box;
-
-    if (progress_dialog && GTK_IS_WIDGET(progress_dialog))
-       gtk_widget_destroy(GTK_WIDGET(progress_dialog));
-
-    progress_dialog =
-       gtk_dialog_new_with_buttons(_("Checking Mail…"),
-                                    GTK_WINDOW(window),
-                                    GTK_DIALOG_DESTROY_WITH_PARENT |
-                                    libbalsa_dialog_flags(),
-                                    _("_Hide"), GTK_RESPONSE_CLOSE,
-                                    NULL);
-#if HAVE_MACOSX_DESKTOP
-    libbalsa_macosx_menu_for_parent(progress_dialog, GTK_WINDOW(window));
-#endif
-    gtk_window_set_role(GTK_WINDOW(progress_dialog), "progress_dialog");
-
-    g_signal_connect(G_OBJECT(progress_dialog), "destroy",
-                    G_CALLBACK(bw_progress_dialog_destroy_cb), NULL);
-    g_signal_connect(G_OBJECT(progress_dialog), "response",
-                    G_CALLBACK(bw_progress_dialog_response_cb), NULL);
-
-    content_box =
-        GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(progress_dialog)));
-    progress_dialog_source = gtk_label_new(_("Checking Mail…"));
-    gtk_box_pack_start(content_box, progress_dialog_source,
-                       FALSE, FALSE, 0);
-
-    progress_dialog_message = gtk_label_new("");
-    gtk_box_pack_start(content_box, progress_dialog_message,
-                       FALSE, FALSE, 0);
-
-    progress_dialog_bar = gtk_progress_bar_new();
-    gtk_box_pack_start(content_box, progress_dialog_bar,
-                       FALSE, FALSE, 0);
-    gtk_window_set_default_size(GTK_WINDOW(progress_dialog), 250, 100);
-    gtk_widget_show_all(progress_dialog);
-}
 
 /*
  * Callbacks
@@ -3306,7 +3301,7 @@ ensure_check_mail_dialog(BalsaWindow * window)
    or NULL.
 */
 void
-check_new_messages_real(BalsaWindow * window, int type)
+check_new_messages_real(BalsaWindow * window, gboolean background_check)
 {
     GSList *list;
     struct check_messages_thread_info *info;
@@ -3317,36 +3312,34 @@ check_new_messages_real(BalsaWindow * window, int type)
 
     list = NULL;
     /*  Only Run once -- If already checking mail, return.  */
-    g_mutex_lock(&checking_mail_lock);
-    if (checking_mail) {
-        g_mutex_unlock(&checking_mail_lock);
-        fprintf(stderr, "Already Checking Mail!\n");
-       if (progress_dialog)
-           gtk_window_present(GTK_WINDOW(progress_dialog));
+    if (!g_atomic_int_dec_and_test(&checking_mail)) {
+       g_atomic_int_inc(&checking_mail);
+        g_debug("Already Checking Mail!");
+        g_mutex_lock(&progress_dialog.mutex);
+        if (progress_dialog.dialog != NULL) {
+               gtk_window_present(GTK_WINDOW(progress_dialog.dialog));
+        }
+        g_mutex_unlock(&progress_dialog.mutex);
         return;
     }
-    checking_mail = TRUE;
+
     if (window)
         bw_action_set_enabled(window, "get-new-mail", FALSE);
 
-    quiet_check = (type == TYPE_CALLBACK)
-        ? 0 : balsa_app.quiet_background_check;
-
-    g_mutex_unlock(&checking_mail_lock);
-
-    if (type == TYPE_CALLBACK &&
-        (balsa_app.pwindow_option == WHILERETR ||
-         (balsa_app.pwindow_option == UNTILCLOSED && progress_dialog)))
-       ensure_check_mail_dialog(window);
-
     gtk_tree_model_foreach(GTK_TREE_MODEL(balsa_app.mblist_tree_store),
                           (GtkTreeModelForeachFunc) bw_add_mbox_to_checklist,
                           &list);
 
-    /* initiate threads */
+    /* initiate thread */
     info = g_new(struct check_messages_thread_info, 1);
     info->list = list;
+    info->with_progress_dialog = !background_check && balsa_app.recv_progress_dialog;
     info->window = window ? g_object_ref(window) : window;
+    info->with_activity_bar = background_check && !balsa_app.quiet_background_check && (info->window != 
NULL);
+       if (info->with_activity_bar) {
+               balsa_window_increase_activity(info->window, _("Checking Mail…"));
+       }
+
     get_mail_thread =
        g_thread_new("bw_check_messages_thread",
                                 (GThreadFunc) bw_check_messages_thread,
@@ -3362,7 +3355,7 @@ check_new_messages_real(BalsaWindow * window, int type)
 static void
 bw_check_new_messages(gpointer data)
 {
-    check_new_messages_real(data, TYPE_CALLBACK);
+    check_new_messages_real(data, FALSE);
 
     if (balsa_app.check_mail_auto) {
         /* restart the timer */
@@ -3409,31 +3402,30 @@ check_new_messages_count(LibBalsaMailbox * mailbox, gboolean notify)
 
 /* this one is called only in the threaded code */
 static void
-bw_mailbox_check(LibBalsaMailbox * mailbox, BalsaWindow * window)
+bw_mailbox_check(LibBalsaMailbox * mailbox, struct check_messages_thread_info *info)
 {
-    MailThreadMessage *threadmessage;
-    gchar *string = NULL;
-
     if (libbalsa_mailbox_get_subscribe(mailbox) == LB_MAILBOX_SUBSCRIBE_NO)
         return;
 
+    g_debug("checking mailbox %s", mailbox->name);
     if (LIBBALSA_IS_MAILBOX_IMAP(mailbox)) {
-        if (window && !window->network_available) {
-                return;
-        }
-
-       string = g_strdup_printf(_("IMAP mailbox: %s"), mailbox->url);
-        if (balsa_app.debug)
-            fprintf(stderr, "%s\n", string);
+       if ((info->window != NULL) && !info->window->network_available) {
+               return;
+       }
+
+       if (info->with_progress_dialog) {
+               libbalsa_progress_dialog_update(&progress_dialog, _("Mailboxes"), FALSE, INFINITY,
+                       _("IMAP mailbox: %s"), mailbox->url);
+       }
     } else if (LIBBALSA_IS_MAILBOX_LOCAL(mailbox)) {
-       string = g_strdup_printf(_("Local mailbox: %s"), mailbox->name);
+       if (info->with_progress_dialog) {
+               libbalsa_progress_dialog_update(&progress_dialog, _("Mailboxes"), FALSE, INFINITY,
+                       _("Local mailbox: %s"), mailbox->name);
+       }
     } else {
-        g_assert_not_reached();
+       g_assert_not_reached();
     }
 
-    MSGMAILTHREAD(threadmessage, LIBBALSA_NTFY_SOURCE, NULL, string, 0, 0);
-    g_free(string);
-
     libbalsa_mailbox_check(mailbox);
 }
 
@@ -3454,21 +3446,27 @@ bw_check_messages_thread(struct check_messages_thread_info *info)
      *  and that the calling procedure will check for an existing lock
      *  and set checking_mail to true before calling.
      */
-    MailThreadMessage *threadmessage;
-    GSList *list = info->list;
-
-    MSGMAILTHREAD(threadmessage, LIBBALSA_NTFY_SOURCE, NULL, "POP3", 0, 0);
-    bw_check_mailbox_list(info->window, balsa_app.inbox_input);
-
-    g_slist_foreach(list, (GFunc) bw_mailbox_check, info->window);
-    g_slist_foreach(list, (GFunc) g_object_unref, NULL);
-    g_slist_free(list);
+    bw_check_mailbox_list(info, balsa_app.inbox_input);
+
+    if (info->list!= NULL) {
+        GSList *list = info->list;
+
+       if (info->with_progress_dialog) {
+               libbalsa_progress_dialog_ensure(&progress_dialog, _("Checking Mail…"), 
GTK_WINDOW(info->window), _("Mailboxes"));
+       }
+       g_slist_foreach(list, (GFunc) bw_mailbox_check, info);
+       g_slist_foreach(list, (GFunc) g_object_unref, NULL);
+       g_slist_free(list);
+       if (info->with_progress_dialog) {
+               libbalsa_progress_dialog_update(&progress_dialog, _("Mailboxes"), TRUE, 1.0, NULL);
+       }
+    }
 
-    MSGMAILTHREAD(threadmessage, LIBBALSA_NTFY_FINISHED, NULL, "Finished",
-                  0, 0);
+       if (info->with_activity_bar) {
+               balsa_window_decrease_activity(info->window, _("Checking Mail…"));
+       }
 
-    g_mutex_lock(&checking_mail_lock);
-    checking_mail = FALSE;
+    g_atomic_int_inc(&checking_mail);
 
     if (info->window) {
         g_idle_add((GSourceFunc) bw_check_messages_thread_idle_cb,
@@ -3477,151 +3475,11 @@ bw_check_messages_thread(struct check_messages_thread_info *info)
             time(&info->window->last_check_time);
         g_object_unref(info->window);
     }
-    g_mutex_unlock(&checking_mail_lock);
 
     g_free(info);
     g_thread_exit(0);
 }
 
-/* mail_progress_notify_cb:
-   called from the thread checking the new mail. Basically does the GUI
-   interaction because checking thread cannot do it.
-*/
-gboolean
-mail_progress_notify_cb(GIOChannel * source, GIOCondition condition,
-                        BalsaWindow ** window)
-{
-    const int MSG_BUFFER_SIZE = 512 * sizeof(MailThreadMessage *);
-    MailThreadMessage *threadmessage;
-    MailThreadMessage **currentpos;
-    void *msgbuffer;
-    ssize_t count;
-    gfloat fraction;
-    GtkStatusbar *statusbar;
-    guint context_id;
-
-    msgbuffer = g_malloc(MSG_BUFFER_SIZE);
-    count = read(mail_thread_pipes[0], msgbuffer, MSG_BUFFER_SIZE);
-
-    /* FIXME: imagine reading just half of the pointer. The sync is gone.. */
-    if (count % sizeof(MailThreadMessage *)) {
-        g_free(msgbuffer);
-        return TRUE;
-    }
-
-    currentpos = (MailThreadMessage **) msgbuffer;
-
-    if (quiet_check || !*window) {
-        /* Eat messages */
-        while (count) {
-            threadmessage = *currentpos;
-            g_free(threadmessage);
-            currentpos++;
-            count -= sizeof(void *);
-        }
-        g_free(msgbuffer);
-        return TRUE;
-    }
-
-    statusbar = GTK_STATUSBAR((*window)->statusbar);
-    context_id = gtk_statusbar_get_context_id(statusbar, "BalsaWindow mail progress");
-
-    while (count) {
-        threadmessage = *currentpos;
-
-        if (balsa_app.debug)
-            fprintf(stderr, "Message: %lu, %d, %s\n",
-                    (unsigned long) threadmessage,
-                    threadmessage->message_type,
-                    threadmessage->message_string);
-
-        if (!progress_dialog)
-            gtk_statusbar_pop(statusbar, context_id);
-
-        switch (threadmessage->message_type) {
-        case LIBBALSA_NTFY_SOURCE:
-            if (progress_dialog) {
-                gtk_label_set_text(GTK_LABEL(progress_dialog_source),
-                                   threadmessage->message_string);
-                gtk_label_set_text(GTK_LABEL(progress_dialog_message), "");
-                gtk_widget_show_all(progress_dialog);
-            } else
-                gtk_statusbar_push(statusbar, context_id,
-                                   threadmessage->message_string);
-            break;
-        case LIBBALSA_NTFY_MSGINFO:
-            if (progress_dialog) {
-                gtk_label_set_text(GTK_LABEL(progress_dialog_message),
-                                   threadmessage->message_string);
-                gtk_widget_show_all(progress_dialog);
-            } else
-                gtk_statusbar_push(statusbar, context_id,
-                                   threadmessage->message_string);
-            break;
-        case LIBBALSA_NTFY_UPDATECONFIG:
-            config_mailbox_update(threadmessage->mailbox);
-            break;
-
-        case LIBBALSA_NTFY_PROGRESS:
-            fraction = (gfloat) threadmessage->num_bytes /
-                (gfloat) threadmessage->tot_bytes;
-            if (fraction > 1.0 || fraction < 0.0) {
-                if (balsa_app.debug)
-                    fprintf(stderr,
-                            "progress bar fraction out of range %f\n",
-                            fraction);
-                fraction = 1.0;
-            }
-            if (progress_dialog) {
-                gtk_label_set_text(GTK_LABEL(progress_dialog_message),
-                                   threadmessage->message_string);
-                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR
-                                              (progress_dialog_bar),
-                                             fraction);
-            } else {
-                gtk_statusbar_push(statusbar, context_id,
-                                   threadmessage->message_string);
-                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR
-                                              ((*window)->progress_bar),
-                                              fraction);
-            }
-            break;
-        case LIBBALSA_NTFY_FINISHED:
-
-            if (balsa_app.pwindow_option == WHILERETR && progress_dialog) {
-                gtk_widget_destroy(progress_dialog);
-            } else if (progress_dialog) {
-                gtk_label_set_text(GTK_LABEL(progress_dialog_source),
-                                   _("Finished Checking."));
-                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR
-                                              (progress_dialog_bar), 0.0);
-            } else {
-                gtk_statusbar_pop(statusbar, context_id);
-                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR
-                                              ((*window)->progress_bar), 0.0);
-            }
-            break;
-
-        case LIBBALSA_NTFY_ERROR:
-            balsa_information(LIBBALSA_INFORMATION_ERROR,
-                              "%s",
-                              threadmessage->message_string);
-            break;
-
-        default:
-            fprintf(stderr, " Unknown check mail message(%d): %s\n",
-                    threadmessage->message_type,
-                    threadmessage->message_string);
-        }
-        g_free(threadmessage);
-        currentpos++;
-        count -= sizeof(void *);
-    }
-    g_free(msgbuffer);
-
-    return TRUE;
-}
-
 
 /** Returns properly formatted string informing the user about the
     amount of the new mail.
diff --git a/src/main-window.h b/src/main-window.h
index 731b4dc..0b5fd0d 100644
--- a/src/main-window.h
+++ b/src/main-window.h
@@ -42,12 +42,6 @@
     (G_TYPE_INSTANCE_GET_CLASS ((window), BALSA_TYPE_WINDOW, \
                                BalsaWindowClass))
 
-/* Type values for mailbox checking */
-enum MailboxCheckType {
-    TYPE_BACKGROUND,
-    TYPE_CALLBACK
-};
-
 typedef struct _BalsaWindow BalsaWindow;
 typedef struct _BalsaWindowClass BalsaWindowClass;
 typedef enum {
@@ -140,7 +134,7 @@ gboolean mail_progress_notify_cb(GIOChannel * source,
 gboolean send_progress_notify_cb(GIOChannel * source,
                                  GIOCondition condition,
                                  BalsaWindow ** window);
-void check_new_messages_real(BalsaWindow * window, int type);
+void check_new_messages_real(BalsaWindow * window, gboolean background_check);
 void check_new_messages_count(LibBalsaMailbox * mailbox, gboolean notify);
 void empty_trash(BalsaWindow * window);
 void update_view_menu(BalsaWindow * window);
diff --git a/src/main.c b/src/main.c
index 77eb9dd..77746dd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,7 +47,6 @@
 #include "information.h"
 #include "imap-server.h"
 #include "libbalsa-conf.h"
-#include "threads.h"
 
 #include "libinit_balsa/assistant_init.h"
 
@@ -56,15 +55,6 @@
 #include "libbalsa-gpgme-cb.h"
 #endif
 
-/* Globals for Thread creation, messaging, pipe I/O */
-gboolean checking_mail;
-int mail_thread_pipes[2];
-GIOChannel *mail_thread_msg_send;
-GIOChannel *mail_thread_msg_receive;
-
-static void threads_init(void);
-static void threads_destroy(void);
-
 static void config_init(gboolean check_only);
 static void mailboxes_init(gboolean check_only);
 static void balsa_cleanup(void);
@@ -103,7 +93,7 @@ accel_map_save(void)
 static gboolean
 balsa_main_check_new_messages(gpointer data)
 {
-    check_new_messages_real(data, TYPE_CALLBACK);
+    check_new_messages_real(data, FALSE);
     return FALSE;
 }
 
@@ -168,28 +158,6 @@ mailboxes_init(gboolean check_only)
     }
 }
 
-GMutex checking_mail_lock;
-
-static void
-threads_init(void)
-{
-    if (pipe(mail_thread_pipes) < 0) {
-       g_log("BALSA Init", G_LOG_LEVEL_DEBUG,
-             "Error opening pipes.\n");
-    }
-    mail_thread_msg_send = g_io_channel_unix_new(mail_thread_pipes[1]);
-    mail_thread_msg_receive =
-       g_io_channel_unix_new(mail_thread_pipes[0]);
-    g_io_add_watch(mail_thread_msg_receive, G_IO_IN,
-                  (GIOFunc) mail_progress_notify_cb,
-                   &balsa_app.main_window);
-}
-
-static void
-threads_destroy(void)
-{
-    g_mutex_clear(&checking_mail_lock);
-}
 
 /* initial_open_mailboxes:
    open mailboxes on startup if requested so.
@@ -515,9 +483,6 @@ real_main(int argc, char *argv[])
     setlocale(LC_ALL, "");
 #endif
 
-    /* initiate thread mutexs, variables */
-    threads_init();
-
 #ifdef HAVE_RUBRICA
     /* initialise libxml */
     LIBXML_TEST_VERSION
@@ -603,8 +568,6 @@ real_main(int argc, char *argv[])
     balsa_cleanup();
     accel_map_save();
 
-    threads_destroy();
-
     libbalsa_imap_server_close_all_connections();
     return 0;
 }
diff --git a/src/pref-manager.c b/src/pref-manager.c
index 781bd62..fb0ffae 100644
--- a/src/pref-manager.c
+++ b/src/pref-manager.c
@@ -108,7 +108,8 @@ typedef struct _PropertyUI {
     GtkWidget *view_allheaders;
     GtkWidget *debug;           /* enable/disable debugging */
     GtkWidget *empty_trash;
-    GtkRadioButton *pwindow_type[NUM_PWINDOW_MODES];
+    GtkWidget *recv_progress_dlg;
+    GtkWidget *send_progress_dlg;
     GtkWidget *wordwrap;
     GtkWidget *wraplength;
     GtkWidget *open_inbox_upon_startup;
@@ -402,12 +403,8 @@ apply_prefs(GtkDialog * pbox)
     /* 
      * display page 
      */
-    for (i = 0; i < NUM_PWINDOW_MODES; i++)
-        if (gtk_toggle_button_get_active
-                (GTK_TOGGLE_BUTTON(pui->pwindow_type[i]))) {
-            balsa_app.pwindow_option = pwindow_type[i];
-            break;
-        }
+    balsa_app.recv_progress_dialog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->recv_progress_dlg));
+    balsa_app.send_progress_dialog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->send_progress_dlg));
 
     balsa_app.debug =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->debug));
@@ -660,12 +657,8 @@ set_prefs(void)
     unsigned i;
     gchar *tmp;
 
-    for (i = 0; i < NUM_PWINDOW_MODES; i++)
-        if (balsa_app.pwindow_option == pwindow_type[i]) {
-            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
-                                         (pui->pwindow_type[i]), TRUE);
-            break;
-        }
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->recv_progress_dlg), balsa_app.recv_progress_dialog);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->send_progress_dlg), balsa_app.send_progress_dialog);
 
     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER
                                         (pui->mail_directory),
@@ -2702,19 +2695,10 @@ pm_grid_add_progress_group(GtkWidget * grid_widget)
 {
     GtkGrid *grid = (GtkGrid *) grid_widget;
     gint row = pm_grid_get_next_row(grid);
-    GSList *radio_group;
-    gint i;
 
     pm_grid_attach(grid, pm_group_label(_("Display progress dialog")), 0, row, 3, 1);
-
-    radio_group = NULL;
-    for (i = 0; i < NUM_PWINDOW_MODES; i++) {
-       pui->pwindow_type[i] =
-           GTK_RADIO_BUTTON(gtk_radio_button_new_with_label
-                            (radio_group, _(pwindow_type_label[i])));
-       pm_grid_attach(grid, GTK_WIDGET(pui->pwindow_type[i]), 1, ++row, 2, 1);
-       radio_group = gtk_radio_button_get_group(pui->pwindow_type[i]);
-    }
+    pui->send_progress_dlg = pm_grid_attach_check(grid, 1, ++row, 2, 1, _("Display progress dialog when 
sending messages"));
+    pui->recv_progress_dlg = pm_grid_attach_check(grid, 1, ++row, 2, 1, _("Display progress dialog when 
retrieving messages"));
 
     pm_grid_set_next_row(grid, ++row);
 }
@@ -3375,11 +3359,10 @@ open_preferences_manager(GtkWidget * widget, gpointer data)
     gtk_dialog_set_response_sensitive(GTK_DIALOG(property_box),
                                       GTK_RESPONSE_APPLY, FALSE);
 
-    for (i = 0; i < NUM_PWINDOW_MODES; i++) {
-        g_signal_connect(G_OBJECT(pui->pwindow_type[i]), "clicked",
-                         G_CALLBACK(properties_modified_cb), property_box);
-    }
-
+    g_signal_connect(G_OBJECT(pui->recv_progress_dlg), "toggled",
+                     G_CALLBACK(properties_modified_cb), property_box);
+    g_signal_connect(G_OBJECT(pui->send_progress_dlg), "toggled",
+                     G_CALLBACK(properties_modified_cb), property_box);
     g_signal_connect(G_OBJECT(pui->previewpane), "toggled",
                      G_CALLBACK(properties_modified_cb), property_box);
     g_signal_connect(G_OBJECT(pui->layout_type), "changed",
diff --git a/src/save-restore.c b/src/save-restore.c
index 50e0243..5906516 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -37,7 +37,6 @@
 #include "filter-funcs.h"
 #include "mailbox-filter.h"
 #include "libbalsa-conf.h"
-#include "threads.h"
 
 #include "smtp-server.h"
 #include "send.h"
@@ -369,28 +368,6 @@ gint config_folder_update(BalsaMailboxNode * mbnode)
     return res;
 }                              /* config_folder_update */
 
-static void
-pop3_progress_notify(LibBalsaMailbox* mailbox, int msg_type, int prog, int tot,
-                     const char* msg)
-{
-    MailThreadMessage *message;
-
-    message = g_new(MailThreadMessage, 1);
-    message->message_type = msg_type;
-    memcpy(message->message_string, msg, strlen(msg) + 1);
-    message->num_bytes = prog;
-    message->tot_bytes = tot;
-
-    /* FIXME: There is potential for a timeout with 
-       * the server here, if we don't get the lock back
-       * soon enough.. But it prevents the main thread from
-       * blocking on the mutt_lock, andthe pipe filling up.
-       * This would give us a deadlock.
-     */
-    if (write(mail_thread_pipes[1], (void *) &message, sizeof(void *))
-        != sizeof(void *))
-        g_warning("pipe error");
-}
 
 /* Initialize the specified mailbox, creating the internal data
    structures which represent the mailbox. */
@@ -415,9 +392,6 @@ config_mailbox_init(const gchar * prefix)
     }
 
     if (LIBBALSA_IS_MAILBOX_POP3(mailbox)) {
-        g_signal_connect(G_OBJECT(mailbox),
-                         "progress-notify", G_CALLBACK(pop3_progress_notify),
-                         mailbox);
        balsa_app.inbox_input =
             g_list_prepend(balsa_app.inbox_input,
                            balsa_mailbox_node_new_from_mailbox(mailbox));
@@ -787,8 +761,9 @@ config_global_load(void)
     balsa_app.show_sos_bar =
         libbalsa_conf_get_bool("ShowSOSbar=true");
 
-    /* ... Progress Window Dialog */
-    balsa_app.pwindow_option = d_get_gint("ProgressWindow", WHILERETR);
+    /* ... Progress Window Dialogs */
+       balsa_app.recv_progress_dialog = libbalsa_conf_get_bool("ShowRecvProgressDlg=true");
+    balsa_app.send_progress_dialog = libbalsa_conf_get_bool("ShowSendProgressDlg=true");
 
     /* ... deleting messages: defaults enshrined here */
     filter_mask = libbalsa_mailbox_get_filter(NULL);
@@ -1275,7 +1250,8 @@ config_save(void)
     libbalsa_conf_set_bool("ShowPreviewPane", balsa_app.previewpane);
     libbalsa_conf_set_bool("ShowMailboxList", balsa_app.show_mblist);
     libbalsa_conf_set_bool("ShowTabs", balsa_app.show_notebook_tabs);
-    libbalsa_conf_set_int("ProgressWindow", balsa_app.pwindow_option);
+       libbalsa_conf_set_bool("ShowRecvProgressDlg", balsa_app.recv_progress_dialog);
+    libbalsa_conf_set_bool("ShowSendProgressDlg", balsa_app.send_progress_dialog);
     libbalsa_conf_set_int("LayoutType",     balsa_app.layout_type);
     libbalsa_conf_set_bool("ViewMessageOnOpen", balsa_app.view_message_on_open);
     libbalsa_conf_set_bool("AskBeforeSelect", balsa_app.ask_before_select);
diff --git a/src/sendmsg-window.c b/src/sendmsg-window.c
index df8bd91..1b1bec2 100644
--- a/src/sendmsg-window.c
+++ b/src/sendmsg-window.c
@@ -59,7 +59,6 @@
 #include "balsa-message.h"
 #include "balsa-index.h"
 #include "balsa-icons.h"
-#include "threads.h"
 
 #include "missing.h"
 #include "ab-window.h"
@@ -5244,6 +5243,7 @@ send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
         result = libbalsa_message_send(message, balsa_app.outbox, fcc,
                                        balsa_find_sentbox_by_url,
                                       bsmsg->ident->smtp_server,
+                                                                          balsa_app.send_progress_dialog,
                                        GTK_WINDOW(balsa_app.main_window),
                                        bsmsg->flow, &error);
     if (result == LIBBALSA_MESSAGE_CREATE_OK) {


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