+
+/* This bullshit is needed because the VidMode extension doesn't work
+ on remote displays -- but if the remote display has the extension
+ at all, XF86VidModeQueryExtension returns true, and then
+ XF86VidModeQueryVersion dies with an X error. Thank you XFree,
+ may I have another.
+ */
+
+static Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ return 0;
+}
+
+static Bool
+safe_XF86VidModeQueryVersion (Display *dpy, int *majP, int *minP)
+{
+ Bool result;
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ result = XF86VidModeQueryVersion (dpy, majP, minP);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return (error_handler_hit_p
+ ? False
+ : result);
+}
+
+
+
+/* VidModeExtension version 2.0 or better is needed to do gamma.
+ 2.0 added gamma values; 2.1 added gamma ramps.
+ */
+# define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
+# define XF86_VIDMODE_GAMMA_MIN_MINOR 0
+# define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
+# define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
+
+
+
+/* Returns 0 if gamma fading not available; 1 if only gamma value setting
+ is available; 2 if gamma ramps are available.
+ */
+static int
+xf86_check_gamma_extension (Display *dpy)
+{
+ int event, error, major, minor;
+
+ if (!XF86VidModeQueryExtension (dpy, &event, &error))
+ return 0; /* display doesn't have the extension. */
+
+ if (!safe_XF86VidModeQueryVersion (dpy, &major, &minor))
+ return 0; /* unable to get version number? */
+
+ if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
+ return 0; /* extension is too old for gamma. */
+
+ if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
+ return 1; /* extension is too old for gamma ramps. */
+
+ /* Copacetic */
+ return 2;
+}
+
+
+/* XFree doesn't let you set gamma to a value smaller than this.
+ Apparently they didn't anticipate the trick I'm doing here...
+ */
+#define XF86_MIN_GAMMA 0.1
+
+
+static Bool
+xf86_whack_gamma(Display *dpy, int screen, xf86_gamma_info *info,
+ float ratio)
+{
+ Bool status;
+
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ if (ratio < 0) ratio = 0;
+ if (ratio > 1) ratio = 1;
+
+ if (info->size == 0) /* we only have a gamma number, not a ramp. */
+ {
+ XF86VidModeGamma g2;
+
+ g2.red = info->vmg.red * ratio;
+ g2.green = info->vmg.green * ratio;
+ g2.blue = info->vmg.blue * ratio;
+
+# ifdef XF86_MIN_GAMMA
+ if (g2.red < XF86_MIN_GAMMA) g2.red = XF86_MIN_GAMMA;
+ if (g2.green < XF86_MIN_GAMMA) g2.green = XF86_MIN_GAMMA;
+ if (g2.blue < XF86_MIN_GAMMA) g2.blue = XF86_MIN_GAMMA;
+# endif
+
+ status = XF86VidModeSetGamma (dpy, screen, &g2);
+ }
+ else
+ {
+# ifdef HAVE_XF86VMODE_GAMMA_RAMP
+
+ unsigned short *r, *g, *b;
+ int i;
+ r = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+ g = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+ b = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+
+ for (i = 0; i < info->size; i++)
+ {
+ r[i] = info->r[i] * ratio;
+ g[i] = info->g[i] * ratio;
+ b[i] = info->b[i] * ratio;
+ }
+
+ status = XF86VidModeSetGammaRamp(dpy, screen, info->size, r, g, b);
+
+ free (r);
+ free (g);
+ free (b);
+
+# else /* !HAVE_XF86VMODE_GAMMA_RAMP */
+ abort();
+# endif /* !HAVE_XF86VMODE_GAMMA_RAMP */
+ }
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return status;
+}
+
+#endif /* HAVE_XF86VMODE_GAMMA */