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)
50 int delay, hold, clear, logminwidth, shiftk, xor;
56 XWindowAttributes xgwa;
61 int atX, atY, kX, kT, kY, grav;
66 static int munchOnce (struct state *st, int width)
69 if (st->munch_t == 0) {
71 fprintf(stderr,"Doing width %d at %d %d shift %d %d %d grav %d\n",
72 width, atX, atY, kX, kT, kY, grav);
77 fgc.red = random() % 65535;
78 fgc.green = random() % 65535;
79 fgc.blue = random() % 65535;
81 if (XAllocColor(st->dpy, st->xgwa.colormap, &fgc)) {
82 XSetForeground(st->dpy, st->gc, fgc.pixel);
87 /* Finally draw this munching square. */
88 /* for(munch_t = 0; munch_t < width; munch_t++) */
91 for(x = 0; x < width; x++) {
92 /* figure out the next point */
93 int y = ((x ^ ((st->munch_t + st->kT) % width)) + st->kY) % width;
94 int drawX = ((x + st->kX) % width) + st->atX;
95 int drawY = (st->grav ? y + st->atY : st->atY + width - 1 - y);
97 /* used to be bugs where it would draw partially offscreen.
98 while that might be a pretty feature, I didn'munch_t want it to do
99 that yet. if these trigger, please let me know.
101 /* assert(drawX >= 0 && drawX < xgwa.width);
102 assert(drawY >= 0 && drawY < xgwa.height);
105 XDrawPoint(st->dpy, st->window, st->gc, drawX, drawY);
106 /* XXX may want to change this to XDrawPoints,
107 but it's fast enough without it for the moment. */
113 if (st->munch_t >= width) {
122 * dumb way to get # of digits in number. Probably faster than actually
123 * doing a log and a division, maybe.
125 static int dumb_log_2(int k)
135 munch_init (Display *dpy, Window w)
137 struct state *st = (struct state *) calloc (1, sizeof(*st));
143 /* get the dimensions of the window */
144 XGetWindowAttributes (st->dpy, w, &st->xgwa);
146 /* We need a square; limit on screen size? */
147 /* we want a power of 2 for the width or the munch doesn't fill up.
149 st->logmaxwidth = (int)
150 dumb_log_2(st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width);
152 st->maxwidth = 1 << st->logmaxwidth;
154 if (st->logmaxwidth < st->logminwidth) {
155 /* off-by-one error here? Anyone running on < 640x480? */
156 fprintf(stderr, "munch: screen too small; use -logminwidth\n");
157 fprintf(stderr, "\t(width is %d; log is %d; log must be at least "
159 (st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width),
160 st->logmaxwidth, st->logminwidth);
165 gcv.foreground= get_pixel_resource(st->dpy, st->xgwa.colormap,
166 "foreground","Foreground");
167 gcv.background= get_pixel_resource(st->dpy, st->xgwa.colormap,
168 "background","Background");
170 st->gc = XCreateGC(st->dpy, w, GCForeground|GCBackground, &gcv);
172 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
173 if (st->delay < 0) st->delay = 0;
175 st->hold = get_integer_resource (st->dpy, "hold", "Integer");
176 if (st->hold < 0) st->hold = 0;
178 st->clear = get_integer_resource (st->dpy, "clear", "Integer");
179 if (st->clear < 0) st->clear = 0;
181 st->logminwidth = get_integer_resource (st->dpy, "logminwidth", "Integer");
182 if (st->logminwidth < 2) st->logminwidth = 2;
184 st->shiftk = get_boolean_resource(st->dpy, "shift", "Boolean");
186 st->xor = get_boolean_resource(st->dpy, "xor", "Boolean");
188 /* always draw xor on mono. */
189 if (mono_p || st->xor) {
190 XSetFunction(st->dpy, st->gc, GXxor);
199 munch_draw (Display *dpy, Window w, void *closure)
201 struct state *st = (struct state *) closure;
202 int this_delay = st->delay;
208 this_delay = st->hold;
209 /* saves some calls to random. big deal */
210 st->randflags = random();
212 /* choose size -- power of two */
213 st->thiswidth = 1 << (st->logminwidth +
214 (random() % (1 + st->logmaxwidth - st->logminwidth)));
216 if (st->clear && ++st->square_count >= st->clear) {
217 XClearWindow(st->dpy, w);
218 st->square_count = 0;
221 /* draw at this location */
222 st->atX = (random() % (st->xgwa.width <= st->thiswidth ? 1
223 : st->xgwa.width - st->thiswidth));
224 st->atY = (random() % (st->xgwa.height <= st->thiswidth ? 1
225 : st->xgwa.width - st->thiswidth));
227 /* wrap-around by these values; no need to %
228 as we end up doing that later anyway*/
229 st->kX = ((st->shiftk && (st->randflags & SHIFT_KX))
230 ? (random() % st->thiswidth) : 0);
231 st->kT = ((st->shiftk && (st->randflags & SHIFT_KT))
232 ? (random() % st->thiswidth) : 0);
233 st->kY = ((st->shiftk && (st->randflags & SHIFT_KY))
234 ? (random() % st->thiswidth) : 0);
236 /* set the gravity of the munch, or rather,
237 which direction we draw stuff in. */
238 st->grav = (st->randflags & GRAV);
241 if (munchOnce (st, st->thiswidth))
244 /* printf("%d\n",this_delay);*/
249 munch_reshape (Display *dpy, Window window, void *closure,
250 unsigned int w, unsigned int h)
252 struct state *st = (struct state *) closure;
255 st->logmaxwidth = (int)
256 dumb_log_2(st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width);
257 st->maxwidth = 1 << st->logmaxwidth;
261 munch_event (Display *dpy, Window window, void *closure, XEvent *event)
267 munch_free (Display *dpy, Window window, void *closure)
269 struct state *st = (struct state *) closure;
274 static const char *munch_defaults [] = {
275 ".background: black",
276 ".foreground: white",
287 static XrmOptionDescRec munch_options [] = {
288 { "-delay", ".delay", XrmoptionSepArg, 0 },
289 { "-hold", ".hold", XrmoptionSepArg, 0 },
290 { "-clear", ".clear", XrmoptionSepArg, "true" },
291 { "-shift", ".shift", XrmoptionNoArg, "true" },
292 { "-no-shift", ".shift", XrmoptionNoArg, "false" },
293 { "-logminwidth", ".logminwidth", XrmoptionSepArg, 0 },
294 { "-xor", ".xor", XrmoptionNoArg, "true" },
295 { "-no-xor", ".xor", XrmoptionNoArg, "false" },
299 XSCREENSAVER_MODULE ("Munch", munch)