ctemp

Set color temperature
git clone git://git.akobets.xyz/ctemp
Log | Files | Refs | README | LICENSE

ctemp.c (6735B)


      1 /* See LICENSE for license details. */
      2 
      3 #if !defined(DRM_SUPPORT) && !defined(QUARTZ_SUPPORT) && !defined(X_SUPPORT)
      4 	#error "No supported interface configured"
      5 #endif
      6 
      7 #include <fcntl.h>
      8 #include <errno.h>
      9 #include <stdarg.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <unistd.h>
     14 
     15 #include "arg.h"
     16 
     17 #define LEN(x)                  (sizeof(x) / sizeof(x[0]))
     18 
     19 #define TEMP_MIN      1000
     20 #define TEMP_MAX      25000
     21 #define TEMP_INTERVAL 100
     22 
     23 typedef struct {
     24 	char *name;
     25 	void (*handler)(int temp);
     26 } Interface;
     27 
     28 #ifdef DRM_SUPPORT
     29 static void drm_handler(int temp);
     30 #endif
     31 #ifdef QUARTZ_SUPPORT
     32 static void quartz_handler(int temp);
     33 #endif
     34 #ifdef X_SUPPORT
     35 static void x_handler(int temp);
     36 #endif
     37 static void die(const char *fmt, ...);
     38 static void usage();
     39 
     40 Interface interfaces[] = {
     41 #ifdef DRM_SUPPORT
     42 	{ "drm", drm_handler },
     43 #endif
     44 #ifdef QUARTZ_SUPPORT
     45 	{ "quartz", quartz_handler },
     46 #endif
     47 #ifdef X_SUPPORT
     48 	{ "x", x_handler },
     49 #endif
     50 };
     51 
     52 extern const struct {
     53 	float r;
     54 	float g;
     55 	float b;
     56 } whitepoints[];
     57 char *argv0;
     58 
     59 #ifdef DRM_SUPPORT
     60 #include <xf86drm.h>
     61 #include <xf86drmMode.h>
     62 
     63 static void
     64 drm_handler(int temp)
     65 {
     66 	unsigned int i;
     67 	float ratio_red, ratio_green, ratio_blue;
     68 	char dev_name[64];
     69 	int fd;
     70 	drmModeResPtr res;
     71 	uint16_t *colors, *red, *green, *blue;
     72 	int gamma_size, prev_gamma_size;
     73 	int n;
     74 
     75 	i = (temp - TEMP_MIN) / TEMP_INTERVAL;
     76 	ratio_red = whitepoints[i].r;
     77 	ratio_green = whitepoints[i].g;
     78 	ratio_blue = whitepoints[i].b;
     79 
     80 	/* open DRM device with minor number 0 */
     81 	snprintf(dev_name, sizeof(dev_name), DRM_DEV_NAME, DRM_DIR_NAME, 0);
     82 	fd = open(dev_name, O_RDWR, 0);
     83 	if (fd < 0)
     84 		die("cannot open %s: %s\n", dev_name, strerror(errno));
     85 
     86 	res = drmModeGetResources(fd);
     87 
     88 	colors = NULL;
     89 	prev_gamma_size = 0;
     90 	for (n = 0; n < res->count_crtcs; n++) {
     91 		uint32_t crtc_id;
     92 		drmModeCrtcPtr crtc;
     93 		int i;
     94 
     95 		crtc_id = res->crtcs[n];
     96 		crtc = drmModeGetCrtc(fd, crtc_id);
     97 		gamma_size = crtc->gamma_size;
     98 
     99 		if (colors == NULL) {
    100 			colors = malloc(3 * gamma_size * sizeof(uint16_t));
    101 			if (colors == NULL)
    102 				die("malloc: %s\n", strerror(errno));
    103 		} else if (gamma_size > prev_gamma_size) {
    104 			colors = realloc(colors, 3 * gamma_size * sizeof(uint16_t));
    105 			if (colors == NULL)
    106 				die("realloc: %s\n", strerror(errno));
    107 		}
    108 		red = colors;
    109 		green = red + gamma_size;
    110 		blue = green + gamma_size;
    111 
    112 		for (i = 0; i < gamma_size; i++) {
    113 			float r = 65535.0 * i / gamma_size;
    114 			red[i] = r * ratio_red;
    115 			green[i] = r * ratio_green;
    116 			blue[i] = r * ratio_blue;
    117 		}
    118 		drmModeCrtcSetGamma(fd, crtc_id, gamma_size, red, green, blue);
    119 
    120 		prev_gamma_size = gamma_size;
    121 	}
    122 
    123 	if (colors != NULL)
    124 		free(colors);
    125 }
    126 #endif /* DRM_SUPPORT */
    127 
    128 #ifdef QUARTZ_SUPPORT
    129 #include <CoreGraphics/CoreGraphics.h>
    130 
    131 static void
    132 quartz_handler(int temp)
    133 {
    134 	unsigned int i;
    135 	float ratio_red, ratio_green, ratio_blue;
    136 	CGDirectDisplayID *displays;
    137 	uint32_t display_count, n;
    138 	float *colors, *red, *green, *blue;
    139 	uint32_t gamma_size, prev_gamma_size;
    140 
    141 	i = (temp - TEMP_MIN) / TEMP_INTERVAL;
    142 	ratio_red = whitepoints[i].r;
    143 	ratio_green = whitepoints[i].g;
    144 	ratio_blue = whitepoints[i].b;
    145 
    146 	CGGetOnlineDisplayList(0, NULL, &display_count);
    147 	displays = malloc(display_count * sizeof(CGDirectDisplayID));
    148 	if (displays == NULL)
    149 		die("malloc: %s\n", strerror(errno));
    150 	CGGetOnlineDisplayList(display_count, displays, &display_count);
    151 
    152 	colors = NULL;
    153 	prev_gamma_size = 0;
    154 	for (n = 0; n < display_count; n++) {
    155 		CGDirectDisplayID display_id;
    156 		uint32_t i;
    157 
    158 		display_id = displays[n];
    159 		gamma_size = CGDisplayGammaTableCapacity(display_id);
    160 
    161 		if (colors == NULL) {
    162 			colors = malloc(3 * gamma_size * sizeof(uint16_t));
    163 			if (colors == NULL)
    164 				die("malloc: %s\n", strerror(errno));
    165 		} else if (gamma_size > prev_gamma_size) {
    166 			colors = realloc(colors, 3 * gamma_size * sizeof(uint16_t));
    167 			if (colors == NULL)
    168 				die("realloc: %s\n", strerror(errno));
    169 		}
    170 		red = colors;
    171 		green = red + gamma_size;
    172 		blue = green + gamma_size;
    173 
    174 		for (i = 0; i < gamma_size; i++) {
    175 			float r = (float) i / gamma_size;
    176 			red[i] = r * ratio_red;
    177 			green[i] = r * ratio_green;
    178 			blue[i] = r * ratio_blue;
    179 		}
    180 		CGSetDisplayTransferByTable(display_id, gamma_size, red, green, blue);
    181 
    182 		prev_gamma_size = gamma_size;
    183 	}
    184 
    185 	if (colors != NULL)
    186 		free(colors);
    187 
    188 	/* OS X resets gamma settings on exit, so never quit */
    189 	pause();
    190 }
    191 #endif /* QUARTZ_SUPPORT */
    192 
    193 #ifdef X_SUPPORT
    194 #include <X11/Xlib.h>
    195 #include <X11/extensions/Xrandr.h>
    196 
    197 static void
    198 x_handler(int temp)
    199 {
    200 	unsigned int i;
    201 	float ratio_red, ratio_green, ratio_blue;
    202 	Display *dpy;
    203 	XRRScreenResources *res;
    204 	int n;
    205 
    206 	i = (temp - TEMP_MIN) / TEMP_INTERVAL;
    207 	ratio_red = whitepoints[i].r;
    208 	ratio_green = whitepoints[i].g;
    209 	ratio_blue = whitepoints[i].b;
    210 
    211 	dpy = XOpenDisplay(NULL);
    212 	if (dpy == NULL)
    213 		die("cannot open display\n");
    214 	res = XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
    215 
    216 	for (n = 0; n < res->ncrtc; n++) {
    217 		RRCrtc crtc_id;
    218 		int gamma_size, i;
    219 		XRRCrtcGamma *crtc_gamma;
    220 
    221 		crtc_id = res->crtcs[n];
    222 		gamma_size = XRRGetCrtcGammaSize(dpy, crtc_id);
    223 		crtc_gamma = XRRAllocGamma(gamma_size);
    224 		if (crtc_gamma == NULL)
    225 			die("malloc: %s\n", strerror(errno));
    226 
    227 		for (i = 0; i < gamma_size; i++) {
    228 			float r = 65535.0 * i / gamma_size;
    229 			crtc_gamma->red[i] = r * ratio_red;
    230 			crtc_gamma->green[i] = r * ratio_green;
    231 			crtc_gamma->blue[i] = r * ratio_blue;
    232 		}
    233 		XRRSetCrtcGamma(dpy, crtc_id, crtc_gamma);
    234 
    235 		XRRFreeGamma(crtc_gamma);
    236 	}
    237 
    238 	XCloseDisplay(dpy);
    239 }
    240 #endif /* X_SUPPORT */
    241 
    242 void
    243 die(const char *fmt, ...)
    244 {
    245 	va_list ap;
    246 
    247 	va_start(ap, fmt);
    248 	vfprintf(stderr, fmt, ap);
    249 	va_end(ap);
    250 
    251 	exit(1);
    252 }
    253 
    254 static void
    255 usage()
    256 {
    257 	char ifStr[64];
    258 	unsigned int i;
    259 
    260 	ifStr[0] = '\0';
    261 	for (i = 0; i < LEN(interfaces); i++) {
    262 		strcat(ifStr, interfaces[i].name);
    263 		if (i + 1 < LEN(interfaces))
    264 			strcat(ifStr, " ");
    265 	}
    266 
    267 	die(
    268 		"usage: %s [-hv] -i interface temperature\n"
    269 		"  interface - one of [ %s ]\n"
    270 		"  temperature - %i-%i\n",
    271 		argv0, ifStr, TEMP_MIN, TEMP_MAX
    272 	);
    273 }
    274 
    275 int
    276 main(int argc, char **argv) {
    277 	void (*handler)(int temp);
    278 	char *if_name;
    279 	unsigned int i;
    280 	int temp;
    281 
    282 	handler = NULL;
    283 
    284 	ARGBEGIN {
    285 	case 'i': {
    286 		if_name = EARGF(usage());
    287 		for (i = 0; i < LEN(interfaces); i++)
    288 			if (strcmp(if_name, interfaces[i].name) == 0) {
    289 				handler = interfaces[i].handler;
    290 				break;
    291 			}
    292 		if (handler == NULL)
    293 			usage();
    294 		break;
    295 	}
    296 	case 'v':
    297 		puts("ctemp "VERSION);
    298 		return 0;
    299 	case 'h':
    300 	default:
    301 		usage();
    302 		break;
    303 	} ARGEND
    304 
    305 	if (handler == NULL && LEN(interfaces) == 1)
    306 		handler = interfaces[0].handler;
    307 
    308 	if (handler == NULL)
    309 		usage();
    310 
    311 	temp = 0;
    312 	if (argc == 0)
    313 		usage();
    314 	else {
    315 		temp = atoi(argv[0]);
    316 		if (temp < TEMP_MIN || temp > TEMP_MAX)
    317 			usage();
    318 	}
    319 
    320 	handler(temp);
    321 }