+
+#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 */
+
+