1 /* xscreensaver, Copyright (c) 1992-2011 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;
161 sleep_from (struct timeval *now, struct timeval *then, long usecs_per_step)
163 /* If several seconds have passed, the machine must have been asleep
164 or thrashing or something. Don't sleep in that case, to avoid
165 overflowing and sleeping for an unconscionably long time. This
166 function should only be sleeping for very short periods.
168 if (now->tv_sec - then->tv_sec < 5)
170 long diff = (((now->tv_sec - then->tv_sec) * 1000000) +
171 now->tv_usec - then->tv_usec);
172 if (usecs_per_step > diff)
173 usleep (usecs_per_step - diff);
176 then->tv_sec = now->tv_sec;
177 then->tv_usec = now->tv_usec;
182 /* The business with `cmaps_per_screen' is to fake out the SGI 8-bit video
183 hardware, which is capable of installing multiple (4) colormaps
184 simultaneously. We have to install multiple copies of the same set of
185 colors in order to fill up all the available slots in the hardware color
186 lookup table, so we install an extra N colormaps per screen to make sure
187 that all screens really go black.
189 I'm told that this trick also works with XInside's AcceleratedX when using
190 the Matrox Millennium card (which also allows multiple PseudoColor and
191 TrueColor visuals to co-exist and display properly at the same time.)
193 This trick works ok on the 24-bit Indy video hardware, but doesn't work at
194 all on the O2 24-bit hardware. I guess the higher-end hardware is too
195 "good" for this to work (dammit.) So... I figured out the "right" way to
196 do this on SGIs, which is to ramp the monitor's gamma down to 0. That's
197 what is implemented in sgi_gamma_fade(), so we use that if we can.
200 fade_screens_1 (Display *dpy, Colormap *cmaps,
201 Window *black_windows, int nwindows,
202 int seconds, int ticks,
203 Bool out_p, Bool clear_windows)
206 int steps = seconds * ticks;
207 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
209 int cmaps_per_screen = 5;
210 int nscreens = ScreenCount(dpy);
211 int ncmaps = nscreens * cmaps_per_screen;
212 Colormap *fade_cmaps = 0;
213 Bool installed = False;
215 XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors;
216 struct timeval then, now;
217 #ifdef GETTIMEOFDAY_TWO_ARGS
222 for (i = 0; i < nscreens; i++)
223 total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
225 orig_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
226 current_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
228 /* Get the contents of the colormap we are fading from or to. */
229 screen_colors = orig_colors;
230 for (i = 0; i < nscreens; i++)
232 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, i));
233 Colormap cmap = (cmaps ? cmaps[i] : 0);
234 if (!cmap) cmap = DefaultColormap(dpy, i);
236 for (j = 0; j < ncolors; j++)
237 screen_colors[j].pixel = j;
238 XQueryColors (dpy, cmap, screen_colors, ncolors);
240 screen_colors += ncolors;
243 memcpy (current_colors, orig_colors, total_ncolors * sizeof (XColor));
246 /* Make the writable colormaps (we keep these around and reuse them.) */
249 fade_cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
250 for (i = 0; i < nscreens; i++)
252 Visual *v = DefaultVisual(dpy, i);
253 Screen *s = ScreenOfDisplay(dpy, i);
254 if (has_writable_cells (s, v))
255 for (j = 0; j < cmaps_per_screen; j++)
256 fade_cmaps[(i * cmaps_per_screen) + j] =
257 XCreateColormap (dpy, RootWindowOfScreen (s), v, AllocAll);
261 #ifdef GETTIMEOFDAY_TWO_ARGS
262 gettimeofday(&then, &tzp);
267 /* Iterate by steps of the animation... */
268 for (i = (out_p ? steps : 0);
269 (out_p ? i > 0 : i < steps);
273 /* For each screen, compute the current value of each color...
275 orig_screen_colors = orig_colors;
276 screen_colors = current_colors;
277 for (j = 0; j < nscreens; j++)
279 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
280 for (k = 0; k < ncolors; k++)
282 /* This doesn't take into account the relative luminance of the
283 RGB components (0.299, 0.587, and 0.114 at gamma 2.2) but
284 the difference is imperceptible for this application... */
285 screen_colors[k].red = orig_screen_colors[k].red * i / steps;
286 screen_colors[k].green = orig_screen_colors[k].green * i / steps;
287 screen_colors[k].blue = orig_screen_colors[k].blue * i / steps;
289 screen_colors += ncolors;
290 orig_screen_colors += ncolors;
293 /* Put the colors into the maps...
295 screen_colors = current_colors;
296 for (j = 0; j < nscreens; j++)
298 int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
299 for (k = 0; k < cmaps_per_screen; k++)
301 Colormap c = fade_cmaps[j * cmaps_per_screen + k];
303 XStoreColors (dpy, c, screen_colors, ncolors);
305 screen_colors += ncolors;
308 /* Put the maps on the screens, and then take the windows off the screen.
309 (only need to do this the first time through the loop.)
313 for (j = 0; j < ncmaps; j++)
315 XInstallColormap (dpy, fade_cmaps[j]);
318 if (black_windows && !out_p)
319 for (j = 0; j < nwindows; j++)
320 if (black_windows[j])
322 XUnmapWindow (dpy, black_windows[j]);
323 XClearWindow (dpy, black_windows[j]);
329 /* If there is user activity, bug out. (Bug out on keypresses or
330 mouse presses, but not motion, and not release events. Bugging
331 out on motion made the unfade hack be totally useless, I think.)
333 We put the event back so that the calling code can notice it too.
334 It would be better to not remove it at all, but that's harder
335 because Xlib has such a non-design for this kind of crap, and
336 in this application it doesn't matter if the events end up out
337 of order, so in the grand unix tradition we say "fuck it" and
338 do something that mostly works for the time being.
340 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask), &dummy_event))
342 XPutBackEvent (dpy, &dummy_event);
346 #ifdef GETTIMEOFDAY_TWO_ARGS
347 gettimeofday(&now, &tzp);
352 /* If we haven't already used up our alotted time, sleep to avoid
353 changing the colormap too fast. */
354 sleep_from (&now, &then, usecs_per_step);
359 if (orig_colors) free (orig_colors);
360 if (current_colors) free (current_colors);
362 /* If we've been given windows to raise after blackout, raise them before
363 releasing the colormaps.
365 if (out_p && black_windows)
367 for (i = 0; i < nwindows; i++)
370 XClearWindow (dpy, black_windows[i]);
371 XMapRaised (dpy, black_windows[i]);
376 /* Now put the target maps back.
377 If we're fading out, use the given cmap (or the default cmap, if none.)
378 If we're fading in, always use the default cmap.
380 for (i = 0; i < nscreens; i++)
382 Colormap cmap = (cmaps ? cmaps[i] : 0);
384 cmap = DefaultColormap(dpy, i);
385 XInstallColormap (dpy, cmap);
388 /* The fade (in or out) is complete, so we don't need the black maps on
391 for (i = 0; i < ncmaps; i++)
394 XUninstallColormap(dpy, fade_cmaps[i]);
395 XFreeColormap(dpy, fade_cmaps[i]);
404 /* SGI Gamma fading */
406 #ifdef HAVE_SGI_VC_EXTENSION
408 # include <X11/extensions/XSGIvc.h>
410 struct screen_sgi_gamma_info {
411 int gamma_map; /* ??? always using 0 */
412 int nred, ngreen, nblue;
413 unsigned short *red1, *green1, *blue1;
414 unsigned short *red2, *green2, *blue2;
421 static void sgi_whack_gamma(Display *dpy, int screen,
422 struct screen_sgi_gamma_info *info, float ratio);
425 sgi_gamma_fade (Display *dpy,
426 Window *black_windows, int nwindows,
427 int seconds, int ticks,
428 Bool out_p, Bool clear_windows)
430 int steps = seconds * ticks;
431 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
433 int nscreens = ScreenCount(dpy);
434 struct timeval then, now;
435 #ifdef GETTIMEOFDAY_TWO_ARGS
440 struct screen_sgi_gamma_info *info = (struct screen_sgi_gamma_info *)
441 calloc(nscreens, sizeof(*info));
443 /* Get the current gamma maps for all screens.
444 Bug out and return -1 if we can't get them for some screen.
446 for (screen = 0; screen < nscreens; screen++)
448 if (!XSGIvcQueryGammaMap(dpy, screen, info[screen].gamma_map,
449 &info[screen].gamma_size,
450 &info[screen].gamma_precision,
451 &info[screen].alpha_p))
454 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
455 XSGIVC_COMPONENT_RED,
456 &info[screen].nred, &info[screen].red1))
458 if (! XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
459 XSGIVC_COMPONENT_GREEN,
460 &info[screen].ngreen, &info[screen].green1))
462 if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
463 XSGIVC_COMPONENT_BLUE,
464 &info[screen].nblue, &info[screen].blue1))
467 if (info[screen].gamma_precision == 8) /* Scale it up to 16 bits. */
470 for(j = 0; j < info[screen].nred; j++)
471 info[screen].red1[j] =
472 ((info[screen].red1[j] << 8) | info[screen].red1[j]);
473 for(j = 0; j < info[screen].ngreen; j++)
474 info[screen].green1[j] =
475 ((info[screen].green1[j] << 8) | info[screen].green1[j]);
476 for(j = 0; j < info[screen].nblue; j++)
477 info[screen].blue1[j] =
478 ((info[screen].blue1[j] << 8) | info[screen].blue1[j]);
481 info[screen].red2 = (unsigned short *)
482 malloc(sizeof(*info[screen].red2) * (info[screen].nred+1));
483 info[screen].green2 = (unsigned short *)
484 malloc(sizeof(*info[screen].green2) * (info[screen].ngreen+1));
485 info[screen].blue2 = (unsigned short *)
486 malloc(sizeof(*info[screen].blue2) * (info[screen].nblue+1));
489 #ifdef GETTIMEOFDAY_TWO_ARGS
490 gettimeofday(&then, &tzp);
495 /* If we're fading in (from black), then first crank the gamma all the
496 way down to 0, then take the windows off the screen.
500 for (screen = 0; screen < nscreens; screen++)
501 sgi_whack_gamma(dpy, screen, &info[screen], 0.0);
503 for (screen = 0; screen < nwindows; screen++)
504 if (black_windows && black_windows[screen])
506 XUnmapWindow (dpy, black_windows[screen]);
507 XClearWindow (dpy, black_windows[screen]);
512 /* Iterate by steps of the animation... */
513 for (i = (out_p ? steps : 0);
514 (out_p ? i > 0 : i < steps);
517 for (screen = 0; screen < nscreens; screen++)
519 sgi_whack_gamma(dpy, screen, &info[screen],
520 (((float)i) / ((float)steps)));
522 /* If there is user activity, bug out. (Bug out on keypresses or
523 mouse presses, but not motion, and not release events. Bugging
524 out on motion made the unfade hack be totally useless, I think.)
526 We put the event back so that the calling code can notice it too.
527 It would be better to not remove it at all, but that's harder
528 because Xlib has such a non-design for this kind of crap, and
529 in this application it doesn't matter if the events end up out
530 of order, so in the grand unix tradition we say "fuck it" and
531 do something that mostly works for the time being.
533 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
536 XPutBackEvent (dpy, &dummy_event);
540 #ifdef GETTIMEOFDAY_TWO_ARGS
541 gettimeofday(&now, &tzp);
546 /* If we haven't already used up our alotted time, sleep to avoid
547 changing the colormap too fast. */
548 sleep_from (&now, &then, usecs_per_step);
555 if (out_p && black_windows)
557 for (screen = 0; screen < nwindows; screen++)
560 XClearWindow (dpy, black_windows[screen]);
561 XMapRaised (dpy, black_windows[screen]);
566 /* I can't explain this; without this delay, we get a flicker.
567 I suppose there's some lossage with stale bits being in the
568 hardware frame buffer or something, and this delay gives it
569 time to flush out. This sucks! */
570 usleep(100000); /* 1/10th second */
572 for (screen = 0; screen < nscreens; screen++)
573 sgi_whack_gamma(dpy, screen, &info[screen], 1.0);
579 for (screen = 0; screen < nscreens; screen++)
581 if (info[screen].red1) free (info[screen].red1);
582 if (info[screen].green1) free (info[screen].green1);
583 if (info[screen].blue1) free (info[screen].blue1);
584 if (info[screen].red2) free (info[screen].red2);
585 if (info[screen].green2) free (info[screen].green2);
586 if (info[screen].blue2) free (info[screen].blue2);
594 sgi_whack_gamma(Display *dpy, int screen, struct screen_sgi_gamma_info *info,
599 if (ratio < 0) ratio = 0;
600 if (ratio > 1) ratio = 1;
601 for (k = 0; k < info->gamma_size; k++)
603 info->red2[k] = info->red1[k] * ratio;
604 info->green2[k] = info->green1[k] * ratio;
605 info->blue2[k] = info->blue1[k] * ratio;
608 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nred,
609 XSGIVC_MComponentRed, info->red2);
610 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->ngreen,
611 XSGIVC_MComponentGreen, info->green2);
612 XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nblue,
613 XSGIVC_MComponentBlue, info->blue2);
617 #endif /* HAVE_SGI_VC_EXTENSION */
621 /* XFree86 4.x+ Gamma fading */
623 #ifdef HAVE_XF86VMODE_GAMMA
625 #include <X11/extensions/xf86vmode.h>
628 XF86VidModeGamma vmg;
630 unsigned short *r, *g, *b;
633 static int xf86_check_gamma_extension (Display *dpy);
634 static Bool xf86_whack_gamma (Display *dpy, int screen,
635 xf86_gamma_info *ginfo, float ratio);
638 xf86_gamma_fade (Display *dpy,
639 Window *black_windows, int nwindows,
640 int seconds, int ticks,
641 Bool out_p, Bool clear_windows)
643 int steps = seconds * ticks;
644 long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
646 int nscreens = ScreenCount(dpy);
647 struct timeval then, now;
648 #ifdef GETTIMEOFDAY_TWO_ARGS
653 xf86_gamma_info *info = 0;
655 static int ext_ok = -1;
657 /* Only probe the extension once: the answer isn't going to change. */
659 ext_ok = xf86_check_gamma_extension (dpy);
661 /* If this server doesn't have the gamma extension, bug out. */
665 # ifndef HAVE_XF86VMODE_GAMMA_RAMP
666 if (ext_ok == 2) ext_ok = 1; /* server is newer than client! */
669 info = (xf86_gamma_info *) calloc(nscreens, sizeof(*info));
671 /* Get the current gamma maps for all screens.
672 Bug out and return -1 if we can't get them for some screen.
674 for (screen = 0; screen < nscreens; screen++)
676 if (ext_ok == 1) /* only have gamma parameter, not ramps. */
678 if (!XF86VidModeGetGamma(dpy, screen, &info[screen].vmg))
681 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
682 else if (ext_ok == 2) /* have ramps */
684 if (!XF86VidModeGetGammaRampSize(dpy, screen, &info[screen].size))
686 if (info[screen].size <= 0)
689 info[screen].r = (unsigned short *)
690 calloc(info[screen].size, sizeof(unsigned short));
691 info[screen].g = (unsigned short *)
692 calloc(info[screen].size, sizeof(unsigned short));
693 info[screen].b = (unsigned short *)
694 calloc(info[screen].size, sizeof(unsigned short));
696 if (!(info[screen].r && info[screen].g && info[screen].b))
699 if (!XF86VidModeGetGammaRamp(dpy, screen, info[screen].size,
705 # endif /* HAVE_XF86VMODE_GAMMA_RAMP */
710 #ifdef GETTIMEOFDAY_TWO_ARGS
711 gettimeofday(&then, &tzp);
716 /* If we're fading in (from black), then first crank the gamma all the
717 way down to 0, then take the windows off the screen.
721 for (screen = 0; screen < nscreens; screen++)
722 xf86_whack_gamma(dpy, screen, &info[screen], 0.0);
723 for (screen = 0; screen < nwindows; screen++)
724 if (black_windows && black_windows[screen])
726 XUnmapWindow (dpy, black_windows[screen]);
727 XClearWindow (dpy, black_windows[screen]);
732 /* Iterate by steps of the animation... */
733 for (i = (out_p ? steps : 0);
734 (out_p ? i > 0 : i < steps);
737 for (screen = 0; screen < nscreens; screen++)
739 xf86_whack_gamma(dpy, screen, &info[screen],
740 (((float)i) / ((float)steps)));
742 /* If there is user activity, bug out. (Bug out on keypresses or
743 mouse presses, but not motion, and not release events. Bugging
744 out on motion made the unfade hack be totally useless, I think.)
746 We put the event back so that the calling code can notice it too.
747 It would be better to not remove it at all, but that's harder
748 because Xlib has such a non-design for this kind of crap, and
749 in this application it doesn't matter if the events end up out
750 of order, so in the grand unix tradition we say "fuck it" and
751 do something that mostly works for the time being.
753 if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
756 XPutBackEvent (dpy, &dummy_event);
760 #ifdef GETTIMEOFDAY_TWO_ARGS
761 gettimeofday(&now, &tzp);
766 /* If we haven't already used up our alotted time, sleep to avoid
767 changing the colormap too fast. */
768 sleep_from (&now, &then, usecs_per_step);
775 if (out_p && black_windows)
777 for (screen = 0; screen < nwindows; screen++)
780 XClearWindow (dpy, black_windows[screen]);
781 XMapRaised (dpy, black_windows[screen]);
786 /* I can't explain this; without this delay, we get a flicker.
787 I suppose there's some lossage with stale bits being in the
788 hardware frame buffer or something, and this delay gives it
789 time to flush out. This sucks! */
790 usleep(100000); /* 1/10th second */
792 for (screen = 0; screen < nscreens; screen++)
793 xf86_whack_gamma(dpy, screen, &info[screen], 1.0);
801 for (screen = 0; screen < nscreens; screen++)
803 if (info[screen].r) free(info[screen].r);
804 if (info[screen].g) free(info[screen].g);
805 if (info[screen].b) free(info[screen].b);
814 /* This bullshit is needed because the VidMode extension doesn't work
815 on remote displays -- but if the remote display has the extension
816 at all, XF86VidModeQueryExtension returns true, and then
817 XF86VidModeQueryVersion dies with an X error. Thank you XFree,
821 static Bool error_handler_hit_p = False;
824 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
826 error_handler_hit_p = True;
831 safe_XF86VidModeQueryVersion (Display *dpy, int *majP, int *minP)
834 XErrorHandler old_handler;
836 error_handler_hit_p = False;
837 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
839 result = XF86VidModeQueryVersion (dpy, majP, minP);
842 XSetErrorHandler (old_handler);
845 return (error_handler_hit_p
852 /* VidModeExtension version 2.0 or better is needed to do gamma.
853 2.0 added gamma values; 2.1 added gamma ramps.
855 # define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
856 # define XF86_VIDMODE_GAMMA_MIN_MINOR 0
857 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
858 # define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
862 /* Returns 0 if gamma fading not available; 1 if only gamma value setting
863 is available; 2 if gamma ramps are available.
866 xf86_check_gamma_extension (Display *dpy)
868 int event, error, major, minor;
870 if (!XF86VidModeQueryExtension (dpy, &event, &error))
871 return 0; /* display doesn't have the extension. */
873 if (!safe_XF86VidModeQueryVersion (dpy, &major, &minor))
874 return 0; /* unable to get version number? */
876 if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
877 (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
878 minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
879 return 0; /* extension is too old for gamma. */
881 if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
882 (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
883 minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
884 return 1; /* extension is too old for gamma ramps. */
891 /* XFree doesn't let you set gamma to a value smaller than this.
892 Apparently they didn't anticipate the trick I'm doing here...
894 #define XF86_MIN_GAMMA 0.1
898 xf86_whack_gamma(Display *dpy, int screen, xf86_gamma_info *info,
903 XErrorHandler old_handler;
905 error_handler_hit_p = False;
906 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
908 if (ratio < 0) ratio = 0;
909 if (ratio > 1) ratio = 1;
911 if (info->size == 0) /* we only have a gamma number, not a ramp. */
915 g2.red = info->vmg.red * ratio;
916 g2.green = info->vmg.green * ratio;
917 g2.blue = info->vmg.blue * ratio;
919 # ifdef XF86_MIN_GAMMA
920 if (g2.red < XF86_MIN_GAMMA) g2.red = XF86_MIN_GAMMA;
921 if (g2.green < XF86_MIN_GAMMA) g2.green = XF86_MIN_GAMMA;
922 if (g2.blue < XF86_MIN_GAMMA) g2.blue = XF86_MIN_GAMMA;
925 status = XF86VidModeSetGamma (dpy, screen, &g2);
929 # ifdef HAVE_XF86VMODE_GAMMA_RAMP
931 unsigned short *r, *g, *b;
933 r = (unsigned short *) malloc(info->size * sizeof(unsigned short));
934 g = (unsigned short *) malloc(info->size * sizeof(unsigned short));
935 b = (unsigned short *) malloc(info->size * sizeof(unsigned short));
937 for (i = 0; i < info->size; i++)
939 r[i] = info->r[i] * ratio;
940 g[i] = info->g[i] * ratio;
941 b[i] = info->b[i] * ratio;
944 status = XF86VidModeSetGammaRamp(dpy, screen, info->size, r, g, b);
950 # else /* !HAVE_XF86VMODE_GAMMA_RAMP */
952 # endif /* !HAVE_XF86VMODE_GAMMA_RAMP */
956 XSetErrorHandler (old_handler);
962 #endif /* HAVE_XF86VMODE_GAMMA */