http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / utils / fade.c
index 2fbb2e97fa4f872609c6413ff5ca243977c57982..07b1a4e7d71484f1acd9a3089b43a3aa8cc6754e 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+/* xscreensaver, Copyright (c) 1992-1998 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
  * implied warranty.
  */
 
-#if __STDC__
-# include <stdlib.h>
-#endif
+#include "utils.h"
 
-#include <stdio.h>
-#include <X11/Xlib.h>
-#include <X11/Xos.h>
+#include <sys/time.h> /* for gettimeofday() */
 
-#if __STDC__
-# define bcopy(from,to,size) memcpy((to),(from),(size))
-# define bzero(addr,size) memset((addr),0,(size))
-extern void screenhack_usleep (unsigned long);
-#else
-extern void screenhack_usleep ();
-#endif
+#ifdef VMS
+# include "vms-gtod.h"
+#endif /* VMS */
 
-#define usleep screenhack_usleep
+#include "visual.h"
+#include "usleep.h"
+#include "fade.h"
 
-#define MAX_COLORS 4096
-static XColor orig_colors [MAX_COLORS];
-static XColor current_colors [MAX_COLORS];
-static int ncolors;
 
 Colormap
-copy_colormap (dpy, cmap, into_cmap)
-     Display *dpy;
-     Colormap cmap, into_cmap;
+copy_colormap (Screen *screen, Visual *visual,
+              Colormap cmap, Colormap into_cmap)
 {
   int i;
-  ncolors = CellsOfScreen (DefaultScreenOfDisplay (dpy));
-  if (ncolors <= 2 || ncolors > MAX_COLORS)
+  Display *dpy = DisplayOfScreen (screen);
+  Window window = RootWindowOfScreen (screen);
+  int ncolors = CellsOfScreen (screen);
+  XColor *colors = 0;
+
+  /* If this is a colormap on a mono visual, or one with insanely many
+     color cells, bug out. */
+  if (ncolors <= 2 || ncolors > 4096)
     return 0;
+  /* If this is a non-writable visual, bug out. */
+  if (!has_writable_cells (screen, visual))
+    return 0;
+
   if (! into_cmap)
-    into_cmap = XCreateColormap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
-                                DefaultVisual (dpy, DefaultScreen (dpy)),
-                                AllocAll);
+    into_cmap = XCreateColormap (dpy, window, visual, AllocAll);
   if (! cmap)
-    cmap = DefaultColormap (dpy, DefaultScreen (dpy));
+    cmap = DefaultColormapOfScreen (screen);
+
+  colors = (XColor *) calloc(sizeof(XColor), ncolors);
   for (i = 0; i < ncolors; i++)
-    orig_colors [i].pixel = i;
-  XQueryColors (dpy, cmap, orig_colors, ncolors);
-  XStoreColors (dpy, into_cmap, orig_colors, ncolors);
+    colors [i].pixel = i;
+  XQueryColors (dpy, cmap, colors, ncolors);
+  XStoreColors (dpy, into_cmap, colors, ncolors);
+  free (colors);
   return into_cmap;
 }
 
+
 void
-blacken_colormap (dpy, cmap)
-     Display *dpy;
-     Colormap cmap;
+blacken_colormap (Screen *screen, Colormap cmap)
 {
+  Display *dpy = DisplayOfScreen (screen);
+  int ncolors = CellsOfScreen (screen);
+  XColor *colors;
   int i;
+  if (ncolors > 4096)
+    return;
+  colors = (XColor *) calloc(sizeof(XColor), ncolors);
   for (i = 0; i < ncolors; i++)
+    colors[i].pixel = i;
+  XStoreColors (dpy, cmap, colors, ncolors);
+  free (colors);
+}
+
+
+
+static void fade_screens_1 (Display *dpy, Colormap *cmaps,
+                           Window *black_windows, int seconds, int ticks,
+                           Bool out_p, Bool clear_windows);
+#ifdef HAVE_SGI_VC_EXTENSION
+static int sgi_gamma_fade (Display *dpy,
+                          Window *black_windows, int seconds, int ticks,
+                          Bool out_p, Bool clear_windows);
+#endif /* HAVE_SGI_VC_EXTENSION */
+
+
+
+void
+fade_screens (Display *dpy, Colormap *cmaps, Window *black_windows,
+             int seconds, int ticks,
+             Bool out_p, Bool clear_windows)
+{
+  int oseconds = seconds;
+  Bool was_in_p = !out_p;
+
+  /* When we're asked to fade in, first fade out, then fade in.
+     That way all the transitions are smooth -- from what's on the
+     screen, to black, to the desktop.
+   */
+  if (was_in_p)
+    {
+      clear_windows = True;
+      out_p = True;
+      seconds /= 3;
+      if (seconds == 0)
+       seconds = 1;
+    }
+
+ AGAIN:
+
+#ifdef HAVE_SGI_VC_EXTENSION
+  /* First try to do it by fading the gamma in an SGI-specific way... */
+  if (0 != sgi_gamma_fade(dpy, black_windows, seconds, ticks, out_p,
+                         clear_windows))
+#endif /* HAVE_SGI_VC_EXTENSION */
+    /* Else, do it the old-fashioned way, which (somewhat) loses if
+       there are TrueColor windows visible. */
+    fade_screens_1 (dpy, cmaps, black_windows, seconds, ticks,
+                   out_p, clear_windows);
+
+  /* If we were supposed to be fading in, do so now (we just faded out,
+     so now fade back in.)
+   */
+  if (was_in_p)
     {
-      current_colors [i].pixel = i;
-      current_colors [i].red = current_colors [i].green =
-       current_colors [i].blue = 0;
+      was_in_p = False;
+      out_p = False;
+      seconds = oseconds * 2 / 3;
+      if (seconds == 0)
+       seconds = 1;
+      goto AGAIN;
     }
-  XStoreColors (dpy, cmap, current_colors, ncolors);
 }
 
 
-void
-fade_colormap (dpy, cmap, cmap2, seconds, ticks, out_p)
-     Display *dpy;
-     Colormap cmap, cmap2;
-     int seconds, ticks;
-     Bool out_p;
+/* The business with `cmaps_per_screen' is to fake out the SGI 8-bit video
+   hardware, which is capable of installing multiple (4) colormaps
+   simultaniously.  We have to install multiple copies of the same set of
+   colors in order to fill up all the available slots in the hardware color
+   lookup table, so we install an extra N colormaps per screen to make sure
+   that all screens really go black.
+
+   I'm told that this trick also works with XInside's AcceleratedX when using
+   the Matrox Millenium card (which also allows multiple PseudoColor and
+   TrueColor visuals to co-exist and display properly at the same time.)  
+
+   This trick works ok on the 24-bit Indy video hardware, but doesn't work at
+   all on the O2 24-bit hardware.  I guess the higher-end hardware is too
+   "good" for this to work (dammit.)  So... I figured out the "right" way to
+   do this on SGIs, which is to ramp the monitor's gamma down to 0.  That's
+   what is implemented in sgi_gamma_fade(), so we use that if we can.
+ */
+static void
+fade_screens_1 (Display *dpy, Colormap *cmaps, Window *black_windows,
+               int seconds, int ticks,
+               Bool out_p, Bool clear_windows)
 {
-  int i;
+  int i, j, k;
   int steps = seconds * ticks;
+  long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
   XEvent dummy_event;
+  int cmaps_per_screen = 5;
+  int nscreens = ScreenCount(dpy);
+  int ncmaps = nscreens * cmaps_per_screen;
+  Colormap *fade_cmaps = 0;
+  Bool installed = False;
+  int total_ncolors;
+  XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors;
+  struct timeval then, now;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+  struct timezone tzp;
+#endif
 
-  if (! cmap2)
-    return;
+  total_ncolors = 0;
+  for (i = 0; i < nscreens; i++)
+    total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
 
-  for (i = 0; i < ncolors; i++)
-    orig_colors [i].pixel = i;
-  XQueryColors (dpy, cmap, orig_colors, ncolors);
-  bcopy (orig_colors, current_colors, ncolors * sizeof (XColor));
+  orig_colors    = (XColor *) calloc(sizeof(XColor), total_ncolors);
+  current_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
+
+  /* Get the contents of the colormap we are fading from or to. */
+  screen_colors = orig_colors;
+  for (i = 0; i < nscreens; i++)
+    {
+      int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, i));
+      Colormap cmap = (cmaps ? cmaps[i] : 0);
+      if (!cmap) cmap = DefaultColormap(dpy, i);
+
+      for (j = 0; j < ncolors; j++)
+       screen_colors[j].pixel = j;
+      XQueryColors (dpy, cmap, screen_colors, ncolors);
 
+      screen_colors += ncolors;
+    }
+
+  memcpy (current_colors, orig_colors, total_ncolors * sizeof (XColor));
+
+
+  /* Make the writable colormaps (we keep these around and reuse them.) */
+  if (!fade_cmaps)
+    {
+      fade_cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
+      for (i = 0; i < nscreens; i++)
+       {
+         Visual *v = DefaultVisual(dpy, i);
+         Screen *s = ScreenOfDisplay(dpy, i);
+         if (has_writable_cells (s, v))
+           for (j = 0; j < cmaps_per_screen; j++)
+             fade_cmaps[(i * cmaps_per_screen) + j] =
+               XCreateColormap (dpy, RootWindowOfScreen (s), v, AllocAll);
+       }
+    }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+  gettimeofday(&then, &tzp);
+#else
+  gettimeofday(&then);
+#endif
+
+  /* Iterate by steps of the animation... */
   for (i = (out_p ? steps : 0);
        (out_p ? i > 0 : i < steps);
        (out_p ? i-- : i++))
     {
-      int j;
-      for (j = 0; j < ncolors; j++)
+
+      /* For each screen, compute the current value of each color...
+       */
+      orig_screen_colors = orig_colors;
+      screen_colors = current_colors;
+      for (j = 0; j < nscreens; j++)
+       {
+         int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
+         for (k = 0; k < ncolors; k++)
+           {
+             /* This doesn't take into account the relative luminance of the
+                RGB components (0.299, 0.587, and 0.114 at gamma 2.2) but
+                the difference is imperceptible for this application... */
+             screen_colors[k].red   = orig_screen_colors[k].red   * i / steps;
+             screen_colors[k].green = orig_screen_colors[k].green * i / steps;
+             screen_colors[k].blue  = orig_screen_colors[k].blue  * i / steps;
+           }
+         screen_colors      += ncolors;
+         orig_screen_colors += ncolors;
+       }
+
+      /* Put the colors into the maps...
+       */
+      screen_colors = current_colors;
+      for (j = 0; j < nscreens; j++)
        {
-         current_colors[j].red   = orig_colors[j].red   * i / steps;
-         current_colors[j].green = orig_colors[j].green * i / steps;
-         current_colors[j].blue  = orig_colors[j].blue  * i / steps;
+         int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
+         for (k = 0; k < cmaps_per_screen; k++)
+           {
+             Colormap c = fade_cmaps[j * cmaps_per_screen + k];
+             if (c)
+               XStoreColors (dpy, c, screen_colors, ncolors);
+           }
+         screen_colors += ncolors;
        }
-      XStoreColors (dpy, cmap2, current_colors, ncolors);
+
+      /* Put the maps on the screens, and then take the windows off the screen.
+        (only need to do this the first time through the loop.)
+       */
+      if (!installed)
+       {
+         for (j = 0; j < ncmaps; j++)
+           if (fade_cmaps[j])
+             XInstallColormap (dpy, fade_cmaps[j]);
+         installed = True;
+
+         if (black_windows && !out_p)
+           for (j = 0; j < nscreens; j++)
+             if (black_windows[j])
+               {
+                 XUnmapWindow (dpy, black_windows[j]);
+                 XClearWindow (dpy, black_windows[j]);
+               }
+       }
+
       XSync (dpy, False);
 
-      /* If there is user activity, bug out.
+      /* If there is user activity, bug out.  (Bug out on keypresses or
+        mouse presses, but not motion, and not release events.  Bugging
+        out on motion made the unfade hack be totally useless, I think.)
+
         We put the event back so that the calling code can notice it too.
         It would be better to not remove it at all, but that's harder
         because Xlib has such a non-design for this kind of crap, and
@@ -111,24 +289,301 @@ fade_colormap (dpy, cmap, cmap2, seconds, ticks, out_p)
         of order, so in the grand unix tradition we say "fuck it" and
         do something that mostly works for the time being.
        */
-      if (XCheckMaskEvent (dpy, (KeyPressMask | KeyReleaseMask |
-                                ButtonPressMask | ButtonReleaseMask |
-                                PointerMotionMask),
-                          &dummy_event))
+      if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask), &dummy_event))
        {
          XPutBackEvent (dpy, &dummy_event);
-         return;
+         goto DONE;
        }
 
-      usleep (1000000 / (ticks * 2)); /* the 2 is a hack... */
+#ifdef GETTIMEOFDAY_TWO_ARGS
+      gettimeofday(&now, &tzp);
+#else
+      gettimeofday(&now);
+#endif
+
+      /* If we haven't already used up our alotted time, sleep to avoid
+        changing the colormap too fast. */
+      {
+       long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
+                    now.tv_usec - then.tv_usec);
+       then.tv_sec = now.tv_sec;
+       then.tv_usec = now.tv_usec;
+       if (usecs_per_step > diff)
+         usleep (usecs_per_step - diff);
+      }
     }
+
+ DONE:
+
+  if (orig_colors)    free (orig_colors);
+  if (current_colors) free (current_colors);
+
+  /* If we've been given windows to raise after blackout, raise them before
+     releasing the colormaps.
+   */
+  if (out_p && black_windows)
+    {
+      for (i = 0; i < nscreens; i++)
+       {
+         if (clear_windows)
+           XClearWindow (dpy, black_windows[i]);
+         XMapRaised (dpy, black_windows[i]);
+       }
+      XSync(dpy, False);
+    }
+
+  /* Now put the target maps back.
+     If we're fading out, use the given cmap (or the default cmap, if none.)
+     If we're fading in, always use the default cmap.
+   */
+  for (i = 0; i < nscreens; i++)
+    {
+      Colormap cmap = (cmaps ? cmaps[i] : 0);
+      if (!cmap || !out_p)
+       cmap = DefaultColormap(dpy, i);
+      XInstallColormap (dpy, cmap);
+    }
+
+  /* The fade (in or out) is complete, so we don't need the black maps on
+     stage any more.
+   */
+  for (i = 0; i < ncmaps; i++)
+    if (fade_cmaps[i])
+      {
+       XUninstallColormap(dpy, fade_cmaps[i]);
+       XFreeColormap(dpy, fade_cmaps[i]);
+       fade_cmaps[i] = 0;
+      }
+  free(fade_cmaps);
+  fade_cmaps = 0;
 }
 
-#if 0
+
+#ifdef HAVE_SGI_VC_EXTENSION
+
+# include <X11/extensions/XSGIvc.h>
+
+struct screen_gamma_info {
+  int gamma_map;  /* ??? always using 0 */
+  int nred, ngreen, nblue;
+  unsigned short *red1, *green1, *blue1;
+  unsigned short *red2, *green2, *blue2;
+  int gamma_size;
+  int gamma_precision;
+  Bool alpha_p;
+};
+
+
+static void whack_gamma(Display *dpy, int screen,
+                       struct screen_gamma_info *info, float ratio);
+
+static int
+sgi_gamma_fade (Display *dpy,
+               Window *black_windows, int seconds, int ticks,
+               Bool out_p, Bool clear_windows)
+{
+  int steps = seconds * ticks;
+  long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
+  XEvent dummy_event;
+  int nscreens = ScreenCount(dpy);
+  struct timeval then, now;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+  struct timezone tzp;
+#endif
+  int i, screen;
+  int status = -1;
+  struct screen_gamma_info *info = (struct screen_gamma_info *)
+    calloc(nscreens, sizeof(*info));
+
+  /* Get the current gamma maps for all screens.
+     Bug out and return -1 if we can't get them for some screen.
+   */
+  for (screen = 0; screen < nscreens; screen++)
+    {
+      if (!XSGIvcQueryGammaMap(dpy, screen, info[screen].gamma_map,
+                              &info[screen].gamma_size,
+                              &info[screen].gamma_precision,
+                              &info[screen].alpha_p))
+       goto FAIL;
+
+      if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+                                 XSGIVC_COMPONENT_RED,
+                                 &info[screen].nred, &info[screen].red1))
+       goto FAIL;
+      if (! XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+                                  XSGIVC_COMPONENT_GREEN,
+                                  &info[screen].ngreen, &info[screen].green1))
+       goto FAIL;
+      if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+                                 XSGIVC_COMPONENT_BLUE,
+                                 &info[screen].nblue, &info[screen].blue1))
+       goto FAIL;
+
+      if (info[screen].gamma_precision == 8)    /* Scale it up to 16 bits. */
+       {
+         int j;
+         for(j = 0; j < info[screen].nred; j++)
+           info[screen].red1[j]   =
+             ((info[screen].red1[j]   << 8) | info[screen].red1[j]);
+         for(j = 0; j < info[screen].ngreen; j++)
+           info[screen].green1[j] =
+             ((info[screen].green1[j] << 8) | info[screen].green1[j]);
+         for(j = 0; j < info[screen].nblue; j++)
+           info[screen].blue1[j]  =
+             ((info[screen].blue1[j]  << 8) | info[screen].blue1[j]);
+       }
+
+      info[screen].red2   = (unsigned short *)
+       malloc(sizeof(*info[screen].red2)   * (info[screen].nred+1));
+      info[screen].green2 = (unsigned short *)
+       malloc(sizeof(*info[screen].green2) * (info[screen].ngreen+1));
+      info[screen].blue2  = (unsigned short *)
+       malloc(sizeof(*info[screen].blue2)  * (info[screen].nblue+1));
+    }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+  gettimeofday(&then, &tzp);
+#else
+  gettimeofday(&then);
+#endif
+
+  /* If we're fading in (from black), then first crank the gamma all the
+     way down to 0, then take the windows off the screen.
+   */
+  if (!out_p)
+    for (screen = 0; screen < nscreens; screen++)
+      {
+       whack_gamma(dpy, screen, &info[screen], 0.0);
+       if (black_windows && black_windows[screen])
+         {
+           XUnmapWindow (dpy, black_windows[screen]);
+           XClearWindow (dpy, black_windows[screen]);
+           XSync(dpy, False);
+         }
+      }
+
+
+  /* Iterate by steps of the animation... */
+  for (i = (out_p ? steps : 0);
+       (out_p ? i > 0 : i < steps);
+       (out_p ? i-- : i++))
+    {
+      for (screen = 0; screen < nscreens; screen++)
+       {
+         whack_gamma(dpy, screen, &info[screen],
+                     (((float)i) / ((float)steps)));
+
+         /* If there is user activity, bug out.  (Bug out on keypresses or
+            mouse presses, but not motion, and not release events.  Bugging
+            out on motion made the unfade hack be totally useless, I think.)
+
+            We put the event back so that the calling code can notice it too.
+            It would be better to not remove it at all, but that's harder
+            because Xlib has such a non-design for this kind of crap, and
+            in this application it doesn't matter if the events end up out
+            of order, so in the grand unix tradition we say "fuck it" and
+            do something that mostly works for the time being.
+          */
+         if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
+                              &dummy_event))
+           {
+             XPutBackEvent (dpy, &dummy_event);
+             goto DONE;
+           }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+         gettimeofday(&now, &tzp);
+#else
+         gettimeofday(&now);
+#endif
+
+         /* If we haven't already used up our alotted time, sleep to avoid
+            changing the colormap too fast. */
+         {
+           long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
+                        now.tv_usec - then.tv_usec);
+           then.tv_sec = now.tv_sec;
+           then.tv_usec = now.tv_usec;
+           if (usecs_per_step > diff)
+             usleep (usecs_per_step - diff);
+         }
+       }
+    }
+  
+
+ DONE:
+
+  if (out_p && black_windows)
+    {
+      for (screen = 0; screen < nscreens; screen++)
+       {
+         if (clear_windows)
+           XClearWindow (dpy, black_windows[screen]);
+         XMapRaised (dpy, black_windows[screen]);
+       }
+      XSync(dpy, False);
+    }
+
+  /* I can't explain this; without this delay, we get a flicker.
+     I suppose there's some lossage with stale bits being in the
+     hardware frame buffer or something, and this delay gives it
+     time to flush out.  This sucks! */
+  usleep(100000);  /* 1/10th second */
+
+  for (screen = 0; screen < nscreens; screen++)
+    whack_gamma(dpy, screen, &info[screen], 1.0);
+  XSync(dpy, False);
+
+  status = 0;
+
+ FAIL:
+  for (screen = 0; screen < nscreens; screen++)
+    {
+      if (info[screen].red1)   free (info[screen].red1);
+      if (info[screen].green1) free (info[screen].green1);
+      if (info[screen].blue1)  free (info[screen].blue1);
+      if (info[screen].red2)   free (info[screen].red2);
+      if (info[screen].green2) free (info[screen].green2);
+      if (info[screen].blue2)  free (info[screen].blue2);
+    }
+  free(info);
+
+  return status;
+}
+
+static void
+whack_gamma(Display *dpy, int screen, struct screen_gamma_info *info,
+           float ratio)
+{
+  int k;
+
+  if (ratio < 0) ratio = 0;
+  if (ratio > 1) ratio = 1;
+  for (k = 0; k < info->gamma_size; k++)
+    {
+      info->red2[k]   = info->red1[k]   * ratio;
+      info->green2[k] = info->green1[k] * ratio;
+      info->blue2[k]  = info->blue1[k]  * ratio;
+    }
+
+  XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nred,
+                          XSGIVC_MComponentRed, info->red2);
+  XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->ngreen,
+                          XSGIVC_MComponentGreen, info->green2);
+  XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nblue,
+                          XSGIVC_MComponentBlue, info->blue2);
+  XSync(dpy, False);
+}
+
+#endif /* HAVE_SGI_VC_EXTENSION */
+
+
 
 \f
-char *progclass = "foo";
+#if 0
+#include "screenhack.h"
 
+char *progclass = "foo";
 char *defaults [] = {
   0
 };
@@ -141,24 +596,24 @@ screenhack (dpy, w)
      Display *dpy;
      Window w;
 {
-  Colormap cmap = DefaultColormap (dpy, DefaultScreen (dpy));
-  Colormap cmap2 = copy_colormap (dpy, cmap, 0);
-
-  int seconds = 1;
-  int ticks = 30 * seconds;
+  int seconds = 3;
+  int ticks = 20;
   int delay = 1;
 
   while (1)
     {
       XSync (dpy, False);
-      XGrabServer (dpy);
-      XInstallColormap (dpy, cmap2);
-      fade_colormap (dpy, cmap, cmap2, seconds, ticks, True);
+
+      fprintf(stderr,"out..."); fflush(stderr);
+      fade_screens (dpy, 0, seconds, ticks, True);
+      fprintf(stderr, "done.\n"); fflush(stderr);
+
       if (delay) sleep (delay);
-      fade_colormap (dpy, cmap, cmap2, seconds, ticks, False);
-      XInstallColormap (dpy, cmap);
-      XUngrabServer (dpy);
-      XSync (dpy, False);
+
+      fprintf(stderr,"in..."); fflush(stderr);
+      fade_screens (dpy, 0, seconds, ticks, False);
+      fprintf(stderr, "done.\n"); fflush(stderr);
+
       if (delay) sleep (delay);
     }
 }