sct

set color temperature
git clone anongit@rnpnr.xyz:sct.git
Log | Files | Refs | Feed | README | LICENSE

Commit: a38a0df3f85e0c437de3a28cf1627bcae68ef4ff
Parent: fda7df28bb87af79745ef88af3e7699f5537f0db
Author: Fabian Foerg
Date:   Sun,  4 Aug 2019 15:58:23 -0700

Merge pull request #5 from X11-good-tools/master

fix #4: Read current temperature
Diffstat:
MREADME.md | 8++++++--
Msct.c | 99++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mxsct.1 | 6++++--
3 files changed, 85 insertions(+), 28 deletions(-)

diff --git a/README.md b/README.md @@ -30,6 +30,10 @@ Execute sct using the following command: ~~~ The first parameter (`3700` above) denotes the color temperature and can be -between `1000` and `10000`. -If `xsct` is called without parameters, sct sets the color temperature to `6500`. +between `1000` and `10000`. +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. +--- + +https://github.com/faf0/sct/ diff --git a/sct.c b/sct.c @@ -27,14 +27,13 @@ #include <stdlib.h> #include <string.h> -static void -usage() +static void usage() { printf("Usage: xsct [temperature]\n" "Temperatures must be in a range from 1000-10000\n" - "If no arguments are passed xsct resets the display to the default temperature (6500K)\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"); - exit(0); } /* cribbed from redshift, but truncated with 500K steps */ @@ -60,28 +59,72 @@ static const struct { float r; float g; float b; } whitepoints[] = { { 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; + } -static void -sct_for_screen(Display *dpy, int screen, int temp) + 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 -= 1000; - double ratio = temp % 500 / 500.0; -#define AVG(c) whitepoints[temp / 500].c * (1 - ratio) + whitepoints[temp / 500 + 1].c * ratio - double gammar = AVG(r); - double gammag = AVG(g); - double gammab = AVG(b); + 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); - for (int c = 0; c < res->ncrtc; c++) { + 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 = 65535.0 * i / 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; @@ -94,8 +137,7 @@ sct_for_screen(Display *dpy, int screen, int temp) XFree(res); } -int -main(int argc, char **argv) +int main(int argc, char **argv) { Display *dpy = XOpenDisplay(NULL); if (!dpy) { @@ -105,18 +147,27 @@ main(int argc, char **argv) } int screens = XScreenCount(dpy); - int temp = 6500; + int temp = TEMPERATURE_DEFAULT; if (argc > 1) { if (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")) + { usage(); - temp = atoi(argv[1]); - } - if (temp < 1000 || temp > 10000) - temp = 6500; + } 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); + 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); diff --git a/xsct.1 b/xsct.1 @@ -1,4 +1,4 @@ -.TH xsct 1 "June 2016" "1.3" "User Manual" +.TH xsct 1 "Aug 2019" "1.4" "User Manual" .SH NAME xsct \- X11 set screen color temperature .SH SYNOPSIS @@ -20,10 +20,12 @@ sets the screen's color temperature in a range from 1000 to 10000 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 Display usage information and exit .IP none -If no options are passed, xsct sets the color temperature to the default of 6500 +If no arguments are passed, xsct estimates the current display temperature .SH AUTHOR xsct was written by Ted Unangst <tedu@openbsd.org>