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 #include "screenhack.h"
15 #include <X11/Xutil.h>
18 #define COUNT (1 << NSTEPS)
19 #define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
21 static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
26 static XWindowAttributes wattrs;
28 #if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */
32 static unsigned long *pixels = 0, fg_pixel, bg_pixel;
33 static int npixels = 0;
35 static int timeout, cycle_delay;
37 static signed char *cell = NULL;
38 static int xmax, ymax;
39 static int iterations;
47 double fg_s, fg_v, bg_s, bg_v;
49 enum mode_t this_mode;
51 static int ncolors = 0;
57 XGetWindowAttributes (dsp, win, &wattrs);
58 cmap = wattrs.colormap;
62 char *mode_str = get_string_resource ("mode", "Mode");
63 rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
64 cycle_p = get_boolean_resource ("cycle", "Cycle");
65 ncolors = get_integer_resource ("ncolors", "Integer");
66 timeout = get_integer_resource ("timeout", "Integer");
67 cycle_delay = get_integer_resource ("cycleDelay", "Integer");
68 iterations = get_integer_resource ("iterations", "Integer");
69 if (iterations < 0) iterations = 0;
70 else if (iterations > 7) iterations = 7;
71 pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int));
72 fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
73 bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
75 if (mono_p && fg_pixel == bg_pixel)
78 if (mono_p) cycle_p = False;
80 gcv.foreground = fg_pixel;
81 gcv.background = bg_pixel;
82 gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv);
83 gcv.foreground = bg_pixel;
84 gc2 = XCreateGC (dsp, win, GCForeground, &gcv);
86 if (!mode_str || !strcmp (mode_str, "random"))
88 else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
90 else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
92 else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
97 "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
103 XFreeColors (dsp, cmap, pixels, npixels, 0);
106 if (!mono_p && mode == MODE_RANDOM)
107 switch (random () % 3) {
108 case 0: this_mode = MODE_H; break;
109 case 1: this_mode = MODE_S; break;
110 case 2: this_mode = MODE_V; break;
116 pixels [0] = fg_pixel;
117 pixels [1] = bg_pixel;
121 XColor fg_color, bg_color;
123 if (fg_pixel == bg_pixel)
126 fg_h = random () % 360;
127 bg_h = random () % 360;
133 if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4)
135 hsv_to_rgb (fg_h, fg_s, fg_v,
136 &fg_color.red, &fg_color.green, &fg_color.blue);
137 hsv_to_rgb (bg_h, bg_s, bg_v,
138 &bg_color.red, &bg_color.green, &bg_color.blue);
142 fg_color.pixel = fg_pixel;
143 if (! XQueryColor (dsp, cmap, &fg_color))
145 bg_color.pixel = bg_pixel;
146 if (! XQueryColor (dsp, cmap, &bg_color))
149 fg_color.flags = DoRed|DoGreen|DoBlue;
150 bg_color.flags = DoRed|DoGreen|DoBlue;
152 rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
153 &fg_h, &fg_s, &fg_v);
154 rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
155 &bg_h, &bg_s, &bg_v);
157 if (/*mode == MODE_RANDOM &&*/
158 ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
159 (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
160 (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
164 case MODE_H: shift = (bg_h - fg_h) / ncolors; break;
165 case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
166 case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
170 if (mode == MODE_RANDOM &&
171 ((this_mode == MODE_H)
172 ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
173 : (dshift > -0.005 && dshift < 0.005)))
176 if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
179 for (npixels = 0; npixels < ncolors; npixels++)
183 unsigned long plane_masks;
184 /* allocate the writable color cells, one at a time. */
185 if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
189 "%s: couldn't allocate %s writable color cells. Turning off -cycle.\n",
190 progname, (npixels ? "enough" : "any"));
194 XStoreColor (dsp, cmap, &fg_color);
199 if (!XAllocColor (dsp, cmap, &fg_color))
202 pixels[npixels] = fg_color.pixel;
206 case MODE_H: fg_h = (fg_h + shift) % 360; break;
207 case MODE_S: fg_s += dshift; break;
208 case MODE_V: fg_v += dshift; break;
211 hsv_to_rgb (fg_h, fg_s, fg_v,
212 &fg_color.red, &fg_color.green, &fg_color.blue);
215 XSetForeground (dsp, gc, pixels [0]);
216 XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
220 #define HEIGHT_TO_PIXEL(height) \
221 (((int) (height)) < 0 ? 0 : \
222 ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
225 set (l, c, size, height)
226 unsigned int l, c, size;
229 int rang = 1 << (NSTEPS - size);
230 height = height + (random () % rang) - rang / 2;
231 CELL (l, c) = height;
233 return pixels [HEIGHT_TO_PIXEL (height)];
241 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
242 send its bits over all at once. This consumes much less network
243 bandwidth. The image we create is Wx1 intead of WxH, so that we
244 don't use enormous amounts of memory.
247 XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
248 1, XYBitmap, 0, /* depth, format, offset */
249 (char *) calloc ((xmax + 1) / 8, 1), /* data */
250 xmax, 1, 8, 0); /* w, h, pad, bpl */
252 for (y = 0; y < ymax - 1; y++)
254 for (x = 0; x < xmax - 1; x++)
259 XPutPixel (image, x, 0, 1);
263 err = CELL (x, y) - 1;
264 XPutPixel (image, x, 0, 0);
266 /* distribute error */
267 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
268 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
269 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
271 XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
273 XDestroyImage (image);
277 draw (x, y, pixel, grid_size) /* not called in mono mode */
281 static unsigned int last_pixel, last_valid = 0;
282 if (! (last_valid && pixel == last_pixel))
283 XSetForeground (disp, gc, pixel);
284 last_valid = 1, last_pixel = pixel;
286 XDrawPoint (disp, wind, gc, x, y);
288 XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
295 unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
296 unsigned int pixel, qpixels [4];
299 ymax = wattrs.height;
301 cell = (signed char *) calloc (xmax * ymax, 1);
307 for (i = 0; i < iterations; i++)
310 for (x = 0; x < xmax; x += step)
318 for (y = 0; y < ymax; y += step)
327 qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
328 qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
329 qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
330 qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
332 pixel = set (x, y1, i,
333 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
335 (pixel != qpixels[0] || pixel != qpixels[1] ||
336 pixel != qpixels[2] || pixel != qpixels[3]))
337 draw (x, y1, pixel, nextStep);
339 pixel = set (x1, y, i,
340 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
342 (pixel != qpixels[0] || pixel != qpixels[1] ||
343 pixel != qpixels[2] || pixel != qpixels[3]))
344 draw (x1, y, pixel, nextStep);
346 pixel = set (x1, y1, i,
347 ((int) CELL (x, y) + (int) CELL (x, y2) +
348 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
351 (pixel != qpixels[0] || pixel != qpixels[1] ||
352 pixel != qpixels[2] || pixel != qpixels[3]))
353 draw (x1, y1, pixel, nextStep);
361 /* in mono-mode, we do all the drawing at the end */
372 XColor *colors = (XColor *) malloc (npixels * sizeof (XColor));
375 for (i = 0; i < npixels; i++)
376 colors [i].pixel = pixels [i];
377 XQueryColors (dpy, cmap, colors, npixels);
378 stop = (time_t) ((time ((time_t) 0)) + timeout);
379 while (stop >= (time_t) time ((time_t) 0))
381 unsigned long scratch = colors [npixels-1].pixel;
382 for (i = npixels-1; i > 0; i--)
383 colors [i].pixel = colors [i-1].pixel;
384 colors [0].pixel = scratch;
385 XStoreColors (dpy, cmap, colors, npixels);
387 if (cycle_delay) usleep (cycle_delay);
394 char *progclass = "Imsmap";
396 char *defaults [] = {
397 "*background: black",
398 "*foreground: black",
403 "*cycleDelay: 100000",
408 XrmOptionDescRec options [] = {
409 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
410 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
411 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
412 { "-mode", ".mode", XrmoptionSepArg, 0 },
413 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
414 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
415 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" }
417 int options_size = (sizeof (options) / sizeof (options[0]));
421 screenhack (dpy, window)
429 initwin (dpy, window);