1 /* xscreensaver, Copyright (c) 1992-2003 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 nwindows,
77 int seconds, int ticks,
78 Bool out_p, Bool clear_windows);
80 #ifdef HAVE_SGI_VC_EXTENSION
81 static int sgi_gamma_fade (Display *dpy,
82 Window *black_windows, int nwindows,
83 int seconds, int ticks,
84 Bool out_p, Bool clear_windows);
85 #endif /* HAVE_SGI_VC_EXTENSION */
87 #ifdef HAVE_XF86VMODE_GAMMA
88 static int xf86_gamma_fade (Display *dpy,
89 Window *black_windows, int nwindows,
90 int seconds, int ticks,
91 Bool out_p, Bool clear_windows);
92 #endif /* HAVE_XF86VMODE_GAMMA */
96 fade_screens (Display *dpy, Colormap *cmaps,
97 Window *black_windows, int nwindows,
98 int seconds, int ticks,
99 Bool out_p, Bool clear_windows)
101 int oseconds = seconds;
102 Bool was_in_p = !out_p;
104 /* When we're asked to fade in, first fade out, then fade in.
105 That way all the transitions are smooth -- from what's on the
106 screen, to black, to the desktop.
110 clear_windows = True;
119 /* #### printf("\n\nfade_screens %d %d %d\n", seconds, ticks, out_p); */
121 #ifdef HAVE_SGI_VC_EXTENSION
122 /* First try to do it by fading the gamma in an SGI-specific way... */
123 if (0 == sgi_gamma_fade(dpy, black_windows, nwindows,
124 seconds, ticks, out_p,
128 #endif /* HAVE_SGI_VC_EXTENSION */
130 #ifdef HAVE_XF86VMODE_GAMMA
131 /* Then try to do it by fading the gamma in an XFree86-specific way... */
132 if (0 == xf86_gamma_fade(dpy, black_windows, nwindows,
133 seconds, ticks, out_p,
137 #endif /* HAVE_XF86VMODE_GAMMA */
139 /* Else, do it the old-fashioned way, which (somewhat) loses if
140 there are TrueColor windows visible. */
141 fade_screens_1 (dpy, cmaps, black_windows, nwindows,
143 out_p, clear_windows);
145 /* If we were supposed to be fading in, do so now (we just faded out,
146 so now fade back in.)
152 seconds = oseconds * 2 / 3;
160 /* The business with `cmaps_per_screen' is to fake out the SGI 8-bit video
161 hardware, which is capable of installing multiple (4) colormaps
162 simultaniously. We have to install multiple copies of the same set of
163 colors in order to fill up all the available slots in the hardware color
164 lookup table, so we install an extra N colormaps per screen to make sure
165 that all screens really go black.
167 I'm told that this trick also works with XInside's AcceleratedX when using
168 the Matrox Millennium card (which also allows multiple PseudoColor and
169 TrueColor visuals to co-exist and display properly at the same time.)
171 This trick works ok on the 24-bit Indy video hardware, but doesn't work at
172 all on the O2 24-bit hardware. I guess the higher-end hardware is too
173 "good" for this to work (dammit.) So... I figured out the "right" way to
174 do this on SGIs, which is to ramp the monitor's gamma down to 0. That's
175 what is implemented in sgi_gamma_fade(), so we use that if we can.
178 fade_screens_1 (Display *dpy, Colormap *cmaps,
179 Window *black_windows, int nwindows,
180 int seconds, int ticks,
181 Bool out_p, Bool clear_windows)
184 int steps = seconds * ticks;
185 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
187 int cmaps_per_screen = 5;
188 int nscreens = ScreenCount(dpy);
189 int ncmaps = nscreens * cmaps_per_screen;
190 Colormap *fade_cmaps = 0;
191 Bool installed = False;
193 XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors;
194 struct timeval then, now;
195 #ifdef GETTIMEOFDAY_TWO_ARGS
200 for (i = 0; i < nscreens; i++)
201 total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
203 orig_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
204 current_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
206 /* Get the contents of the colormap we are fading from or to. */
207 screen_colors = orig_colors;
208 for (i = 0; i < nscreens; i++)
210 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, i));
211 Colormap cmap = (cmaps ? cmaps[i] : 0);
212 if (!cmap) cmap = DefaultColormap(dpy, i);
214 for (j = 0; j < ncolors; j++)
215 screen_colors[j].pixel = j;
216 XQueryColors (dpy, cmap, screen_colors, ncolors);
218 screen_colors += ncolors;
221 memcpy (current_colors, orig_colors, total_ncolors * sizeof (XColor));
224 /* Make the writable colormaps (we keep these around and reuse them.) */
227 fade_cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
228 for (i = 0; i < nscreens; i++)
230 Visual *v = DefaultVisual(dpy, i);
231 Screen *s = ScreenOfDisplay(dpy, i);
232 if (has_writable_cells (s, v))
233 for (j = 0; j < cmaps_per_screen; j++)
234 fade_cmaps[(i * cmaps_per_screen) + j] =
235 XCreateColormap (dpy, RootWindowOfScreen (s), v, AllocAll);
239 #ifdef GETTIMEOFDAY_TWO_ARGS
240 gettimeofday(&then, &tzp);
245 /* Iterate by steps of the animation... */
246 for (i = (out_p ? steps : 0);
247 (out_p ? i > 0 : i < steps);
251 /* For each screen, compute the current value of each color...
253 orig_screen_colors = orig_colors;
254 screen_colors = current_colors;
255 for (j = 0; j < nscreens; j++)
257 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
258 for (k = 0; k < ncolors; k++)
260 /* This doesn't take into account the relative luminance of the
261 RGB components (0.299, 0.587, and 0.114 at gamma 2.2) but
262 the difference is imperceptible for this application... */
263 screen_colors[k].red = orig_screen_colors[k].red * i / steps;
264 screen_colors[k].green = orig_screen_colors[k].green * i / steps;
265 screen_colors[k].blue = orig_screen_colors[k].blue * i / steps;
267 screen_colors += ncolors;
268 orig_screen_colors += ncolors;
271 /* Put the colors into the maps...
273 screen_colors = current_colors;
274 for (j = 0; j < nscreens; j++)
276 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
277 for (k = 0; k < cmaps_per_screen; k++)
279 Colormap c = fade_cmaps[j * cmaps_per_screen + k];
281 XStoreColors (dpy, c, screen_colors, ncolors);
283 screen_colors += ncolors;
286 /* Put the maps on the screens, and then take the windows off the screen.
287 (only need to do this the first time through the loop.)
291 for (j = 0; j < ncmaps; j++)
293 XInstallColormap (dpy, fade_cmaps[j]);
296 if (black_windows && !out_p)
297 for (j = 0; j < nwindows; j++)
298 if (black_windows[j])
300 XUnmapWindow (dpy, black_windows[j]);
301 XClearWindow (dpy, black_windows[j]);
307 /* If there is user activity, bug out. (Bug out on keypresses or
308 mouse presses, but not motion, and not release events. Bugging
309 out on motion made the unfade hack be totally useless, I think.)
311 We put the event back so that the calling code can notice it too.
312 It would be better to not remove it at all, but that's harder
313 because Xlib has such a non-design for this kind of crap, and
314 in this application it doesn't matter if the events end up out
315 of order, so in the grand unix tradition we say "fuck it" and
316 do something that mostly works for the time being.
318 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask), &dummy_event))
320 XPutBackEvent (dpy, &dummy_event);
324 #ifdef GETTIMEOFDAY_TWO_ARGS
325 gettimeofday(&now, &tzp);
330 /* If we haven't already used up our alotted time, sleep to avoid
331 changing the colormap too fast. */
333 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
334 now.tv_usec - then.tv_usec);
335 then.tv_sec = now.tv_sec;
336 then.tv_usec = now.tv_usec;
337 if (usecs_per_step > diff)
338 usleep (usecs_per_step - diff);
344 if (orig_colors) free (orig_colors);
345 if (current_colors) free (current_colors);
347 /* If we've been given windows to raise after blackout, raise them before
348 releasing the colormaps.
350 if (out_p && black_windows)
352 for (i = 0; i < nwindows; i++)
355 XClearWindow (dpy, black_windows[i]);
356 XMapRaised (dpy, black_windows[i]);
361 /* Now put the target maps back.
362 If we're fading out, use the given cmap (or the default cmap, if none.)
363 If we're fading in, always use the default cmap.
365 for (i = 0; i < nscreens; i++)
367 Colormap cmap = (cmaps ? cmaps[i] : 0);
369 cmap = DefaultColormap(dpy, i);
370 XInstallColormap (dpy, cmap);
373 /* The fade (in or out) is complete, so we don't need the black maps on
376 for (i = 0; i < ncmaps; i++)
379 XUninstallColormap(dpy, fade_cmaps[i]);
380 XFreeColormap(dpy, fade_cmaps[i]);
389 /* SGI Gamma fading */
391 #ifdef HAVE_SGI_VC_EXTENSION
393 # include <X11/extensions/XSGIvc.h>
395 struct screen_sgi_gamma_info {
396 int gamma_map; /* ??? always using 0 */
397 int nred, ngreen, nblue;
398 unsigned short *red1, *green1, *blue1;
399 unsigned short *red2, *green2, *blue2;
406 static void sgi_whack_gamma(Display *dpy, int screen,
407 struct screen_sgi_gamma_info *info, float ratio);
410 sgi_gamma_fade (Display *dpy,
411 Window *black_windows, int nwindows,
412 int seconds, int ticks,
413 Bool out_p, Bool clear_windows)
415 int steps = seconds * ticks;
416 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
418 int nscreens = ScreenCount(dpy);
419 struct timeval then, now;
420 #ifdef GETTIMEOFDAY_TWO_ARGS
425 struct screen_sgi_gamma_info *info = (struct screen_sgi_gamma_info *)
426 calloc(nscreens, sizeof(*info));
428 /* Get the current gamma maps for all screens.
429 Bug out and return -1 if we can't get them for some screen.
431 for (screen = 0; screen < nscreens; screen++)
433 if (!XSGIvcQueryGammaMap(dpy, screen, info[screen].gamma_map,
434 &info[screen].gamma_size,
435 &info[screen].gamma_precision,
436 &info[screen].alpha_p))
439 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
440 XSGIVC_COMPONENT_RED,
441 &info[screen].nred, &info[screen].red1))
443 if (! XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
444 XSGIVC_COMPONENT_GREEN,
445 &info[screen].ngreen, &info[screen].green1))
447 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
448 XSGIVC_COMPONENT_BLUE,
449 &info[screen].nblue, &info[screen].blue1))
452 if (info[screen].gamma_precision == 8) /* Scale it up to 16 bits. */
455 for(j = 0; j < info[screen].nred; j++)
456 info[screen].red1[j] =
457 ((info[screen].red1[j] << 8) | info[screen].red1[j]);
458 for(j = 0; j < info[screen].ngreen; j++)
459 info[screen].green1[j] =
460 ((info[screen].green1[j] << 8) | info[screen].green1[j]);
461 for(j = 0; j < info[screen].nblue; j++)
462 info[screen].blue1[j] =
463 ((info[screen].blue1[j] << 8) | info[screen].blue1[j]);
466 info[screen].red2 = (unsigned short *)
467 malloc(sizeof(*info[screen].red2) * (info[screen].nred+1));
468 info[screen].green2 = (unsigned short *)
469 malloc(sizeof(*info[screen].green2) * (info[screen].ngreen+1));
470 info[screen].blue2 = (unsigned short *)
471 malloc(sizeof(*info[screen].blue2) * (info[screen].nblue+1));
474 #ifdef GETTIMEOFDAY_TWO_ARGS
475 gettimeofday(&then, &tzp);
480 /* If we're fading in (from black), then first crank the gamma all the
481 way down to 0, then take the windows off the screen.
485 for (screen = 0; screen < nscreens; screen++)
486 sgi_whack_gamma(dpy, screen, &info[screen], 0.0);
488 for (screen = 0; screen < nwindows; screen++)
489 if (black_windows && black_windows[screen])
491 XUnmapWindow (dpy, black_windows[screen]);
492 XClearWindow (dpy, black_windows[screen]);
497 /* Iterate by steps of the animation... */
498 for (i = (out_p ? steps : 0);
499 (out_p ? i > 0 : i < steps);
502 for (screen = 0; screen < nscreens; screen++)
504 sgi_whack_gamma(dpy, screen, &info[screen],
505 (((float)i) / ((float)steps)));
507 /* If there is user activity, bug out. (Bug out on keypresses or
508 mouse presses, but not motion, and not release events. Bugging
509 out on motion made the unfade hack be totally useless, I think.)
511 We put the event back so that the calling code can notice it too.
512 It would be better to not remove it at all, but that's harder
513 because Xlib has such a non-design for this kind of crap, and
514 in this application it doesn't matter if the events end up out
515 of order, so in the grand unix tradition we say "fuck it" and
516 do something that mostly works for the time being.
518 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
521 XPutBackEvent (dpy, &dummy_event);
525 #ifdef GETTIMEOFDAY_TWO_ARGS
526 gettimeofday(&now, &tzp);
531 /* If we haven't already used up our alotted time, sleep to avoid
532 changing the colormap too fast. */
534 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
535 now.tv_usec - then.tv_usec);
536 then.tv_sec = now.tv_sec;
537 then.tv_usec = now.tv_usec;
538 if (usecs_per_step > diff)
539 usleep (usecs_per_step - diff);
547 if (out_p && black_windows)
549 for (screen = 0; screen < nwindows; screen++)
552 XClearWindow (dpy, black_windows[screen]);
553 XMapRaised (dpy, black_windows[screen]);
558 /* I can't explain this; without this delay, we get a flicker.
559 I suppose there's some lossage with stale bits being in the
560 hardware frame buffer or something, and this delay gives it
561 time to flush out. This sucks! */
562 usleep(100000); /* 1/10th second */
564 for (screen = 0; screen < nscreens; screen++)
565 sgi_whack_gamma(dpy, screen, &info[screen], 1.0);
571 for (screen = 0; screen < nscreens; screen++)
573 if (info[screen].red1) free (info[screen].red1);
574 if (info[screen].green1) free (info[screen].green1);
575 if (info[screen].blue1) free (info[screen].blue1);
576 if (info[screen].red2) free (info[screen].red2);
577 if (info[screen].green2) free (info[screen].green2);
578 if (info[screen].blue2) free (info[screen].blue2);
586 sgi_whack_gamma(Display *dpy, int screen, struct screen_sgi_gamma_info *info,
591 if (ratio < 0) ratio = 0;
592 if (ratio > 1) ratio = 1;
593 for (k = 0; k < info->gamma_size; k++)
595 info->red2[k] = info->red1[k] * ratio;
596 info->green2[k] = info->green1[k] * ratio;
597 info->blue2[k] = info->blue1[k] * ratio;
600 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nred,
601 XSGIVC_MComponentRed, info->red2);
602 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->ngreen,
603 XSGIVC_MComponentGreen, info->green2);
604 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nblue,
605 XSGIVC_MComponentBlue, info->blue2);
609 #endif /* HAVE_SGI_VC_EXTENSION */
613 /* XFree86 4.x+ Gamma fading */
615 #ifdef HAVE_XF86VMODE_GAMMA
617 #include <X11/extensions/xf86vmode.h>
620 XF86VidModeGamma vmg;
622 unsigned short *r, *g, *b;
625 static int xf86_check_gamma_extension (Display *dpy);
626 static Bool xf86_whack_gamma (Display *dpy, int screen,
627 xf86_gamma_info *ginfo, float ratio);
630 xf86_gamma_fade (Display *dpy,
631 Window *black_windows, int nwindows,
632 int seconds, int ticks,
633 Bool out_p, Bool clear_windows)
635 int steps = seconds * ticks;
636 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
638 int nscreens = ScreenCount(dpy);
639 struct timeval then, now;
640 #ifdef GETTIMEOFDAY_TWO_ARGS
645 xf86_gamma_info *info = 0;
647 static int ext_ok = -1;
649 /* Only probe the extension once: the answer isn't going to change. */
651 ext_ok = xf86_check_gamma_extension (dpy);
653 /* If this server doesn't have the gamma extension, bug out. */
657 # ifndef HAVE_XF86VMODE_GAMMA_RAMP
658 if (ext_ok == 2) ext_ok = 1; /* server is newer than client! */
661 info = (xf86_gamma_info *) calloc(nscreens, sizeof(*info));
663 /* Get the current gamma maps for all screens.
664 Bug out and return -1 if we can't get them for some screen.
666 for (screen = 0; screen < nscreens; screen++)
668 if (ext_ok == 1) /* only have gamma parameter, not ramps. */
670 if (!XF86VidModeGetGamma(dpy, screen, &info[screen].vmg))
673 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
674 else if (ext_ok == 2) /* have ramps */
676 if (!XF86VidModeGetGammaRampSize(dpy, screen, &info[screen].size))
678 if (info[screen].size <= 0)
681 info[screen].r = (unsigned short *)
682 calloc(info[screen].size, sizeof(unsigned short));
683 info[screen].g = (unsigned short *)
684 calloc(info[screen].size, sizeof(unsigned short));
685 info[screen].b = (unsigned short *)
686 calloc(info[screen].size, sizeof(unsigned short));
688 if (!(info[screen].r && info[screen].g && info[screen].b))
691 if (!XF86VidModeGetGammaRamp(dpy, screen, info[screen].size,
697 # endif /* HAVE_XF86VMODE_GAMMA_RAMP */
702 #ifdef GETTIMEOFDAY_TWO_ARGS
703 gettimeofday(&then, &tzp);
708 /* If we're fading in (from black), then first crank the gamma all the
709 way down to 0, then take the windows off the screen.
713 for (screen = 0; screen < nscreens; screen++)
714 xf86_whack_gamma(dpy, screen, &info[screen], 0.0);
715 for (screen = 0; screen < nwindows; screen++)
716 if (black_windows && black_windows[screen])
718 XUnmapWindow (dpy, black_windows[screen]);
719 XClearWindow (dpy, black_windows[screen]);
724 /* Iterate by steps of the animation... */
725 for (i = (out_p ? steps : 0);
726 (out_p ? i > 0 : i < steps);
729 for (screen = 0; screen < nscreens; screen++)
731 xf86_whack_gamma(dpy, screen, &info[screen],
732 (((float)i) / ((float)steps)));
734 /* If there is user activity, bug out. (Bug out on keypresses or
735 mouse presses, but not motion, and not release events. Bugging
736 out on motion made the unfade hack be totally useless, I think.)
738 We put the event back so that the calling code can notice it too.
739 It would be better to not remove it at all, but that's harder
740 because Xlib has such a non-design for this kind of crap, and
741 in this application it doesn't matter if the events end up out
742 of order, so in the grand unix tradition we say "fuck it" and
743 do something that mostly works for the time being.
745 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
748 XPutBackEvent (dpy, &dummy_event);
752 #ifdef GETTIMEOFDAY_TWO_ARGS
753 gettimeofday(&now, &tzp);
758 /* If we haven't already used up our alotted time, sleep to avoid
759 changing the colormap too fast. */
761 long diff = (((now.tv_sec - then.tv_sec) * 1000000) +
762 now.tv_usec - then.tv_usec);
763 then.tv_sec = now.tv_sec;
764 then.tv_usec = now.tv_usec;
765 if (usecs_per_step > diff)
766 usleep (usecs_per_step - diff);
774 if (out_p && black_windows)
776 for (screen = 0; screen < nwindows; screen++)
779 XClearWindow (dpy, black_windows[screen]);
780 XMapRaised (dpy, black_windows[screen]);
785 /* I can't explain this; without this delay, we get a flicker.
786 I suppose there's some lossage with stale bits being in the
787 hardware frame buffer or something, and this delay gives it
788 time to flush out. This sucks! */
789 usleep(100000); /* 1/10th second */
791 for (screen = 0; screen < nscreens; screen++)
792 xf86_whack_gamma(dpy, screen, &info[screen], 1.0);
800 for (screen = 0; screen < nscreens; screen++)
802 if (info[screen].r) free(info[screen].r);
803 if (info[screen].g) free(info[screen].g);
804 if (info[screen].b) free(info[screen].b);
813 /* This bullshit is needed because the VidMode extension doesn't work
814 on remote displays -- but if the remote display has the extension
815 at all, XF86VidModeQueryExtension returns true, and then
816 XF86VidModeQueryVersion dies with an X error. Thank you XFree,
820 static Bool error_handler_hit_p = False;
823 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
825 error_handler_hit_p = True;
830 safe_XF86VidModeQueryVersion (Display *dpy, int *majP, int *minP)
833 XErrorHandler old_handler;
835 error_handler_hit_p = False;
836 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
838 result = XF86VidModeQueryVersion (dpy, majP, minP);
841 XSetErrorHandler (old_handler);
844 return (error_handler_hit_p
851 /* VidModeExtension version 2.0 or better is needed to do gamma.
852 2.0 added gamma values; 2.1 added gamma ramps.
854 # define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
855 # define XF86_VIDMODE_GAMMA_MIN_MINOR 0
856 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
857 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
861 /* Returns 0 if gamma fading not available; 1 if only gamma value setting
862 is available; 2 if gamma ramps are available.
865 xf86_check_gamma_extension (Display *dpy)
867 int event, error, major, minor;
869 if (!XF86VidModeQueryExtension (dpy, &event, &error))
870 return 0; /* display doesn't have the extension. */
872 if (!safe_XF86VidModeQueryVersion (dpy, &major, &minor))
873 return 0; /* unable to get version number? */
875 if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
876 (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
877 minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
878 return 0; /* extension is too old for gamma. */
880 if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
881 (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
882 minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
883 return 1; /* extension is too old for gamma ramps. */
890 /* XFree doesn't let you set gamma to a value smaller than this.
891 Apparently they didn't anticipate the trick I'm doing here...
893 #define XF86_MIN_GAMMA 0.1
897 xf86_whack_gamma(Display *dpy, int screen, xf86_gamma_info *info,
902 if (ratio < 0) ratio = 0;
903 if (ratio > 1) ratio = 1;
905 if (info->size == 0) /* we only have a gamma number, not a ramp. */
909 g2.red = info->vmg.red * ratio;
910 g2.green = info->vmg.green * ratio;
911 g2.blue = info->vmg.blue * ratio;
913 # ifdef XF86_MIN_GAMMA
914 if (g2.red < XF86_MIN_GAMMA) g2.red = XF86_MIN_GAMMA;
915 if (g2.green < XF86_MIN_GAMMA) g2.green = XF86_MIN_GAMMA;
916 if (g2.blue < XF86_MIN_GAMMA) g2.blue = XF86_MIN_GAMMA;
919 status = XF86VidModeSetGamma (dpy, screen, &g2);
923 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
925 unsigned short *r, *g, *b;
927 r = (unsigned short *) malloc(info->size * sizeof(unsigned short));
928 g = (unsigned short *) malloc(info->size * sizeof(unsigned short));
929 b = (unsigned short *) malloc(info->size * sizeof(unsigned short));
931 for (i = 0; i < info->size; i++)
933 r[i] = info->r[i] * ratio;
934 g[i] = info->g[i] * ratio;
935 b[i] = info->b[i] * ratio;
938 status = XF86VidModeSetGammaRamp(dpy, screen, info->size, r, g, b);
944 # else /* !HAVE_XF86VMODE_GAMMA_RAMP */
946 # endif /* !HAVE_XF86VMODE_GAMMA_RAMP */
953 #endif /* HAVE_XF86VMODE_GAMMA */