ftp://ftp.sunet.se/pub/os/Linux/distributions/ultrapenguin/ultrapenguin-1.1/SRPMS...
[xscreensaver] / utils / fade.c
index 16f815ce066488b3d18dd477a193b29842e3df43..e174dfbf148318bb4aeb43d6e43eeb13f7643691 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@mcom.com>
+/* xscreensaver, Copyright (c) 1992-1997 Jamie Zawinski <jwz@netscape.com>
  *
  * 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 P(x)x
-#else
-# define P(x)()
-#endif
+#ifdef VMS
+# include "vms-gtod.h"
+#endif /* VMS */
 
-extern int get_visual_class P((Display *, Visual *));
-extern void screenhack_usleep P((int));
-#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;
-  Screen *screen = DefaultScreenOfDisplay (dpy);
-  Visual *visual = DefaultVisualOfScreen (screen);
+  Display *dpy = DisplayOfScreen (screen);
   Window window = RootWindowOfScreen (screen);
-  int vclass = get_visual_class (dpy, visual);
-
-  ncolors = CellsOfScreen (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 > MAX_COLORS)
+  if (ncolors <= 2 || ncolors > 4096)
     return 0;
   /* If this is a non-writable visual, bug out. */
-  if (vclass == StaticGray || vclass == StaticColor || vclass == TrueColor)
+  if (!has_writable_cells (screen, visual))
     return 0;
 
   if (! into_cmap)
     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++)
-    {
-      current_colors [i].pixel = i;
-      current_colors [i].red = current_colors [i].green =
-       current_colors [i].blue = 0;
-    }
-  XStoreColors (dpy, cmap, current_colors, ncolors);
+    colors[i].pixel = i;
+  XStoreColors (dpy, cmap, colors, ncolors);
+  free (colors);
 }
 
 
+/* 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.  */
+
 void
-fade_colormap (dpy, cmap, cmap2, seconds, ticks, out_p)
-     Display *dpy;
-     Colormap cmap, cmap2;
-     int seconds, ticks;
-     Bool out_p;
+fade_screens (Display *dpy, Colormap *cmaps,
+             int seconds, int ticks,
+             Bool out_p)
 {
-  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;
+  static 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);
-  memcpy (current_colors, orig_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++)
        {
-         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 < 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;
        }
-      XStoreColors (dpy, cmap2, current_colors, ncolors);
+
+      /* Put the colors into the maps...
+       */
+      screen_colors = current_colors;
+      for (j = 0; j < nscreens; j++)
+       {
+         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;
+       }
+
+      /* Put the maps on the screens...
+        (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;
+       }
+
       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
@@ -121,24 +211,67 @@ 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);
+
+  /* Now put the original maps back, if we want to end up with them.
+   */
+  if (!out_p)
+    {
+      for (i = 0; i < nscreens; i++)
+       {
+         Colormap cmap = (cmaps ? cmaps[i] : 0);
+         if (!cmap) cmap = DefaultColormap(dpy, i);
+         XInstallColormap (dpy, cmap);
+       }
+
+      /* We've faded to the default cmaps, so we don't need the black maps
+        on stage any more.  (We can't uninstall these maps yet if we've
+        faded to black, because that would lead to flicker between when
+        we uninstalled them and when the caller raised its black window.)
+       */
+      for (i = 0; i < ncmaps; i++)
+       if (fade_cmaps[i])
+         {
+           XFreeColormap(dpy, fade_cmaps[i]);
+           fade_cmaps[i] = 0;
+         }
+      free(fade_cmaps);
+      fade_cmaps = 0;
     }
 }
 
+\f
 #if 0
+#include "screenhack.h"
 
-\f
 char *progclass = "foo";
-
 char *defaults [] = {
   0
 };
@@ -151,24 +284,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);
     }
 }