diff options
| author | Mattias Andrée <m@maandree.se> | 2025-02-05 17:54:08 +0100 | 
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2025-02-05 17:54:08 +0100 | 
| commit | 0f60b84867f0a275a05353f5da13973c8d0d1910 (patch) | |
| tree | 4baf40316a1e04eb42eb757728583b239006f85a | |
| parent | Add support for SIGUSR1 and SIGUSR2 (diff) | |
| download | radharc-0f60b84867f0a275a05353f5da13973c8d0d1910.tar.gz radharc-0f60b84867f0a275a05353f5da13973c8d0d1910.tar.bz2 radharc-0f60b84867f0a275a05353f5da13973c8d0d1910.tar.xz  | |
Add support for -t get/? and transition from applied temperature when starting1.2
Signed-off-by: Mattias Andrée <m@maandree.se>
| -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;  | 
