#!/usr/bin/perl


# snesaver.pl - perl xscreensaver script for running zsnes movies
#               Author:      Hunter Davis, www.hunterdavis.com 2008
#               License:     GPLV3 - see licence.txt or google gplv3
#               Function:    For each rom, it is assumed a saved zsnes video state resides in state 0
#                            Loads zsnes fullscreen to play each state as as screensaver 
#		Assumptions: 1.  zsnes is executed fullscreen with custom resolution 22, otherwise $cmdline will need to be changed
#			     2.  for each rom in your rompath, there is a saved zsnes session at slot 0, otherwise change $cmdline
#			     3.  you've added snesaver.pl to your path, and to the programs section of your ~/.xscreensaver file
#			     4.  you don't mind hitting escape, sometimes twice or with wiggling mouse to exit your screensaver
#			     5.  you've installed zsnes32 (for those of us running amd64bit), otherwise change references to zsnes
#


# used for our recursive game video directory search
use File::Find;

# executable to call
# amd64 = zsnes32
# generic = zsnes
$zsnesex = "zsnes32";

#set our directory full of game roms here - recurses
$dir = '/home/hunter/projects/SNES-SCREENSAVER/gamevids/';

#global storage for gamevids list
my @gamevids=();

# verbose output
$debugmode = 0;

# our Wanted function should push files only into gamevids
# used by file::find, adds each game roms absolute path to the gamevids array
sub Wanted
{
        # gotta be a file
        push(@gamevids,$_) if (-f "$_");

        if($debugmode > 0)
        {
                print $_ , "\n" if (-f "$_"); # print all files found
        }
}


# our terminate signal handler - signal 15 TERM
# xscreensaver sends a running screensaver process the TERM signal
# unfortunately, mouse initialization in zsnes causes xscreensaver to TERM
# this TERM signal handler ignores this first TERM and allows zsnes to continue
# until an actual TERM command is received, at which time zsnes32 is killed, script exits
# unfortunately, this is also why you must hit escape to quit

$terms = 0;
sub termHandler {
	$terms = $terms + 1;
	local($sig) = @_;
	if($debugmode == 1)
	{
	    print "signal: " . $sig . " \n";
	}
	if($terms > 1){
		system "killall " . $zsnesex; #better way?
		$ENV{SNESAVER} = 0;
		exit(0);
	}
}
$SIG{TERM} = \&termHandler;



# Get all our saved game sessions
$File::Find::no_chdir = 1;
find( { wanted => \&Wanted, no_chdir => 1} , $dir);


# how many sessions do we have?
$numvids = @gamevids;
if ($debugmode == 1){
        print "$numvids", "\n";
}



# when this script spawns a zsnes session, the environment var SNESAVER
# is set.  If a xscreensaver process attempts to re-activate xscreensaver
# and this var is active, no process is spawned
$instanced = $ENV{SNESAVER};
if($instanced == 0)
{
		# our processing kernel

		# kill any floating zsnes sessions
		system "killall " . $zsnesex;

		# generate our command line with a random game session
		$random_num = int(rand($numvids));
		$cmdline = $zsnesex . " -dd -k 1 -r 0 -z -m -mc -v 22 -zm 0 " . @gamevids[$random_num] . "   ";

		
		# execute/wait for command line, and wrap in env variable defs
		$ENV{SNESAVER} = 1;
		system $cmdline;
		$ENV{SNESAVER} = 0;

		# start the whole thing over again
		# without which screensaver not guaranteed to be on
		system "xscreensaver-command -activate";
		
		# let us know our command line if verbose output
		if($debugmode == 1){
		        print "\n", $cmdline, "\n";
		}
}
