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 imsmap_mode { 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 imsmap_mode 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;
80 if (ncolors > 255) ncolors = 255; /* too many look bad */
82 fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
83 bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
85 if (fg_pixel == bg_pixel)
88 black.red = black.green = black.blue = 0;
89 white.red = white.green = white.blue = 0xFFFF;
90 black.flags = white.flags = DoRed|DoGreen|DoBlue;
91 XAllocColor(dpy, cmap, &black);
92 XAllocColor(dpy, cmap, &white);
93 if (bg_pixel == black.pixel)
94 fg_pixel = white.pixel;
96 fg_pixel = black.pixel;
99 if (mono_p) cycle_p = False;
101 gcv.foreground = fg_pixel;
102 gcv.background = bg_pixel;
103 gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
104 gcv.foreground = bg_pixel;
105 gc2 = XCreateGC (dpy, window, GCForeground, &gcv);
107 if (!mode_str || !strcmp (mode_str, "random"))
109 else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
111 else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
113 else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
118 "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
125 if (!mono_p && mode == MODE_RANDOM)
126 switch (random () % 6) {
127 case 0: this_mode = MODE_H; break;
128 case 1: this_mode = MODE_S; break;
129 case 2: this_mode = MODE_V; break;
134 extra_krinkly_p = !(random() % 15);
136 extra_krinkly_p = !(random() % 5);
140 double distance, fg_H, bg_H, dh;
143 fg_h = random() % 360;
154 bg_h = random() % 360;
157 distance = fg_h - bg_h;
159 distance = -distance;
161 distance = 180 - (distance - 180);
170 distance = fg_s - bg_s;
172 distance = -distance;
179 distance = fg_v - bg_v;
181 distance = -distance;
187 bg_h = random() % 360;
191 fg_H = ((double) fg_h) / 360;
192 bg_H = ((double) bg_h) / 360;
194 if (dh < 0) dh = -dh;
195 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
196 distance = sqrt ((dh * dh) +
197 ((fg_s - bg_s) * (fg_s - bg_s)) +
198 ((fg_v - bg_v) * (fg_v - bg_v)));
205 free_colors (dpy, cmap, colors, ncolors);
207 colors = (XColor *) malloc (ncolors * sizeof(*colors));
209 cycle_direction = (random() & 1 ? 1 : -1);
214 make_color_ramp (dpy, cmap,
218 True, True, cycle_p);
219 if (n == 0 && cycle_p)
222 goto RETRY_NON_WRITABLE;
233 static Bool done = False;
237 ncolors = sizeof(c)/sizeof(*c);
242 colors[0].pixel = fg_pixel;
243 for (i = 1; i < ncolors; i++)
244 colors[i].pixel = bg_pixel;
248 XSetForeground (dpy, gc, colors[1].pixel);
249 XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
253 #define HEIGHT_TO_PIXEL(height) \
256 ? ncolors - ((-(height)) % ncolors) \
258 : ((height) >= ncolors \
260 ? (height) % ncolors \
271 int rang = 1 << (NSTEPS - size);
272 height = height + (random () % rang) - rang / 2;
273 height = HEIGHT_TO_PIXEL(height);
274 CELL (l, c) = height;
275 return colors[height].pixel;
279 floyd_steinberg (Display *dpy, Window window)
283 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
284 send its bits over all at once. This consumes much less network
285 bandwidth. The image we create is Wx1 intead of WxH, so that we
286 don't use enormous amounts of memory.
289 XCreateImage (dpy, xgwa.visual,
290 1, XYBitmap, 0, /* depth, format, offset */
291 (char *) calloc ((xmax + 8) / 8, 1), /* data */
292 xmax, 1, 8, 0); /* w, h, pad, bpl */
294 XSetForeground (dpy, gc, colors[0].pixel);
295 XSetBackground (dpy, gc, colors[1].pixel);
297 for (y = 0; y < ymax - 1; y++)
299 for (x = 0; x < xmax - 1; x++)
304 XPutPixel (image, x, 0, 1);
308 err = CELL (x, y) - 1;
309 XPutPixel (image, x, 0, 0);
311 /* distribute error */
312 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
313 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
314 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
316 XPutImage (dpy, window, gc, image, 0, 0, 0, y, xmax, 1);
318 XDestroyImage (image);
322 draw (Display *dpy, Window window,
323 int x, int y, unsigned long pixel, int grid_size)
325 static unsigned int last_pixel, last_valid = 0;
326 if (! (last_valid && pixel == last_pixel))
327 XSetForeground (dpy, gc, pixel);
328 last_valid = 1, last_pixel = pixel;
330 XDrawPoint (dpy, window, gc, x, y);
332 XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size);
337 draw_map (Display *dpy, Window window)
339 int xstep, ystep, xnextStep, ynextStep;
340 int x, y, i, x1, x2, y1, y2;
341 unsigned int pixel, qpixels [4];
343 int backwards = random() & 1;
348 cell = (signed char *) calloc (xmax * ymax, 1);
353 xstep = (backwards ? -COUNT : COUNT);
355 for (i = 0; i < iterations; i++)
357 xnextStep = xstep / 2;
358 ynextStep = ystep / 2;
359 for (x = (backwards ? xmax-1 : 0);
360 (backwards ? x >= 0 : x < xmax);
375 for (y = 0; y < ymax; y += ystep)
389 qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
390 qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
391 qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
392 qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
394 pixel = set (x, y1, i,
395 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
397 (pixel != qpixels[0] || pixel != qpixels[1] ||
398 pixel != qpixels[2] || pixel != qpixels[3]))
399 draw (dpy, window, x, y1, pixel, ynextStep);
401 pixel = set (x1, y, i,
402 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
404 (pixel != qpixels[0] || pixel != qpixels[1] ||
405 pixel != qpixels[2] || pixel != qpixels[3]))
406 draw (dpy, window, x1, y, pixel, ynextStep);
408 pixel = set (x1, y1, i,
409 ((int) CELL (x, y) + (int) CELL (x, y2) +
410 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
413 (pixel != qpixels[0] || pixel != qpixels[1] ||
414 pixel != qpixels[2] || pixel != qpixels[3]))
415 draw (dpy, window, x1, y1, pixel, ynextStep);
421 static struct timeval then = { 0, };
423 #ifdef GETTIMEOFDAY_TWO_ARGS
425 gettimeofday(&now, &tzp);
429 diff = (((now.tv_sec - then.tv_sec) * 1000000) +
430 (now.tv_usec - then.tv_usec));
431 if (diff > cycle_delay)
433 rotate_colors (dpy, cmap, colors, ncolors,
444 screenhack_handle_events (dpy);
447 /* in mono-mode, we do all the drawing at the end */
448 floyd_steinberg (dpy, window);
455 char *progclass = "Imsmap";
457 char *defaults [] = {
458 ".background: black",
459 ".foreground: black",
464 "*cycleDelay: 100000",
469 XrmOptionDescRec options [] = {
470 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
471 { "-delay", ".delay", XrmoptionSepArg, 0 },
472 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
473 { "-mode", ".mode", XrmoptionSepArg, 0 },
474 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
475 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
476 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
482 screenhack (Display *dpy, Window window)
486 init_map (dpy, window);
487 draw_map (dpy, window);
492 time_t start = time((time_t) 0);
493 while (start + delay > time((time_t) 0))
495 rotate_colors (dpy, cmap, colors, ncolors,
497 if (cycle_delay) usleep(cycle_delay);
498 screenhack_handle_events (dpy);
503 screenhack_handle_events (dpy);