mikew@wyse.wyse.com (Mike Wexler) (03/21/89)
Submitted-by: tbray@watdragon.waterloo.edu (Tim Bray) Posting-number: Volume 3, Issue 58 Archive-name: xstatic/part01 #! /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 1 (of 1)." # Contents: README AUTHOR Imakefile Makefile genbits.c patchlevel.h # xranmap.c xstatic.1 xstatic.c # Wrapped by mikew@wyse on Mon Mar 20 14:41:01 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(233 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XThis program has been nominated for the Rogue memorial waste-of-programmer- Xtime award as well as the GNU memorial cute-name award. There's a man page Xthat describes what it does. Seems to work on Sun3, Sun4, and Vax under XXV11R3. END_OF_FILE if test 233 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'AUTHOR' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'AUTHOR'\" else echo shar: Extracting \"'AUTHOR'\" \(919 characters\) sed "s/^X//" >'AUTHOR' <<'END_OF_FILE' X(Message inbox:1330) XReturn-Path: tbray%watdragon.waterloo.edu@RELAY.CS.NET XReceived: by wyse.wyse.com (5.58/Wyse master/5-13-88) X id AA17065; Sat, 18 Mar 89 12:06:03 PST XReceived: from RELAY.CS.NET by uunet.UU.NET (5.61/1.14) with SMTP X id AA13772; Sat, 18 Mar 89 11:49:39 -0500 XReceived: from [129.97.128.1] by RELAY.CS.NET id aa13386; 18 Mar 89 11:48 EST XReceived: from watdragon.waterloo.edu by watmath.waterloo.edu with SMTP; Sat, 18 Mar 89 11:44:43 EST XReceived: by watdragon.waterloo.edu; Sat, 18 Mar 89 11:43:47 EST XTo: comp-sources-x%watmath.waterloo.edu@RELAY.CS.NET XPath: watdragon!tbray XFrom: Tim Bray <tbray%watdragon.waterloo.edu@RELAY.CS.NET> XNewsgroups: comp.sources.x XSubject: Ecstatic X Static XMessage-Id: <12484@watdragon.waterloo.edu> XDate: 18 Mar 89 16:43:45 GMT XReply-To: Tim Bray <tbray%watdragon.waterloo.edu@RELAY.CS.NET> XDistribution: world XOrganization: U. of Waterloo, Ontario XLines: 535 X END_OF_FILE if test 919 -ne `wc -c <'AUTHOR'`; then echo shar: \"'AUTHOR'\" unpacked with wrong size! fi # end of 'AUTHOR' fi if test -f 'Imakefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Imakefile'\" else echo shar: Extracting \"'Imakefile'\" \(336 characters\) sed "s/^X//" >'Imakefile' <<'END_OF_FILE' XSYSLAST_LIBRARIES = $(XLIB) X SRCS1 = xstatic.c genbits.c X OBJS1 = xstatic.o genbits.o X XAllTarget(xstatic xranmap) XSingleProgramTarget(xstatic,$(OBJS1),,) XNormalLintTarget($(SRCS)) X X SRCS2 = xranmap.c X OBJS2 = xranmap.o X XSingleProgramTarget(xranmap,$(OBJS2),,) XNormalLintTarget($(SRCS2)) X END_OF_FILE if test 336 -ne `wc -c <'Imakefile'`; then echo shar: \"'Imakefile'\" unpacked with wrong size! fi # end of 'Imakefile' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(163 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' Xall: xstatic xranmap X Xxstatic: xstatic.o genbits.o X cc -o xstatic $(CFLAGS) xstatic.o genbits.o -lX11 X Xxranmap: xranmap.o X cc -o xranmap $(CFLAGS) xranmap.o -lX11 END_OF_FILE if test 163 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'genbits.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'genbits.c'\" else echo shar: Extracting \"'genbits.c'\" \(7022 characters\) sed "s/^X//" >'genbits.c' <<'END_OF_FILE' X/* X** Portions stolen from 'xphoon' with grateful acknowledgement AND X** Portions written by Tim Bray are X** Copyright (C) 1988 by Jef Poskanzer and Craig Leres. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include <X11/Xos.h> X X/* X * genbits(p, bytecount, bits) - fills the char array 'bits', which is of size X * 'bytecount', with bits each of of which is on with probability not too far X * from p. X * X * This is quite a lot of bits; at least a million. Calling random() this X * many times is slow, sez the profiler. For this reason, the random bits X * are generated eight at a time. It is easy to calculate the probability X * of N bits in a byte being on as a function of p. An array of 1024 chars X * is filled with numbers from 0 to 8 inclusive in numbers proportional to X * the probability of a byte having that many bits on. Ten bits of random X * number index this array and select the number of bits to be on in the next X * byte. Once the number of on-bits is selected, another random number is X * used to select which byte to use among all the bytes with that many bits X * on. For fear that something might not be relatively prime with something X * else, the same random number is not used for the two indexing operations - X * this is almost certainly unnecessary caution. X * X * There is a slight loss due to quantizing the probability domain into X * 1024 slots. For example if p is less than about .43, this will never X * generate a byte of all 1's. An earlier version, which called random() X * once per bit, would in fact do this a few times in a million, as the X * combinatorics say it should. Note that the possible bit counts can be X * encoded in 4 bits, so you could quantize into 2048 or 4096 chunks without X * wasting too much memory. However, I went cross-eyed alternating my screen X * back and forth between the two versions and couldn't convince myself that X * there was a difference. And this version (with the tenbits() trick) X * has 24 times fewer calls to random and is dramatically faster. Have to X * show this to a real mathematician who understands what a random number is X * and dodge the flying vomit. X */ X/* Static precomputed data for genbits */ X/* bytes with this many bits on */ Xstatic int BytesWithCount0[] = { 0 }; Xstatic int BytesWithCount1[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; Xstatic int BytesWithCount2[] = X{ X 3, 5, 6, 9, 10, 12, 17, 18, 20, 24, 33, 34, 36, 40, 48, 65, 66, 68, 72, 80, X 96, 129, 130, 132, 136, 144, 160, 192 X}; Xstatic int BytesWithCount3[] = X{ X 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50, 52, X 56, 67, 69, 70, 73, 74, 76, 81, 82, 84, 88, 97, 98, 100, 104, 112, 131, 133, X 134, 137, 138, 140, 145, 146, 148, 152, 161, 162, 164, 168, 176, 193, 194, X 196, 200, 208, 224 X}; Xstatic int BytesWithCount4[] = X{ X 15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, X 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, X 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, X 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, X 226, 228, 232, 240 X}; Xstatic int BytesWithCount5[] = X{ X 31, 47, 55, 59, 61, 62, 79, 87, 91, 93, 94, 103, 107, 109, 110, 115, 117, X 118, 121, 122, 124, 143, 151, 155, 157, 158, 167, 171, 173, 174, 179, 181, X 182, 185, 186, 188, 199, 203, 205, 206, 211, 213, 214, 217, 218, 220, 227, X 229, 230, 233, 234, 236, 241, 242, 244, 248 X}; Xstatic int BytesWithCount6[] = X{ X 63, 95, 111, 119, 123, 125, 126, 159, 175, 183, 187, 189, 190, 207, 215, 219, X 221, 222, 231, 235, 237, 238, 243, 245, 246, 249, 250, 252 X}; Xstatic int BytesWithCount7[] = { 127, 191, 223, 239, 247, 251, 253, 254 }; Xstatic int BytesWithCount8[] = { 255 }; X Xstatic int * BytesWithCount[] = X{ X BytesWithCount0, BytesWithCount1, BytesWithCount2, BytesWithCount3, X BytesWithCount4, BytesWithCount5, BytesWithCount6, BytesWithCount7, X BytesWithCount8 X}; X X/* Eight choose whatever - also the sizes of the BytesWith arrays */ Xstatic int EightChoose[] = { 1, 8, 28, 56, 70, 56, 28, 8, 1 }; X Xextern time_t time(); Xextern long random(); X Xvoid Xgenbits(p, bytecount, bits) X double p; X int bytecount; X register char * bits; X{ X char bitcounts[1024]; X register int count; X int i; X int j; X int k; X register int last; X int maxbitcount; X int PartOfK[9]; X double PToThe[9]; X double probability; X double QToThe[9]; X register int selector; X register char * stop; X X /* Compute the probabilities of bit counts 0 through 8 */ X /* first, work out the powers of p and 1-p */ X PToThe[0] = QToThe[0] = 1.0; X for (i = 1; i <= 8; i++) X { /* for each bit count */ X PToThe[i] = PToThe[i - 1] * p; X QToThe[i] = QToThe[i - 1] * (1.0 - p); X } /* for each bit count */ X X /* the probability of i bits being on is (8 choose i) * p**i * q**(8-i) */ X count = maxbitcount = 0; X for (i = 0; i <= 8; i++) X { /* for each bit count */ X probability = ((double) EightChoose[i]) * PToThe[i] * QToThe[8 - i]; X PartOfK[i] = (int) (1024.0 * probability); X if (PartOfK[i] > PartOfK[maxbitcount]) X maxbitcount = i; X count += PartOfK[i]; X } /* for each bit count */ X X /* might not come to 1024 because of rounding error; correct largest */ X if (count != 1024) X PartOfK[maxbitcount] += 1024 - count; X X /* Load up bitcount array with appropriate numbers of different counts */ X for(i = 0, j = 0; i <= 8; i++) X for (k = 0; k < PartOfK[i]; k++) X bitcounts[j++] = i; X X /* Set up and let 'er rip */ X srandom((int) time((time_t *) 0)); X last = tenbits(); X stop = bits + bytecount; X while (bits < stop) X { /* for each byte */ X X /* select bit count depending on probability */ X selector = tenbits(); X count = bitcounts[selector]; X X /* use a randomly selected byte with that many bits on */ X if (count == 0) X count = 0; X else if (count == 8) X count = 0xff; X else X count = BytesWithCount[count][last % EightChoose[count]]; X *bits++ = count; X X /* remember the random number to re-use next time */ X last = selector; X X } /* for each byte */ X} X X/* X * Returns ten random bits. Since it is expensive to call random(), and we X * only need ten bits per, and random gives us 31 bits per call, why waste X * the other 20? X */ Xstatic int Xtenbits() X{ X static int onetwothree = 3; X static int ranbits; X X /* use random() every third call; shift 10 bits over on the other two */ X if (onetwothree == 3) X { X ranbits = random(); X onetwothree = 1; X } X else X { X ranbits >>= 10; X onetwothree++; X } X X return ranbits & 1023; X} END_OF_FILE if test 7022 -ne `wc -c <'genbits.c'`; then echo shar: \"'genbits.c'\" unpacked with wrong size! fi # end of 'genbits.c' fi if test -f 'patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patchlevel.h'\" else echo shar: Extracting \"'patchlevel.h'\" \(21 characters\) sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE' X#define PATCHLEVEL 0 END_OF_FILE if test 21 -ne `wc -c <'patchlevel.h'`; then echo shar: \"'patchlevel.h'\" unpacked with wrong size! fi # end of 'patchlevel.h' fi if test -f 'xranmap.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xranmap.c'\" else echo shar: Extracting \"'xranmap.c'\" \(1908 characters\) sed "s/^X//" >'xranmap.c' <<'END_OF_FILE' X/* X * genb side percent X * This program prints out an X11 bitmap file representing a square of X * size 'side', in which each bit has probability 'percent' of being off. X * 'Percent' is converted using atof(), so it can be integral or floating. X */ X#include <stdio.h> X#include <X11/Xos.h> X Xextern double atof(); Xextern long random(); Xextern time_t time(); X Xmain(argc, argv) X int argc; X char * argv[]; X{ X int bit[8]; X int dimension; X register int j; X int onrow = 0; X register long percent; X register int word; X X /* no flexibility here */ X if (argc != 3) X { /* yecch */ X (void) fprintf(stderr, "usage: genb length-of-side percent-of-bits-off\n"); X exit(1); X } /* yecch */ X X /* precompute bit masks; assumes array ref is faster than 1 << j in loop */ X for (j = 0; j < 8; j++) X bit[j] = 1 << j; X srandom((int) time((time_t *) 0)); X X /* this many bits on a side; X11 wants bytes; round up */ X dimension = atoi(argv[1]); X (void) printf("#define bm_width %d\n#define bm_height %d\n", X dimension, dimension); X (void) printf("static char bm_bits[] = {\n"); X dimension = ((dimension * dimension) + 7) / 8; X X /* percent is to 2**32 - 1 as argv[2] is to 100 */ X percent = (long) ( ((double) 0x7fffffff) * (atof(argv[2]) / 100.0) ); X X /* for each byte */ X while (dimension--) X { /* for each byte */ X X /* use the X11 indentation standard */ X if (onrow == 0) X fputs(" ", stdout); X X /* turn on bits in byte with probability percent/100 */ X for (word = 0, j = 0; j < 8; j++) X if (random() >= percent) X word |= bit[j]; X X /* print out a byte */ X (void) printf("0x%02x", word); X if (dimension) X fputs(", ", stdout); X X /* use 12 bytes/row */ X if (++onrow == 12) X { /* new row */ X fputs("\n", stdout); X onrow = 0; X } /* new row */ X } /* for each byte */ X X fputs("\n};\n", stdout); X exit(0); X} X END_OF_FILE if test 1908 -ne `wc -c <'xranmap.c'`; then echo shar: \"'xranmap.c'\" unpacked with wrong size! fi # end of 'xranmap.c' fi if test -f 'xstatic.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xstatic.1'\" else echo shar: Extracting \"'xstatic.1'\" \(2841 characters\) sed "s/^X//" >'xstatic.1' <<'END_OF_FILE' X.TH XSTATIC 1 "10 March 1989" X.SH NAME Xxstatic, xranmap \- generate Static for X windows X.SH SYNOPSIS X.B xstatic X[ percent ] X.sp X.B xranmap Xside-of-square percent X.SH DESCRIPTION XTired of that boring old moon or gray or weave bitmap on your screen? X.I Xstatic Xproduces a screen background guaranteed with near Xcertainty to be totally unique to you. XTo be precise, it fills the root window background with visual static: Xrandom bits with \fIpercent\fP \(di 100.0 probability of being white. X.I Percent Xis converted using \fIatof(3)\fP, so fractional numbers can be used. XIt defaults to 50.0. X.PP X.I Xranmap Xwrites to standard output an X11 bitmap file describing a square of Xside \fIside-of-square\fP bits each having probability of X\fIpercent\fP \(di 100.0 of being 1. XSo you can have a static-filled icon, cursor, or background for anything; can't Ximagine why you'd want to. X.SH NOTES XThis was written in the hope of a visual analogue to the fact Xthat white noise is a good palliative for audio pollution. XThe author (an entirely objective sample of size 1) feels that this works; Xan appropriate choice of percentage produces a screen background Xthat is easier on the eyes than any \fIxsetroot(1)\fP option. XOn the author's bottom-end Sun-3/50, this choice is in the 25 - 40 range. XPercentages in the range 0.1 - 4.0 produce screens that look Xsomething like \fIxphoon(1)\fP without the moon. X.PP XNote that the sequence X.sp Xxranmap 1024 NN > ran.bm X.br Xxsetroot -bitmap ran.bm X.sp Xis more or less equivalent to X.sp Xxstatic NN X.sp Xon a megapixel screen, but is much, much slower (and chews up 819K of Xdisk space). X.PP XThe original motivation for this program (to quote the xphoon man page) Xwas that xphoon was X.B too boring Xonce everybody started using it. X.PP XThe straightforward approach to generating a screenful of random bits using Xa million or so calls to \fIrandom(3)\fP turns out to be slow. XAs a result, the code for the function \fIgenbits()\fP contains some Xoptimizations that might be of mild interest to the bit-bangers in the Xcrowd. X.I Xranmap Xuses the obvious approach, since it spends all its time in X\fIprintf(3)\fP anyhow. X.SH "SEE ALSO" X.IR xsetroot(1), X.IR xphoon(1) X.SH AUTHORS XThe mainline and window-setting code (and the basis of this man page) Xare pretty well a straight steal from xphoon, and since I'm embarrassed Xto admit that I spent a whole day Xworking on this, the whole thing remains XCopyright (C) 1988 by Jef Poskanzer and Craig Leres. X XPermission to use, copy, modify, and distribute this software and its Xdocumentation for any purpose and without fee is hereby granted, provided Xthat the above copyright notice appear in all copies and that both that Xcopyright notice and this permission notice appear in supporting Xdocumentation. This software is provided "as is" without express or Ximplied warranty. END_OF_FILE if test 2841 -ne `wc -c <'xstatic.1'`; then echo shar: \"'xstatic.1'\" unpacked with wrong size! fi # end of 'xstatic.1' fi if test -f 'xstatic.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xstatic.c'\" else echo shar: Extracting \"'xstatic.c'\" \(3416 characters\) sed "s/^X//" >'xstatic.c' <<'END_OF_FILE' X/* X** Portions written by Tim Bray AND X** Portions stolen from 'xphoon' with grateful acknowledgement are X** Copyright (C) 1988 by Jef Poskanzer and Craig Leres. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include <X11/Xlib.h> X#include <X11/Xatom.h> X#include <stdio.h> X Xextern double atof(); Xextern char * malloc(); X Xstatic char * argv0; X Xmain(argc, argv) X int argc; X char * argv[]; X{ X XWindowAttributes attributes; X char * bits; X int bytecount; X char * display = NULL; X Display * dpy = NULL; X void genbits(); X double percent = 0.5; X X argv0 = argv[0]; X if ((dpy = XOpenDisplay(display)) == 0) X { X fprintf(stderr, "%s: Can't open display \"%s\"\n", argv0, X XDisplayName(display)); X exit(1); X } X X /* make sure percent is reasonable */ X if (argc > 1) X percent = atof(argv[1]) / 100.0; X if (percent < 0.0 || percent > 1.0) X { X fprintf(stderr, "%s: bogus percentage\n", argv0); X exit(1); X } X X /* how many bits to fill the window? */ X XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attributes); X X /* compute the byte count, rounding up, and get some memory */ X bytecount = ((attributes.width * attributes.height) + 7) / 8; X if ((bits = malloc((unsigned) bytecount)) == NULL) X { X fprintf(stderr, "%s: Can't malloc\n", argv0); X exit(1); X } X X genbits(percent, bytecount, bits); X setroot(attributes.width, attributes.height, bits, dpy); X XCloseDisplay(dpy); X exit(0); X} X Xsetroot(w, h, bits, dpy) X int w, h; X char *bits; X Display * dpy; X{ X Pixmap bitmap; X Pixmap pixmap; X GC gc; X XGCValues gcv; X unsigned long length, after; X int format; X Atom prop, type; X unsigned char *data; X X bitmap = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), bits, w, h); X if (bitmap == 0) X { X fprintf(stderr, "%s: Unable to store Bitmap\n", argv0); X exit(1); X } X X /* xphoon had these the other way round - why? */ X gcv.background = BlackPixel(dpy,DefaultScreen(dpy)); X gcv.foreground = WhitePixel(dpy,DefaultScreen(dpy)); X gc = XCreateGC(dpy, DefaultRootWindow(dpy), GCForeground|GCBackground, &gcv); X X pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), w, h, X DefaultDepth(dpy, DefaultScreen(dpy))); X if (pixmap == 0) X { X fprintf(stderr, "%s: Unable to create Pixmap", argv0); X exit(1); X } X X XCopyPlane(dpy, bitmap, pixmap, gc, 0, 0, w, h, 0, 0, 1L); X XSetWindowBackgroundPixmap(dpy, DefaultRootWindow(dpy), pixmap); X XFreeGC(dpy, gc); X XFreePixmap(dpy, bitmap); X XFreePixmap(dpy, pixmap); X XClearWindow(dpy, DefaultRootWindow(dpy)); X XFlush(dpy); X X /* Not sure what this garbage does, but xsetroot has it, so... */ X prop = XInternAtom(dpy, "_XSETROOT_ID", False); X (void) XGetWindowProperty(dpy, DefaultRootWindow(dpy), prop, 0L, 1L, True, X AnyPropertyType, &type, &format, &length, &after, &data); X if ((type == XA_PIXMAP) && (format == 32) && (length == 1) && (after == 0)) X XKillClient(dpy, *((Pixmap *)data)); X else if (type != None) X fprintf(stderr, "%s: warning: _XSETROOT_ID property is garbage\n", argv0); X XFlush(dpy); X} X END_OF_FILE if test 3416 -ne `wc -c <'xstatic.c'`; then echo shar: \"'xstatic.c'\" unpacked with wrong size! fi # end of 'xstatic.c' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. 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 -- Mike Wexler(wyse!mikew) Phone: (408)433-1000 x1330 Moderator of comp.sources.x