172b4363aSmrg/*
272b4363aSmrg * Copyright 1999  The XFree86 Project
372b4363aSmrg *
472b4363aSmrg * Permission is hereby granted, free of charge, to any person obtaining a
572b4363aSmrg * copy of this software and associated documentation files (the "Software"),
672b4363aSmrg * to deal in the Software without restriction, including without limitation
772b4363aSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
872b4363aSmrg * and/or sell copies of the Software, and to permit persons to whom the
972b4363aSmrg * Software is furnished to do so, subject to the following conditions:
1072b4363aSmrg *
1172b4363aSmrg * The above copyright notice and this permission notice shall be included in
1272b4363aSmrg * all copies or substantial portions of the Software.
1372b4363aSmrg *
1472b4363aSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1572b4363aSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1672b4363aSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1772b4363aSmrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1872b4363aSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
1972b4363aSmrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2072b4363aSmrg * SOFTWARE.
2172b4363aSmrg *
2272b4363aSmrg * Written by David Bateman
2372b4363aSmrg */
2472b4363aSmrg
2533dddc75Smrg#ifdef HAVE_CONFIG_H
2633dddc75Smrg# include "config.h"
2733dddc75Smrg#endif
2833dddc75Smrg
2972b4363aSmrg#include <stdio.h>
3072b4363aSmrg#include <errno.h>
3172b4363aSmrg#include <X11/Xos.h>
3272b4363aSmrg#include <X11/Xlib.h>
3372b4363aSmrg#include <X11/Xutil.h>
3472b4363aSmrg#include <X11/extensions/xf86vmode.h>
3572b4363aSmrg#include <ctype.h>
3672b4363aSmrg#include <stdlib.h>
3772b4363aSmrg
387ed541caSmrg#ifndef HAVE_STRTOF
397ed541caSmrg#define strtof(a, n)  (float)atof(a)
407ed541caSmrg#endif
417ed541caSmrg
42dd77ae96Smrgstatic char *ProgramName;
43dd77ae96Smrgstatic int MajorVersion, MinorVersion;
44dd77ae96Smrgstatic int EventBase, ErrorBase;
4572b4363aSmrg
4672b4363aSmrg/* Minimum extension version required */
4772b4363aSmrg#define MINMAJOR 2
4872b4363aSmrg#define MINMINOR 0
4972b4363aSmrg
5072b4363aSmrg/* Maximum and Minimum gamma values */
517ed541caSmrg#define GAMMA_MIN 0.1f
527ed541caSmrg#define GAMMA_MAX 10.0f
5372b4363aSmrg
5433dddc75Smrgstatic void _X_NORETURN
5533dddc75SmrgSyntax(const char *errmsg)
5672b4363aSmrg{
5733dddc75Smrg    if (errmsg != NULL)
5833dddc75Smrg        fprintf (stderr, "%s: %s\n\n", ProgramName, errmsg);
5933dddc75Smrg
6033dddc75Smrg    fprintf (stderr, "usage:  %s [-options]\n\n%s", ProgramName,
6133dddc75Smrg             "where the available options are:\n"
6233dddc75Smrg             "    -display host:dpy       or -d\n"
6333dddc75Smrg             "    -quiet                  or -q\n"
6433dddc75Smrg             "    -screen                 or -s\n"
6533dddc75Smrg             "    -version                or -v\n"
6633dddc75Smrg             "    -gamma f.f              Gamma Value\n"
6733dddc75Smrg             "    -rgamma f.f             Red Gamma Value\n"
6833dddc75Smrg             "    -ggamma f.f             Green Gamma Value\n"
6933dddc75Smrg             "    -bgamma f.f             Blue Gamma Value\n\n"
7033dddc75Smrg             "If no gamma is specified, returns the current setting\n");
7172b4363aSmrg    exit (1);
7272b4363aSmrg}
7372b4363aSmrg
7472b4363aSmrg
7572b4363aSmrg/*
7672b4363aSmrg * The following is a hack until XrmParseCommand is ready.  It determines
7772b4363aSmrg * whether or not the given string is an abbreviation of the arg.
7872b4363aSmrg */
7972b4363aSmrg
8072b4363aSmrgstatic Bool
8133dddc75Smrgisabbreviation(const char *arg, const char *s, size_t minslen)
8272b4363aSmrg{
8333dddc75Smrg    size_t arglen;
8433dddc75Smrg    size_t slen;
8572b4363aSmrg
8672b4363aSmrg    /* exact match */
8772b4363aSmrg    if (strcmp (arg, s) == 0) return (True);
8872b4363aSmrg
8972b4363aSmrg    arglen = strlen (arg);
9072b4363aSmrg    slen = strlen (s);
9172b4363aSmrg
9272b4363aSmrg    /* too long or too short */
9372b4363aSmrg    if (slen >= arglen || slen < minslen) return (False);
9472b4363aSmrg
9572b4363aSmrg    /* abbreviation */
9672b4363aSmrg    if (strncmp (arg, s, slen) == 0) return (True);
9772b4363aSmrg
9872b4363aSmrg    /* bad */
9972b4363aSmrg    return (False);
10072b4363aSmrg}
10172b4363aSmrg
10272b4363aSmrgint
10372b4363aSmrgmain(int argc, char *argv[])
10472b4363aSmrg{
1057ed541caSmrg    int ret = 2;
10672b4363aSmrg    char *displayname = NULL;
10772b4363aSmrg    Display *dpy;
1087ed541caSmrg    float gam = -1.0f, rgam = -1.0f, ggam = -1.0f, bgam = -1.0f;
10972b4363aSmrg    XF86VidModeGamma gamma;
11072b4363aSmrg    Bool quiet = False;
11172b4363aSmrg    int screen = -1;
11272b4363aSmrg
11372b4363aSmrg    ProgramName = argv[0];
1147ed541caSmrg    for (int i = 1; i < argc; i++) {
11572b4363aSmrg	char *arg = argv[i];
11672b4363aSmrg
11772b4363aSmrg	if (arg[0] == '-') {
11872b4363aSmrg	    if (isabbreviation ("-display", arg, 1)) {
11933dddc75Smrg		if (++i >= argc) Syntax ("-display requires an argument");
12072b4363aSmrg		displayname = argv[i];
12172b4363aSmrg		continue;
12272b4363aSmrg	    } else if (isabbreviation ("-quiet", arg, 1)) {
12372b4363aSmrg		quiet = True;
12472b4363aSmrg		continue;
12533dddc75Smrg	    } else if (isabbreviation ("-version", arg, 1)) {
12633dddc75Smrg		puts(PACKAGE_STRING);
12733dddc75Smrg		exit(0);
12872b4363aSmrg	    } else if (isabbreviation ("-screen", arg, 1)) {
12933dddc75Smrg		if (++i >= argc) Syntax ("-screen requires an argument");
13072b4363aSmrg		screen = atoi(argv[i]);
13172b4363aSmrg		continue;
13272b4363aSmrg	    } else if (isabbreviation ("-gamma", arg, 2)) {
13333dddc75Smrg		if (++i >= argc) Syntax ("-gamma requires an argument");
1347ed541caSmrg		if ((rgam >= 0.0f) || (ggam >= 0.0f) || (bgam >= 0.0f))
13533dddc75Smrg		    Syntax ("-gamma cannot be used with -rgamma, -ggamma, or -bgamma");
1367ed541caSmrg		gam = strtof(argv[i], NULL);
13772b4363aSmrg		if ((gam < GAMMA_MIN) || (gam > GAMMA_MAX)) {
13872b4363aSmrg		    fprintf(stderr,
13972b4363aSmrg			    "Gamma values must be between %6.3f and %6.3f\n",
1407ed541caSmrg			    (double)GAMMA_MIN, (double)GAMMA_MAX);
14172b4363aSmrg		    exit(1);
14272b4363aSmrg		}
14372b4363aSmrg		continue;
14472b4363aSmrg	    } else if (isabbreviation ("-rgamma", arg, 2)) {
14533dddc75Smrg		if (++i >= argc) Syntax ("-rgamma requires an argument");
1467ed541caSmrg		if (gam >= 0.0f) Syntax ("cannot set both -gamma and -rgamma");
1477ed541caSmrg		rgam = strtof(argv[i], NULL);
14872b4363aSmrg		if ((rgam < GAMMA_MIN) || (rgam > GAMMA_MAX)) {
14972b4363aSmrg		    fprintf(stderr,
15072b4363aSmrg			    "Gamma values must be between %6.3f and %6.3f\n",
1517ed541caSmrg			    (double)GAMMA_MIN, (double)GAMMA_MAX);
15272b4363aSmrg		    exit(1);
15372b4363aSmrg		}
15472b4363aSmrg		continue;
15572b4363aSmrg	    } else if (isabbreviation ("-ggamma", arg, 2)) {
15633dddc75Smrg		if (++i >= argc) Syntax ("-ggamma requires an argument");
1577ed541caSmrg		if (gam >= 0.0f) Syntax ("cannot set both -gamma and -ggamma");
1587ed541caSmrg		ggam = strtof(argv[i], NULL);
15972b4363aSmrg		if ((ggam < GAMMA_MIN) || (ggam > GAMMA_MAX)) {
16072b4363aSmrg		    fprintf(stderr,
16172b4363aSmrg			    "Gamma values must be between %6.3f and %6.3f\n",
1627ed541caSmrg			    (double)GAMMA_MIN, (double)GAMMA_MAX);
16372b4363aSmrg		    exit(1);
16472b4363aSmrg		}
16572b4363aSmrg		continue;
16672b4363aSmrg	    } else if (isabbreviation ("-bgamma", arg, 2)) {
16733dddc75Smrg		if (++i >= argc) Syntax ("-bgamma requires an argument");
1687ed541caSmrg		if (gam >= 0.0f) Syntax ("cannot set both -gamma and -bgamma");
1697ed541caSmrg		bgam = strtof(argv[i], NULL);
17072b4363aSmrg		if ((bgam < GAMMA_MIN) || (bgam > GAMMA_MAX)) {
17172b4363aSmrg		    fprintf(stderr,
17272b4363aSmrg			    "Gamma values must be between %6.3f and %6.3f\n",
1737ed541caSmrg			    (double)GAMMA_MIN, (double)GAMMA_MAX);
17472b4363aSmrg		    exit(1);
17572b4363aSmrg		}
17672b4363aSmrg		continue;
17733dddc75Smrg	    } else {
17833dddc75Smrg		if (!isabbreviation ("-help", arg, 1))
17933dddc75Smrg		    fprintf (stderr, "%s: unrecognized argument %s\n\n",
18033dddc75Smrg			     ProgramName, arg);
18133dddc75Smrg		Syntax (NULL);
18233dddc75Smrg	    }
18333dddc75Smrg	} else {
18433dddc75Smrg	    fprintf (stderr, "%s: unrecognized argument %s\n\n",
18533dddc75Smrg		     ProgramName, arg);
18633dddc75Smrg	    Syntax (NULL);
18733dddc75Smrg	}
18872b4363aSmrg    }
18972b4363aSmrg
19072b4363aSmrg    if ((dpy = XOpenDisplay(displayname)) == NULL) {
19172b4363aSmrg	fprintf (stderr, "%s:  unable to open display '%s'\n",
19272b4363aSmrg		 ProgramName, XDisplayName (displayname));
19372b4363aSmrg	exit(1);
19472b4363aSmrg    } else if (screen == -1)
19572b4363aSmrg	screen = DefaultScreen(dpy);
19672b4363aSmrg
19772b4363aSmrg    if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
19872b4363aSmrg	fprintf(stderr, "Unable to query video extension version\n");
1997ed541caSmrg	goto finish;
20072b4363aSmrg    }
20172b4363aSmrg
20272b4363aSmrg    if (!XF86VidModeQueryExtension(dpy, &EventBase, &ErrorBase)) {
20372b4363aSmrg	fprintf(stderr, "Unable to query video extension information\n");
2047ed541caSmrg	goto finish;
20572b4363aSmrg    }
20672b4363aSmrg
20772b4363aSmrg    /* Fail if the extension version in the server is too old */
20872b4363aSmrg    if (MajorVersion < MINMAJOR ||
20972b4363aSmrg	(MajorVersion == MINMAJOR && MinorVersion < MINMINOR)) {
21072b4363aSmrg	fprintf(stderr,
21172b4363aSmrg		"Xserver is running an old XFree86-VidModeExtension version"
21272b4363aSmrg		" (%d.%d)\n", MajorVersion, MinorVersion);
21372b4363aSmrg	fprintf(stderr, "Minimum required version is %d.%d\n",
21472b4363aSmrg		MINMAJOR, MINMINOR);
2157ed541caSmrg	goto finish;
21672b4363aSmrg    }
21772b4363aSmrg
21872b4363aSmrg    if (!XF86VidModeGetGamma(dpy, screen, &gamma)) {
21972b4363aSmrg	fprintf(stderr, "Unable to query gamma correction\n");
2207ed541caSmrg	goto finish;
22172b4363aSmrg    } else if (!quiet)
2227ed541caSmrg	fprintf(stderr, "-> Red %6.3f, Green %6.3f, Blue %6.3f\n",
2237ed541caSmrg		(double)gamma.red, (double)gamma.green, (double)gamma.blue);
22472b4363aSmrg
2257ed541caSmrg    if (gam >= 0.0f) {
22672b4363aSmrg	gamma.red = gam;
22772b4363aSmrg	gamma.green = gam;
22872b4363aSmrg	gamma.blue = gam;
2297ed541caSmrg    } else if ((rgam >= 0.0f) || (ggam >= 0.0f) || (bgam >= 0.0f)) {
2307ed541caSmrg	if (rgam >= 0.0f) gamma.red = rgam;
2317ed541caSmrg	if (ggam >= 0.0f) gamma.green = ggam;
2327ed541caSmrg	if (bgam >= 0.0f) gamma.blue = bgam;
2337ed541caSmrg    } else {
2347ed541caSmrg	/* Not changing gamma, all done */
2357ed541caSmrg	ret = 0;
2367ed541caSmrg	goto finish;
2377ed541caSmrg    }
2387ed541caSmrg
2397ed541caSmrg    /* Change gamma now */
2407ed541caSmrg    if (!XF86VidModeSetGamma(dpy, screen, &gamma)) {
2417ed541caSmrg	fprintf(stderr, "Unable to set gamma correction\n");
2427ed541caSmrg    } else {
2437ed541caSmrg	if (!XF86VidModeGetGamma(dpy, screen, &gamma)) {
2447ed541caSmrg	    fprintf(stderr, "Unable to query gamma correction\n");
24572b4363aSmrg	} else {
2467ed541caSmrg	    ret = 0; /* Success! */
2477ed541caSmrg	    if (!quiet) {
24872b4363aSmrg		fprintf(stderr, "<- Red %6.3f, Green %6.3f, Blue %6.3f\n",
2497ed541caSmrg			(double)gamma.red, (double)gamma.green,
2507ed541caSmrg			(double)gamma.blue);
2517ed541caSmrg	    }
25272b4363aSmrg	}
25372b4363aSmrg    }
25472b4363aSmrg
2557ed541caSmrg  finish:
25672b4363aSmrg    XCloseDisplay (dpy);
25772b4363aSmrg    exit (ret);
25872b4363aSmrg}
25972b4363aSmrg
260