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" */
34 #define signed /**/ /* for VAX C */
37 static unsigned long *pixels = 0, fg_pixel, bg_pixel;
38 static int npixels = 0;
40 static int timeout, cycle_delay;
42 static signed char *cell = NULL;
43 static int xmax, ymax;
44 static int iterations;
52 double fg_s, fg_v, bg_s, bg_v;
54 enum mode_t this_mode;
56 static int ncolors = 0;
62 XGetWindowAttributes (dsp, win, &wattrs);
63 cmap = wattrs.colormap;
67 char *mode_str = get_string_resource ("mode", "Mode");
68 rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
69 cycle_p = get_boolean_resource ("cycle", "Cycle");
70 ncolors = get_integer_resource ("ncolors", "Integer");
71 timeout = get_integer_resource ("timeout", "Integer");
72 cycle_delay = get_integer_resource ("cycleDelay", "Integer");
73 iterations = get_integer_resource ("iterations", "Integer");
74 if (iterations < 0) iterations = 0;
75 else if (iterations > 7) iterations = 7;
76 pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int));
77 fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
78 bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
80 if (mono_p && fg_pixel == bg_pixel)
83 if (mono_p) cycle_p = False;
85 gcv.foreground = fg_pixel;
86 gcv.background = bg_pixel;
87 gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv);
88 gcv.foreground = bg_pixel;
89 gc2 = XCreateGC (dsp, win, GCForeground, &gcv);
91 if (!mode_str || !strcmp (mode_str, "random"))
93 else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
95 else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
97 else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
102 "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
108 XFreeColors (dsp, cmap, pixels, npixels, 0);
111 if (!mono_p && mode == MODE_RANDOM)
112 switch (random () % 3) {
113 case 0: this_mode = MODE_H; break;
114 case 1: this_mode = MODE_S; break;
115 case 2: this_mode = MODE_V; break;
121 pixels [0] = fg_pixel;
122 pixels [1] = bg_pixel;
126 XColor fg_color, bg_color;
128 if (fg_pixel == bg_pixel)
131 fg_h = random () % 360;
132 bg_h = random () % 360;
138 if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4)
140 hsv_to_rgb (fg_h, fg_s, fg_v,
141 &fg_color.red, &fg_color.green, &fg_color.blue);
142 hsv_to_rgb (bg_h, bg_s, bg_v,
143 &bg_color.red, &bg_color.green, &bg_color.blue);
147 XQueryColor (dsp, cmap, &fg_color);
148 XQueryColor (dsp, cmap, &bg_color);
149 fg_color.pixel = fg_pixel;
150 bg_color.pixel = bg_pixel;
152 fg_color.flags = DoRed|DoGreen|DoBlue;
153 bg_color.flags = DoRed|DoGreen|DoBlue;
155 rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
156 &fg_h, &fg_s, &fg_v);
157 rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
158 &bg_h, &bg_s, &bg_v);
160 if (/*mode == MODE_RANDOM &&*/
161 ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
162 (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
163 (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
167 case MODE_H: shift = (bg_h - fg_h) / ncolors; break;
168 case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
169 case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
173 if (mode == MODE_RANDOM &&
174 ((this_mode == MODE_H)
175 ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
176 : (dshift > -0.005 && dshift < 0.005)))
179 if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
182 for (npixels = 0; npixels < ncolors; npixels++)
186 unsigned long plane_masks;
187 /* allocate the writable color cells, one at a time. */
188 if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
192 "%s: couldn't allocate %s writable color cells. Turning off -cycle.\n",
193 progname, (npixels ? "enough" : "any"));
197 XStoreColor (dsp, cmap, &fg_color);
202 if (!XAllocColor (dsp, cmap, &fg_color))
205 pixels[npixels] = fg_color.pixel;
209 case MODE_H: fg_h = (fg_h + shift) % 360; break;
210 case MODE_S: fg_s += dshift; break;
211 case MODE_V: fg_v += dshift; break;
214 hsv_to_rgb (fg_h, fg_s, fg_v,
215 &fg_color.red, &fg_color.green, &fg_color.blue);
218 XSetForeground (dsp, gc, pixels [0]);
219 XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
223 #define HEIGHT_TO_PIXEL(height) \
224 (((int) (height)) < 0 ? 0 : \
225 ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
228 set (l, c, size, height)
229 unsigned int l, c, size;
232 int rang = 1 << (NSTEPS - size);
233 height = height + (random () % rang) - rang / 2;
234 CELL (l, c) = height;
236 return pixels [HEIGHT_TO_PIXEL (height)];
244 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
245 send its bits over all at once. This consumes much less network
246 bandwidth. The image we create is Wx1 intead of WxH, so that we
247 don't use enormous amounts of memory.
250 XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
251 1, XYBitmap, 0, /* depth, format, offset */
252 (char *) calloc ((xmax + 1) / 8, 1), /* data */
253 xmax, 1, 8, 0); /* w, h, pad, bpl */
255 for (y = 0; y < ymax - 1; y++)
257 for (x = 0; x < xmax - 1; x++)
262 XPutPixel (image, x, 0, 1);
266 err = CELL (x, y) - 1;
267 XPutPixel (image, x, 0, 0);
269 /* distribute error */
270 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
271 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
272 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
274 XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
276 XDestroyImage (image);
280 draw (x, y, pixel, grid_size) /* not called in mono mode */
284 static unsigned int last_pixel, last_valid = 0;
285 if (! (last_valid && pixel == last_pixel))
286 XSetForeground (disp, gc, pixel);
287 last_valid = 1, last_pixel = pixel;
289 XDrawPoint (disp, wind, gc, x, y);
291 XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
298 unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
299 unsigned int pixel, qpixels [4];
302 ymax = wattrs.height;
304 cell = (signed char *) calloc (xmax * ymax, 1);
310 for (i = 0; i < iterations; i++)
313 for (x = 0; x < xmax; x += step)
321 for (y = 0; y < ymax; y += step)
330 qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
331 qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
332 qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
333 qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
335 pixel = set (x, y1, i,
336 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
338 (pixel != qpixels[0] || pixel != qpixels[1] ||
339 pixel != qpixels[2] || pixel != qpixels[3]))
340 draw (x, y1, pixel, nextStep);
342 pixel = set (x1, y, i,
343 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
345 (pixel != qpixels[0] || pixel != qpixels[1] ||
346 pixel != qpixels[2] || pixel != qpixels[3]))
347 draw (x1, y, pixel, nextStep);
349 pixel = set (x1, y1, i,
350 ((int) CELL (x, y) + (int) CELL (x, y2) +
351 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
354 (pixel != qpixels[0] || pixel != qpixels[1] ||
355 pixel != qpixels[2] || pixel != qpixels[3]))
356 draw (x1, y1, pixel, nextStep);
364 /* in mono-mode, we do all the drawing at the end */
375 XColor *colors = (XColor *) malloc (npixels * sizeof (XColor));
378 for (i = 0; i < npixels; i++)
379 colors [i].pixel = pixels [i];
380 XQueryColors (dpy, cmap, colors, npixels);
381 stop = (time_t) ((time ((time_t) 0)) + timeout);
382 while (stop >= (time_t) time ((time_t) 0))
384 unsigned long scratch = colors [npixels-1].pixel;
385 for (i = npixels-1; i > 0; i--)
386 colors [i].pixel = colors [i-1].pixel;
387 colors [0].pixel = scratch;
388 XStoreColors (dpy, cmap, colors, npixels);
390 if (cycle_delay) usleep (cycle_delay);
397 char *progclass = "Imsmap";
399 char *defaults [] = {
400 "Imsmap.background: black", /* to placate SGI */
401 "Imsmap.foreground: black",
406 "*cycleDelay: 100000",
411 XrmOptionDescRec options [] = {
412 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
413 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
414 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
415 { "-mode", ".mode", XrmoptionSepArg, 0 },
416 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
417 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
418 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" }
420 int options_size = (sizeof (options) / sizeof (options[0]));
424 screenhack (dpy, window)
432 initwin (dpy, window);