quartz: Add preserve option to Quartz method
This change adds the preserve option to the quartz method which makes it base the temperature adjustments on the existing gamma ramps when set. This requires that the existing gamma ramps are saved at start-up which this commit also adds. One drawback is that the list of displays is enumerated at start-up now which means that Redshift will likely not affect displays that are connected after start-up. This could be fixed in the future by listening to reconfiguration events.
This commit is contained in:
+120
-40
@@ -40,12 +40,95 @@
|
||||
int
|
||||
quartz_init(quartz_state_t *state)
|
||||
{
|
||||
state->preserve = 0;
|
||||
state->displays = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
quartz_start(quartz_state_t *state)
|
||||
{
|
||||
int r;
|
||||
CGError error;
|
||||
uint32_t display_count;
|
||||
|
||||
/* Get display count */
|
||||
error = CGGetOnlineDisplayList(0, NULL, &display_count);
|
||||
if (error != kCGErrorSuccess) return -1;
|
||||
|
||||
state->display_count = display_count;
|
||||
|
||||
CGDirectDisplayID* displays =
|
||||
malloc(sizeof(CGDirectDisplayID)*display_count);
|
||||
if (displays == NULL) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get list of displays */
|
||||
error = CGGetOnlineDisplayList(display_count, displays,
|
||||
&display_count);
|
||||
if (error != kCGErrorSuccess) {
|
||||
free(displays);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate list of display state */
|
||||
state->displays = malloc(display_count *
|
||||
sizeof(quartz_display_state_t));
|
||||
if (state->displays == NULL) {
|
||||
perror("malloc");
|
||||
free(displays);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy display indentifiers to display state */
|
||||
for (int i = 0; i < display_count; i++) {
|
||||
state->displays[i].display = displays[i];
|
||||
state->displays[i].saved_ramps = NULL;
|
||||
}
|
||||
|
||||
free(displays);
|
||||
|
||||
/* Save gamma ramps for all displays in display state */
|
||||
for (int i = 0; i < display_count; i++) {
|
||||
CGDirectDisplayID display = state->displays[i].display;
|
||||
|
||||
uint32_t ramp_size = CGDisplayGammaTableCapacity(display);
|
||||
if (ramp_size == 0) {
|
||||
fprintf(stderr, _("Gamma ramp size too small: %i\n"),
|
||||
ramp_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->displays[i].ramp_size = ramp_size;
|
||||
|
||||
/* Allocate space for saved ramps */
|
||||
state->displays[i].saved_ramps =
|
||||
malloc(3 * ramp_size * sizeof(float));
|
||||
if (state->displays[i].saved_ramps == NULL) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
float *gamma_r = &state->displays[i].saved_ramps[0*ramp_size];
|
||||
float *gamma_g = &state->displays[i].saved_ramps[1*ramp_size];
|
||||
float *gamma_b = &state->displays[i].saved_ramps[2*ramp_size];
|
||||
|
||||
/* Copy the ramps to allocated space */
|
||||
uint32_t sample_count;
|
||||
error = CGGetDisplayTransferByTable(display, ramp_size,
|
||||
gamma_r, gamma_g, gamma_b,
|
||||
&sample_count);
|
||||
if (error != kCGErrorSuccess ||
|
||||
sample_count != ramp_size) {
|
||||
fputs(_("Unable to save current gamma ramp.\n"),
|
||||
stderr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -58,6 +141,12 @@ quartz_restore(quartz_state_t *state)
|
||||
void
|
||||
quartz_free(quartz_state_t *state)
|
||||
{
|
||||
if (state->displays != NULL) {
|
||||
for (int i = 0; i < state->display_count; i++) {
|
||||
free(state->displays[i].saved_ramps);
|
||||
}
|
||||
}
|
||||
free(state->displays);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -65,25 +154,33 @@ quartz_print_help(FILE *f)
|
||||
{
|
||||
fputs(_("Adjust gamma ramps on OSX using Quartz.\n"), f);
|
||||
fputs("\n", f);
|
||||
|
||||
/* TRANSLATORS: Quartz help output
|
||||
left column must not be translated */
|
||||
fputs(_(" preserve={0,1}\tWhether existing gamma should be"
|
||||
" preserved\n"),
|
||||
f);
|
||||
fputs("\n", f);
|
||||
}
|
||||
|
||||
int
|
||||
quartz_set_option(quartz_state_t *state, const char *key, const char *value)
|
||||
{
|
||||
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
|
||||
return -1;
|
||||
if (strcasecmp(key, "preserve") == 0) {
|
||||
state->preserve = atoi(value);
|
||||
} else {
|
||||
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
quartz_set_temperature_for_display(CGDirectDisplayID display,
|
||||
quartz_set_temperature_for_display(quartz_state_t *state, int display,
|
||||
const color_setting_t *setting)
|
||||
{
|
||||
uint32_t ramp_size = CGDisplayGammaTableCapacity(display);
|
||||
if (ramp_size == 0) {
|
||||
fprintf(stderr, _("Gamma ramp size too small: %i\n"),
|
||||
ramp_size);
|
||||
return;
|
||||
}
|
||||
uint32_t ramp_size = state->displays[display].ramp_size;
|
||||
|
||||
/* Create new gamma ramps */
|
||||
float *gamma_ramps = malloc(3*ramp_size*sizeof(float));
|
||||
@@ -96,12 +193,18 @@ quartz_set_temperature_for_display(CGDirectDisplayID display,
|
||||
float *gamma_g = &gamma_ramps[1*ramp_size];
|
||||
float *gamma_b = &gamma_ramps[2*ramp_size];
|
||||
|
||||
/* Initialize gamma ramps to pure state */
|
||||
for (int i = 0; i < ramp_size; i++) {
|
||||
float value = (double)i/ramp_size;
|
||||
gamma_r[i] = value;
|
||||
gamma_g[i] = value;
|
||||
gamma_b[i] = value;
|
||||
if (state->preserve) {
|
||||
/* Initialize gamma ramps from saved state */
|
||||
memcpy(gamma_ramps, state->displays[display].saved_ramps,
|
||||
3*ramp_size*sizeof(float));
|
||||
} else {
|
||||
/* Initialize gamma ramps to pure state */
|
||||
for (int i = 0; i < ramp_size; i++) {
|
||||
float value = (double)i/ramp_size;
|
||||
gamma_r[i] = value;
|
||||
gamma_g[i] = value;
|
||||
gamma_b[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
colorramp_fill_float(gamma_r, gamma_g, gamma_b, ramp_size,
|
||||
@@ -122,32 +225,9 @@ int
|
||||
quartz_set_temperature(quartz_state_t *state,
|
||||
const color_setting_t *setting)
|
||||
{
|
||||
int r;
|
||||
CGError error;
|
||||
uint32_t display_count;
|
||||
|
||||
error = CGGetOnlineDisplayList(0, NULL, &display_count);
|
||||
if (error != kCGErrorSuccess) return -1;
|
||||
|
||||
CGDirectDisplayID* displays =
|
||||
malloc(sizeof(CGDirectDisplayID)*display_count);
|
||||
if (displays == NULL) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
for (int i = 0; i < state->display_count; i++) {
|
||||
quartz_set_temperature_for_display(state, i, setting);
|
||||
}
|
||||
|
||||
error = CGGetOnlineDisplayList(display_count, displays,
|
||||
&display_count);
|
||||
if (error != kCGErrorSuccess) {
|
||||
free(displays);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < display_count; i++) {
|
||||
quartz_set_temperature_for_display(displays[i], setting);
|
||||
}
|
||||
|
||||
free(displays);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+13
-1
@@ -20,11 +20,23 @@
|
||||
#ifndef REDSHIFT_GAMMA_QUARTZ_H
|
||||
#define REDSHIFT_GAMMA_QUARTZ_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
#include "redshift.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int dummy;
|
||||
CGDirectDisplayID display;
|
||||
uint32_t ramp_size;
|
||||
float *saved_ramps;
|
||||
} quartz_display_state_t;
|
||||
|
||||
typedef struct {
|
||||
quartz_display_state_t *displays;
|
||||
uint32_t display_count;
|
||||
int preserve;
|
||||
} quartz_state_t;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user