#!/usr/bin/perl
use warnings;
use strict;
# by Phil Letschert on gtk2-perl maillist
#It is common behaviour that the C library uses isatty(3) to decide if
+ stdout
#is line-buffered or block-buffered. When reading from a pipe to an ex
+ternal
#command the output is block-buffered, which explains the reported beh
+aviour.
#Solution is using a pseudo-terminal and connect the watcher to it, fo
+llowing is
#a complete example:
use Glib;
use IO::Pty;
my $pty = IO::Pty->new;
my $cmd = "top -d .5";
my $pid;
unless ($pid = fork) { # child process
die "problem spawning program: $!\n" unless defined $pid;
use POSIX ();
POSIX::setsid
or die "setsid failed: $!";
my $tty = $pty->slave;
my $tty_fd = $tty->fileno;
open STDIN, "<&$tty_fd" or die $!;
open STDOUT, ">&$tty_fd" or die $!;
open STDERR, ">&STDOUT" or die $!;
close $pty;
close $tty;
exec $cmd;
}
my $main_loop = Glib::MainLoop->new;
my $watcher;
$watcher = Glib::IO->add_watch( fileno( $pty ), ['in', 'hup'], \&callb
+ack);
$main_loop->run;
sub callback {
if ( $pty->eof ) {
Gtk2::Helper->remove_watch( $watcher );
close( $pty );
}
else {
my $line = $pty->getline;
print $line;
}
}
If you need to read and write to it, look at this usage: (only quickly tested :-) )
#!/usr/bin/perl
use warnings;
use strict;
use Glib;
use IO::Pty;
my $pty = IO::Pty->new;
my $cmd = "top";
my $pid;
unless ($pid = fork) { # child process
die "problem spawning program: $!\n" unless defined $pid;
use POSIX ();
POSIX::setsid
or die "setsid failed: $!";
my $tty = $pty->slave;
my $tty_fd = $tty->fileno;
open STDIN, "<&$tty_fd" or die $!;
open STDOUT, ">&$tty_fd" or die $!;
open STDERR, ">&STDOUT" or die $!;
exec $cmd;
}
my $main_loop = Glib::MainLoop->new;
my $watcher;
$watcher = Glib::IO->add_watch( fileno( $pty ), ['in', 'hup'], \&callb
+ack);
syswrite( $pty, 'l',16);
syswrite( $pty, "\n",16);
syswrite( $pty, 't',16);
syswrite( $pty, "\n",16);
syswrite( $pty, 'm',16);
syswrite( $pty, "\n",16);
$main_loop->run;
sub callback {
if ( $pty->eof ) {
Gtk2::Helper->remove_watch( $watcher );
close( $pty );
}
else {
my $line = $pty->getline;
print $line;
}
}
|