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 XQueryColor (dsp, cmap, &fg_color);
143 XQueryColor (dsp, cmap, &bg_color);
144 fg_color.pixel = fg_pixel;
145 bg_color.pixel = bg_pixel;
147 fg_color.flags = DoRed|DoGreen|DoBlue;
148 bg_color.flags = DoRed|DoGreen|DoBlue;
150 rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
151 &fg_h, &fg_s, &fg_v);
152 rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
153 &bg_h, &bg_s, &bg_v);
155 if (/*mode == MODE_RANDOM &&*/
156 ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
157 (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
158 (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
162 case MODE_H: shift = (bg_h - fg_h) / ncolors; break;
163 case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
164 case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
168 if (mode == MODE_RANDOM &&
169 ((this_mode == MODE_H)
170 ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
171 : (dshift > -0.005 && dshift < 0.005)))
174 if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
177 for (npixels = 0; npixels < ncolors; npixels++)
181 unsigned long plane_masks;
182 /* allocate the writable color cells, one at a time. */
183 if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
187 "%s: couldn't allocate %s writable color cells. Turning off -cycle.\n",
188 progname, (npixels ? "enough" : "any"));
192 XStoreColor (dsp, cmap, &fg_color);
197 if (!XAllocColor (dsp, cmap, &fg_color))
200 pixels[npixels] = fg_color.pixel;
204 case MODE_H: fg_h = (fg_h + shift) % 360; break;
205 case MODE_S: fg_s += dshift; break;
206 case MODE_V: fg_v += dshift; break;
209 hsv_to_rgb (fg_h, fg_s, fg_v,
210 &fg_color.red, &fg_color.green, &fg_color.blue);
213 XSetForeground (dsp, gc, pixels [0]);
214 XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
218 #define HEIGHT_TO_PIXEL(height) \
219 (((int) (height)) < 0 ? 0 : \
220 ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
223 set (l, c, size, height)
224 unsigned int l, c, size;
227 int rang = 1 << (NSTEPS - size);
228 height = height + (random () % rang) - rang / 2;
229 CELL (l, c) = height;
231 return pixels [HEIGHT_TO_PIXEL (height)];
239 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
240 send its bits over all at once. This consumes much less network
241 bandwidth. The image we create is Wx1 intead of WxH, so that we
242 don't use enormous amounts of memory.
245 XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
246 1, XYBitmap, 0, /* depth, format, offset */
247 (char *) calloc ((xmax + 1) / 8, 1), /* data */
248 xmax, 1, 8, 0); /* w, h, pad, bpl */
250 for (y = 0; y < ymax - 1; y++)
252 for (x = 0; x < xmax - 1; x++)
257 XPutPixel (image, x, 0, 1);
261 err = CELL (x, y) - 1;
262 XPutPixel (image, x, 0, 0);
264 /* distribute error */
265 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
266 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
267 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
269 XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
271 XDestroyImage (image);
275 draw (x, y, pixel, grid_size) /* not called in mono mode */
279 static unsigned int last_pixel, last_valid = 0;
280 if (! (last_valid && pixel == last_pixel))
281 XSetForeground (disp, gc, pixel);
282 last_valid = 1, last_pixel = pixel;
284 XDrawPoint (disp, wind, gc, x, y);
286 XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
293 unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
294 unsigned int pixel, qpixels [4];
297 ymax = wattrs.height;
299 cell = (signed char *) calloc (xmax * ymax, 1);
305 for (i = 0; i < iterations; i++)
308 for (x = 0; x < xmax; x += step)
316 for (y = 0; y < ymax; y += step)
325 qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
326 qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
327 qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
328 qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
330 pixel = set (x, y1, i,
331 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
333 (pixel != qpixels[0] || pixel != qpixels[1] ||
334 pixel != qpixels[2] || pixel != qpixels[3]))
335 draw (x, y1, pixel, nextStep);
337 pixel = set (x1, y, i,
338 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
340 (pixel != qpixels[0] || pixel != qpixels[1] ||
341 pixel != qpixels[2] || pixel != qpixels[3]))
342 draw (x1, y, pixel, nextStep);
344 pixel = set (x1, y1, i,
345 ((int) CELL (x, y) + (int) CELL (x, y2) +
346 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
349 (pixel != qpixels[0] || pixel != qpixels[1] ||
350 pixel != qpixels[2] || pixel != qpixels[3]))
351 draw (x1, y1, pixel, nextStep);
359 /* in mono-mode, we do all the drawing at the end */
370 XColor *colors = (XColor *) malloc (npixels * sizeof (XColor));
373 for (i = 0; i < npixels; i++)
374 colors [i].pixel = pixels [i];
375 XQueryColors (dpy, cmap, colors, npixels);
376 stop = (time_t) ((time ((time_t) 0)) + timeout);
377 while (stop >= (time_t) time ((time_t) 0))
379 unsigned long scratch = colors [npixels-1].pixel;
380 for (i = npixels-1; i > 0; i--)
381 colors [i].pixel = colors [i-1].pixel;
382 colors [0].pixel = scratch;
383 XStoreColors (dpy, cmap, colors, npixels);
385 if (cycle_delay) usleep (cycle_delay);
392 char *progclass = "Imsmap";
394 char *defaults [] = {
395 "Imsmap.background: black", /* to placate SGI */
396 "Imsmap.foreground: black",
401 "*cycleDelay: 100000",
406 XrmOptionDescRec options [] = {
407 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
408 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
409 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
410 { "-mode", ".mode", XrmoptionSepArg, 0 },
411 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
412 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
413 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" }
415 int options_size = (sizeof (options) / sizeof (options[0]));
419 screenhack (dpy, window)
427 initwin (dpy, window);