From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / twang.c
index ce22944fca1c22b38cceacb54a1030f856961813..ae589ad662c75a8e24fbccaf33039ecc2fafb144 100644 (file)
 
 #include <math.h>
 #include "screenhack.h"
-
-#ifdef HAVE_XSHM_EXTENSION
 #include "xshm.h"
-#endif
 
 #define FLOAT double
 
@@ -48,6 +45,7 @@ struct state {
   Window window;
 
   int delay;                   /* delay (usec) between iterations */
+  int duration;                        /* time (sec) before loading new image */
   int maxColumns;              /* the maximum number of columns of tiles */
   int maxRows;                 /* the maximum number of rows of tiles */
   int tileSize;                        /* the size (width and height) of a tile */
@@ -61,7 +59,6 @@ struct state {
   Screen *screen;                 /* the screen to draw on */
   XImage *sourceImage;            /* image source of stuff to draw */
   XImage *workImage;              /* work area image, used when rendering */
-  XImage *backgroundImage;      /* image filled with background pixels */
 
   GC backgroundGC;              /* GC for the background color */
   GC foregroundGC;              /* GC for the foreground color */
@@ -76,12 +73,11 @@ struct state {
   Tile **sortedTiles; /* array of tile pointers, sorted by zoom */
   int tileCount;     /* total number of tiles */
 
+  time_t start_time;
   async_load_state *img_loader;
+  Pixmap pm;
 
-  Bool useShm;         /* whether or not to use xshm */
-#ifdef HAVE_XSHM_EXTENSION
   XShmSegmentInfo shmInfo;
-#endif
 };
 
 
@@ -102,46 +98,39 @@ struct state {
  */
 
 /* grab the source image */
-static void grabImage_start (struct state *st, XWindowAttributes *xwa)
+static void
+grabImage_start (struct state *st, XWindowAttributes *xwa)
 {
-    XFillRectangle (st->dpy, st->window, st->backgroundGC, 0, 0, 
-                   st->windowWidth, st->windowHeight);
-    st->backgroundImage = 
-       XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight,
-                  ~0L, ZPixmap);
-
+    /* 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,
+                            xwa->width, xwa->height, xwa->depth);
+
+    st->start_time = time ((time_t *) 0);
     st->img_loader = load_image_async_simple (0, xwa->screen, st->window,
-                                              st->window, 0, 0);
+                                              st->pm, 0, 0);
 }
 
-static void grabImage_done (struct state *st)
+static void
+grabImage_done (struct state *st)
 {
-   XWindowAttributes xwa;
-   XGetWindowAttributes (st->dpy, st->window, &xwa);
+    XWindowAttributes xwa;
+    XGetWindowAttributes (st->dpy, st->window, &xwa);
 
-    st->sourceImage = XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight,
+    st->start_time = time ((time_t *) 0);
+    if (st->sourceImage) XDestroyImage (st->sourceImage);
+    st->sourceImage = XGetImage (st->dpy, st->pm, 0, 0,
+                                 st->windowWidth, st->windowHeight,
                             ~0L, ZPixmap);
 
-#ifdef HAVE_XSHM_EXTENSION
-    st->workImage = NULL;
-    if (st->useShm) 
-    {
-       st->workImage = create_xshm_image (st->dpy, xwa.visual, xwa.depth,
-                                      ZPixmap, 0, &st->shmInfo, 
-                                      st->windowWidth, st->windowHeight);
-       if (!st->workImage) 
-       {
-           st->useShm = False;
-           fprintf (stderr, "create_xshm_image failed\n");
-       }
-    }
-
-    if (st->workImage == NULL)
-#endif /* HAVE_XSHM_EXTENSION */
+    if (st->workImage) destroy_xshm_image (st->dpy, st->workImage,
+                                           &st->shmInfo);
 
-       /* just use XSubImage to acquire the right visual, depth, etc;
-        * easier than the other alternatives */
-       st->workImage = XSubImage (st->sourceImage, 0, 0, st->windowWidth, st->windowHeight);
+    st->workImage = create_xshm_image (st->dpy, xwa.visual, xwa.depth,
+                                       ZPixmap, &st->shmInfo,
+                                       st->windowWidth, st->windowHeight);
 }
 
 /* set up the system */
@@ -515,7 +504,8 @@ static void renderFrame (struct state *st)
 {
     int n;
 
-    memcpy (st->workImage->data, st->backgroundImage->data, 
+    /* This assumes black is zero. */
+    memset (st->workImage->data, 0, 
            st->workImage->bytes_per_line * st->workImage->height);
 
     sortTiles (st);
@@ -525,14 +515,8 @@ static void renderFrame (struct state *st)
        renderTile (st, st->sortedTiles[n]);
     }
 
-#ifdef HAVE_XSHM_EXTENSION
-    if (st->useShm)
-       XShmPutImage (st->dpy, st->window, st->backgroundGC, st->workImage, 0, 0, 0, 0,
-                     st->windowWidth, st->windowHeight, False);
-    else
-#endif /* HAVE_XSHM_EXTENSION */
-       XPutImage (st->dpy, st->window, st->backgroundGC, st->workImage, 
-                  0, 0, 0, 0, st->windowWidth, st->windowHeight);
+    put_xshm_image (st->dpy, st->window, st->backgroundGC, st->workImage, 0, 0, 0, 0,
+                    st->windowWidth, st->windowHeight, &st->shmInfo);
 }
 
 /* set up the model */
@@ -554,8 +538,8 @@ static void setupModel (struct state *st)
        st->tileSize = st->windowHeight / 2;
     }
 
-    st->columns = st->windowWidth / st->tileSize;
-    st->rows = st->windowHeight / st->tileSize;
+    st->columns = st->tileSize ? st->windowWidth / st->tileSize : 0;
+    st->rows = st->tileSize ? st->windowHeight / st->tileSize : 0;
 
     if ((st->maxColumns != 0) && (st->columns > st->maxColumns))
     {
@@ -572,6 +556,7 @@ static void setupModel (struct state *st)
     leftX = (st->windowWidth - (st->columns * st->tileSize) + st->tileSize) / 2;
     topY = (st->windowHeight - (st->rows * st->tileSize) + st->tileSize) / 2;
 
+    if (st->tileCount < 1) st->tileCount = 1;
     st->tiles = calloc (st->tileCount, sizeof (Tile));
     st->sortedTiles = calloc (st->tileCount, sizeof (Tile *));
 
@@ -605,6 +590,13 @@ twang_draw (Display *dpy, Window window, void *closure)
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t *) 0)) {
+    XWindowAttributes xgwa;
+    XGetWindowAttributes (st->dpy, st->window, &xgwa);
+    grabImage_start (st, &xgwa);
+    return st->delay;
+  }
 
   modelEvents (st);
   updateModel (st);
@@ -622,6 +614,12 @@ twang_reshape (Display *dpy, Window window, void *closure,
 static Bool
 twang_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
+  struct state *st = (struct state *) closure;
+  if (screenhack_event_helper (dpy, window, event))
+    {
+      st->start_time = 0;
+      return True;
+    }
   return False;
 }
 
@@ -629,6 +627,7 @@ static void
 twang_free (Display *dpy, Window window, void *closure)
 {
   struct state *st = (struct state *) closure;
+  if (st->pm) XFreePixmap (dpy, st->pm);
   free (st);
 }
 
@@ -655,6 +654,9 @@ static void initParams (struct state *st)
        problems = 1;
     }
 
+    st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+    if (st->duration < 1) st->duration = 1;
+
     st->eventChance = get_float_resource (st->dpy, "eventChance", "Double");
     if ((st->eventChance < 0.0) || (st->eventChance > 1.0))
     {
@@ -704,10 +706,6 @@ static void initParams (struct state *st)
        problems = 1;
     }
 
-#ifdef HAVE_XSHM_EXTENSION
-    st->useShm = get_boolean_resource (st->dpy, "useSHM", "Boolean");
-#endif
-
     if (problems)
     {
        exit (1);
@@ -735,6 +733,7 @@ static const char *twang_defaults [] = {
     "*borderColor:      blue",
     "*borderWidth:     3",
     "*delay:           10000",
+    "*duration:                120",
     "*eventChance:      0.01",
     "*friction:                0.05",
     "*maxColumns:       0",
@@ -746,6 +745,10 @@ static const char *twang_defaults [] = {
     "*useSHM: True",
 #else
     "*useSHM: False",
+#endif
+#ifdef HAVE_MOBILE
+  "*ignoreRotation: True",
+  "*rotateImages:   True",
 #endif
     0
 };
@@ -754,6 +757,7 @@ static XrmOptionDescRec twang_options [] = {
   { "-border-color",     ".borderColor",    XrmoptionSepArg, 0 },
   { "-border-width",     ".borderWidth",    XrmoptionSepArg, 0 },
   { "-delay",            ".delay",          XrmoptionSepArg, 0 },
+  { "-duration",        ".duration",       XrmoptionSepArg, 0 },
   { "-event-chance",     ".eventChance",    XrmoptionSepArg, 0 },
   { "-friction",         ".friction",       XrmoptionSepArg, 0 },
   { "-max-columns",      ".maxColumns",     XrmoptionSepArg, 0 },