Make the async dialogs non-modal; add cleanup callbacks in the main thread.

svn path=/trunk/; revision=3694
This commit is contained in:
Peter Williams
2000-06-22 20:31:01 +00:00
parent a3a3ee2b14
commit 855dff022c
4 changed files with 122 additions and 56 deletions

View File

@ -1,3 +1,20 @@
2000-06-22 Peter Williams <peterw@curious-george.helixcode.com>
* mail-threads.c: Make the dialog boxes for error and
question non-modal. They're modal relative to the dispatch
thread, but before they would also eg lock up the toolbar
buttons (while the menus, managed by another process, were
active -- a weird effect).
2000-06-22 Peter Williams <peterw@curious-george.helixcode.com>
* mail-threads.[ch]: Extra argument to mail_operation_try:
'cleanup', a function to be called in the main thread after
the dispatcher thread exits. gtk_object_destroy's et al may
attempt to unmap windows so we can't do them in the dispatcher
thread :-(
* test-thread.c: Updated with demo of new argument working.
2000-06-22 Peter Williams <peterw@helixcode.com>
* test-thread.c (op_5): New tests for the get_password

View File

@ -41,7 +41,8 @@
**/
typedef struct closure_s {
void (*func)( gpointer );
void (*callback)( gpointer );
void (*cleanup)( gpointer );
gpointer data;
gchar *prettyname;
@ -56,7 +57,10 @@ typedef struct com_msg_s {
enum com_msg_type_e { STARTING, PERCENTAGE, HIDE_PBAR, SHOW_PBAR, MESSAGE, PASSWORD, ERROR, FINISHED } type;
gfloat percentage;
gchar *message;
void (*func)( gpointer );
gpointer userdata;
/* Password stuff */
gchar **reply;
gboolean secret;
@ -145,8 +149,10 @@ 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 show_error_clicked( void );
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 );
/* Pthread code */
/* FIXME: support other thread types!!!! */
@ -177,6 +183,7 @@ choke on this: no thread type defined
* mail_operation_try:
* @description: A user-friendly string describing the operation.
* @callback: the function to call in another thread to start the operation
* @cleanup: the function to call in the main thread when the callback is finished
* @user_data: extra data passed to the callback
*
* Runs a mail operation asynchronously. If no other operation is running,
@ -192,13 +199,15 @@ choke on this: no thread type defined
**/
gboolean
mail_operation_try( const gchar *description, void (*callback)( gpointer ), gpointer user_data )
mail_operation_try( const gchar *description, void (*callback)( gpointer ),
void (*cleanup)( gpointer ), gpointer user_data )
{
closure_t *clur;
g_assert( callback );
clur = g_new( closure_t, 1 );
clur->func = callback;
clur->callback = callback;
clur->cleanup = cleanup;
clur->data = user_data;
clur->prettyname = g_strdup( description );
@ -541,9 +550,11 @@ static void *dispatch_func( void *data )
msg.message = clur->prettyname;
write( WRITER, &msg, sizeof( msg ) );
(clur->func)( clur->data );
(clur->callback)( clur->data );
msg.type = FINISHED;
msg.func = clur->cleanup; /* NULL is ok */
msg.userdata = clur->data;
write( WRITER, &msg, sizeof( msg ) );
g_free( clur->prettyname );
@ -592,28 +603,35 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
case STARTING:
gtk_label_set_text( GTK_LABEL( queue_window_message ), msg->message );
gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), 0.0 );
g_free( msg );
break;
case PERCENTAGE:
gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), msg->percentage );
g_free( msg );
break;
case HIDE_PBAR:
gtk_widget_hide( GTK_WIDGET( queue_window_progress ) );
g_free( msg );
break;
case SHOW_PBAR:
gtk_widget_show( GTK_WIDGET( queue_window_progress ) );
g_free( msg );
break;
case MESSAGE:
gtk_label_set_text( GTK_LABEL( queue_window_message ),
msg->message );
g_free( msg->message );
g_free( msg );
break;
case PASSWORD:
g_assert( msg->reply );
g_assert( msg->success );
get_password( msg );
/* don't free msg! done later */
break;
case ERROR:
show_error( msg );
g_free( msg );
break;
/* Don't fall through; dispatch_func does the FINISHED
@ -621,6 +639,9 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
*/
case FINISHED:
if( msg->func )
(msg->func)( msg->userdata );
if( op_queue == NULL ) {
/* All done! */
gtk_widget_hide( queue_window );
@ -640,6 +661,7 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
/* Run run run little process */
dispatch( clur );
}
g_free( msg );
break;
default:
g_warning( _("Corrupted message from dispatching thread?") );
@ -647,33 +669,9 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u
}
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:
*
@ -701,6 +699,42 @@ static void remove_next_pending( void )
gtk_widget_hide( queue_window_pending );
}
/**
* 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 );
gnome_dialog_set_close( GNOME_DIALOG(err_dialog), TRUE );
gtk_signal_connect( GTK_OBJECT( err_dialog ), "clicked", (GtkSignalFunc) show_error_clicked, NULL );
g_free( msg->message );
G_LOCK( modal_lock );
modal_may_proceed = FALSE;
/*gnome_dialog_run_and_close( GNOME_DIALOG( err_dialog ) );*/
gtk_widget_show( GTK_WIDGET( err_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( void )
{
modal_may_proceed = TRUE;
g_cond_signal( modal_cond );
G_UNLOCK( modal_lock );
}
/**
* get_password:
*
@ -710,12 +744,12 @@ static void remove_next_pending( void )
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 );
gnome_dialog_set_close( GNOME_DIALOG(dialog), TRUE );
gtk_signal_connect( GTK_OBJECT( dialog ), "clicked", get_password_clicked, msg );
G_LOCK( modal_lock );
@ -724,25 +758,14 @@ static void get_password( com_msg_t *msg )
if( dialog == NULL ) {
*(msg->success) = FALSE;
*(msg->reply) = g_strdup( _("Could not create dialog box.") );
goto done;
modal_may_proceed = TRUE;
g_cond_signal( modal_cond );
G_UNLOCK( modal_lock );
} else {
*(msg->reply) = NULL;
/*ret = gnome_dialog_run_and_close( GNOME_DIALOG(dialog) );*/
gtk_widget_show( GTK_WIDGET( dialog ) );
}
*(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 )
@ -754,3 +777,22 @@ static void get_password_cb( gchar *string, gpointer data )
else
*(msg->reply) = NULL;
}
static void get_password_clicked( GnomeDialog *dialog, gint button, gpointer user_data )
{
com_msg_t *msg = (com_msg_t *) user_data;
if( button == 1 || *(msg->reply) == NULL ) {
*(msg->success) = FALSE;
*(msg->reply) = g_strdup( _("User cancelled query.") );
goto done;
}
*(msg->success) = TRUE;
done:
g_free( msg );
modal_may_proceed = TRUE;
g_cond_signal( modal_cond );
G_UNLOCK( modal_lock );
}

View File

@ -29,6 +29,7 @@
gboolean mail_operation_try( const gchar *description,
void (*callback)( gpointer ),
void (*cleanup)( gpointer ),
gpointer user_data );
/* User interface hooks for the other thread */

View File

@ -13,6 +13,7 @@ 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 void done( gpointer userdata );
static gboolean queue_ops( void );
static gboolean queue_ops( void )
@ -22,13 +23,13 @@ static gboolean queue_ops( void )
g_message( "Top of queue_ops" );
mail_operation_try( "The Crawling Progress Bar of Doom", op_1, NULL );
mail_operation_try( "The Mysterious Message Setter", op_2, NULL );
mail_operation_try( "The Error Dialog of No Return", op_3, NULL );
mail_operation_try( "The Crawling Progress Bar of Doom", op_1, done, "op1 finished" );
mail_operation_try( "The Mysterious Message Setter", op_2, done, "op2 finished" );
mail_operation_try( "The Error Dialog of No Return", op_3, done, "op3 finished" );
for( i = 0; i < 3; i++ ) {
sprintf( buf, "Queue Filler %d", i );
mail_operation_try( buf, op_4, GINT_TO_POINTER( i ) );
mail_operation_try( buf, op_4, NULL, GINT_TO_POINTER( i ) );
}
g_message( "Waiting for finish..." );
@ -36,18 +37,18 @@ static gboolean queue_ops( void )
g_message( "Ops done -- queue some more!" );
mail_operation_try( "Progress Bar Redux", op_1, NULL );
mail_operation_try( "Progress Bar Redux", op_1, NULL, NULL );
g_message( "Waiting for finish again..." );
mail_operation_wait_for_finish();
g_message( "Ops done -- more, more!" );
mail_operation_try( "Dastardly Password Stealer", op_5, NULL );
mail_operation_try( "Dastardly Password Stealer", op_5, NULL, NULL );
for( i = 0; i < 3; i++ ) {
sprintf( buf, "Queue Filler %d", i );
mail_operation_try( buf, op_4, GINT_TO_POINTER( i ) );
mail_operation_try( buf, op_4, NULL, GINT_TO_POINTER( i ) );
}
g_message( "Waiting for finish AGAIN..." );
@ -125,6 +126,11 @@ static void op_5( gpointer userdata )
sleep( 1 );
}
static void done( gpointer userdata )
{
g_message( "Operation done: %s", (gchar *) userdata );
}
int main( int argc, char **argv )
{
g_thread_init( NULL );