From 855dff022c610063a9524c19386f9e2863b88ae7 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 22 Jun 2000 20:31:01 +0000 Subject: Make the async dialogs non-modal; add cleanup callbacks in the main thread. svn path=/trunk/; revision=3694 --- mail/ChangeLog | 17 +++++++ mail/mail-threads.c | 134 ++++++++++++++++++++++++++++++++++------------------ mail/mail-threads.h | 1 + mail/test-thread.c | 20 +++++--- 4 files changed, 119 insertions(+), 53 deletions(-) diff --git a/mail/ChangeLog b/mail/ChangeLog index 9fe42f1379..ad42b1fa5e 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,20 @@ +2000-06-22 Peter Williams + * 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 + + * 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 * test-thread.c (op_5): New tests for the get_password diff --git a/mail/mail-threads.c b/mail/mail-threads.c index c54ebd67ae..8dc6ef2d48 100644 --- a/mail/mail-threads.c +++ b/mail/mail-threads.c @@ -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,14 +758,31 @@ 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) ); +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; +} - /* The -1 check doesn't seem to work too well. */ - if( /*ret == -1 ||*/ *(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; @@ -740,17 +791,8 @@ static void get_password( com_msg_t *msg ) *(msg->success) = TRUE; done: + g_free( msg ); 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 a56c6433a6..d3f2a184e3 100644 --- a/mail/mail-threads.h +++ b/mail/mail-threads.h @@ -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 */ diff --git a/mail/test-thread.c b/mail/test-thread.c index a08cd63702..9c62e7f78c 100644 --- a/mail/test-thread.c +++ b/mail/test-thread.c @@ -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 ); -- cgit v1.2.3