/* xscreensaver, Copyright (c) 1997-2013 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* Concept snarfed from Michael D. Bayne in
* http://samskivert.com/internet/deep/1997/04/16/body.html
*/
#include "screenhack.h"
#include "xshm.h"
struct state {
Display *dpy;
Window window;
XShmSegmentInfo shm_info;
int delay;
int offset;
XColor *colors;
int ncolors;
GC gc;
unsigned long fg_pixel;
unsigned long bg_pixel;
int depth;
int draw_y, draw_xo, draw_yo;
int draw_factor;
XImage *draw_image;
XWindowAttributes xgwa;
};
static void
moire_init_1 (struct state *st)
{
int oncolors;
int i;
int fgh, bgh;
double fgs, fgv, bgs, bgv;
XWindowAttributes xgwa;
XColor fgc, bgc;
XGCValues gcv;
XGetWindowAttributes (st->dpy, st->window, &xgwa);
st->delay = get_integer_resource (st->dpy, "delay", "Integer");
st->offset = get_integer_resource (st->dpy, "offset", "Integer");
if (st->offset < 2) st->offset = 2;
MONO:
if (st->colors)
{
for (i = 0; i < st->ncolors; i++)
XFreeColors (st->dpy, xgwa.colormap, &st->colors[i].pixel, 1, 0);
free(st->colors);
st->colors = 0;
}
if (mono_p)
{
st->fg_pixel = WhitePixelOfScreen (DefaultScreenOfDisplay(st->dpy));
st->bg_pixel = BlackPixelOfScreen (DefaultScreenOfDisplay(st->dpy));
}
else
{
st->fg_pixel = get_pixel_resource (st->dpy,
xgwa.colormap, "foreground", "Foreground");
st->bg_pixel = get_pixel_resource (st->dpy,
xgwa.colormap, "background", "Background");
}
if (mono_p)
{
st->offset *= 20; /* compensate for lack of shading */
gcv.foreground = st->fg_pixel;
}
else
{
st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
if (st->ncolors < 2) st->ncolors = 2;
oncolors = st->ncolors;
fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue;
if (get_boolean_resource(st->dpy, "random","Boolean"))
{
fgc.red = random() & 0xFFFF;
fgc.green = random() & 0xFFFF;
fgc.blue = random() & 0xFFFF;
bgc.red = random() & 0xFFFF;
bgc.green = random() & 0xFFFF;
bgc.blue = random() & 0xFFFF;
}
else
{
fgc.pixel = st->fg_pixel;
bgc.pixel = st->bg_pixel;
XQueryColor (st->dpy, xgwa.colormap, &fgc);
XQueryColor (st->dpy, xgwa.colormap, &bgc);
}
rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
st->colors = (XColor *) malloc (sizeof (XColor) * (st->ncolors+2));
memset(st->colors, 0, (sizeof (XColor) * (st->ncolors+2)));
make_color_ramp (xgwa.screen, xgwa.visual, xgwa.colormap,
fgh, fgs, fgv, bgh, bgs, bgv,
st->colors, &st->ncolors,
True, True, False);
if (st->ncolors != oncolors)
fprintf(stderr, "%s: got %d of %d requested colors.\n",
progname, st->ncolors, oncolors);
if (st->ncolors <= 2)
{
mono_p = True;
goto MONO;
}
gcv.foreground = st->colors[0].pixel;
}
st->gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
}
static void *
moire_init (Display *dpy, Window window)
{
struct state *st = (struct state *) calloc (1, sizeof(*st));
st->dpy = dpy;
st->window = window;
moire_init_1 (st);
return st;
}
static unsigned long
moire_draw (Display *dpy, Window window, void *closure)
{
struct state *st = (struct state *) closure;
XGCValues gcv;
int chunk_size = 20, ii;
if (st->draw_y == 0)
{
moire_init_1 (st);
XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
st->draw_xo = (random() % st->xgwa.width) - st->xgwa.width/2;
st->draw_yo = (random() % st->xgwa.height) - st->xgwa.height/2;
st->draw_factor = (random() % st->offset) + 1;
st->depth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
st->draw_image = create_xshm_image(st->dpy, st->xgwa.visual,
st->depth, ZPixmap, &st->shm_info, /* depth, format, shm_info */
st->xgwa.width, chunk_size); /* w, h */
}
/* for (y = 0; y < st->xgwa.height; y++) */
for (ii = 0; ii < chunk_size; ii++)
{
int x;
for (x = 0; x < st->xgwa.width; x++)
{
double xx = x + st->draw_xo;
double yy = st->draw_y + ii + st->draw_yo;
double i = ((xx * xx) + (yy * yy)) / (double) st->draw_factor;
if (mono_p)
gcv.foreground = ((((long) i) & 1) ? st->fg_pixel : st->bg_pixel);
else
gcv.foreground = st->colors[((long) i) % st->ncolors].pixel;
XPutPixel (st->draw_image, x, ii, gcv.foreground);
}
if (st->draw_y + ii >= st->xgwa.height)
break;
}
put_xshm_image(st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, chunk_size, &st->shm_info);
st->draw_y += chunk_size;
if (st->draw_y >= st->xgwa.height)
{
st->draw_y = 0;
destroy_xshm_image (st->dpy, st->draw_image, &st->shm_info);
st->draw_image = 0;
return st->delay * 1000000;
}
return st->delay * 10000;
}
static const char *moire_defaults [] = {
".background: blue",
".foreground: red",
"*fpsSolid: true",
"*random: true",
"*delay: 5",
"*ncolors: 64",
"*offset: 50",
"*useSHM: True",
#ifdef HAVE_MOBILE
"*ignoreRotation: True",
#endif
0
};
static XrmOptionDescRec moire_options [] = {
{ "-random", ".random", XrmoptionNoArg, "True" },
{ "-no-random", ".random", XrmoptionNoArg, "False" },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
{ "-offset", ".offset", XrmoptionSepArg, 0 },
{ "-shm", ".useSHM", XrmoptionNoArg, "True" },
{ "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
{ 0, 0, 0, 0 }
};
static void
moire_reshape (Display *dpy, Window window, void *closure,
unsigned int w, unsigned int h)
{
}
static Bool
moire_event (Display *dpy, Window window, void *closure, XEvent *event)
{
return False;
}
static void
moire_free (Display *dpy, Window window, void *closure)
{
}
XSCREENSAVER_MODULE ("Moire", moire)