From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / hacks / decayscreen.c
index 855d80a5e45dc819445d4219d838619fd7d18602..d4927b6070b64fe1ed609c92d1e75d8562d2e8b6 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2013 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
 struct state {
   Display *dpy;
   Window window;
+  XWindowAttributes xgwa;
+  Pixmap saved;
+  int saved_w, saved_h;
 
   int sizex, sizey;
   int delay;
+  int duration;
   GC gc;
   int mode;
-  int iterations;
+  int random_p;
+  time_t start_time;
 
   int fuzz_toggle;
   const int *current_bias;
@@ -69,18 +74,31 @@ struct state {
 #define STRETCH                12
 #define FUZZ           13
 
+static void
+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;
 
   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;
@@ -100,33 +118,30 @@ decayscreen_init (Display *dpy, Window window)
   else {
     if (s && *s && !!strcmp(s, "random"))
       fprintf(stderr, "%s: unknown mode %s\n", progname, s);
+    st->random_p = 1;
     st->mode = random() % (FUZZ+1);
   }
 
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
-
   if (st->delay < 0) st->delay = 0;
 
-  XGetWindowAttributes (st->dpy, st->window, &xgwa);
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+  if (st->duration < 1) st->duration = 1;
+
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
 
   gcv.function = GXcopy;
   gcv.subwindow_mode = IncludeInferiors;
-  bg = get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background");
+  bg = get_pixel_resource (st->dpy, st->xgwa.colormap, "background", "Background");
   gcv.foreground = bg;
 
   gcflags = GCForeground | GCFunction;
-  if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
+  if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
     gcflags |= GCSubwindowMode;
   st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
 
-  st->sizex = xgwa.width;
-  st->sizey = xgwa.height;
-
-  if (st->mode == MELT || st->mode == STRETCH)
-    st->iterations = 1;    /* slow down for smoother melting */
-
-  st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
-                                            st->window, 0, 0);
+  st->start_time = time ((time_t) 0);
+  decayscreen_load_image (st);
 
   return st;
 }
@@ -161,13 +176,33 @@ decayscreen_draw (Display *dpy, Window window, void *closure)
         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); 
+
+          if (!st->saved) {
+            st->saved = XCreatePixmap (st->dpy, st->window,
+                                       st->sizex, st->sizey,
+                                       st->xgwa.depth);
+            st->saved_w = st->sizex;
+            st->saved_h = st->sizey;
+          }
+          XCopyArea (st->dpy, st->window, st->saved, st->gc, 0, 0,
+                     st->sizex, st->sizey, 0, 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;
@@ -186,7 +221,7 @@ decayscreen_draw (Display *dpy, Window window, void *closure)
      default: abort();
     }
 
-#define nrnd(x) (random() % (x))
+#define nrnd(x) ((x) ? random() % (x) : x)
 
     if (st->mode == MELT || st->mode == STRETCH) {
       left = nrnd(st->sizex/2);
@@ -294,6 +329,11 @@ decayscreen_reshape (Display *dpy, Window window, void *closure,
                  unsigned int w, unsigned int h)
 {
   struct state *st = (struct state *) closure;
+  XClearWindow (st->dpy, st->window);
+  XCopyArea (st->dpy, st->saved, st->window, st->gc,
+             0, 0, st->saved_w, st->saved_h,
+             ((int)w - st->saved_w) / 2,
+             ((int)h - st->saved_h) / 2);
   st->sizex = w;
   st->sizey = h;
 }
@@ -317,6 +357,7 @@ static const char *decayscreen_defaults [] = {
   ".background:                        Black",
   ".foreground:                        Yellow",
   "*dontClearRoot:             True",
+  "*fpsSolid:                  True",
 
 #ifdef __sgi   /* really, HAVE_READ_DISPLAY_EXTENSION */
   "*visualID:                  Best",
@@ -324,12 +365,17 @@ static const char *decayscreen_defaults [] = {
 
   "*delay:                     10000",
   "*mode:                      random",
+  "*duration:                  120",
+#ifdef USE_IPHONE
+  "*ignoreRotation:             True",
+#endif
   0
 };
 
 static XrmOptionDescRec decayscreen_options [] = {
   { "-delay",          ".delay",               XrmoptionSepArg, 0 },
   { "-mode",           ".mode",                XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",            XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };