[comp.sources.x] v10i069: xlock, Part03/03

naughton@Eng (Patrick Naughton) (11/14/90)

Submitted-by: naughton@Eng (Patrick Naughton)
Posting-number: Volume 10, Issue 69
Archive-name: xlock/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  xlock.c
# Wrapped by naughton@wind on Tue Oct 30 11:26:51 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xlock.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xlock.c'\"
else
echo shar: Extracting \"'xlock.c'\" \(21618 characters\)
sed "s/^X//" >'xlock.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char sccsid[] = "@(#)xlock.c	23.16 90/10/29 XLOCK SMI";
X#endif
X/*-
X * xlock.c - X11 client to lock a display and show a screen saver.
X *
X * Copyright (c) 1988-90 by Patrick Naughton and Sun Microsystems, Inc.
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation.
X *
X * This file is provided AS IS with no warranties of any kind.  The author
X * shall have no liability with respect to the infringement of copyrights,
X * trade secrets or any patents by this file or any part thereof.  In no
X * event will the author be liable for any lost revenue or profits or
X * other special, indirect and consequential damages.
X *
X * Comments and additions should be sent to the author:
X *
X *		       naughton@eng.sun.com
X *
X *		       Patrick J. Naughton
X *		       MS 14-01
X *		       Windows and Graphics Group
X *		       Sun Microsystems, Inc.
X *		       2550 Garcia Ave
X *		       Mountain View, CA  94043
X *
X * Revision History:
X * 29-Oct-90: added cast to XFree() arg.
X *	      added volume arg to call to XBell().
X * 28-Oct-90: center prompt screen.
X *	      make sure Xlib input buffer does not use up all of swap.
X *	      make displayed text come from resource file for better I18N.
X *	      add backward compatible signal handlers for pre 4.1 machines.
X * 31-Aug-90: added blank mode.
X *	      added swarm mode.
X *	      moved usleep() and seconds() out to usleep.c.
X *	      added SVR4 defines to xlock.h
X * 29-Jul-90: added support for multiple screens to be locked by one xlock.
X *	      moved global defines to xlock.h
X *	      removed use of allowsig().
X * 07-Jul-90: reworked commandline args and resources to use Xrm.
X *	      moved resource processing out to resource.c
X * 02-Jul-90: reworked colors to not use dynamic colormap.
X * 23-May-90: added autoraise when obscured.
X * 15-Apr-90: added hostent alias searching for host authentication.
X * 18-Feb-90: added SunOS3.5 fix.
X *	      changed -mono -> -color, and -saver -> -lock.
X *	      allow non-locking screensavers to display on remote machine.
X *	      added -echokeys to disable echoing of '?'s on input.
X *	      cleaned up all of the parameters and defaults.
X * 20-Dec-89: added -xhost to allow access control list to be left alone.
X *	      added -screensaver (don't disable screen saver) for the paranoid.
X *	      Moved seconds() here from all of the display mode source files.
X *	      Fixed bug with calling XUngrabHosts() in finish().
X * 19-Dec-89: Fixed bug in GrabPointer.
X *	      Changed fontname to XLFD style.
X * 23-Sep-89: Added fix to allow local hostname:0 as a display.
X *	      Put empty case for Enter/Leave events.
X *	      Moved colormap installation later in startup.
X * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
X *	      Replaced SunView code for life mode with Jim Graham's version,
X *		so I could contrib it without legal problems.
X *	      Sent to expo for X11R4 contrib.
X * 19-Sep-89: Added '?'s on input.
X * 27-Mar-89: Added -qix mode.
X *	      Fixed GContext->GC.
X * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
X *	      Changed default font to lucida-sans-24.
X * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
X * 24-Feb-89: Replaced hopalong display with life display from SunView1.
X * 22-Feb-89: Added fix for color servers with n < 8 planes.
X * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
X *	      Added -count for number of iterations per color.
X *	      Fixed defaulting mechanism.
X *	      Ripped out VMS hacks.
X *	      Sent to expo for X11R3 contrib.
X * 15-Feb-89: Changed default font to pellucida-sans-18.
X * 20-Jan-89: Added -verbose and fixed usage message.
X * 19-Jan-89: Fixed monochrome gc bug.
X * 16-Dec-88: Added SunView style password prompting.
X * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
X *	      Added -saver option. (just do display... don't lock.)
X * 31-Aug-88: Added -time option.
X *	      Removed code for fractals to separate file for modularity.
X *	      Added signal handler to restore host access.
X *	      Installs dynamic colormap with a Hue Ramp.
X *	      If grabs fail then exit.
X *	      Added VMS Hacks. (password 'iwiwuu').
X *	      Sent to expo for X11R2 contrib.
X * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
X * 20-May-88: Added -root to allow root to unlock.
X * 12-Apr-88: Added root password override.
X *	      Added screen saver override.
X *	      Removed XGrabServer/XUngrabServer.
X *	      Added access control handling instead.
X * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
X * 30-Mar-88: Removed startup password requirement.
X *	      Removed cursor to avoid phosphor burn.
X * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
X * 24-Mar-88: Added color support. [-color]
X *	      wrote the man page.
X * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
X *	      added password requirement for invokation
X *	      removed option for command line password
X *	      added requirement for display to be "unix:0".
X * 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
X *
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <string.h>
X#include <pwd.h>
X
X#include "xlock.h"
X#include <X11/cursorfont.h>
X
Xextern char *crypt();
Xextern char *getenv();
X
Xchar       *ProgramName;	/* argv[0] */
Xperscreen   Scr[MAXSCREENS];
XDisplay    *dsp = NULL;		/* server display connection */
Xint         screen;		/* current screen */
Xvoid        (*callback) () = NULL;
Xvoid        (*init) () = NULL;
X
Xstatic int  screens;		/* number of screens */
Xstatic Window win[MAXSCREENS];	/* window used to cover screen */
Xstatic Window icon[MAXSCREENS];	/* window used during password typein */
Xstatic Window root[MAXSCREENS];	/* convenience pointer to the root window */
Xstatic GC   textgc[MAXSCREENS];	/* graphics context used for text rendering */
Xstatic XColor fgcol[MAXSCREENS];/* used for text rendering */
Xstatic XColor bgcol[MAXSCREENS];/* background of text screen */
Xstatic int  iconx[MAXSCREENS];	/* location of left edge of icon */
Xstatic int  icony[MAXSCREENS];	/* location of top edge of icon */
Xstatic Cursor mycursor;		/* blank cursor */
Xstatic Pixmap lockc;
Xstatic Pixmap lockm;		/* pixmaps for cursor and mask */
Xstatic char no_bits[] = {0};	/* dummy array for the blank cursor */
Xstatic int  passx;		/* position of the ?'s */
Xstatic int  passy;
Xstatic XFontStruct *font;
Xstatic int  sstimeout;		/* screen saver parameters */
Xstatic int  ssinterval;
Xstatic int  ssblanking;
Xstatic int  ssexposures;
X
X#define FALLBACK_FONTNAME	"fixed"
X#define ICONW			64
X#define ICONH			64
X
X#define AllPointerEventMask \
X	(ButtonPressMask | ButtonReleaseMask | \
X	EnterWindowMask | LeaveWindowMask | \
X	PointerMotionMask | PointerMotionHintMask | \
X	Button1MotionMask | Button2MotionMask | \
X	Button3MotionMask | Button4MotionMask | \
X	Button5MotionMask | ButtonMotionMask | \
X	KeymapStateMask)
X
X
X/* VARARGS1 */
Xvoid
Xerror(s1, s2)
X    char       *s1,
X               *s2;
X{
X    fprintf(stderr, s1, ProgramName, s2);
X    exit(1);
X}
X
X/*
X * Server access control support.
X */
X
Xstatic XHostAddress *XHosts;	/* the list of "friendly" client machines */
Xstatic int  HostAccessCount;	/* the number of machines in XHosts */
Xstatic Bool HostAccessState;	/* whether or not we even look at the list */
X
Xstatic void
XXGrabHosts(dsp)
X    Display    *dsp;
X{
X    XHosts = XListHosts(dsp, &HostAccessCount, &HostAccessState);
X    if (XHosts)
X	XRemoveHosts(dsp, XHosts, HostAccessCount);
X    XEnableAccessControl(dsp);
X}
X
Xstatic void
XXUngrabHosts(dsp)
X    Display    *dsp;
X{
X    if (XHosts) {
X	XAddHosts(dsp, XHosts, HostAccessCount);
X	XFree((char *)XHosts);
X    }
X    if (HostAccessState == False)
X	XDisableAccessControl(dsp);
X}
X
X
X/*
X * Simple wrapper to get an asynchronous grab on the keyboard and mouse.
X * If either grab fails, we sleep for one second and try again since some
X * window manager might have had the mouse grabbed to drive the menu choice
X * that picked "Lock Screen..".  If either one fails the second time we print
X * an error message and exit.
X */
Xstatic void
XGrabKeyboardAndMouse()
X{
X    Status      status;
X
X    status = XGrabKeyboard(dsp, win[0], True,
X			   GrabModeAsync, GrabModeAsync, CurrentTime);
X    if (status != GrabSuccess) {
X	sleep(1);
X	status = XGrabKeyboard(dsp, win[0], True,
X			       GrabModeAsync, GrabModeAsync, CurrentTime);
X
X	if (status != GrabSuccess)
X	    error("%s: couldn't grab keyboard! (%d)\n", status);
X    }
X    status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
X			  GrabModeAsync, GrabModeAsync, None, mycursor,
X			  CurrentTime);
X    if (status != GrabSuccess) {
X	sleep(1);
X	status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
X			      GrabModeAsync, GrabModeAsync, None, mycursor,
X			      CurrentTime);
X
X	if (status != GrabSuccess)
X	    error("%s: couldn't grab pointer! (%d)\n", status);
X    }
X}
X
X
X/*
X * Assuming that we already have an asynch grab on the pointer,
X * just grab it again with a new cursor shape and ignore the return code.
X */
Xstatic void
XXChangeGrabbedCursor(cursor)
X    Cursor      cursor;
X{
X#ifndef DEBUG
X    (void) XGrabPointer(dsp, win[0], True, AllPointerEventMask,
X		    GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
X#endif
X}
X
X
X/*
X * Restore all grabs, reset screensaver, restore colormap, close connection.
X */
Xstatic void
Xfinish()
X{
X    XSync(dsp, False);
X    if (!nolock && !allowaccess)
X	XUngrabHosts(dsp);
X    XUngrabPointer(dsp, CurrentTime);
X    XUngrabKeyboard(dsp, CurrentTime);
X    if (!enablesaver)
X	XSetScreenSaver(dsp, sstimeout, ssinterval, ssblanking, ssexposures);
X    XFlush(dsp);
X    XCloseDisplay(dsp);
X}
X
X
Xstatic int
XReadXString(s, slen)
X    char       *s;
X    int         slen;
X{
X    XEvent      event;
X    char        keystr[20];
X    char        c;
X    int         i;
X    int         bp;
X    int         len;
X    int         thisscreen = screen;
X    char       *pwbuf = (char *) malloc(slen);
X
X#ifdef DEBUG
X    XSetInputFocus(dsp, win[screen], RevertToPointerRoot, CurrentTime);
X#endif
X    for (screen = 0; screen < screens; screen++)
X	if (thisscreen == screen)
X	    init(icon[screen]);
X	else
X	    init(win[screen]);
X    bp = 0;
X    nice(-nicelevel);		/* make sure we can read the keys... */
X    while (True) {
X	unsigned long lasteventtime = seconds();
X	while (!XPending(dsp)) {
X	    for (screen = 0; screen < screens; screen++)
X		if (thisscreen == screen)
X		    callback(icon[screen]);
X		else
X		    callback(win[screen]);
X	    XFlush(dsp);
X	    usleep(delay);
X	    if (seconds() - lasteventtime > timeout) {
X		nice(nicelevel);
X		free(pwbuf);
X		screen = thisscreen;
X		return 1;
X	    }
X	}
X	screen = thisscreen;
X	XNextEvent(dsp, &event);
X	switch (event.type) {
X	case KeyPress:
X	    len = XLookupString((XKeyEvent *) & event, keystr, 20, NULL, NULL);
X	    for (i = 0; i < len; i++) {
X		c = keystr[i];
X		switch (c) {
X		case 8:	/* ^H */
X		case 127:	/* DEL */
X		    if (bp > 0)
X			bp--;
X		    break;
X		case 10:	/* ^J */
X		case 13:	/* ^M */
X		    s[bp] = '\0';
X		    nice(nicelevel);
X		    free(pwbuf);
X		    return 0;
X		case 21:	/* ^U */
X		    bp = 0;
X		    break;
X		default:
X		    s[bp] = c;
X		    if (bp < slen - 1)
X			bp++;
X		    else
X			XSync(dsp, True);	/* flush input buffer */
X
X		}
X	    }
X	    if (echokeys) {
X		memset(pwbuf, '?', slen);
X		XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
X		XFillRectangle(dsp, win[screen], Scr[screen].gc,
X			       passx, passy - font->ascent,
X			       XTextWidth(font, pwbuf, slen),
X			       font->ascent + font->descent);
X		XDrawString(dsp, win[screen], textgc[screen],
X			    passx, passy, pwbuf, bp);
X	    }
X	    /*
X	     * eat all events if there are more than enough pending... this
X	     * keeps the Xlib event buffer from growing larger than all
X	     * available memory and crashing xlock.
X	     */
X	    if (XPending(dsp) > 100) {	/* 100 is arbitrarily big enough */
X		register Status status;
X		do {
X		    status = XCheckMaskEvent(dsp,
X				      KeyPressMask | KeyReleaseMask, &event);
X		} while (status);
X		XBell(dsp, 100);
X	    }
X	    break;
X
X	case ButtonPress:
X	    if (((XButtonEvent *) & event)->window == icon[screen]) {
X		nice(nicelevel);
X		free(pwbuf);
X		return 1;
X	    }
X	    break;
X
X	case VisibilityNotify:
X	    if (event.xvisibility.state != VisibilityUnobscured) {
X#ifndef DEBUG
X		XRaiseWindow(dsp, win[screen]);
X#endif
X		s[0] = '\0';
X		nice(nicelevel);
X		free(pwbuf);
X		return 1;
X	    }
X	    break;
X
X	case KeymapNotify:
X	case KeyRelease:
X	case ButtonRelease:
X	case MotionNotify:
X	case LeaveNotify:
X	case EnterNotify:
X	    break;
X
X	default:
X	    fprintf(stderr, "%s: unexpected event: %d\n",
X		    ProgramName, event.type);
X	    break;
X	}
X    }
X}
X
X
Xstatic int
XgetPassword()
X{
X#define PASSLENGTH 20
X    char        buffer[PASSLENGTH];
X    char        userpass[PASSLENGTH];
X    char        rootpass[PASSLENGTH];
X    struct passwd *pw;
X    XWindowAttributes xgwa;
X    char       *user = getenv(USERNAME);
X    int         y,
X                left,
X                done;
X
X    XGetWindowAttributes(dsp, win[screen], &xgwa);
X
X    XChangeGrabbedCursor(XCreateFontCursor(dsp, XC_left_ptr));
X
X    XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
X    XFillRectangle(dsp, win[screen], Scr[screen].gc,
X		   0, 0, xgwa.width, xgwa.height);
X
X    XMapWindow(dsp, icon[screen]);
X    XRaiseWindow(dsp, icon[screen]);
X
X    left = iconx[screen] + ICONW + font->max_bounds.width;
X    y = icony[screen] + font->ascent;
X
X    XDrawString(dsp, win[screen], textgc[screen],
X		left, y, text_name, strlen(text_name));
X    XDrawString(dsp, win[screen], textgc[screen],
X		left + 1, y, text_name, strlen(text_name));
X    XDrawString(dsp, win[screen], textgc[screen],
X		left + XTextWidth(font, text_name, strlen(text_name)), y,
X		user, strlen(user));
X
X    y += font->ascent + font->descent + 2;
X    XDrawString(dsp, win[screen], textgc[screen],
X		left, y, text_pass, strlen(text_pass));
X    XDrawString(dsp, win[screen], textgc[screen],
X		left + 1, y, text_pass, strlen(text_pass));
X
X    passx = left + 1 + XTextWidth(font, text_pass, strlen(text_pass))
X	+ XTextWidth(font, " ", 1);
X    passy = y;
X
X    y = icony[screen] + ICONH + font->ascent + 2;
X    XDrawString(dsp, win[screen], textgc[screen],
X		iconx[screen], y, text_info, strlen(text_info));
X
X    XFlush(dsp);
X
X    y += font->ascent + font->descent + 2;
X
X    pw = getpwnam("root");
X    strcpy(rootpass, pw->pw_passwd);
X
X    pw = getpwnam(user);
X    strcpy(userpass, pw->pw_passwd);
X
X    done = False;
X    while (!done) {
X	if (ReadXString(buffer, PASSLENGTH)) {
X	    XChangeGrabbedCursor(mycursor);
X	    XUnmapWindow(dsp, icon[screen]);
X	    XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
X	    return 1;
X	}
X	XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
X	XFillRectangle(dsp, win[screen], Scr[screen].gc,
X		       iconx[screen], y - font->ascent,
X		       XTextWidth(font, text_invalid, strlen(text_invalid)),
X		       font->ascent + font->descent + 2);
X
X	XDrawString(dsp, win[screen], textgc[screen],
X		    iconx[screen], y, text_valid, strlen(text_valid));
X
X	done = !((strcmp(crypt(buffer, userpass), userpass))
X	       && (!allowroot || strcmp(crypt(buffer, rootpass), rootpass)));
X
X	if (!done) {
X	    XSync(dsp, True);	/* flush input buffer */
X	    sleep(1);
X	    XFillRectangle(dsp, win[screen], Scr[screen].gc,
X			   iconx[screen], y - font->ascent,
X			   XTextWidth(font, text_valid, strlen(text_valid)),
X			   font->ascent + font->descent + 2);
X
X	    XDrawString(dsp, win[screen], textgc[screen],
X			iconx[screen], y, text_invalid, strlen(text_invalid));
X	}
X    }
X    return 0;
X}
X
X
Xstatic void
XjustDisplay()
X{
X    XEvent      event;
X
X    for (screen = 0; screen < screens; screen++)
X	init(win[screen]);
X    do {
X	while (!XPending(dsp)) {
X	    for (screen = 0; screen < screens; screen++)
X		callback(win[screen]);
X	    XFlush(dsp);
X	    usleep(delay);
X	}
X	XNextEvent(dsp, &event);
X#ifndef DEBUG
X	if (event.type == VisibilityNotify)
X	    XRaiseWindow(dsp, event.xany.window);
X#endif
X    } while (event.type != ButtonPress && event.type != KeyPress);
X    for (screen = 0; screen < screens; screen++)
X	if (event.xbutton.root == RootWindow(dsp, screen))
X	    break;
X}
X
X
Xstatic void
Xsigcatch()
X{
X    finish();
X    error("%s: caught terminate signal.\nAccess control list restored.\n");
X}
X
X
Xstatic void
XlockDisplay()
X{
X    if (!allowaccess) {
X#ifdef SYSV
X	sigset_t    oldsigmask;
X	sigset_t    newsigmask;
X
X	sigemptyset(&newsigmask);
X	sigaddset(&newsigmask, SIGHUP);
X	sigaddset(&newsigmask, SIGINT);
X	sigaddset(&newsigmask, SIGQUIT);
X	sigaddset(&newsigmask, SIGTERM);
X	sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
X#else
X	int         oldsigmask;
X
X	oldsigmask = sigblock(sigmask(SIGHUP) |
X			      sigmask(SIGINT) |
X			      sigmask(SIGQUIT) |
X			      sigmask(SIGTERM));
X#endif
X
X	signal(SIGHUP, sigcatch);
X	signal(SIGINT, sigcatch);
X	signal(SIGQUIT, sigcatch);
X	signal(SIGTERM, sigcatch);
X
X	XGrabHosts(dsp);
X
X#ifdef SYSV
X	sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
X#else
X	sigsetmask(oldsigmask);
X#endif
X    }
X    do {
X	justDisplay();
X    } while (getPassword());
X}
X
X
Xint
Xmain(argc, argv)
X    int         argc;
X    char       *argv[];
X{
X    XSetWindowAttributes xswa;
X    XGCValues   xgcv;
X
X    ProgramName = strrchr(argv[0], '/');
X    if (ProgramName)
X	ProgramName++;
X    else
X	ProgramName = argv[0];
X
X    GetResources(argc, argv);
X
X    CheckResources();
X
X    font = XLoadQueryFont(dsp, fontname);
X    if (font == NULL) {
X	fprintf(stderr, "%s: can't find font: %s, using %s...\n",
X		ProgramName, fontname, FALLBACK_FONTNAME);
X	font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
X	if (font == NULL)
X	    error("%s: can't even find %s!!!\n", FALLBACK_FONTNAME);
X    }
X    screens = ScreenCount(dsp);
X    if (screens > MAXSCREENS)
X	error("%s: can only support %d screens.\n", MAXSCREENS);
X    for (screen = 0; screen < screens; screen++) {
X	XColor      tmp;
X	Screen     *scr = ScreenOfDisplay(dsp, screen);
X	Colormap    cmap = DefaultColormapOfScreen(scr);
X
X	root[screen] = RootWindowOfScreen(scr);
X	if (mono || CellsOfScreen(scr) == 2) {
X	    XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
X	    XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
X	    Scr[screen].pixels[0] = fgcol[screen].pixel;
X	    Scr[screen].pixels[1] = bgcol[screen].pixel;
X	    Scr[screen].npixels = 2;
X	} else {
X	    int         colorcount = NUMCOLORS;
X	    u_char      red[NUMCOLORS];
X	    u_char      green[NUMCOLORS];
X	    u_char      blue[NUMCOLORS];
X	    int         i;
X
X	    if (!XAllocNamedColor(dsp, cmap, background,
X				  &bgcol[screen], &tmp)) {
X		fprintf(stderr, "couldn't allocate: %s\n", background);
X		XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
X	    }
X	    if (!XAllocNamedColor(dsp, cmap, foreground,
X				  &fgcol[screen], &tmp)) {
X		fprintf(stderr, "couldn't allocate: %s\n", foreground);
X		XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
X	    }
X	    hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, colorcount,
X		    red, green, blue);
X	    Scr[screen].npixels = 0;
X	    for (i = 0; i < colorcount; i++) {
X		XColor      xcolor;
X
X		xcolor.red = red[i] << 8;
X		xcolor.green = green[i] << 8;
X		xcolor.blue = blue[i] << 8;
X		xcolor.flags = DoRed | DoGreen | DoBlue;
X
X		if (!XAllocColor(dsp, cmap, &xcolor))
X		    break;
X
X		Scr[screen].pixels[i] = xcolor.pixel;
X		Scr[screen].npixels++;
X	    }
X	    if (verbose)
X		fprintf(stderr, "%d pixels allocated\n", Scr[screen].npixels);
X	}
X
X	xswa.override_redirect = True;
X	xswa.background_pixel = BlackPixelOfScreen(scr);
X	xswa.event_mask = KeyPressMask | ButtonPressMask | VisibilityChangeMask;
X
X	win[screen] = XCreateWindow(dsp, root[screen],
X				    0, 0,
X				    WidthOfScreen(scr),
X				    HeightOfScreen(scr),
X			      0, CopyFromParent, InputOutput, CopyFromParent,
X		      CWOverrideRedirect | CWBackPixel | CWEventMask, &xswa);
X
X	xswa.background_pixel = bgcol[screen].pixel;
X	xswa.event_mask = ButtonPressMask;
X
X	iconx[screen] = (DisplayWidth(dsp, screen) -
X			 XTextWidth(font, text_info, strlen(text_info))) / 2;
X
X	icony[screen] = DisplayHeight(dsp, screen) / 6;
X	icon[screen] = XCreateWindow(dsp, win[screen],
X				     iconx[screen], icony[screen],
X				     ICONW, ICONH,
X				     1, CopyFromParent,
X				     InputOutput, CopyFromParent,
X				     CWBackPixel | CWEventMask, &xswa);
X
X	XMapWindow(dsp, win[screen]);
X	XRaiseWindow(dsp, win[screen]);
X
X	xgcv.foreground = WhitePixelOfScreen(scr);
X	xgcv.background = BlackPixelOfScreen(scr);
X	Scr[screen].gc = XCreateGC(dsp, win[screen],
X				   GCForeground | GCBackground, &xgcv);
X
X	xgcv.foreground = fgcol[screen].pixel;
X	xgcv.background = bgcol[screen].pixel;
X	xgcv.font = font->fid;
X	textgc[screen] = XCreateGC(dsp, win[screen],
X				GCFont | GCForeground | GCBackground, &xgcv);
X    }
X    lockc = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
X    lockm = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
X    mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
X				   &fgcol[screen], &bgcol[screen], 0, 0);
X    XFreePixmap(dsp, lockc);
X    XFreePixmap(dsp, lockm);
X
X
X    if (!enablesaver) {
X	XGetScreenSaver(dsp, &sstimeout, &ssinterval,
X			&ssblanking, &ssexposures);
X	XSetScreenSaver(dsp, 0, 0, 0, 0);	/* disable screen saver */
X    }
X#ifndef DEBUG
X    GrabKeyboardAndMouse();
X#endif
X
X    srandom(getpid());
X
X    nice(nicelevel);
X
X    if (nolock)
X	justDisplay();
X    else
X	lockDisplay();
X
X    finish();
X
X    return 0;
X}
END_OF_FILE
if test 21618 -ne `wc -c <'xlock.c'`; then
    echo shar: \"'xlock.c'\" unpacked with wrong size!
fi
# end of 'xlock.c'
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.
--
dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.