Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v09i053: Screensaver for X window system, Part02/02

7 views
Skip to first unread message

sources...@mirror.tmc.com

unread,
Apr 20, 1987, 4:23:45 PM4/20/87
to
Submitted by: ed...@opal.Berkeley.EDU
Mod.sources: Volume 9, Issue 53
Archive-name: xscreen/Part02

This is part 2/2 of screensaver, a display blanking and lock screen
program for X version 10, release 4. Enjoy.

Edward Moy
Academic Computing Services
University of California
Berkeley, CA 94720

ed...@opal.Berkeley.EDU
ucbvax!opal!edmoy

#! /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:
# screensaver.1
# screensaver.c
if test -f screensaver.1
then
echo shar: will not overwrite existing file "'screensaver.1'"
else
echo 'x - screensaver.1'
cat << \RAZZLE!DAZZLE > screensaver.1
.TH SCREENSAVER 1 "Jan 1987" "X Version 10"
.SH NAME
screensaver \- blanks display
.SH SYNOPSIS
.B screensaver
[
.B \-L
tty
] [
.B \-b
bitmap_file
] [
.B \-f
font
] [
.B \-i
file
] [
.B \-l
] [
.B \-t
seconds
] [
geometry
] [
display
]
.SH DESCRIPTION
.I Screensaver
is a client application running under the X windowing system that blanks
the display after a certain period of idle time; 5 minutes is the default
or set by the
.B \-t
option.
The display is restored by pressing a key or a mouse button.
Unlike the screensaver function built into the X server, this program
only detects input activity (rather than output to the display also), so
that screensaving works even with clocks, load monitor, etc. running.
.PP
When executed,
.I screensaver
splits off a child process to run in the background.
The child first reads in a file in
.IR bitmap (1)
format; the default file is
.B /usr/local/lib/X/Xscreensaver
but can be specified by the
.B \-b
option.
This bitmap is bounced (slowly) around the display, and at random times, the
angle of reflection will also be at random.
.PP
If a file exists with the same name as the bitmap file, but with
.B \&.pm
appended to it, then this bitmap is also read in.
The original bitmap is displayed during AM hours and this second bitmap,
during PM hours.
.PP
If the file is not in
.IR bitmap (1)
format, it is assumed to be a sequence of lines containing 4 items, separated
by white space.
The first item is the name of another file (which must be in
.IR bitmap (1)
format).
If a relative pathname is specified, it is relative to the directory of
the original file.
The second item on the line is the color of this part of the bitmap, and
the last two items are the relative x and y coordinate of this bitmap to
the whole bitmap.
Thus, a full color bitmap can be produced.
.PP
By default, the font used to display the time while the bitmap is being
bounced around the screen is
.BR 9x15 .
An alternate font may be specified by using the
.B \-f
option.
.PP
The
.B \-l
option sets the auto-lock feature, that requests the password of the
current user before un-blanking the screen (the root password will
always unlock the screen).
.PP
When the X window system and
.I screensaver
are started at boot time, the
.B \-L
flag should be given with the tty of the login window.
This automatically disables the locking feature if no one is logged
into the login window.
.PP
Normally,
.I screensaver
checks the master end of all pseudo-tty's to determine input activity.
This is imperfect, as not all applications use pseudo-tty's and mouse
activity is not considered at all.
If the
.B \-i
option is specified to the X server, then it will update the
file changed time on the specified file when any keyboard or mouse
input occurs.
Specifying the same
.B \-i
option and file to
.I screensaver
will then cause it to monitor this file and determine when to blank the screen.
This option also allows
.I screensaver
to run on hosts with multiple displays, as each separate X server could
specify a different file to update.
.PP
The initial position of the icon is in the upper left-hand corner of the
display, but can be set to any other position by using the
.I geometry
argument:
.TP \w'\fB=+\fIx\fB+\fIy\fR'u+4n
\fB=+\fIx\fB+\fIy\fR
(+\fIx\fP,+\fIy\fP) from upper lefthand corner
.TP
\fB=+\fIx\fB\-\fIy\fR
(+\fIx\fP,\-\fIy\fP) from lower lefthand corner
.TP
\fB=\-\fIx\fB+\fIy\fR
(\-\fIx\fP,+\fIy\fP) from upper righthand corner
.TP
\fB=\-\fIx\fB\-\fIy\fR
(\-\fIx\fP,\-\fIy\fP) from lower righthand corner
.PP
The display
.I screensaver
will blank is specified in the
.B DISPLAY
environment variable, or as
.I display
on the command line.
.PP
If either the left or right button of the mouse is released while the cursor
is in the icon, the display will be instantly blanked.
If the middle button is pressed, a menu is displayed, allowing various
parameters to be set, such as auto-locking on timeouts and turning on and
off the automatic timeouts.
.SH FILES
.TP \w'/usr/local/lib/X/Xscreensaver.pm'u+4n
/usr/local/lib/X/Xscreensaver
Default bitmap.
.TP
/usr/local/lib/X/Xscreensaver.pm
Default PM hours bitmap (optional).
.SH SEE ALSO
bitmap(1)
.SH AUTHOR
Written by Edward Moy, Academic Computing Services, University of
California at Berkeley.
RAZZLE!DAZZLE
fi # End screensaver.1
if test -f screensaver.c
then
echo shar: will not overwrite existing file "'screensaver.c'"
else
echo 'x - screensaver.c'
cat << \RAZZLE!DAZZLE > screensaver.c
/*
* screensaver - blanks displays under X window system
* (requires X version 10)
*
* Written by:
* Edward Moy
* Academic Computing Services
* University of California at Berkeley
*/
#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <pwd.h>
#include <setjmp.h>
#include <utmp.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/file.h>
#include <X/Xlib.h>
#include "menu.h"
#include "arrow"
#include "arrowmask"

#define AnyButtonMask (LeftMask | MiddleMask | RightMask)
#define BITMAPOPENERR 0
#define BITMAPOK 1
#define BITSPERBYTE 8
#define BITSPERSHORT (BITSPERBYTE * sizeof(short))
#define BOTTOM 3
#define CURHEIGHT 16
#define CURWIDTH 16
#define DEFAULTHEIGHT 38
#define DEFAULTWIDTH 48
#define DELTA 4
#define FALSE 0
#define IDLETIME 300
#define IMAGESPERSEC 5
#define LEFT 0
#define MICROSEC (1000000 / IMAGESPERSEC)
#define NWALLS 4
#define PAD 4
#define PASSWORDLEN 9
#define RANCNTMAX 32
#define RIGHT 2
#define SELECTERR -1
#define SINN 20
#define TIMEOUT 0
#define TOP 1
#define TRUE 1
#define USERLEN 5
#define VERIFYTIMEOUT 45

#define max(a,b) ((a) > (b) ? (a) : (b))
#define rangex(x) ((x) >= areawidth ? areawidth-1 : ((x) < 0 ? 0 : (x)))
#define rangey(y) ((y) >= areaheight ? areaheight-1 : ((y) < 0 ? 0 : (y)))
#define xmove(x) (signx * sin1000[SINN - sinindex] * x / 1000 + x0)
#define ymove(y) (signy * sin1000[sinindex] * y / 1000 + y0)

#define MENU_ONOFF 0
#define MENU_AUTOLOCK (MENU_ONOFF+1)
#define MENU_LINE (MENU_AUTOLOCK+1)
#define MENU_BLANK (MENU_LINE+1)
#define MENU_LOCK (MENU_BLANK+1)
#define MENU_LINE2 (MENU_LOCK+1)
#define MENU_EXIT (MENU_LINE2+1)

struct bm {
struct bm *next;
short *bits;
int x;
int y;
int width;
int height;
int color;
};

int am;
int amicon;
int areaheight;
int areawidth;
Cursor arrow;
int autolock;
char *bitmap_file = XSCREENSAVER;
int bitmap_height;
int bitmap_width;
Window black;
Cursor blackcursor;
int center;
FILE *console = stderr;
short *cursor_bits;
int cursor_height;
int cursor_width;
FontInfo *finfo;
Font font;
int fontheight;
char *fontname = "9x15";
int halfwidth;
Window icon;
int iconx = DELTA;
int idletime = IDLETIME;
struct timeval idletimeout = {
IDLETIME,
0,
};
Pixmap image;
int imageheight;
Pixmap imagepm;
int imagewidth;
int locked;
char *mtext[] = {
"Screensaving",
"Auto-Lock",
"-",
"Blank Screen",
"Lock Screen",
"-",
"Exit",
0,
};
struct timeval movetimeout = {
0,
MICROSEC,
};
Menu *menu;
char *myname;
int mynamelen;
int newtime;
Vertex outline[5] = {
{0, 0, VertexDontDraw},
{0, 0, VertexRelative},
{0, 0, VertexRelative},
{0, 0, VertexRelative},
{0, 0, VertexRelative},
};
char password[] = "Password:";
int passwordwidth;
struct passwd *pw;
int rancnt;
char rootpasswd[32];
int screensave = TRUE;
int sin1000[SINN + 1] = {
258, 309, 358, 406, 453, 500, 544, 587, 629, 669,
707, 743, 777, 809, 838, 866, 891, 913, 933, 951,
965,
};
int sinindex;
int signx;
int signy;
int spacewidth;
int step;
Pixmap text;
int timemove;
struct timeval *timeout;
struct itimerval timer;
char timestr[] = "00:00";
int timewidth;
char *tty;
char user[] = "User:";
int userwidth;
jmp_buf verifyjmp;
struct timeval verifytimeout = {
VERIFYTIMEOUT,
0,
};
int X_input_fd = -1;
int x0;
int xlast;
int y0;
int ylast;

extern int errno;

main(argc, argv)
char **argv;
{
register XEvent *ev;
register int i, maxfds, status, readfds;
register char *cp, *disp = NULL, *geom = NULL, *Xin = NULL;
register Display *display;
int rfds;
XEvent xevent;

if(myname = rindex(argv[0], '/'))
myname++;
else
myname = argv[0];
mynamelen = strlen(myname);
if(cp = XGetDefault(myname, "AutoLock"))
if(strcmp(cp, "on") == 0)
autolock = TRUE;
if(cp = XGetDefault(myname, "BitmapFile"))
bitmap_file = cp;
if(cp = XGetDefault(myname, "Font"))
fontname = cp;
if(cp = XGetDefault(myname, "IdleTime"))
idletime = idletimeout.tv_sec = atoi(cp);
if(cp = XGetDefault(myname, "InputTrack"))
Xin = cp;
while(--argc > 0) {
if(**++argv == '-')
switch((*argv)[1]) {
case 'L': /* login tty */
if(--argc <= 0)
fatal("No argument for -L");
if(strncmp(tty = *++argv, "tty", 3) != 0)
fatal("Illegal argument for -L");
break;
case 'b': /* alternate bitmap file */
if(--argc <= 0)
fatal("No argument for -b");
bitmap_file = *++argv;
break;
case 'f': /* alternate font */
if(--argc <= 0)
fatal("No argument for -f");
fontname = *++argv;
break;
case 'i': /* X input track file */
if(--argc <= 0)
fatal("No argument for -i");
Xin = *++argv;
break;
case 'l': /* set auto-lock */
autolock = TRUE;
break;
case 't': /* different idle time */
if(--argc <= 0)
fatal("No argument for -t");
if((idletime = idletimeout.tv_sec =
atoi(*++argv)) <= 0)
fatal("Illegal argument for -t");
break;
default:
fatal("Unknown option");
}
else if(**argv == '=')
geom = *argv;
else break;
}
if(argc > 0 && index(disp = *argv, ':') == NULL)
fatal("Illegal display");
if((pw = getpwnam("root")) && *pw->pw_passwd)
strcpy(rootpasswd, pw->pw_passwd);
if(!tty) {
if((pw = getpwuid(getuid())) == NULL)
fatal("No password entry");
endpwent();
}
/*
* Let the parent exit; the child will do the real work.
*/
#ifndef DEBUG
if((i = fork()) < 0)
fatal("Can't fork");
if(i) /* the parent */
exit(0);
#endif DEBUG
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
nice(10);
if(tty) {
/*
* Detach the controlling tty.
*/
for (i = 0; i < 10; i++)
(void) close(i);
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
if((i = open("/dev/tty", 2)) >= 0) {
ioctl(i, TIOCNOTTY, 0);
(void) close(i);
}
console = NULL;
signal(SIGHUP, SIG_IGN);
}
#ifdef DEBUG
freopen("ss.db", "w", stderr);
setlinebuf(stderr);
#endif DEBUG
/*
* Wait until the server is active.
*/
while((display = XOpenDisplay(disp)) == NULL)
sleep(10);
if(Xin)
X_input_fd = open(Xin, O_RDONLY, 0);
init(geom);
/*
* Initialize the select system call's maximum file
* descriptor number to be one more than the file descriptor
* number of the X connection.
*/
maxfds = dpyno() + 1;
/*
* Use the select system call on the file descriptor in
* the display structure to determine if there is work
* to be done. If not block until timeout. Remember to
* reset the file descriptor before each select.
*/
readfds = 1 << dpyno();
/*
* The main process loop. After the first sleep period, we check if
* the master ends of all ptys have been written to within the idle
* period. If not, we blank the screen. Otherwise we calculate
* when we should wake up again to check.
*/
timeout = screensave ? &idletimeout : NULL;
ev = &xevent;
XSync(TRUE);
for( ; ; ) {
if(XPending()) {
XNextEvent(ev);
switch(ev->type) {
case UnmapWindow:
/*
* If we are still in movetimeout mode, then
* something unmapped use. If we are locked
* remap the black window and go through the
* verification process.
*/
if(timeout == &movetimeout) {
if(locked) {
XUnmapWindow(icon);
XMapWindow(black);
}
restorescreen();
}
break;
case ButtonReleased:
case KeyPressed:
/*
* Restore the screen and map the icon if we are
* in move timeout mode.
*/
if(ev->window == black) {
if(timeout == &movetimeout)
restorescreen();
} else if(ev->type != ButtonReleased ||
(((XButtonEvent *)ev)->detail & 0xff)
!= MiddleButton) {
XUnmapWindow(icon);
blank(autolock);
i = IMAGESPERSEC;
}
break;
case ButtonPressed:
/*
* For the icon, do the menu if middle button.
*/
if(ev->window != black &&
(((XButtonEvent *)ev)->detail & 0xff)
== MiddleButton)
i = domenu(ev);
break;
case ExposeWindow:
if(ev->window == black) {
/*
* If we are still doing an idle
* timeout, a window manager must
* have deiconified us.
*/
if(timeout == &idletimeout) {
blank(autolock);
i = IMAGESPERSEC;
}
} else
/*
* refresh the icon
*/
refreshicon();
break;
}
} else {
rfds = readfds;
if((status = select(maxfds, &rfds, NULL, NULL, timeout))
< 0) {
if(errno != EINTR)
fatal("Error in select");
} else if(status == TIMEOUT) {
if(timeout == &idletimeout) {
if((timeout->tv_sec = tryagain()) == 0){
XUnmapWindow(icon);
blank(autolock);
i = IMAGESPERSEC;
}
} else {
drawimage();
if(--i <= 0) {
XRaiseWindow(black);
XSync(FALSE);
newtimestr();
i = IMAGESPERSEC;
}
}
}
}
}
}

/*
* init() does most of the window/bitmap initialization.
*/
init(geom)
char *geom;
{
register Bitmap pic, cur;
register int i;
register Pixmap *ip;
struct bm *head, *headam, *headpm;
register int xx, yy, compensate = FALSE;
int x = 0;
int y = 0;
int w, h;
char pmname[128];
extern int onalarm();

/*
* Make a window the size of the root window, so that it will cover up
* the entire screen.
*/
#ifdef DEBUG
if((black = XCreateWindow(RootWindow, 0, 0, DisplayWidth(),
DisplayHeight() / 2, 0, (Pixmap)0, BlackPixmap)) == NULL)
#else DEBUG
if((black = XCreateWindow(RootWindow, 0, 0, DisplayWidth(),
DisplayHeight(), 0, (Pixmap)0, BlackPixmap)) == NULL)
#endif DEBUG
fatal("Can't create window");
XSelectInput(black, KeyPressed | ButtonPressed | ButtonReleased |
ExposeWindow | UnmapWindow);
/*
* Make an all black cursor, which will be invisible against the
* window's black tile.
*/
XQueryCursorShape(CURWIDTH, CURHEIGHT, &cursor_width, &cursor_height);
if((cursor_bits = (short *)calloc((cursor_width + (BITSPERSHORT - 1))
/ BITSPERSHORT * cursor_height, sizeof(short))) == NULL)
fatal("No memory for cursor");
if((cur = XStoreBitmap(cursor_width, cursor_height, cursor_bits)) ==
NULL)
fatal("Can't make cursor");
free(cursor_bits);
if((blackcursor = XStoreCursor(cur, cur, 0, 0, BlackPixel, BlackPixel,
GXcopy)) == NULL)
fatal("Can't build cursor");
XFreeBitmap(cur);
XDefineCursor(black, blackcursor);
/*
* Now get the font and the font info for the characters of the time.
*/
if((finfo = XOpenFont(fontname)) == NULL)
fatal("Can't get font");
font = finfo->id;
fontheight = finfo->height + DELTA;
outline[4].y = -(outline[2].y = 5 * finfo->height + 5);
/*
* We create the image by reading in the bitmap(s) and making the
* icon the right size. Then we draw the image in the icon and save it
* with addition black space space all around (except the top), so
* that we can just redraw the image, which will overwrite the
* previous image (no erasing is needed).
*/
setupimage(bitmap_file, &bitmap_width, &bitmap_height, &headam, FALSE);
strcpy(pmname, bitmap_file);
strcat(pmname, ".pm");
if(setupimage(pmname, &w, &h, &headpm, TRUE)) {
if(w > bitmap_width)
bitmap_width = w;
if(h > bitmap_height)
bitmap_height = h;
} else
headpm = NULL;
x0 = y0 = DELTA;
/*
* This is how far to move horizontally from the upper left
* corner of the bitmap to the upper left corner of the time
* string.
*/
timemove = (bitmap_width - (timewidth = XStringWidth(timestr,
finfo, 0, 0))) / 2;
halfwidth = XStringWidth("0", finfo, 0, 0) / 2;
if(timemove < 0) {
compensate = TRUE;
iconx = (x0 -= timemove);
timemove = 0;
}
/*
* The image will be a pixmap containing the bitmap and room for
* the time string. It will be further enlarged with a black
* border so that we can simply redraw the image, which will
* overlap the image one step size back.
*/
imagewidth = max(bitmap_width, timewidth) + 2 * DELTA;
imageheight = bitmap_height + DELTA;
/*
* Determine the position of the icon.
*/
if(geom && (i = XParseGeometry(geom, &x, &y, &w, &h))) {
if((i & XValue) && (i & XNegative))
x = DisplayWidth() + x - imagewidth - 2 * PAD;
if((i & YValue) && (i & YNegative))
#ifdef DEBUG
y = DisplayHeight() / 2 + y - imageheight - 2 * PAD -
DELTA;
#else DEBUG
y = DisplayHeight() + y - imageheight - 2 * PAD - DELTA;
#endif DEBUG
}
/*
* Create the icon window, positioned by the geom string, but
* compensate so that the icon is initially all on the screen.
* This is so we can make a pixmap of the image. The window is
* then reset to what the user wants.
*/
if((xx = x) < 0) {
compensate = TRUE;
xx = 0;
}
if((yy = y) < 0) {
compensate = TRUE;
yy = 0;
}
if(xx > (i = DisplayWidth() - imagewidth - 2 * PAD)) {
compensate = TRUE;
xx = i;
}
if(yy > (i = DisplayHeight() - imageheight - 2 * PAD)) {
compensate = TRUE;
yy = i;
}
if((icon = XCreateWindow(RootWindow, xx, yy, imagewidth, imageheight +
DELTA, PAD, WhitePixmap, BlackPixmap)) == NULL)
fatal("Can't create icon window");
if(arrow = XCreateCursor(arrow_width, arrow_height, arrow_bits,
arrowmask_bits, arrow_x_hot, arrow_y_hot, BlackPixel, WhitePixel,
GXcopy))
XDefineCursor(icon, arrow);
/*
* Grab the server to make sure we get the icon done properly.
*/
#ifndef DEBUG
XGrabServer();
#endif DEBUG
XMapWindow(icon);
if(headpm) {
signal(SIGALRM, SIG_IGN);
seticonalarm();
if(amicon) {
head = headpm;
ip = &imagepm;
} else {
head = headam;
ip = &image;
}
drawbm(head);
*ip = XPixmapSave(icon, 0, DELTA, imagewidth, imageheight);
XClear(icon);
if(i = amicon) {
head = headam;
ip = &image;
} else {
head = headpm;
ip = &imagepm;
}
} else {
head = headam;
ip = &image;
}
drawbm(head);
*ip = XPixmapSave(icon, 0, DELTA, imagewidth, imageheight);
if(!image && !imagepm)
fatal("Can't make image");
if(!image) {
image = imagepm;
imagepm = NULL;
}
#ifndef DEBUG
XUngrabServer();
#endif DEBUG
XSelectInput(icon, ExposeWindow | ButtonPressed | ButtonReleased);
XSetIconWindow(black, icon);
if(compensate) {
XConfigureWindow(icon, x, y, bitmap_width + 2 * DELTA,
bitmap_height + 2 * DELTA);
refreshicon();
}
signal(SIGALRM, onalarm);
if(imagepm) {
seticonalarm();
if(i != amicon)
refreshicon();
}
/*
* The area is the size on the rectangle that the image will
* bounce in. Since everything is with reference to the upper
* left corner, all we need to do is prevent the upper left
* corner of the image from going outside the area bounds.
*/
areawidth = DisplayWidth() - imagewidth;
#ifdef DEBUG
areaheight = DisplayHeight() / 2 - imageheight - fontheight;
#else DEBUG
areaheight = DisplayHeight() - imageheight - fontheight;
#endif DEBUG
spacewidth = XStringWidth("n", finfo, 0, 0);
passwordwidth = XStringWidth(password, finfo, 0, 0) + 2 * spacewidth;
userwidth = XStringWidth(user, finfo, 0, 0) + spacewidth;
signx = (random() & 1) ? 1 : -1;
signy = (random() & 1) ? 1 : -1;
}

drawbm(bp)
register struct bm *bp;
{
register struct bm *np;
register Bitmap mask;

if(bp->bits == NULL) { /* default */
XPixSet(icon, x0, y0, DEFAULTWIDTH, DEFAULTHEIGHT, WhitePixel);
XPixSet(icon, x0 + PAD, y0 + PAD, DEFAULTWIDTH - 2 * PAD,
DEFAULTHEIGHT - 2 * PAD, BlackPixel);
free((char *)bp);
return;
}
while(bp) {
if(mask = XStoreBitmap(bp->width, bp->height, bp->bits)) {
XPixFill(icon, x0 + bp->x, y0 + bp->y, bp->width,
bp->height, bp->color, mask, GXcopy, AllPlanes);
XFreeBitmap(mask);
}
np = bp->next;
free((char *)bp);
bp = np;
}
}

/*
* restorescreen() unmaps the black window, maps the icon window and sets the
* idle timeout. If locked, then verify password.
*/
restorescreen()
{
if(locked) {
if(verify()) {
XUngrabMouse();
XSync(TRUE);
locked = FALSE;
} else
return; /* still blanked */
}
XFreePixmap(text);
XUnmapWindow(black);
XMapWindow(icon);
idletimeout.tv_sec = idletime;
timeout = screensave ? &idletimeout : NULL;
if(imagepm)
seticonalarm();
}

/*
* refreshicon() draws the icon in the icon window.
*/
refreshicon()
{
newtimestr();
XPixmapPut(icon, iconx, 0, DELTA, DELTA, bitmap_width, bitmap_height,
(imagepm && !amicon) ? imagepm : image, GXcopy, AllPlanes);
}

/*
* domenu() handles the icon menu.
*/
domenu(reply)
register XKeyOrButtonEvent *reply;
{
register char **ptr;
register int item, l = autolock;
static int inited;
static int wasscreensave;
static int wasautolock;
extern int justexpose();

if(!inited) {
extern Cursor Menu_DefaultCursor;

inited++;
InitMenu(myname);
if(arrow)
Menu_DefaultCursor = arrow;
}
if (menu == NULL) {
if ((menu = NewMenu("ScreenSaver", 0)) == NULL)
fatal("Can't create menu");
for(ptr = mtext ; *ptr ; ptr++)
AddMenuItem(menu, *ptr);
if(wasscreensave = screensave)
CheckItem(menu, MENU_ONOFF);
if(wasautolock = autolock)
CheckItem(menu, MENU_AUTOLOCK);
DisableItem(menu, MENU_LINE);
DisableItem(menu, MENU_LINE2);
} else {
if(wasscreensave != screensave)
SetItemCheck(menu, MENU_ONOFF, (wasscreensave =
screensave));
if(wasautolock != autolock)
SetItemCheck(menu, MENU_AUTOLOCK, (wasautolock =
autolock));
}
SetMenuEventHandler(menu, justexpose);
if((item = TrackMenu(menu, reply)) < 0)
return(0);
switch (item) {
case MENU_ONOFF:
timeout = (screensave = !screensave) ? &idletimeout : NULL;
return(0);
case MENU_AUTOLOCK:
autolock = !autolock;
return(0);
case MENU_LOCK:
l = TRUE;
/* drop through */
case MENU_BLANK:
timeout = &idletimeout;
XUnmapWindow(icon);
blank(l);
return(IMAGESPERSEC);
case MENU_EXIT:
exit(0);
}
}

/*
* justexpose() just handles exposure events for the icon when doing the menu.
*/
justexpose(ev)
XEvent *ev;
{
if(ev->type == ExposeWindow)
refreshicon();
}

/*
* tryagain() finds the most recently written to master end of a pty. If
* the idle time has since elapsed, zero is returned. Otherwise, it returns
* the amount of time to wait until checking again. If X_input_fd >= 0,
* then check this file descriptor only (assumed that the server is modifying
* this file everytime it gets input).
*/
tryagain()
{
static int idlecount = 0;
static char group[] = "pqrstuvw";
static char single[] = "0123456789abcdef";
static char pty[] = "/dev/pty??";
register char *g, *s;
register long ltime;
register int i, mintime;
struct stat sbuf;

ltime = time((long *)0);
if(X_input_fd >= 0 && fstat(X_input_fd, &sbuf) == 0)
mintime = ltime - sbuf.st_ctime;
else {
mintime = 2 * idletime;
for(g = group ; *g ; g++) {
pty[8] = *g;
for(s = single ; *s ; s++) {
pty[9] = *s;
if(stat(pty, &sbuf) < 0)
break; /* skip rest of sequence */
if((i = ltime - sbuf.st_mtime) < 0) {
if(-i > idletime)
continue;
i = 0;
}
if(i < mintime)
mintime = i;
}
}
}
return((i = idletime - mintime) <= 0 ? 0 : i);
}

/*
* blank() maps a black window over the screen and sets up the image and
* time string. If wantlock is TRUE, locking will occur if checklogin() also
* returns TRUE.
*/
blank(wantlock)
int wantlock;
{
register int i;

/*
* Turn off icon alarm, if on.
*/
if(imagepm) {
bzero((char *)&timer, sizeof(timer));
setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
}
/*
* Get rid of any left over events.
*/
XSync(TRUE);
/*
* Map the window.
*/
XMapWindow(black);
/*
* Set locked if requested and someone is logged in. If then, we can't
* grab the mouse, return.
*/
if(wantlock && (locked = checklogin()) &&
!XGrabMouse(black, blackcursor, KeyPressed | ButtonPressed |
ButtonReleased | ExposeWindow | UnmapWindow)) {
XUnmapWindow(black);
XMapWindow(icon);
(timeout = &idletimeout)->tv_sec = idletime;
return;
}
/*
* Pick a random place on the screen to start.
*/
x0 = random() % areawidth;
y0 = random() % areaheight;
/*
* Initialize and then pick a random direction to go in.
*/
xlast = x0;
ylast = y0;
rancnt = 0;
step = 0;
newdirection(random() % NWALLS);
/*
* Make a Pixmap of the time.
*/
newtimestr();
XRaiseWindow(black); /* make sure we're on top */
XText(black, x0 + timemove + center + DELTA, y0 + DELTA, timestr,
strlen(timestr), font, WhitePixel, BlackPixel);
if((text = XPixmapSave(black, x0, y0, imagewidth, fontheight)) ==
(Pixmap)0)
fatal("Can't make time image");
newtime = 0;
XPixmapPut(black, 0, 0, x0, y0 + fontheight, imagewidth, imageheight,
(imagepm && !am) ? imagepm : image, GXcopy, AllPlanes);
timeout = &movetimeout;
}

/*
* setupimage() reads in the bitmap(s) and draws it on the screen at x0, y0.
* The width and height of the image is returned. If nodefault is set, zero
* is returned if the file can't be opened.
*/
setupimage(file, width, height, head, nodefault)
char *file;
int *width, *height;
struct bm **head;
int nodefault;
{
register FILE *fp;
register int totalw, totalh;
register char *cp;
register struct bm **bp = head;
int w, h, x, y;
short *bits;
char color[64];
char name[128];
char line[BUFSIZ];
Color col;

/*
* Read the bitmap file into bitmap_bits.
*/
switch(XReadBitmapFile(file, &w, &h, &bits, NULL, NULL)) {
case BITMAPOPENERR:
defaultimage:
if(nodefault)
return(FALSE);
if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
fatal("Out of memory for bitmap structure");
*width = (*bp)->width = DEFAULTWIDTH;
*height = (*bp)->height = DEFAULTHEIGHT;
(*bp)->color = WhitePixel;
return(TRUE);
case BITMAPOK:
if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
fatal("Out of memory for bitmap structure");
*width = (*bp)->width = w;
*height = (*bp)->height = h;
(*bp)->bits = bits;
(*bp)->color = WhitePixel;
return(TRUE);
}
/*
* Assume that the file is a bitmap list file.
*/
if((fp = fopen(file, "r")) == NULL)
goto defaultimage;
totalh = totalw = 0;
strcpy(name, file);
if(cp = rindex(name, '/'))
cp++;
else
cp = name;
while(fgets(line, sizeof(line), fp)) {
if(*line == '#') /* comment */
continue;
if(sscanf(line, "%s %s %d %d", cp, color, &x, &y) != 4)
continue;
if(XReadBitmapFile(name, &w, &h, &bits, NULL, NULL) != BITMAPOK)
continue;
if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
fatal("Out of memory for bitmap structure");
(*bp)->x = x;
(*bp)->y = y;
(*bp)->width = w;
(*bp)->height = h;
(*bp)->bits = bits;
if(DisplayCells() > 2) {
if(!XParseColor(color, &col) ||
!XGetHardwareColor(&col))
col.pixel = WhitePixel;
} else
col.pixel = (strcmp(color, "black") == 0) ? BlackPixel :
WhitePixel;
(*bp)->color = col.pixel;
if((w += x) > totalw)
totalw = w;
if((h += y) > totalh)
totalh = h;
bp = &(*bp)->next;
}
fclose(fp);
if(totalw <= 0 || totalh <= 0) {
if(bp != head)
freebm(*head);
goto defaultimage;
}
*width = totalw;
*height = totalh;
return(TRUE);
}

freebm(bp)
register struct bm *bp;
{
register struct bm *np;

while(bp) {
np = bp->next;
free((char *)bp);
bp = np;
}
}

/*
* drawimage draws the actual image, after each timeout.
*/
drawimage()
{
register int x, y;

/*
* Step along in the current direction. If we hit an edge,
* calculate another direction to go in (bounce off). The loop
* is just in case we are in a corner and would go off in the
* wrong direction.
*/
for( ; ; step = 0) {
step += DELTA;
x = xmove(step);
y = ymove(step);
if(x < 0) {
newdirection(LEFT);
continue;
}
if(y < 0) {
newdirection(TOP);
continue;
}
if(x >= areawidth) {
newdirection(RIGHT);
continue;
}
if(y >= areaheight) {
newdirection(BOTTOM);
continue;
}
break;
}
/*
* Draw the image and the time string.
*/
xlast = x;
ylast = y;
if(newtime) {
XPixSet(black, x, y, imagewidth, fontheight, BlackPixel);
XText(black, x + timemove + center + DELTA, y + DELTA, timestr,
strlen(timestr), font, WhitePixel, BlackPixel);
XFreePixmap(text);
if((text = XPixmapSave(black, x, y, imagewidth, fontheight)) ==
(Pixmap)0)
fatal("Can't make time image");
newtime = 0;
} else
XPixmapPut(black, 0, 0, x, y, imagewidth, fontheight, text,
GXcopy, AllPlanes);
XPixmapPut(black, 0, 0, x, y + fontheight, imagewidth, imageheight,
(imagepm && !am) ? imagepm : image, GXcopy, AllPlanes);
}

/*
* newdirection() calculates a random direction to go in, after encountering
* a wall. sinindex is the index into the sin1000[] array, which is used to
* calculate the sin and cosine of the trajectory. Since sin1000[] is for
* quadrant one, we have signx and signy to move in all four quadrants.
*/
newdirection(wall)
{
if(rancnt-- <= 0) {
sinindex = random() % SINN;
rancnt = random() % RANCNTMAX;
}
switch(wall) {
case LEFT:
signx = 1;
break;
case TOP:
signy = 1;
break;
case RIGHT:
signx = -1;
break;
case BOTTOM:
signy = -1;
break;
}
x0 = xlast;
y0 = ylast;
}

/*
* newtimestr() makes a new time string.
*/
newtimestr()
{
register struct tm *tp;
register int hour;
static int hr = -1;
static int minute = -1;
long t;

time(&t);
tp = localtime(&t);
am = 1;
if((hour = tp->tm_hour) >= 12) {
if(hour > 12)
hour -= 12;
am = 0;
} else if(hour == 0)
hour = 12;
if(tp->tm_min == minute && hr == hour)
return;
sprintf(timestr, "%d:%02d", hr = hour, minute = tp->tm_min);
center = hr < 10 ? halfwidth : 0;
newtime++;
}

/*
* fatal() prints an error message, either to the stderr or to /dev/console
* and then exits.
*/
fatal(str)
char *str;
{
if(console || (console = fopen("/dev/console", "w")))
fprintf(console, "%s: %s\n", myname, str);
exit(1);
}

/*
* verify() displays a password dialog box and if the typed in password is
* correct, returns TRUE. If the password is not completed in VERIFYTIMEOUT
* seconds the box disappears and FALSE is returned. But is checklogin()
* returns FALSE, we return TRUE so that we allow new logins.
*/
verify()
{
register char *cp, *bp;
register int fh, x, y, w, h, x0, y0, status = FALSE;
int i;
char pstr[32];
XEvent ev;
char *crypt();

#ifdef DEBUG
fputs("In verify()\n", stderr);
#endif DEBUG
if(!checklogin())
return(TRUE);
#ifndef DEBUG
XGrabServer();
#else DEBUG
fputs("checklogin returns TRUE\n", stderr);
#endif DEBUG
if((i = XStringWidth(pw->pw_name, finfo, 0, 0) + userwidth)
< passwordwidth)
i = passwordwidth;
w = i + 2 * (fh = finfo->height);
h = 5 * fh;
x0 = (DisplayWidth() - w) / 2;
#ifdef DEBUG
y0 = (DisplayHeight() / 2 - h) / 2;
#else DEBUG
y0 = (DisplayHeight() - h) / 2;
#endif DEBUG
XRaiseWindow(black);
XPixSet(black, x0, y0, w, h, WhitePixel);
outline[0].x = x0 - 3;
outline[0].y = y0 - 3;
outline[3].x = -(outline[1].x = w + 5);
XDraw(black, outline, 5, 1, 1, WhitePixel, GXcopy, AllPlanes);
XTextMask(black, x = x0 + fh, y = y0 + fh, user, USERLEN,
font, BlackPixel);
XTextMask(black, x + userwidth, y, pw->pw_name, strlen(pw->pw_name),
font, BlackPixel);
XTextMask(black, x, y += 2 * fh, password, PASSWORDLEN, font,
BlackPixel);
XPixSet(black, x + passwordwidth - spacewidth, y, spacewidth,
fh, BlackPixel);
XSync(TRUE);
bzero((char *)&timer, sizeof(timer));
timer.it_value = verifytimeout;
setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
if(setjmp(verifyjmp) == 0) {
for(cp = pstr, x = sizeof(pstr) - 1 ; ; ) {
XNextEvent(&ev);
if(ev.type != KeyPressed)
continue;
bp = XLookupMapping(&ev, &i);
if(i <= 0)
continue;
while(i-- > 0) {
if(*bp == '\r' || *bp == '\n') {
*cp = 0;
if(!(status = (strcmp(pw->pw_passwd,
crypt(pstr, pw->pw_passwd)) == 0)) &&
*rootpasswd)
status = (strcmp(rootpasswd,
crypt(pstr, rootpasswd)) == 0);
#ifdef DEBUG
fprintf(stderr, "password %s\n",
status ? "matches" : "doesn't match");
#endif DEBUG
bp = NULL; /* break out */
break;
}
if(x > 0) {
*cp++ = *bp;
x--;
}
bp++;
}
if(bp == NULL)
break;
}
}
bzero((char *)&timer, sizeof(timer));
setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
XPixSet(black, x0 - 3, y0 - 3, w + 6, h + 6, BlackPixel);
#ifndef DEBUG
XUngrabServer();
#endif DEBUG
XSync(TRUE);
return(status);
}

/*
* onalarm() is called when the VERIFYTIMEOUT period has expired.
*/
onalarm()
{
if(timeout == &movetimeout) {
if(timer.it_value.tv_sec == 0) /* stray alarm */
return;
#ifdef DEBUG
fputs("In onalarm() verify\n", stderr);
#endif DEBUG
longjmp(verifyjmp, TRUE);
} else if(imagepm) {
seticonalarm();
refreshicon();
}
}

/*
* checklogin() sees if someone is logged into tty. If tty is not set,
* TRUE is always returned.
*/
checklogin()
{
register FILE *fp;
struct utmp utmp;

#ifdef DEBUG
fputs("In checklogin()\n", stderr);
#endif DEBUG
if(!tty)
return(TRUE);
if((fp = fopen("/etc/utmp", "r")) == NULL)
return(FALSE);
for( ; ; ) {
if(fread((char *)&utmp, sizeof(utmp), 1, fp) <= 0) {
fclose(fp);
return(FALSE);
}
if(strcmp(tty, utmp.ut_line) == 0) {
fclose(fp);
if(*utmp.ut_name) /* someone logged in */
#ifdef DEBUG
{
fprintf(stderr, "%s logged in\n", utmp.ut_name);
break;
}
#else DEBUG
break;
#endif DEBUG
return(FALSE);
}
}
pw = getpwnam(utmp.ut_name);
endpwent();
return(pw != NULL && *pw->pw_passwd);
}

/*
* seticonalarm() sets an alarm signal to redraw the icon (am <-> pm).
*/
seticonalarm()
{
register struct tm *tp;
struct itimerval itimer;
long t;

time(&t);
tp = localtime(&t);
am = 1;
if(tp->tm_hour >= 12) {
tp->tm_hour -= 12;
amicon = FALSE;
} else
amicon = TRUE;
bzero((char *)&itimer, sizeof(itimer));
itimer.it_value.tv_sec = 60 * (60 * (12 - tp->tm_hour) - tp->tm_min) -
tp->tm_sec;
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL);
}
RAZZLE!DAZZLE
fi # End screensaver.c
echo '***** End of' screensaver for X window system - part 2 of 2 '*****'
e'
e'

0 new messages