Outputbox: Cannot see the output immediately
- From: kyanh <kyanh o2 pl>
- To: gtk-list gnome org
- Subject: Outputbox: Cannot see the output immediately
- Date: Mon, 4 Jul 2005 14:57:34 +0700
Hi all,
I currently maintain winefish [ http://winefish.berlios.de/ ]
From winefish, some external tools (latex, pdflatex,...) will be excuted.
The output of theses tools are expected to be appear line-by-line in the
outputbox (GUI).
But when a tool is called, Winefish is suspend until the tool finishes, then
the lines of output appear (all at once, NOT line by line as desire).
I tried but didn't understand what the reason is.
Please read the code below and give me some advice.
Thank you very much.
Regards,
--
kyanh [ http://kyanh.dotgeek.org/ ]
PS:
[code]
/* $Id: outputbox.c,v 1.2 2005/07/02 08:28:49 kyanh Exp $ */
/* Winefish LaTeX Editor (based on Bluefish HTML Editor)
* outputbox.c the output box
*
* Copyright (C) 2002 Olivier Sessink
* Modified for Winefish (C) 2005 Ky Anh <kyanh o2 pl>
* License: GPL
*/
/* the header */
static void ob_lview_row_activated_lcb( GtkTreeView *tree, GtkTreePath *path,
GtkTreeViewColumn *column, Toutputbox *ob )
{...}
static void outputbox_close_clicked_lcb( GtkWidget *widget, Toutputbox *ob )
{...}
static sig_atomic_t child_exit_status;
static void clean_up_child_process (gint signal_number)
{
/* Clean up the child process. */
gint status;
wait (&status);
/* Store its exit status in a global variable. */
child_exit_status = status;
}
static Toutputbox *init_outputbox( Tbfwin *bfwin )
{
/* we call this once */
/* Handle SIGCHLD by calling clean_up_child_process. */
struct sigaction sigchld_action;
memset (&sigchld_action, 0, sizeof (sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction (SIGCHLD, &sigchld_action, NULL);
/* create the backend ... */
return ob;
}
static void outputbox_message( Toutputbox *ob, const char *string, const char
*markup )
{
GtkTreeIter iter;
gchar *tmpstr = g_markup_escape_text(string,-1);
if (markup) {
tmpstr = g_strdup_printf("> <%s>%s</%s>", markup, string, markup);
}else{
tmpstr = g_strdup_printf("> %s", string);
}
gtk_list_store_append( GTK_LIST_STORE( ob->lstore ), &iter );
gtk_list_store_set( GTK_LIST_STORE( ob->lstore ), &iter, 2, tmpstr, -1 );
g_free(tmpstr);
/* TODO: Scroll as an Optional */
/* The Outputbox may *NOT* be shown before scrolling :) */
/* kyanh, added, 20050301 */
GtkTreePath *treepath =
gtk_tree_model_get_path( GTK_TREE_MODEL( ob->lstore ), &iter );
gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW( ob->lview ), treepath, NULL,
FALSE /* skip align */, 0, 0 );
gtk_tree_path_free( treepath );
}
static void fill_outputbox( Toutputbox *ob, const gchar *source )
{
GtkTreeIter iter;
gchar *tmp_src = NULL;
if ( ob->def->show_all_output ) {
tmp_src = g_markup_escape_text(source,-1);
gtk_list_store_append( GTK_LIST_STORE( ob->lstore ), &iter );
gtk_list_store_set( GTK_LIST_STORE( ob->lstore ), &iter, 2, tmp_src, -1 );
g_free(tmp_src);
}
}
/* kyanh, added, 20050301 */
static void free_ob( Toutputbox *ob, gboolean have_retfile )
{
if ( have_retfile ) {
/* free temporarily file */
remove_secure_dir_and_filename( ob->retfile );
DEBUG_MSG( "continue_execute: retfile=%s\n", ob->retfile );
g_free( ob->retfile );
}
g_free( ob->def->pattern );
regfree( &ob->def->preg );
g_free( ob->def->command );
g_free( ob->def );
ob->def = NULL; /* to be check for next using */
ob->pid = 0;
}
static void finish_execute( Toutputbox *ob )
{
kill( ob->pid, SIGTERM );
waitpid( ob->pid, &child_exit_status, WNOHANG );
{
gint exitcode = WEXITSTATUS( child_exit_status );
gchar *str_status = g_strdup_printf(_("Exit code: %d"), exitcode);
outputbox_message( ob, str_status, "b" );
g_free( str_status );
}
gtk_tree_view_columns_autosize( GTK_TREE_VIEW( ob->lview ) );
g_io_channel_unref( ob->io_channel );
gtk_timeout_remove( ob->pollID );
free_ob( ob, 1 );
}
/* Idea taken from SciTTEGTK.cxx */
static void continue_execute( Toutputbox *ob )
{
gsize count = 0;
GIOStatus io_status;
GError *error = NULL;
gchar *buf = NULL;
gsize terminator_pos = 0;
gboolean continued = TRUE;
while ( continued ) {
continued = FALSE;
buf = NULL;
io_status = g_io_channel_read_line( ob->io_channel, &buf, &count,
&terminator_pos, &error );
switch ( io_status ) {
case G_IO_STATUS_ERROR:
{
gchar * tmpstr;
tmpstr = g_strdup_printf( _("IOChannel Error: %s"), error->message );
outputbox_message( ob, tmpstr, "b" );
g_free( tmpstr );
finish_execute( ob );
}
break;
case G_IO_STATUS_EOF: /* without this, we dump into an infinite loop */
finish_execute( ob );
break;
case G_IO_STATUS_NORMAL:
continued = TRUE;
if ( terminator_pos < count ) {
buf[ terminator_pos ] = '\0';
}
fill_outputbox( ob, buf );
break;
default:
break;
}
}
g_free( buf );
g_clear_error( &error );
}
static void io_signal( GIOChannel *source, GIOCondition condition, Toutputbox
*ob )
{
continue_execute( ob );
}
static int poll_tool( Toutputbox *ob )
{
continue_execute( ob );
return TRUE;
}
static gint xsystem( const gchar *command, const gchar *outfile )
{
gint pid = 0;
/* fork():
create a child proccess the differs from the parent only in its PID and PPID;
the resouce ultilisation are set to 0 */
if ( ( pid = fork() ) == 0 ) {
close( 0 );
gint fh = open( outfile, O_WRONLY );
close( 1 );
dup( fh );
close( 2 );
dup( fh );
DEBUG_MSG( "xsystem: running now [%s]\n", command );
execlp( "/bin/sh", "sh", "-c", command, NULL );
exit( 127 );
}
/* This is the parent process. */
return pid;
}
static void run_command( Toutputbox *ob )
{
file_save_cb( NULL, ob->bfwin );
outputbox_message( ob, ob->def->command, "i" );
{
gchar *project_mode;
if ( main_v->props.project_mode ) {
project_mode = g_strdup( _("Project Mode: ON") );
} else {
project_mode = g_strdup( _("Project Mode: OFF") );
}
outputbox_message( ob, project_mode, "i" );
g_free( project_mode );
}
if ( ob->bfwin->current_document->filename ) {
/* if the user clicked cancel at file_save -> return */
{
gchar * tmpstring;
if ( main_v->props.project_mode && ob->bfwin->project &&
ob->bfwin->project->basedir )
{
tmpstring = g_strdup( ob->bfwin->project->basedir );
} else
{
tmpstring = g_path_get_dirname( ob->bfwin->current_document->filename );
}
/* outputbox_message(ob, g_strconcat("> Working dir: ", tmpstring, NULL));
*/
chdir( tmpstring );
g_free( tmpstring );
}
gchar *command = convert_command( ob->bfwin, ob->def->command );
outputbox_message( ob, command, "b");
ob->retfile = create_secure_dir_return_filename();
gint fd = 1;
if ( ob->retfile ) {
fd = mkfifo( ob->retfile, S_IRUSR | S_IWUSR );
if ( fd == 0 ) {
ob->pid = xsystem( command, ob->retfile );
GError *error = NULL;
ob->io_channel = g_io_channel_new_file( ob->retfile, "r", &error );
if ( ob->io_channel != NULL ) {
/* Fix the BUGS[200503]#20 */
g_io_channel_set_encoding( ob->io_channel, NULL, NULL );
g_io_add_watch( ob->io_channel, G_IO_IN, ( GIOFunc ) io_signal, ob );
/* add a background task in case there is no output from the tool */
ob->pollID = g_timeout_add( 200, ( GSourceFunc ) poll_tool, ob );
} else {
gchar *tmpstr;
tmpstr = g_strdup_printf( _("Error: %s"), error->message );
outputbox_message( ob, tmpstr, "b" );
if ( error->code == G_FILE_ERROR_INTR ) {
outputbox_message( ob, _("Hint: You may call the tool again"), "i" );
}
g_free( tmpstr );
outputbox_message( ob, _("Tool finished."), "b" );
free_ob( ob, 1 );
}
g_clear_error( &error );
}
}
if ( fd != 0 ) {
outputbox_message( ob, _("Error: Cannot create PIPE."), "b" );
free_ob( ob, 1 );
}
g_free( command );
} else {
outputbox_message( ob, _("Tool canceled."), "b" );
free_ob( ob, 0 );
}
}
void outputbox( Tbfwin *bfwin, gchar *pattern, gint file_subpat, gint
line_subpat, gint output_subpat, gchar *command, gboolean show_all_output )
{
Toutputbox * ob;
if ( bfwin->outputbox ) {
ob = OUTPUTBOX( bfwin->outputbox );
gtk_widget_show_all( ob->hbox ); /* fix BUGS[200503]#24 */
setup_toggle_item_from_widget(bfwin->menubar, N_("/View/View Outputbox"),
TRUE); /* fix BUGS[200503]#25 */
} else {
ob = init_outputbox( bfwin );
}
if ( ob->pid ) { /* stop older output box */
outputbox_message( ob, _("Tool is running. Try 'Stop' intead."), "i" );
return;
/*
gchar * tmpstr;
tmpstr = g_strdup_printf(_("Multiple calls... stopping: %s"),
ob->def->command );
outputbox_message( ob, tmpstr, "i" );
g_free( tmpstr );
finish_execute( ob );
*/
}
gtk_list_store_clear( GTK_LIST_STORE( ob->lstore ) );
ob->def = g_new0( Toutput_def, 1 );
ob->def->pattern = g_strdup( pattern );
ob->def->file_subpat = file_subpat;
ob->def->line_subpat = line_subpat;
ob->def->output_subpat = output_subpat;
ob->def->show_all_output = show_all_output;
regcomp( &ob->def->preg, ob->def->pattern, REG_EXTENDED );
ob->def->command = g_strdup( command );
/* kyanh */
ob->retfile = NULL;
ob->io_channel = NULL;
ob->pollID = 0;
ob->pid = 0;
run_command( ob );
/* gtk_widget_show_all(ob->hbox); */
}
[/code]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]