in reply to Gtk2 app on Windows, driving a background process

(OP here, I just don't have my login on this machine)

Shortly after posting, I did find a solution of sorts, here on Perlmonks, of all places. With some modification to the code found here: Non-blocking Reads from Pipe Filehandle, I was able to make a short example GUI program that seems to work.

#!/usr/bin/perl use strict; use warnings; use Gtk2 -init; use Win32API::File qw[ GetOsFHandle ]; use Win32::API qw(); use IPC::Open2; use constant ERROR_BROKEN_PIPE => 109; my $PeekNamedPipe = Win32::API::More->new( 'Kernel32', q[ BOOL PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, DWORD *lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage ) ] ) or die $^E; sub nonblocking_readline { my $fh = shift; my $osfh = GetOsFHandle( $fh ) or die $^E; my( $bufsize, $buffer, $cAvail, $read ) = ( 1024, chr(0)x1024, 0, +0 ); $PeekNamedPipe->Call( $osfh, $buffer, $bufsize, $read, $cAvail, 0 +) or $^E == ERROR_BROKEN_PIPE or die $^E; return if $^E == ERROR_BROKEN_PIPE; my $eolPos = 1+index $buffer, $/; return '' unless $eolPos; sysread( $fh, $buffer, $eolPos ) or die $!; return $buffer; } my $cmd = 'bc.exe'; my ($reader, $writer); my $pid = open2($reader, $writer, $cmd); my $w = Gtk2::Window->new(); my $vbox = Gtk2::VBox->new(); my $l = Gtk2::Label->new(); my $i = Gtk2::Entry->new(); $w->signal_connect(destroy => \&cleanup); $i->signal_connect(activate => sub { my $text = $i->get_text(); print {$writer} $text . "\n"; print STDERR ">>> $text\n"; $i->set_text(''); }); Glib::Timeout->add(100, \&update_label); #Glib::IO->add_watch(fileno($reader), ['in', 'hup'], \&update_label); +# blocks $l->set_text("init $pid\n"); $vbox->add($i); $vbox->add($l); $w->add($vbox); $w->show_all(); Gtk2->main(); sub update_label { if ($reader) { my $read = nonblocking_readline($reader); if (length $read) { chomp $read; chop $read; print STDERR "<<< $read\n"; $l->set_text($read); } elsif (not defined $read) { cleanup(); } } return Glib::SOURCE_CONTINUE; } sub cleanup { kill 'TERM', $pid; # XXX Gtk2->main_quit; }

This program puts up a small GUI window and sends the contents of the input field to the background process (which is bc.exe from here), and puts the result in a label.

You can observe that the GUI is responsive by pasting an expression that takes a long time to calculate (e.g. scale = 20; a = 0; for (i=1; i < 1000000; i++) { a += 1/i^2 }; sqrt(6*a)) and dragging the window around.

Glib IO watchers don't work here either so I had to poll the reader pipe in a Glib timeout, which is not optimal. But still, it's better than nothing.

Thanks, BrowserUK-from-10-years-ago and BrowserUK in the present!