[comp.sources.sun] v01i041: Brushdmt - a screensaver

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (07/13/89)

Submitted-by: pokey@well.sf.ca.us  (Jef Poskanzer)
Posting-number: Volume 1, Issue 40
Archive-name: brushdmt

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	brushdmt.1
#	brushdmt.c
# This archive created: Thu Jun 29 17:06:45 1989
# By:	Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(876 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X       brushdmt - alternate screen blanking program for Suns
X                       Version 1.1 of 28jun89
X                                       
XBrushdmt is a cross between the screenblank daemon and the lockscreen
Xprogram.  Like screenblank, it works automatically, and it works no
Xmatter which window system you are running, or even if you aren't
Xrunning any window system.  Like lockscreen, it does more interesting
Xthings with your screen than just blanking it.
X
XSee the manual entry for more details.
X
XFiles in this distribution:
X    README		this
X    brushdmt.1		manual entry
X    Makefile		guess
X    brushdmt.c		source code for screenblank replacement
X
XTo install:
X    Unpack the files.
X    Edit the Makefile, and define XREFRESH and SUNREFRESH appropriately.
X    Make.
X
XComments to:
X    pokey@well.sf.ca.us
X    {ucbvax, lll-crg, sun!pacbell, apple, hplabs}!well!pokey
SHAR_EOF
if test 876 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 876 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1217 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Makefile for brushdmt.
X#
X# Copyright (C) 1989 by Jef Poskanzer.
X#
X# Permission to use, copy, modify, and distribute this software and its
X# documentation for any purpose and without fee is hereby granted, provided
X# that the above copyright notice appear in all copies and that both that
X# copyright notice and this permission notice appear in supporting
X# documentation.  This software is provided "as is" without express or
X# implied warranty.
X#
X
X# If you have X installed, define this to be a command that will run
X# xrefresh.  You may need to use a full pathname, since brushdmt will
X# probably run as root and root usually has a narrow search path.  If
X# you do not have X, comment this out.
XXREFRESH =	-DXREFRESH=\"/usr/new/X10/xrefresh\"
X
X# If you use suntools, define this to point to shelltool.  Once again,
X# you may need to use a full pathname.  If no one at your site ever uses
X# sunstools, comment this out.
X#SUNREFRESH =	-DSUNREFRESH=\"/usr/bin/shelltool\"
X
Xall:		brushdmt
X
Xbrushdmt:	brushdmt.c
X	cc -O $(XREFRESH) $(SUNREFRESH) brushdmt.c -lpixrect -s -o brushdmt
X
Xshar:		brushdmt.shar
Xbrushdmt.shar:	README Makefile brushdmt.1 brushdmt.c
X	shar -v -c -p X README Makefile brushdmt.1 brushdmt.c > $@
SHAR_EOF
if test 1217 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1217 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'brushdmt.1'" '(2419 characters)'
if test -f 'brushdmt.1'
then
	echo shar: will not over-write existing file "'brushdmt.1'"
else
sed 's/^X//' << \SHAR_EOF > 'brushdmt.1'
X.TH brushdmt 1 "27 May 1989"
X.SH NAME
Xbrushdmt - alternate screen blanking program for Suns
X.SH SYNOPSIS
Xbrushdmt [-d <seconds>] [ [-j|-g] <rasterfile> ] ...
X.SH DESCRIPTION
XBrushdmt is a cross between the screenblank daemon and the lockscreen
Xprogram.
XLike screenblank, it works automatically, starting itself up after a
Xspecified interval of idle time.
XLike screenblank, it works no matter which window system you are running,
Xor even if you aren't running any window system.
XAnd like lockscreen, it does more interesting things
Xwith your screen than just blanking it.
X.PP
XThe -d flag can be used to change the idle time interval that brushdmt
Xwaits before starting itself up.
XThe default interval is 600 seconds (10 minutes).
X.PP
XThe rest of the arguments, a list of rasterfiles with interspersed
Xtype flags, control the animation that brushdmt displays.
XThe rasterfiles are read in and animated in one of two
Xways, jump mode or glide mode, as specified by the -j and -g flags.
XJump mode is the default.
XYou can mix the two modes freely; for example:
X.nf
X    brushdmt cow.r cow.r cow.r -g triangle.r
X.fi
Xputs up three cows in jump mode and a triangle in glide mode.
XIf no rasterfiles are given, a little white box with the current
Xtime is constructed.
X.PP
XNote that while jump mode uses almost no CPU time, glide mode does
Xuse a moderate amount -- about 3% of a 3/50 to glide each small raster.
XBe considerate and don't over-use glide mode, since someone else
Xmight want to use your workstation as a compute server while it's
Xidle.
X.PP
XThe name of the program comes from the similar program at Xerox.
XIn the Xerox world, "DMT" is the generic term for a screenblank program,
Xderiving from the original one for the Alto.  The original DMT actually
Xdid "diagnostic memory tests", the later versions just took the name.
XAnd "brush" is the Xerox term for a small raster file.
X.SH "SEE ALSO"
Xscreenblank(1), lockscreen(1), xrefresh(1)
X.SH "BUGS / DEFICIENCIES"
XThe refresh algorithm is less than optimal.
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 2419 -ne "`wc -c < 'brushdmt.1'`"
then
	echo shar: error transmitting "'brushdmt.1'" '(should have been 2419 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'brushdmt.c'" '(10937 characters)'
if test -f 'brushdmt.c'
then
	echo shar: will not over-write existing file "'brushdmt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'brushdmt.c'
X/*
X** brushdmt.c - an alternate screen blanking program for Suns
X**
X** Comments to:
X**   pokey@well.sf.ca.us
X**   {ucbvax, lll-crg, sun!pacbell, apple, hplabs}!well!pokey
X**
X** Copyright (C) 1989 by Jef Poskanzer.
X**
X** Permission to use, copy, modify, and distribute this software and its
X** documentation for any purpose and without fee is hereby granted, provided
X** that the above copyright notice appear in all copies and that both that
X** copyright notice and this permission notice appear in supporting
X** documentation.  This software is provided "as is" without express or
X** implied warranty.
X*/
X
X#define MAXBRUSHES 500
X#define MAXDELTA 5
X
X#define DEFAULT_WAITING_SECS 600
X
X#define BLANKING_SLEEPS_PERSEC 20
X
X#define TRYS 50
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <pixrect/pixrect_hs.h>
X
X#define min(a,b) ( (a) < (b) ? (a) : (b) )
X
XPixrect *disp_pr, *save_pr;
Xint screen_saved = 0;
Xint disp_w, disp_h;
Xint brushes;
XPixrect *brush[MAXBRUSHES];
Xint brush_w[MAXBRUSHES], brush_h[MAXBRUSHES];
Xint brush_type[MAXBRUSHES];
X#define BT_JUMP 0
X#define BT_GLIDE 1
Xint any_jumpers, any_gliders;
Xint brush_x[MAXBRUSHES], brush_y[MAXBRUSHES];
Xint brush_dx[MAXBRUSHES], brush_dy[MAXBRUSHES];
XPixfont *font;
Xint font_width, font_height, null_yoffset;
X
Xunsigned waiting_secs;
Xunsigned blanking_usecs;
X
Xtime_t curr_time, last_time;
X
Xlong random(), time();
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    int argn, type;
X    colormap_t colormap;
X    FILE *fd;
X    unsigned idle, idle_time();
X    int sighandler();
X    char *usage = "usage:  %s [-d <seconds>] [ [-j|-g] <rasterfile> ] ...\n";
X
X    /* Open display. */
X    if ( (disp_pr = pr_open( "/dev/fb" )) == (Pixrect *) 0 )
X	{
X	(void) fprintf( stderr, "%s: error opening display\n", argv[0] );
X	exit( 1 );
X	}
X    disp_w = disp_pr->pr_size.x;
X    disp_h = disp_pr->pr_size.y;
X    if ( (save_pr = mem_create(disp_w,disp_h,disp_pr->pr_depth)) == (Pixrect *) 0 )
X	{
X	(void) fprintf(
X	    stderr, "%s: not enough memory to save display\n", argv[0] );
X	exit( 1 );
X	}
X
X    /* Parse args. */
X    argn = 1;
X    brushes = 0;
X    any_jumpers = any_gliders = 0;
X    type = BT_JUMP;
X    colormap.type = RMT_NONE;
X    waiting_secs = DEFAULT_WAITING_SECS;
X
X    while ( argn < argc )
X	{
X	if ( strcmp( argv[argn], "-d" ) == 0 )
X	    {
X	    argn++;
X	    if ( argn >= argc ||
X		 sscanf( argv[argn], "%d", &waiting_secs ) != 1 )
X		{
X		(void) fprintf( stderr, usage, argv[0] );
X		exit( 1 );
X		}
X	    }
X	else if ( strcmp( argv[argn], "-g" ) == 0 )
X	    type = BT_GLIDE;
X	else if ( strcmp( argv[argn], "-j" ) == 0 )
X	    type = BT_JUMP;
X	else if ( argv[argn][0] == '-' && argv[argn][1] != '\0' )
X	    {
X	    (void) fprintf( stderr, usage, argv[0] );
X	    exit( 1 );
X	    }
X	else
X	    {
X	    if ( strcmp( argv[argn], "-" ) == 0 )
X		fd = stdin;
X	    else
X		if ( (fd = fopen( argv[argn], "r" )) == (FILE *) 0 )
X		    {
X		    perror( argv[argn] );
X		    exit( 1 );
X		    }
X	    if ( (brush[brushes] = pr_load(fd,&colormap)) == (Pixrect *) 0 )
X		{
X		(void) fprintf(
X		    stderr, "%s: error reading brush from %s\n",
X		    argv[0], argv[argn] );
X		exit( 1 );
X		}
X	    if ( fd != stdin )
X		(void) fclose( fd );
X	    if ( brush[brushes]->pr_depth > disp_pr->pr_depth )
X		{
X		(void) fprintf(
X		    stderr, "%s: brush in %s is too deep for this display\n",
X		    argv[0], argv[argn] );
X		exit( 1 );
X		}
X	    brush_w[brushes] = brush[brushes]->pr_size.x;
X	    brush_h[brushes] = brush[brushes]->pr_size.y;
X	    brush_type[brushes] = type;
X	    if ( ! newxy( brushes ) )
X		{
X		(void) fprintf(
X		    stderr, "%s: not enough room on the screen!\n", argv[0] );
X		exit( 1 );
X		}
X	    if ( type == BT_JUMP )
X		any_jumpers = 1;
X	    else if ( type == BT_GLIDE )
X		{
X		any_gliders = 1;
X		newdeltas( brushes );
X		}
X	    brushes++;
X	    }
X	argn++;
X	}
X    
X    if ( brushes == 0 )
X	{
X	if ( (font = pf_default( )) == (Pixfont *) 0 )
X	    {
X	    (void) fprintf( stderr, "%s: error opening font\n", argv[0] );
X	    exit( 1 );
X	    }
X	font_width = font->pf_defaultsize.x;
X	font_height = font->pf_defaultsize.y;
X	brush[brushes] = (Pixrect *) 0;
X	brush_w[brushes] = 10 * font_width;
X	brush_h[brushes] = 3 * font_height;
X	brush_type[brushes] = type;
X	(void) newxy( brushes );
X	if ( type == BT_JUMP )
X	    any_jumpers = 1;
X	else if ( type == BT_GLIDE )
X	    {
X	    any_gliders = 1;
X	    newdeltas( brushes );
X	    }
X	null_yoffset =
X	    ( brush_h[brushes] - 2 * font_height ) / 2 -
X	    font->pf_char[77].pc_home.y;
X	brushes++;
X	}
X
X    srandom( (int) time( (long *) 0 ) );
X    (void) signal( SIGHUP, sighandler );
X    (void) signal( SIGINT, sighandler );
X    (void) signal( SIGTERM, sighandler );
X    (void) nice( 15 );
X
X    blanking_usecs = 1000000 / BLANKING_SLEEPS_PERSEC;
X    for ( ; ; )
X	{
X	idle = 0;
X	do
X	    {
X	    sleep( waiting_secs - idle );
X	    }
X	while ( ( idle = idle_time( ) ) < waiting_secs );
X	blank_init( );
X	do
X	    {
X	    blank( );
X	    usleep( blanking_usecs );
X	    }
X	while ( idle_time( ) >= waiting_secs );
X	blank_term( );
X	}
X    }
X
Xblank_init( )
X    {
X    int i;
X
X    save_screen( );
X    pr_rop( disp_pr, 0, 0, disp_w, disp_h, PIX_SET, (Pixrect *) 0, 0, 0 );
X    for ( i = 0; i < brushes; i++ )
X	draw_brush( i );
X    last_time = curr_time;
X    }
X
Xblank( )
X    {
X    int i;
X
X    if ( any_jumpers )
X	{
X	if ( curr_time != last_time )
X	    {
X	    last_time = curr_time;
X	    /* Handle jumpers. */
X	    for ( i = 0; i < brushes; i++ )
X		if ( brush_type[i] == BT_JUMP )
X		    if ( random() % 3 == 0 )
X			{
X			pr_rop(
X			    disp_pr, brush_x[i], brush_y[i], brush_w[i],
X			    brush_h[i], PIX_SET, (Pixrect *) 0, 0, 0 );
X			(void) newxy( i );
X			draw_brush( i );
X			}
X		    else if ( brush[i] == (Pixrect *) 0 )
X			/* Always draw null brush, even if it doesn't move. */
X			draw_brush( i );
X	    }
X	}
X
X    if ( any_gliders )
X	{
X	/* Handle gliders. */
X	for ( i = 0; i < brushes; i++ )
X	    if ( brush_type[i] == BT_GLIDE )
X		{
X		int oldx, oldy;
X
X		oldx = brush_x[i];
X		oldy = brush_y[i];
X		if ( glidexy( i ) )
X		    {
X		    /* Draw in new position. */
X		    draw_brush( i );
X		    /* Erase remains of old position. */
X		    if ( brush_dx[i] > 0 )
X			pr_rop(
X			    disp_pr, oldx, oldy, brush_dx[i], brush_h[i],
X			    PIX_SET, (Pixrect *) 0, 0, 0 );
X		    else if ( brush_dx[i] < 0 )
X			pr_rop(
X			    disp_pr, oldx + brush_w[i] + brush_dx[i], oldy,
X			    -brush_dx[i], brush_h[i], PIX_SET,
X			    (Pixrect *) 0, 0, 0 );
X		    if ( brush_dy[i] > 0 )
X			pr_rop(
X			    disp_pr, oldx, oldy, brush_w[i], brush_dy[i],
X			    PIX_SET, (Pixrect *) 0, 0, 0 );
X		    else if ( brush_dy[i] < 0 )
X			pr_rop(
X			    disp_pr, oldx, oldy + brush_h[i] + brush_dy[i],
X			    brush_w[i], -brush_dy[i], PIX_SET,
X			    (Pixrect *) 0, 0, 0 );
X		    }
X		}
X	}
X    }
X
Xblank_term( )
X    {
X    restore_screen( );
X    }
X
Xdraw_brush( i )
Xint i;
X    {
X    if ( brush[i] != (Pixrect *) 0 )
X	pr_rop(
X	    disp_pr, brush_x[i], brush_y[i], brush_w[i], brush_h[i],
X	    PIX_SRC, brush[i], 0, 0 );
X    else
X	{
X	/* Null brush. */
X	char *timestr;
X
X	pr_rop(
X	    disp_pr, brush_x[i], brush_y[i],
X	    brush_w[i], brush_h[i], PIX_CLR, (Pixrect *) 0, 0, 0 );
X	/*
X	** curr_time is kept up to date by idle_time(); otherwise we
X	** would just do a time( 0 ) here.
X	*/
X	timestr = ctime( &curr_time );
X	/*
X	** Format of timestr: Wdy Mon DD HH:MM:SS YYYY\n
X	**                    0    5    10   15   20
X	*/
X	/* First line: HH:MM:SS */
X	timestr[19] = '\0';
X	pr_text(
X	    disp_pr, brush_x[i] + ( brush_w[i] - 8 * font_width ) / 2,
X	    brush_y[i] + null_yoffset, PIX_SRC, font, &(timestr[11]) );
X	/* Second line: Mon DD */
X	timestr[10] = '\0';
X	pr_text(
X	    disp_pr, brush_x[i] + ( brush_w[i] - 6 * font_width ) / 2,
X	    brush_y[i] + null_yoffset + font_height, PIX_SRC, font,
X	    &(timestr[4]) );
X	}
X    }
X
Xunsigned
Xidle_time( )
X    {
X    struct stat sb;
X    long mintime;
X
X    curr_time = time( (long *) 0 );
X
X    my_stat( "/dev/mouse", &sb );
X    mintime = curr_time - sb.st_atime;
X    mintime = min( mintime, curr_time - sb.st_mtime );
X
X    my_stat( "/dev/kbd", &sb );
X    mintime = min( mintime, curr_time - sb.st_atime );
X    mintime = min( mintime, curr_time - sb.st_mtime );
X
X    my_stat( "/dev/console", &sb );
X    mintime = min( mintime, curr_time - sb.st_atime );
X    mintime = min( mintime, curr_time - sb.st_mtime );
X
X    return mintime;
X    }
X
Xmy_stat( dev, sbP )
Xchar *dev;
Xstruct stat *sbP;
X    {
X    if ( stat( dev, sbP ) < 0 )
X	{
X	(void) fprintf( stderr, "stat" );
X	perror( dev );
X	exit( 1 );
X	}
X    }
X
Xint
Xnewxy( i )
Xint i;
X    {
X    int oldx, oldy;
X    int j;
X
X    oldx = brush_x[i];
X    oldy = brush_y[i];
X    for ( j = 0; j < TRYS; j++ )
X	{
X	brush_x[i] = random() % ( disp_w - brush_w[i] );
X	brush_y[i] = random() % ( disp_h - brush_h[i] );
X	if ( ! collision( i ) )
X	    return 1;
X	}
X
X    brush_x[i] = oldx;
X    brush_y[i] = oldy;
X    return 0;
X    }
X
Xint
Xglidexy( i )
Xint i;
X    {
X    int oldx, oldy;
X    int j;
X
X    oldx = brush_x[i];
X    oldy = brush_y[i];
X    for ( j = 0; j < TRYS; j++ )
X	{
X	brush_x[i] = oldx + brush_dx[i];
X	brush_y[i] = oldy + brush_dy[i];
X	if ( brush_x[i] >= 0 && brush_x[i] + brush_w[i] < disp_w &&
X	     brush_y[i] >= 0 && brush_y[i] + brush_h[i] < disp_h &&
X	     ! collision( i ) )
X	    return 1;
X	newdeltas( i );
X	}
X
X    brush_x[i] = oldx;
X    brush_y[i] = oldy;
X    return 0;
X    }
X
Xint collision( i )
Xint i;
X    {
X    int j;
X    register int x1, y1, w1, h1;
X    register int x2, y2, w2, h2;
X
X    x1 = brush_x[i];
X    y1 = brush_y[i];
X    w1 = brush_w[i];
X    h1 = brush_h[i];
X    for ( j = 0; j < brushes; j++ )
X	if ( j != i )
X	    {
X	    x2 = brush_x[j];
X	    y2 = brush_y[j];
X	    w2 = brush_w[j];
X	    h2 = brush_h[j];
X	    if ( x1 < x2 + w2 && x2 < x1 + w1 &&
X	         y1 < y2 + h2 && y2 < y1 + h1 )
X		return 1;
X	    }
X
X    return 0;
X    }
X
Xnewdeltas( i )
Xint i;
X    {
X    brush_dx[i] = random() % ( MAXDELTA * 2 ) - MAXDELTA;
X    if ( brush_dx[i] <= 0 ) brush_dx[i]--;
X    brush_dy[i] = random() % ( MAXDELTA * 2 ) - MAXDELTA;
X    if ( brush_dy[i] <= 0 ) brush_dy[i]--;
X    }
X
X/* ARGSUSED */
Xint
Xsighandler( sig, code, scp )
Xint sig, code;
Xstruct sigcontext *scp;
X    {
X    restore_screen( );
X    exit( 0 );
X    }
X
Xsave_screen( )
X    {
X    pr_rop( save_pr, 0, 0, disp_w, disp_h, PIX_SRC, disp_pr, 0, 0 );
X    screen_saved = 1;
X    }
X
Xrestore_screen( )
X    {
X    if ( screen_saved )
X	{
X	char command[200];
X
X	/*
X	** Refresh the screen as well as we can, which is not very.
X	** Perhaps no one will notice.
X	*/
X	pr_rop( disp_pr, 0, 0, disp_w, disp_h, PIX_SRC, save_pr, 0, 0 );
X
X#ifdef XREFRESH
X	/* If X happens to be running, do a real refresh. */
X	sprintf( command, "%s 2> /dev/null &", XREFRESH );
X	(void) system( command );
X#endif XREFRESH
X
X#ifdef SUNREFRESH
X	/* If suntools happens to be running, do a real refresh. */
X	sprintf(
X	    command,
X	    "%s -position 0 0 -size %d %d -label refresh true 2> /dev/null &",
X	    SUNREFRESH, disp_w, disp_h );
X	(void) system( command );
X#endif SUNREFRESH
X
X	screen_saved = 0;
X	}
X    }
SHAR_EOF
if test 10937 -ne "`wc -c < 'brushdmt.c'`"
then
	echo shar: error transmitting "'brushdmt.c'" '(should have been 10937 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0