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:
Jon Lund Steffensen
2015-01-04 16:34:33 -05:00
parent 77e2c3b88b
commit d32314f8cc
2 changed files with 133 additions and 41 deletions
+120 -40
View File
@@ -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
View File
@@ -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;