#!/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; }