diff options
-rw-r--r-- | README | 31 | ||||
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | cg-base.c | 2 | ||||
-rw-r--r-- | radharc.1 | 31 | ||||
-rw-r--r-- | radharc.c | 216 |
5 files changed, 266 insertions, 19 deletions
@@ -94,11 +94,42 @@ OPTIONS -t temperature Colour temperature, in Kelvins, to apply. + If temperature is '?' or 'get', the utility will print the + currently applied temperature. + -x Remove the currently applied filter. OPERANDS No operands are supported. +SIGNALS + The following signals have non-default meaning: + + SIGINT + Gradually fade out the effect and terminate the process. + + If the fade out time is 0 (default) or if the signal is sent + twice, the effect is removed immediately. + + SIGHUP + Terminate the process after any current fade in or fade out + action, but leaf the effect in place. + + SIGUSR1 + Gradually fade out the effect but do not terminate the process. + + If the fade out time is 0 (default) or if the signal is sent + twice, the effect is removed immediately. + + SIGUSR2 + Gradually fade the effect back in (from SIGUSR1). + + If the fade in time is 0 (default) or if the signal is sent + twice, the effect is restored immediately. + + If sent during the initial fade in, the fade in is cancelled + and the full effect is immediately applied. + SEE ALSO coopgammad(1), cg-tools(7), redshift(1), blueshift(1) @@ -1,4 +1,3 @@ -On fade in, query active setting and start from there. (requires libred>=1.1) Use bus for changing settings and CRTCs online. -Add "-t ?" and "-t get" for getting the current temperature. (requires libred>=1.1) -Add PF_UNIX SOCK_DGRAM socket with abstract address @/proc/<pid>/radharc for IPC +Add PF_UNIX SOCK_DGRAM socket with abstract address @/proc/<pid>/<class> for IPC +Add support for non-sRGB, RGB monitors @@ -697,7 +697,7 @@ main(int argc, char *argv[]) fprintf(stderr, "%s: no CRTC:s are available\n", argv0); goto custom_fail; } - + if (!*class_suffixes) { classes = &class; classes_n = 1; @@ -153,6 +153,14 @@ for local display 0 when using X. .TP .BR -t \ \fItemperature\fP Colour temperature, in Kelvins, to apply. + +If +.I temperature +is +.RB ' ? ' +or +.RB ' get ', +the utility will print the currently applied temperature. .TP .B -x Remove the currently applied filter. @@ -187,7 +195,28 @@ If the fade in time is 0 (default) or if the signal is sent twice, the effect is restored immediately. If sent during the initial fade in, the fade in is cancelled -and the full effect is immediately applied +and the full effect is immediately applied. + +.SH STDOUT +The standard output is normally not used, however if +.I temperature +has been specified with +.RB ' get ' +or +.RB ' ? ', +the colour temperature that was set before when the +program started is printed to standard output on the +following format: +.P +.RS +.nf +\fB\(dq%uK\en\(dq, \fP<\fIpreapplied temperature\fP> +.fi +.RE +.P +where it is garanteed that +.I preapplied temperature +is within [1000, 40000]. .SH SEE ALSO .BR coopgammad (1), @@ -11,6 +11,14 @@ #include <libclut.h> #include <libred.h> + +#if 0 +# define IF_LINEARISING(...) __VA_ARGS__ +#else +# define IF_LINEARISING(...) ((void)0) +#endif + + /** * The default filter priority for the program */ @@ -92,6 +100,21 @@ static int dflag = 0; */ static int xflag = 0; +/** + * Whether the currently applied temperature should be + * printed when the program starts + */ +static int print_temperature = 0; + + +/** + * Set to 1 by `handle_args` if the used arguments + * does not describe an action that requires the + * temperature to be modified; that is, only "-t get" + * (or "-t ?" is specified) + */ +static int no_temperature_change = 0; + /** * If 0, SIGINT has not been received, @@ -238,9 +261,13 @@ handle_opt(char *opt, char *arg) xflag = 0; return 1; case 't': - if (parse_double(&choosen_temperature, arg)) - usage(); - xflag = 0; + if (!strcmp(arg, "get") || !strcmp(arg, "?")) { + print_temperature = 1; + } else { + if (parse_double(&choosen_temperature, arg)) + usage(); + xflag = 0; + } return 1; case 'x': xflag = 1; @@ -268,7 +295,8 @@ handle_opt(char *opt, char *arg) int handle_args(int argc, char *argv[], char *prio) { - if (argc || (!xflag && !have_location && choosen_temperature < 0)) + no_temperature_change = (!xflag && !have_location && choosen_temperature < 0); + if (argc || (no_temperature_change && !print_temperature)) usage(); return 0; (void) argv; @@ -291,9 +319,9 @@ fill_filter(libcoopgamma_filter_t *restrict filter, double red, double green, do #define X(CONST, MEMBER, MAX, TYPE)\ case CONST:\ libclut_start_over(&(filter->ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ - libclut_linearise(&(filter->ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ + IF_LINEARISING(libclut_linearise(&(filter->ramps.MEMBER), (MAX), TYPE, 1, 1, 1));\ libclut_rgb_brightness(&(filter->ramps.MEMBER), MAX, TYPE, red, green, blue);\ - libclut_standardise(&(filter->ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ + IF_LINEARISING(libclut_standardise(&(filter->ramps.MEMBER), (MAX), TYPE, 1, 1, 1));\ break; LIST_DEPTHS #undef X @@ -320,7 +348,6 @@ set_ramps(double red, double green, double blue) int r; size_t i, j; - libclut_model_standard_to_linear(&red, &green, &blue); for (i = 0, r = 1; i < filters_n; i++) { if (!crtc_updates[i].master || !crtc_info[crtc_updates[i].crtc].supported) continue; @@ -351,6 +378,34 @@ set_ramps(double red, double green, double blue) /** + * Get the colour of a temperature + * + * @param t The temperature, in Kelvin + * @param r_out Output parameter for the red channel multiplier + * @param g_out Output parameter for the green channel multiplier + * @param b_out Output parameter for the blue channel multiplier + * @return 0 on success, -1 on failure + */ +static int +get_colour(long int t, double *r_out, double *g_out, double *b_out) +{ + double x, y, z, max; + if (libred_get_colour_xy(t, &x, &y)) + return -1; + libclut_model_ciexyy_to_ciexyz(x, y, 1.0, &x, &z); + libclut_model_ciexyz_to_linear(x, 1.0, z, r_out, g_out, b_out); + *r_out = fmax(0.0, *r_out); + *g_out = fmax(0.0, *g_out); + *b_out = fmax(0.0, *b_out); + max = fmax(fmax(*r_out, *g_out), *b_out); + *r_out /= max; + *g_out /= max; + *b_out /= max; + return 0; +} + + +/** * Get the colour temperature for the current time * * @param tp Output parameter for the colour temperature @@ -376,6 +431,120 @@ get_temperature(double *tp) /** + * Get the currently applied colour temperature + * + * @param tp Output parameter for the colour temperature + * @return 0: Success + * -1: Error, `errno` set + * -2: Error, `cg.error` set + */ +static int +get_applied_temperature(double *tp) +{ + libcoopgamma_filter_table_t table; + libcoopgamma_filter_query_t query; + libcoopgamma_ramps_t *restrict ramps; + size_t filter_i, i, tn = 0; + long double lred, lgreen, lblue; + double red, green, blue, t, tsum = 0; + double x, y, z; + + if (libcoopgamma_set_nonblocking(&cg, 0) < 0) + return -1; + + if (libcoopgamma_filter_table_initialise(&table) < 0) + return -1; + if (libcoopgamma_filter_query_initialise(&query) < 0) + return -1; + query.coalesce = 0; + + for (filter_i = 0; filter_i < filters_n; filter_i++) { + query.crtc = crtc_updates[filter_i].filter.crtc; + while (libcoopgamma_get_gamma_sync(&query, &table, &cg) < 0) { + if (errno == EINTR) + continue; + return -1; + } + + for (i = 0; i < table.filter_count; i++) + if (!strcmp(table.filters[i].class, crtc_updates[filter_i].filter.class)) + break; + if (i == table.filter_count) { + no_filter: +#if 0 + fprintf(stderr, "%s: temperature on %s: not found\n", argv0, query.crtc); +#endif + continue; + } + + ramps = &table.filters[i].ramps; + if (!table.red_size || !table.green_size || !table.blue_size) + goto no_filter; + + switch (table.depth) { +#define X(CONST, MEMBER, MAX, TYPE)\ + case CONST:\ + IF_LINEARISING(libclut_linearise(&(ramps->MEMBER), (MAX), TYPE, 1, 1, 1));\ + lred = (long double)ramps->MEMBER.red[table.red_size - 1U] / (MAX);\ + lgreen = (long double)ramps->MEMBER.green[table.green_size - 1U] / (MAX);\ + lblue = (long double)ramps->MEMBER.blue[table.blue_size - 1U] / (MAX);\ + break + X(LIBCOOPGAMMA_DOUBLE, d, 1.0, double); + X(LIBCOOPGAMMA_FLOAT, f, 1.0, float); + X(LIBCOOPGAMMA_UINT8, u8, UINT8_MAX, uint8_t); + X(LIBCOOPGAMMA_UINT16, u16, UINT16_MAX, uint16_t); + X(LIBCOOPGAMMA_UINT32, u32, UINT32_MAX, uint32_t); + X(LIBCOOPGAMMA_UINT64, u64, UINT64_MAX, uint64_t); +#undef X + default: + errno = EPROTO; + return -1; + } + red = (double)lred; + green = (double)lgreen; + blue = (double)lblue; + + if (red > 0.996 && blue < 0.004) { /* out of gamut (1000K to 1900K) */ + long int t1 = LIBRED_LOWEST_TEMPERATURE, t2; + double g1 = 0, r2, g2, b2; + for (t2 = LIBRED_LOWEST_TEMPERATURE; t2 <= 1900; t2 += LIBRED_DELTA_TEMPERATURE) { + libred_get_colour_xy(t2, &x, &y); + libclut_model_ciexyy_to_ciexyz(x, y, 1.0, &x, &z); + libclut_model_ciexyz_to_linear(x, 1.0, z, &r2, &g2, &b2); + g2 /= fmax(fmax(r2, g2), b2); + if (green <= g2) { + t = (green - g1) / (g2 - g1); + t = t1 + (t2 - t1) * t; + goto estimated; + } + t1 = t2; + g1 = g2; + } + t = 1900; + } + + libclut_model_linear_to_ciexyz(red, green, blue, &x, &y, &z); + libclut_model_ciexyz_to_ciexyy(x, y, z, &x, &y); + t = libred_get_temperature_xy(x, y, &x, &y); +#if 0 + libred_get_colour_xy((long int)t, &x, &y); + x = sqrt(x*x + y*y); + fprintf(stderr, "%s: temperature on %s: %gK (error: %g)\n", argv0, query.crtc, t, x); +#endif + estimated: + tsum += t; + tn += 1U; + } + + if (libcoopgamma_set_nonblocking(&cg, 1) < 0) + return -1; + + *tp = tn ? tsum / (double)tn : 6500; + return 0; +} + + +/** * Called when SIGINT is received * * @param sig Always `SIGINT` @@ -436,10 +605,10 @@ sigusr2_handler(int sig) int start(void) { - int r, tfd; + int r, tfd, initial_fade_in = 1; size_t i; double target_temperature; - long int original_temperature; + long int original_temperature = 6500; long int current_temperature = 6500; double red = 1, green = 1, blue = 1; uint64_t overrun; @@ -476,6 +645,18 @@ start(void) if (choosen_temperature < 0) dflag = 1; + if (fade_in_cs || print_temperature) { + double t; + if ((r = get_applied_temperature(&t))) + return r; + original_temperature = (long int)(t + 0.5); + if (print_temperature) + printf("%liK\n", original_temperature); + } + + if (no_temperature_change) + return 0; + if (xflag) return set_ramps(1, 1, 1); @@ -494,7 +675,14 @@ fade_in: return -1; fade_cs = (size_t)fade_in_cs; -fade_in_have_timer: + if (initial_fade_in) { + initial_fade_in = 0; + if ((r = get_temperature(&target_temperature)) < 0) + return r; + } else { + fade_in_have_timer: + original_temperature = 6500; + } for (i = 0; i < fade_cs;) { if (sigint_received) { goto reverse_fade_in; @@ -512,8 +700,8 @@ fade_in_have_timer: if (i % 600 == 0) if ((r = get_temperature(&target_temperature)) < 0) return r; - current_temperature = (long int)(6500 - (6500 - target_temperature) * i / fade_cs); - if (libred_get_colour(current_temperature, &red, &green, &blue)) + current_temperature = (long int)(original_temperature - (original_temperature - target_temperature) * i / fade_cs); + if (get_colour(current_temperature, &red, &green, &blue)) return -1; if ((r = set_ramps(red, green, blue)) < 0) return r; @@ -550,7 +738,7 @@ faded_in: if ((r = get_temperature(&target_temperature)) < 0) return r; current_temperature = (long int)target_temperature; - if (libred_get_colour(current_temperature, &red, &green, &blue)) + if (get_colour(current_temperature, &red, &green, &blue)) return -1; if ((r = set_ramps(red, green, blue)) < 0) return r; @@ -597,7 +785,7 @@ fade_out_have_timer: } current_temperature = original_temperature + (double)(6500 - original_temperature) * i / fade_cs; - if (libred_get_colour(current_temperature, &red, &green, &blue)) + if (get_colour(current_temperature, &red, &green, &blue)) goto fade_out_fail; if ((r = set_ramps(red, green, blue)) < 0) goto fade_out_fail_use_r; |