|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T x
Length: 19200 (0x4b00) Types: TextFile Names: »xmoire.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Xmoire/xmoire.c«
/* * xmoire.c * Copyright 1988 The Student Information Processing Board (SIPB) * Written by Mark W. Eichin, begun April 13, 1988. * * All distribution rights hereby granted, as long as * 1) you do not charge for this code or derivatives of it * without my consent; * 2) you leave this header comment in place unchanged; * 3) you attempt to inform myself <eichin@athena.mit.edu> or the * Board <sipb@athena.mit.edu> of any changes or improvements. * * The idea for this program comes from a public domain `screensaver' * for the Mac labeled: * * * "Moire V1.1 by John Lim" * * * "Algorithm by Anonymous" * * * "Portions (c) John Lim and THINK Tech." * After watching it for a short time, it was obvious how to implement * a similar (if not identical) program; however, all the code here is * my original work, its purpose only being to provide the same look * and feel under X11. Due to the eminent simplicity of the concept, I * feel I am not stepping on any toes by creating this. In any case, * it is a different window system, and the user interface differs in * certain ways (unlabeled keys do NOT produce rectangles; space bar * does NOT produce an instructional message (yet); curly braces are * used to control operation speed, not 0-9) and that this alone may * be sufficient to call the look and feel different. The people here * who have found it most similar included at least one person who * despised the original, and wanted me to port Pyro instead... */ /* * Mutable comments follow: * $Header: xmoire.c,v 1.1 88/04/15 12:51:10 eichin Exp $ * $Log: xmoire.c,v $ * Revision 1.1 88/04/15 12:51:10 eichin * Initial revision * */ /* * Things to add (may be superseded by the above logs): * geometry spec for the mousetrap window * password locking (or integration with xscreensaver) * Things *not* to add (don't waste time on:) * number keys to control speed */ #include <X11/Xlib.h> #include <stdio.h> #include <sys/types.h> #include <strings.h> Display *dpy; #define SIZ 51 /* SIZ is for alloc'ing */ #define MAXSIZ SIZ-1 /* valid indices are <= MAXSIZ, so if (x>MAXSIZ) x=0; */ #define INITSIZ 5 #define MINSIZ 2 #define MAXTIM 1000000 #define MINTIM 1000 #define SLEEPTIME 50000 #define XR 5 #define XRM 1 #define YR 5 #define YRM 1 #define CHCHANCE (25 - 1) void init_random() { /* * We really don't need a VERY random seed, since we are only * adjusting the vectors, and that only needs about 4 bits/sample of * magnitude change. Low part of time would be ok, I suppose. So * what? */ srandom(getpid()); } /* * These are global, so they don't have to be passed between main and * the draw/undraw procs. They should at least be made local to a * smaller file/set of procs... for now, they just sit here. * * The routine simply bounces a bounding box around the screen, and * then draws the correct image within it; these are the origin and * sides of the bounding box. */ int xx[SIZ], yy[SIZ], xs[SIZ], ys[SIZ]; void draw(), undraw(); /* * pic is all the possible returns from a keyboard entry; it is also * all of the possible shapes (a subset.) */ typedef enum _pic { RECT, CIRC, PENT, DIAM, LEFT, RIGHT, HGLS, PLUS, CROSS, VEE, TRI, PUNT, LONG, SHORT, FAST, SLOW, } pic; /* HGLS == HourGlass, also H key... */ /* * opts are the keys pressed, and popts are the values returned from * char2pic for those keys. */ char opts[] = "ropd/\\h+xvtQ][}{"; pic popts[] = { RECT, CIRC, PENT, DIAM, LEFT, RIGHT, HGLS, PLUS, CROSS, VEE, TRI, PUNT, LONG, SHORT, FAST, SLOW, }; pic char2pic(in,old) char in; pic old; { char *where; where = index(opts, in); return(where?popts[where-opts]:old); } /* * again, it is easier to make these global than to pass them to the * draw/undraw routines all the time. */ GC gc, ungc; Window win; /* * This could stand to be broken down a bit more. But then, none of * the important bottlenecks are here... far too much time was spent * writing it in the first place to justify rewriting it. Unless of * course we can merge it into the other xscreensaver... */ main (argc, argv) int argc; char **argv; { Window rtwin, scanwin; /* root and mouse entry windows */ int scrn; XGCValues gc_val; pic pictype = RECT; /* current displayed picture */ int siz = INITSIZ; int start, end, ostart; int swid, shi; int xxoff, yyoff, xsoff, ysoff; unsigned long vmask; XSetWindowAttributes wvals; int timeout, interval, blanking, exposures; /* screen saver parameters */ unsigned micr = SLEEPTIME; /* microseconds between motion */ init_random(); /* start random number generator */ dpy = XOpenDisplay(""); scrn = DefaultScreen(dpy); rtwin = RootWindow(dpy, scrn); swid = DisplayWidth(dpy, scrn); shi = DisplayHeight(dpy, scrn); wvals.override_redirect = True; wvals.background_pixel = BlackPixel(dpy, scrn); vmask = CWOverrideRedirect | CWBackPixel; /* * Creating the drawing window to fill the whole screen and get mapped * later on. */ win = XCreateWindow(dpy, rtwin, /* excitement window */ 0, 0, /* origin */ swid, shi, /* size */ 0, /* border width */ 0, /* depth from parent */ InputOutput, /* class */ CopyFromParent, /* visual */ vmask, &wvals); #define BOXSIZ 50 vmask = CWOverrideRedirect; /* * Creating the window to catch the mouse motion, into and out of the * ``corner''; this perhaps ought to be smaller, and should parse the * geometry specification from somwhere as well. */ scanwin = XCreateWindow(dpy, rtwin, /* toggle window */ swid-BOXSIZ, 0, /* origin */ BOXSIZ, BOXSIZ, /* size */ 0, /* border width */ 0, /* depth from parent */ InputOnly, /* class */ CopyFromParent, /* visual */ vmask, &wvals); /* * The GC's for draw and undraw. The method used is to draw the first * shapes, then erase the last one and repeat. */ gc_val.foreground = (unsigned long) WhitePixel (dpy, scrn); gc_val.background = (unsigned long) BlackPixel (dpy, scrn); gc = XCreateGC (dpy, win, GCForeground|GCBackground, &gc_val); gc_val.foreground = (unsigned long) BlackPixel (dpy, scrn); gc_val.background = (unsigned long) WhitePixel (dpy, scrn); ungc = XCreateGC (dpy, win, GCForeground|GCBackground, &gc_val); start = 0; /* duplicated later... */ xx[start] = 0; /* initial vals, should read them? */ yy[start] = 0; xs[start] = 100; ys[start] = 100; xxoff = 3; yyoff = 3; xsoff = 0; ysoff = 0; for (;;) { int sizoff; /* * First we deal with the selector window, then we fall into the * drawing window, and then back to the selector window. */ XSelectInput(dpy, scanwin, EnterWindowMask); XMapWindow(dpy, scanwin); for (;;) { XEvent event; XNextEvent(dpy, &event); if(event.type == EnterNotify) { break; /* * they came in to the corner zone... * interesting frob here might be to * check the position on an angle. */ } } /* * Nuke the screensaver, for now WE are the screensaver. There * really should be a ``screensaver activated'' event of some * sort, so we could trigger on this too... */ XGetScreenSaver(dpy, &timeout, &interval, &blanking, &exposures); XSetScreenSaver(dpy, /* all these are zero, but lets do it right */ DisableScreenSaver, DisableScreenInterval, DontPreferBlanking, DontAllowExposures); /* disable screen saver */ /* * Now wait for the full-screen drawing window to show up */ XSelectInput(dpy, win, ExposureMask); XMapRaised(dpy, win); /* put it on top */ /* * Turn off entry, just notice when the mouse exits. To make it * appear on top again, and to allow other events to leak * through, reparent the mousetrap window into the drawing * window. */ XSelectInput(dpy, scanwin, LeaveWindowMask); XReparentWindow(dpy, scanwin, win, swid-BOXSIZ, 0); /* * always start with one, but make end negative so that we don't * start erasing things until we have enough of them there. */ start = 0; end = start - siz; for (;;) { XEvent event; XNextEvent(dpy, &event); if(event.type == Expose) { break; /* * same type of loop as above, but * this time it is waiting for the * mapping to finish. This could be * made MUCH prettier. */ } } /* * Now start looking for key presses to change the display. Note * that we could just look at scanwin (we know we are in it, * right?) but this way is more fun... */ XSelectInput(dpy, win, KeyPressMask); for (;;) { usleep(micr); /* bored with the X server, sleeping... */ if(XPending(dpy)) /* Got one! */ { XEvent event; XNextEvent(dpy, &event); if(event.type == KeyPress) /* Could listen to both windows... */ { char input; pic tmppic; /* just get the first char of the keypress */ (void)XLookupString(&event.xkey, &input, 1, NULL, NULL); /* convert it to a picture index */ tmppic = char2pic(input, pictype); if (tmppic == pictype) continue; /* punt if already running that one */ if (tmppic == PUNT) /* get out, should check passwd? */ { break; /* * actually a relic from before * mousing stuff worked. */ } if (tmppic == LONG) /* make the pattern longer */ { sizoff = 1; continue; } if (tmppic == SHORT) /* make it shorter */ { sizoff = -1; continue; } if (tmppic == FAST) /* update faster */ { micr <<= (micr>=MAXTIM)?0:1; continue; } if (tmppic == SLOW) /* update slower */ { micr >>= (micr<=MINTIM)?0:1; continue; } while(start != end) /* ok, it IS a new pattern, wipe old */ { undraw(pictype, end); end++; if(end > MAXSIZ) end = 0; } /* set up as a fresh start for the new one */ xx[0] = xx[start]; xs[0] = xs[start]; yy[0] = yy[start]; ys[0] = ys[start]; start = 0; end = start - siz; pictype = tmppic; } else if (event.type == LeaveNotify) { /* this is the REAL escape method... */ break; /* getting out... Password? */ } continue; } if(sizoff == -1) { if(siz > MINSIZ) { siz--; undraw(pictype, end); end++; if(end > MAXSIZ) end = 0; } sizoff = 0; } /* else */ { if (sizoff == 0 || siz >= MAXSIZ) { undraw(pictype, end); end++; if(end > MAXSIZ) end = 0; } if(sizoff == 1 && siz <= MAXSIZ) { siz++; } sizoff = 0; } draw(pictype, start); /* actually draw a stage */ /* * Now for the common box incrementing code... */ ostart = start++; if(start >= SIZ) start = 0; /* jump the bounding box a step... */ xx[start] = xx[ostart] + xxoff; xs[start] = xs[ostart] + xsoff; yy[start] = yy[ostart] + yyoff; ys[start] = ys[ostart] + ysoff; if(xx[start]+xs[start] + xxoff + xsoff > swid) /* past right edge */ { if(xxoff>0) xxoff = -xxoff; if(xsoff>0) xsoff = -xsoff; } if(xx[start]+xxoff < 0) /* past left edge */ { xxoff = -xxoff; } if(yy[start]+ys[start] + yyoff + ysoff > shi) /* below bottom */ { if(yyoff>0) yyoff = -yyoff; if(ysoff>0) ysoff = -ysoff; } if(yy[start]+yyoff < 0) /* above top */ { yyoff = -yyoff; } if(xs[start]+xsoff < 0) /* too narrow */ { xsoff = - xsoff; } if(ys[start]+ysoff < 0) /* too short */ { ysoff = - ysoff; } if(!small_random(0,CHCHANCE)) /* 1:20 chance of actual change */ { if(small_random(0,1)) /* 1:2 choice... */ { xxoff = small_random((xxoff>0?XRM:-XR), (xxoff>0?XR:-XRM)); } else { yyoff = small_random((yyoff>0?YRM:-YR), (yyoff>0?YR:-YRM)); } } if(!small_random(0,CHCHANCE)) { if(small_random(0,1)) /* 1:2 choice... */ { xsoff = 2*small_random((xsoff>0?XRM:-XR), (xsoff>0?XR:-XRM)); } else { ysoff = 2*small_random((ysoff>0?YRM:-YR), (ysoff>0?YR:-YRM)); } } } /* put the special box back in the root window */ XReparentWindow(dpy, scanwin, rtwin, swid-BOXSIZ, 0); /* turn the drawing window off */ XUnmapWindow(dpy, win); /* * hide the graphics, and fall up to * the top. */ /* restore the screensaver to the old defaults */ XSetScreenSaver(dpy, timeout, interval, blanking, exposures); } } void undraw(ptype, ind) pic ptype; int ind; { switch(ptype) { case RECT: if (ind>=0) { XDrawRectangle(dpy, win, ungc, xx[ind], yy[ind], xs[ind], ys[ind]); } break; case CIRC: if(ind>=0) XDrawArc(dpy, win, ungc, xx[ind], yy[ind], xs[ind], ys[ind], 0, 360*64); break; case PENT: if(ind>=0) { XPoint xps[6]; xps[5].x = xps[0].x = xx[ind]+xs[ind]/2; xps[5].y = xps[0].y = yy[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]/2; xps[3].x = xx[ind]+xs[ind]; xps[3].y = yy[ind]+ys[ind]/2; xps[4].x = xx[ind]+xs[ind]/3; xps[4].y = yy[ind]+ys[ind]; xps[1].x = xx[ind]+2*xs[ind]/3; xps[1].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, ungc, xps, 6, CoordModeOrigin); } break; case DIAM: if(ind>=0) { XPoint xps[5]; xps[4].x = xps[0].x = xx[ind]+xs[ind]/2; xps[4].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]+ys[ind]/2; xps[2].x = xx[ind]+xs[ind]/2; xps[2].y = yy[ind]+ys[ind]; xps[3].x = xx[ind]; xps[3].y = yy[ind]+ys[ind]/2; XDrawLines(dpy, win, ungc, xps, 5, CoordModeOrigin); } break; case LEFT: /* / */ if(ind>=0) XDrawLine(dpy, win, ungc, xx[ind], yy[ind]+ys[ind], xx[ind]+xs[ind], yy[ind]); break; case RIGHT: /* \ */ if(ind>=0) XDrawLine(dpy, win, ungc, xx[ind], yy[ind], xx[ind]+xs[ind], yy[ind]+ys[ind]); break; case HGLS: if(ind>=0) { XPoint xps[5]; xps[4].x = xps[0].x = xx[ind]; xps[4].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]; xps[3].x = xx[ind]+xs[ind]; xps[3].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, ungc, xps, 5, CoordModeOrigin); } break; case PLUS: if(ind>=0) { XDrawLine(dpy, win, ungc, /* - */ xx[ind], yy[ind]+ys[ind]/2, xx[ind]+xs[ind], yy[ind]+ys[ind]/2); XDrawLine(dpy, win, ungc, /* | */ xx[ind]+xs[ind]/2, yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); } break; case CROSS: if(ind>=0) { XDrawLine(dpy, win, ungc, /* / */ xx[ind], yy[ind]+ys[ind], xx[ind]+xs[ind], yy[ind]); XDrawLine(dpy, win, ungc, /* \ */ xx[ind], yy[ind], xx[ind]+xs[ind], yy[ind]+ys[ind]); } break; case VEE: if(ind>=0) { XDrawLine(dpy, win, ungc, /* \ */ xx[ind], yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); XDrawLine(dpy, win, ungc, /* / */ xx[ind]+xs[ind], yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); } break; case TRI: if(ind>=0) { XPoint xps[4]; xps[3].x = xps[0].x = xx[ind]+xs[ind]/2; xps[3].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]+ys[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, ungc, xps, 4, CoordModeOrigin); } break; /* , TRI, */ default: break; } } void draw(ptype, ind) pic ptype; int ind; { switch(ptype) { case RECT: XDrawRectangle(dpy, win, gc, xx[ind], yy[ind], xs[ind], ys[ind]); break; case CIRC: XDrawArc(dpy, win, gc, xx[ind], yy[ind], xs[ind], ys[ind], 0, 360*64); break; case PENT: /* * Pentagon: five points. * Top center, * upper left/right (same y, diff. x) * lower left/right (same y, diff. x) * This should fit in a rectangle... * tc = (xx+xs/2, yy) * ul = (xx, yy+ys/2) ur = (xx+xs, yy+ys/2) * ll = (xx+xs/3, yy+ys) lr = (xx+2xs/3, yy+ys) * draw tc->lr->ul->ur->ll->tc. */ { XPoint xps[6]; xps[5].x = xps[0].x = xx[ind]+xs[ind]/2; xps[5].y = xps[0].y = yy[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]/2; xps[3].x = xx[ind]+xs[ind]; xps[3].y = yy[ind]+ys[ind]/2; xps[4].x = xx[ind]+xs[ind]/3; xps[4].y = yy[ind]+ys[ind]; xps[1].x = xx[ind]+2*xs[ind]/3; xps[1].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, gc, xps, 6, CoordModeOrigin); } break; case DIAM: { XPoint xps[5]; xps[4].x = xps[0].x = xx[ind]+xs[ind]/2; xps[4].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]+ys[ind]/2; xps[2].x = xx[ind]+xs[ind]/2; xps[2].y = yy[ind]+ys[ind]; xps[3].x = xx[ind]; xps[3].y = yy[ind]+ys[ind]/2; XDrawLines(dpy, win, gc, xps, 5, CoordModeOrigin); } break; case LEFT: /* / */ XDrawLine(dpy, win, gc, xx[ind], yy[ind]+ys[ind], xx[ind]+xs[ind], yy[ind]); break; case RIGHT: /* \ */ XDrawLine(dpy, win, gc, xx[ind], yy[ind], xx[ind]+xs[ind], yy[ind]+ys[ind]); break; case HGLS: { XPoint xps[5]; xps[4].x = xps[0].x = xx[ind]; xps[4].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]; xps[3].x = xx[ind]+xs[ind]; xps[3].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, gc, xps, 5, CoordModeOrigin); } break; case PLUS: XDrawLine(dpy, win, gc, /* - */ xx[ind], yy[ind]+ys[ind]/2, xx[ind]+xs[ind], yy[ind]+ys[ind]/2); XDrawLine(dpy, win, gc, /* | */ xx[ind]+xs[ind]/2, yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); break; case CROSS: XDrawLine(dpy, win, gc, /* / */ xx[ind], yy[ind]+ys[ind], xx[ind]+xs[ind], yy[ind]); XDrawLine(dpy, win, gc, /* \ */ xx[ind], yy[ind], xx[ind]+xs[ind], yy[ind]+ys[ind]); break; case VEE: XDrawLine(dpy, win, gc, /* \ */ xx[ind], yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); XDrawLine(dpy, win, gc, /* / */ xx[ind]+xs[ind], yy[ind], xx[ind]+xs[ind]/2, yy[ind]+ys[ind]); break; case TRI: { XPoint xps[4]; xps[3].x = xps[0].x = xx[ind]+xs[ind]/2; xps[3].y = xps[0].y = yy[ind]; xps[1].x = xx[ind]+xs[ind]; xps[1].y = yy[ind]+ys[ind]; xps[2].x = xx[ind]; xps[2].y = yy[ind]+ys[ind]; XDrawLines(dpy, win, gc, xps, 4, CoordModeOrigin); } break; default: break; } } int small_random(low, high) /* low <= s_r <= high */ int low, high; { long r; r = random(); return((r % (high-low+1))+low); }