-/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997
- * Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2008 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
#include "screenhack.h"
-static int sizex, sizey;
-static int delay;
-static GC gc;
-static int mode;
-static int iterations=100;
-
-#define SHUFFLE 0
-#define UP 1
-#define LEFT 2
-#define RIGHT 3
-#define DOWN 4
-#define UPLEFT 5
-#define DOWNLEFT 6
-#define UPRIGHT 7
-#define DOWNRIGHT 8
-#define IN 9
-#define OUT 10
-#define MELT 11
-#define STRETCH 12
-#define FUZZ 13
+struct state {
+ Display *dpy;
+ Window window;
+
+ int sizex, sizey;
+ int delay;
+ int duration;
+ GC gc;
+ int mode;
+ int random_p;
+ time_t start_time;
+
+ int fuzz_toggle;
+ const int *current_bias;
+
+ async_load_state *img_loader;
+};
+
+
+#define SHUFFLE 0
+#define UP 1
+#define LEFT 2
+#define RIGHT 3
+#define DOWN 4
+#define UPLEFT 5
+#define DOWNLEFT 6
+#define UPRIGHT 7
+#define DOWNRIGHT 8
+#define IN 9
+#define OUT 10
+#define MELT 11
+#define STRETCH 12
+#define FUZZ 13
static void
-init_decay (Display *dpy, Window window)
+decayscreen_load_image (struct state *st)
+{
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (st->dpy, st->window, &xgwa);
+ st->sizex = xgwa.width;
+ st->sizey = xgwa.height;
+ if (st->img_loader) abort();
+ st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+ st->window, 0, 0);
+}
+
+static void *
+decayscreen_init (Display *dpy, Window window)
{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
XGCValues gcv;
XWindowAttributes xgwa;
long gcflags;
unsigned long bg;
-
- char *s = get_string_resource("mode", "Mode");
- if (s && !strcmp(s, "shuffle")) mode = SHUFFLE;
- else if (s && !strcmp(s, "up")) mode = UP;
- else if (s && !strcmp(s, "left")) mode = LEFT;
- else if (s && !strcmp(s, "right")) mode = RIGHT;
- else if (s && !strcmp(s, "down")) mode = DOWN;
- else if (s && !strcmp(s, "upleft")) mode = UPLEFT;
- else if (s && !strcmp(s, "downleft")) mode = DOWNLEFT;
- else if (s && !strcmp(s, "upright")) mode = UPRIGHT;
- else if (s && !strcmp(s, "downright")) mode = DOWNRIGHT;
- else if (s && !strcmp(s, "in")) mode = IN;
- else if (s && !strcmp(s, "out")) mode = OUT;
- else if (s && !strcmp(s, "melt")) mode = MELT;
- else if (s && !strcmp(s, "stretch")) mode = STRETCH;
- else if (s && !strcmp(s, "fuzz")) mode = FUZZ;
+ char *s;
+
+ st->dpy = dpy;
+ st->window = window;
+ st->random_p = 0;
+
+ s = get_string_resource(st->dpy, "mode", "Mode");
+ if (s && !strcmp(s, "shuffle")) st->mode = SHUFFLE;
+ else if (s && !strcmp(s, "up")) st->mode = UP;
+ else if (s && !strcmp(s, "left")) st->mode = LEFT;
+ else if (s && !strcmp(s, "right")) st->mode = RIGHT;
+ else if (s && !strcmp(s, "down")) st->mode = DOWN;
+ else if (s && !strcmp(s, "upleft")) st->mode = UPLEFT;
+ else if (s && !strcmp(s, "downleft")) st->mode = DOWNLEFT;
+ else if (s && !strcmp(s, "upright")) st->mode = UPRIGHT;
+ else if (s && !strcmp(s, "downright")) st->mode = DOWNRIGHT;
+ else if (s && !strcmp(s, "in")) st->mode = IN;
+ else if (s && !strcmp(s, "out")) st->mode = OUT;
+ else if (s && !strcmp(s, "melt")) st->mode = MELT;
+ else if (s && !strcmp(s, "stretch")) st->mode = STRETCH;
+ else if (s && !strcmp(s, "fuzz")) st->mode = FUZZ;
else {
if (s && *s && !!strcmp(s, "random"))
fprintf(stderr, "%s: unknown mode %s\n", progname, s);
- mode = random() % (FUZZ+1);
+ st->random_p = 1;
+ st->mode = random() % (FUZZ+1);
}
- delay = get_integer_resource ("delay", "Integer");
+ st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+ if (st->delay < 0) st->delay = 0;
- if (delay < 0) delay = 0;
+ st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+ if (st->duration < 1) st->duration = 1;
- XGetWindowAttributes (dpy, window, &xgwa);
+ XGetWindowAttributes (st->dpy, st->window, &xgwa);
gcv.function = GXcopy;
gcv.subwindow_mode = IncludeInferiors;
+ bg = get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background");
+ gcv.foreground = bg;
- if (mode == MELT || mode == STRETCH) {
- bg = get_pixel_resource ("background", "Background", dpy, xgwa.colormap);
- gcv.foreground = bg;
- }
-
- gcflags = GCForeground |GCFunction;
- if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
+ gcflags = GCForeground | GCFunction;
+ if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
gcflags |= GCSubwindowMode;
- gc = XCreateGC (dpy, window, gcflags, &gcv);
-
- sizex = xgwa.width;
- sizey = xgwa.height;
-
- load_random_image (xgwa.screen, window, window);
-
- if (mode == MELT || mode == STRETCH) {
- /* make sure screen eventually turns background color */
- XDrawLine(dpy, window, gc, 0, 0, sizex, 0);
+ st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
- /* slow down for smoother melting*/
- iterations = 1;
- }
+ st->start_time = time ((time_t) 0);
+ decayscreen_load_image (st);
+ return st;
}
/*
* perform one iteration of decay
*/
-static void
-decay1 (Display *dpy, Window window)
+static unsigned long
+decayscreen_draw (Display *dpy, Window window, void *closure)
{
+ struct state *st = (struct state *) closure;
int left, top, width, height, toleft, totop;
#define L 101
#define R 102
#define U 103
#define D 104
- static int no_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
- static int up_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
- static int down_bias[] = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
- static int left_bias[] = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
- static int right_bias[] = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
-
- static int upleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
- static int downleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
- static int upright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
- static int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
- static int *bias;
-
- switch (mode) {
- case SHUFFLE: bias = no_bias; break;
- case UP: bias = up_bias; break;
- case LEFT: bias = left_bias; break;
- case RIGHT: bias = right_bias; break;
- case DOWN: bias = down_bias; break;
- case UPLEFT: bias = upleft_bias; break;
- case DOWNLEFT: bias = downleft_bias; break;
- case UPRIGHT: bias = upright_bias; break;
- case DOWNRIGHT: bias = downright_bias; break;
- case IN: bias = no_bias; break;
- case OUT: bias = no_bias; break;
- case MELT: bias = no_bias; break;
- case STRETCH: bias = no_bias; break;
- case FUZZ: bias = no_bias; break;
+ static const int no_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
+ static const int up_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
+ static const int down_bias[] = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
+ static const int left_bias[] = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
+ static const int right_bias[] = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
+
+ static const int upleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
+ static const int downleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
+ static const int upright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
+ static const int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
+
+ if (st->img_loader) /* still loading */
+ {
+ st->img_loader = load_image_async_simple (st->img_loader,
+ 0, 0, 0, 0, 0);
+ if (! st->img_loader) { /* just finished */
+
+ st->start_time = time ((time_t) 0);
+ if (st->random_p)
+ st->mode = random() % (FUZZ+1);
+
+ if (st->mode == MELT || st->mode == STRETCH)
+ /* make sure screen eventually turns background color */
+ XDrawLine (st->dpy, st->window, st->gc, 0, 0, st->sizex, 0);
+ }
+ return st->delay;
+ }
+
+ if (!st->img_loader &&
+ st->start_time + st->duration < time ((time_t) 0)) {
+ decayscreen_load_image (st);
+ }
+
+ switch (st->mode) {
+ case SHUFFLE: st->current_bias = no_bias; break;
+ case UP: st->current_bias = up_bias; break;
+ case LEFT: st->current_bias = left_bias; break;
+ case RIGHT: st->current_bias = right_bias; break;
+ case DOWN: st->current_bias = down_bias; break;
+ case UPLEFT: st->current_bias = upleft_bias; break;
+ case DOWNLEFT: st->current_bias = downleft_bias; break;
+ case UPRIGHT: st->current_bias = upright_bias; break;
+ case DOWNRIGHT: st->current_bias = downright_bias; break;
+ case IN: st->current_bias = no_bias; break;
+ case OUT: st->current_bias = no_bias; break;
+ case MELT: st->current_bias = no_bias; break;
+ case STRETCH: st->current_bias = no_bias; break;
+ case FUZZ: st->current_bias = no_bias; break;
default: abort();
}
-#define nrnd(x) (random() % (x))
+#define nrnd(x) ((x) ? random() % (x) : x)
- if (mode == MELT || mode == STRETCH) {
- left = nrnd(sizex/2);
- top = nrnd(sizey);
- width = nrnd( sizex/2 ) + sizex/2 - left;
- height = nrnd(sizey - top);
+ if (st->mode == MELT || st->mode == STRETCH) {
+ left = nrnd(st->sizex/2);
+ top = nrnd(st->sizey);
+ width = nrnd( st->sizex/2 ) + st->sizex/2 - left;
+ height = nrnd(st->sizey - top);
toleft = left;
totop = top+1;
- } else if (mode == FUZZ) { /* By Vince Levey <vincel@vincel.org>;
+ } else if (st->mode == FUZZ) { /* By Vince Levey <vincel@vincel.org>;
inspired by the "melt" mode of the
"scrhack" IrisGL program by Paul Haeberli
circa 1991. */
- static int toggle = 0;
-
- left = nrnd(sizex - 1);
- top = nrnd(sizey - 1);
- toggle = !toggle;
- if (toggle)
+ left = nrnd(st->sizex - 1);
+ top = nrnd(st->sizey - 1);
+ st->fuzz_toggle = !st->fuzz_toggle;
+ if (st->fuzz_toggle)
{
totop = top;
height = 1;
- toleft = nrnd(sizex - 1);
+ toleft = nrnd(st->sizex - 1);
if (toleft > left)
{
width = toleft-left;
{
toleft = left;
width = 1;
- totop = nrnd(sizey - 1);
+ totop = nrnd(st->sizey - 1);
if (totop > top)
{
height = totop-top;
} else {
- left = nrnd(sizex - 1);
- top = nrnd(sizey);
- width = nrnd(sizex - left);
- height = nrnd(sizey - top);
+ left = nrnd(st->sizex - 1);
+ top = nrnd(st->sizey);
+ width = nrnd(st->sizex - left);
+ height = nrnd(st->sizey - top);
toleft = left;
totop = top;
- if (mode == IN || mode == OUT) {
+ if (st->mode == IN || st->mode == OUT) {
int x = left+(width/2);
int y = top+(height/2);
- int cx = sizex/2;
- int cy = sizey/2;
- if (mode == IN) {
- if (x > cx && y > cy) bias = upleft_bias;
- else if (x < cx && y > cy) bias = upright_bias;
- else if (x < cx && y < cy) bias = downright_bias;
- else /* (x > cx && y < cy)*/ bias = downleft_bias;
+ int cx = st->sizex/2;
+ int cy = st->sizey/2;
+ if (st->mode == IN) {
+ if (x > cx && y > cy) st->current_bias = upleft_bias;
+ else if (x < cx && y > cy) st->current_bias = upright_bias;
+ else if (x < cx && y < cy) st->current_bias = downright_bias;
+ else /* (x > cx && y < cy)*/ st->current_bias = downleft_bias;
} else {
- if (x > cx && y > cy) bias = downright_bias;
- else if (x < cx && y > cy) bias = downleft_bias;
- else if (x < cx && y < cy) bias = upleft_bias;
- else /* (x > cx && y < cy)*/ bias = upright_bias;
+ if (x > cx && y > cy) st->current_bias = downright_bias;
+ else if (x < cx && y > cy) st->current_bias = downleft_bias;
+ else if (x < cx && y < cy) st->current_bias = upleft_bias;
+ else /* (x > cx && y < cy)*/ st->current_bias = upright_bias;
}
}
- switch (bias[random() % (sizeof(no_bias)/sizeof(*no_bias))]) {
+ switch (st->current_bias[random() % (sizeof(no_bias)/sizeof(*no_bias))]) {
case L: toleft = left-1; break;
case R: toleft = left+1; break;
case U: totop = top-1; break;
}
}
- if (mode == STRETCH) {
- XCopyArea (dpy, window, window, gc, 0, sizey-top-2, sizex, top+1,
- 0, sizey-top-1);
+ if (st->mode == STRETCH) {
+ XCopyArea (st->dpy, st->window, st->window, st->gc, 0, st->sizey-top-2, st->sizex, top+1,
+ 0, st->sizey-top-1);
} else {
- XCopyArea (dpy, window, window, gc, left, top, width, height,
+ XCopyArea (st->dpy, st->window, st->window, st->gc, left, top, width, height,
toleft, totop);
}
#undef nrnd
+
+ return st->delay;
+}
+
+static void
+decayscreen_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ st->sizex = w;
+ st->sizey = h;
+}
+
+static Bool
+decayscreen_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
+}
+
+static void
+decayscreen_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ free (st);
}
\f
-char *progclass = "DecayScreen";
-char *defaults [] = {
+static const char *decayscreen_defaults [] = {
+ ".background: Black",
+ ".foreground: Yellow",
"*dontClearRoot: True",
+ "*fpsSolid: True",
#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
"*visualID: Best",
"*delay: 10000",
"*mode: random",
+ "*duration: 120",
0
};
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec decayscreen_options [] = {
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-mode", ".mode", XrmoptionSepArg, 0 },
+ { "-duration", ".duration", XrmoptionSepArg, 0 },
{ 0, 0, 0, 0 }
};
-void
-screenhack (Display *dpy, Window window)
-{
- init_decay (dpy, window);
- while (1) {
- int i;
- for (i = 0; i < iterations; i++)
- decay1 (dpy, window);
- XSync(dpy, False);
- screenhack_handle_events (dpy);
- if (delay) usleep (delay);
- }
-}
+
+XSCREENSAVER_MODULE ("DecayScreen", decayscreen)