From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / distort.c
index 7755f0283fda8c722c23ef29b1c2e28a06a4dd0c..54439d44733f03b3aa29843cf493845df34ff0cf 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- mode: C; tab-width: 4 -*-
- * xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1992-2014 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
  *    on wood).
  * 08 Oct 1999 Jonas Munsin (jmunsin@iki.fi)
  *     Corrected several bugs causing references beyond allocated memory.
+ * 09 Oct 2016 Dave Odell (dmo2118@gmail.com)
+ *  Updated for new xshm.c.
  */
 
 #include <math.h>
+#include <time.h>
 #include "screenhack.h"
 /*#include <X11/Xmd.h>*/
-
-#ifdef HAVE_XSHM_EXTENSION
 # include "xshm.h"
-#endif /* HAVE_XSHM_EXTENSION */
 
 #define CARD32 unsigned int
 #define CARD16 unsigned short
@@ -61,6 +61,9 @@ struct state {
   struct coo xy_coo[10];
 
   int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
+  int duration;
+  time_t start_time;
+
   XWindowAttributes xgwa;
   GC gc;
   unsigned long black_pixel;
@@ -74,16 +77,14 @@ struct state {
 
   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;
+  Pixmap pm;
 };
 
 
@@ -102,33 +103,31 @@ 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)
+static void
+distort_reset (struct state *st)
 {
-  struct state *st = (struct state *) calloc (1, sizeof(*st));
-       XGCValues gcv;
-       long gcflags;
-       int i;
     char *s;
+    int i;
 
-    st->dpy = dpy;
-    st->window = window;
+    st->start_time = 0;
+
+       XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
 
        st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+    st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
        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
-       st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
-#endif /* HAVE_XSHM_EXTENSION */
-       
        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 (st->delay < 0) st->delay = 0;
+    if (st->duration < 1) st->duration = 1;
+
     st->effect = NULL;
     s = get_string_resource(st->dpy, "effect", "String");
        if (s && !strcasecmp(s,"swamp"))
@@ -140,29 +139,27 @@ distort_init (Display *dpy, Window window)
     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
- * -radius 50 -number 4 -speed 1 -vortex
- * -radius 50 -number 4 -speed 1 -vortex -magnify
- * -radius 50 -number 4 -speed 1 -vortex -magnify -blackhole
- * -radius 100 -number 1 -speed 2 -bounce
- * -radius 100 -number 1 -speed 2 -blackhole
- * -radius 100 -number 1 -speed 2 -vortex
- * -radius 100 -number 1 -speed 2 -vortex -magnify
- * -radius 100 -number 1 -speed 2 -vortex -magnify -blackhole
+ * -radius 125 -number 4 -speed 1 -bounce
+ * -radius 125 -number 4 -speed 1 -blackhole
+ * -radius 125 -number 4 -speed 1 -vortex
+ * -radius 125 -number 4 -speed 1 -vortex -magnify
+ * -radius 125 -number 4 -speed 1 -vortex -magnify -blackhole
+ * -radius 250 -number 1 -speed 2 -bounce
+ * -radius 250 -number 1 -speed 2 -blackhole
+ * -radius 250 -number 1 -speed 2 -vortex
+ * -radius 250 -number 1 -speed 2 -vortex -magnify
+ * -radius 250 -number 1 -speed 2 -vortex -magnify -blackhole
  * -radius 80 -number 1 -speed 2 -reflect
- * -radius 50 -number 3 -speed 2 -reflect
+ * -radius 125 -number 3 -speed 2 -reflect
  * jwz: not these
- *   -radius 50 -number 4 -speed 2 -swamp
- *   -radius 50 -number 4 -speed 2 -swamp -blackhole
- *   -radius 50 -number 4 -speed 2 -swamp -vortex
- *   -radius 50 -number 4 -speed 2 -swamp -vortex -magnify
- *   -radius 50 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
+ *   -radius 125 -number 4 -speed 2 -swamp
+ *   -radius 125 -number 4 -speed 2 -swamp -blackhole
+ *   -radius 125 -number 4 -speed 2 -swamp -vortex
+ *   -radius 125 -number 4 -speed 2 -swamp -vortex -magnify
+ *   -radius 125 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
  */
                
                i = (random() % 12 /* 17 */);
@@ -171,74 +168,70 @@ distort_init (Display *dpy, Window window)
 
                switch (i) {
                        case 0:
-                               st->radius=50;st->number=4;st->speed=1;
+                               st->radius=125;st->number=4;st->speed=1;
                                st->effect=&move_lense;break;
                        case 1:
-                               st->radius=50;st->number=4;st->speed=1;st->blackhole=1;
+                               st->radius=125;st->number=4;st->speed=1;st->blackhole=1;
                                st->effect=&move_lense;break;
                        case 2:
-                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;
+                               st->radius=125;st->number=4;st->speed=1;st->vortex=1;
                                st->effect=&move_lense;break;
                        case 3:
-                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;
+                               st->radius=125;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;
                                st->effect=&move_lense;break;
                        case 4:
-                               st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;st->blackhole=1;
+                               st->radius=125;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;st->blackhole=1;
                                st->effect=&move_lense;break;
                        case 5:
-                               st->radius=100;st->number=1;st->speed=2;
+                               st->radius=250;st->number=1;st->speed=2;
                                st->effect=&move_lense;break;
                        case 6:
-                               st->radius=100;st->number=1;st->speed=2;st->blackhole=1;
+                               st->radius=250;st->number=1;st->speed=2;st->blackhole=1;
                                st->effect=&move_lense;break;
                        case 7:
-                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;
+                               st->radius=250;st->number=1;st->speed=2;st->vortex=1;
                                st->effect=&move_lense;break;
                        case 8:
-                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;
+                               st->radius=250;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;
                                st->effect=&move_lense;break;
                        case 9:
-                               st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
+                               st->radius=250;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
                                st->effect=&move_lense;break;
 
                        case 10:
                                st->radius=80;st->number=1;st->speed=2;st->reflect=1;
                                st->draw = &reflect_draw;st->effect = &move_lense;break;
                        case 11:
-                               st->radius=50;st->number=4;st->speed=2;st->reflect=1;
+                               st->radius=125;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:
-                               st->radius=50;st->number=4;st->speed=2;
+                               st->radius=125;st->number=4;st->speed=2;
                                effect=&swamp_thing;break;
                        case 13:
-                               st->radius=50;st->number=4;st->speed=2;st->blackhole=1;
+                               st->radius=125;st->number=4;st->speed=2;st->blackhole=1;
                                effect=&swamp_thing;break;
                        case 14:
-                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;
+                               st->radius=125;st->number=4;st->speed=2;st->vortex=1;
                                effect=&swamp_thing;break;
                        case 15:
-                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;
+                               st->radius=125;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;
                                effect=&swamp_thing;break;
                        case 16:
-                               st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
+                               st->radius=125;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
                                effect=&swamp_thing;break;
 #endif
 
             default:
                 abort(); break;
                }
-
-        /* but if the window is small, reduce default radius */
-        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 (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;
+    if (st->radius > st->xgwa.width  * 0.3) st->radius = st->xgwa.width  * 0.3;
+    if (st->radius > st->xgwa.height * 0.3) st->radius = st->xgwa.height * 0.3;
 
 
     /* -swamp mode consumes vast amounts of memory, proportional to radius --
@@ -265,6 +258,19 @@ distort_init (Display *dpy, Window window)
        }
        if (st->draw == NULL)
                st->draw = &plain_draw;
+}
+
+static void *
+distort_init (Display *dpy, Window window)
+{
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+       XGCValues gcv;
+       long gcflags;
+
+    st->dpy = dpy;
+    st->window = window;
+
+    distort_reset (st);
 
        st->black_pixel = BlackPixelOfScreen( st->xgwa.screen );
 
@@ -275,8 +281,16 @@ distort_init (Display *dpy, Window window)
                gcflags |= GCSubwindowMode;
        st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
 
+    /* On MacOS X11, XGetImage on a Window often gets an inexplicable BadMatch,
+       possibly due to the window manager having occluded something?  It seems
+       nondeterministic. Loading the image into a pixmap instead fixes it. */
+    if (st->pm) XFreePixmap (st->dpy, st->pm);
+    st->pm = XCreatePixmap (st->dpy, st->window,
+                            st->xgwa.width, st->xgwa.height, st->xgwa.depth);
+
     st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
-                                              st->window, 0, 0);
+                                              st->pm, 0, 0);
+    st->start_time = time ((time_t *) 0);
     return st;
 }
 
@@ -285,9 +299,15 @@ distort_finish_loading (struct state *st)
 {
     int i;
 
-       st->buffer_map = 0;
-       st->orig_map = XGetImage(st->dpy, st->window, 0, 0, st->xgwa.width, st->xgwa.height,
-                                                ~0L, ZPixmap);
+    st->start_time = time ((time_t *) 0);
+
+    if (! st->pm) abort();
+    XClearWindow (st->dpy, st->window);
+    XCopyArea (st->dpy, st->pm, st->window, st->gc, 
+               0, 0, st->xgwa.width, st->xgwa.height, 0, 0);
+       st->orig_map = XGetImage(st->dpy, st->pm, 0, 0,
+                             st->xgwa.width, st->xgwa.height,
+                             ~0L, ZPixmap);
        st->buffer_map_cache = malloc(sizeof(unsigned long)*(2*st->radius+st->speed+2)*(2*st->radius+st->speed+2));
 
        if (st->buffer_map_cache == NULL) {
@@ -295,28 +315,10 @@ distort_finish_loading (struct state *st)
                exit(EXIT_FAILURE);
        }
 
-# ifdef HAVE_XSHM_EXTENSION
-
-       if (st->use_shm)
-         {
-               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 (!st->buffer_map)
-         {
-               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);
-               st->buffer_map->data = (char *)
-                 calloc(st->buffer_map->height, st->buffer_map->bytes_per_line);
-       }
+       st->buffer_map = create_xshm_image(st->dpy, st->xgwa.visual, st->orig_map->depth,
+                                          ZPixmap, &st->shm_info,
+                                          2*st->radius + st->speed + 2,
+                                          2*st->radius + st->speed + 2);
 
        if ((st->buffer_map->byte_order == st->orig_map->byte_order)
                        && (st->buffer_map->depth == st->orig_map->depth)
@@ -583,17 +585,8 @@ static void plain_draw(struct state *st, int k)
 
        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 (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 (!st->use_shm)
-# endif
-               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);
-
+       put_xshm_image(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, &st->shm_info);
 }
 
 
@@ -654,6 +647,7 @@ static void reflect_draw(struct state *st, int k)
 static void new_rnd_coo(struct state *st, int k)
 {
        int i;
+    int loop = 0;
 
        st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
        st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
@@ -667,6 +661,7 @@ static void new_rnd_coo(struct state *st, int k)
                                i=-1; /* ugly */
                        } 
                }
+        if (loop++ > 1000) return;  /* let's not get stuck */
        }
 }
 
@@ -747,11 +742,22 @@ distort_draw (Display *dpy, Window window, void *closure)
   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 */
+      if (! st->img_loader)  /* just finished */
         distort_finish_loading (st);
+      }
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t *) 0)) {
+    if (st->pm) XFreePixmap (st->dpy, st->pm);
+    st->pm = XCreatePixmap (st->dpy, st->window,
+                            st->xgwa.width, st->xgwa.height, st->xgwa.depth);
+    st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+                                              st->pm, 0, 0);
+    return st->delay;
+  }
+
   for (k = 0; k < st->number; k++) {
     st->effect(st,k);
     st->draw(st,k);
@@ -763,11 +769,24 @@ static void
 distort_reshape (Display *dpy, Window window, void *closure, 
                  unsigned int w, unsigned int h)
 {
+  struct state *st = (struct state *) closure;
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+  /* XClearWindow (dpy, window); */
+  /* Why doesn't this work? */
+  if (st->orig_map)  /* created in distort_finish_loading, might be early */
+    XPutImage (st->dpy, st->window, st->gc, st->orig_map,
+               0, 0, st->orig_map->width, st->orig_map->height, 0, 0);
 }
 
 static Bool
 distort_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
+  struct state *st = (struct state *) closure;
+  if (screenhack_event_helper (dpy, window, event))
+    {
+      distort_reset(st);
+      return True;
+    }
   return False;
 }
 
@@ -776,8 +795,9 @@ distort_free (Display *dpy, Window window, void *closure)
 {
   struct state *st = (struct state *) closure;
   XFreeGC (st->dpy, st->gc);
+  if (st->pm) XFreePixmap (dpy, st->pm);
   if (st->orig_map) XDestroyImage (st->orig_map);
-  if (st->buffer_map) XDestroyImage (st->buffer_map);
+  if (st->buffer_map) destroy_xshm_image (st->dpy, st->buffer_map, &st->shm_info);
   if (st->from) free (st->from);
   if (st->fast_from) free (st->fast_from);
   if (st->from_array) free (st->from_array);
@@ -790,11 +810,13 @@ distort_free (Display *dpy, Window window, void *closure)
 static const char *distort_defaults [] = {
        "*dontClearRoot:                True",
        "*background:                   Black",
+    "*fpsSolid:                                true",
 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
        "*visualID:                     Best",
 #endif
 
        "*delay:                        20000",
+    "*duration:                        120",
        "*radius:                       0",
        "*speed:                        0",
        "*number:                       0",
@@ -807,11 +829,16 @@ static const char *distort_defaults [] = {
 #ifdef HAVE_XSHM_EXTENSION
        "*useSHM:                       False",         /* xshm turns out not to help. */
 #endif /* HAVE_XSHM_EXTENSION */
+#ifdef HAVE_MOBILE
+  "*ignoreRotation:     True",
+  "*rotateImages:       True",
+#endif
        0
 };
 
 static XrmOptionDescRec distort_options [] = {
   { "-delay",     ".delay",       XrmoptionSepArg, 0 },
+  { "-duration",  ".duration",   XrmoptionSepArg, 0 },
   { "-radius",    ".radius",      XrmoptionSepArg, 0 },
   { "-speed",     ".speed",       XrmoptionSepArg, 0 },
   { "-number",    ".number",      XrmoptionSepArg, 0 },