2 * A munching squares implementation for X
3 * Tim Showalter <tjs@andrew.cmu.edu>
5 * Copyright 1997, Tim Showalter
6 * Permission is granted to copy, modify, and use this as long
7 * as this notice remains intact. No warranties are expressed or implied.
10 * Some code stolen from / This is meant to work with
11 * xscreensaver, Copyright (c) 1992, 1995, 1996
12 * Jamie Zawinski <jwz@jwz.org>
14 * Permission to use, copy, modify, distribute, and sell this software and its
15 * documentation for any purpose is hereby granted without fee, provided that
16 * the above copyright notice appear in all copies and that both that
17 * copyright notice and this permission notice appear in supporting
18 * documentation. No representations are made about the suitability of this
19 * software for any purpose. It is provided "as is" without express or
23 /* Munching Squares is this simplistic, silly screen hack (according
24 to HAKMEM, discovered by Jackson Wright in 1962) where you take
25 Y = X XOR T and graph it over and over. According to HAKMEM, it
26 takes 5 instructions of PDP-1 assembly. This is a little more
27 complicated than that, mostly X's fault, but it does some other
30 http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item146
34 /*#include <assert.h>*/
35 #include "screenhack.h"
37 /* flags for random things. Must be < log2(random's maximum), incidentially.
39 #define SHIFT_KX (0x01)
40 #define SHIFT_KT (0x02)
41 #define SHIFT_KY (0x04)
44 char *progclass = "Munch";
58 XrmOptionDescRec options [] = {
59 { "-delay", ".delay", XrmoptionSepArg, 0 },
60 { "-hold", ".hold", XrmoptionSepArg, 0 },
61 { "-clear", ".clear", XrmoptionSepArg, "true" },
62 { "-shift", ".shift", XrmoptionNoArg, "true" },
63 { "-no-shift", ".shift", XrmoptionNoArg, "false" },
64 { "-logminwidth", ".logminwidth", XrmoptionSepArg, 0 },
65 { "-xor", ".xor", XrmoptionNoArg, "true" },
66 { "-no-xor", ".xor", XrmoptionNoArg, "false" },
72 /* only configurable things right now */
73 static int delay, hold, clear, logminwidth, shiftk, xor;
75 static void munchOnce (Display* dpy, Window w,
76 int width, /* pixels */
77 int atX, int atY, /* pixels */
78 int kX, int kT, int kY, /* pixels */
79 int grav /* 0 or not */) {
83 XWindowAttributes xgwa;
88 fprintf(stderr,"Doing width %d at %d %d shift %d %d %d grav %d\n",
89 width, atX, atY, kX, kT, kY, grav);
92 XGetWindowAttributes (dpy, w, &xgwa);
95 /* XXX there are probably bugs with this. */
98 fgc.red = random() % 65535;
99 fgc.green = random() % 65535;
100 fgc.blue = random() % 65535;
102 if (XAllocColor(dpy, cmap, &fgc)) {
103 XSetForeground(dpy, gc, fgc.pixel);
107 /* Finally draw this munching square. */
108 for(t = 0; t < width; t++) {
109 for(x = 0; x < width; x++) {
110 /* figure out the next point */
111 y = ((x ^ ((t + kT) % width)) + kY) % width;
113 drawX = ((x + kX) % width) + atX;
114 drawY = (grav ? y + atY : atY + width - 1 - y);
116 /* used to be bugs where it would draw partially offscreen.
117 while that might be a pretty feature, I didn't want it to do
118 that yet. if these trigger, please let me know.
120 /* assert(drawX >= 0 && drawX < xgwa.width);
121 assert(drawY >= 0 && drawY < xgwa.height);
124 XDrawPoint(dpy, w, gc, drawX, drawY);
125 /* XXX may want to change this to XDrawPoints,
126 but it's fast enough without it for the moment. */
130 /* we've drawn one pass' worth of points. let the server catch up
131 or this won't be interesting to watch at all. we call this here
132 in the hopes of having one whole sequence of dots appear at the
133 same time (one for each value of x, surprisingly enough)
136 if (delay) usleep(delay);
141 * dumb way to get # of digits in number. Probably faster than actually
142 * doing a log and a division, maybe.
144 static int dumb_log_2(int k) {
152 /* This parses arguments, initializes the window, etc., and finally starts
153 * calling munchOnce ad infinitum.
156 screenhack (dpy, w) Display *dpy; Window w;
160 XWindowAttributes xgwa;
163 int n = 0; /* number of squares before we have to clear */
167 /* get the dimensions of the window */
168 XGetWindowAttributes (dpy, w, &xgwa);
170 /* We need a square; limit on screen size? */
171 /* we want a power of 2 for the width or the munch doesn't fill up.
174 dumb_log_2(xgwa.height < xgwa.width ? xgwa.height : xgwa.width);
176 maxwidth = 1 << logmaxwidth;
178 if (logmaxwidth < logminwidth) {
179 /* off-by-one error here? Anyone running on < 640x480? */
180 fprintf(stderr, "munch: screen too small; use -logminwidth\n");
181 fprintf(stderr, "\t(width is %d; log is %d; log must be at least "
183 (xgwa.height < xgwa.width ? xgwa.height : xgwa.width),
184 logmaxwidth, logminwidth);
189 cmap = xgwa.colormap;
190 gcv.foreground= get_pixel_resource("foreground","Foreground",
192 gcv.background= get_pixel_resource("background","Background",
195 gc = XCreateGC(dpy, w, GCForeground|GCBackground, &gcv);
197 delay = get_integer_resource ("delay", "Integer");
198 if (delay < 0) delay = 0;
200 hold = get_integer_resource ("hold", "Integer");
201 if (hold < 0) hold = 0;
203 clear = get_integer_resource ("clear", "Integer");
204 if (clear < 0) clear = 0;
206 logminwidth = get_integer_resource ("logminwidth", "Integer");
207 if (logminwidth < 2) logminwidth = 2;
209 shiftk = get_boolean_resource("shift", "Boolean");
211 xor = get_boolean_resource("xor", "Boolean");
213 /* always draw xor on mono. */
215 XSetFunction(dpy, gc, GXxor);
219 /* saves some calls to random. big deal */
220 randflags = random();
222 /* choose size -- power of two */
223 thiswidth = 1 << (logminwidth +
224 (random() % (1 + logmaxwidth - logminwidth)));
227 thiswidth, /* Width, in pixels */
229 /* draw at this location */
230 (random() % (xgwa.width <= thiswidth ? 1
231 : xgwa.width - thiswidth)),
232 (random() % (xgwa.height <= thiswidth ? 1
233 : xgwa.width - thiswidth)),
235 /* wrap-around by these values; no need to %
236 as we end up doing that later anyway*/
237 ((shiftk && (randflags & SHIFT_KX))
238 ? (random() % thiswidth) : 0),
239 ((shiftk && (randflags & SHIFT_KT))
240 ? (random() % thiswidth) : 0),
241 ((shiftk && (randflags & SHIFT_KY))
242 ? (random() % thiswidth) : 0),
244 /* set the gravity of the munch, or rather,
245 which direction we draw stuff in. */
249 if (hold) usleep(hold);
251 if (clear && ++n >= clear) {
252 XClearWindow(dpy, w);