]> git.hungrycats.org Git - xscreensaver/blobdiff - hacks/distort.c
From https://www.jwz.org/xscreensaver/xscreensaver-6.09.tar.gz
[xscreensaver] / hacks / distort.c
index 28593f06f3aa8793c56001ab6543f62fff09cd9d..2795119fc5b073311d56d2e2e773900e1bd55a23 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- mode: C; tab-width: 4 -*-
- * xscreensaver, Copyright (c) 1992-2014 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1992-2018 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
@@ -74,19 +74,18 @@ struct state {
   int ***from;
   int ****from_array;
   int *fast_from;
+  int from_size;
 
   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;
 };
 
 
@@ -140,6 +139,7 @@ distort_reset (struct state *st)
       ;
     else if (s && *s)
       fprintf(stderr,"%s: bogus effect: %s\n", progname, s);
+    if (s) free (s);
 
        if (st->effect == NULL && st->radius == 0 && st->speed == 0 && st->number == 0
                && !st->blackhole && !st->vortex && !st->magnify && !st->reflect) {
@@ -230,11 +230,8 @@ distort_reset (struct state *st)
                }
        }
 
-    /* never allow the radius to be too close to the min window dimension
-     */
-    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;
-
+    if (st->xgwa.width > 2560 || st->xgwa.height > 2560)
+      st->radius *= 2;  /* Retina displays */
 
     /* -swamp mode consumes vast amounts of memory, proportional to radius --
        so throttle radius to a small-ish value (60 => ~30MB.)
@@ -242,6 +239,14 @@ distort_reset (struct state *st)
     if (st->effect == &swamp_thing && st->radius > 60)
       st->radius = 60;
 
+    /* never allow the radius to be too close to the min window dimension
+     */
+    {
+      int max = (st->xgwa.width > st->xgwa.height
+                 ? st->xgwa.height : st->xgwa.width) * 2 / (5 * st->number);
+      if (st->radius > max) st->radius = max;
+    }
+
        if (st->delay < 0)
                st->delay = 0;
        if (st->radius <= 0)
@@ -272,23 +277,23 @@ distort_init (Display *dpy, Window window)
     st->dpy = dpy;
     st->window = window;
 
-#ifdef HAVE_XSHM_EXTENSION
-       st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
-#endif /* HAVE_XSHM_EXTENSION */
-       
     distort_reset (st);
 
        st->black_pixel = BlackPixelOfScreen( st->xgwa.screen );
 
        gcv.function = GXcopy;
-       gcv.subwindow_mode = IncludeInferiors;
        gcflags = GCFunction;
-       if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
-               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;
 }
@@ -300,9 +305,15 @@ distort_finish_loading (struct state *st)
 
     st->start_time = time ((time_t *) 0);
 
-       st->buffer_map = 0;
-       st->orig_map = XGetImage(st->dpy, st->window, 0, 0, st->xgwa.width, st->xgwa.height,
-                                                ~0L, ZPixmap);
+    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);
+    if (st->orig_map) XDestroyImage (st->orig_map);
+       st->orig_map = XGetImage(st->dpy, st->pm, 0, 0,
+                             st->xgwa.width, st->xgwa.height,
+                             ~0L, ZPixmap);
+    if (st->buffer_map_cache) free (st->buffer_map_cache);
        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) {
@@ -310,28 +321,12 @@ 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);
-       }
+    if (st->buffer_map)
+      destroy_xshm_image (st->dpy, st->buffer_map, &st->shm_info);
+       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)
@@ -388,6 +383,7 @@ static void convert(struct state *st)
 {
        int *p;
        int i, j;
+    if (st->fast_from) free (st->fast_from);
        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");
@@ -489,6 +485,17 @@ static void allocate_lense(struct state *st)
         * then pointers could be used instead of arrays in some places (and
         * maybe give a speedup - maybe also consume less memory)
         */
+    if (st->from) {
+      for (i = 0; i < st->from_size; i++)
+               if (st->from[i]) {
+          for (j = 0; j < st->from_size; j++) {
+            if (st->from[i][j]) free (st->from[i][j]);
+          }
+          free (st->from[i]);
+        }
+      free (st->from);
+    }
+    st->from_size = s;
        st->from = (int ***)malloc(s*sizeof(int **));
        if (st->from == NULL) {
                perror("distort");
@@ -519,6 +526,7 @@ static void init_round_lense(struct state *st)
        int k;
 
        if (st->effect == &swamp_thing) {
+        if (st->from_array) free (st->from_array);
                st->from_array = (int ****)malloc((st->radius+1)*sizeof(int ***));
                for (k=0; k <= st->radius; k++) {
                        allocate_lense(st);
@@ -598,17 +606,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);
 }
 
 
@@ -772,8 +771,11 @@ distort_draw (Display *dpy, Window window, void *closure)
 
   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->window, 0, 0);
+                                              st->pm, 0, 0);
     return st->delay;
   }
 
@@ -813,12 +815,27 @@ static void
 distort_free (Display *dpy, Window window, void *closure)
 {
   struct state *st = (struct state *) closure;
+  int i, j;
   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->from) free (st->from);
+  if (st->buffer_map)
+    destroy_xshm_image (st->dpy, st->buffer_map, &st->shm_info);
   if (st->fast_from) free (st->fast_from);
   if (st->from_array) free (st->from_array);
+  if (st->buffer_map_cache) free (st->buffer_map_cache);
+
+  if (st->from) {
+    for (i = 0; i < st->from_size; i++)
+      if (st->from[i]) {
+        for (j = 0; j < st->from_size; j++) {
+          if (st->from[i][j]) free (st->from[i][j]);
+        }
+        free (st->from[i]);
+      }
+    free (st->from);
+  }
+
   free (st);
 }
 
@@ -826,13 +843,9 @@ distort_free (Display *dpy, Window window, void *closure)
 \f
 
 static const char *distort_defaults [] = {
-       "*dontClearRoot:                True",
-       "*background:                   Black",
-    "*fpsSolid:                                true",
-#ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
-       "*visualID:                     Best",
-#endif
-
+       "*dontClearRoot:        True",
+       "*background:           Black",
+    "*fpsSolid:                        true",
        "*delay:                        20000",
     "*duration:                        120",
        "*radius:                       0",
@@ -847,7 +860,7 @@ static const char *distort_defaults [] = {
 #ifdef HAVE_XSHM_EXTENSION
        "*useSHM:                       False",         /* xshm turns out not to help. */
 #endif /* HAVE_XSHM_EXTENSION */
-#ifdef USE_IPHONE
+#ifdef HAVE_MOBILE
   "*ignoreRotation:     True",
   "*rotateImages:       True",
 #endif