* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
+ *
+ * Revision History:
+ * 24-aug-92: jwz: hacked.
+ * 17-May-97: jwz: hacked more.
*/
-#include "screenhack.h"
#include <stdio.h>
+#include <math.h>
+#include <sys/time.h> /* for gettimeofday() */
+
+#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include "screenhack.h"
+
#define NSTEPS 7
#define COUNT (1 << NSTEPS)
#define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
static GC gc, gc2;
-static Display *disp;
-static Window wind;
-static XWindowAttributes wattrs;
+static XWindowAttributes xgwa;
#if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */
#define signed /**/
#endif
-static unsigned long *pixels = 0, fg_pixel, bg_pixel;
-static int npixels = 0;
static Colormap cmap;
-static int timeout, cycle_delay;
-static int cycle_p;
+static int ncolors;
+static XColor *colors;
+static Bool cycle_p;
+static int cycle_direction;
+static Bool extra_krinkly_p;
+
+static int delay, cycle_delay;
static signed char *cell = NULL;
static int xmax, ymax;
static int iterations;
static void
-initwin (dsp, win)
- Display *dsp;
- Window win;
+init_map (Display *dpy, Window window)
{
+ unsigned long fg_pixel = 0, bg_pixel = 0;
int fg_h, bg_h;
double fg_s, fg_v, bg_s, bg_v;
enum mode_t this_mode;
static Bool rv_p;
- static int ncolors = 0;
- int shift;
- double dshift;
XGCValues gcv;
- XGetWindowAttributes (dsp, win, &wattrs);
- cmap = wattrs.colormap;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ cmap = xgwa.colormap;
if (!ncolors)
{
rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
cycle_p = get_boolean_resource ("cycle", "Cycle");
ncolors = get_integer_resource ("ncolors", "Integer");
- timeout = get_integer_resource ("timeout", "Integer");
+ delay = get_integer_resource ("delay", "Integer");
cycle_delay = get_integer_resource ("cycleDelay", "Integer");
iterations = get_integer_resource ("iterations", "Integer");
if (iterations < 0) iterations = 0;
else if (iterations > 7) iterations = 7;
- pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int));
- fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
- bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
- if (mono_p && fg_pixel == bg_pixel)
- bg_pixel = !bg_pixel;
+ if (ncolors <= 2) ncolors = 0;
+ if (ncolors == 0) mono_p = True;
+
+ fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
+ bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+
+ if (fg_pixel == bg_pixel)
+ {
+ XColor black, white;
+ black.red = black.green = black.blue = 0;
+ white.red = white.green = white.blue = 0xFFFF;
+ black.flags = white.flags = DoRed|DoGreen|DoBlue;
+ XAllocColor(dpy, cmap, &black);
+ XAllocColor(dpy, cmap, &white);
+ if (bg_pixel == black.pixel)
+ fg_pixel = white.pixel;
+ else
+ fg_pixel = black.pixel;
+ }
if (mono_p) cycle_p = False;
gcv.foreground = fg_pixel;
gcv.background = bg_pixel;
- gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv);
+ gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
gcv.foreground = bg_pixel;
- gc2 = XCreateGC (dsp, win, GCForeground, &gcv);
+ gc2 = XCreateGC (dpy, window, GCForeground, &gcv);
if (!mode_str || !strcmp (mode_str, "random"))
mode = MODE_RANDOM;
mode = MODE_RANDOM;
}
}
- else if (! mono_p)
- XFreeColors (dsp, cmap, pixels, npixels, 0);
this_mode = mode;
if (!mono_p && mode == MODE_RANDOM)
- switch (random () % 3) {
+ switch (random () % 6) {
case 0: this_mode = MODE_H; break;
case 1: this_mode = MODE_S; break;
case 2: this_mode = MODE_V; break;
+ default: break;
}
if (mono_p)
- {
- npixels = ncolors;
- pixels [0] = fg_pixel;
- pixels [1] = bg_pixel;
- }
+ extra_krinkly_p = !(random() % 15);
else
+ extra_krinkly_p = !(random() % 5);
+
+ if (!mono_p)
{
- XColor fg_color, bg_color;
+ double distance, fg_H, bg_H, dh;
- if (fg_pixel == bg_pixel)
+ RETRY:
+ fg_h = random() % 360;
+ fg_s = frand(1.0);
+ fg_v = frand(1.0);
+
+ bg_h = fg_h;
+ bg_s = fg_s;
+ bg_v = fg_v;
+
+ switch (this_mode)
{
- HSV_AGAIN:
- fg_h = random () % 360;
- bg_h = random () % 360;
- fg_s = frand (1.0);
- bg_s = frand (1.0);
- V_AGAIN:
- fg_v = frand (1.0);
- bg_v = frand (1.0);
- if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4)
- goto V_AGAIN;
- hsv_to_rgb (fg_h, fg_s, fg_v,
- &fg_color.red, &fg_color.green, &fg_color.blue);
- hsv_to_rgb (bg_h, bg_s, bg_v,
- &bg_color.red, &bg_color.green, &bg_color.blue);
+ case MODE_H:
+ bg_h = random() % 360;
+ if (fg_v < 0.4)
+ goto RETRY;
+ distance = fg_h - bg_h;
+ if (distance < 0)
+ distance = -distance;
+ if (distance > 360)
+ distance = 180 - (distance - 180);
+ if (distance < 30)
+ goto RETRY;
+ break;
+
+ case MODE_S:
+ bg_s = frand(1.0);
+ if (fg_v < 0.4)
+ goto RETRY;
+ distance = fg_s - bg_s;
+ if (distance < 0)
+ distance = -distance;
+ if (distance < 0.2)
+ goto RETRY;
+ break;
+
+ case MODE_V:
+ bg_v = frand(1.0);
+ distance = fg_v - bg_v;
+ if (distance < 0)
+ distance = -distance;
+ if (distance < 0.4)
+ goto RETRY;
+ break;
+
+ default:
+ bg_h = random() % 360;
+ bg_s = frand(1.0);
+ bg_v = frand(1.0);
+
+ fg_H = ((double) fg_h) / 360;
+ bg_H = ((double) bg_h) / 360;
+ dh = fg_H - bg_H;
+ if (dh < 0) dh = -dh;
+ if (dh > 0.5) dh = 0.5 - (dh - 0.5);
+ distance = sqrt ((dh * dh) +
+ ((fg_s - bg_s) * (fg_s - bg_s)) +
+ ((fg_v - bg_v) * (fg_v - bg_v)));
+ if (distance < 0.2)
+ goto RETRY;
}
+
+ cycle_p = True;
+ if (colors)
+ free_colors (dpy, cmap, colors, ncolors);
else
- {
- XQueryColor (dsp, cmap, &fg_color);
- XQueryColor (dsp, cmap, &bg_color);
- fg_color.pixel = fg_pixel;
- bg_color.pixel = bg_pixel;
- }
- fg_color.flags = DoRed|DoGreen|DoBlue;
- bg_color.flags = DoRed|DoGreen|DoBlue;
-
- rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
- &fg_h, &fg_s, &fg_v);
- rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
- &bg_h, &bg_s, &bg_v);
-
- if (/*mode == MODE_RANDOM &&*/
- ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
- (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
- (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
- goto HSV_AGAIN;
-
- switch (this_mode) {
- case MODE_H: shift = (bg_h - fg_h) / ncolors; break;
- case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
- case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
- default: abort ();
+ colors = (XColor *) malloc (ncolors * sizeof(*colors));
+
+ cycle_direction = (random() & 1 ? 1 : -1);
+
+ RETRY_NON_WRITABLE:
+ {
+ int n = ncolors;
+ make_color_ramp (dpy, cmap,
+ fg_h, fg_s, fg_v,
+ bg_h, bg_s, bg_v,
+ colors, &n,
+ True, True, cycle_p);
+ if (n == 0 && cycle_p)
+ {
+ cycle_p = False;
+ goto RETRY_NON_WRITABLE;
+ }
+ ncolors = n;
}
-
- if (mode == MODE_RANDOM &&
- ((this_mode == MODE_H)
- ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
- : (dshift > -0.005 && dshift < 0.005)))
- goto HSV_AGAIN;
- if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
- goto V_AGAIN;
+ if (ncolors <= 0)
+ mono_p = 1;
+ }
- for (npixels = 0; npixels < ncolors; npixels++)
+ if (mono_p)
+ {
+ static Bool done = False;
+ static XColor c[50];
+ colors = c;
+ cycle_p = False;
+ ncolors = sizeof(c)/sizeof(*c);
+ if (!done)
{
- if (cycle_p)
- {
- unsigned long plane_masks;
- /* allocate the writable color cells, one at a time. */
- if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
- &fg_color.pixel, 1))
- {
- fprintf (stderr,
- "%s: couldn't allocate %s writable color cells. Turning off -cycle.\n",
- progname, (npixels ? "enough" : "any"));
- cycle_p = 0;
- goto NON_CYCLE;
- }
- XStoreColor (dsp, cmap, &fg_color);
- }
- else
- {
- NON_CYCLE:
- if (!XAllocColor (dsp, cmap, &fg_color))
- break;
- }
- pixels[npixels] = fg_color.pixel;
-
- switch (this_mode)
- {
- case MODE_H: fg_h = (fg_h + shift) % 360; break;
- case MODE_S: fg_s += dshift; break;
- case MODE_V: fg_v += dshift; break;
- default: abort ();
- }
- hsv_to_rgb (fg_h, fg_s, fg_v,
- &fg_color.red, &fg_color.green, &fg_color.blue);
+ int i;
+ done = True;
+ colors[0].pixel = fg_pixel;
+ for (i = 1; i < ncolors; i++)
+ colors[i].pixel = bg_pixel;
}
}
- XSetForeground (dsp, gc, pixels [0]);
- XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
+
+ XSetForeground (dpy, gc, colors[1].pixel);
+ XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
}
-#define HEIGHT_TO_PIXEL(height) \
- (((int) (height)) < 0 ? 0 : \
- ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
+#define HEIGHT_TO_PIXEL(height) \
+ ((height) < 0 \
+ ? (extra_krinkly_p \
+ ? ncolors - ((-(height)) % ncolors) \
+ : 0) \
+ : ((height) >= ncolors \
+ ? (extra_krinkly_p \
+ ? (height) % ncolors \
+ : ncolors-1) \
+ : (height)))
+
static unsigned int
-set (l, c, size, height)
- unsigned int l, c, size;
- int height;
+set (unsigned int l,
+ unsigned int c,
+ unsigned int size,
+ int height)
{
int rang = 1 << (NSTEPS - size);
height = height + (random () % rang) - rang / 2;
+ height = HEIGHT_TO_PIXEL(height);
CELL (l, c) = height;
-
- return pixels [HEIGHT_TO_PIXEL (height)];
+ return colors[height].pixel;
}
static void
-floyd_steinberg ()
+floyd_steinberg (Display *dpy, Window window)
{
int x, y, err;
don't use enormous amounts of memory.
*/
XImage *image =
- XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
+ XCreateImage (dpy, xgwa.visual,
1, XYBitmap, 0, /* depth, format, offset */
- (char *) calloc ((xmax + 1) / 8, 1), /* data */
+ (char *) calloc ((xmax + 8) / 8, 1), /* data */
xmax, 1, 8, 0); /* w, h, pad, bpl */
+ XSetForeground (dpy, gc, colors[0].pixel);
+ XSetBackground (dpy, gc, colors[1].pixel);
+
for (y = 0; y < ymax - 1; y++)
{
for (x = 0; x < xmax - 1; x++)
CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
}
- XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
+ XPutImage (dpy, window, gc, image, 0, 0, 0, y, xmax, 1);
}
XDestroyImage (image);
}
static void
-draw (x, y, pixel, grid_size) /* not called in mono mode */
- int x, y, grid_size;
- unsigned long pixel;
+draw (Display *dpy, Window window,
+ int x, int y, unsigned long pixel, int grid_size)
{
static unsigned int last_pixel, last_valid = 0;
if (! (last_valid && pixel == last_pixel))
- XSetForeground (disp, gc, pixel);
+ XSetForeground (dpy, gc, pixel);
last_valid = 1, last_pixel = pixel;
if (grid_size == 1)
- XDrawPoint (disp, wind, gc, x, y);
+ XDrawPoint (dpy, window, gc, x, y);
else
- XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
+ XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size);
}
static void
-drawmap ()
+draw_map (Display *dpy, Window window)
{
- unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
+ int xstep, ystep, xnextStep, ynextStep;
+ int x, y, i, x1, x2, y1, y2;
unsigned int pixel, qpixels [4];
- xmax = wattrs.width;
- ymax = wattrs.height;
+ int backwards = random() & 1;
+
+ xmax = xgwa.width;
+ ymax = xgwa.height;
cell = (signed char *) calloc (xmax * ymax, 1);
if (cell == NULL)
exit (1);
CELL (0, 0) = 0;
- step = COUNT;
+ xstep = (backwards ? -COUNT : COUNT);
+ ystep = COUNT;
for (i = 0; i < iterations; i++)
{
- nextStep = step / 2;
- for (x = 0; x < xmax; x += step)
+ xnextStep = xstep / 2;
+ ynextStep = ystep / 2;
+ for (x = (backwards ? xmax-1 : 0);
+ (backwards ? x >= 0 : x < xmax);
+ x += xstep)
{
- x1 = x + nextStep;
- if (x1 >= xmax)
+ x1 = x + xnextStep;
+ if (x1 < 0)
+ x1 = xmax-1;
+ else if (x1 >= xmax)
x1 = 0;
- x2 = x + step;
- if (x2 >= xmax)
+
+ x2 = x + xstep;
+ if (x2 < 0)
+ x2 = xmax-1;
+ else if (x2 >= xmax)
x2 = 0;
- for (y = 0; y < ymax; y += step)
+
+ for (y = 0; y < ymax; y += ystep)
{
- y1 = y + nextStep;
- if (y1 >= ymax)
+ y1 = y + ynextStep;
+ if (y1 < 0)
+ y1 = ymax-1;
+ else if (y1 >= ymax)
y1 = 0;
- y2 = y + step;
- if (y2 >= ymax)
+
+ y2 = y + ystep;
+ if (y2 < 0)
+ y2 = ymax-1;
+ else if (y2 >= ymax)
y2 = 0;
- qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
- qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
- qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
- qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
+ qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
+ qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
+ qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
+ qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
pixel = set (x, y1, i,
((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
if (! mono_p &&
(pixel != qpixels[0] || pixel != qpixels[1] ||
pixel != qpixels[2] || pixel != qpixels[3]))
- draw (x, y1, pixel, nextStep);
+ draw (dpy, window, x, y1, pixel, ynextStep);
pixel = set (x1, y, i,
((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
if (! mono_p &&
(pixel != qpixels[0] || pixel != qpixels[1] ||
pixel != qpixels[2] || pixel != qpixels[3]))
- draw (x1, y, pixel, nextStep);
+ draw (dpy, window, x1, y, pixel, ynextStep);
pixel = set (x1, y1, i,
((int) CELL (x, y) + (int) CELL (x, y2) +
if (! mono_p &&
(pixel != qpixels[0] || pixel != qpixels[1] ||
pixel != qpixels[2] || pixel != qpixels[3]))
- draw (x1, y1, pixel, nextStep);
+ draw (dpy, window, x1, y1, pixel, ynextStep);
+
+
+ if (cycle_p)
+ {
+ struct timeval now;
+ static struct timeval then = { 0, };
+ unsigned long diff;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+ gettimeofday(&now, &tzp);
+#else
+ gettimeofday(&now);
+#endif
+ diff = (((now.tv_sec - then.tv_sec) * 1000000) +
+ (now.tv_usec - then.tv_usec));
+ if (diff > cycle_delay)
+ {
+ rotate_colors (dpy, cmap, colors, ncolors,
+ cycle_direction);
+ then = now;
+ }
+ }
}
}
- step = nextStep;
+ xstep = xnextStep;
+ ystep = ynextStep;
if (!mono_p)
- XSync (disp, True);
+ XSync (dpy, True);
}
if (mono_p)
/* in mono-mode, we do all the drawing at the end */
- floyd_steinberg ();
+ floyd_steinberg (dpy, window);
free (cell);
- XSync (disp, True);
-}
-
-static void
-cycle (dpy)
- Display *dpy;
-{
- XColor *colors = (XColor *) malloc (npixels * sizeof (XColor));
- time_t stop;
- int i;
- for (i = 0; i < npixels; i++)
- colors [i].pixel = pixels [i];
- XQueryColors (dpy, cmap, colors, npixels);
- stop = (time_t) ((time ((time_t) 0)) + timeout);
- while (stop >= (time_t) time ((time_t) 0))
- {
- unsigned long scratch = colors [npixels-1].pixel;
- for (i = npixels-1; i > 0; i--)
- colors [i].pixel = colors [i-1].pixel;
- colors [0].pixel = scratch;
- XStoreColors (dpy, cmap, colors, npixels);
- XSync (dpy, True);
- if (cycle_delay) usleep (cycle_delay);
- }
XSync (dpy, True);
- free (colors);
}
char *progclass = "Imsmap";
char *defaults [] = {
- "*background: black",
- "*foreground: black",
+ ".background: black",
+ ".foreground: black",
"*mode: random",
"*ncolors: 50",
"*iterations: 7",
- "*timeout: 10",
+ "*delay: 10",
"*cycleDelay: 100000",
"*cycle: true",
0
XrmOptionDescRec options [] = {
{ "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
- { "-timeout", ".timeout", XrmoptionSepArg, 0 },
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
{ "-mode", ".mode", XrmoptionSepArg, 0 },
{ "-iterations", ".iterations", XrmoptionSepArg, 0 },
{ "-cycle", ".cycle", XrmoptionNoArg, "True" },
- { "-no-cycle", ".cycle", XrmoptionNoArg, "False" }
+ { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
+ { 0, 0, 0, 0 }
};
-int options_size = (sizeof (options) / sizeof (options[0]));
void
-screenhack (dpy, window)
- Display *dpy;
- Window window;
+screenhack (Display *dpy, Window window)
{
- disp = dpy;
- wind = window;
while (1)
{
- initwin (dpy, window);
- drawmap ();
- if (timeout)
+ init_map (dpy, window);
+ draw_map (dpy, window);
+ if (delay)
{
if (cycle_p)
- cycle (dpy);
+ {
+ time_t start = time((time_t) 0);
+ while (start + delay > time((time_t) 0))
+ {
+ rotate_colors (dpy, cmap, colors, ncolors,
+ cycle_direction);
+ if (cycle_delay) usleep(cycle_delay);
+ }
+ }
else
- sleep (timeout);
+ sleep (delay);
}
}
}