1 /* xscreensaver, Copyright (c) 1992-2002 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 #include <sys/time.h> /* for gettimeofday() */
17 # include "vms-gtod.h"
25 copy_colormap (Screen *screen, Visual *visual,
26 Colormap cmap, Colormap into_cmap)
29 Display *dpy = DisplayOfScreen (screen);
30 Window window = RootWindowOfScreen (screen);
31 int ncolors = CellsOfScreen (screen);
34 /* If this is a colormap on a mono visual, or one with insanely many
35 color cells, bug out. */
36 if (ncolors <= 2 || ncolors > 4096)
38 /* If this is a non-writable visual, bug out. */
39 if (!has_writable_cells (screen, visual))
43 into_cmap = XCreateColormap (dpy, window, visual, AllocAll);
45 cmap = DefaultColormapOfScreen (screen);
47 colors = (XColor *) calloc(sizeof(XColor), ncolors);
48 for (i = 0; i < ncolors; i++)
50 XQueryColors (dpy, cmap, colors, ncolors);
51 XStoreColors (dpy, into_cmap, colors, ncolors);
58 blacken_colormap (Screen *screen, Colormap cmap)
60 Display *dpy = DisplayOfScreen (screen);
61 int ncolors = CellsOfScreen (screen);
66 colors = (XColor *) calloc(sizeof(XColor), ncolors);
67 for (i = 0; i < ncolors; i++)
69 XStoreColors (dpy, cmap, colors, ncolors);
75 static void fade_screens_1 (Display *dpy, Colormap *cmaps,
76 Window *black_windows, int seconds, int ticks,
77 Bool out_p, Bool clear_windows);
79 #ifdef HAVE_SGI_VC_EXTENSION
80 static int sgi_gamma_fade (Display *dpy,
81 Window *black_windows, int seconds, int ticks,
82 Bool out_p, Bool clear_windows);
83 #endif /* HAVE_SGI_VC_EXTENSION */
85 #ifdef HAVE_XF86VMODE_GAMMA
86 static int xf86_gamma_fade (Display *dpy,
87 Window *black_windows, int seconds, int ticks,
88 Bool out_p, Bool clear_windows);
89 #endif /* HAVE_XF86VMODE_GAMMA */
93 fade_screens (Display *dpy, Colormap *cmaps, Window *black_windows,
94 int seconds, int ticks,
95 Bool out_p, Bool clear_windows)
97 int oseconds = seconds;
98 Bool was_in_p = !out_p;
100 /* When we're asked to fade in, first fade out, then fade in.
101 That way all the transitions are smooth -- from what's on the
102 screen, to black, to the desktop.
106 clear_windows = True;
115 /* #### printf("\n\nfade_screens %d %d %d\n", seconds, ticks, out_p); */
117 #ifdef HAVE_SGI_VC_EXTENSION
118 /* First try to do it by fading the gamma in an SGI-specific way... */
119 if (0 == sgi_gamma_fade(dpy, black_windows, seconds, ticks, out_p,
123 #endif /* HAVE_SGI_VC_EXTENSION */
125 #ifdef HAVE_XF86VMODE_GAMMA
126 /* Then try to do it by fading the gamma in an XFree86-specific way... */
127 if (0 == xf86_gamma_fade(dpy, black_windows, seconds, ticks, out_p,
131 #endif /* HAVE_XF86VMODE_GAMMA */
133 /* Else, do it the old-fashioned way, which (somewhat) loses if
134 there are TrueColor windows visible. */
135 fade_screens_1 (dpy, cmaps, black_windows, seconds, ticks,
136 out_p, clear_windows);
138 /* If we were supposed to be fading in, do so now (we just faded out,
139 so now fade back in.)
145 seconds = oseconds * 2 / 3;
153 /* The business with `cmaps_per_screen' is to fake out the SGI 8-bit video
154 hardware, which is capable of installing multiple (4) colormaps
155 simultaniously. We have to install multiple copies of the same set of
156 colors in order to fill up all the available slots in the hardware color
157 lookup table, so we install an extra N colormaps per screen to make sure
158 that all screens really go black.
160 I'm told that this trick also works with XInside's AcceleratedX when using
161 the Matrox Millennium card (which also allows multiple PseudoColor and
162 TrueColor visuals to co-exist and display properly at the same time.)
164 This trick works ok on the 24-bit Indy video hardware, but doesn't work at
165 all on the O2 24-bit hardware. I guess the higher-end hardware is too
166 "good" for this to work (dammit.) So... I figured out the "right" way to
167 do this on SGIs, which is to ramp the monitor's gamma down to 0. That's
168 what is implemented in sgi_gamma_fade(), so we use that if we can.
171 fade_screens_1 (Display *dpy, Colormap *cmaps, Window *black_windows,
172 int seconds, int ticks,
173 Bool out_p, Bool clear_windows)
176 int steps = seconds * ticks;
177 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
179 int cmaps_per_screen = 5;
180 int nscreens = ScreenCount(dpy);
181 int ncmaps = nscreens * cmaps_per_screen;
182 Colormap *fade_cmaps = 0;
183 Bool installed = False;
185 XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors;
186 struct timeval then, now;
187 #ifdef GETTIMEOFDAY_TWO_ARGS
192 for (i = 0; i < nscreens; i++)
193 total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
195 orig_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
196 current_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
198 /* Get the contents of the colormap we are fading from or to. */
199 screen_colors = orig_colors;
200 for (i = 0; i < nscreens; i++)
202 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, i));
203 Colormap cmap = (cmaps ? cmaps[i] : 0);
204 if (!cmap) cmap = DefaultColormap(dpy, i);
206 for (j = 0; j < ncolors; j++)
207 screen_colors[j].pixel = j;
208 XQueryColors (dpy, cmap, screen_colors, ncolors);
210 screen_colors += ncolors;
213 memcpy (current_colors, orig_colors, total_ncolors * sizeof (XColor));
216 /* Make the writable colormaps (we keep these around and reuse them.) */
219 fade_cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
220 for (i = 0; i < nscreens; i++)
222 Visual *v = DefaultVisual(dpy, i);
223 Screen *s = ScreenOfDisplay(dpy, i);
224 if (has_writable_cells (s, v))
225 for (j = 0; j < cmaps_per_screen; j++)
226 fade_cmaps[(i * cmaps_per_screen) + j] =
227 XCreateColormap (dpy, RootWindowOfScreen (s), v, AllocAll);
231 #ifdef GETTIMEOFDAY_TWO_ARGS
232 gettimeofday(&then, &tzp);
237 /* Iterate by steps of the animation... */
238 for (i = (out_p ? steps : 0);
239 (out_p ? i > 0 : i < steps);
243 /* For each screen, compute the current value of each color...
245 orig_screen_colors = orig_colors;
246 screen_colors = current_colors;
247 for (j = 0; j < nscreens; j++)
249 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
250 for (k = 0; k < ncolors; k++)
252 /* This doesn't take into account the relative luminance of the
253 RGB components (0.299, 0.587, and 0.114 at gamma 2.2) but
254 the difference is imperceptible for this application... */
255 screen_colors[k].red = orig_screen_colors[k].red * i / steps;
256 screen_colors[k].green = orig_screen_colors[k].green * i / steps;
257 screen_colors[k].blue = orig_screen_colors[k].blue * i / steps;
259 screen_colors += ncolors;
260 orig_screen_colors += ncolors;
263 /* Put the colors into the maps...
265 screen_colors = current_colors;
266 for (j = 0; j < nscreens; j++)
268 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
269 for (k = 0; k < cmaps_per_screen; k++)
271 Colormap c = fade_cmaps[j * cmaps_per_screen + k];
273 XStoreColors (dpy, c, screen_colors, ncolors);
275 screen_colors += ncolors;
278 /* Put the maps on the screens, and then take the windows off the screen.
279 (only need to do this the first time through the loop.)
283 for (j = 0; j < ncmaps; j++)
285 XInstallColormap (dpy, fade_cmaps[j]);
288 if (black_windows && !out_p)
289 for (j = 0; j < nscreens; j++)
290 if (black_windows[j])
292 XUnmapWindow (dpy, black_windows[j]);
293 XClearWindow (dpy, black_windows[j]);
299 /* If there is user activity, bug out. (Bug out on keypresses or
300 mouse presses, but not motion, and not release events. Bugging
301 out on motion made the unfade hack be totally useless, I think.)
303 We put the event back so that the calling code can notice it too.
304 It would be better to not remove it at all, but that's harder
305 because Xlib has such a non-design for this kind of crap, and
306 in this application it doesn't matter if the events end up out
307 of order, so in the grand unix tradition we say "fuck it" and
308 do something that mostly works for the time being.
310 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask), &dummy_event))
312 XPutBackEvent (dpy, &dummy_event);
316 #ifdef GETTIMEOFDAY_TWO_ARGS
317 gettimeofday(&now, &tzp);
322 /* If we haven't already used up our alotted time, sleep to avoid
323 changing the colormap too fast. */
325 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
326 now.tv_usec - then.tv_usec);
327 then.tv_sec = now.tv_sec;
328 then.tv_usec = now.tv_usec;
329 if (usecs_per_step > diff)
330 usleep (usecs_per_step - diff);
336 if (orig_colors) free (orig_colors);
337 if (current_colors) free (current_colors);
339 /* If we've been given windows to raise after blackout, raise them before
340 releasing the colormaps.
342 if (out_p && black_windows)
344 for (i = 0; i < nscreens; i++)
347 XClearWindow (dpy, black_windows[i]);
348 XMapRaised (dpy, black_windows[i]);
353 /* Now put the target maps back.
354 If we're fading out, use the given cmap (or the default cmap, if none.)
355 If we're fading in, always use the default cmap.
357 for (i = 0; i < nscreens; i++)
359 Colormap cmap = (cmaps ? cmaps[i] : 0);
361 cmap = DefaultColormap(dpy, i);
362 XInstallColormap (dpy, cmap);
365 /* The fade (in or out) is complete, so we don't need the black maps on
368 for (i = 0; i < ncmaps; i++)
371 XUninstallColormap(dpy, fade_cmaps[i]);
372 XFreeColormap(dpy, fade_cmaps[i]);
381 /* SGI Gamma fading */
383 #ifdef HAVE_SGI_VC_EXTENSION
385 # include <X11/extensions/XSGIvc.h>
387 struct screen_sgi_gamma_info {
388 int gamma_map; /* ??? always using 0 */
389 int nred, ngreen, nblue;
390 unsigned short *red1, *green1, *blue1;
391 unsigned short *red2, *green2, *blue2;
398 static void sgi_whack_gamma(Display *dpy, int screen,
399 struct screen_sgi_gamma_info *info, float ratio);
402 sgi_gamma_fade (Display *dpy,
403 Window *black_windows, int seconds, int ticks,
404 Bool out_p, Bool clear_windows)
406 int steps = seconds * ticks;
407 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
409 int nscreens = ScreenCount(dpy);
410 struct timeval then, now;
411 #ifdef GETTIMEOFDAY_TWO_ARGS
416 struct screen_sgi_gamma_info *info = (struct screen_sgi_gamma_info *)
417 calloc(nscreens, sizeof(*info));
419 /* Get the current gamma maps for all screens.
420 Bug out and return -1 if we can't get them for some screen.
422 for (screen = 0; screen < nscreens; screen++)
424 if (!XSGIvcQueryGammaMap(dpy, screen, info[screen].gamma_map,
425 &info[screen].gamma_size,
426 &info[screen].gamma_precision,
427 &info[screen].alpha_p))
430 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
431 XSGIVC_COMPONENT_RED,
432 &info[screen].nred, &info[screen].red1))
434 if (! XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
435 XSGIVC_COMPONENT_GREEN,
436 &info[screen].ngreen, &info[screen].green1))
438 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
439 XSGIVC_COMPONENT_BLUE,
440 &info[screen].nblue, &info[screen].blue1))
443 if (info[screen].gamma_precision == 8) /* Scale it up to 16 bits. */
446 for(j = 0; j < info[screen].nred; j++)
447 info[screen].red1[j] =
448 ((info[screen].red1[j] << 8) | info[screen].red1[j]);
449 for(j = 0; j < info[screen].ngreen; j++)
450 info[screen].green1[j] =
451 ((info[screen].green1[j] << 8) | info[screen].green1[j]);
452 for(j = 0; j < info[screen].nblue; j++)
453 info[screen].blue1[j] =
454 ((info[screen].blue1[j] << 8) | info[screen].blue1[j]);
457 info[screen].red2 = (unsigned short *)
458 malloc(sizeof(*info[screen].red2) * (info[screen].nred+1));
459 info[screen].green2 = (unsigned short *)
460 malloc(sizeof(*info[screen].green2) * (info[screen].ngreen+1));
461 info[screen].blue2 = (unsigned short *)
462 malloc(sizeof(*info[screen].blue2) * (info[screen].nblue+1));
465 #ifdef GETTIMEOFDAY_TWO_ARGS
466 gettimeofday(&then, &tzp);
471 /* If we're fading in (from black), then first crank the gamma all the
472 way down to 0, then take the windows off the screen.
475 for (screen = 0; screen < nscreens; screen++)
477 sgi_whack_gamma(dpy, screen, &info[screen], 0.0);
478 if (black_windows && black_windows[screen])
480 XUnmapWindow (dpy, black_windows[screen]);
481 XClearWindow (dpy, black_windows[screen]);
487 /* Iterate by steps of the animation... */
488 for (i = (out_p ? steps : 0);
489 (out_p ? i > 0 : i < steps);
492 for (screen = 0; screen < nscreens; screen++)
494 sgi_whack_gamma(dpy, screen, &info[screen],
495 (((float)i) / ((float)steps)));
497 /* If there is user activity, bug out. (Bug out on keypresses or
498 mouse presses, but not motion, and not release events. Bugging
499 out on motion made the unfade hack be totally useless, I think.)
501 We put the event back so that the calling code can notice it too.
502 It would be better to not remove it at all, but that's harder
503 because Xlib has such a non-design for this kind of crap, and
504 in this application it doesn't matter if the events end up out
505 of order, so in the grand unix tradition we say "fuck it" and
506 do something that mostly works for the time being.
508 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
511 XPutBackEvent (dpy, &dummy_event);
515 #ifdef GETTIMEOFDAY_TWO_ARGS
516 gettimeofday(&now, &tzp);
521 /* If we haven't already used up our alotted time, sleep to avoid
522 changing the colormap too fast. */
524 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
525 now.tv_usec - then.tv_usec);
526 then.tv_sec = now.tv_sec;
527 then.tv_usec = now.tv_usec;
528 if (usecs_per_step > diff)
529 usleep (usecs_per_step - diff);
537 if (out_p && black_windows)
539 for (screen = 0; screen < nscreens; screen++)
542 XClearWindow (dpy, black_windows[screen]);
543 XMapRaised (dpy, black_windows[screen]);
548 /* I can't explain this; without this delay, we get a flicker.
549 I suppose there's some lossage with stale bits being in the
550 hardware frame buffer or something, and this delay gives it
551 time to flush out. This sucks! */
552 usleep(100000); /* 1/10th second */
554 for (screen = 0; screen < nscreens; screen++)
555 sgi_whack_gamma(dpy, screen, &info[screen], 1.0);
561 for (screen = 0; screen < nscreens; screen++)
563 if (info[screen].red1) free (info[screen].red1);
564 if (info[screen].green1) free (info[screen].green1);
565 if (info[screen].blue1) free (info[screen].blue1);
566 if (info[screen].red2) free (info[screen].red2);
567 if (info[screen].green2) free (info[screen].green2);
568 if (info[screen].blue2) free (info[screen].blue2);
576 sgi_whack_gamma(Display *dpy, int screen, struct screen_sgi_gamma_info *info,
581 if (ratio < 0) ratio = 0;
582 if (ratio > 1) ratio = 1;
583 for (k = 0; k < info->gamma_size; k++)
585 info->red2[k] = info->red1[k] * ratio;
586 info->green2[k] = info->green1[k] * ratio;
587 info->blue2[k] = info->blue1[k] * ratio;
590 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nred,
591 XSGIVC_MComponentRed, info->red2);
592 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->ngreen,
593 XSGIVC_MComponentGreen, info->green2);
594 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nblue,
595 XSGIVC_MComponentBlue, info->blue2);
599 #endif /* HAVE_SGI_VC_EXTENSION */
603 /* XFree86 4.x+ Gamma fading */
605 #ifdef HAVE_XF86VMODE_GAMMA
607 #include <X11/extensions/xf86vmode.h>
610 XF86VidModeGamma vmg;
612 unsigned short *r, *g, *b;
615 static int xf86_check_gamma_extension (Display *dpy);
616 static Bool xf86_whack_gamma (Display *dpy, int screen,
617 xf86_gamma_info *ginfo, float ratio);
620 xf86_gamma_fade (Display *dpy,
621 Window *black_windows, int seconds, int ticks,
622 Bool out_p, Bool clear_windows)
624 int steps = seconds * ticks;
625 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
627 int nscreens = ScreenCount(dpy);
628 struct timeval then, now;
629 #ifdef GETTIMEOFDAY_TWO_ARGS
634 xf86_gamma_info *info = 0;
636 static int ext_ok = -1;
638 /* Only probe the extension once: the answer isn't going to change. */
640 ext_ok = xf86_check_gamma_extension (dpy);
642 /* If this server doesn't have the gamma extension, bug out. */
646 # ifndef HAVE_XF86VMODE_GAMMA_RAMP
647 if (ext_ok == 2) ext_ok = 1; /* server is newer than client! */
650 info = (xf86_gamma_info *) calloc(nscreens, sizeof(*info));
652 /* Get the current gamma maps for all screens.
653 Bug out and return -1 if we can't get them for some screen.
655 for (screen = 0; screen < nscreens; screen++)
657 if (ext_ok == 1) /* only have gamma parameter, not ramps. */
659 if (!XF86VidModeGetGamma(dpy, screen, &info[screen].vmg))
662 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
663 else if (ext_ok == 2) /* have ramps */
665 if (!XF86VidModeGetGammaRampSize(dpy, screen, &info[screen].size))
667 if (info[screen].size <= 0)
670 info[screen].r = (unsigned short *)
671 calloc(info[screen].size, sizeof(unsigned short));
672 info[screen].g = (unsigned short *)
673 calloc(info[screen].size, sizeof(unsigned short));
674 info[screen].b = (unsigned short *)
675 calloc(info[screen].size, sizeof(unsigned short));
677 if (!(info[screen].r && info[screen].g && info[screen].b))
680 if (!XF86VidModeGetGammaRamp(dpy, screen, info[screen].size,
686 # endif /* HAVE_XF86VMODE_GAMMA_RAMP */
691 #ifdef GETTIMEOFDAY_TWO_ARGS
692 gettimeofday(&then, &tzp);
697 /* If we're fading in (from black), then first crank the gamma all the
698 way down to 0, then take the windows off the screen.
701 for (screen = 0; screen < nscreens; screen++)
703 xf86_whack_gamma(dpy, screen, &info[screen], 0.0);
704 if (black_windows && black_windows[screen])
706 XUnmapWindow (dpy, black_windows[screen]);
707 XClearWindow (dpy, black_windows[screen]);
713 /* Iterate by steps of the animation... */
714 for (i = (out_p ? steps : 0);
715 (out_p ? i > 0 : i < steps);
718 for (screen = 0; screen < nscreens; screen++)
720 xf86_whack_gamma(dpy, screen, &info[screen],
721 (((float)i) / ((float)steps)));
723 /* If there is user activity, bug out. (Bug out on keypresses or
724 mouse presses, but not motion, and not release events. Bugging
725 out on motion made the unfade hack be totally useless, I think.)
727 We put the event back so that the calling code can notice it too.
728 It would be better to not remove it at all, but that's harder
729 because Xlib has such a non-design for this kind of crap, and
730 in this application it doesn't matter if the events end up out
731 of order, so in the grand unix tradition we say "fuck it" and
732 do something that mostly works for the time being.
734 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
737 XPutBackEvent (dpy, &dummy_event);
741 #ifdef GETTIMEOFDAY_TWO_ARGS
742 gettimeofday(&now, &tzp);
747 /* If we haven't already used up our alotted time, sleep to avoid
748 changing the colormap too fast. */
750 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
751 now.tv_usec - then.tv_usec);
752 then.tv_sec = now.tv_sec;
753 then.tv_usec = now.tv_usec;
754 if (usecs_per_step > diff)
755 usleep (usecs_per_step - diff);
763 if (out_p && black_windows)
765 for (screen = 0; screen < nscreens; screen++)
768 XClearWindow (dpy, black_windows[screen]);
769 XMapRaised (dpy, black_windows[screen]);
774 /* I can't explain this; without this delay, we get a flicker.
775 I suppose there's some lossage with stale bits being in the
776 hardware frame buffer or something, and this delay gives it
777 time to flush out. This sucks! */
778 usleep(100000); /* 1/10th second */
780 for (screen = 0; screen < nscreens; screen++)
781 xf86_whack_gamma(dpy, screen, &info[screen], 1.0);
789 for (screen = 0; screen < nscreens; screen++)
791 if (info[screen].r) free(info[screen].r);
792 if (info[screen].g) free(info[screen].g);
793 if (info[screen].b) free(info[screen].b);
802 /* This bullshit is needed because the VidMode extension doesn't work
803 on remote displays -- but if the remote display has the extension
804 at all, XF86VidModeQueryExtension returns true, and then
805 XF86VidModeQueryVersion dies with an X error. Thank you XFree,
809 static Bool error_handler_hit_p = False;
812 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
814 error_handler_hit_p = True;
819 safe_XF86VidModeQueryVersion (Display *dpy, int *majP, int *minP)
822 XErrorHandler old_handler;
824 error_handler_hit_p = False;
825 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
827 result = XF86VidModeQueryVersion (dpy, majP, minP);
830 XSetErrorHandler (old_handler);
833 return (error_handler_hit_p
840 /* VidModeExtension version 2.0 or better is needed to do gamma.
841 2.0 added gamma values; 2.1 added gamma ramps.
843 # define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
844 # define XF86_VIDMODE_GAMMA_MIN_MINOR 0
845 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
846 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
850 /* Returns 0 if gamma fading not available; 1 if only gamma value setting
851 is available; 2 if gamma ramps are available.
854 xf86_check_gamma_extension (Display *dpy)
856 int event, error, major, minor;
858 if (!XF86VidModeQueryExtension (dpy, &event, &error))
859 return 0; /* display doesn't have the extension. */
861 if (!safe_XF86VidModeQueryVersion (dpy, &major, &minor))
862 return 0; /* unable to get version number? */
864 if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
865 (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
866 minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
867 return 0; /* extension is too old for gamma. */
869 if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
870 (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
871 minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
872 return 1; /* extension is too old for gamma ramps. */
879 /* XFree doesn't let you set gamma to a value smaller than this.
880 Apparently they didn't anticipate the trick I'm doing here...
882 #define XF86_MIN_GAMMA 0.1
886 xf86_whack_gamma(Display *dpy, int screen, xf86_gamma_info *info,
891 if (ratio < 0) ratio = 0;
892 if (ratio > 1) ratio = 1;
894 if (info->size == 0) /* we only have a gamma number, not a ramp. */
898 g2.red = info->vmg.red * ratio;
899 g2.green = info->vmg.green * ratio;
900 g2.blue = info->vmg.blue * ratio;
902 # ifdef XF86_MIN_GAMMA
903 if (g2.red < XF86_MIN_GAMMA) g2.red = XF86_MIN_GAMMA;
904 if (g2.green < XF86_MIN_GAMMA) g2.green = XF86_MIN_GAMMA;
905 if (g2.blue < XF86_MIN_GAMMA) g2.blue = XF86_MIN_GAMMA;
908 status = XF86VidModeSetGamma (dpy, screen, &g2);
912 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
914 unsigned short *r, *g, *b;
916 r = (unsigned short *) malloc(info->size * sizeof(unsigned short));
917 g = (unsigned short *) malloc(info->size * sizeof(unsigned short));
918 b = (unsigned short *) malloc(info->size * sizeof(unsigned short));
920 for (i = 0; i < info->size; i++)
922 r[i] = info->r[i] * ratio;
923 g[i] = info->g[i] * ratio;
924 b[i] = info->b[i] * ratio;
927 status = XF86VidModeSetGammaRamp(dpy, screen, info->size, r, g, b);
933 # else /* !HAVE_XF86VMODE_GAMMA_RAMP */
935 # endif /* !HAVE_XF86VMODE_GAMMA_RAMP */
942 #endif /* HAVE_XF86VMODE_GAMMA */