Commit: d8fbaa90d50211fac83f2e198c2dacaedd266726
Parent: a38a0df3f85e0c437de3a28cf1627bcae68ef4ff
Author: Fabian Foerg
Date: Tue, 13 Aug 2019 21:43:09 -0700
Merge pull request #10 from X11-good-tools/master
fix #9: 1.5: Approximation of the redshift table (no limits)
Diffstat:
M | CHANGELOG | | | 9 | +++++++++ |
M | LICENSE | | | 37 | ++++++++++++++++++++++++++++--------- |
M | Makefile | | | 6 | +++--- |
M | README.md | | | 11 | ++++++++--- |
D | sct.c | | | 176 | ------------------------------------------------------------------------------- |
M | xsct.1 | | | 35 | ++++++++++++++++++----------------- |
A | xsct.c | | | 232 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 298 insertions(+), 208 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,5 +1,14 @@
PROJECT: https://github.com/faf0/sct
+1.5: zvezdochiot on 08 Aug 2019
+* Option --verbose to display debugging information
+
+1.5: zvezdochiot on 07 Aug 2019
+* Approximation of the `redshift` table from https://github.com/jonls/redshift/blob/04760afe31bff5b26cf18fe51606e7bdeac15504/src/colorramp.c#L30-L273 without limits
+
+1.4: zvezdochiot on 04 Aug 2019
+* Read current temperature
+
1.3: zvezdochiot on 02 Jan 2019
* Rename utilites for X11
* Add -h option to print usage information
diff --git a/LICENSE b/LICENSE
@@ -1,11 +1,30 @@
-This project is public domain, do as you wish
+Public Domain Mark 1.0
+ No Copyright
-The whitepoints data within sct.c has been released into the public domain
-by Ingo Thies:
-"I have calculated the table by following mathematical rules of color
- integration and conversion from the CIE 1931 color space to sRGB.
+ This work has been identified as being free of known restrictions
+ under copyright law, including all related and neighboring rights.
- I doubt that a numerically computed color table is copyrightable at all
- (in contrast to the actual software implementation). However, if it is
- indeed copyrightable, I have no problem with releasing it into the
- public domain."
+ You can copy, modify, distribute and perform the work, even for
+ commercial purposes, all without asking permission. See Other
+ Information below.
+
+ Other Information
+
+ The work may not be free of known copyright restrictions in all
+ jurisdictions.
+
+ Persons may have other rights in or related to the work, such as
+ patent or trademark rights, and others may have rights in how the
+ work is used, such as publicity or privacy rights.
+
+ In some jurisdictions moral rights of the author may persist beyond
+ the term of copyright. These rights may include the right to be
+ identified as the author and the right to object to derogatory
+ treatments.
+
+ Unless expressly stated otherwise, the person who identified the work
+ makes no warranties about the work, and disclaims liability for all
+ uses of the work, to the fullest extent permitted by applicable law.
+
+ When using or citing the work, you should not imply endorsement by
+ the author or the person who identified the work.
diff --git a/Makefile b/Makefile
@@ -1,8 +1,8 @@
PROG = xsct
CC = gcc
-CFLAGS = -Wall -std=c99 -O2 -I /usr/X11R6/include
-LDFLAGS = -L /usr/X11R6/lib -lX11 -lXrandr
-SRCS = sct.c
+CFLAGS = -Wall -Wextra -Werror -pedantic -std=c99 -O2 -I /usr/X11R6/include
+LDFLAGS = -L /usr/X11R6/lib -lX11 -lXrandr -lm -s
+SRCS = xsct.c
PREFIX = /usr
BIN = $(PREFIX)/bin
MAN = $(PREFIX)/share/man/man1
diff --git a/README.md b/README.md
@@ -20,7 +20,7 @@ Minor modifications were made in order to get sct to:
Compile the code using the following command:
~~~
-cc -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr
+gcc -Wall -Wextra -Werror -pedantic -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr -lm -s
~~~
Execute sct using the following command:
@@ -29,11 +29,16 @@ Execute sct using the following command:
./xsct 3700
~~~
-The first parameter (`3700` above) denotes the color temperature and can be
-between `1000` and `10000`.
+The first parameter (`3700` above) denotes the color temperature.
If `xsct` is called with parameter 0, the color temperature is set to `6500`.
If `xsct` is called without parameters, the current display temperature is estimated.
+Test sct using the following command:
+
+~~~
+./xsct 3700 && ./xsct
+~~~
+
---
https://github.com/faf0/sct/
diff --git a/sct.c b/sct.c
@@ -1,176 +0,0 @@
-/*
- * xsct - X11 set color temperature
- *
- * Compile the code using the following command:
- * cc -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr
- *
- * Original code published by Ted Unangst:
- * http://www.tedunangst.com/flak/post/sct-set-color-temperature
- *
- * Modified by Fabian Foerg in order to:
- * - compile on Ubuntu 14.04
- * - iterate over all screens of the default display and change the color
- * temperature
- * - fix memleaks
- * - clean up code
- * - return EXIT_SUCCESS
- *
- * Public domain, do as you wish.
- */
-
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xproto.h>
-#include <X11/extensions/Xrandr.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static void usage()
-{
- printf("Usage: xsct [temperature]\n"
- "Temperatures must be in a range from 1000-10000\n"
- "If the argument is 0, xsct resets the display to the default temperature (6500K)\n"
- "If no arguments are passed, xsct estimates the current display temperature\n"
- "If -h or --help is passed xsct will display this usage information\n");
-}
-
-/* cribbed from redshift, but truncated with 500K steps */
-static const struct { float r; float g; float b; } whitepoints[] = {
- { 1.00000000, 0.18172716, 0.00000000, }, /* 1000K */
- { 1.00000000, 0.42322816, 0.00000000, },
- { 1.00000000, 0.54360078, 0.08679949, },
- { 1.00000000, 0.64373109, 0.28819679, },
- { 1.00000000, 0.71976951, 0.42860152, },
- { 1.00000000, 0.77987699, 0.54642268, },
- { 1.00000000, 0.82854786, 0.64816570, },
- { 1.00000000, 0.86860704, 0.73688797, },
- { 1.00000000, 0.90198230, 0.81465502, },
- { 1.00000000, 0.93853986, 0.88130458, },
- { 1.00000000, 0.97107439, 0.94305985, },
- { 1.00000000, 1.00000000, 1.00000000, }, /* 6500K */
- { 0.95160805, 0.96983355, 1.00000000, },
- { 0.91194747, 0.94470005, 1.00000000, },
- { 0.87906581, 0.92357340, 1.00000000, },
- { 0.85139976, 0.90559011, 1.00000000, },
- { 0.82782969, 0.89011714, 1.00000000, },
- { 0.80753191, 0.87667891, 1.00000000, },
- { 0.78988728, 0.86491137, 1.00000000, }, /* 10000K */
- { 0.77442176, 0.85453121, 1.00000000, },
-};
-#define TEMPERATURE_DEFAULT 6500
-#define TEMPERATURE_MIN 1000
-#define TEMPERATURE_MAX 10000
-#define TEMPERATURE_STEP 500
-#define GAMMA_MULT 65535.0
-#define AVG(c,temp,ratio) whitepoints[(temp) / TEMPERATURE_STEP].c * (1 - (ratio)) + whitepoints[(temp) / TEMPERATURE_STEP + 1].c * (ratio)
-
-static int get_sct_for_screen(Display *dpy, int screen)
-{
- Window root = RootWindow(dpy, screen);
- XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
-
- int temp = 0;
- double t, ts;
- double gammar, gammag, gammab;
-
- int n = res->ncrtc;
- ts = 0.0;
- for (int c = 0; c < n; c++)
- {
- int crtcxid = res->crtcs[c];
- XRRCrtcGamma *crtc_gamma = XRRGetCrtcGamma(dpy, crtcxid);
- int size = crtc_gamma->size;
-
- if (size > 0)
- {
- double g_inv = (size + 1) / size / GAMMA_MULT;
- gammar = crtc_gamma->red[size - 1] * g_inv;
- gammag = crtc_gamma->green[size - 1] * g_inv;
- gammab = crtc_gamma->blue[size - 1] * g_inv;
- t = (64465 - 109049 * gammar + 46013 * gammar * gammar -
- 4322 * gammag + 10708 * gammag * gammag -
- 2662 * gammab + 1355 * gammab * gammab);
- ts += t;
- }
-
- XFree(crtc_gamma);
- }
- temp = (int)(ts / (double)n);
-
- XFree(res);
- return temp;
-}
-
-static void sct_for_screen(Display *dpy, int screen, int temp)
-{
- Window root = RootWindow(dpy, screen);
- XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
-
- temp -= TEMPERATURE_MIN;
- double ratio = temp % TEMPERATURE_STEP / TEMPERATURE_STEP;
- double gammar = AVG(r, temp, ratio);
- double gammag = AVG(g, temp, ratio);
- double gammab = AVG(b, temp, ratio);
-
- int n = res->ncrtc;
- for (int c = 0; c < n; c++)
- {
- int crtcxid = res->crtcs[c];
- int size = XRRGetCrtcGammaSize(dpy, crtcxid);
-
- XRRCrtcGamma *crtc_gamma = XRRAllocGamma(size);
-
- for (int i = 0; i < size; i++)
- {
- double g = GAMMA_MULT * i / size;
- crtc_gamma->red[i] = g * gammar;
- crtc_gamma->green[i] = g * gammag;
- crtc_gamma->blue[i] = g * gammab;
- }
-
- XRRSetCrtcGamma(dpy, crtcxid, crtc_gamma);
- XFree(crtc_gamma);
- }
-
- XFree(res);
-}
-
-int main(int argc, char **argv)
-{
- Display *dpy = XOpenDisplay(NULL);
- if (!dpy) {
- perror("XOpenDisplay(NULL) failed");
- fprintf(stderr, "Make sure DISPLAY is set correctly.\n");
- return EXIT_FAILURE;
- }
- int screens = XScreenCount(dpy);
-
- int temp = TEMPERATURE_DEFAULT;
- if (argc > 1)
- {
- if (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))
- {
- usage();
- } else {
- temp = atoi(argv[1]);
- if (temp < TEMPERATURE_MIN || temp > TEMPERATURE_MAX)
- temp = TEMPERATURE_DEFAULT;
-
- for (int screen = 0; screen < screens; screen++)
- sct_for_screen(dpy, screen, temp);
- }
- } else {
- for (int screen = 0; screen < screens; screen++)
- {
- temp = get_sct_for_screen(dpy, screen);
- printf("Screen %d: temperature ~ %d\n", screen, temp);
- }
- }
-
- XCloseDisplay(dpy);
-
- return EXIT_SUCCESS;
-}
-
diff --git a/xsct.1 b/xsct.1
@@ -1,31 +1,32 @@
-.TH xsct 1 "Aug 2019" "1.4" "User Manual"
+.TH xsct 1 "Aug 2019" "1.5" "User Manual"
.SH NAME
xsct \- X11 set screen color temperature
.SH SYNOPSIS
.B xsct
-[temperature]
-
-or
-
-.B xsct
-[-h || --help]
-
+[options]
+.I [temperature]
.SH DESCRIPTION
.B xsct
-sets the screen's color temperature in a range from 1000 to 10000
+sets the screen's color temperature.
.SH OPTIONS
-.IP temperature
-If passed a value in the correct range (see above)
-.B xsct
-will set the current screen temperature to this value
-.IP 0
-If the value is 0, xsct sets the color temperature to the default of 6500
-.IP -h,--help
+.TP
+.B -h, --help
Display usage information and exit
-.IP none
+.TP
+.B -v, --verbose
+Display debugging information
+.TP
+.I [temperature]
+Black body temperature
+.br
+If the value is 0, xsct sets the color temperature to the default of 6500
+.br
If no arguments are passed, xsct estimates the current display temperature
.SH AUTHOR
xsct was written by Ted Unangst <tedu@openbsd.org>
+
+.SH SEE ALSO
+redshift(1), xtemp(1)
diff --git a/xsct.c b/xsct.c
@@ -0,0 +1,232 @@
+/*
+ * xsct - X11 set color temperature
+ *
+ * Original code published by Ted Unangst:
+ * http://www.tedunangst.com/flak/post/sct-set-color-temperature
+ *
+ * Modified by Fabian Foerg in order to:
+ * - compile on Ubuntu 14.04
+ * - iterate over all screens of the default display and change the color
+ * temperature
+ * - fix memleaks
+ * - clean up code
+ * - return EXIT_SUCCESS
+ *
+ * Public domain, do as you wish.
+ *
+ * Compile the code using the following command:
+ * gcc -Wall -Wextra -Werror -pedantic -std=c99 -O2 -I /usr/X11R6/include xsct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr -lm -s
+ *
+ */
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/Xrandr.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+static void usage(char * pname)
+{
+ printf("Xsct (1.5)\n"
+ "Usage: %s [options] [temperature]\n"
+ "\tIf the argument is 0, xsct resets the display to the default temperature (6500K)\n"
+ "\tIf no arguments are passed, xsct estimates the current display temperature\n"
+ "Options:\n"
+ "\t-v, --verbose \t xsct will display debugging information\n"
+ "\t-h, --help \t xsct will display this usage information\n", pname);
+}
+
+#define TEMPERATURE_NORM 6500
+#define TEMPERATURE_ZERO 700
+#define GAMMA_MULT 65535.0
+// Approximation of the `redshift` table from
+// https://github.com/jonls/redshift/blob/04760afe31bff5b26cf18fe51606e7bdeac15504/src/colorramp.c#L30-L273
+// without limits:
+// GAMMA = K0 + K1 * ln(T - T0)
+// Red range (T0 = TEMPERATURE_ZERO)
+// Green color
+#define GAMMA_K0GR -1.47751309139817
+#define GAMMA_K1GR 0.28590164772055
+// Blue color
+#define GAMMA_K0BR -4.38321650114872
+#define GAMMA_K1BR 0.6212158769447
+// Blue range (T0 = TEMPERATURE_NORM - TEMPERATURE_ZERO)
+// Red color
+#define GAMMA_K0RB 1.75390204039018
+#define GAMMA_K1RB -0.1150805671482
+// Green color
+#define GAMMA_K0GB 1.49221604915144
+#define GAMMA_K1GB -0.07513509588921
+
+static double DoubleTrim(double x, double a, double b)
+{
+ double buff[3] = {a, x, b};
+ return buff[ (int)(x > a) + (int)(x > b) ];
+}
+
+static int get_sct_for_screen(Display *dpy, int screen, int fdebug)
+{
+ Window root = RootWindow(dpy, screen);
+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
+
+ int temp = 0, n, c;
+ double t = 0.0;
+ double gammar = 0.0, gammag = 0.0, gammab = 0.0, gammam = 1.0, gammad = 0.0;
+
+ n = res->ncrtc;
+ for (c = 0; c < n; c++)
+ {
+ RRCrtc crtcxid;
+ int size;
+ XRRCrtcGamma *crtc_gamma;
+ crtcxid = res->crtcs[c];
+ crtc_gamma = XRRGetCrtcGamma(dpy, crtcxid);
+ size = crtc_gamma->size;
+ gammar += crtc_gamma->red[size - 1];
+ gammag += crtc_gamma->green[size - 1];
+ gammab += crtc_gamma->blue[size - 1];
+
+ XRRFreeGamma(crtc_gamma);
+ }
+ XFree(res);
+ gammam = (gammar > gammag) ? gammar : gammag;
+ gammam = (gammab > gammam) ? gammab : gammam;
+ if (gammam > 0.0)
+ {
+ gammar /= gammam;
+ gammag /= gammam;
+ gammab /= gammam;
+ if (fdebug > 0) fprintf(stderr, "DEBUG: Gamma: %f, %f, %f\n", gammar, gammag, gammab);
+ gammad = gammab - gammar;
+ if (gammad < 0.0)
+ {
+ if (gammab > 0.0)
+ {
+ t = exp((gammag + 1.0 + gammad - (GAMMA_K0GR + GAMMA_K0BR)) / (GAMMA_K1GR + GAMMA_K1BR)) + TEMPERATURE_ZERO;
+ }
+ else
+ {
+ t = (gammag > 0.0) ? (exp((gammag - GAMMA_K0GR) / GAMMA_K1GR) + TEMPERATURE_ZERO) : TEMPERATURE_ZERO;
+ }
+ }
+ else
+ {
+ t = exp((gammag + 1.0 - gammad - (GAMMA_K0GB + GAMMA_K0RB)) / (GAMMA_K1GB + GAMMA_K1RB)) + (TEMPERATURE_NORM - TEMPERATURE_ZERO);
+ }
+ }
+
+ temp = (int)(t + 0.5);
+
+ return temp;
+}
+
+static void sct_for_screen(Display *dpy, int screen, int temp, int fdebug)
+{
+ double t = 0.0, g = 0.0, gammar, gammag, gammab;
+ int n, c;
+ Window root = RootWindow(dpy, screen);
+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
+
+ t = (double)temp;
+ if (temp < TEMPERATURE_NORM)
+ {
+ gammar = 1.0;
+ if (temp < TEMPERATURE_ZERO)
+ {
+ gammag = 0.0;
+ gammab = 0.0;
+ }
+ else
+ {
+ g = log(t - TEMPERATURE_ZERO);
+ gammag = DoubleTrim(GAMMA_K0GR + GAMMA_K1GR * g, 0.0, 1.0);
+ gammab = DoubleTrim(GAMMA_K0BR + GAMMA_K1BR * g, 0.0, 1.0);
+ }
+ }
+ else
+ {
+ g = log(t - (TEMPERATURE_NORM - TEMPERATURE_ZERO));
+ gammar = DoubleTrim(GAMMA_K0RB + GAMMA_K1RB * g, 0.0, 1.0);
+ gammag = DoubleTrim(GAMMA_K0GB + GAMMA_K1GB * g, 0.0, 1.0);
+ gammab = 1.0;
+ }
+ if (fdebug > 0) fprintf(stderr, "DEBUG: Gamma: %f, %f, %f\n", gammar, gammag, gammab);
+
+ n = res->ncrtc;
+ for (c = 0; c < n; c++)
+ {
+ int size, i;
+ RRCrtc crtcxid;
+ XRRCrtcGamma *crtc_gamma;
+ crtcxid = res->crtcs[c];
+ size = XRRGetCrtcGammaSize(dpy, crtcxid);
+
+ crtc_gamma = XRRAllocGamma(size);
+
+ for (i = 0; i < size; i++)
+ {
+ g = GAMMA_MULT * (double)i / (double)size;
+ crtc_gamma->red[i] = (unsigned short int)(g * gammar + 0.5);
+ crtc_gamma->green[i] = (unsigned short int)(g * gammag + 0.5);
+ crtc_gamma->blue[i] = (unsigned short int)(g * gammab + 0.5);
+ }
+
+ XRRSetCrtcGamma(dpy, crtcxid, crtc_gamma);
+ XRRFreeGamma(crtc_gamma);
+ }
+
+ XFree(res);
+}
+
+int main(int argc, char **argv)
+{
+ int i, screen, screens, temp;
+ int fdebug = 0, fhelp = 0;
+ Display *dpy = XOpenDisplay(NULL);
+ if (!dpy)
+ {
+ perror("XOpenDisplay(NULL) failed");
+ fprintf(stderr, "Make sure DISPLAY is set correctly.\n");
+ return EXIT_FAILURE;
+ }
+ screens = XScreenCount(dpy);
+
+ temp = -1;
+ for (i = 1; i < argc; i++)
+ {
+ if ((strcmp(argv[i],"-v") == 0) || (strcmp(argv[i],"--verbose") == 0)) fdebug = 1;
+ else if ((strcmp(argv[i],"-h") == 0) || (strcmp(argv[i],"--help") == 0)) fhelp = 1;
+ else temp = atoi(argv[i]);
+ }
+ if (fhelp > 0)
+ {
+ usage(argv[0]);
+ }
+ else
+ {
+ if (temp < 0)
+ {
+ for (screen = 0; screen < screens; screen++)
+ {
+ temp = get_sct_for_screen(dpy, screen, fdebug);
+ printf("Screen %d: temperature ~ %d\n", screen, temp);
+ }
+ }
+ else
+ {
+ temp = (temp == 0) ? TEMPERATURE_NORM : temp;
+
+ for (screen = 0; screen < screens; screen++)
+ sct_for_screen(dpy, screen, temp, fdebug);
+ }
+ }
+
+ XCloseDisplay(dpy);
+
+ return EXIT_SUCCESS;
+}
+