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:
M | README.md | | | 8 | ++++++-- |
M | sct.c | | | 99 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
M | xsct.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>