Make the async dialogs non-modal; add cleanup callbacks in the main thread.
svn path=/trunk/; revision=3694
This commit is contained in:
@ -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
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user