[comp.sources.unix] v11i077: Small SUN screen-saver

rsalz@uunet.UU.NET (Rich Salz) (09/26/87)

Submitted-by: gerolima@ford-wdl34.arpa (Mark Gerolimatos)
Posting-number: Volume 11, Issue 77
Archive-name: saver

Saver is a screen saver program that works not by writing on the screen,
but rather by turning the frame buffer's output off, rather like a
terminal's screen darkener. Saver hardly uses any CPU time (it selects on
input), and does not need to be run in a windowing system.  There are two
modes: dark on demand (DOD!), and daemon mode (real nice if you don't want
have to remember to darken the screen).  In DOD mode, the screen will turn
dark about five seconds from when the command is given. In daemon mode,
the screen darkens automatically after a certain length of inactivity of
both the keyboard and mouse.
		-Mark

: ----------------------------- CUT HERE --------------------------- :
export PATH || exec /bin/sh $0 $*
: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::':
: This is a shell archive, meaning:
: 1. Remove everything above the "export PATH ..." line.
: 2. Save the resulting text in a file.
: 3. Execute the file with /bin/sh (NOT csh) to create the files:
:	Makefile
:	saver.1
:	saver.c
: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::':
PATH="/bin:/usr/bin:/usr/lbin:/usr/ucb:$PATH"
export PATH
if test -f 'Makefile' -o -d 'Makefile'
then
	echo 'shar: "Makefile" exists; NOT overwritten'
else
echo 'x Makefile 79 bytes'
sed -e 's/^X//' << 'EOF Makefile' > 'Makefile'
X# Easy Makefile, Eh?
XCFLAGS = -O
Xsaver: saver.o
X	cc $(CFLAGS) -o saver saver.o
EOF Makefile
if test 79 -ne "`wc -c < 'Makefile'`"
then
	echo 'shar: "Makefile" CORRUPTED (not 79 bytes)'
fi
fi ; : End of overwrite check
if test -f 'saver.1' -o -d 'saver.1'
then
	echo 'shar: "saver.1" exists; NOT overwritten'
else
echo 'x saver.1 1959 bytes'
sed -e 's/^X//' << 'EOF saver.1' > 'saver.1'
X.TH SAVER 1 "18 September 1987"
X.SH NAME
Xsaver \- black out a Sun screen
X.SH SYNOPSIS
X.B saver
X[ \fB\-d\fP ] 
X[ \fB\-t \fP\fItime\fP ] 
X.LP
X.SH DESCRIPTION
X\fIsaver\fP is a screen saver program that works not by writing on
Xthe screen, but rather by turning the frame buffer's output off,
Xrather like a terminal's screen darkener. \fISaver\fP hardly uses
Xany CPU time (it selects on input), and does not need
Xto be run in a windowing system.
X.LP
XThere are two modes: dark on demand (DOD!), and daemon mode (real
Xnice if you don't want have to remember to darken the screen).
XIn DOD mode, the screen will turn dark about five seconds from
Xwhen the command is given. In daemon mode, the screen darkens 
Xautomatically after a certain length of inactivity of both the 
Xkeyboard and mouse.
X.LP
XIn both cases, the screen turns back on when something happens on
Xthe keyboard or mouse (when in a windowing system), or the console
X(when out of a windowing system). Not that when in most windowing
Xsystems, merely moving the mouse, or hitting any key will turn
Xthe screen back on. However, when out of a windowing system, the
X<return> key must be hit (except when in raw mode).
X.LP
X.SH OPTIONS
X.TP
X\fB\-d\fP
XDaemon mode: run (forever), darkening after an idle interval on the
Xkeyboard or mouse or console (default 300 seconds...5 minutes).
X.TP
X\fB\-t\fP
XTime: Set the time interval to darken the screen.
X.LP
X.SH EXAMPLES
X.LP
XTo run in daemon mode (interval of 10 minutes):
X.RS
X.IP "% \fBsaver -d -t 600\fP"
X.RE
X.LP
XTo run in DOD mode:
X.RS
X.IP "% \fBsaver\fP (real hard, eh?)"
X.RE
X.LP
X.SH BUGS
X.LP
XWhen out of a windowing system, \fIsaver\fP stats the console for
Xmodify and access time. Difficulties can arise when nothing is reading
Xthe console and echo is turned off.
X.LP
X\fISaver\fP must be run in the background when in daemon mode
X(I don't do forks).
X.LP
X\fISaver\fP should be run by root in daemon mode to prevent any
Xfunny ownership problems due to logout/login.
EOF saver.1
if test 1959 -ne "`wc -c < 'saver.1'`"
then
	echo 'shar: "saver.1" CORRUPTED (not 1959 bytes)'
fi
fi ; : End of overwrite check
if test -f 'saver.c' -o -d 'saver.c'
then
	echo 'shar: "saver.c" exists; NOT overwritten'
else
echo 'x saver.c 8826 bytes'
sed -e 's/^X//' << 'EOF saver.c' > 'saver.c'
X/* You may do whatever you want with this program, so long as this
X** header is left intact:
X**	
X**	saver, written by Mark Gerolimatos (gerolima@ford-wdl1.arpa)
X**
X**	This program is free, and totally devoid of any sort of warantee.
X**	Neither the author nor Ford Aerospace assume any responsibility
X**	for any damage or unpleasantness that might be caused by its use.
X**
X*/
X
X
X
X
X
X/*
X**	(However, if you find any bugs, it would be nice if you reported
X**	them to me).
X*/
X
X
X/* This here porgram opens up the frame buffer, sends it an "off"
X** video call, and then sends it an "on" call (both very nicely 
X** undocumented by sun) when the return key gets hit. A nice 
X** screen-saver that won't let console messages
X** screw it up.
X**
X** When in suntools or X, the screen my be relit by moving the
X** mouse, or hitting any key on the keyboard.
X**
X** When in console mode, a <return> must be hit, unless you're in
X** some kind of uncooked mode (like when playing rogue), in which
X** case any character will do.
X**
X** Complaints to: Mark Gerolimatos, gerolima@ford-wdl1.arpa
X**
X**
X** There is also a daemon option, which will turn off after so
X** many seconds (default == 300) of nothing happening on the machine.
X** To run it this way, use
X**
X**	saver -d -t some_number &
X**
X** It's good for root to do this, so that when /dev/console changes
X** ownership, nothing funny happens.
X**
X** Bugs: 
X**
X** when /dev/console is not in direct mode (ie !raw), you
X** have to hit a <return> to make the screen come back to life.
X** Not only that, but the carriage-return must be read by someone
X** or the screen will never darken (the select(2) will fall thru).
X** So tail -f'ing somthing will defeat the darkener, as tail doesn't
X** read the console. Oh, well.
X**
X** when not in suntools or X, (when the mouse puts out data in native
X** mode), the mouse will not be used to figure out whether or not
X** to turn the screen on/off. This is because you can't guarantee that
X** the mouse will be read, resulting in the screen never darkening. 
X** When not in suntools, this happens anytime you barely touch the mouse.
X**
X** However, when in suntools, or when not tail -f'ing (or anthing like that),
X** it seems quite robust. I've had it in my /etc/rc file for quite a
X** while, and nothing bad has happened.
X*/
X
X#include	<sys/param.h>
X#include	<sys/file.h>
X#include	<sys/ioctl.h>
X#include	<sun/fbio.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<sys/time.h>
X#include	<sundev/vuid_event.h>
X
X#include	<stdio.h>
X
Xint kbd = NOFILE+500;	/* some impossible fd number */
Xint mouse = NOFILE+500;
Xint console = NOFILE+500;
Xint	screen_fd;
Xint	statfds;
Xint	nfds;
Xint	delay_time = 300;
Xint	debug = 0;
X
X#define max(A,B) 	(((A) > (B))?(A):(B))
Xmain (argc,argv)
Xint argc; char **argv;
X{
X
X	char c;
X	int i;
X	int do_mouse = 0;
X	int daemon = 0;
X	int use_stdin = 0;
X	if((screen_fd = open("/dev/fb",O_RDWR)) < 0)
X	{
X		Perror("open");
X		exit(1);
X	}
X	kbd = open("/dev/kbd",O_RDONLY,0);
X	mouse = -1;
X	while (--argc > 0 && (*++argv)[0] == '-')
X	{
X		switch((*argv)[1])
X		{
X		case 'D':
X			debug = 1;
X			break;
X		case 'd':
X			daemon = 1;
X			/* also must open mouse with daemon */
X		case 'm':	/* this option is pretty useless */
X			do_mouse = 1;
X			break;
X		case 't':
X			argc--; argv++;
X			if(argc <= 0)
X			{
X				fprintf(stderr,"time with no delay\n");
X				fflush(stderr);
X				exit(1);
X			}
X			i = atoi(*argv);
X			if(i > 0) delay_time = i;
X			break;
X		default:
X			break;
X		}
X	}
X	/* now, check to see if mouse is in suntools mode */
X	mouse = open("/dev/mouse",O_RDONLY,0);
X	if(mouse >= 0)
X	{
X		if((ioctl(mouse,VUIDGFORMAT,&i)) < 0)
X		{
X			Perror("ioctl on mouse to get VUIDFORMAT");
X			exit(1);
X		}
X		if(i == VUID_NATIVE && !do_mouse)	/* ignore the sucker */
X		{
X			close(mouse);
X			mouse = -1;
X		}
X	}
X
X	console = open("/dev/console",O_RDONLY,0);
X	/* mouse, kbd, and stdin */
X	if(kbd >= 0) statfds |= (1 << kbd);
X	if(mouse >= 0) statfds |= (1 << mouse);
X	if(console >= 0) statfds |= (1 << console);
X	/* if can't do this stuff, just do a getchar to block */
X	if(!statfds)
X	{
X		int q;
X		/* do a simple ioctl to see if operations on 0 fail */
X		if((ioctl(0,TIOCGPGRP,&q)) < 0)
X		{
X			/* not a terminal, and you can't read kbd or mouse,
X			** so give up, right a way
X			*/
X			fprintf(stderr,"Cannot get kbd, mouse, console, or stdin\n");
X			fflush(stderr);
X			return;
X		}
X	}
X	sleep(5);	/* give the kbd and mouse a chance to flush */
X	if(daemon)
X	{
X		run_daemon();
X		exit(0);
X	}
X	video_off();
X	delay(statfds); /* wait for some kind of input */
X	video_on();
X	exit(0);
X}
X
X
Xstruct stat sbuf;
Xrun_daemon ()
X{
X	static time_t ktime = -1, catime = -1, cmtime = -1, mtime = -1;
X	static time_t oktime = -1, ocatime = -1, ocmtime = -1, 
X			omtime = -1;
X	int t;
X
X	t = delay_time;
X	while(1)
X	{
X
X		if(debug)
X		{
X			fprintf(stderr,"Statting\n");
X			fflush(stderr);
X		}
X		if(fstat(console,&sbuf) <0)
X		{
X			Perror("fstat, console");
X			exit(1);
X		}
X		catime = sbuf.st_atime;
X		cmtime = sbuf.st_mtime;
X		if(fstat(kbd,&sbuf) <0)
X		{
X			Perror("fstat, kbd");
X			exit(1);
X		}
X		ktime = sbuf.st_atime;
X		if(fstat(mouse,&sbuf) <0)
X		{
X			Perror("fstat, mouse");
X			exit(1);
X		}
X		mtime = sbuf.st_atime;
X
X		/**** HERE'S THE SLEEP ****/
X		sleep(t);
X
X		if(fstat(kbd,&sbuf) <0)
X		{
X			Perror("fstat, kbd");
X			exit(1);
X		}
X		oktime = sbuf.st_atime - ktime;
X		if(fstat(mouse,&sbuf) <0)
X		{
X			Perror("fstat, mouse");
X			exit(1);
X		}
X		omtime = sbuf.st_atime - mtime;
X		if(fstat(console,&sbuf) <0)
X		{
X			Perror("fstat, console");
X			exit(1);
X		}
X		ocatime = sbuf.st_atime - catime;
X		ocmtime = sbuf.st_mtime - cmtime;
X
X		/* if none of the times changed 
X		** there was no access in the last t seconds. Turn
X		** off the screen.
X		*/
X
X		/* give 2 seconds leeway (that's a highway in Virginia) 
X		** for whatever */
X		if(debug)
X		{
X			fprintf(stderr,"oktime = %d, omtime = %d, ocmtime = %d, ocatime = %d\n",
X				oktime,omtime,ocmtime,ocatime);
X			fflush(stderr);
X		}
X		if(oktime < 2 && omtime < 2 && ocmtime < 2 && ocatime < 2)
X		{
X			int i;
X			int fds;
X			/* mice are a special case: they aren't always read */
X			/* now, we must check to see what mode the
X			** mouse is in. This is expensive, but only
X			** need be done every once in a while
X			** (delay time)
X			*/
X			if((ioctl(mouse,VUIDGFORMAT,&i)) < 0)
X			{
X				Perror("ioctl on mouse to get VUIDFORMAT");
X				exit(1);
X			}
X			if(i == VUID_NATIVE)	/* ignore the sucker */
X				statfds &= ~(1 << mouse);
X			else
X				statfds |= (1 << mouse);
X
X			if(debug) 
X			{
X				if(!ready(statfds))
X					fprintf(stderr,"offing\n");
X				else
X					fprintf(stderr,"would have offed\n");
X				fflush(stderr);
X			}
X			else 
X			{
X				if(!ready(statfds))
X					video_off();
X			}
X			fds = delay(statfds);
X
X			video_on();
X			t = delay_time;
X			sleep(1);	/* more leeway for jerks who do -t 1*/
X		}
X		/* if you did not need to shut the screen off,
X		** wait delay_time from the last thing that was
X		** accessed last.
X		*/
X		else
X		{
X			/** I'm not so sure this is correct. When in suntools,
X			*** you read off of /dev/kbd. When out of suntools,
X			*** /dev/console registers. Now, if octime is just
X			*** so that oc%delay = 1, (but is in fact some huge
X			*** number becuz console ain't been used since
X			*** you brought up suntools) you will black out, right
X			*** away. No, it looks like you'll have to take
X			*** a hit, such that you will black out at the maximum
X			*** time. Sigh.
X			***
X			int	i = oktime%delay_time, 
X				j = omtime%delay_time, 
X				k = octime%delay_time;
X			t = max(i,j);
X			t = max(t,k);
X			****/
X			t = max(oktime,omtime);
X			t = max(t,ocatime);
X			t = max(t,ocmtime);
X			if(t == 0 || t > delay_time) t = delay_time;
X			if(debug)
X			{
X				fprintf(stderr,"delay time = %d\n",t);
X				fflush(stderr);
X			}
X		}
X	}
X}
X
Xlast_time (time,fd)
X{
X	struct stat sbuf;
X	int retval;
X	if(fstat(fd,&sbuf) <0)
X	{
X		Perror("fstat, last_time");
X		exit(1);
X	}
X	retval = sbuf.st_atime - time;
X	return(retval);
X}
X
Xdelay (fds)
X{
X	if(!fds)
X		return(getchar());
X
X	nfds = select(NOFILE,&fds,0,0,0);
X	if(nfds < 0)
X	{
X		Perror("select");
X	}
X	return(fds);
X}
X
Xstatic struct timeval timer;	/* zeroed out */
Xready (fds)
X{
X	struct timeval t;
X	t = timer;
X	switch(select(NOFILE,&fds,0,0,&t))
X	{
X	case -1:
X		Perror("select in ready");
X		return(0);
X	default:
X		return(fds);
X	}
X}
X
X/* apparently, this is not always up-to-date...so ignore it! */
Xget_video ()
X{
X	int i;
X	int q;
X	i = ioctl(screen_fd,FBIOGVIDEO,&q);
X	return(q);
X}
X
Xvideo_off ()
X{
X	int i;
X	int q;
X	q = FBVIDEO_OFF;
X	i = ioctl(screen_fd,FBIOSVIDEO,&q);
X	if(i < 0)
X	{
X		Perror("ioctl");
X	}
X	return(i);
X}
X
Xvideo_on ()
X{
X	int i;
X	int j;
X	j = FBVIDEO_ON;
X	i = ioctl(screen_fd,FBIOSVIDEO,&j);
X	if(i < 0)
X	{
X		Perror("ioctl");
X	}
X	return(i);
X}
X
X/* was originally when the fprintf went to a separate file */
XPerror (string)
Xchar *string;
X{
X	perror(string);
X	/***
X	fprintf(stderr,"%s\n",string);
X	fflush(stderr);
X	***/
X}
EOF saver.c
if test 8826 -ne "`wc -c < 'saver.c'`"
then
	echo 'shar: "saver.c" CORRUPTED (not 8826 bytes)'
fi
fi ; : End of overwrite check
: End of shell archive
exit 0