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.
20 #include <sys/time.h> /* for gettimeofday() */
23 #include <X11/Xutil.h>
25 #include "screenhack.h"
28 #define COUNT (1 << NSTEPS)
29 #define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
31 static enum imsmap_mode { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
34 static XWindowAttributes xgwa;
36 #if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */
42 static XColor *colors;
44 static int cycle_direction;
45 static Bool extra_krinkly_p;
47 static int delay, cycle_delay;
48 static signed char *cell = NULL;
49 static int xmax, ymax;
50 static int iterations;
53 init_map (Display *dpy, Window window)
55 unsigned long fg_pixel = 0, bg_pixel = 0;
57 double fg_s, fg_v, bg_s, bg_v;
59 enum imsmap_mode this_mode;
64 XGetWindowAttributes (dpy, window, &xgwa);
69 char *mode_str = get_string_resource ("mode", "Mode");
70 rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
71 cycle_p = get_boolean_resource ("cycle", "Cycle");
72 ncolors = get_integer_resource ("ncolors", "Integer");
73 delay = get_integer_resource ("delay", "Integer");
74 cycle_delay = get_integer_resource ("cycleDelay", "Integer");
75 iterations = get_integer_resource ("iterations", "Integer");
76 if (iterations < 0) iterations = 0;
77 else if (iterations > 7) iterations = 7;
79 if (ncolors <= 2) ncolors = 0;
80 if (ncolors == 0) mono_p = True;
81 if (ncolors > 255) ncolors = 255; /* too many look bad */
83 fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
84 bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
86 if (fg_pixel == bg_pixel)
89 black.red = black.green = black.blue = 0;
90 white.red = white.green = white.blue = 0xFFFF;
91 black.flags = white.flags = DoRed|DoGreen|DoBlue;
92 XAllocColor(dpy, cmap, &black);
93 XAllocColor(dpy, cmap, &white);
94 if (bg_pixel == black.pixel)
95 fg_pixel = white.pixel;
97 fg_pixel = black.pixel;
100 if (mono_p) cycle_p = False;
102 gcv.foreground = fg_pixel;
103 gcv.background = bg_pixel;
104 gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
105 gcv.foreground = bg_pixel;
106 gc2 = XCreateGC (dpy, window, GCForeground, &gcv);
108 if (!mode_str || !strcmp (mode_str, "random"))
110 else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
112 else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
114 else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
119 "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
126 if (!mono_p && mode == MODE_RANDOM)
127 switch (random () % 6) {
128 case 0: this_mode = MODE_H; break;
129 case 1: this_mode = MODE_S; break;
130 case 2: this_mode = MODE_V; break;
135 extra_krinkly_p = !(random() % 15);
137 extra_krinkly_p = !(random() % 5);
141 double distance, fg_H, bg_H, dh;
144 fg_h = random() % 360;
155 bg_h = random() % 360;
158 distance = fg_h - bg_h;
160 distance = -distance;
162 distance = 180 - (distance - 180);
171 distance = fg_s - bg_s;
173 distance = -distance;
180 distance = fg_v - bg_v;
182 distance = -distance;
188 bg_h = random() % 360;
192 fg_H = ((double) fg_h) / 360;
193 bg_H = ((double) bg_h) / 360;
195 if (dh < 0) dh = -dh;
196 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
197 distance = sqrt ((dh * dh) +
198 ((fg_s - bg_s) * (fg_s - bg_s)) +
199 ((fg_v - bg_v) * (fg_v - bg_v)));
206 free_colors (dpy, cmap, colors, ncolors);
208 colors = (XColor *) malloc (ncolors * sizeof(*colors));
210 cycle_direction = (random() & 1 ? 1 : -1);
215 make_color_ramp (dpy, cmap,
219 True, True, cycle_p);
220 if (n == 0 && cycle_p)
223 goto RETRY_NON_WRITABLE;
234 static Bool done = False;
238 ncolors = sizeof(c)/sizeof(*c);
243 colors[0].pixel = fg_pixel;
244 for (i = 1; i < ncolors; i++)
245 colors[i].pixel = bg_pixel;
249 XSetForeground (dpy, gc, colors[1].pixel);
250 XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
254 #define HEIGHT_TO_PIXEL(height) \
257 ? ncolors - ((-(height)) % ncolors) \
259 : ((height) >= ncolors \
261 ? (height) % ncolors \
272 int rang = 1 << (NSTEPS - size);
273 height = height + (random () % rang) - rang / 2;
274 height = HEIGHT_TO_PIXEL(height);
275 CELL (l, c) = height;
276 return colors[height].pixel;
280 floyd_steinberg (Display *dpy, Window window)
284 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
285 send its bits over all at once. This consumes much less network
286 bandwidth. The image we create is Wx1 intead of WxH, so that we
287 don't use enormous amounts of memory.
290 XCreateImage (dpy, xgwa.visual,
291 1, XYBitmap, 0, /* depth, format, offset */
292 (char *) calloc ((xmax + 8) / 8, 1), /* data */
293 xmax, 1, 8, 0); /* w, h, pad, bpl */
295 XSetForeground (dpy, gc, colors[0].pixel);
296 XSetBackground (dpy, gc, colors[1].pixel);
298 for (y = 0; y < ymax - 1; y++)
300 for (x = 0; x < xmax - 1; x++)
305 XPutPixel (image, x, 0, 1);
309 err = CELL (x, y) - 1;
310 XPutPixel (image, x, 0, 0);
312 /* distribute error */
313 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
314 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
315 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
317 XPutImage (dpy, window, gc, image, 0, 0, 0, y, xmax, 1);
319 XDestroyImage (image);
323 draw (Display *dpy, Window window,
324 int x, int y, unsigned long pixel, int grid_size)
326 static unsigned int last_pixel, last_valid = 0;
327 if (! (last_valid && pixel == last_pixel))
328 XSetForeground (dpy, gc, pixel);
329 last_valid = 1, last_pixel = pixel;
331 XDrawPoint (dpy, window, gc, x, y);
333 XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size);
338 draw_map (Display *dpy, Window window)
340 int xstep, ystep, xnextStep, ynextStep;
341 int x, y, i, x1, x2, y1, y2;
342 unsigned int pixel, qpixels [4];
344 int backwards = random() & 1;
349 cell = (signed char *) calloc (xmax * ymax, 1);
354 xstep = (backwards ? -COUNT : COUNT);
356 for (i = 0; i < iterations; i++)
358 xnextStep = xstep / 2;
359 ynextStep = ystep / 2;
360 for (x = (backwards ? xmax-1 : 0);
361 (backwards ? x >= 0 : x < xmax);
376 for (y = 0; y < ymax; y += ystep)
390 qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
391 qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
392 qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
393 qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
395 pixel = set (x, y1, i,
396 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
398 (pixel != qpixels[0] || pixel != qpixels[1] ||
399 pixel != qpixels[2] || pixel != qpixels[3]))
400 draw (dpy, window, x, y1, pixel, ynextStep);
402 pixel = set (x1, y, i,
403 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
405 (pixel != qpixels[0] || pixel != qpixels[1] ||
406 pixel != qpixels[2] || pixel != qpixels[3]))
407 draw (dpy, window, x1, y, pixel, ynextStep);
409 pixel = set (x1, y1, i,
410 ((int) CELL (x, y) + (int) CELL (x, y2) +
411 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
414 (pixel != qpixels[0] || pixel != qpixels[1] ||
415 pixel != qpixels[2] || pixel != qpixels[3]))
416 draw (dpy, window, x1, y1, pixel, ynextStep);
422 static struct timeval then = { 0, 0 };
424 #ifdef GETTIMEOFDAY_TWO_ARGS
426 gettimeofday(&now, &tzp);
430 diff = (((now.tv_sec - then.tv_sec) * 1000000) +
431 (now.tv_usec - then.tv_usec));
432 if (diff > cycle_delay)
434 rotate_colors (dpy, cmap, colors, ncolors,
445 screenhack_handle_events (dpy);
448 /* in mono-mode, we do all the drawing at the end */
449 floyd_steinberg (dpy, window);
456 char *progclass = "Imsmap";
458 char *defaults [] = {
459 ".background: black",
460 ".foreground: black",
465 "*cycleDelay: 100000",
470 XrmOptionDescRec options [] = {
471 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
472 { "-delay", ".delay", XrmoptionSepArg, 0 },
473 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
474 { "-mode", ".mode", XrmoptionSepArg, 0 },
475 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
476 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
477 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
483 screenhack (Display *dpy, Window window)
487 init_map (dpy, window);
488 draw_map (dpy, window);
493 time_t start = time((time_t) 0);
494 while (start + delay > time((time_t) 0))
496 rotate_colors (dpy, cmap, colors, ncolors,
498 if (cycle_delay) usleep(cycle_delay);
499 screenhack_handle_events (dpy);
504 screenhack_handle_events (dpy);