Does nobody have a Mac? Or at least a little insight?

Regards

Jeff

On 13 March 2015 at 22:41, Jeffrey Ratcliffe
<jeffrey.ratcli...@gmail.com> wrote:
> Now, at last with a small working example. The following code works
> fine on Linux, but on MacOS:
>
> a. the gui does not seem to respond to the "hup" signal from the subprocess
> b. gets far more "in" signals than it should
>
> Unfortunately, the above description is secondhand, as I do not have
> access to a Mac.
>
> I would be very glad if somebody could give me a clue how to get
> things working under both operating systems.
>
> Regards
>
> Jeff
>
> #!/usr/bin/perl
>
> use warnings;
> use strict;
> use Gtk2 -init;
> use Glib qw(TRUE FALSE);    # To get TRUE and FALSE
> use POSIX qw(locale_h :signal_h :errno_h :sys_wait_h);
> use IPC::Open3;
> use IO::Handle;
> use Readonly;
> Readonly my $_POLL_INTERVAL => 100;    # ms
> Readonly my $_1KB           => 1024;
> my $EMPTY = q{};
>
> # Create the windows
> my $window  = Gtk2::Window->new('toplevel');
> my $box     = Gtk2::VBox->new;
> my $entry   = Gtk2::Entry->new;
> my $pbar    = Gtk2::ProgressBar->new;
> my $qbutton = Gtk2::Button->new('Quit');
> my $sbutton = Gtk2::Button->new('Start');
>
> $window->add($box);
> $box->add($pbar);
> $box->add($qbutton);
> $box->add($sbutton);
>
> # We should also link this to the destroy message on the main window,
> # this is just quick and dirty
> $qbutton->signal_connect( clicked => sub { Gtk2->main_quit } );
> $sbutton->signal_connect( clicked => \&start_process );
> $window->show_all;
> Gtk2->main;
>
> sub start_process {
>     watch_cmd(
>         cmd              => 'for i in `seq 1 5`; do echo $i; sleep 1; done',
>         running_callback => sub {
>             $pbar->pulse;
>         },
>         started_callback => sub {
>             $pbar->set_text('Started');
>         },
>         out_callback => sub {
>             my ($line) = @_;
>             $pbar->set_text($line);
>         },
>         err_callback => sub {
>             my ($line) = @_;
>             $pbar->set_text("Error: $line");
>         },
>         finished_callback => sub {
>             $pbar->set_text('Finished');
>         },
>     );
>     return;
> }
>
> sub watch_cmd {
>     my (%options) = @_;
>
>     my $out_finished = FALSE;
>     my $err_finished = FALSE;
>     my $error_flag   = FALSE;
>     print "$options{cmd}\n";
>
>     if ( defined $options{running_callback} ) {
>         my $timer = Glib::Timeout->add(
>             $_POLL_INTERVAL,
>             sub {
>                 $options{running_callback}->();
>                 return Glib::SOURCE_REMOVE
>                   if ( $out_finished or $err_finished );
>                 return Glib::SOURCE_CONTINUE;
>             }
>         );
>     }
>
>     my ( $write, $read );
>     my $error = IO::Handle->new;
>     my $pid = IPC::Open3::open3( $write, $read, $error, $options{cmd} );
>     print "Forked PID $pid\n";
>
>     if ( defined $options{started_callback} ) { 
> $options{started_callback}->() }
>     my ( $stdout, $stderr, $error_message );
>
>     add_watch(
>         $read,
>         sub {
>             my ($line) = @_;
>             $stdout .= $line;
>             if ( defined $options{out_callback} ) {
>                 $options{out_callback}->($line);
>             }
>         },
>         sub {
>
>           # Don't flag this until after the callback to avoid the race 
> condition
>           # where stdout is truncated by stderr prematurely reaping the 
> process
>             $out_finished = TRUE;
>         },
>         sub {
>             ($error_message) = @_;
>             $error_flag = TRUE;
>         }
>     );
>     add_watch(
>         $error,
>         sub {
>             my ($line) = @_;
>             $stderr .= $line;
>             if ( defined $options{err_callback} ) {
>                 $options{err_callback}->($line);
>             }
>         },
>         sub {
>
>           # Don't flag this until after the callback to avoid the race 
> condition
>           # where stderr is truncated by stdout prematurely reaping the 
> process
>             $err_finished = TRUE;
>         },
>         sub {
>             ($error_message) = @_;
>             $error_flag = TRUE;
>         }
>     );
>
>     # Watch for the process to hang up before running the finished callback
>     Glib::Child->watch_add(
>         $pid,
>         sub {
>
>           # Although the process has hung up, we may still have output to 
> read,
>           # so wait until the _watch_add flags that the process has ended 
> first.
>             my $timer = Glib::Timeout->add(
>                 $_POLL_INTERVAL,
>                 sub {
>                     if ($error_flag) {
>                         if ( defined $options{error_callback} ) {
>                             $options{error_callback}->($error_message);
>                         }
>                         return Glib::SOURCE_REMOVE;
>                     }
>                     elsif ( $out_finished and $err_finished ) {
>
>                         if ( defined $options{finished_callback} ) {
>                             $options{finished_callback}->( $stdout, $stderr );
>                         }
>                         print "Waiting to reap process\n";
>
>              # -1 indicates a non-blocking wait for all pending zombie 
> processes
>                         print 'Reaped PID ', waitpid(
>                             -1,    ## no critic (ProhibitMagicNumbers)
>                             WNOHANG
>                           ),
>                           "\n";
>                         return Glib::SOURCE_REMOVE;
>                     }
>                     return Glib::SOURCE_CONTINUE;
>                 }
>             );
>         }
>     );
>     return;
> }
>
> sub add_watch {
>     my ( $fh, $line_callback, $finished_callback, $error_callback ) = @_;
>     my $line;
>     Glib::IO->add_watch(
>         fileno($fh),
>         [ 'in', 'hup' ],
>         sub {
>             my ( $fileno, $condition ) = @_;
>             my $buffer;
>             if ( $condition & 'in' ) { # bit field operation. >= would also 
> work
>
>                 # For Linux, this "if" should always return true, as the
>                 # callback is only triggered when there is data to read.
>                 # MacOS seems to trigger this callback even when there is
>                 # nothing to read, and therefore we need this conditional
>                 # Only reading one buffer, rather than until sysread gives EOF
>                 # because things seem to be strange for stderr
>                 if ( sysread $fh, $buffer, $_1KB ) {
>                     if ($buffer) { $line .= $buffer }
>
>                     while ( $line =~ /([\r\n])/xsm ) {
>                         my $le = $1;
>                         if ( defined $line_callback ) {
>                             $line_callback->(
>                                 substr $line, 0, index( $line, $le ) + 1
>                             );
>                         }
>                         $line = substr $line, index( $line, $le ) + 1,
>                           length $line;
>                     }
>                 }
>             }
>
>             # Only allow the hup if sure an empty buffer has been read.
>             if (
>                 ( $condition & 'hup' ) # bit field operation. >= would also 
> work
>                 and ( not defined $buffer or $buffer eq $EMPTY )
>               )
>             {
>                 if ( close $fh ) {
>                     $finished_callback->();
>                 }
>                 elsif ( defined $error_callback ) {
>                     $error_callback->('Error closing filehandle');
>                 }
>                 return Glib::SOURCE_REMOVE;
>             }
>             return Glib::SOURCE_CONTINUE;
>         }
>     );
>     return;
> }
_______________________________________________
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list

Reply via email to