aboutsummaryrefslogtreecommitdiffstats
path: root/mail/mail-threads.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/mail-threads.c')
-rw-r--r--mail/mail-threads.c838
1 files changed, 303 insertions, 535 deletions
diff --git a/mail/mail-threads.c b/mail/mail-threads.c
index ebf1e862ad..e1707eb3f3 100644
--- a/mail/mail-threads.c
+++ b/mail/mail-threads.c
@@ -26,19 +26,15 @@
#include <string.h>
#include <glib.h>
+
+#include "folder-browser-factory.h"
+
#include "camel/camel-object.h"
#include "mail.h"
#include "mail-threads.h"
#define DEBUG(p) g_print p
-/* FIXME TODO: Do we need operations that don't get a progress window because
- * they're quick, but we still want camel to be locked? We need some kind
- * of flag to mail_operation_queue, but then we also need some kind of monitor
- * to open the window if it takes more than a second or something. That would
- * probably entail another thread....
- */
-
/**
* A function and its userdata
**/
@@ -63,15 +59,20 @@ typedef struct com_msg_s
{
enum com_msg_type_e {
STARTING,
+
+#if 0
PERCENTAGE,
HIDE_PBAR,
SHOW_PBAR,
+#endif
+
MESSAGE,
PASSWORD,
ERROR,
FORWARD_EVENT,
FINISHED
} type;
+
gfloat percentage;
gchar *message;
@@ -91,6 +92,18 @@ typedef struct com_msg_s
com_msg_t;
/**
+ * Stuff needed for blocking
+ **/
+
+typedef struct block_info_s {
+ GMutex *mutex;
+ GCond *cond;
+ gboolean val;
+} block_info_t;
+
+#define BLOCK_INFO_INIT { NULL, NULL, FALSE }
+
+/**
* @dispatch_thread_started: gboolean that tells us whether
* the dispatch thread has been launched.
**/
@@ -110,31 +123,6 @@ static gboolean dispatch_thread_started = FALSE;
static gint queue_len = 0;
/**
- * @queue_window: The little window on the screen that
- * shows the progress of the current operation and the
- * operations that are queued to proceed after it.
- *
- * @queue_window_pending: The vbox that contains the
- * list of pending operations.
- *
- * @queue_window_message: The label that contains the
- * operation's message to the user
- **/
-
-static GtkWidget *queue_window = NULL;
-static GtkWidget *queue_window_pending = NULL;
-static GtkWidget *queue_window_message = NULL;
-static GtkWidget *queue_window_progress = NULL;
-
-/**
- * @progress_timeout_handle: the handle to our timer
- * function so that we can remove it when the progress bar
- * mode changes.
- **/
-
-static int progress_timeout_handle = -1;
-
-/**
* @main_compipe: The pipe through which the dispatcher communicates
* with the main thread for GTK+ calls
*
@@ -155,59 +143,57 @@ static int dispatch_compipe[2] = { -1, -1 };
GIOChannel *chan_reader = NULL;
/**
- * @modal_cond: a condition maintained so that the
+ * @modal_block: a condition maintained so that the
* calling thread (the dispatch thread) blocks correctly
* until the user has responded to some kind of modal
* dialog boxy thing.
- *
- * @modal_lock: a mutex for said condition
- *
- * @modal_may_proceed: a gboolean telling us whether
- * the dispatch thread may proceed its operations.
*/
-G_LOCK_DEFINE_STATIC (modal_lock);
-static GCond *modal_cond = NULL;
-static gboolean modal_may_proceed = FALSE;
+static block_info_t modal_block = BLOCK_INFO_INIT;
/**
- * @ready_for_op: A lock that the main thread only releases
- * when it is ready for the dispatch thread to do its thing
- *
- * @ready_cond: A condition for this ... condition
- *
- * @ready_may_proceed: a gboolean telling the dispatch thread
- * when it may proceed.
+ * @finish_block: A condition so that the dispatch thread
+ * blocks until the main thread has finished the cleanup.
**/
-G_LOCK_DEFINE_STATIC (ready_for_op);
-static GCond *ready_cond = NULL;
-static gboolean ready_may_proceed = FALSE;
+static block_info_t finish_block = BLOCK_INFO_INIT;
+
+/**
+ * @current_message: The current message for the status bar.
+ * @busy_status: Whether we are currently busy doing some async operation,
+ * for status bar purposes.
+ */
+
+static char *current_message = NULL;
+static gboolean busy = FALSE;
/**
* Static prototypes
**/
-static void create_queue_window (void);
-static void destroy_queue_window (void);
+static void ui_set_busy (void);
+static void ui_unset_busy (void);
+static void ui_set_message (const char *message);
+static void ui_unset_message (void);
+
+static void block_prepare (block_info_t *info);
+static void block_wait (block_info_t *info);
+static void block_hold (block_info_t *info);
+static void block_release (block_info_t *info);
+
static void *dispatch (void * data);
static void check_dispatcher (void);
static void check_compipes (void);
-static void check_cond (void);
static gboolean read_msg (GIOChannel * source, GIOCondition condition,
gpointer userdata);
-static void remove_next_pending (void);
+
static void show_error (com_msg_t * msg);
-static void show_error_clicked (GtkObject * obj);
+
static void get_password (com_msg_t * msg);
static void get_password_cb (gchar * string, gpointer data);
-static void get_password_clicked (GnomeDialog * dialog, gint button,
- gpointer user_data);
-static void get_password_deleted (GtkWidget *widget, gpointer user_data);
-static gboolean progress_timeout (gpointer data);
-static void timeout_toggle (gboolean active);
-static gboolean display_timeout (gpointer data);
+static void cleanup_op (com_msg_t * msg);
+
static closure_t *new_closure (const mail_operation_spec * spec, gpointer input,
gboolean free_in_data);
static void free_closure (closure_t *clur);
@@ -292,9 +278,11 @@ mail_operation_queue (const mail_operation_spec * spec, gpointer input,
g_free (msg);
gnome_dialog_set_close (GNOME_DIALOG (err_dialog),
TRUE);
- /*gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog));*/
+ GDK_THREADS_ENTER ();
+ gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog));
+ GDK_THREADS_LEAVE ();
/*gtk_widget_destroy (err_dialog); */
- gtk_widget_show (GTK_WIDGET (err_dialog));
+ /*gtk_widget_show (GTK_WIDGET (err_dialog));*/
g_warning ("Setup failed for `%s': %s",
clur->infinitive,
@@ -307,37 +295,16 @@ mail_operation_queue (const mail_operation_spec * spec, gpointer input,
}
if (queue_len == 0) {
- check_cond ();
check_compipes ();
check_dispatcher ();
- create_queue_window ();
- /*gtk_widget_show_all (queue_window); */
- gtk_timeout_add (1000, display_timeout, NULL);
- } else {
- GtkWidget *label;
-
- /* We already have an operation running. Well,
- * queue ourselves up. (visually)
- */
-
- /* Show us in the pending window. */
- label = gtk_label_new (clur->infinitive);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_box_pack_start (GTK_BOX (queue_window_pending), label,
- FALSE, TRUE, 2);
- gtk_widget_show (label);
-
- /* If we want the next op to be on the bottom, uncomment this */
- /* 1 = first on list always (0-based) */
- /* gtk_box_reorder_child( GTK_BOX( queue_window_pending ), label, 1 ); */
- gtk_widget_show (queue_window_pending);
- }
+ } /* else add self to queue */
write (DISPATCH_WRITER, clur, sizeof (closure_t));
queue_len++;
return TRUE;
}
+#if 0
/**
* mail_op_set_percentage:
* @percentage: the percentage that will be displayed in the progress bar
@@ -363,11 +330,6 @@ mail_op_set_percentage (gfloat percentage)
* Threadsafe for, nay, intended to be called by, the dispatching thread.
**/
-/* FIXME: I'd much rather have one of those Netscape-style progress
- * bars that just zips back and forth, but gtkprogressbar can't do
- * that, right?
- */
-
void
mail_op_hide_progressbar (void)
{
@@ -393,6 +355,8 @@ mail_op_show_progressbar (void)
write (MAIN_WRITER, &msg, sizeof (msg));
}
+#endif
+
/**
* mail_op_set_message:
* @fmt: printf-style format string for the message
@@ -443,17 +407,9 @@ mail_op_get_password (gchar * prompt, gboolean secret, gchar ** dest)
(*dest) = NULL;
- G_LOCK (modal_lock);
-
+ block_prepare (&modal_block);
write (MAIN_WRITER, &msg, sizeof (msg));
- modal_may_proceed = FALSE;
-
- while (modal_may_proceed == FALSE)
- g_cond_wait (modal_cond,
- g_static_mutex_get_mutex (&G_LOCK_NAME
- (modal_lock)));
-
- G_UNLOCK (modal_lock);
+ block_wait (&modal_block);
return result;
}
@@ -478,17 +434,9 @@ mail_op_error (gchar * fmt, ...)
msg.message = g_strdup_vprintf (fmt, val);
va_end (val);
- G_LOCK (modal_lock);
-
- modal_may_proceed = FALSE;
+ block_prepare (&modal_block);
write (MAIN_WRITER, &msg, sizeof (msg));
-
- while (modal_may_proceed == FALSE)
- g_cond_wait (modal_cond,
- g_static_mutex_get_mutex (&G_LOCK_NAME
- (modal_lock)));
-
- G_UNLOCK (modal_lock);
+ block_wait (&modal_block);
}
/**
@@ -558,6 +506,14 @@ mail_operations_terminate (void)
write (DISPATCH_WRITER, &clur, sizeof (closure_t));
}
+void
+mail_operations_get_status (int *busy_return,
+ const char **message_return)
+{
+ *busy_return = busy;
+ *message_return = current_message;
+}
+
/* ** Static functions **************************************************** */
static void check_dispatcher (void)
@@ -583,117 +539,6 @@ static void check_dispatcher (void)
dispatch_thread_started = TRUE;
}
-static void
-print_hide (GtkWidget * wid)
-{
- g_message ("$$$ hide signal emitted");
-}
-
-static void
-print_unmap (GtkWidget * wid)
-{
- g_message ("$$$ unmap signal emitted");
-}
-
-static void
-print_map (GtkWidget * wid)
-{
- g_message ("$$$ map signal emitted");
-}
-
-static void
-print_show (GtkWidget * wid)
-{
- g_message ("$$$ show signal emitted");
-}
-
-/**
- * create_queue_window:
- *
- * Creates the queue_window widget that displays the progress of the
- * current operation.
- */
-
-static void
-queue_window_delete_event_cb (GtkWindow *window,
- void *data)
-{
- /* Do nothing. Just prevent GTK+ from destroying the window. */
-}
-
-static void
-create_queue_window (void)
-{
- GtkWidget *vbox;
- GtkWidget *pending_vb, *pending_lb;
- GtkWidget *progress_lb, *progress_bar;
-
- /* Check to see if we've only hidden it */
- if (queue_window != NULL)
- return;
-
- queue_window = gtk_window_new (GTK_WINDOW_DIALOG);
- gtk_container_set_border_width (GTK_CONTAINER (queue_window), 8);
-
- gtk_signal_connect (GTK_OBJECT (queue_window), "delete_event",
- GTK_SIGNAL_FUNC (queue_window_delete_event_cb), NULL);
-
- vbox = gtk_vbox_new (FALSE, 4);
-
- pending_vb = gtk_vbox_new (FALSE, 2);
- queue_window_pending = pending_vb;
-
- pending_lb = gtk_label_new (_("Currently pending operations:"));
- gtk_misc_set_alignment (GTK_MISC (pending_lb), 0.0, 0.0);
- gtk_box_pack_start (GTK_BOX (pending_vb), pending_lb, FALSE, TRUE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), pending_vb, TRUE, TRUE, 4);
-
- /* FIXME: 'operation' is not the warmest cuddliest word. */
- progress_lb = gtk_label_new ("");
- queue_window_message = progress_lb;
- gtk_box_pack_start (GTK_BOX (vbox), progress_lb, FALSE, TRUE, 4);
-
- progress_bar = gtk_progress_bar_new ();
- queue_window_progress = progress_bar;
- /* FIXME: is this fit for l10n? */
- gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (progress_bar),
- GTK_PROGRESS_LEFT_TO_RIGHT);
- gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (progress_bar),
- GTK_PROGRESS_CONTINUOUS);
- gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 4);
-
- gtk_container_add (GTK_CONTAINER (queue_window), vbox);
-
- gtk_widget_show (GTK_WIDGET (progress_bar));
- gtk_widget_show (GTK_WIDGET (progress_lb));
- gtk_widget_show (GTK_WIDGET (pending_lb));
- gtk_widget_show (GTK_WIDGET (pending_vb));
- gtk_widget_show (GTK_WIDGET (vbox));
-
- gtk_signal_connect (GTK_OBJECT (queue_window), "hide", print_hide,
- NULL);
- gtk_signal_connect (GTK_OBJECT (queue_window), "unmap", print_unmap,
- NULL);
- gtk_signal_connect (GTK_OBJECT (queue_window), "show", print_show,
- NULL);
- gtk_signal_connect (GTK_OBJECT (queue_window), "map", print_map,
- NULL);
-}
-
-static void destroy_queue_window (void)
-{
- g_return_if_fail (queue_window);
-
- timeout_toggle (FALSE);
- gtk_widget_destroy (queue_window);
-
- queue_window = NULL;
- queue_window_progress = NULL;
- queue_window_pending = NULL;
- queue_window_message = NULL;
-}
-
/**
* check_compipes:
*
@@ -727,22 +572,6 @@ check_compipes (void)
}
/**
- * check_cond:
- *
- * See if our condition is initialized and do so if necessary
- **/
-
-static void
-check_cond (void)
-{
- if (modal_cond == NULL)
- modal_cond = g_cond_new ();
-
- if (ready_cond == NULL)
- ready_cond = g_cond_new ();
-}
-
-/**
* dispatch:
* @clur: The operation to execute and its parameters
*
@@ -779,8 +608,6 @@ dispatch (void *unused)
msg.message = g_strdup (clur->gerund);
write (MAIN_WRITER, &msg, sizeof (msg));
- mail_op_hide_progressbar ();
-
(clur->spec->callback) (clur->in_data, clur->op_data, clur->ex);
if (camel_exception_is_set (clur->ex)) {
@@ -799,15 +626,10 @@ dispatch (void *unused)
msg.type = FINISHED;
msg.clur = clur;
- G_LOCK (ready_for_op);
+ /* Wait for the cleanup to finish before starting our next op */
+ block_prepare (&finish_block);
write (MAIN_WRITER, &msg, sizeof (msg));
-
- ready_may_proceed = FALSE;
- while (ready_may_proceed == FALSE)
- g_cond_wait (ready_cond,
- g_static_mutex_get_mutex (&G_LOCK_NAME
- (ready_for_op)));
- G_UNLOCK (ready_for_op);
+ block_wait (&finish_block);
}
#ifdef G_THREADS_IMPL_POSIX
@@ -860,54 +682,41 @@ read_msg (GIOChannel * source, GIOCondition condition, gpointer userdata)
switch (msg->type) {
case STARTING:
DEBUG (("*** Message -- STARTING %s\n", msg->message));
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- msg->message);
- gtk_progress_bar_update (GTK_PROGRESS_BAR
- (queue_window_progress), 0.0);
+ ui_set_message (msg->message);
+ ui_set_busy ();
g_free (msg->message);
- g_free (msg);
break;
+#if 0
case PERCENTAGE:
DEBUG (("*** Message -- PERCENTAGE\n"));
- gtk_progress_bar_update (GTK_PROGRESS_BAR
- (queue_window_progress),
- msg->percentage);
- g_free (msg);
+ g_warning ("PERCENTAGE operation unsupported");
break;
case HIDE_PBAR:
DEBUG (("*** Message -- HIDE_PBAR\n"));
- gtk_progress_set_activity_mode (GTK_PROGRESS
- (queue_window_progress),
- TRUE);
- timeout_toggle (TRUE);
- g_free (msg);
+ g_warning ("HIDE_PBAR operation unsupported");
break;
case SHOW_PBAR:
DEBUG (("*** Message -- SHOW_PBAR\n"));
- timeout_toggle (FALSE);
- gtk_progress_set_activity_mode (GTK_PROGRESS
- (queue_window_progress),
- FALSE);
- g_free (msg);
+ g_warning ("HIDE_PBAR operation unsupported");
break;
+#endif
+
case MESSAGE:
DEBUG (("*** Message -- MESSAGE\n"));
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- msg->message);
+ ui_set_message (msg->message);
g_free (msg->message);
- g_free (msg);
break;
+
case PASSWORD:
DEBUG (("*** Message -- PASSWORD\n"));
g_assert (msg->reply);
g_assert (msg->success);
get_password (msg);
- /* don't free msg! done later */
break;
+
case ERROR:
DEBUG (("*** Message -- ERROR\n"));
show_error (msg);
- g_free (msg);
break;
/* Don't fall through; dispatch_func does the FINISHED
@@ -916,100 +725,62 @@ read_msg (GIOChannel * source, GIOCondition condition, gpointer userdata)
case FORWARD_EVENT:
DEBUG (("*** Message -- FORWARD_EVENT %p\n", msg->event_hook));
-
g_assert (msg->event_hook);
(msg->event_hook) (msg->event_obj, msg->event_event_data, msg->event_user_data);
- g_free (msg);
break;
case FINISHED:
- DEBUG (
- ("*** Message -- FINISH %s\n",
- msg->clur->gerund));
-
- if (msg->clur->spec->cleanup)
- (msg->clur->spec->cleanup) (msg->clur->in_data,
- msg->clur->op_data,
- msg->clur->ex);
-
- G_LOCK (ready_for_op);
- ready_may_proceed = TRUE;
- g_cond_signal (ready_cond);
- G_UNLOCK (ready_for_op);
-
- if (camel_exception_is_set (msg->clur->ex) &&
- msg->clur->ex->id != CAMEL_EXCEPTION_USER_CANCEL) {
- g_warning ("Error on cleanup of `%s': %s",
- msg->clur->infinitive,
- camel_exception_get_description (msg->
- clur->
- ex));
- }
-
- free_closure (msg->clur);
- queue_len--;
-
- if (queue_len == 0) {
- g_print ("\tNo more ops -- hide %p.\n", queue_window);
- /* All done! */
- /* gtk_widget_hide seems to have problems sometimes
- * here... perhaps because we're in a gsource handler,
- * not a GTK event handler? Anyway, we defer the hiding
- * til an idle. */
- /*gtk_idle_add (hide_queue_window, NULL);*/
- /*gtk_widget_hide (queue_window); */
- destroy_queue_window ();
- } else {
- g_print ("\tOperation(s) left.\n");
-
- /* There's another operation left :
- * Clear it out of the 'pending' vbox
- */
- remove_next_pending ();
- }
- g_free (msg);
+ DEBUG (("*** Message -- FINISH %s\n", msg->clur->gerund));
+ cleanup_op (msg);
break;
+
default:
g_warning (_("Corrupted message from dispatching thread?"));
break;
}
GDK_THREADS_LEAVE ();
+ g_free (msg);
return TRUE;
}
/**
- * remove_next_pending:
+ * cleanup_op:
*
- * Remove an item from the list of pending items. If
- * that's the last one, additionally hide the little
- * 'pending' message.
+ * Cleanup after a finished operation
**/
static void
-remove_next_pending (void)
+cleanup_op (com_msg_t * msg)
{
- GList *children;
+ block_hold (&finish_block);
- children =
- gtk_container_children (GTK_CONTAINER (queue_window_pending));
+ /* Run the cleanup */
- /* Skip past the header label */
- children = g_list_first (children);
- children = g_list_next (children);
+ if (msg->clur->spec->cleanup)
+ (msg->clur->spec->cleanup) (msg->clur->in_data,
+ msg->clur->op_data,
+ msg->clur->ex);
+
+ /* Tell the dispatch thread that it can start
+ * the next operation */
- if (!children) {
- g_warning ("Mistake in queue window!");
- return;
+ block_release (&finish_block);
+
+ /* Print an exception if the cleanup caused one */
+
+ if (camel_exception_is_set (msg->clur->ex) &&
+ msg->clur->ex->id != CAMEL_EXCEPTION_USER_CANCEL) {
+ g_warning ("Error on cleanup of `%s': %s",
+ msg->clur->infinitive,
+ camel_exception_get_description (msg->clur->ex));
}
- /* Nuke the one on top */
- gtk_container_remove (GTK_CONTAINER (queue_window_pending),
- GTK_WIDGET (children->data));
+ free_closure (msg->clur);
+ queue_len--;
- /* Hide it? */
- if (g_list_next (children) == NULL)
- gtk_widget_hide (queue_window_pending);
+ ui_unset_busy ();
+ ui_unset_message ();
}
/**
@@ -1022,63 +793,27 @@ static void
show_error (com_msg_t * msg)
{
GtkWidget *err_dialog;
- gchar *old_message;
+
+ /* Create the dialog */
err_dialog = gnome_error_dialog (msg->message);
- gnome_dialog_set_close (GNOME_DIALOG (err_dialog), TRUE);
- gtk_signal_connect (GTK_OBJECT (err_dialog), "close",
- (GtkSignalFunc) show_error_clicked, NULL);
- gtk_signal_connect (GTK_OBJECT (err_dialog), "clicked",
- (GtkSignalFunc) show_error_clicked, NULL);
g_free (msg->message);
- /* Save the old message, but display a new one right now */
- gtk_label_get (GTK_LABEL (queue_window_message), &old_message);
- gtk_object_set_data (GTK_OBJECT (err_dialog), "old_message",
- g_strdup (old_message));
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- _("Waiting for user to close error dialog"));
+ /* Stop the other thread until the user reacts */
- G_LOCK (modal_lock);
+ ui_unset_busy ();
+ block_hold (&modal_block);
- timeout_toggle (FALSE);
- modal_may_proceed = FALSE;
- /*gtk_widget_show_all (GTK_WIDGET (err_dialog));*/
- gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog));
- /*
- *gnome_win_hints_set_layer (err_dialog, WIN_LAYER_ONTOP);
- *gnome_win_hints_set_state (err_dialog, WIN_STATE_ARRANGE_IGNORE);
- *gnome_win_hints_set_hints (err_dialog,
- * WIN_HINTS_SKIP_FOCUS |
- * WIN_HINTS_SKIP_WINLIST |
- * WIN_HINTS_SKIP_TASKBAR);
- */
-}
+ /* Show the dialog. */
-/**
- * show_error_clicked:
- *
- * Called when the user makes hits okay to the error dialog --
- * the dispatch thread is allowed to continue.
- **/
-
-static void
-show_error_clicked (GtkObject * obj)
-{
- gchar *old_message;
-
- gtk_signal_disconnect_by_func (GTK_OBJECT (obj), show_error_clicked, NULL);
+ GDK_THREADS_ENTER ();
+ gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog));
+ GDK_THREADS_LEAVE ();
- /* Restore the old message */
- old_message = gtk_object_get_data (obj, "old_message");
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- old_message);
- g_free (old_message);
+ /* Allow the other thread to proceed */
- modal_may_proceed = TRUE;
- timeout_toggle (TRUE);
- g_cond_signal (modal_cond);
- G_UNLOCK (modal_lock);
+ block_release (&modal_block);
+ ui_set_busy ();
}
/**
@@ -1091,46 +826,43 @@ static void
get_password (com_msg_t * msg)
{
GtkWidget *dialog;
- gchar *old_message;
+ int button;
+
+ /* Create the dialog */
dialog = gnome_request_dialog (msg->secret, msg->message, NULL,
0, get_password_cb, msg, NULL);
- gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);
- gtk_signal_connect (GTK_OBJECT (dialog), "clicked",
- get_password_clicked, msg);
- gtk_signal_connect (GTK_OBJECT (dialog), "close",
- get_password_deleted, msg);
+ g_free (msg->message);
- /* Save the old message, but display a new one right now */
- gtk_label_get (GTK_LABEL (queue_window_message), &old_message);
- gtk_object_set_data (GTK_OBJECT (dialog), "old_message", g_strdup(old_message));
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- _("Waiting for user to enter data"));
+ /* Stop the other thread */
- G_LOCK (modal_lock);
+ ui_unset_busy ();
+ block_hold (&modal_block);
- modal_may_proceed = FALSE;
+ /* Show the dialog (or report an error) */
if (dialog == NULL) {
*(msg->success) = FALSE;
*(msg->reply) = g_strdup (_("Could not create dialog box."));
- modal_may_proceed = TRUE;
- g_cond_signal (modal_cond);
- G_UNLOCK (modal_lock);
+ button = -1;
} else {
*(msg->reply) = NULL;
- timeout_toggle (FALSE);
- /*
- *gtk_widget_show_all (GTK_WIDGET (dialog));
- *gnome_win_hints_set_layer (dialog, WIN_LAYER_ONTOP);
- *gnome_win_hints_set_state (dialog, WIN_STATE_ARRANGE_IGNORE);
- *gnome_win_hints_set_hints (dialog,
- * WIN_HINTS_SKIP_FOCUS |
- * WIN_HINTS_SKIP_WINLIST |
- * WIN_HINTS_SKIP_TASKBAR);
- */
- gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+ GDK_THREADS_ENTER ();
+ button = gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+ GDK_THREADS_LEAVE ();
+ }
+
+ if (button == 1 || *(msg->reply) == NULL) {
+ *(msg->success) = FALSE;
+ *(msg->reply) = g_strdup (_("User cancelled query."));
+ } else if (button > 0) {
+ *(msg->success) = TRUE;
}
+
+ /* Allow the other thread to proceed */
+
+ block_release (&modal_block);
+ ui_set_busy ();
}
static void
@@ -1144,167 +876,203 @@ get_password_cb (gchar * string, gpointer data)
*(msg->reply) = NULL;
}
-static void
-get_password_deleted (GtkWidget *widget, gpointer user_data)
+static closure_t *
+new_closure (const mail_operation_spec * spec, gpointer input,
+ gboolean free_in_data)
{
- get_password_clicked (GNOME_DIALOG (widget), 1, user_data);
-}
+ closure_t *clur;
-static void
-get_password_clicked (GnomeDialog * dialog, gint button, gpointer user_data)
-{
- com_msg_t *msg = (com_msg_t *) user_data;
- gchar *old_message;
+ clur = g_new0 (closure_t, 1);
+ clur->spec = spec;
+ clur->in_data = input;
+ clur->free_in_data = free_in_data;
+ clur->ex = camel_exception_new ();
- gtk_signal_disconnect_by_func (GTK_OBJECT (dialog), get_password_deleted, user_data);
+ clur->op_data = g_malloc (spec->datasize);
- /* Restore the old message */
- old_message = gtk_object_get_data (GTK_OBJECT (dialog), "old_message");
- gtk_label_set_text (GTK_LABEL (queue_window_message),
- old_message);
- g_free (old_message);
+ camel_exception_init (clur->ex);
- if (button == 1 || *(msg->reply) == NULL) {
- *(msg->success) = FALSE;
- *(msg->reply) = g_strdup (_("User cancelled query."));
- } else
- *(msg->success) = TRUE;
+ clur->infinitive = (spec->describe) (input, FALSE);
+ clur->gerund = (spec->describe) (input, TRUE);
- g_free (msg);
- modal_may_proceed = TRUE;
- timeout_toggle (TRUE);
- g_cond_signal (modal_cond);
- G_UNLOCK (modal_lock);
+ return clur;
}
-/* NOT totally copied from gtk+/gtk/testgtk.c, really! */
-
-static gboolean
-progress_timeout (gpointer data)
+static void
+free_closure (closure_t *clur)
{
- gfloat new_val;
- GtkAdjustment *adj;
+ clur->spec = NULL;
- if (queue_window == NULL) {
- gtk_timeout_remove (progress_timeout_handle);
- progress_timeout_handle = -1;
- return FALSE;
- }
-
- adj = GTK_PROGRESS (data)->adjustment;
+ if (clur->free_in_data)
+ g_free (clur->in_data);
+ clur->in_data = NULL;
- new_val = adj->value + 1;
- if (new_val > adj->upper)
- new_val = adj->lower;
+ g_free (clur->op_data);
+ clur->op_data = NULL;
- gtk_progress_set_value (GTK_PROGRESS (data), new_val);
+ camel_exception_free (clur->ex);
+ clur->ex = NULL;
- return TRUE;
+ g_free (clur->infinitive);
+ g_free (clur->gerund);
+
+ g_free (clur);
}
+/* ******************** */
+
/**
- * timeout_toggle:
*
- * Turn on and off our timeout to zip the progressbar along,
- * protecting against recursion (Ie, call with TRUE twice
- * in a row.
+ * Thread A calls block_prepare
+ * Thread A causes thread B to do something
+ * Thread A calls block_wait
+ * Thread A continues when thread B calls block_release
+ *
+ * Thread B gets thread A's message
+ * Thread B calls block_hold
+ * Thread B does something
+ * Thread B calls block_release
+ *
**/
static void
-timeout_toggle (gboolean active)
+block_prepare (block_info_t *info)
{
- if (!queue_window)
- return;
-
- if ((GTK_PROGRESS (queue_window_progress))->activity_mode == 0)
- return;
-
- if (active) {
- /* We do this in case queue_window_progress gets reset */
- if (progress_timeout_handle < 0) {
- progress_timeout_handle =
- gtk_timeout_add (80, progress_timeout,
- queue_window_progress);
- } else {
- gtk_timeout_remove (progress_timeout_handle);
- progress_timeout_handle =
- gtk_timeout_add (80, progress_timeout,
- queue_window_progress);
- }
- } else {
- if (progress_timeout_handle >= 0) {
- gtk_timeout_remove (progress_timeout_handle);
- progress_timeout_handle = -1;
- }
+ if (info->cond == NULL) {
+ info->cond = g_cond_new ();
+ info->mutex = g_mutex_new ();
}
+
+ g_mutex_lock (info->mutex);
+ info->val = FALSE;
}
-/* This can theoretically run into problems where if a short operation starts
- * and finishes, then another short operation starts and finishes a second
- * later, we will see the window prematurely. My response: oh noooooo!
- *
- * Solution: keep the timeout's handle and remove the timeout upon reception
- * of FINISH, and zero out the handle in this function. Whatever.
- */
-static gboolean
-display_timeout (gpointer data)
+static void
+block_wait (block_info_t *info)
{
- if (queue_len > 0 && queue_window) {
- gtk_widget_show (queue_window);
- gnome_win_hints_set_layer (queue_window, WIN_LAYER_ONTOP);
- gnome_win_hints_set_state (queue_window,
- WIN_STATE_ARRANGE_IGNORE);
- gnome_win_hints_set_hints (queue_window,
- WIN_HINTS_SKIP_FOCUS |
- WIN_HINTS_SKIP_WINLIST |
- WIN_HINTS_SKIP_TASKBAR);
-
- if (queue_len == 1)
- gtk_widget_hide (queue_window_pending);
- }
+ g_assert (info->cond);
+
+ while (info->val == FALSE)
+ g_cond_wait (info->cond, info->mutex);
- return FALSE;
+ g_mutex_unlock (info->mutex);
}
+static void
+block_hold (block_info_t *info)
+{
+ g_assert (info->cond);
-static closure_t *
-new_closure (const mail_operation_spec * spec, gpointer input,
- gboolean free_in_data)
+ g_mutex_lock (info->mutex);
+ info->val = FALSE;
+}
+
+static void
+block_release (block_info_t *info)
{
- closure_t *clur;
+ g_assert (info->cond);
- clur = g_new0 (closure_t, 1);
- clur->spec = spec;
- clur->in_data = input;
- clur->free_in_data = free_in_data;
- clur->ex = camel_exception_new ();
+ info->val = TRUE;
+ g_cond_signal (info->cond);
+ g_mutex_unlock (info->mutex);
+}
- clur->op_data = g_malloc (spec->datasize);
+/* ******************** */
- camel_exception_init (clur->ex);
+/* FIXME FIXME FIXME This is a totally evil hack. */
- clur->infinitive = (spec->describe) (input, FALSE);
- clur->gerund = (spec->describe) (input, TRUE);
+static Evolution_ShellView
+retrieve_shell_view_interface_from_control (BonoboControl *control)
+{
+ Bonobo_ControlFrame control_frame;
+ Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control_frame = bonobo_control_get_control_frame (control);
+
+ CORBA_exception_init (&ev);
+ shell_view_interface = Bonobo_Unknown_query_interface (control_frame,
+ "IDL:Evolution/ShellView:1.0",
+ &ev);
+ CORBA_exception_free (&ev);
+
+ if (shell_view_interface != CORBA_OBJECT_NIL)
+ gtk_object_set_data (GTK_OBJECT (control),
+ "mail_threads_shell_view_interface",
+ shell_view_interface);
+ else
+ g_warning ("Control frame doesn't have Evolution/ShellView.");
- return clur;
+ return shell_view_interface;
}
static void
-free_closure (closure_t *clur)
+update_active_views (void)
{
- clur->spec = NULL;
+ GList *active_controls;
+ GList *p;
+
+ active_controls = folder_browser_factory_get_active_control_list ();
+ for (p = active_controls; p != NULL; p = p->next) {
+ BonoboControl *control;
+ Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control = BONOBO_CONTROL (p->data);
+
+ shell_view_interface = gtk_object_get_data (GTK_OBJECT (control), "mail_threads_shell_view_interface");
+
+ if (shell_view_interface == CORBA_OBJECT_NIL)
+ shell_view_interface = retrieve_shell_view_interface_from_control (control);
+
+ CORBA_exception_init (&ev);
+
+ if (shell_view_interface != CORBA_OBJECT_NIL) {
+ if (current_message == NULL && ! busy) {
+ Evolution_ShellView_unset_message (shell_view_interface, &ev);
+ } else {
+ if (current_message == NULL)
+ Evolution_ShellView_set_message (shell_view_interface,
+ "",
+ busy,
+ &ev);
+ else
+ Evolution_ShellView_set_message (shell_view_interface,
+ current_message,
+ busy,
+ &ev);
+ }
+ }
- if (clur->free_in_data)
- g_free (clur->in_data);
- clur->in_data = NULL;
+ CORBA_exception_free (&ev);
+ }
+}
- g_free (clur->op_data);
- clur->op_data = NULL;
+static void
+ui_set_busy (void)
+{
+ busy = TRUE;
+ update_active_views ();
+}
- camel_exception_free (clur->ex);
- clur->ex = NULL;
+static void
+ui_unset_busy (void)
+{
+ busy = FALSE;
+ update_active_views ();
+}
- g_free (clur->infinitive);
- g_free (clur->gerund);
+static void
+ui_set_message (const char *message)
+{
+ g_free (current_message);
+ current_message = g_strdup (message);
+ update_active_views ();
+}
- g_free (clur);
+static void
+ui_unset_message (void)
+{
+ g_free (current_message);
+ current_message = NULL;
+ update_active_views ();
}