|
| 1 | +/* colortemp.c */ |
| 2 | +/* Copyright (c) 2009, Jon Lund Steffensen <jonlst@gmail.com> */ |
| 3 | + |
| 4 | +#include <stdio.h> |
| 5 | +#include <stdlib.h> |
| 6 | +#include <stdint.h> |
| 7 | +#include <math.h> |
| 8 | + |
| 9 | +#include <xcb/xcb.h> |
| 10 | +#include <xcb/randr.h> |
| 11 | + |
| 12 | + |
| 13 | +/* Source: http://www.vendian.org/mncharity/dir3/blackbody/ |
| 14 | + Rescaled to make exactly 6500K equal to full intensity in all channels. */ |
| 15 | +static const float blackbody_color[] = { |
| 16 | + 1.0000, 0.0425, 0.0000, /* 1000K */ |
| 17 | + 1.0000, 0.0668, 0.0000, /* 1100K */ |
| 18 | + 1.0000, 0.0911, 0.0000, /* 1200K */ |
| 19 | + 1.0000, 0.1149, 0.0000, /* ... */ |
| 20 | + 1.0000, 0.1380, 0.0000, |
| 21 | + 1.0000, 0.1604, 0.0000, |
| 22 | + 1.0000, 0.1819, 0.0000, |
| 23 | + 1.0000, 0.2024, 0.0000, |
| 24 | + 1.0000, 0.2220, 0.0000, |
| 25 | + 1.0000, 0.2406, 0.0000, |
| 26 | + 1.0000, 0.2630, 0.0062, |
| 27 | + 1.0000, 0.2868, 0.0155, |
| 28 | + 1.0000, 0.3102, 0.0261, |
| 29 | + 1.0000, 0.3334, 0.0379, |
| 30 | + 1.0000, 0.3562, 0.0508, |
| 31 | + 1.0000, 0.3787, 0.0650, |
| 32 | + 1.0000, 0.4008, 0.0802, |
| 33 | + 1.0000, 0.4227, 0.0964, |
| 34 | + 1.0000, 0.4442, 0.1136, |
| 35 | + 1.0000, 0.4652, 0.1316, |
| 36 | + 1.0000, 0.4859, 0.1505, |
| 37 | + 1.0000, 0.5062, 0.1702, |
| 38 | + 1.0000, 0.5262, 0.1907, |
| 39 | + 1.0000, 0.5458, 0.2118, |
| 40 | + 1.0000, 0.5650, 0.2335, |
| 41 | + 1.0000, 0.5839, 0.2558, |
| 42 | + 1.0000, 0.6023, 0.2786, |
| 43 | + 1.0000, 0.6204, 0.3018, |
| 44 | + 1.0000, 0.6382, 0.3255, |
| 45 | + 1.0000, 0.6557, 0.3495, |
| 46 | + 1.0000, 0.6727, 0.3739, |
| 47 | + 1.0000, 0.6894, 0.3986, |
| 48 | + 1.0000, 0.7058, 0.4234, |
| 49 | + 1.0000, 0.7218, 0.4485, |
| 50 | + 1.0000, 0.7375, 0.4738, |
| 51 | + 1.0000, 0.7529, 0.4992, |
| 52 | + 1.0000, 0.7679, 0.5247, |
| 53 | + 1.0000, 0.7826, 0.5503, |
| 54 | + 1.0000, 0.7970, 0.5760, |
| 55 | + 1.0000, 0.8111, 0.6016, |
| 56 | + 1.0000, 0.8250, 0.6272, |
| 57 | + 1.0000, 0.8384, 0.6529, |
| 58 | + 1.0000, 0.8517, 0.6785, |
| 59 | + 1.0000, 0.8647, 0.7040, |
| 60 | + 1.0000, 0.8773, 0.7294, |
| 61 | + 1.0000, 0.8897, 0.7548, |
| 62 | + 1.0000, 0.9019, 0.7801, |
| 63 | + 1.0000, 0.9137, 0.8051, |
| 64 | + 1.0000, 0.9254, 0.8301, |
| 65 | + 1.0000, 0.9367, 0.8550, |
| 66 | + 1.0000, 0.9478, 0.8795, |
| 67 | + 1.0000, 0.9587, 0.9040, |
| 68 | + 1.0000, 0.9694, 0.9283, |
| 69 | + 1.0000, 0.9798, 0.9524, |
| 70 | + 1.0000, 0.9900, 0.9763, |
| 71 | + 1.0000, 1.0000, 1.0000, /* 6500K */ |
| 72 | + 0.9917, 1.0014, 1.0149, |
| 73 | + 0.9696, 0.9885, 1.0149, |
| 74 | + 0.9488, 0.9761, 1.0149, |
| 75 | + 0.9290, 0.9642, 1.0149, |
| 76 | + 0.9102, 0.9529, 1.0149, |
| 77 | + 0.8923, 0.9420, 1.0149, |
| 78 | + 0.8753, 0.9316, 1.0149, |
| 79 | + 0.8591, 0.9215, 1.0149, |
| 80 | + 0.8437, 0.9120, 1.0149, |
| 81 | + 0.8289, 0.9028, 1.0149, |
| 82 | + 0.8149, 0.8939, 1.0149, |
| 83 | + 0.8014, 0.8854, 1.0149, |
| 84 | + 0.7885, 0.8772, 1.0149, |
| 85 | + 0.7762, 0.8693, 1.0149, |
| 86 | + 0.7644, 0.8617, 1.0149, |
| 87 | + 0.7531, 0.8543, 1.0149, |
| 88 | + 0.7423, 0.8472, 1.0149, |
| 89 | + 0.7319, 0.8404, 1.0149, |
| 90 | + 0.7219, 0.8338, 1.0149, |
| 91 | + 0.7123, 0.8274, 1.0149, |
| 92 | + 0.7030, 0.8213, 1.0149, |
| 93 | + 0.6941, 0.8152, 1.0149, |
| 94 | + 0.6856, 0.8094, 1.0149, |
| 95 | + 0.6773, 0.8039, 1.0149, |
| 96 | + 0.6693, 0.7984, 1.0149, |
| 97 | + 0.6617, 0.7932, 1.0149, |
| 98 | + 0.6543, 0.7881, 1.0149, |
| 99 | + 0.6471, 0.7832, 1.0149, |
| 100 | + 0.6402, 0.7784, 1.0149, |
| 101 | + 0.6335, 0.7737, 1.0149, |
| 102 | + 0.6271, 0.7692, 1.0149, |
| 103 | + 0.6208, 0.7648, 1.0149, |
| 104 | + 0.6148, 0.7605, 1.0149, |
| 105 | + 0.6089, 0.7564, 1.0149, |
| 106 | + 0.6033, 0.7524, 1.0149 /* 10000K */ |
| 107 | +}; |
| 108 | + |
| 109 | + |
| 110 | +static void |
| 111 | +interpolate_color(float a, const float *c1, const float *c2, float *c) |
| 112 | +{ |
| 113 | + c[0] = (1.0-a)*c1[0] + a*c2[0]; |
| 114 | + c[1] = (1.0-a)*c1[1] + a*c2[1]; |
| 115 | + c[2] = (1.0-a)*c1[2] + a*c2[2]; |
| 116 | +} |
| 117 | + |
| 118 | +int |
| 119 | +colortemp_check_extension() |
| 120 | +{ |
| 121 | + xcb_generic_error_t *error; |
| 122 | + |
| 123 | + /* Open X server connection */ |
| 124 | + xcb_connection_t *conn = xcb_connect(NULL, NULL); |
| 125 | + |
| 126 | + /* Query RandR version */ |
| 127 | + xcb_randr_query_version_cookie_t ver_cookie = |
| 128 | + xcb_randr_query_version(conn, 1, 3); |
| 129 | + xcb_randr_query_version_reply_t *ver_reply = |
| 130 | + xcb_randr_query_version_reply(conn, ver_cookie, &error); |
| 131 | + |
| 132 | + if (error) { |
| 133 | + fprintf(stderr, "RANDR Query Version, error: %d\n", |
| 134 | + error->error_code); |
| 135 | + xcb_disconnect(conn); |
| 136 | + return -1; |
| 137 | + } |
| 138 | + |
| 139 | + if (ver_reply->major_version < 1 || ver_reply->minor_version < 3) { |
| 140 | + fprintf(stderr, "Unsupported RANDR version (%u.%u)\n", |
| 141 | + ver_reply->major_version, ver_reply->minor_version); |
| 142 | + free(ver_reply); |
| 143 | + xcb_disconnect(conn); |
| 144 | + return -1; |
| 145 | + } |
| 146 | + |
| 147 | + free(ver_reply); |
| 148 | + |
| 149 | + /* Close connection */ |
| 150 | + xcb_disconnect(conn); |
| 151 | + |
| 152 | + return 0; |
| 153 | +} |
| 154 | + |
| 155 | +int |
| 156 | +colortemp_set_temperature(int temp, float gamma) |
| 157 | +{ |
| 158 | + xcb_generic_error_t *error; |
| 159 | + |
| 160 | + /* Open X server connection */ |
| 161 | + xcb_connection_t *conn = xcb_connect(NULL, NULL); |
| 162 | + |
| 163 | + /* Get first screen */ |
| 164 | + const xcb_setup_t *setup = xcb_get_setup(conn); |
| 165 | + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); |
| 166 | + xcb_screen_t *screen = iter.data; |
| 167 | + |
| 168 | + /* Get list of CRTCs for the screen */ |
| 169 | + xcb_randr_get_screen_resources_current_cookie_t res_cookie = |
| 170 | + xcb_randr_get_screen_resources_current(conn, screen->root); |
| 171 | + xcb_randr_get_screen_resources_current_reply_t *res_reply = |
| 172 | + xcb_randr_get_screen_resources_current_reply(conn, res_cookie, |
| 173 | + &error); |
| 174 | + |
| 175 | + if (error) { |
| 176 | + fprintf(stderr, "RANDR Get Screen Resources Current," |
| 177 | + " error: %d\n", error->error_code); |
| 178 | + xcb_disconnect(conn); |
| 179 | + return -1; |
| 180 | + } |
| 181 | + |
| 182 | + xcb_randr_crtc_t *crtcs = |
| 183 | + xcb_randr_get_screen_resources_current_crtcs(res_reply); |
| 184 | + xcb_randr_crtc_t crtc = crtcs[0]; |
| 185 | + |
| 186 | + free(res_reply); |
| 187 | + |
| 188 | + /* Request size of gamma ramps */ |
| 189 | + xcb_randr_get_crtc_gamma_size_cookie_t gamma_size_cookie = |
| 190 | + xcb_randr_get_crtc_gamma_size(conn, crtc); |
| 191 | + xcb_randr_get_crtc_gamma_size_reply_t *gamma_size_reply = |
| 192 | + xcb_randr_get_crtc_gamma_size_reply(conn, gamma_size_cookie, |
| 193 | + &error); |
| 194 | + |
| 195 | + if (error) { |
| 196 | + fprintf(stderr, "RANDR Get CRTC Gamma Size, error: %d\n", |
| 197 | + error->error_code); |
| 198 | + xcb_disconnect(conn); |
| 199 | + return -1; |
| 200 | + } |
| 201 | + |
| 202 | + int gamma_ramp_size = gamma_size_reply->size; |
| 203 | + |
| 204 | + free(gamma_size_reply); |
| 205 | + |
| 206 | + if (gamma_ramp_size == 0) { |
| 207 | + fprintf(stderr, "Error: Gamma ramp size too small, %i\n", |
| 208 | + gamma_ramp_size); |
| 209 | + xcb_disconnect(conn); |
| 210 | + return -1; |
| 211 | + } |
| 212 | + |
| 213 | + /* Calculate white point */ |
| 214 | + float white_point[3]; |
| 215 | + float alpha = (temp % 100) / 100.0; |
| 216 | + int temp_index = ((temp - 1000) / 100)*3; |
| 217 | + interpolate_color(alpha, &blackbody_color[temp_index], |
| 218 | + &blackbody_color[temp_index+3], white_point); |
| 219 | + |
| 220 | + printf("White point: %f, %f, %f\n", |
| 221 | + white_point[0], white_point[1], white_point[2]); |
| 222 | + |
| 223 | + /* Create new gamma ramps */ |
| 224 | + uint16_t *gamma_ramps = malloc(3*gamma_ramp_size*sizeof(uint16_t)); |
| 225 | + if (gamma_ramps == NULL) abort(); |
| 226 | + |
| 227 | + uint16_t *gamma_r = &gamma_ramps[0*gamma_ramp_size]; |
| 228 | + uint16_t *gamma_g = &gamma_ramps[1*gamma_ramp_size]; |
| 229 | + uint16_t *gamma_b = &gamma_ramps[2*gamma_ramp_size]; |
| 230 | + |
| 231 | + for (int i = 0; i < gamma_ramp_size; i++) { |
| 232 | + gamma_r[i] = pow((float)i/gamma_ramp_size, 1.0/gamma) * |
| 233 | + UINT16_MAX * white_point[0]; |
| 234 | + gamma_g[i] = pow((float)i/gamma_ramp_size, 1.0/gamma) * |
| 235 | + UINT16_MAX * white_point[1]; |
| 236 | + gamma_b[i] = pow((float)i/gamma_ramp_size, 1.0/gamma) * |
| 237 | + UINT16_MAX * white_point[2]; |
| 238 | + } |
| 239 | + |
| 240 | + /* Set new gamma ramps */ |
| 241 | + xcb_void_cookie_t gamma_set_cookie = |
| 242 | + xcb_randr_set_crtc_gamma_checked(conn, crtc, gamma_ramp_size, |
| 243 | + gamma_r, gamma_g, gamma_b); |
| 244 | + error = xcb_request_check(conn, gamma_set_cookie); |
| 245 | + |
| 246 | + if (error) { |
| 247 | + fprintf(stderr, "RANDR Set CRTC Gamma, error: %d\n", |
| 248 | + error->error_code); |
| 249 | + free(gamma_ramps); |
| 250 | + xcb_disconnect(conn); |
| 251 | + return -1; |
| 252 | + } |
| 253 | + |
| 254 | + free(gamma_ramps); |
| 255 | + |
| 256 | + /* Close connection */ |
| 257 | + xcb_disconnect(conn); |
| 258 | + |
| 259 | + return 0; |
| 260 | +} |
0 commit comments