1 /* imsmap, Copyright (c) 1992 Juergen Nickelsen <nickel@cs.tu-berlin.de>
2 * Derived from code by Markus Schirmer, TU Berlin.
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 * 24-aug-92: jwz: hacked.
14 * 17-May-97: jwz: hacked more.
19 #include <sys/time.h> /* for gettimeofday() */
22 #include <X11/Xutil.h>
24 #include "screenhack.h"
27 #define COUNT (1 << NSTEPS)
28 #define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
30 static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
33 static XWindowAttributes xgwa;
35 #if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */
41 static XColor *colors;
43 static int cycle_direction;
44 static Bool extra_krinkly_p;
46 static int delay, cycle_delay;
47 static signed char *cell = NULL;
48 static int xmax, ymax;
49 static int iterations;
52 init_map (Display *dpy, Window window)
54 unsigned long fg_pixel = 0, bg_pixel = 0;
56 double fg_s, fg_v, bg_s, bg_v;
58 enum mode_t this_mode;
63 XGetWindowAttributes (dpy, window, &xgwa);
68 char *mode_str = get_string_resource ("mode", "Mode");
69 rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
70 cycle_p = get_boolean_resource ("cycle", "Cycle");
71 ncolors = get_integer_resource ("ncolors", "Integer");
72 delay = get_integer_resource ("delay", "Integer");
73 cycle_delay = get_integer_resource ("cycleDelay", "Integer");
74 iterations = get_integer_resource ("iterations", "Integer");
75 if (iterations < 0) iterations = 0;
76 else if (iterations > 7) iterations = 7;
78 if (ncolors <= 2) ncolors = 0;
79 if (ncolors == 0) mono_p = True;
81 fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
82 bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
84 if (fg_pixel == bg_pixel)
87 black.red = black.green = black.blue = 0;
88 white.red = white.green = white.blue = 0xFFFF;
89 black.flags = white.flags = DoRed|DoGreen|DoBlue;
90 XAllocColor(dpy, cmap, &black);
91 XAllocColor(dpy, cmap, &white);
92 if (bg_pixel == black.pixel)
93 fg_pixel = white.pixel;
95 fg_pixel = black.pixel;
98 if (mono_p) cycle_p = False;
100 gcv.foreground = fg_pixel;
101 gcv.background = bg_pixel;
102 gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
103 gcv.foreground = bg_pixel;
104 gc2 = XCreateGC (dpy, window, GCForeground, &gcv);
106 if (!mode_str || !strcmp (mode_str, "random"))
108 else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
110 else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
112 else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
117 "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
124 if (!mono_p && mode == MODE_RANDOM)
125 switch (random () % 6) {
126 case 0: this_mode = MODE_H; break;
127 case 1: this_mode = MODE_S; break;
128 case 2: this_mode = MODE_V; break;
133 extra_krinkly_p = !(random() % 15);
135 extra_krinkly_p = !(random() % 5);
139 double distance, fg_H, bg_H, dh;
142 fg_h = random() % 360;
153 bg_h = random() % 360;
156 distance = fg_h - bg_h;
158 distance = -distance;
160 distance = 180 - (distance - 180);
169 distance = fg_s - bg_s;
171 distance = -distance;
178 distance = fg_v - bg_v;
180 distance = -distance;
186 bg_h = random() % 360;
190 fg_H = ((double) fg_h) / 360;
191 bg_H = ((double) bg_h) / 360;
193 if (dh < 0) dh = -dh;
194 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
195 distance = sqrt ((dh * dh) +
196 ((fg_s - bg_s) * (fg_s - bg_s)) +
197 ((fg_v - bg_v) * (fg_v - bg_v)));
204 free_colors (dpy, cmap, colors, ncolors);
206 colors = (XColor *) malloc (ncolors * sizeof(*colors));
208 cycle_direction = (random() & 1 ? 1 : -1);
213 make_color_ramp (dpy, cmap,
217 True, True, cycle_p);
218 if (n == 0 && cycle_p)
221 goto RETRY_NON_WRITABLE;
232 static Bool done = False;
236 ncolors = sizeof(c)/sizeof(*c);
241 colors[0].pixel = fg_pixel;
242 for (i = 1; i < ncolors; i++)
243 colors[i].pixel = bg_pixel;
247 XSetForeground (dpy, gc, colors[1].pixel);
248 XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
252 #define HEIGHT_TO_PIXEL(height) \
255 ? ncolors - ((-(height)) % ncolors) \
257 : ((height) >= ncolors \
259 ? (height) % ncolors \
270 int rang = 1 << (NSTEPS - size);
271 height = height + (random () % rang) - rang / 2;
272 height = HEIGHT_TO_PIXEL(height);
273 CELL (l, c) = height;
274 return colors[height].pixel;
278 floyd_steinberg (Display *dpy, Window window)
282 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
283 send its bits over all at once. This consumes much less network
284 bandwidth. The image we create is Wx1 intead of WxH, so that we
285 don't use enormous amounts of memory.
288 XCreateImage (dpy, xgwa.visual,
289 1, XYBitmap, 0, /* depth, format, offset */
290 (char *) calloc ((xmax + 8) / 8, 1), /* data */
291 xmax, 1, 8, 0); /* w, h, pad, bpl */
293 XSetForeground (dpy, gc, colors[0].pixel);
294 XSetBackground (dpy, gc, colors[1].pixel);
296 for (y = 0; y < ymax - 1; y++)
298 for (x = 0; x < xmax - 1; x++)
303 XPutPixel (image, x, 0, 1);
307 err = CELL (x, y) - 1;
308 XPutPixel (image, x, 0, 0);
310 /* distribute error */
311 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
312 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
313 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
315 XPutImage (dpy, window, gc, image, 0, 0, 0, y, xmax, 1);
317 XDestroyImage (image);
321 draw (Display *dpy, Window window,
322 int x, int y, unsigned long pixel, int grid_size)
324 static unsigned int last_pixel, last_valid = 0;
325 if (! (last_valid && pixel == last_pixel))
326 XSetForeground (dpy, gc, pixel);
327 last_valid = 1, last_pixel = pixel;
329 XDrawPoint (dpy, window, gc, x, y);
331 XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size);
336 draw_map (Display *dpy, Window window)
338 int xstep, ystep, xnextStep, ynextStep;
339 int x, y, i, x1, x2, y1, y2;
340 unsigned int pixel, qpixels [4];
342 int backwards = random() & 1;
347 cell = (signed char *) calloc (xmax * ymax, 1);
352 xstep = (backwards ? -COUNT : COUNT);
354 for (i = 0; i < iterations; i++)
356 xnextStep = xstep / 2;
357 ynextStep = ystep / 2;
358 for (x = (backwards ? xmax-1 : 0);
359 (backwards ? x >= 0 : x < xmax);
374 for (y = 0; y < ymax; y += ystep)
388 qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
389 qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
390 qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
391 qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
393 pixel = set (x, y1, i,
394 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
396 (pixel != qpixels[0] || pixel != qpixels[1] ||
397 pixel != qpixels[2] || pixel != qpixels[3]))
398 draw (dpy, window, x, y1, pixel, ynextStep);
400 pixel = set (x1, y, i,
401 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
403 (pixel != qpixels[0] || pixel != qpixels[1] ||
404 pixel != qpixels[2] || pixel != qpixels[3]))
405 draw (dpy, window, x1, y, pixel, ynextStep);
407 pixel = set (x1, y1, i,
408 ((int) CELL (x, y) + (int) CELL (x, y2) +
409 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
412 (pixel != qpixels[0] || pixel != qpixels[1] ||
413 pixel != qpixels[2] || pixel != qpixels[3]))
414 draw (dpy, window, x1, y1, pixel, ynextStep);
420 static struct timeval then = { 0, };
422 #ifdef GETTIMEOFDAY_TWO_ARGS
424 gettimeofday(&now, &tzp);
428 diff = (((now.tv_sec - then.tv_sec) * 1000000) +
429 (now.tv_usec - then.tv_usec));
430 if (diff > cycle_delay)
432 rotate_colors (dpy, cmap, colors, ncolors,
445 /* in mono-mode, we do all the drawing at the end */
446 floyd_steinberg (dpy, window);
453 char *progclass = "Imsmap";
455 char *defaults [] = {
456 ".background: black",
457 ".foreground: black",
462 "*cycleDelay: 100000",
467 XrmOptionDescRec options [] = {
468 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
469 { "-delay", ".delay", XrmoptionSepArg, 0 },
470 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
471 { "-mode", ".mode", XrmoptionSepArg, 0 },
472 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
473 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
474 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
480 screenhack (Display *dpy, Window window)
484 init_map (dpy, window);
485 draw_map (dpy, window);
490 time_t start = time((time_t) 0);
491 while (start + delay > time((time_t) 0))
493 rotate_colors (dpy, cmap, colors, ncolors,
495 if (cycle_delay) usleep(cycle_delay);