Add nice blocking stuff for the error dialog and a new get_password hook in the async toolkit

svn path=/trunk/; revision=3692
This commit is contained in:
Peter Williams
2000-06-22 16:34:33 +00:00
parent c74b334a2c
commit c14e8dd705
4 changed files with 241 additions and 41 deletions
+15 -1
View File
@@ -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.
+197 -36
View File
@@ -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;
/**
@@ -116,6 +118,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>
@@ -305,6 +328,44 @@ void mail_op_set_message( gchar *fmt, ... )
write( WRITER, &msg, sizeof( msg ) );
}
/**
* 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
@@ -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,9 +646,34 @@ 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:
*
@@ -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;
}
+3
View File
@@ -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_ */
+26 -4
View File
@@ -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;