+++ /dev/null
-/* 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
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- */
-
-#include "utils.h"
-
-#include <sys/time.h> /* for gettimeofday() */
-
-#ifdef VMS
-# include "vms-gtod.h"
-#endif /* VMS */
-
-#include "visual.h"
-#include "usleep.h"
-#include "fade.h"
-
-
-Colormap
-copy_colormap (Screen *screen, Visual *visual,
- Colormap cmap, Colormap into_cmap)
-{
- int i;
- 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, window, visual, AllocAll);
- if (! cmap)
- cmap = DefaultColormapOfScreen (screen);
-
- colors = (XColor *) calloc(sizeof(XColor), ncolors);
- for (i = 0; i < ncolors; i++)
- colors [i].pixel = i;
- XQueryColors (dpy, cmap, colors, ncolors);
- XStoreColors (dpy, into_cmap, colors, ncolors);
- free (colors);
- return into_cmap;
-}
-
-
-void
-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)
- {
- was_in_p = False;
- out_p = False;
- seconds = oseconds * 2 / 3;
- if (seconds == 0)
- seconds = 1;
- goto AGAIN;
- }
-}
-
-
-/* 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, 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
-
- total_ncolors = 0;
- for (i = 0; i < nscreens; i++)
- total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
-
- 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++))
- {
-
- /* 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++)
- {
- 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, 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. (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 (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;
-}
-
-
-#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
-#if 0
-#include "screenhack.h"
-
-char *progclass = "foo";
-char *defaults [] = {
- 0
-};
-
-XrmOptionDescRec options [] = {0};
-int options_size = 0;
-
-void
-screenhack (dpy, w)
- Display *dpy;
- Window w;
-{
- int seconds = 3;
- int ticks = 20;
- int delay = 1;
-
- while (1)
- {
- XSync (dpy, False);
-
- fprintf(stderr,"out..."); fflush(stderr);
- fade_screens (dpy, 0, seconds, ticks, True);
- fprintf(stderr, "done.\n"); fflush(stderr);
-
- if (delay) sleep (delay);
-
- fprintf(stderr,"in..."); fflush(stderr);
- fade_screens (dpy, 0, seconds, ticks, False);
- fprintf(stderr, "done.\n"); fflush(stderr);
-
- if (delay) sleep (delay);
- }
-}
-
-#endif