http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / distort.c
index 919aa4bd83219f88daab240017cfc0ea85c3f207..7755f0283fda8c722c23ef29b1c2e28a06a4dd0c 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- mode: C; tab-width: 4 -*-
- * xscreensaver, Copyright (c) 1992-2005 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1992-2006 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 <math.h>
 #include "screenhack.h"
-#include <X11/Xutil.h>
-#include <X11/Xmd.h>
+/*#include <X11/Xmd.h>*/
 
 #ifdef HAVE_XSHM_EXTENSION
 # include "xshm.h"
-static Bool use_shm = False;
-static XShmSegmentInfo shm_info;
 #endif /* HAVE_XSHM_EXTENSION */
 
+#define CARD32 unsigned int
+#define CARD16 unsigned short
+#define CARD8  unsigned char
+
+
 struct coo {
        int x;
        int y;
        int r, r_change;
        int xmove, ymove;
 };
-static struct coo xy_coo[10];
-
-static int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
-static XWindowAttributes xgwa;
-static GC gc;
-static Window g_window;
-static Display *g_dpy;
-static unsigned long black_pixel;
-
-static XImage *orig_map, *buffer_map;
-static unsigned long *buffer_map_cache;
-
-static int ***from;
-static int ****from_array;
-static int *fast_from = NULL;
-static void (*effect) (int) = NULL;
-static void move_lense(int);
-static void swamp_thing(int);
-static void new_rnd_coo(int);
-static void init_round_lense(void);
-static void (*draw) (int) = NULL;
-static void reflect_draw(int);
-static void plain_draw(int);
-
-static void (*draw_routine)(XImage *, XImage *, int, int, int *) = NULL;
-static void fast_draw_8(XImage *, XImage *, int, int, int *);
-static void fast_draw_16(XImage *, XImage *, int, int, int *);
-static void fast_draw_32(XImage *, XImage *, int, int, int *);
-static void generic_draw(XImage *, XImage *, int, int, int *);
-static int bpp_size = 0;
-
-
-static void init_distort(Display *dpy, Window window) 
+
+struct state {
+  Display *dpy;
+  Window window;
+
+  struct coo xy_coo[10];
+
+  int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
+  XWindowAttributes xgwa;
+  GC gc;
+  unsigned long black_pixel;
+
+  XImage *orig_map, *buffer_map;
+  unsigned long *buffer_map_cache;
+
+  int ***from;
+  int ****from_array;
+  int *fast_from;
+
+  int bpp_size;
+
+#ifdef HAVE_XSHM_EXTENSION
+  Bool use_shm;
+  XShmSegmentInfo shm_info;
+#endif /* HAVE_XSHM_EXTENSION */
+
+  void (*effect) (struct state *, int);
+  void (*draw) (struct state *, int);
+  void (*draw_routine) (struct state *st, XImage *, XImage *, int, int, int *);
+
+  async_load_state *img_loader;
+};
+
+
+static void move_lense(struct state *, int);
+static void swamp_thing(struct state *, int);
+static void new_rnd_coo(struct state *, int);
+static void init_round_lense(struct state *st);
+static void reflect_draw(struct state *, int);
+static void plain_draw(struct state *, int);
+
+static void fast_draw_8 (struct state *st, XImage *, XImage *, int, int, int *);
+static void fast_draw_16(struct state *st, XImage *, XImage *, int, int, int *);
+static void fast_draw_32(struct state *st, XImage *, XImage *, int, int, int *);
+static void generic_draw(struct state *st, XImage *, XImage *, int, int, int *);
+
+
+static void distort_finish_loading (struct state *);
+
+static void *
+distort_init (Display *dpy, Window window)
 {
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
        XGCValues gcv;
        long gcflags;
        int i;
+    char *s;
 
-       g_window=window;
-       g_dpy=dpy;
+    st->dpy = dpy;
+    st->window = window;
 
-       delay = get_integer_resource("delay", "Integer");
-       radius = get_integer_resource("radius", "Integer");
-       speed = get_integer_resource("speed", "Integer");
-       number = get_integer_resource("number", "Integer");
+       st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+       st->radius = get_integer_resource(st->dpy, "radius", "Integer");
+       st->speed = get_integer_resource(st->dpy, "speed", "Integer");
+       st->number = get_integer_resource(st->dpy, "number", "Integer");
 
 #ifdef HAVE_XSHM_EXTENSION
-       use_shm = get_boolean_resource("useSHM", "Boolean");
+       st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
 #endif /* HAVE_XSHM_EXTENSION */
        
-       blackhole = get_boolean_resource("blackhole", "Boolean");
-       vortex = get_boolean_resource("vortex", "Boolean");
-       magnify = get_boolean_resource("magnify", "Boolean");
-       reflect = get_boolean_resource("reflect", "Boolean");
-       slow = get_boolean_resource("slow", "Boolean");
+       st->blackhole = get_boolean_resource(st->dpy, "blackhole", "Boolean");
+       st->vortex = get_boolean_resource(st->dpy, "vortex", "Boolean");
+       st->magnify = get_boolean_resource(st->dpy, "magnify", "Boolean");
+       st->reflect = get_boolean_resource(st->dpy, "reflect", "Boolean");
+       st->slow = get_boolean_resource(st->dpy, "slow", "Boolean");
        
-       if (get_boolean_resource("swamp", "Boolean"))
-               effect = &swamp_thing;
-       if (get_boolean_resource("bounce", "Boolean"))
-               effect = &move_lense;
-
-       XGetWindowAttributes (dpy, window, &xgwa);
-
-       if (effect == NULL && radius == 0 && speed == 0 && number == 0
-               && !blackhole && !vortex && !magnify && !reflect) {
+    st->effect = NULL;
+    s = get_string_resource(st->dpy, "effect", "String");
+       if (s && !strcasecmp(s,"swamp"))
+      st->effect = &swamp_thing;
+    else if (s && !strcasecmp(s,"bounce"))
+      st->effect = &move_lense;
+    else if (s && !strcasecmp(s,"none"))
+      ;
+    else if (s && *s)
+      fprintf(stderr,"%s: bogus effect: %s\n", progname, s);
+
+       XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+
+       if (st->effect == NULL && st->radius == 0 && st->speed == 0 && st->number == 0
+               && !st->blackhole && !st->vortex && !st->magnify && !st->reflect) {
 /* if no cmdline options are given, randomly choose one of:
  * -radius 50 -number 4 -speed 1 -bounce
  * -radius 50 -number 4 -speed 1 -blackhole
@@ -139,62 +167,62 @@ static void init_distort(Display *dpy, Window window)
                
                i = (random() % 12 /* 17 */);
 
-               draw = &plain_draw;
+               st->draw = &plain_draw;
 
                switch (i) {
                        case 0:
-                               radius=50;number=4;speed=1;
-                               effect=&move_lense;break;
+                               st->radius=50;st->number=4;st->speed=1;
+                               st->effect=&move_lense;break;
                        case 1:
-                               radius=50;number=4;speed=1;blackhole=1;
-                               effect=&move_lense;break;
+                               st->radius=50;st->number=4;st->speed=1;st->blackhole=1;
+                               st->effect=&move_lense;break;
                        case 2:
-                               radius=50;number=4;speed=1;vortex=1;
-                               effect=&move_lense;break;
+                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;
+                               st->effect=&move_lense;break;
                        case 3:
-                               radius=50;number=4;speed=1;vortex=1;magnify=1;
-                               effect=&move_lense;break;
+                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;
+                               st->effect=&move_lense;break;
                        case 4:
-                               radius=50;number=4;speed=1;vortex=1;magnify=1;blackhole=1;
-                               effect=&move_lense;break;
+                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;st->blackhole=1;
+                               st->effect=&move_lense;break;
                        case 5:
-                               radius=100;number=1;speed=2;
-                               effect=&move_lense;break;
+                               st->radius=100;st->number=1;st->speed=2;
+                               st->effect=&move_lense;break;
                        case 6:
-                               radius=100;number=1;speed=2;blackhole=1;
-                               effect=&move_lense;break;
+                               st->radius=100;st->number=1;st->speed=2;st->blackhole=1;
+                               st->effect=&move_lense;break;
                        case 7:
-                               radius=100;number=1;speed=2;vortex=1;
-                               effect=&move_lense;break;
+                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;
+                               st->effect=&move_lense;break;
                        case 8:
-                               radius=100;number=1;speed=2;vortex=1;magnify=1;
-                               effect=&move_lense;break;
+                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;
+                               st->effect=&move_lense;break;
                        case 9:
-                               radius=100;number=1;speed=2;vortex=1;magnify=1;blackhole=1;
-                               effect=&move_lense;break;
+                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
+                               st->effect=&move_lense;break;
 
                        case 10:
-                               radius=80;number=1;speed=2;reflect=1;
-                               draw = &reflect_draw;effect = &move_lense;break;
+                               st->radius=80;st->number=1;st->speed=2;st->reflect=1;
+                               st->draw = &reflect_draw;st->effect = &move_lense;break;
                        case 11:
-                               radius=50;number=4;speed=2;reflect=1;
-                               draw = &reflect_draw;effect = &move_lense;break;
+                               st->radius=50;st->number=4;st->speed=2;st->reflect=1;
+                               st->draw = &reflect_draw;st->effect = &move_lense;break;
 
 #if 0 /* jwz: not these */
                        case 12:
-                               radius=50;number=4;speed=2;
+                               st->radius=50;st->number=4;st->speed=2;
                                effect=&swamp_thing;break;
                        case 13:
-                               radius=50;number=4;speed=2;blackhole=1;
+                               st->radius=50;st->number=4;st->speed=2;st->blackhole=1;
                                effect=&swamp_thing;break;
                        case 14:
-                               radius=50;number=4;speed=2;vortex=1;
+                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;
                                effect=&swamp_thing;break;
                        case 15:
-                               radius=50;number=4;speed=2;vortex=1;magnify=1;
+                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;
                                effect=&swamp_thing;break;
                        case 16:
-                               radius=50;number=4;speed=2;vortex=1;magnify=1;blackhole=1;
+                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
                                effect=&swamp_thing;break;
 #endif
 
@@ -203,127 +231,134 @@ static void init_distort(Display *dpy, Window window)
                }
 
         /* but if the window is small, reduce default radius */
-        if (xgwa.width < radius * 8)
-          radius = xgwa.width/8;
+        if (st->xgwa.width < st->radius * 8)
+          st->radius = st->xgwa.width/8;
        }
 
     /* never allow the radius to be too close to the min window dimension
      */
-    if (radius >= xgwa.width  * 0.45) radius = xgwa.width  * 0.45;
-    if (radius >= xgwa.height * 0.45) radius = xgwa.height * 0.45;
+    if (st->radius >= st->xgwa.width  * 0.45) st->radius = st->xgwa.width  * 0.45;
+    if (st->radius >= st->xgwa.height * 0.45) st->radius = st->xgwa.height * 0.45;
 
 
     /* -swamp mode consumes vast amounts of memory, proportional to radius --
        so throttle radius to a small-ish value (60 => ~30MB.)
      */
-    if (effect == &swamp_thing && radius > 60)
-      radius = 60;
-
-       if (delay < 0)
-               delay = 0;
-       if (radius <= 0)
-               radius = 60;
-       if (speed <= 0) 
-               speed = 2;
-       if (number <= 0)
-               number=1;
-       if (number >= 10)
-               number=1;
-       if (effect == NULL)
-               effect = &move_lense;
-       if (reflect) {
-               draw = &reflect_draw;
-               effect = &move_lense;
+    if (st->effect == &swamp_thing && st->radius > 60)
+      st->radius = 60;
+
+       if (st->delay < 0)
+               st->delay = 0;
+       if (st->radius <= 0)
+               st->radius = 60;
+       if (st->speed <= 0) 
+               st->speed = 2;
+       if (st->number <= 0)
+               st->number=1;
+       if (st->number >= 10)
+               st->number=1;
+       if (st->effect == NULL)
+               st->effect = &move_lense;
+       if (st->reflect) {
+               st->draw = &reflect_draw;
+               st->effect = &move_lense;
        }
-       if (draw == NULL)
-               draw = &plain_draw;
+       if (st->draw == NULL)
+               st->draw = &plain_draw;
 
-       black_pixel = BlackPixelOfScreen( xgwa.screen );
+       st->black_pixel = BlackPixelOfScreen( st->xgwa.screen );
 
        gcv.function = GXcopy;
        gcv.subwindow_mode = IncludeInferiors;
-       gcflags = GCForeground |GCFunction;
-       if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
+       gcflags = GCFunction;
+       if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
                gcflags |= GCSubwindowMode;
-       gc = XCreateGC (dpy, window, gcflags, &gcv);
+       st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
+
+    st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+                                              st->window, 0, 0);
+    return st;
+}
 
-    load_random_image (xgwa.screen, window, window, NULL, NULL);
+static void
+distort_finish_loading (struct state *st)
+{
+    int i;
 
-       buffer_map = 0;
-       orig_map = XGetImage(dpy, window, 0, 0, xgwa.width, xgwa.height,
+       st->buffer_map = 0;
+       st->orig_map = XGetImage(st->dpy, st->window, 0, 0, st->xgwa.width, st->xgwa.height,
                                                 ~0L, ZPixmap);
-       buffer_map_cache = malloc(sizeof(unsigned long)*(2*radius+speed+2)*(2*radius+speed+2));
+       st->buffer_map_cache = malloc(sizeof(unsigned long)*(2*st->radius+st->speed+2)*(2*st->radius+st->speed+2));
 
-       if (buffer_map_cache == NULL) {
+       if (st->buffer_map_cache == NULL) {
                perror("distort");
                exit(EXIT_FAILURE);
        }
 
 # ifdef HAVE_XSHM_EXTENSION
 
-       if (use_shm)
+       if (st->use_shm)
          {
-               buffer_map = create_xshm_image(dpy, xgwa.visual, orig_map->depth,
-                                                                          ZPixmap, 0, &shm_info,
-                                                                          2*radius + speed + 2,
-                                                                          2*radius + speed + 2);
-               if (!buffer_map)
-                 use_shm = False;
+               st->buffer_map = create_xshm_image(st->dpy, st->xgwa.visual, st->orig_map->depth,
+                                                                          ZPixmap, 0, &st->shm_info,
+                                                                          2*st->radius + st->speed + 2,
+                                                                          2*st->radius + st->speed + 2);
+               if (!st->buffer_map)
+                 st->use_shm = False;
          }
 # endif /* HAVE_XSHM_EXTENSION */
 
-       if (!buffer_map)
+       if (!st->buffer_map)
          {
-               buffer_map = XCreateImage(dpy, xgwa.visual,
-                                                                 orig_map->depth, ZPixmap, 0, 0,
-                                                                 2*radius + speed + 2, 2*radius + speed + 2,
+               st->buffer_map = XCreateImage(st->dpy, st->xgwa.visual,
+                                                                 st->orig_map->depth, ZPixmap, 0, 0,
+                                                                 2*st->radius + st->speed + 2, 2*st->radius + st->speed + 2,
                                                                  8, 0);
-               buffer_map->data = (char *)
-                 calloc(buffer_map->height, buffer_map->bytes_per_line);
+               st->buffer_map->data = (char *)
+                 calloc(st->buffer_map->height, st->buffer_map->bytes_per_line);
        }
 
-       if ((buffer_map->byte_order == orig_map->byte_order)
-                       && (buffer_map->depth == orig_map->depth)
-                       && (buffer_map->format == ZPixmap)
-                       && (orig_map->format == ZPixmap)
-                       && !slow) {
-               switch (orig_map->bits_per_pixel) {
+       if ((st->buffer_map->byte_order == st->orig_map->byte_order)
+                       && (st->buffer_map->depth == st->orig_map->depth)
+                       && (st->buffer_map->format == ZPixmap)
+                       && (st->orig_map->format == ZPixmap)
+                       && !st->slow) {
+               switch (st->orig_map->bits_per_pixel) {
                        case 32:
-                               draw_routine = &fast_draw_32;
-                               bpp_size = sizeof(CARD32);
+                               st->draw_routine = &fast_draw_32;
+                               st->bpp_size = sizeof(CARD32);
                                break;
                        case 16:
-                               draw_routine = &fast_draw_16;
-                               bpp_size = sizeof(CARD16);
+                               st->draw_routine = &fast_draw_16;
+                               st->bpp_size = sizeof(CARD16);
                                break;
                        case 8:
-                               draw_routine = &fast_draw_8;
-                               bpp_size = sizeof(CARD8);
+                               st->draw_routine = &fast_draw_8;
+                               st->bpp_size = sizeof(CARD8);
                                break;
                        default:
-                               draw_routine = &generic_draw;
+                               st->draw_routine = &generic_draw;
                                break;
                }
        } else {
-               draw_routine = &generic_draw;
+               st->draw_routine = &generic_draw;
        }
-       init_round_lense();
+       init_round_lense(st);
 
-       for (i = 0; i < number; i++) {
-               new_rnd_coo(i);
-               if (number != 1)
-                       xy_coo[i].r = (i*radius)/(number-1); /* "randomize" initial */
+       for (i = 0; i < st->number; i++) {
+               new_rnd_coo(st,i);
+               if (st->number != 1)
+                       st->xy_coo[i].r = (i*st->radius)/(st->number-1); /* "randomize" initial */
                else
-                        xy_coo[i].r = 0;
-               xy_coo[i].r_change = speed + (i%2)*2*(-speed);  /* values a bit */
-               xy_coo[i].xmove = speed + (i%2)*2*(-speed);
-               xy_coo[i].ymove = speed + (i%2)*2*(-speed);
+                        st->xy_coo[i].r = 0;
+               st->xy_coo[i].r_change = st->speed + (i%2)*2*(-st->speed);      /* values a bit */
+               st->xy_coo[i].xmove = st->speed + (i%2)*2*(-st->speed);
+               st->xy_coo[i].ymove = st->speed + (i%2)*2*(-st->speed);
        }
-
 }
 
 /* example: initializes a "see-trough" matrix */
-/* static void make_null_lense(void)
+/* static void make_null_lense(struct state *st)
 {
        int i, j;
        for (i = 0; i < 2*radius+speed+2; i++) {
@@ -334,22 +369,23 @@ static void init_distort(Display *dpy, Window window)
        } 
 }
 */
-static void convert(void) {
+static void convert(struct state *st) 
+{
        int *p;
        int i, j;
-       fast_from = calloc(1, sizeof(int)*((buffer_map->bytes_per_line/bpp_size)*(2*radius+speed+2) + 2*radius+speed+2));
-       if (fast_from == NULL) {
+       st->fast_from = calloc(1, sizeof(int)*((st->buffer_map->bytes_per_line/st->bpp_size)*(2*st->radius+st->speed+2) + 2*st->radius+st->speed+2));
+       if (st->fast_from == NULL) {
                perror("distort");
                exit(EXIT_FAILURE);
        }
-       p = fast_from;
-       for (i = 0; i < 2*radius+speed+2; i++) {
-               for (j = 0; j < 2*radius+speed+2; j++) {
-                       *(p + i + j*buffer_map->bytes_per_line/bpp_size)
-                               = from[i][j][0] + xgwa.width*from[i][j][1];
-                       if (*(p + i + j*buffer_map->bytes_per_line/bpp_size) < 0
-                                       || *(p + i + j*buffer_map->bytes_per_line/bpp_size) >= orig_map->height*orig_map->width) {
-                               *(p + i + j*buffer_map->bytes_per_line/bpp_size) = 0;
+       p = st->fast_from;
+       for (i = 0; i < 2*st->radius+st->speed+2; i++) {
+               for (j = 0; j < 2*st->radius+st->speed+2; j++) {
+                       *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size)
+                               = st->from[i][j][0] + st->xgwa.width*st->from[i][j][1];
+                       if (*(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) < 0
+                                       || *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) >= st->orig_map->height*st->orig_map->width) {
+                               *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) = 0;
                        }
                }
        }
@@ -358,12 +394,12 @@ static void convert(void) {
 /* makes a lense with the Radius=loop and centred in
  * the point (radius, radius)
  */
-static void make_round_lense(int radius, int loop)
+static void make_round_lense(struct state *st, int radius, int loop)
 {
        int i, j;
 
-       for (i = 0; i < 2*radius+speed+2; i++) {
-               for(j = 0; j < ((0 == bpp_size) ? (2*radius+speed+2) : (buffer_map->bytes_per_line/bpp_size)); j++) {
+       for (i = 0; i < 2*radius+st->speed+2; i++) {
+               for(j = 0; j < ((0 == st->bpp_size) ? (2*radius+st->speed+2) : (st->buffer_map->bytes_per_line/st->bpp_size)); j++) {
                        double r, d;
                        r = sqrt ((i-radius)*(i-radius)+(j-radius)*(j-radius));
                        if (loop == 0)
@@ -373,7 +409,7 @@ static void make_round_lense(int radius, int loop)
 
                        if (r < loop-1) {
 
-                               if (vortex) { /* vortex-twist effect */
+                               if (st->vortex) { /* vortex-twist effect */
                                        double angle;
                /* this one-line formula for getting a nice rotation angle is borrowed
                 * (with permission) from the whirl plugin for gimp,
@@ -384,20 +420,20 @@ static void make_round_lense(int radius, int loop)
 
         /* Avoid atan2: DOMAIN error message */
                                        if ((radius-j) == 0.0 && (radius-i) == 0.0) {
-                                               from[i][j][0] = radius + cos(angle)*r;
-                                               from[i][j][1] = radius + sin(angle)*r;
+                                               st->from[i][j][0] = radius + cos(angle)*r;
+                                               st->from[i][j][1] = radius + sin(angle)*r;
                                        } else {
-                                               from[i][j][0] = radius +
+                                               st->from[i][j][0] = radius +
                                                        cos(angle - atan2(radius-j, -(radius-i)))*r;
-                                               from[i][j][1] = radius +
+                                               st->from[i][j][1] = radius +
                                                        sin(angle - atan2(radius-j, -(radius-i)))*r;
                                        }
-                                       if (magnify) {
+                                       if (st->magnify) {
                                                r = sin(d*M_PI_2);
-                                               if (blackhole && r != 0) /* blackhole effect */
+                                               if (st->blackhole && r != 0) /* blackhole effect */
                                                        r = 1/r;
-                                               from[i][j][0] = radius + (from[i][j][0]-radius)*r;
-                                               from[i][j][1] = radius + (from[i][j][1]-radius)*r;
+                                               st->from[i][j][0] = radius + (st->from[i][j][0]-radius)*r;
+                                               st->from[i][j][1] = radius + (st->from[i][j][1]-radius)*r;
                                        }
                                } else { /* default is to magnify */
                                        r = sin(d*M_PI_2);
@@ -406,23 +442,23 @@ static void make_round_lense(int radius, int loop)
         * distortion, a negative value sucks everything into a black hole
         */
                                /*      r = r*r; */
-                                       if (blackhole && r != 0) /* blackhole effect */
+                                       if (st->blackhole && r != 0) /* blackhole effect */
                                                r = 1/r;
                                                                        /* bubble effect (and blackhole) */
-                                       from[i][j][0] = radius + (i-radius)*r;
-                                       from[i][j][1] = radius + (j-radius)*r;
+                                       st->from[i][j][0] = radius + (i-radius)*r;
+                                       st->from[i][j][1] = radius + (j-radius)*r;
                                }
                        } else { /* not inside loop */
-                               from[i][j][0] = i;
-                               from[i][j][1] = j;
+                               st->from[i][j][0] = i;
+                               st->from[i][j][1] = j;
                        }
                }
        }
 
        /* this is really just a quick hack to keep both the compability mode with all depths and still
         * allow the custom optimized draw routines with the minimum amount of work */
-       if (0 != bpp_size) {
-               convert();
+       if (0 != st->bpp_size) {
+               convert(st);
        }
 }
 
@@ -430,28 +466,28 @@ static void make_round_lense(int radius, int loop)
 # define EXIT_FAILURE -1
 #endif
 
-static void allocate_lense(void)
+static void allocate_lense(struct state *st)
 {
        int i, j;
-       int s = ((0 != bpp_size) ? (buffer_map->bytes_per_line/bpp_size) : (2*radius+speed+2));
+       int s = ((0 != st->bpp_size) ? (st->buffer_map->bytes_per_line/st->bpp_size) : (2*st->radius+st->speed+2));
        /* maybe this should be redone so that from[][][] is in one block;
         * then pointers could be used instead of arrays in some places (and
         * maybe give a speedup - maybe also consume less memory)
         */
-       from = (int ***)malloc(s*sizeof(int **));
-       if (from == NULL) {
+       st->from = (int ***)malloc(s*sizeof(int **));
+       if (st->from == NULL) {
                perror("distort");
                exit(EXIT_FAILURE);
        }
        for (i = 0; i < s; i++) {
-               from[i] = (int **)malloc((2*radius+speed+2) * sizeof(int *));
-               if (from[i] == NULL) {
+               st->from[i] = (int **)malloc((2*st->radius+st->speed+2) * sizeof(int *));
+               if (st->from[i] == NULL) {
                        perror("distort");
                        exit(EXIT_FAILURE);
                }
                for (j = 0; j < s; j++) {
-                       from[i][j] = (int *)malloc(2 * sizeof(int));
-                       if (from[i][j] == NULL) {
+                       st->from[i][j] = (int *)malloc(2 * sizeof(int));
+                       if (st->from[i][j] == NULL) {
                                perror("distort");
                                exit(EXIT_FAILURE);
                        }
@@ -463,20 +499,20 @@ static void allocate_lense(void)
  * this is a double faced mem vs speed trade, it's faster, but eats
  * _a lot_ of mem for large radius (is there a bug here? I can't see it)
  */
-static void init_round_lense(void)
+static void init_round_lense(struct state *st)
 {
        int k;
 
-       if (effect == &swamp_thing) {
-               from_array = (int ****)malloc((radius+1)*sizeof(int ***));
-               for (k=0; k <= radius; k++) {
-                       allocate_lense();
-                       make_round_lense(radius, k);
-                       from_array[k] = from;
+       if (st->effect == &swamp_thing) {
+               st->from_array = (int ****)malloc((st->radius+1)*sizeof(int ***));
+               for (k=0; k <= st->radius; k++) {
+                       allocate_lense(st);
+                       make_round_lense(st, st->radius, k);
+                       st->from_array[k] = st->from;
                }
        } else { /* just allocate one from[][][] */
-               allocate_lense();
-               make_round_lense(radius,radius);
+               allocate_lense(st);
+               make_round_lense(st, st->radius,st->radius);
        }
 }
 
@@ -490,7 +526,8 @@ static void init_round_lense(void)
  * distort_matrix is a precalculated array of how to distort the matrix
  */
 
-static void fast_draw_8(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
+static void fast_draw_8(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
        CARD8 *u = (CARD8 *)dest->data;
        CARD8 *t = (CARD8 *)src->data + x + y*src->bytes_per_line/sizeof(CARD8);
 
@@ -500,7 +537,8 @@ static void fast_draw_8(XImage *src, XImage *dest, int x, int y, int *distort_ma
        }
 }
 
-static void fast_draw_16(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
+static void fast_draw_16(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
        CARD16 *u = (CARD16 *)dest->data;
        CARD16 *t = (CARD16 *)src->data + x + y*src->bytes_per_line/sizeof(CARD16);
 
@@ -510,7 +548,8 @@ static void fast_draw_16(XImage *src, XImage *dest, int x, int y, int *distort_m
        }
 }
 
-static void fast_draw_32(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
+static void fast_draw_32(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
        CARD32 *u = (CARD32 *)dest->data;
        CARD32 *t = (CARD32 *)src->data + x + y*src->bytes_per_line/sizeof(CARD32);
 
@@ -520,39 +559,40 @@ static void fast_draw_32(XImage *src, XImage *dest, int x, int y, int *distort_m
        }
 }
 
-static void generic_draw(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
+static void generic_draw(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
        int i, j;
        for (i = 0; i < dest->width; i++)
                for (j = 0; j < dest->height; j++)
-                       if (from[i][j][0] + x >= 0 &&
-                                       from[i][j][0] + x < src->width &&
-                                       from[i][j][1] + y >= 0 &&
-                                       from[i][j][1] + y < src->height)
+                       if (st->from[i][j][0] + x >= 0 &&
+                                       st->from[i][j][0] + x < src->width &&
+                                       st->from[i][j][1] + y >= 0 &&
+                                       st->from[i][j][1] + y < src->height)
                                XPutPixel(dest, i, j,
                                                XGetPixel(src,
-                                                       from[i][j][0] + x,
-                                                       from[i][j][1] + y));
+                                                       st->from[i][j][0] + x,
+                                                       st->from[i][j][1] + y));
 }
 
 /* generate an XImage of from[][][] and draw it on the screen */
-static void plain_draw(int k)
+static void plain_draw(struct state *st, int k)
 {
-       if (xy_coo[k].x+2*radius+speed+2 > orig_map->width ||
-                       xy_coo[k].y+2*radius+speed+2 > orig_map->height)
+       if (st->xy_coo[k].x+2*st->radius+st->speed+2 > st->orig_map->width ||
+                       st->xy_coo[k].y+2*st->radius+st->speed+2 > st->orig_map->height)
                return;
 
-       draw_routine(orig_map, buffer_map, xy_coo[k].x, xy_coo[k].y, fast_from);
+       st->draw_routine(st, st->orig_map, st->buffer_map, st->xy_coo[k].x, st->xy_coo[k].y, st->fast_from);
 
 # ifdef HAVE_XSHM_EXTENSION
-       if (use_shm)
-               XShmPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
-                               2*radius+speed+2, 2*radius+speed+2, False);
+       if (st->use_shm)
+               XShmPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+                               2*st->radius+st->speed+2, 2*st->radius+st->speed+2, False);
        else
 
-       if (!use_shm)
+       if (!st->use_shm)
 # endif
-               XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
-                               2*radius+speed+2, 2*radius+speed+2);
+               XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+                               2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
 
 }
 
@@ -563,67 +603,67 @@ static void plain_draw(int k)
  * it should be possible to use the from[][] to speed it up
  * (once I figure out the algorithm used :)
  */
-static void reflect_draw(int k)
+static void reflect_draw(struct state *st, int k)
 {
        int i, j;
        int     cx, cy;
-       int     ly, lysq, lx, ny, dist, rsq = radius * radius;
+       int     ly, lysq, lx, ny, dist, rsq = st->radius * st->radius;
 
-       cx = cy = radius;
-       if (xy_coo[k].ymove > 0)
-               cy += speed;
-       if (xy_coo[k].xmove > 0)
-               cx += speed;
+       cx = cy = st->radius;
+       if (st->xy_coo[k].ymove > 0)
+               cy += st->speed;
+       if (st->xy_coo[k].xmove > 0)
+               cx += st->speed;
 
-       for(i = 0 ; i < 2*radius+speed+2; i++) {
+       for(i = 0 ; i < 2*st->radius+st->speed+2; i++) {
                ly = i - cy;
                lysq = ly * ly;
-               ny = xy_coo[k].y + i;
-               if (ny >= orig_map->height) ny = orig_map->height-1;
-               for(j = 0 ; j < 2*radius+speed+2 ; j++) {
+               ny = st->xy_coo[k].y + i;
+               if (ny >= st->orig_map->height) ny = st->orig_map->height-1;
+               for(j = 0 ; j < 2*st->radius+st->speed+2 ; j++) {
                        lx = j - cx;
                        dist = lx * lx + lysq;
                        if (dist > rsq ||
-                               ly < -radius || ly > radius ||
-                               lx < -radius || lx > radius)
-                               XPutPixel( buffer_map, j, i,
-                                                  XGetPixel( orig_map, xy_coo[k].x + j, ny ));
+                               ly < -st->radius || ly > st->radius ||
+                               lx < -st->radius || lx > st->radius)
+                               XPutPixel( st->buffer_map, j, i,
+                                                  XGetPixel( st->orig_map, st->xy_coo[k].x + j, ny ));
                        else if (dist == 0)
-                               XPutPixel( buffer_map, j, i, black_pixel );
+                               XPutPixel( st->buffer_map, j, i, st->black_pixel );
                        else {
-                               int     x = xy_coo[k].x + cx + (lx * rsq / dist);
-                               int     y = xy_coo[k].y + cy + (ly * rsq / dist);
-                               if (x < 0 || x >= xgwa.width ||
-                                       y < 0 || y >= xgwa.height)
-                                       XPutPixel( buffer_map, j, i, black_pixel );
+                               int     x = st->xy_coo[k].x + cx + (lx * rsq / dist);
+                               int     y = st->xy_coo[k].y + cy + (ly * rsq / dist);
+                               if (x < 0 || x >= st->xgwa.width ||
+                                       y < 0 || y >= st->xgwa.height)
+                                       XPutPixel( st->buffer_map, j, i, st->black_pixel );
                                else
-                                       XPutPixel( buffer_map, j, i,
-                                                          XGetPixel( orig_map, x, y ));
+                                       XPutPixel( st->buffer_map, j, i,
+                                                          XGetPixel( st->orig_map, x, y ));
                        }
                }
        }
 
-       XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
-                       2*radius+speed+2, 2*radius+speed+2);
+       XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+                       2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
 }
 
 /* create a new, random coordinate, that won't interfer with any other
  * coordinates, as the drawing routines would be significantly slowed
  * down if they were to handle serveral layers of distortions
  */
-static void new_rnd_coo(int k)
+static void new_rnd_coo(struct state *st, int k)
 {
        int i;
 
-       xy_coo[k].x = (random() % (xgwa.width-2*radius));
-       xy_coo[k].y = (random() % (xgwa.height-2*radius));
+       st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
+       st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
        
-       for (i = 0; i < number; i++) {
+       for (i = 0; i < st->number; i++) {
                if (i != k) {
-                       if ((abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius+speed+2)
-                        && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius+speed+2)) {
-                               xy_coo[k].x = (random() % (xgwa.width-2*radius));
-                               xy_coo[k].y = (random() % (xgwa.height-2*radius));
+                       if ((abs(st->xy_coo[k].x - st->xy_coo[i].x) <= 2*st->radius+st->speed+2)
+                        && (abs(st->xy_coo[k].y - st->xy_coo[i].y) <= 2*st->radius+st->speed+2)) {
+                               st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
+                               st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
                                i=-1; /* ugly */
                        } 
                }
@@ -631,24 +671,24 @@ static void new_rnd_coo(int k)
 }
 
 /* move lens and handle bounces with walls and other lenses */
-static void move_lense(int k)
+static void move_lense(struct state *st, int k)
 {
        int i;
 
-       if (xy_coo[k].x + 2*radius + speed + 2 >= xgwa.width)
-               xy_coo[k].xmove = -abs(xy_coo[k].xmove);
-       if (xy_coo[k].x <= speed) 
-               xy_coo[k].xmove = abs(xy_coo[k].xmove);
-       if (xy_coo[k].y + 2*radius + speed + 2 >= xgwa.height)
-               xy_coo[k].ymove = -abs(xy_coo[k].ymove);
-       if (xy_coo[k].y <= speed)
-               xy_coo[k].ymove = abs(xy_coo[k].ymove);
+       if (st->xy_coo[k].x + 2*st->radius + st->speed + 2 >= st->xgwa.width)
+               st->xy_coo[k].xmove = -abs(st->xy_coo[k].xmove);
+       if (st->xy_coo[k].x <= st->speed) 
+               st->xy_coo[k].xmove = abs(st->xy_coo[k].xmove);
+       if (st->xy_coo[k].y + 2*st->radius + st->speed + 2 >= st->xgwa.height)
+               st->xy_coo[k].ymove = -abs(st->xy_coo[k].ymove);
+       if (st->xy_coo[k].y <= st->speed)
+               st->xy_coo[k].ymove = abs(st->xy_coo[k].ymove);
 
-       xy_coo[k].x = xy_coo[k].x + xy_coo[k].xmove;
-       xy_coo[k].y = xy_coo[k].y + xy_coo[k].ymove;
+       st->xy_coo[k].x = st->xy_coo[k].x + st->xy_coo[k].xmove;
+       st->xy_coo[k].y = st->xy_coo[k].y + st->xy_coo[k].ymove;
 
        /* bounce against othe lenses */
-       for (i = 0; i < number; i++) {
+       for (i = 0; i < st->number; i++) {
                if ((i != k)
                
 /* This commented test is for rectangular lenses (not currently used) and
@@ -656,54 +696,100 @@ static void move_lense(int k)
                && (abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius)
                && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius)) { */
 
-               && ((xy_coo[k].x - xy_coo[i].x)*(xy_coo[k].x - xy_coo[i].x)
-                 + (xy_coo[k].y - xy_coo[i].y)*(xy_coo[k].y - xy_coo[i].y)
-                       <= 2*radius*2*radius)) {
+               && ((st->xy_coo[k].x - st->xy_coo[i].x)*(st->xy_coo[k].x - st->xy_coo[i].x)
+                 + (st->xy_coo[k].y - st->xy_coo[i].y)*(st->xy_coo[k].y - st->xy_coo[i].y)
+                       <= 2*st->radius*2*st->radius)) {
 
                        int x, y;
-                       x = xy_coo[k].xmove;
-                       y = xy_coo[k].ymove;
-                       xy_coo[k].xmove = xy_coo[i].xmove;
-                       xy_coo[k].ymove = xy_coo[i].ymove;
-                       xy_coo[i].xmove = x;
-                       xy_coo[i].ymove = y;
+                       x = st->xy_coo[k].xmove;
+                       y = st->xy_coo[k].ymove;
+                       st->xy_coo[k].xmove = st->xy_coo[i].xmove;
+                       st->xy_coo[k].ymove = st->xy_coo[i].ymove;
+                       st->xy_coo[i].xmove = x;
+                       st->xy_coo[i].ymove = y;
                }
        }
 
 }
 
 /* make xy_coo[k] grow/shrink */
-static void swamp_thing(int k)
+static void swamp_thing(struct state *st, int k)
 {
-       if (xy_coo[k].r >= radius)
-               xy_coo[k].r_change = -abs(xy_coo[k].r_change);
+       if (st->xy_coo[k].r >= st->radius)
+               st->xy_coo[k].r_change = -abs(st->xy_coo[k].r_change);
        
-       if (xy_coo[k].r <= 0) {
-               from = from_array[0];
-               draw(k); 
-               xy_coo[k].r_change = abs(xy_coo[k].r_change);
-               new_rnd_coo(k);
-               xy_coo[k].r=xy_coo[k].r_change;
+       if (st->xy_coo[k].r <= 0) {
+               st->from = st->from_array[0];
+               st->draw(st,k); 
+               st->xy_coo[k].r_change = abs(st->xy_coo[k].r_change);
+               new_rnd_coo(st,k);
+               st->xy_coo[k].r=st->xy_coo[k].r_change;
                return;
        }
 
-       xy_coo[k].r = xy_coo[k].r + xy_coo[k].r_change;
+       st->xy_coo[k].r = st->xy_coo[k].r + st->xy_coo[k].r_change;
 
-       if (xy_coo[k].r >= radius)
-               xy_coo[k].r = radius;
-       if (xy_coo[k].r <= 0)
-               xy_coo[k].r=0;
+       if (st->xy_coo[k].r >= st->radius)
+               st->xy_coo[k].r = st->radius;
+       if (st->xy_coo[k].r <= 0)
+               st->xy_coo[k].r=0;
 
-       from = from_array[xy_coo[k].r];
+       st->from = st->from_array[st->xy_coo[k].r];
 }
 
 
-\f
+static unsigned long
+distort_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  int k;
+
+  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 */
+        distort_finish_loading (st);
+      return st->delay;
+    }
+
+  for (k = 0; k < st->number; k++) {
+    st->effect(st,k);
+    st->draw(st,k);
+  }
+  return st->delay;
+}
+
+static void
+distort_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+distort_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
 
-char *progclass = "Distort";
+static void
+distort_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  XFreeGC (st->dpy, st->gc);
+  if (st->orig_map) XDestroyImage (st->orig_map);
+  if (st->buffer_map) XDestroyImage (st->buffer_map);
+  if (st->from) free (st->from);
+  if (st->fast_from) free (st->fast_from);
+  if (st->from_array) free (st->from_array);
+  free (st);
+}
 
-char *defaults [] = {
+
+\f
+
+static const char *distort_defaults [] = {
        "*dontClearRoot:                True",
+       "*background:                   Black",
 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
        "*visualID:                     Best",
 #endif
@@ -712,52 +798,38 @@ char *defaults [] = {
        "*radius:                       0",
        "*speed:                        0",
        "*number:                       0",
+       "*slow:                         False",
        "*vortex:                       False",
        "*magnify:                      False",
-       "*swamp:                        False",
-       "*bounce:                       False",
        "*reflect:                      False",
        "*blackhole:            False",
+       "*effect:                   none",
 #ifdef HAVE_XSHM_EXTENSION
        "*useSHM:                       False",         /* xshm turns out not to help. */
 #endif /* HAVE_XSHM_EXTENSION */
        0
 };
 
-XrmOptionDescRec options [] = {
-       { "-delay",     ".delay",       XrmoptionSepArg, 0 },
-       { "-radius",    ".radius",      XrmoptionSepArg, 0 },
-       { "-speed",     ".speed",       XrmoptionSepArg, 0 },
-       { "-number",    ".number",      XrmoptionSepArg, 0 },
-       { "-swamp",     ".swamp",       XrmoptionNoArg, "True" },
-       { "-bounce",    ".bounce",      XrmoptionNoArg, "True" },
-       { "-reflect",   ".reflect",     XrmoptionNoArg, "True" },
-       { "-vortex",    ".vortex",      XrmoptionNoArg, "True" },
-       { "-magnify",   ".magnify",     XrmoptionNoArg, "True" },
-       { "-blackhole", ".blackhole",   XrmoptionNoArg, "True" },
-       { "-slow",      ".slow",        XrmoptionNoArg, "True" },
+static XrmOptionDescRec distort_options [] = {
+  { "-delay",     ".delay",       XrmoptionSepArg, 0 },
+  { "-radius",    ".radius",      XrmoptionSepArg, 0 },
+  { "-speed",     ".speed",       XrmoptionSepArg, 0 },
+  { "-number",    ".number",      XrmoptionSepArg, 0 },
+
+  { "-effect",    ".effect",      XrmoptionSepArg, 0 },
+  { "-swamp",     ".effect",      XrmoptionNoArg, "swamp"  },
+  { "-bounce",    ".effect",      XrmoptionNoArg, "bounce" },
+
+  { "-reflect",   ".reflect",     XrmoptionNoArg, "True" },
+  { "-vortex",    ".vortex",      XrmoptionNoArg, "True" },
+  { "-magnify",   ".magnify",     XrmoptionNoArg, "True" },
+  { "-blackhole", ".blackhole",   XrmoptionNoArg, "True" },
+  { "-slow",      ".slow",        XrmoptionNoArg, "True" },
 #ifdef HAVE_XSHM_EXTENSION
-       { "-shm",               ".useSHM",      XrmoptionNoArg, "True" },
-       { "-no-shm",    ".useSHM",      XrmoptionNoArg, "False" },
+  { "-shm",       ".useSHM",      XrmoptionNoArg, "True" },
+  { "-no-shm",    ".useSHM",      XrmoptionNoArg, "False" },
 #endif /* HAVE_XSHM_EXTENSION */
-       { 0, 0, 0, 0 }
+  { 0, 0, 0, 0 }
 };
 
-
-void screenhack(Display *dpy, Window window)
-{
-       int k;
-
-       init_distort (dpy, window);
-       while (1) {
-               for (k = 0; k < number; k++) {
-                       effect(k);
-                       draw(k);
-               }
-
-               XSync(dpy, False);
-        screenhack_handle_events (dpy);
-               if (delay) usleep(delay);
-       }
-
-}
+XSCREENSAVER_MODULE ("Distort", distort)