#!/usr/bin/env perl

$usage = "usage: $0 pdf-file";
@ARGV || die $usage;


## Todo: handle the case when file has been deleted.

## User variables.

$verbose = 1;			# Set to non-zero for feedback.
$delay = 0.30;			# delay time, in seconds, between polling
				# to see if pdf has changed.

######################################################################
$remote = "wxpdf_$$";		# create a unique remote name for xpdf.
$pid = $$;			# Get the current process i.d.
$pdf = $ARGV[$#ARGV];		# name of pdf is last arg on command line.
$cmd =    "xpdf -remote $remote @ARGV";		# cmd to start xpdf
$reload = "xpdf -remote $remote -reload";	# -reload only with -remote

$verbose && print "$$: cmd is $cmd.\n";

## FORK code taken from Programming Perl, p167.
 FORK: {
     if ($pid = fork) {
	 ## This is the parent.
	 $verbose && print "$$: I am the parent; child has pid $pid.\n";

	 # get last mod time of pdf; this is needed by atchange below.
	 $old = (stat($pdf))[9]; 
	 
	 while (1) {
	     select(undef, undef, undef, $delay); # wait some delay.


	     if (&atchange($pdf)) {
		 $verbose && print "$$: reload with ($reload).\n";
		 system($reload);
	     }
	 }
     }
     elsif (defined $pid) {
	 ## This is the child.
	 ## $pid will be zero here if defined.
	 system("$cmd");	# start viewer.

	 ## If we get this far in the program, it means that the viewer
	 ## has been closed, so the child can kill the parent to stop
	 ## it keeping in watch.
	 $parent_pid = getppid();
	 $verbose && print "$$: Child ending... parent $parent_pid.\n";
	 if ($parent_pid > 1) {
	     kill 9, $parent_pid;
	 }
	 
	 exit;
     } else {
	 # weird fork error
	 die "$$: Can't fork: $!\n";
     }
}



## This taken from the atchange program, see below.
sub atchange {		# if $file has changed, do $cmd{$file}
	my($file) = @_;
	my($new);

	$new = (stat($file))[9];
	return 0 if ($old == $new);
	while (1) {			# wait until it stops changing
		$old = $new;
		select(undef, undef, undef, $delay); # wait some delay.
		$new = (stat($file))[9];
		if ($old == $new) {
			return 1;
		}
	}
}

__END__

=head1 NAME

wxpdf - watch a pdf file

=head1 SYNOPSIS

wxpdf <file.pdf>

=head1 DESCRIPTION

Run the xpdf viewer on file.pdf, but provide a watchfile facility
similar to the -watch switch in gv.  If the pdf file changes, then
xpdf automatically reloads the pdf without you needing to press R for
reload, or change the page.  (file.pdf is checked every `delay'
seconds, where delay is set at the top of the script.)

If xpdf viewer is killed by the user, this program finishes watching
the file.

Some of the code for watching for file changes comes from the
excellent utility atchange,
http://www.lecb.ncifcrf.gov/~toms/atchange.html

Tested on linux.

=head1 OPTIONS

=head1 ENVIRONMENT

=head1 EXAMPLES

wxpdf main.pdf


=head1 FILES

=head1 AUTHOR

Stephen Eglen <stephen@gnu.org>
GPL.

Thanks to Karl Berry for a patch (June 2013).

=head1 SEE ALSO

=head1 DIAGNOSTICS

=head1 BUGS

=cut
