diff options
-rw-r--r-- | mail/ChangeLog | 28 | ||||
-rw-r--r-- | mail/Makefile.am | 1 | ||||
-rw-r--r-- | mail/component-factory.c | 1 | ||||
-rw-r--r-- | mail/folder-browser-factory.c | 24 | ||||
-rw-r--r-- | mail/folder-browser-factory.h | 19 | ||||
-rw-r--r-- | mail/folder-browser.c | 4 | ||||
-rw-r--r-- | mail/mail-threads.c | 838 | ||||
-rw-r--r-- | mail/mail-threads.h | 3 | ||||
-rw-r--r-- | mail/mail.h | 6 |
9 files changed, 380 insertions, 544 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index c09bf593f3..1e7342be4c 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,31 @@ +2000-08-13 Ettore Perazzoli <ettore@helixcode.com> + + * folder-browser-factory.c (control_destroy_cb): Remove the + control from the active control list, if it's there. + + * mail.h (folder_browser_factory_new_control): Removed prototype. + (folder_browser_factory_init): Removed prototype. + + * folder-browser-factory.h: New. + + * folder-browser-factory.c: New static variable `active_controls', + list of the currently active controls. + (control_activate): Add the control to it. + (control_deactivate): Remove the control from it. + (folder_browser_factory_get_active_control_list): New. + + * mail-threads.c (mail_operations_get_status): New function. + + * folder-browser.c (folder_browser_gui_init): Add i18n support for + the labels. + + [The following is actually from a patch by Peter Williams + <peterw@helixcode.com>.] + + * Removed types `PERCENTAGE', `HIDE_PBAR', `SHOW_PBAR'. New + struct `block_info_s'. Removed all the code to create and destroy + the progress window. + 2000-08-13 Jeffrey Stedfast <fejj@helixcode.com> * component-factory.c (create_news_storage): Updated to reflect diff --git a/mail/Makefile.am b/mail/Makefile.am index 6a3e2fff91..651bb71b66 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -42,6 +42,7 @@ evolution_mail_SOURCES = \ folder-browser.c \ folder-browser.h \ folder-browser-factory.c \ + folder-browser-factory.h \ mail-autofilter.c \ mail-autofilter.h \ mail-callbacks.c \ diff --git a/mail/component-factory.c b/mail/component-factory.c index 7d17abda69..eaabce8e38 100644 --- a/mail/component-factory.c +++ b/mail/component-factory.c @@ -32,6 +32,7 @@ #include "Evolution.h" #include "evolution-storage.h" +#include "folder-browser-factory.h" #include "evolution-shell-component.h" #include "folder-browser.h" #include "mail.h" /* YUCK FIXME */ diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c index 4d288946b5..c8575e6747 100644 --- a/mail/folder-browser-factory.c +++ b/mail/folder-browser-factory.c @@ -7,19 +7,28 @@ * * (C) 2000 Helix Code, Inc. */ + #include <config.h> + #include <gnome.h> #include <bonobo/bonobo-main.h> #include <bonobo/bonobo-object.h> #include <bonobo/bonobo-generic-factory.h> #include <bonobo/bonobo-control.h> + #include "e-util/e-util.h" #include "e-util/e-gui-utils.h" + +#include "folder-browser-factory.h" + #include "folder-browser.h" #include "mail.h" #include "shell/Evolution.h" #include "mail-config.h" +/* The active folder browser BonoboControls. */ +static GList *active_controls = NULL; + static GnomeUIInfo gnome_toolbar [] = { GNOMEUIINFO_ITEM_STOCK (N_("Get mail"), N_("Check for new mail"), fetch_mail, GNOME_STOCK_PIXMAP_MAIL_RCV), GNOMEUIINFO_ITEM_STOCK (N_("Compose"), N_("Compose a new message"), compose_msg, GNOME_STOCK_PIXMAP_MAIL_NEW), @@ -52,6 +61,8 @@ control_activate (BonoboControl *control, BonoboUIHandler *uih, GtkWidget *toolbar, *toolbar_frame, *folder_browser; char *toolbar_name = g_strdup_printf ("/Toolbar%d", fb->serial); + active_controls = g_list_prepend (active_controls, control); + remote_uih = bonobo_control_get_remote_ui_handler (control); bonobo_ui_handler_set_container (uih, remote_uih); bonobo_object_release_unref (remote_uih, NULL); @@ -165,11 +176,14 @@ control_activate (BonoboControl *control, BonoboUIHandler *uih, } static void -control_deactivate (BonoboControl *control, BonoboUIHandler *uih, +control_deactivate (BonoboControl *control, + BonoboUIHandler *uih, FolderBrowser *fb) { char *toolbar_name = g_strdup_printf ("/Toolbar%d", fb->serial); + active_controls = g_list_remove (active_controls, control); + bonobo_ui_handler_menu_remove (uih, "/File/<Print Placeholder>/separator1"); bonobo_ui_handler_menu_remove (uih, "/File/<Print Placeholder>/Print message..."); @@ -209,6 +223,8 @@ control_destroy_cb (BonoboControl *control, { GtkWidget *folder_browser = user_data; + active_controls = g_list_remove (active_controls, control); + gtk_object_destroy (GTK_OBJECT (folder_browser)); } @@ -244,3 +260,9 @@ folder_browser_factory_new_control (const char *uri) return control; } + +GList * +folder_browser_factory_get_active_control_list (void) +{ + return active_controls; +} diff --git a/mail/folder-browser-factory.h b/mail/folder-browser-factory.h new file mode 100644 index 0000000000..a2346d5119 --- /dev/null +++ b/mail/folder-browser-factory.h @@ -0,0 +1,19 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * folder-browser-factory.c: A Bonobo Control factory for Folder Browsers + * + * Author: + * Miguel de Icaza (miguel@helixcode.com) + * + * (C) 2000 Helix Code, Inc. + */ + +#ifndef _FOLDER_BROWSER_FACTORY_H +#define _FOLDER_BROWSER_FACTORY_H + +#include <bonobo.h> + +BonoboControl *folder_browser_factory_new_control (const char *uri); +GList *folder_browser_factory_get_active_control_list (void); + +#endif /* _FOLDER_BROWSER_FACTORY_H */ diff --git a/mail/folder-browser.c b/mail/folder-browser.c index 60feba556f..522a6b1804 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -346,10 +346,10 @@ folder_browser_gui_init (FolderBrowser *fb) gtk_widget_show(fb->search_entry); gtk_signal_connect(GTK_OBJECT (fb->search_entry), "activate", search_activate, fb); /* gtk_signal_connect(fb->search_entry, "changed", search_activate, fb); */ - label = gtk_label_new("Search"); + label = gtk_label_new(_("Search")); gtk_widget_show(label); fb->search_menu = create_option_menu(search_options, 0, fb); - button = (GtkButton *)gtk_button_new_with_label("Save"); + button = (GtkButton *)gtk_button_new_with_label(_("Save")); gtk_widget_show((GtkWidget *)button); gtk_signal_connect((GtkObject *)button, "clicked", search_save, fb); gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)button, FALSE, FALSE, 3); 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 (); } diff --git a/mail/mail-threads.h b/mail/mail-threads.h index ab745c2ee3..b84b71d836 100644 --- a/mail/mail-threads.h +++ b/mail/mail-threads.h @@ -66,4 +66,7 @@ void mail_operation_wait_for_finish (void); gboolean mail_operations_are_executing (void); void mail_operations_terminate (void); +void mail_operations_get_status (int *busy_return, const char **message_return); +void mail_operations_update_status (void); + #endif /* defined _MAIL_THREADS_H_ */ diff --git a/mail/mail.h b/mail/mail.h index 0bcda78a61..48c7defcb0 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -1,5 +1,4 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - /* * Copyright 2000, Helix Code, Inc. (http://www.helixcode.com) * @@ -27,11 +26,6 @@ extern char *evolution_dir; -/* FIXME FIXME FIXME this sucks sucks sucks sucks */ -/* folder-browser-factory */ -void folder_browser_factory_init (void); -BonoboControl *folder_browser_factory_new_control (const char *uri); - /* mail-config */ void mail_config_druid (void); |