aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog16
-rw-r--r--mail/mail-threads.c233
-rw-r--r--mail/mail-threads.h3
-rw-r--r--mail/test-thread.c30
4 files changed, 241 insertions, 41 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 363bd9577b..9fe42f1379 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,4 +1,18 @@
-2000-06-22 Peter Williams <peterw@curious-george.helixcode.com>
+2000-06-22 Peter Williams <peterw@helixcode.com>
+
+ * test-thread.c (op_5): New tests for the get_password
+ hook.
+
+ * mail-threads.[ch]: New hook, mail_op_get_password, for
+ getting a user response from an async operation. The operation
+ blocks while waiting for the response. A big whole mutex
+ condition threading blocking dealie to make sure that it
+ works.
+
+ Also the error hook creates a dialog again, which also needs
+ to block its caller while we wait for the user to press ok.
+
+2000-06-22 Peter Williams <peterw@helixcode.com>
* mail-threads.c (various functions): Prettify the UI
so that the progress bar doesn't become all huge 'n stuff.
diff --git a/mail/mail-threads.c b/mail/mail-threads.c
index d0a20ee2be..c54ebd67ae 100644
--- a/mail/mail-threads.c
+++ b/mail/mail-threads.c
@@ -29,9 +29,6 @@
#include "mail.h"
#include "mail-threads.h"
-/* FIXME: support other thread types!!!! */
-#define USE_PTHREADS
-
/* 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_try, but then we also need some kind of monitor
@@ -56,9 +53,14 @@ typedef struct closure_s {
**/
typedef struct com_msg_s {
- enum com_msg_type_e { STARTING, PERCENTAGE, HIDE_PBAR, SHOW_PBAR, MESSAGE, ERROR, FINISHED } type;
+ enum com_msg_type_e { STARTING, PERCENTAGE, HIDE_PBAR, SHOW_PBAR, MESSAGE, PASSWORD, ERROR, FINISHED } type;
gfloat percentage;
gchar *message;
+
+ /* Password stuff */
+ gchar **reply;
+ gboolean secret;
+ gboolean *success;
} com_msg_t;
/**
@@ -117,6 +119,22 @@ static int compipe[2] = { -1, -1 };
GIOChannel *chan_reader = NULL;
/**
+ * @modal_cond: 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 prototypes
**/
@@ -126,9 +144,14 @@ static void *dispatch_func( void *data );
static void check_compipe( 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 get_password( com_msg_t *msg );
+static void get_password_cb( gchar *string, gpointer data );
/* Pthread code */
-#ifdef USE_PTHREADS
+/* FIXME: support other thread types!!!! */
+
+#ifdef G_THREADS_IMPL_POSIX
#include <pthread.h>
@@ -306,6 +329,44 @@ void mail_op_set_message( gchar *fmt, ... )
}
/**
+ * mail_op_get_password:
+ * @prompt: the question put to the user
+ * @secret: whether the dialog box shold print stars when the user types
+ * @dest: where to store the reply
+ *
+ * Asks the user for a password (or string entry in general). Waits for
+ * the user's response. On success, returns TRUE and @dest contains the
+ * response. On failure, returns FALSE and @dest contains the error
+ * message.
+ **/
+
+gboolean mail_op_get_password( gchar *prompt, gboolean secret, gchar **dest )
+{
+ com_msg_t msg;
+ gboolean result;
+
+ msg.type = PASSWORD;
+ msg.secret = secret;
+ msg.message = prompt;
+ msg.reply = dest;
+ msg.success = &result;
+
+ (*dest) = NULL;
+
+ G_LOCK( modal_lock );
+
+ write( 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 );
+
+ return result;
+}
+
+/**
* mail_op_error:
* @fmt: printf-style format string for the error
* @...: arguments to the format string
@@ -318,13 +379,21 @@ void mail_op_error( gchar *fmt, ... )
{
com_msg_t msg;
va_list val;
-
+
va_start( val, fmt );
msg.type = ERROR;
msg.message = g_strdup_vprintf( fmt, val );
va_end( val );
+ G_LOCK( modal_lock );
+
+ modal_may_proceed = FALSE;
write( 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 );
}
/**
@@ -342,6 +411,18 @@ void mail_operation_wait_for_finish( void )
}
}
+/**
+ * mail_operations_are_executing:
+ *
+ * Returns TRUE if operations are being executed asynchronously
+ * when called, FALSE if not.
+ */
+
+gboolean mail_operations_are_executing( void )
+{
+ return mail_operation_in_progress;
+}
+
/* ** Static functions **************************************************** */
/**
@@ -418,6 +499,10 @@ static void check_compipe( void )
chan_reader = g_io_channel_unix_new( READER );
g_io_add_watch( chan_reader, G_IO_IN, read_msg, NULL );
+
+ /* Misc */
+ modal_cond = g_cond_new();
+
}
/**
@@ -480,33 +565,36 @@ static void *dispatch_func( void *data )
static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer userdata )
{
- com_msg_t msg;
+ com_msg_t *msg;
closure_t *clur;
GSList *temp;
guint size;
- #if 0
- GtkWidget *err_dialog;
- #else
- gchar *errmsg;
- #endif
- g_io_channel_read( source, (gchar *) &msg,
- sizeof( msg ) / sizeof( gchar ),
+ msg = g_new0( com_msg_t, 1 );
+
+ g_io_channel_read( source, (gchar *) msg,
+ sizeof( com_msg_t ) / sizeof( gchar ),
&size );
- if( size != sizeof( msg ) ) {
+ if( size != sizeof( com_msg_t ) ) {
g_warning( _("Incomplete message written on pipe!") );
- msg.type = ERROR;
- msg.message = g_strdup( _("Error reading commands from dispatching thread.") );
+ msg->type = ERROR;
+ msg->message = g_strdup( _("Error reading commands from dispatching thread.") );
}
- switch( msg.type ) {
+ /* This is very important, though I'm not quite sure why
+ * it is as we are in the main thread right now.
+ */
+
+ GDK_THREADS_ENTER();
+
+ switch( msg->type ) {
case STARTING:
- gtk_label_set_text( GTK_LABEL( queue_window_message ), 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 );
break;
case PERCENTAGE:
- gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), msg.percentage );
+ gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), msg->percentage );
break;
case HIDE_PBAR:
gtk_widget_hide( GTK_WIDGET( queue_window_progress ) );
@@ -516,28 +604,22 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
break;
case MESSAGE:
gtk_label_set_text( GTK_LABEL( queue_window_message ),
- msg.message );
- g_free( msg.message );
+ msg->message );
+ g_free( msg->message );
+ break;
+ case PASSWORD:
+ g_assert( msg->reply );
+ g_assert( msg->success );
+ get_password( msg );
break;
case ERROR:
- #if 0
- /* FIXME FIXME: the gnome_dialog_ functions are causing coredumps
- * on my machine! Every time, threads or not... "IMLIB ERROR: Cannot
- * allocate XImage buffer". Until then, work around
- */
- err_dialog = gnome_error_dialog( msg.message );
- gnome_dialog_run_and_close( GNOME_DIALOG( err_dialog ) );
- #else
- errmsg = g_strdup_printf( "ERROR: %s", msg.message );
- gtk_label_set_text( GTK_LABEL( queue_window_message ),
- errmsg );
- g_free( errmsg );
- #endif
- g_free( msg.message );
+ show_error( msg );
break;
+
/* Don't fall through; dispatch_func does the FINISHED
* call for us
*/
+
case FINISHED:
if( op_queue == NULL ) {
/* All done! */
@@ -564,10 +646,35 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
break;
}
+ GDK_THREADS_LEAVE();
+ g_free( msg );
return TRUE;
}
/**
+ * show_error:
+ *
+ * Show the error dialog and wait for user OK
+ **/
+
+static void show_error( com_msg_t *msg )
+{
+ GtkWidget *err_dialog;
+
+ err_dialog = gnome_error_dialog( msg->message );
+ g_free( msg->message );
+
+ G_LOCK( modal_lock );
+
+ modal_may_proceed = FALSE;
+ gnome_dialog_run_and_close( GNOME_DIALOG( err_dialog ) );
+ modal_may_proceed = TRUE;
+
+ g_cond_signal( modal_cond );
+ G_UNLOCK( modal_lock );
+}
+
+/**
* remove_next_pending:
*
* Remove an item from the list of pending items. If
@@ -593,3 +700,57 @@ static void remove_next_pending( void )
if( g_list_next( children ) == NULL )
gtk_widget_hide( queue_window_pending );
}
+
+/**
+ * get_password:
+ *
+ * Ask for a password and put the answer in *(msg->reply)
+ **/
+
+static void get_password( com_msg_t *msg )
+{
+ GtkWidget *dialog;
+ gint ret;
+
+ dialog = gnome_request_dialog( msg->secret, msg->message, NULL,
+ 0, get_password_cb, msg,
+ NULL );
+
+
+ G_LOCK( modal_lock );
+
+ modal_may_proceed = FALSE;
+
+ if( dialog == NULL ) {
+ *(msg->success) = FALSE;
+ *(msg->reply) = g_strdup( _("Could not create dialog box.") );
+ goto done;
+ }
+
+ *(msg->reply) = NULL;
+ ret = gnome_dialog_run_and_close( GNOME_DIALOG(dialog) );
+
+ /* The -1 check doesn't seem to work too well. */
+ if( /*ret == -1 ||*/ *(msg->reply) == NULL ) {
+ *(msg->success) = FALSE;
+ *(msg->reply) = g_strdup( _("User cancelled query.") );
+ goto done;
+ }
+
+ *(msg->success) = TRUE;
+
+ done:
+ modal_may_proceed = TRUE;
+ g_cond_signal( modal_cond );
+ G_UNLOCK( modal_lock );
+}
+
+static void get_password_cb( gchar *string, gpointer data )
+{
+ com_msg_t *msg = (com_msg_t *) data;
+
+ if (string)
+ *(msg->reply) = g_strdup( string );
+ else
+ *(msg->reply) = NULL;
+}
diff --git a/mail/mail-threads.h b/mail/mail-threads.h
index 89fa439fa9..a56c6433a6 100644
--- a/mail/mail-threads.h
+++ b/mail/mail-threads.h
@@ -38,8 +38,11 @@ void mail_op_hide_progressbar( void );
void mail_op_show_progressbar( void );
void mail_op_set_message( gchar *fmt, ... ) G_GNUC_PRINTF( 1, 2 );
void mail_op_error( gchar *fmt, ... ) G_GNUC_PRINTF( 1, 2 );
+gboolean mail_op_get_password( gchar *prompt, gboolean secret, gchar **dest );
/* Wait for the async operations to finish */
void mail_operation_wait_for_finish( void );
+gboolean mail_operations_are_executing( void );
+
#endif /* defined _MAIL_THREADS_H_ */
diff --git a/mail/test-thread.c b/mail/test-thread.c
index f2b46be763..a08cd63702 100644
--- a/mail/test-thread.c
+++ b/mail/test-thread.c
@@ -4,6 +4,7 @@
#include <unistd.h>
#include <glib.h>
#include <gtk/gtk.h>
+#include <libgnomeui/libgnomeui.h>
#include <stdio.h>
#include "mail-threads.h"
@@ -11,6 +12,7 @@ static void op_1( gpointer userdata );
static void op_2( gpointer userdata );
static void op_3( gpointer userdata );
static void op_4( gpointer userdata );
+static void op_5( gpointer userdata );
static gboolean queue_ops( void );
static gboolean queue_ops( void )
@@ -24,7 +26,7 @@ static gboolean queue_ops( void )
mail_operation_try( "The Mysterious Message Setter", op_2, NULL );
mail_operation_try( "The Error Dialog of No Return", op_3, NULL );
- for( i = 0; i < 7; i++ ) {
+ for( i = 0; i < 3; i++ ) {
sprintf( buf, "Queue Filler %d", i );
mail_operation_try( buf, op_4, GINT_TO_POINTER( i ) );
}
@@ -41,6 +43,8 @@ static gboolean queue_ops( void )
g_message( "Ops done -- more, more!" );
+ mail_operation_try( "Dastardly Password Stealer", op_5, NULL );
+
for( i = 0; i < 3; i++ ) {
sprintf( buf, "Queue Filler %d", i );
mail_operation_try( buf, op_4, GINT_TO_POINTER( i ) );
@@ -60,7 +64,7 @@ static void op_1( gpointer userdata )
mail_op_show_progressbar();
mail_op_set_message( "Watch the progress bar!" );
- for( pct = 0.0; pct < 1.0; pct += 0.1 ) {
+ for( pct = 0.0; pct < 1.0; pct += 0.2 ) {
sleep( 1 );
mail_op_set_percentage( pct );
}
@@ -71,7 +75,7 @@ static void op_2( gpointer userdata )
int i;
mail_op_hide_progressbar();
- for( i = 10; i > 0; i-- ) {
+ for( i = 5; i > 0; i-- ) {
mail_op_set_message( "%d", i );
sleep( 1 );
}
@@ -103,10 +107,28 @@ static void op_4( gpointer userdata )
sleep( 1 );
}
+static void op_5( gpointer userdata )
+{
+ gchar *pass;
+ gboolean ret;
+
+ mail_op_show_progressbar();
+ mail_op_set_percentage( 0.5 );
+
+ ret = mail_op_get_password( "What is your super-secret password?", TRUE, &pass );
+
+ if( ret == FALSE )
+ mail_op_set_message( "Oh no, you cancelled! : %s", pass );
+ else
+ mail_op_set_message( "\"%s\", you said?", pass );
+
+ sleep( 1 );
+}
+
int main( int argc, char **argv )
{
g_thread_init( NULL );
- gtk_init( &argc, &argv );
+ gnome_init( "test-thread", "0.0", argc, argv );
gtk_idle_add( (GtkFunction) queue_ops, NULL );
gtk_main();
return 0;