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 screenhack_handle_events (dpy);
137 if (delay) usleep(delay);
142 * dumb way to get # of digits in number. Probably faster than actually
143 * doing a log and a division, maybe.
145 static int dumb_log_2(int k) {
153 /* This parses arguments, initializes the window, etc., and finally starts
154 * calling munchOnce ad infinitum.
157 screenhack (dpy, w) Display *dpy; Window w;
161 XWindowAttributes xgwa;
164 int n = 0; /* number of squares before we have to clear */
168 /* get the dimensions of the window */
169 XGetWindowAttributes (dpy, w, &xgwa);
171 /* We need a square; limit on screen size? */
172 /* we want a power of 2 for the width or the munch doesn't fill up.
175 dumb_log_2(xgwa.height < xgwa.width ? xgwa.height : xgwa.width);
177 maxwidth = 1 << logmaxwidth;
179 if (logmaxwidth < logminwidth) {
180 /* off-by-one error here? Anyone running on < 640x480? */
181 fprintf(stderr, "munch: screen too small; use -logminwidth\n");
182 fprintf(stderr, "\t(width is %d; log is %d; log must be at least "
184 (xgwa.height < xgwa.width ? xgwa.height : xgwa.width),
185 logmaxwidth, logminwidth);
190 cmap = xgwa.colormap;
191 gcv.foreground= get_pixel_resource("foreground","Foreground",
193 gcv.background= get_pixel_resource("background","Background",
196 gc = XCreateGC(dpy, w, GCForeground|GCBackground, &gcv);
198 delay = get_integer_resource ("delay", "Integer");
199 if (delay < 0) delay = 0;
201 hold = get_integer_resource ("hold", "Integer");
202 if (hold < 0) hold = 0;
204 clear = get_integer_resource ("clear", "Integer");
205 if (clear < 0) clear = 0;
207 logminwidth = get_integer_resource ("logminwidth", "Integer");
208 if (logminwidth < 2) logminwidth = 2;
210 shiftk = get_boolean_resource("shift", "Boolean");
212 xor = get_boolean_resource("xor", "Boolean");
214 /* always draw xor on mono. */
216 XSetFunction(dpy, gc, GXxor);
220 /* saves some calls to random. big deal */
221 randflags = random();
223 /* choose size -- power of two */
224 thiswidth = 1 << (logminwidth +
225 (random() % (1 + logmaxwidth - logminwidth)));
228 thiswidth, /* Width, in pixels */
230 /* draw at this location */
231 (random() % (xgwa.width <= thiswidth ? 1
232 : xgwa.width - thiswidth)),
233 (random() % (xgwa.height <= thiswidth ? 1
234 : xgwa.width - thiswidth)),
236 /* wrap-around by these values; no need to %
237 as we end up doing that later anyway*/
238 ((shiftk && (randflags & SHIFT_KX))
239 ? (random() % thiswidth) : 0),
240 ((shiftk && (randflags & SHIFT_KT))
241 ? (random() % thiswidth) : 0),
242 ((shiftk && (randflags & SHIFT_KY))
243 ? (random() % thiswidth) : 0),
245 /* set the gravity of the munch, or rather,
246 which direction we draw stuff in. */
250 screenhack_handle_events (dpy);
251 if (hold) usleep(hold);
253 if (clear && ++n >= clear) {
254 XClearWindow(dpy, w);