X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fvidwhacker;h=d958c5623c7eddfbf533cbc6f0339360ce4aa0db;hp=a2ab029b99c0cb54e99b8660e75ada37f0bde51e;hb=ffd8c0873576a9e3065696a624dce6b766b77062;hpb=481b95e2617b69e6fd4444432747d7e1e0c3dc85 diff --git a/hacks/vidwhacker b/hacks/vidwhacker index a2ab029b..d958c562 100755 --- a/hacks/vidwhacker +++ b/hacks/vidwhacker @@ -1,330 +1,498 @@ -#!/bin/sh +#!/usr/bin/perl -w +# vidwhacker, for xscreensaver. Copyright (c) 1998-2004 Jamie Zawinski. # -# vidwhacker, for xscreensaver. Copyright (c) 1998 Jamie Zawinski. +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. No representations are made about the suitability of this +# software for any purpose. It is provided "as is" without express or +# implied warranty. # -# This script grabs a frame of video, then uses various pbm filters to -# munge the image in random nefarious ways, then uses xv to put it on -# the root window. This works out really nicely if you just feed some -# random TV station into it... +# This program grabs a frame of video, then uses various pbm filters to +# munge the image in random nefarious ways, then uses xloadimage, xli, or xv +# to put it on the root window. This works out really nicely if you just +# feed some random TV station into it... # -# The video grabbing part is SGI-specific -- if you want to use this on -# another system, add a new clause to the grab() procedure. - - -# Process command-line args... - -onroot=false -verbose=false -delay=3 -use_stdin=false - -pid="" -tmp=/tmp/vd$$ -tmp_rgb=$tmp-00000.rgb -tmp_ppm0=$tmp-0.ppm -tmp_ppm1=$tmp-1.ppm -tmp_ppm2=$tmp-2.ppm -tmp_ppm3=$tmp-3.ppm -tmp_ppm4=$tmp-4.ppm - - -getargs() { - - while [ $# != 0 ]; do - case "$1" in - -root ) - onroot=true - ;; - -verbose ) - verbose=true - ;; - -stdin ) - use_stdin=true - ;; - * ) - echo "usage: $0 [ -root | -verbose | -stdin ]" >&2 - exit 1 - ;; - esac - shift - done - - xvargs="-quick24" - - if [ "$onroot" = true ]; then - xvargs="$xvargs -root -rmode 5 -noresetroot -rfg black -rbg black -viewonly" - else - xvargs="$xvargs -geom +0+0" - fi - - screen_width=`xdpyinfo | sed -n 's/.* dimensions: *\([0-9]*\).*/\1/p'` -} +# Created: 14-Apr-01. +require 5; +use diagnostics; +use strict; -clean() { - rm -f $tmp_rgb $tmp_ppm1 $tmp_ppm2 $tmp_ppm3 $tmp_ppm4 -} +my $progname = $0; $progname =~ s@.*/@@g; +my $version = q{ $Revision: 1.25 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/; -clean2() { - clean - rm -f $tmp_ppm0 -} +my $verbose = 0; +my $use_stdin = 0; +my $use_stdout = 0; +my $video_p = 0; +my $file_p = 1; +my $delay = 5; +my $imagedir; +my $screen_width = -1; -# Grab a frame of video. +my $displayer = "xscreensaver-getimage -root -file"; + + +# apparently some versions of netpbm call it "pamoil" instead of "pgmoil"... # -grab() { - uname=`uname` - if [ $uname = IRIX ]; then - # - # SGI's "vidtomem" returns an SGI RGB image of the default video input, - # and has stupid non-overridable ouput-file-naming conventions. So, let - # it write its file; and then convert it to a pgm. - # - - vidtomem -f $tmp - sgitopnm $tmp_rgb > $tmp_ppm1 - - # Cut off the close-captioning blips in the NTSC overscan region. YMMV. - # | pnmcut 12 7 695 477 - - elif [ $uname = Linux ]; then - - # Marcus Herbert says the following works with his Connectix Qcam. - # Don't have qcam? Well, do something else then... and send me a patch. - - qcam > $tmp_ppm1 - - else - echo "$0: don't know how to grab video on this OS." >&2 - clean2 - exit 1 - fi -} +my $pgmoil = (which("pamoil") ? "pamoil" : "pgmoil"); -# Use perl to pick a random foreground/background color in pbm's syntax. +# List of interesting PPM filter pipelines. +# In this list, the following magic words may be used: # -randcolor() { - perl -e 'srand; - printf("#%02x%02x%02x-#%02x%02x%02x", - int(rand()*60), - int(rand()*60), - int(rand()*60), - 120+int(rand()*135), - 120+int(rand()*135), - 120+int(rand()*135))' +# COLORS a randomly-selected pair of RGB foreground/background colors. +# FILE1 the (already-existing) input PPM file (ok to overwrite it). +# FILE2-FILE4 names of other tmp files you can use. +# +# These commands should read from FILE1, and write to stdout. +# All tmp files will be deleted afterward. +# +my @filters = ( + "ppmtopgm FILE1 | pgmedge | pgmtoppm COLORS | ppmnorm", + "ppmtopgm FILE1 | pgmenhance | pgmtoppm COLORS", + "ppmtopgm FILE1 | $pgmoil | pgmtoppm COLORS", + "ppmtopgm FILE1 | pgmbentley | pgmtoppm COLORS", + + "ppmrelief FILE1 | ppmtopgm | pgmedge | ppmrelief | ppmtopgm |" . + " pgmedge | pnminvert | pgmtoppm COLORS", + + "ppmspread 71 FILE1 > FILE2 ; " . + " pnmarith -add FILE1 FILE2 ; ", + + "pnmflip -lr < FILE1 > FILE2 ; " . + " pnmarith -multiply FILE1 FILE2 > FILE3 ; " . + " pnmflip -tb FILE3 | ppmnorm > FILE2 ; " . + " pnmarith -multiply FILE1 FILE2", + + "pnmflip -lr FILE1 > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "pnmflip -tb FILE1 > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "pnmflip -lr FILE1 | pnmflip -tb > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "ppmtopgm < FILE1 | pgmedge > FILE2 ; " . + " pnmarith -difference FILE1 FILE2 > FILE3 ; " . + " cp FILE3 FILE1 ; " . + " ppmtopgm < FILE1 | pgmedge > FILE2 ; " . + " pnmarith -difference FILE1 FILE2 > FILE3 ; " . + " ppmnorm < FILE1", + + "pnmflip -lr < FILE1 > FILE2 ; " . + " pnmarith -multiply FILE1 FILE2 | ppmrelief | ppmnorm | pnminvert", + + "pnmflip -lr FILE1 > FILE2 ; " . + " pnmarith -subtract FILE1 FILE2 | ppmrelief | ppmtopgm | pgmedge", + + "pgmcrater -number 20000 -width WIDTH -height HEIGHT FILE1 | " . + " pgmtoppm COLORS > FILE2 ; " . + " pnmarith -difference FILE1 FILE2 > FILE3 ; " . + " pnmflip -tb FILE3 | ppmnorm > FILE2 ; " . + " pnmarith -multiply FILE1 FILE2", + + "ppmshift 30 FILE1 | ppmtopgm | $pgmoil | pgmedge | " . + " pgmtoppm COLORS > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "ppmpat -madras WIDTH HEIGHT | pnmdepth 255 > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "ppmpat -tartan WIDTH HEIGHT | pnmdepth 255 > FILE2 ; " . + " pnmarith -difference FILE1 FILE2", + + "ppmpat -camo WIDTH HEIGHT | pnmdepth 255 | ppmshift 50 > FILE2 ; " . + " pnmarith -multiply FILE1 FILE2", + + "pgmnoise WIDTH HEIGHT | pgmedge | pgmtoppm COLORS > FILE2 ; " . + " pnmarith -difference FILE1 FILE2 | pnmdepth 255 | pnmsmooth", +); + + +sub error { + ($_) = @_; + print STDERR "$progname: $_\n"; + exit 1; } -# Frobnicate the image in some random way. +# Any files on this list will be deleted at exit. # -frob() { - - w_h=`head -2 $tmp_ppm1 | tail -1` - width=`echo $w_h | awk '{print $1}'` - height=`echo $w_h | awk '{print $2}'` - - N=`perl -e 'srand; print int(rand() * 17)'` - - if [ "$verbose" = true ]; then - echo "mode $N..." >&2 - fi - - if [ $N = 0 ]; then - ppmtopgm $tmp_ppm1 | pgmedge | pgmtoppm `randcolor` | ppmnorm - - elif [ $N = 1 ]; then - ppmtopgm $tmp_ppm1 | - pgmenhance | - pgmtoppm `randcolor` - - elif [ $N = 2 ]; then - ppmtopgm $tmp_ppm1 | pgmoil | pgmtoppm `randcolor` - - elif [ $N = 3 ]; then - ppmrelief $tmp_ppm1 | ppmtopgm | pgmedge | ppmrelief | ppmtopgm | - pgmedge | pnminvert | pgmtoppm `randcolor` - - elif [ $N = 4 ]; then - ppmspread 71 $tmp_ppm1 > $tmp_ppm2 - pnmarith -add $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 5 ]; then - pnmflip -lr $tmp_ppm1 > $tmp_ppm2 - pnmarith -multiply $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3 - pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2 - pnmarith -multiply $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 6 ]; then - N2=`perl -e 'srand; print int(rand() * 3)'` - if [ $N2 = 0 ]; then - pnmflip -lr $tmp_ppm1 > $tmp_ppm2 - elif [ $N2 = 1 ]; then - pnmflip -tb $tmp_ppm1 > $tmp_ppm2 - else - pnmflip -lr $tmp_ppm1 > $tmp_ppm2 - pnmflip -tb $tmp_ppm2 > $tmp_ppm3 - cp $tmp_ppm3 $tmp_ppm2 - fi - - pnmarith -difference $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 7 ]; then - - for i in 1 2 3 ; do - ppmtopgm $tmp_ppm1 | pgmedge > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3 - cp $tmp_ppm3 $tmp_ppm1 - done - ppmnorm < $tmp_ppm1 - - elif [ $N = 8 ]; then - pnmflip -lr $tmp_ppm1 > $tmp_ppm2 - pnmarith -multiply $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmnorm | pnminvert - - elif [ $N = 9 ]; then - pnmflip -lr $tmp_ppm1 > $tmp_ppm2 - pnmarith -subtract $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmtopgm | pgmedge - - elif [ $N = 10 ]; then - ppmtopgm $tmp_ppm1 | pgmbentley | pgmtoppm `randcolor` - - elif [ $N = 11 ]; then - pgmcrater -number 20000 -height $height -width $width | pgmtoppm `randcolor` > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3 - pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2 - pnmarith -multiply $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 12 ]; then - ppmshift 30 $tmp_ppm1 | ppmtopgm | pgmoil | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 13 ]; then - ppmpat -madras $width $height | pnmdepth 255 > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 14 ]; then - ppmpat -tartan $width $height | pnmdepth 255 > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 15 ]; then - ppmpat -camo $width $height | pnmdepth 255 | ppmshift 50 > $tmp_ppm2 - pnmarith -multiply $tmp_ppm1 $tmp_ppm2 - - elif [ $N = 16 ]; then - pgmnoise $width $height | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2 - pnmarith -difference $tmp_ppm1 $tmp_ppm2 | pnmdepth 255 | pnmsmooth - - else cat $tmp_ppm1 - fi +my @all_tmpfiles = (); + +sub exit_cleanup { + print STDERR "$progname: delete tmp files\n" if ($verbose); + unlink @all_tmpfiles; } +sub signal_cleanup { + my ($sig) = @_; + print STDERR "$progname: caught SIG$sig\n" if ($verbose); + exit 1; +} -# Grab a frame and frob it. leave it in $tmp_ppm3. -# -whack() { - clean - - while [ ! -f $tmp_ppm1 ]; do - if [ "$use_stdin" != true ]; then - grab - else - cp $tmp_ppm0 $tmp_ppm1 - fi - done - - rm -f $tmp_rgb - frob | pnmscale -width $screen_width > $tmp_ppm3 - rm -f $tmp_ppm1 $tmp_ppm2 +sub init_signals { + + $SIG{HUP} = \&signal_cleanup; + $SIG{INT} = \&signal_cleanup; + $SIG{QUIT} = \&signal_cleanup; + $SIG{ABRT} = \&signal_cleanup; + $SIG{KILL} = \&signal_cleanup; + $SIG{TERM} = \&signal_cleanup; + + # Need this so that if giftopnm dies, we don't die. + $SIG{PIPE} = 'IGNORE'; } +END { exit_cleanup(); } + + -# Kill off the xv subprocess, if it's running + +# returns the full path of the named program, or undef. # -kill_pid() { - if [ "$pid" != "" ]; then +sub which { + my ($prog) = @_; + foreach (split (/:/, $ENV{PATH})) { + if (-x "$_/$prog") { + return $prog; + } + } + return undef; +} - if [ "$verbose" = true ]; then - echo "killing pid $pid..." >&2 - fi - # need to do this to avoid "6898 Terminated" messages! - # apparently one can't redirect the output of the builtin `kill' command. -# ( sh -c "kill $pid" ) >/dev/null 2>/dev/null &- >&- - pid="" - fi +sub filter_subst { + my ($filter, $width, $height, @tmpfiles) = @_; + my $colors = randcolors(); + $filter =~ s/\bWIDTH\b/$width/g; + $filter =~ s/\bHEIGHT\b/$height/g; + $filter =~ s/\bCOLORS\b/'$colors'/g; + my $i = 1; + foreach my $t (@tmpfiles) { + $filter =~ s/\bFILE$i\b/$t/g; + $i++; + } + if ($filter =~ m/([A-Z]+)/) { + error "internal error: what is \"$1\"?"; + } + $filter =~ s/ +/ /g; + return $filter; } -# called when this process is signalled (for cleanup) +# Frobnicate the image in some random way. # -my_trap() { - if [ "$verbose" = true ]; then - echo "trapped signal!" >&2 - fi - kill_pid - clean2 - exit 1 +sub frob_ppm { + my ($ppm_data) = @_; + $_ = $ppm_data; + + error "0-length data" if (!defined($ppm_data) || $ppm_data eq ""); + error "not a PPM file" unless (m/^P\d\n/s); + my ($width, $height) = m/^P\d\n(\d+) (\d+)\n/s; + error "got a bogus PPM" unless ($width && $height); + + my $tmpdir = $ENV{TMPDIR}; + $tmpdir = "/tmp" unless $tmpdir; + my $fn = sprintf ("%s/vidwhacker-0-%08x", $tmpdir, rand(0xFFFFFFFF)); + my $fn1 = sprintf ("%s/vidwhacker-1-%08x", $tmpdir, rand(0xFFFFFFFF)); + my $fn2 = sprintf ("%s/vidwhacker-2-%08x", $tmpdir, rand(0xFFFFFFFF)); + my $fn3 = sprintf ("%s/vidwhacker-3-%08x", $tmpdir, rand(0xFFFFFFFF)); + my @files = ( "$fn", "$fn1", "$fn2", "$fn3" ); + push @all_tmpfiles, @files; + + my $n = int(rand($#filters+1)); + my $filter = $filters[$n]; + + if ($verbose == 1) { + printf STDERR "$progname: running filter $n\n"; + } elsif ($verbose > 1) { + my $f = $filter; + $f =~ s/ +/ /g; + $f =~ s/^ */\t/; + $f =~ s/ *\|/\n\t|/g; + $f =~ s/ *\; */ ;\n\t/g; + print STDERR "$progname: filter $n:\n\n$f\n\n" if $verbose; + } + + $filter = filter_subst ($filter, $width, $height, @files); + + unlink @files; + + local *OUT; + open (OUT, ">$files[0]") || error ("writing $files[0]: $!"); + print OUT $ppm_data; + close OUT; + + $filter = "( $filter )"; + $filter .= "2>/dev/null" unless ($verbose > 1); + + local *IN; + open (IN, "$filter |") || error ("opening pipe: $!"); + $ppm_data = ""; + while () { $ppm_data .= $_; } + close IN; + + unlink @files; + return $ppm_data; } -main() { - getargs $@ +sub read_config { + my $conf = "$ENV{HOME}/.xscreensaver"; - trap my_trap 0 1 2 3 6 9 13 + my $had_dir = defined($imagedir); - if [ "$use_stdin" = true ]; then - cat > $tmp_ppm0 - fi + local *IN; + open (IN, "<$conf") || error "reading $conf: $!"; + while () { + if (!$imagedir && m/^imageDirectory:\s+(.*)\s*$/i) { $imagedir = $1; } + elsif (m/^grabVideoFrames:\s+true\s*$/i) { $video_p = 1; } + elsif (m/^grabVideoFrames:\s+false\s*$/i) { $video_p = 0; } + elsif (m/^chooseRandomImages:\s+true\s*$/i) { $file_p = 1; } + elsif (m/^chooseRandomImages:\s+false\s*$/i) { $file_p = 0; } + } + close IN; - while true; do + $file_p = 1 if $had_dir; - # Loop grabbing and frobbing images. - # - # If we're running on the root, run xv in the foreground (with -exit) - # and then wait. - # - # If we're running in a window, spawn xv in the background; then when - # it's time to put up the new image, kill off the currently-running xv. + $imagedir = undef unless ($imagedir && $imagedir ne ''); - if [ "$verbose" = true ]; then - whack - else - whack >&- 2>&- - fi + if (!$file_p && !$video_p) { +# error "neither grabVideoFrames nor chooseRandomImages are set\n\t" . +# "in $conf; $progname requires one or both." + $file_p = 1; + } - kill_pid + if ($file_p) { + error "no imageDirectory set in $conf" unless $imagedir; + error "imageDirectory $imagedir doesn't exist" unless (-d $imagedir); + } - if [ ! -s $tmp_ppm3 ]; then - echo "$0: no image grabbed" >&2 - else + if ($verbose > 1) { + printf STDERR "$progname: grab video: $video_p\n"; + printf STDERR "$progname: grab images: $file_p\n"; + printf STDERR "$progname: directory: $imagedir\n"; + } - pnmtosgi < $tmp_ppm3 > $tmp_ppm2 - rm -f $tmp_ppm3 +} - if [ -s $tmp_ppm2 ]; then - if [ "$verbose" = true ]; then - echo "launching xv $xvargs $tmp_ppm2" >&2 - ls -lF $tmp_ppm2 - fi - # cat the file so that we can nuke it without racing against xv. - cat $tmp_ppm2 | xv $xvargs - & - pid=$! - fi - fi +sub get_ppm { + if ($use_stdin) { + print STDERR "$progname: reading from stdin\n" if ($verbose > 1); + my $ppm = ""; + while () { $ppm .= $_; } + return $ppm; + + } else { + + my $do_file_p; + + if ($file_p && $video_p) { + $do_file_p = (int(rand(2)) == 0); + print STDERR "$progname: doing " . ($do_file_p ? "files" : "video") ."\n" + if ($verbose); + } + elsif ($file_p) { $do_file_p = 1; } + elsif ($video_p) { $do_file_p = 0; } + else { + error "internal error: not grabbing files or video?"; + } + + my $v = ($verbose <= 1 ? "" : "-" . ("v" x ($verbose-1))); + my $cmd; + if ($do_file_p) { + $cmd = "xscreensaver-getimage-file $v --name \"$imagedir\""; + } else { + $cmd = "xscreensaver-getimage-video $v --stdout"; + } + + my $ppm; + + if ($do_file_p) { + + print STDERR "$progname: running: $cmd\n" if ($verbose > 1); + my $fn = `$cmd`; + $fn =~ s/\n$//s; + error "didn't get a file?" if ($fn eq ""); + + print STDERR "$progname: selected file $fn\n" if ($verbose > 1); + + if ($fn =~ m/\.gif/i) { $cmd = "giftopnm < \"$fn\""; } + elsif ($fn =~ m/\.jpe?g/i) { $cmd = "djpeg < \"$fn\""; } + elsif ($fn =~ m/\.png/i) { $cmd = "pngtopnm < \"$fn\""; } + elsif ($fn =~ m/\.xpm/i) { $cmd = "xpmtoppm < \"$fn\""; } + elsif ($fn =~ m/\.bmp/i) { $cmd = "bmptoppm < \"$fn\""; } + elsif ($fn =~ m/\.tiff?/i) { $cmd = "tifftopnm < \"$fn\""; } + elsif ($fn =~ m/\.p[bgp]m/i) { return `cat \"$fn\"`; } + else { + error "unrecognized file extension on $fn"; + } + + print STDERR "$progname: converting with: $cmd\n" if ($verbose > 1); + $cmd .= " 2>/dev/null" unless ($verbose > 1); + $ppm = `$cmd`; + + } else { + + print STDERR "$progname: running: $cmd\n" if ($verbose > 1); + $ppm = `$cmd`; + error "no data?" if ($ppm eq ""); + error "not a PPM file" unless ($ppm =~ m/^P\d\n/s); + + $_ = $ppm; + my ($width, $height) = m/^P\d\n(\d+) (\d+)\n/s; + error "got a bogus PPM" unless ($width && $height); + print STDERR "$progname: grabbed ${width}x$height PPM\n" + if ($verbose > 1); + $_ = 0; + } + + return $ppm; + } +} - clean - sleep $delay +sub dispose_ppm { + my ($ppm) = @_; + + error "0-length data" if (!defined($ppm) || $ppm eq ""); + error "not a PPM file" unless ($ppm =~ m/^P\d\n/s); + + if ($use_stdout) { + print STDERR "$progname: writing to stdout\n" if ($verbose > 1); + print $ppm; + + } else { + my $tmpdir = $ENV{TMPDIR}; + $tmpdir = "/tmp" unless $tmpdir; + my $fn = sprintf ("%s/vidwhacker-%08x", $tmpdir, rand(0xFFFFFFFF)); + local *OUT; + unlink $fn; + push @all_tmpfiles, $fn; + open (OUT, ">$fn") || error "writing $fn: $!"; + print OUT $ppm; + close OUT; + + my @cmd = split (/ +/, $displayer); + push @cmd, $fn; + print STDERR "$progname: executing \"" . join(" ", @cmd) . "\"\n" + if ($verbose); + system (@cmd); + + my $exit_value = $? >> 8; + my $signal_num = $? & 127; + my $dumped_core = $? & 128; + + unlink $fn; + + error ("$cmd[0]: core dumped!") if ($dumped_core); + error ("$cmd[0]: signal $signal_num!") if ($signal_num); + error ("$cmd[0]: exited with $exit_value!") if ($exit_value); + } +} - done - exit 1 + +my $stdin_ppm = undef; + +sub vidwhack { + my $ppm; + if ($use_stdin) { + if (!defined($stdin_ppm)) { + $stdin_ppm = get_ppm(); + } + $ppm = $stdin_ppm; + } else { + my $max_err_count = 20; + my $err_count = 0; + while (!defined($ppm)) { + $ppm = get_ppm(); + $err_count++ if (!defined ($ppm)); + error ("too many errors, too few images!") + if ($err_count > $max_err_count); + } + } + + $ppm = frob_ppm ($ppm); + dispose_ppm ($ppm); + $ppm = undef; } -main $@ -# to find stray xv data: -# xwininfo -root -children|grep 'xv image comments' | awk '{print "xkill -id ", $1}' +sub usage { + print STDERR "VidWhacker, Copyright (c) 2001 Jamie Zawinski \n"; + print STDERR " http://www.jwz.org/xscreensaver/"; + print STDERR "\n"; + print STDERR "usage: $0 [-display dpy] [-verbose]\n"; + print STDERR "\t\t[-root | -window | -window-id 0xXXXXX ]\n"; + print STDERR "\t\t[-stdin] [-stdout] [-delay secs]\n"; + print STDERR "\t\t[-directory image_directory]\n"; + exit 1; +} + +sub main { + while ($_ = $ARGV[0]) { + shift @ARGV; + if ($_ eq "--verbose") { $verbose++; } + elsif (m/^-v+$/) { $verbose += length($_)-1; } + elsif (m/^(-display|-disp|-dis|-dpy|-d)$/) { $ENV{DISPLAY} = shift @ARGV; } + elsif (m/^--?stdin$/) { $use_stdin = 1; } + elsif (m/^--?stdout$/) { $use_stdout = 1; } + elsif (m/^--?delay$/) { $delay = shift @ARGV; } + elsif (m/^--?dir(ectory)?$/) { $imagedir = shift @ARGV; } + elsif (m/^--?root$/) { } + elsif (m/^--?window-id$/) { + my $id = shift @ARGV; + error ("unparsable window id: $id") + unless ($id =~ m/^\d+$|^0x[\da-f]+$/i); + $displayer =~ s/--?root\b/$id/ || + error ("unable to munge displayer: $displayer"); + } + elsif (m/^--?window$/) { + print STDERR "$progname: sorry, \"-window\" is unimplemented.\n"; + print STDERR "$progname: use \"-stdout\" and pipe to a displayer.\n"; + exit 1; + } + elsif (m/^-./) { usage; } + else { usage; } + } + + init_signals(); + + read_config; + + if (!$use_stdout) { + $_ = `xdpyinfo 2>&-`; + ($screen_width) =~ m/ dimensions: +(\d+)x(\d+) pixels/; + $screen_width = 800 unless $screen_width > 0; + } + + if ($use_stdout) { + vidwhack(); + } else { + while (1) { + vidwhack(); + sleep $delay; + } + } +} + +main; +exit 0;