From 9b299132ef8912910df5a90b1628cc3af1efc54d Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Sun, 28 Dec 2014 22:58:54 -0500 Subject: colorramp: Use supplied gamma ramps as initial value This changes colorramp_fill() to base the ramp calculations on the existing values in the supplied tables, instead of basing it on a pure `i/size` value computed on the fly. All gamma adjustment methods are changed to explicitly initialize the ramps to the `i/size` value before calls to colorramp_fill(). --- src/colorramp.c | 15 +++++++++------ src/gamma-drm.c | 10 ++++++++++ src/gamma-quartz.c | 8 ++++++++ src/gamma-randr.c | 8 ++++++++ src/gamma-vidmode.c | 8 ++++++++ src/gamma-w32gdi.c | 8 ++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/colorramp.c b/src/colorramp.c index d732a18..fda75f2 100644 --- a/src/colorramp.c +++ b/src/colorramp.c @@ -297,9 +297,12 @@ colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, &blackbody_color[temp_index+3], white_point); for (int i = 0; i < size; i++) { - gamma_r[i] = F((float)i/size, 0) * (UINT16_MAX+1); - gamma_g[i] = F((float)i/size, 1) * (UINT16_MAX+1); - gamma_b[i] = F((float)i/size, 2) * (UINT16_MAX+1); + gamma_r[i] = F((double)gamma_r[i]/(UINT16_MAX+1), 0) * + (UINT16_MAX+1); + gamma_g[i] = F((double)gamma_g[i]/(UINT16_MAX+1), 1) * + (UINT16_MAX+1); + gamma_b[i] = F((double)gamma_b[i]/(UINT16_MAX+1), 2) * + (UINT16_MAX+1); } } @@ -315,9 +318,9 @@ colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b, &blackbody_color[temp_index+3], white_point); for (int i = 0; i < size; i++) { - gamma_r[i] = F((float)i/size, 0); - gamma_g[i] = F((float)i/size, 1); - gamma_b[i] = F((float)i/size, 2); + gamma_r[i] = F((double)gamma_r[i], 0); + gamma_g[i] = F((double)gamma_g[i], 1); + gamma_b[i] = F((double)gamma_b[i], 2); } } diff --git a/src/gamma-drm.c b/src/gamma-drm.c index cbdafe5..d431395 100644 --- a/src/gamma-drm.c +++ b/src/gamma-drm.c @@ -268,6 +268,16 @@ drm_set_temperature(drm_state_t *state, const color_setting_t *setting) } last_gamma_size = crtcs->gamma_size; } + + /* Initialize gamma ramps to pure state */ + int ramp_size = crtcs->gamma_size; + for (int i = 0; i < ramp_size; i++) { + uint16_t value = (double)i/ramp_size * (UINT16_MAX+1); + r_gamma[i] = value; + g_gamma[i] = value; + b_gamma[i] = value; + } + colorramp_fill(r_gamma, g_gamma, b_gamma, crtcs->gamma_size, setting); drmModeCrtcSetGamma(state->fd, crtcs->crtc_id, crtcs->gamma_size, diff --git a/src/gamma-quartz.c b/src/gamma-quartz.c index f28955f..4eeac4d 100644 --- a/src/gamma-quartz.c +++ b/src/gamma-quartz.c @@ -96,6 +96,14 @@ 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; + } + colorramp_fill_float(gamma_r, gamma_g, gamma_b, ramp_size, setting); diff --git a/src/gamma-randr.c b/src/gamma-randr.c index 4f6b0f0..5ef7a4f 100644 --- a/src/gamma-randr.c +++ b/src/gamma-randr.c @@ -327,6 +327,14 @@ randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, uint16_t *gamma_g = &gamma_ramps[1*ramp_size]; uint16_t *gamma_b = &gamma_ramps[2*ramp_size]; + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < ramp_size; i++) { + uint16_t value = (double)i/ramp_size * (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } + colorramp_fill(gamma_r, gamma_g, gamma_b, ramp_size, setting); diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c index 58a552f..a25b06e 100644 --- a/src/gamma-vidmode.c +++ b/src/gamma-vidmode.c @@ -180,6 +180,14 @@ vidmode_set_temperature(vidmode_state_t *state, uint16_t *gamma_g = &gamma_ramps[1*state->ramp_size]; uint16_t *gamma_b = &gamma_ramps[2*state->ramp_size]; + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < state->ramp_size; i++) { + uint16_t value = (double)i/state->ramp_size * (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } + colorramp_fill(gamma_r, gamma_g, gamma_b, state->ramp_size, setting); diff --git a/src/gamma-w32gdi.c b/src/gamma-w32gdi.c index ee603e6..c07ce91 100644 --- a/src/gamma-w32gdi.c +++ b/src/gamma-w32gdi.c @@ -153,6 +153,14 @@ w32gdi_set_temperature(w32gdi_state_t *state, WORD *gamma_g = &gamma_ramps[1*GAMMA_RAMP_SIZE]; WORD *gamma_b = &gamma_ramps[2*GAMMA_RAMP_SIZE]; + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < GAMMA_RAMP_SIZE; i++) { + WORD value = (double)i/GAMMA_RAMP_SIZE * (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } + colorramp_fill(gamma_r, gamma_g, gamma_b, GAMMA_RAMP_SIZE, setting); -- cgit v1.2.3-70-g09d2 From 77e2c3b88b47ec899a68fe6d9d5275950bcf3cec Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Sun, 28 Dec 2014 23:00:33 -0500 Subject: randr: Add preserve option to RandR method --- src/gamma-randr.c | 29 +++++++++++++++++++++-------- src/gamma-randr.h | 1 + 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/gamma-randr.c b/src/gamma-randr.c index 5ef7a4f..0594332 100644 --- a/src/gamma-randr.c +++ b/src/gamma-randr.c @@ -51,6 +51,8 @@ randr_init(randr_state_t *state) state->crtc_count = 0; state->crtcs = NULL; + state->preserve = 0; + xcb_generic_error_t *error; /* Open X server connection */ @@ -274,8 +276,11 @@ randr_print_help(FILE *f) /* TRANSLATORS: RANDR help output left column must not be translated */ - fputs(_(" screen=N\tX screen to apply adjustments to\n" - " crtc=N\tCRTC to apply adjustments to\n"), f); + fputs(_(" screen=N\t\tX screen to apply adjustments to\n" + " crtc=N\t\tCRTC to apply adjustments to\n" + " preserve={0,1}\tWhether existing gamma should be" + " preserved\n"), + f); fputs("\n", f); } @@ -286,6 +291,8 @@ randr_set_option(randr_state_t *state, const char *key, const char *value) state->screen_num = atoi(value); } else if (strcasecmp(key, "crtc") == 0) { state->crtc_num = atoi(value); + } else if (strcasecmp(key, "preserve") == 0) { + state->preserve = atoi(value); } else { fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); return -1; @@ -327,12 +334,18 @@ randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, uint16_t *gamma_g = &gamma_ramps[1*ramp_size]; uint16_t *gamma_b = &gamma_ramps[2*ramp_size]; - /* Initialize gamma ramps to pure state */ - for (int i = 0; i < ramp_size; i++) { - uint16_t value = (double)i/ramp_size * (UINT16_MAX+1); - 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->crtcs[crtc_num].saved_ramps, + 3*ramp_size*sizeof(uint16_t)); + } else { + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < ramp_size; i++) { + uint16_t value = (double)i/ramp_size * (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } } colorramp_fill(gamma_r, gamma_g, gamma_b, ramp_size, diff --git a/src/gamma-randr.h b/src/gamma-randr.h index e541379..093c41f 100644 --- a/src/gamma-randr.h +++ b/src/gamma-randr.h @@ -39,6 +39,7 @@ typedef struct { xcb_connection_t *conn; xcb_screen_t *screen; int preferred_screen; + int preserve; int screen_num; int crtc_num; unsigned int crtc_count; -- cgit v1.2.3-70-g09d2 From d32314f8ccfa706e9f46d052952af2b43be3f5a0 Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Sun, 28 Dec 2014 23:49:36 -0500 Subject: 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. --- src/gamma-quartz.c | 160 +++++++++++++++++++++++++++++++++++++++-------------- src/gamma-quartz.h | 14 ++++- 2 files changed, 133 insertions(+), 41 deletions(-) diff --git a/src/gamma-quartz.c b/src/gamma-quartz.c index 4eeac4d..6691c91 100644 --- a/src/gamma-quartz.c +++ b/src/gamma-quartz.c @@ -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; } diff --git a/src/gamma-quartz.h b/src/gamma-quartz.h index b5bc213..cd29d54 100644 --- a/src/gamma-quartz.h +++ b/src/gamma-quartz.h @@ -20,11 +20,23 @@ #ifndef REDSHIFT_GAMMA_QUARTZ_H #define REDSHIFT_GAMMA_QUARTZ_H +#include + +#include + #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; -- cgit v1.2.3-70-g09d2 From aaf455c9ae42e2a75f1aa746134161206f0bc9b2 Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Mon, 29 Dec 2014 00:53:50 -0500 Subject: vidmode: Add preserve option to VidMode method --- src/gamma-vidmode.c | 28 +++++++++++++++++++++------- src/gamma-vidmode.h | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c index a25b06e..254d065 100644 --- a/src/gamma-vidmode.c +++ b/src/gamma-vidmode.c @@ -43,6 +43,8 @@ vidmode_init(vidmode_state_t *state) state->screen_num = -1; state->saved_ramps = NULL; + state->preserve = 0; + /* Open display */ state->display = XOpenDisplay(NULL); if (state->display == NULL) { @@ -129,7 +131,10 @@ vidmode_print_help(FILE *f) /* TRANSLATORS: VidMode help output left column must not be translated */ - fputs(_(" screen=N\tX screen to apply adjustments to\n"), f); + fputs(_(" screen=N\t\tX screen to apply adjustments to\n" + " preserve={0,1}\tWhether existing gamma should be" + " preserved\n"), + f); fputs("\n", f); } @@ -138,6 +143,8 @@ vidmode_set_option(vidmode_state_t *state, const char *key, const char *value) { if (strcasecmp(key, "screen") == 0) { state->screen_num = atoi(value); + } else if (strcasecmp(key, "preserve") == 0) { + state->preserve = atoi(value); } else { fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); return -1; @@ -180,12 +187,19 @@ vidmode_set_temperature(vidmode_state_t *state, uint16_t *gamma_g = &gamma_ramps[1*state->ramp_size]; uint16_t *gamma_b = &gamma_ramps[2*state->ramp_size]; - /* Initialize gamma ramps to pure state */ - for (int i = 0; i < state->ramp_size; i++) { - uint16_t value = (double)i/state->ramp_size * (UINT16_MAX+1); - 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->saved_ramps, + 3*state->ramp_size*sizeof(uint16_t)); + } else { + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < state->ramp_size; i++) { + uint16_t value = (double)i/state->ramp_size * + (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } } colorramp_fill(gamma_r, gamma_g, gamma_b, state->ramp_size, diff --git a/src/gamma-vidmode.h b/src/gamma-vidmode.h index 05f5919..4b6cecc 100644 --- a/src/gamma-vidmode.h +++ b/src/gamma-vidmode.h @@ -29,6 +29,7 @@ typedef struct { Display *display; + int preserve; int screen_num; int ramp_size; uint16_t *saved_ramps; -- cgit v1.2.3-70-g09d2 From 699e25b33c98e31868d43cbe91e769ba05b840e6 Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Mon, 29 Dec 2014 01:02:06 -0500 Subject: w32gdi: Add preserve option to windows GDI method --- src/gamma-w32gdi.c | 36 +++++++++++++++++++++++++++++------- src/gamma-w32gdi.h | 1 + 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/gamma-w32gdi.c b/src/gamma-w32gdi.c index c07ce91..c518fe6 100644 --- a/src/gamma-w32gdi.c +++ b/src/gamma-w32gdi.c @@ -43,6 +43,7 @@ int w32gdi_init(w32gdi_state_t *state) { state->saved_ramps = NULL; + state->preserve = 0; return 0; } @@ -102,12 +103,26 @@ w32gdi_print_help(FILE *f) { fputs(_("Adjust gamma ramps with the Windows GDI.\n"), f); fputs("\n", f); + + /* TRANSLATORS: Windows GDI help output + left column must not be translated */ + fputs(_(" preserve={0,1}\tWhether existing gamma should be" + " preserved\n"), + f); + fputs("\n", f); } int w32gdi_set_option(w32gdi_state_t *state, const char *key, const char *value) { - return -1; + if (strcasecmp(key, "preserve") == 0) { + state->preserve = atoi(value); + } else { + fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); + return -1; + } + + return 0; } void @@ -153,12 +168,19 @@ w32gdi_set_temperature(w32gdi_state_t *state, WORD *gamma_g = &gamma_ramps[1*GAMMA_RAMP_SIZE]; WORD *gamma_b = &gamma_ramps[2*GAMMA_RAMP_SIZE]; - /* Initialize gamma ramps to pure state */ - for (int i = 0; i < GAMMA_RAMP_SIZE; i++) { - WORD value = (double)i/GAMMA_RAMP_SIZE * (UINT16_MAX+1); - 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->saved_ramps, + 3*GAMMA_RAMP_SIZE*sizeof(WORD)); + } else { + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < GAMMA_RAMP_SIZE; i++) { + WORD value = (double)i/GAMMA_RAMP_SIZE * + (UINT16_MAX+1); + gamma_r[i] = value; + gamma_g[i] = value; + gamma_b[i] = value; + } } colorramp_fill(gamma_r, gamma_g, gamma_b, GAMMA_RAMP_SIZE, diff --git a/src/gamma-w32gdi.h b/src/gamma-w32gdi.h index 1f985c8..6e73cd1 100644 --- a/src/gamma-w32gdi.h +++ b/src/gamma-w32gdi.h @@ -28,6 +28,7 @@ typedef struct { WORD *saved_ramps; + int preserve; } w32gdi_state_t; -- cgit v1.2.3-70-g09d2