• 0

GTK PIPE


Question

hello every1,

i'm trying to capture stdout.stderr of a child prosses while using gtk. i'v found the following codes and i changed it a little and it works perfect

void run_program( char *cmd)
{

	gint	stdin_pipe[2];
	gint	stdout_pipe[2];
	gint	stderr_pipe[2];

	/*  Define buffs to copy your reads from the pipes to */
	gchar buffer[BUFSIZ+1];
	gchar buffer_err[BUFSIZ+1];

	/* Def some vars to hold your results */
	gint fork_result;
	gint data_processed;
	gint data_processed_err;
	gint nchars;
	nchars=0;

	/* Clear Your Buffers */
	memset(buffer, '\0', sizeof(buffer));
	memset(buffer_err, '\0', sizeof(buffer_err));

	/* Do the fork and pipe - watch closely here */

	/* Create pipes to read from and write too */
	if( (pipe(stdin_pipe) == 0)
		&& (pipe(stdout_pipe) == 0)
		&& (pipe(stderr_pipe) == 0)
	  )
	{
		/* Perform the fork */
		fork_result = fork();

		/* fork attempt was not successful */
		if(fork_result == -1)
		{
			fprintf(stderr, "Fork Failure\n");
			exit(EXIT_FAILURE);
		}

		/*  We're in the child process! */
		else if(fork_result == 0)
		{
			/* Close the Child process' STDIN */
			close(0);

			/* Duplicate the Child's STDIN to the stdin_pipe file descriptor */
			dup(stdin_pipe[0]);

			/* Close the read and write to for the pipe for the child.  The child will now only be able to read from it's STDIN (which is our pipe). */ 
			close(stdin_pipe[0]);
			close(stdin_pipe[1]);

			/* Close the Child process' STDOUT */
			close(1);
			dup(stdout_pipe[1]);
			close(stdout_pipe[0]);
			close(stdout_pipe[1]);

			/* Close the Child process' STDERR */
			close(2);
			dup(stderr_pipe[1]);
			close(stderr_pipe[0]);
			close(stderr_pipe[1]);

			/*  Make the system call to run the program. */
			system(cmd);

			/*  If javac didn't take over the exec call failed. */
			exit(EXIT_FAILURE);
		}

		/* We're in the parent process. */
		else
		{
			/* Close STDIN for read & write and close STDERR for write */
			close(stdin_pipe[0]);
			close(stdin_pipe[1]);
			close(stderr_pipe[1]);

			while(1)
			{
				data_processed_err=read(stderr_pipe[0],buffer_err,BUFSIZ);
				if(data_processed_err == 0) break;
				//addMsgInfo( buffer_err );
				Msg_dialog("Error",buffer_err);
			}
			/* Close the read end of STDERR */

			close(stderr_pipe[0]);
			/* Close the write end of STDOUT */
			close(stdout_pipe[1]);

			while(1)
			{
				/* Read BUFSIZ of STDOUT data */ 
				data_processed=read(stdout_pipe[0],buffer,BUFSIZ);

				/* Break this loop when we're read all of the STDOUT data */
				if(data_processed == 0) break;

				/* Insert it into our gtktextbox */
				addMsgInfo( buffer );
			}

			/* Close STDOUT for reading */
			close(stdout_pipe[0]);
		}
	}
}

but if i call the following function (clicking that button)

void on_button1_clicked(GtkButton *button, gpointer user_data){

GtkWidget *dialog;
GtkFileFilter *filter = gtk_file_filter_new ();
GtkFileFilter *filter2 = gtk_file_filter_new ();
GtkWidget *parent = lookup_widget(GTK_WIDGET(button), "win");
GtkWidget *entry  = lookup_widget(GTK_WIDGET(button), "entry1");
dialog = gtk_file_chooser_dialog_new ("Open Image File",
					  parent,
					  GTK_FILE_CHOOSER_ACTION_OPEN,
					  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
					  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
					  NULL);
gtk_file_filter_set_name		(filter,"Iso Files");
gtk_file_filter_set_name		(filter2,"All Files");
gtk_file_filter_add_pattern (filter, "*.iso");
gtk_file_filter_add_pattern (filter2, "*.*");
gtk_file_chooser_add_filter  (GTK_FILE_CHOOSER (dialog), filter);
gtk_file_chooser_add_filter  (GTK_FILE_CHOOSER (dialog), filter2);

if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
  {
	char *filename;

	filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
	gtk_entry_set_text(GTK_ENTRY(entry),filename);
	g_free (filename);
  }

gtk_widget_destroy (dialog);

}

befor using the first one my program chrashes. has anyone any idea? i can't actually find any relationship bitween these two functions. but with a little experiment i realized it crashesh if i make any dialog (filechooser or not) in my programm.

thankx

Ammsa

Edited by wildworld_ammsa
Link to comment
https://www.neowin.net/forum/topic/408161-gtk-pipe/
Share on other sites

4 answers to this question

Recommended Posts

  • 0

It's the while (1) loops. If you have those going in the same thread as your main loop, it will tie it up and the windows don't get a chance to refresh.

Since you're using GTK, you may want to check out IO Channels in Glib. http://developer.gnome.org/doc/API/2.0/gli...O-Channels.html

They let you call a function every time there's input available and they won't tie up your GUI.

Link to comment
https://www.neowin.net/forum/topic/408161-gtk-pipe/#findComment-586925216
Share on other sites

  • 0

Thank you. I think it works fine now. here is what coud make out of it:

void addMsgInfo( gchar *buf ){

	GtkWidget *textview = lookup_widget(GTK_WIDGET(generlanwin), "textview1");
	GtkTextBuffer *buffer;
	GtkTextIter  enditer, beginditer;
	buffer=gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
	gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &enditer);
	gtk_text_buffer_insert(buffer, &enditer,buf, -1);
	g_idle_add ( (GSourceFunc) scroll_to_end, NULL );
}

void scroll_to_end(){

  GtkTextBuffer *buffer;
  GtkTextIter  enditer;
  GtkWidget *textview = lookup_widget(GTK_WIDGET(generlanwin), "textview1");
  buffer=gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
  gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &enditer);
  gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(textview), &enditer, 0, TRUE, 0.0, 0.0);
}

gboolean  on_pipe_error 					(GIOChannel *source,
											 GIOCondition condition,
											 gpointer data)
{
	printf("ahan\n");
	gchar buffer_err[BUFSIZ+1];
	gsize *bytes_read;
	g_io_channel_read(source,buffer_err, BUFSIZ,bytes_read);
	Msg_dialog("Error",buffer_err);
}
gboolean  on_pipe_output 					(GIOChannel *source,
											 GIOCondition condition,
											 gpointer data)
{
	gchar buffer[BUFSIZ+1];
	gsize *bytes_read;
	g_io_channel_read(source,buffer, BUFSIZ,bytes_read);
	addMsgInfo( buffer );
}

void run_program2(gchar  **argv){


	GError  *error = NULL;
	GPid	 child_pid;
	gint	 stdout_fd;
	gint	 stderr_fd;

	g_spawn_async_with_pipes(
		NULL,			/* use current working directory							 */
		argv,			/* the program we want to run and parameters for it		  */
		NULL,			/* use the environment variables that are set for the parent */
		(GSpawnFlags) G_SPAWN_SEARCH_PATH   /* look for wget in $PATH			  */
			  | G_SPAWN_DO_NOT_REAP_CHILD,  /* we'll check the exit status ourself */
		NULL,			/* don't need a child setup function either				  */
		NULL,			/* and therefore no child setup func data argument		   */
		&child_pid,	  /* where to store the child's PID							*/
		NULL,			/* don't need standard input (=> will be /dev/null)		  */
		&stdout_fd,	  /* where to put wget's stdout file descriptor				*/
		&stderr_fd,	  /* where to put wget's stderr file descriptor				*/
		&error);

	GIOChannel *errchannel=g_io_channel_unix_new(stderr_fd);
	g_io_add_watch (errchannel, G_IO_IN|G_IO_PRI|G_IO_ERR, on_pipe_error, NULL);

	GIOChannel *outchannel=g_io_channel_unix_new(stdout_fd);
	g_io_add_watch (outchannel, G_IO_IN|G_IO_PRI|G_IO_ERR, on_pipe_output, NULL);

}

i posted the "complete" code here beacuase i had to do a lot of searching to make it word. if anybody else needs it, it's better to also take a look at this:

http://scentric.net/tmp/spawn-async-with-pipes-gtk.c

Link to comment
https://www.neowin.net/forum/topic/408161-gtk-pipe/#findComment-586926054
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.