home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 = ℑ
- }
- drawbm(head);
- *ip = XPixmapSave(icon, 0, DELTA, imagewidth, imageheight);
- XClear(icon);
- if(i = amicon) {
- head = headam;
- ip = ℑ
- } else {
- head = headpm;
- ip = &imagepm;
- }
- } else {
- head = headam;
- ip = ℑ
- }
- 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);
- }
-