stumped by graphics display problem...


K

kj

I need to generate and view a large number of data plots. My plan
for this was to have a loop that at each iteration would generate
the plot, display it, and wait for keyboard input before proceeding
to the next iteration. (FWIW, this code is to run on a remote
Linux system, and the display should take place on a local Mac OS
X workstation running an X11 server.)

The code I've written succeeds in displaying the graph, but somehow
the displaying of the graph the script's execution, so the script
does not get to request for keyboard input to move on to the next
iteration.

The relevant portion of the code is shown below. (In this snippet
I have omitted all error checking and other such details for clarity;
still, I confirmed that this simplified version of the code displays
the behavior I described above.) The place where the problem occurs
is indicated with "###".

# unbuffer selected output handle (STDOUT)
$| = 1;

for my $data ( @data ) {
my $chart = GD::Graph::lines->new( 400, 300 );
$chart->set( transparent => 0 );

# next line produces a GD::Image object
my $gd = $chart->plot( $data );

open my $IMG, '|-', 'display';
print $IMG $gd->png;

# display won't happen without this line!
close $IMG;

### script stalls before executing the next line

print "Press any key to continue... ";
ReadMode 'cbreak';
ReadKey( 0 );
ReadMode 'normal';
print "\n";
}

If someone could explain to me why this snippet is not behaving as
I expect it to I'd be most thankful.

BTW, I found it surprising that I needed to close the $IMG handle
for the display to appear; turning on autoflush on the handle was
not enough.

Maybe the problem with the code above has more to do with a
peculiarity of the 'display' command (from the ImageMagick suite)
than with the Perl code? If so, is there a better way to achieve
what I trying to do?

Any suggestions or comments would be much appreciated.

TIA!

kj
 
Ad

Advertisements

G

Greg Bacon

: [...]
: # display won't happen without this line!
: close $IMG;
:
: ### script stalls before executing the next line

The perlfunc(1) manpage's section on the close operator makes the
following note: "Closing a pipe also waits for the process executing
on the pipe to complete . . ."

Hope this helps,
Greg
 
M

Mumia W.

[...]
open my $IMG, '|-', 'display';
print $IMG $gd->png;

# display won't happen without this line!
close $IMG;

### script stalls before executing the next line

print "Press any key to continue... ";
ReadMode 'cbreak';
ReadKey( 0 );
ReadMode 'normal';
print "\n";
}
[...]

The method used to remotely display X programs is different from the
method used to remotely display console programs, and Term::ReadKey
doesn't have internal support for remote displays.

Trying to mix console type user-interaction with graphical
user-interaction will confound you. It's best just to make your program
fully graphical with one of the toolkits available: Gtk, Perl-Tk, etc.
 
K

kj

In said:
[...]
open my $IMG, '|-', 'display';
print $IMG $gd->png;

# display won't happen without this line!
close $IMG;

### script stalls before executing the next line

print "Press any key to continue... ";
ReadMode 'cbreak';
ReadKey( 0 );
ReadMode 'normal';
print "\n";
}
[...]
The method used to remotely display X programs is different from the
method used to remotely display console programs, and Term::ReadKey
doesn't have internal support for remote displays.
Trying to mix console type user-interaction with graphical
user-interaction will confound you. It's best just to make your program
fully graphical with one of the toolkits available: Gtk, Perl-Tk, etc.

There's no shortage of fully graphical programs for viewing PNG
files, but what I need is a viewer that I can control *entirely*
from the keyboard. Are you saying that this would be too difficult
to program?

kj
 
M

Mumia W.

[...]
Trying to mix console type user-interaction with graphical
user-interaction will confound you [....]

And me too. Mr. Bacon's comment is correct. The user must close
'display' before your program continues.

However, I would still avoid using both Term::ReadKey and X11 to
interact with the same user.
 
G

Greg Bacon

It seems like that code ought to be a lot simpler. I tried using mjd's
Secret Passage trick[*], but display never got the chance to start
because the pipe filled up while I tried to write the image data to it.

[*] <URL:http://perl.plover.com/LOD/199906.html#9>

Hmm.. what about a double-fork.. That gets pretty close, but it leaves
the display process running.

#! /usr/local/bin/perl

use warnings;
use strict;

open my $png, "<", "out.png" or die "$0: open: $!";

my $pid = open my $display, "|-";
die "$0: fork: $!" unless defined $pid;

if ($pid) {
print { $display } <$png>;
close $display or warn "$0: pipe exited $?";
}
else {
unless (fork) {
exec "display", "-" or die "$0: exec: $!";
}
exit 0;
}

print "Press enter to exit...\n";
my(undef) = scalar <>;

Without the curlies around $display in the parent's print, I get a
syntax error near "$png>" with perl v5.8.5. Weird.

Greg
 
Ad

Advertisements

K

kj

In said:
What you're trying to do is separate closing the pipe from waiting on the
child process. The magical '|-' open ties those 2 actions together because
most of the time, having them tied together is convenient. If you want them
separate, you have to give up the magic and write it the long way with pipe()
and fork().

Thanks, that worked like gangbusters.
# Create a pipe and a child process
my ($rd, $wr);
pipe($rd, $wr) or die "pipe: $!\n";
my $pid=fork();
defined($pid) or die "fork: $!\n";
if(!$pid) {
# Child process reads from the pipe on stdin
open(STDIN, '<&', $rd);
# Child process doesn't write to the pipe, so close that end.
close($wr);
#{ exec 'display' } # I don't have "display"
{ exec 'xli', 'stdin' } # But I do have xli
die "exec: $!\n";
}

I'm curious: why the curly brackets around the exec statement?

Thanks again,

kj
 
Ad

Advertisements

M

Martien verbruggen

In said:
[...]
open my $IMG, '|-', 'display';
print $IMG $gd->png;

# display won't happen without this line!
close $IMG;

### script stalls before executing the next line

print "Press any key to continue... ";
ReadMode 'cbreak';
ReadKey( 0 );
ReadMode 'normal';
print "\n";
}
[...]
The method used to remotely display X programs is different from the
method used to remotely display console programs, and Term::ReadKey
doesn't have internal support for remote displays.
Trying to mix console type user-interaction with graphical
user-interaction will confound you. It's best just to make your program
fully graphical with one of the toolkits available: Gtk, Perl-Tk, etc.

There's no shortage of fully graphical programs for viewing PNG
files, but what I need is a viewer that I can control *entirely*
from the keyboard. Are you saying that this would be too difficult
to program?

You could always use the Image::Magick module in a child process and
control that child from the parent via a pipe, or signals if control is
simple enough.

The Image::Magick module can do pretty much everything the command line
tools can do as well.


Of course, you can also fork and exec a child for the display command
line program, and then control that with a signal.

Martien
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top