From 47241e0fc7b00769d014430bf6f6903c4fe41b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:00:47 +0100 Subject: [PATCH 01/11] Update .gitignore with data/systemd/redshift{,-gtk}.service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8742289f..dc6de478 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ src/redshift-gtk/redshift-gtk contrib/redshift.spec src/redshift src/redshift-gtk/__pycache__/ +/data/systemd/redshift.service +/data/systemd/redshift-gtk.service # gettext /po/POTFILES From 41d6333cd9b584f43267ba07838115af60c3bf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:06:24 +0100 Subject: [PATCH 02/11] Typo in DESIGN: whic => which MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- DESIGN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESIGN b/DESIGN index 1b88aba1..7b708795 100644 --- a/DESIGN +++ b/DESIGN @@ -58,7 +58,7 @@ I've been mostly consistent with the naming throughout the source code (I hope). First adjustment methods: There is "randr" which is the preferred -because it has support for multiple outputs per X screen whic is lacking +because it has support for multiple outputs per X screen which is lacking in "vidmode". Both are APIs in the X server that allow for manipulation of gamma ramps, which is what Redshift uses to change the screen color temperature. There's also "wingdi" which is for the Windows version, From 6df6bb8e144cd5b269c56e146db5a89d2893240c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:11:37 +0100 Subject: [PATCH 03/11] Adjustment method common changes for support for using any number of CRTC:s in any number of screens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/config-ini.c | 31 +++++++++++ src/config-ini.h | 3 + src/redshift.c | 142 ++++++++++++++++++++--------------------------- src/redshift.h | 38 ++++++++++++- 4 files changed, 129 insertions(+), 85 deletions(-) diff --git a/src/config-ini.c b/src/config-ini.c index 65751ddf..628a7140 100644 --- a/src/config-ini.c +++ b/src/config-ini.c @@ -297,3 +297,34 @@ config_ini_get_section(config_ini_state_t *state, const char *name) return NULL; } + +config_ini_section_t ** +config_ini_get_sections(config_ini_state_t *state, const char *name) +{ + config_ini_section_t **sections = malloc(1 * sizeof(config_ini_section_t*)); + if (sections == NULL) { + perror("malloc"); + return NULL; + } + + int ptr = 0; + config_ini_section_t *section = state->sections; + while (section != NULL) { + if (strcasecmp(section->name, name) == 0) { + sections[ptr++] = section; + + if ((ptr & -ptr) == ptr) { + sections = realloc(sections, (ptr << 1) * sizeof(config_ini_section_t*)); + if (sections == NULL) { + perror("realloc"); + return NULL; + } + } + } + + section = section->next; + } + + sections[ptr] = NULL; + return sections; +} diff --git a/src/config-ini.h b/src/config-ini.h index 5cdcc729..da1d3b3d 100644 --- a/src/config-ini.h +++ b/src/config-ini.h @@ -46,4 +46,7 @@ void config_ini_free(config_ini_state_t *state); config_ini_section_t *config_ini_get_section(config_ini_state_t *state, const char *name); +config_ini_section_t **config_ini_get_sections(config_ini_state_t *state, + const char *name); + #endif /* ! REDSHIFT_CONFIG_INI_H */ diff --git a/src/redshift.c b/src/redshift.c index beecd353..af388c61 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -15,6 +15,7 @@ along with Redshift. If not, see . Copyright (c) 2013 Jon Lund Steffensen + Copyright (c) 2014 Mattias Andrée */ #ifdef HAVE_CONFIG_H @@ -198,34 +199,6 @@ static const location_provider_t location_providers[] = { { NULL } }; -/* Bounds for parameters. */ -#define MIN_LAT -90.0 -#define MAX_LAT 90.0 -#define MIN_LON -180.0 -#define MAX_LON 180.0 -#define MIN_TEMP 1000 -#define MAX_TEMP 25000 -#define MIN_BRIGHTNESS 0.1 -#define MAX_BRIGHTNESS 1.0 -#define MIN_GAMMA 0.1 -#define MAX_GAMMA 10.0 - -/* Default values for parameters. */ -#define DEFAULT_DAY_TEMP 5500 -#define DEFAULT_NIGHT_TEMP 3500 -#define DEFAULT_BRIGHTNESS 1.0 -#define DEFAULT_GAMMA 1.0 - -/* The color temperature when no adjustment is applied. */ -#define NEUTRAL_TEMP 6500 - -/* Angular elevation of the sun at which the color temperature - transition period starts and ends (in degress). - Transition during twilight, and while the sun is lower than - 3.0 degrees above the horizon. */ -#define TRANSITION_LOW SOLAR_CIVIL_TWILIGHT_ELEV -#define TRANSITION_HIGH 3.0 - /* Program modes. */ typedef enum { PROGRAM_MODE_CONTINUAL, @@ -493,7 +466,8 @@ provider_try_start(const location_provider_t *provider, static int method_try_start(const gamma_method_t *method, gamma_state_t *state, - config_ini_state_t *config, char *args) + config_ini_state_t *config, char *args, + char *gamma) { int r; @@ -504,28 +478,46 @@ method_try_start(const gamma_method_t *method, return -1; } + /* Set default gamma. */ + if (gamma != NULL) { + r = method->set_option(state, "gamma", gamma, -1); + free(gamma); + if (r < 0) { + method->free(state); + return -1; + } + } + /* Set method options from config file. */ - config_ini_section_t *section = - config_ini_get_section(config, method->name); - if (section != NULL) { - config_ini_setting_t *setting = section->settings; - while (setting != NULL) { - r = method->set_option(state, setting->name, - setting->value); - if (r < 0) { - method->free(state); - fprintf(stderr, _("Failed to set %s" - " option.\n"), - method->name); - /* TRANSLATORS: `help' must not be - translated. */ - fprintf(stderr, _("Try `-m %s:help' for more" - " information.\n"), - method->name); - return -1; + config_ini_section_t **sections = + config_ini_get_sections(config, method->name); + if (sections != NULL) { + int section_i = 0; + while (sections[section_i] != NULL) { + config_ini_setting_t *setting = sections[section_i]->settings; + while (setting != NULL) { + r = method->set_option(state, setting->name, + setting->value, section_i); + if (r < 0) { + method->free(state); + fprintf(stderr, _("Failed to set %s" + " option.\n"), + method->name); + /* TRANSLATORS: `help' must not be + translated. */ + fprintf(stderr, _("Try `-m %s:help' for more" + " information.\n"), + method->name); + return -1; + } + setting = setting->next; } - setting = setting->next; + section_i++; } + free(sections); + } else { + method->free(state); + return -1; } /* Set method options from command line. */ @@ -543,7 +535,7 @@ method_try_start(const gamma_method_t *method, *(value++) = '\0'; } - r = method->set_option(state, key, value); + r = method->set_option(state, key, value, -1); if (r < 0) { method->free(state); fprintf(stderr, _("Failed to set %s option.\n"), @@ -571,7 +563,7 @@ method_try_start(const gamma_method_t *method, /* A gamma string contains either one floating point value, or three values separated by colon. */ -static int +int parse_gamma_string(const char *str, float gamma[]) { char *s = strchr(str, ':'); @@ -663,7 +655,7 @@ main(int argc, char *argv[]) int temp_set = -1; int temp_day = -1; int temp_night = -1; - float gamma[3] = { NAN, NAN, NAN }; + char *gamma = NULL; float brightness_day = NAN; float brightness_night = NAN; @@ -687,6 +679,7 @@ main(int argc, char *argv[]) /* Parse command line arguments. */ int opt; while ((opt = getopt(argc, argv, "b:c:g:hl:m:oO:prt:vVx")) != -1) { + float _gamma[3]; switch (opt) { case 'b': parse_brightness_string(optarg, &brightness_day, &brightness_night); @@ -696,7 +689,8 @@ main(int argc, char *argv[]) config_filepath = strdup(optarg); break; case 'g': - r = parse_gamma_string(optarg, gamma); + gamma = strdup(optarg); + r = parse_gamma_string(optarg, _gamma); if (r < 0) { fputs(_("Malformed gamma argument.\n"), stderr); @@ -876,15 +870,8 @@ main(int argc, char *argv[]) brightness_night = atof(setting->value); } } else if (strcasecmp(setting->name, "gamma") == 0) { - if (isnan(gamma[0])) { - r = parse_gamma_string(setting->value, - gamma); - if (r < 0) { - fputs(_("Malformed gamma" - " setting.\n"), - stderr); - exit(EXIT_FAILURE); - } + if (gamma == NULL) { + gamma = strdup(setting->value); } } else if (strcasecmp(setting->name, "adjustment-method") == 0) { @@ -929,7 +916,6 @@ main(int argc, char *argv[]) if (temp_night < 0) temp_night = DEFAULT_NIGHT_TEMP; if (isnan(brightness_day)) brightness_day = DEFAULT_BRIGHTNESS; if (isnan(brightness_night)) brightness_night = DEFAULT_BRIGHTNESS; - if (isnan(gamma[0])) gamma[0] = gamma[1] = gamma[2] = DEFAULT_GAMMA; if (transition < 0) transition = 1; float lat = NAN; @@ -1056,20 +1042,10 @@ main(int argc, char *argv[]) printf(_("Brightness: %.2f:%.2f\n"), brightness_day, brightness_night); } - /* Gamma */ - if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || - gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || - gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { - fprintf(stderr, - _("Gamma value must be between %.1f and %.1f.\n"), - MIN_GAMMA, MAX_GAMMA); - exit(EXIT_FAILURE); - } - - if (verbose) { + /*if (verbose) { TODO gamma is now set on outputs individually printf(_("Gamma: %.3f, %.3f, %.3f\n"), gamma[0], gamma[1], gamma[2]); - } + }*/ /* Initialize gamma adjustment method. If method is NULL try all methods until one that works is found. */ @@ -1080,15 +1056,18 @@ main(int argc, char *argv[]) if (method != NULL) { /* Use method specified on command line. */ r = method_try_start(method, &state, &config_state, - method_args); - if (r < 0) exit(EXIT_FAILURE); + method_args, gamma); + if (r < 0) { + config_ini_free(&config_state); + exit(EXIT_FAILURE); + } } else { /* Try all methods, use the first that works. */ for (int i = 0; gamma_methods[i].name != NULL; i++) { const gamma_method_t *m = &gamma_methods[i]; if (!m->autostart) continue; - r = method_try_start(m, &state, &config_state, NULL); + r = method_try_start(m, &state, &config_state, NULL, gamma); if (r < 0) { fputs(_("Trying next method...\n"), stderr); continue; @@ -1147,7 +1126,7 @@ main(int argc, char *argv[]) } /* Adjust temperature */ - r = method->set_temperature(&state, temp, brightness, gamma); + r = method->set_temperature(&state, temp, brightness); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1160,7 +1139,7 @@ main(int argc, char *argv[]) if (verbose) printf(_("Color temperature: %uK\n"), temp_set); /* Adjust temperature */ - r = method->set_temperature(&state, temp_set, brightness_day, gamma); + r = method->set_temperature(&state, temp_set, brightness_day); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1172,7 +1151,7 @@ main(int argc, char *argv[]) case PROGRAM_MODE_RESET: { /* Reset screen */ - r = method->set_temperature(&state, NEUTRAL_TEMP, 1.0, gamma); + r = method->set_temperature(&state, NEUTRAL_TEMP, 1.0); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1353,8 +1332,7 @@ main(int argc, char *argv[]) /* Adjust temperature */ if (!disabled || short_trans) { r = method->set_temperature(&state, - temp, brightness, - gamma); + temp, brightness); if (r < 0) { fputs(_("Temperature adjustment" " failed.\n"), stderr); diff --git a/src/redshift.h b/src/redshift.h index 3a878777..27f868c9 100644 --- a/src/redshift.h +++ b/src/redshift.h @@ -24,17 +24,45 @@ #include +/* Bounds for parameters. */ +#define MIN_LAT -90.0 +#define MAX_LAT 90.0 +#define MIN_LON -180.0 +#define MAX_LON 180.0 +#define MIN_TEMP 1000 +#define MAX_TEMP 25000 +#define MIN_BRIGHTNESS 0.1 +#define MAX_BRIGHTNESS 1.0 +#define MIN_GAMMA 0.1 +#define MAX_GAMMA 10.0 + +/* Default values for parameters. */ +#define DEFAULT_DAY_TEMP 5500 +#define DEFAULT_NIGHT_TEMP 3500 +#define DEFAULT_BRIGHTNESS 1.0 +#define DEFAULT_GAMMA 1.0 + +/* The color temperature when no adjustment is applied. */ +#define NEUTRAL_TEMP 6500 + +/* Angular elevation of the sun at which the color temperature + transition period starts and ends (in degress). + Transition during twilight, and while the sun is lower than + 3.0 degrees above the horizon. */ +#define TRANSITION_LOW SOLAR_CIVIL_TWILIGHT_ELEV +#define TRANSITION_HIGH 3.0 + + /* Gamma adjustment method */ typedef int gamma_method_init_func(void *state); typedef int gamma_method_start_func(void *state); typedef void gamma_method_free_func(void *state); typedef void gamma_method_print_help_func(FILE *f); typedef int gamma_method_set_option_func(void *state, const char *key, - const char *value); + const char *value, int section); typedef void gamma_method_restore_func(void *state); typedef int gamma_method_set_temperature_func(void *state, int temp, - float brightness, - const float gamma[3]); + float brightness); typedef struct { char *name; @@ -91,4 +119,8 @@ typedef struct { } location_provider_t; +int +parse_gamma_string(const char *str, float gamma[]); + + #endif /* ! REDSHIFT_REDSHIFT_H */ From ef48fcacb376a5211f3a4b337cf320d054d29103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:16:35 +0100 Subject: [PATCH 04/11] =?UTF-8?q?Multi-monitor=E2=80=93multi-screen=20supp?= =?UTF-8?q?ort=20in=20gamma-dummy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-dummy.c | 31 ++++++++++++++++++++++++++----- src/gamma-dummy.h | 5 ++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/gamma-dummy.c b/src/gamma-dummy.c index 0ebb12d1..9c77ecfa 100644 --- a/src/gamma-dummy.c +++ b/src/gamma-dummy.c @@ -19,6 +19,7 @@ #include #include +#include #ifdef ENABLE_NLS # include @@ -27,6 +28,8 @@ # define _(s) s #endif +#include "redshift.h" + int gamma_dummy_init(void *state) @@ -59,15 +62,33 @@ gamma_dummy_print_help(FILE *f) } int -gamma_dummy_set_option(void *state, const char *key, const char *value) +gamma_dummy_set_option(void *state, const char *key, const char *value, int section) { - fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); - return -1; + if (strcasecmp(key, "gamma") == 0) { + float gamma[3]; + if (parse_gamma_string(value, gamma) < 0) { + fputs(_("Malformed gamma setting.\n"), + stderr); + return -1; + } + if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || + gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || + gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { + fprintf(stderr, + _("Gamma value must be between %.1f and %.1f.\n"), + MIN_GAMMA, MAX_GAMMA); + return -1; + } + } else { + fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); + return -1; + } + + return 0; } int -gamma_dummy_set_temperature(void *state, int temp, float brightness, - const float gamma[3]) +gamma_dummy_set_temperature(void *state, int temp, float brightness) { printf(_("Temperature: %i\n"), temp); return 0; diff --git a/src/gamma-dummy.h b/src/gamma-dummy.h index 64bc40d8..8270e7de 100644 --- a/src/gamma-dummy.h +++ b/src/gamma-dummy.h @@ -28,11 +28,10 @@ int gamma_dummy_start(void *state); void gamma_dummy_free(void *state); void gamma_dummy_print_help(FILE *f); -int gamma_dummy_set_option(void *state, const char *key, const char *value); +int gamma_dummy_set_option(void *state, const char *key, const char *value, int section); void gamma_dummy_restore(void *state); -int gamma_dummy_set_temperature(void *state, int temp, float brightness, - const float gamma[3]); +int gamma_dummy_set_temperature(void *state, int temp, float brightness); #endif /* ! REDSHIFT_GAMMA_DUMMY_H */ From 14389fcbe658475976b6915b8d17ea8b9d2f9556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:19:16 +0100 Subject: [PATCH 05/11] =?UTF-8?q?Multi-monitor=E2=80=93multi-screen=20supp?= =?UTF-8?q?ort=20in=20gamma-randr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-randr.c | 411 ++++++++++++++++++++++++++++++++-------------- src/gamma-randr.h | 23 ++- 2 files changed, 302 insertions(+), 132 deletions(-) diff --git a/src/gamma-randr.c b/src/gamma-randr.c index 9e528b5d..a5b01ba6 100644 --- a/src/gamma-randr.c +++ b/src/gamma-randr.c @@ -15,6 +15,7 @@ along with Redshift. If not, see . Copyright (c) 2010 Jon Lund Steffensen + Copyright (c) 2014 Mattias Andrée */ #include @@ -34,6 +35,7 @@ #include "gamma-randr.h" #include "colorramp.h" +#include "redshift.h" #define RANDR_VERSION_MAJOR 1 @@ -43,11 +45,15 @@ int randr_init(randr_state_t *state) { - /* Initialize state. */ - state->screen_num = -1; - state->crtc_num = -1; - - state->crtc_count = 0; + /* Initialize state */ + state->conn = NULL; + state->selection_count = 0; + state->selections = malloc(1 * sizeof(randr_selection_t)); + if (state->selections == NULL) { + perror("malloc"); + return -1; + } + state->crtcs_used = 0; state->crtcs = NULL; xcb_generic_error_t *error; @@ -83,6 +89,13 @@ randr_init(randr_state_t *state) free(ver_reply); + /* Default selection */ + state->selections->screen_num = -1; + state->selections->crtc_num = -1; + state->selections->gamma[0] = DEFAULT_GAMMA; + state->selections->gamma[1] = DEFAULT_GAMMA; + state->selections->gamma[2] = DEFAULT_GAMMA; + return 0; } @@ -91,71 +104,167 @@ randr_start(randr_state_t *state) { xcb_generic_error_t *error; - int screen_num = state->screen_num; - if (screen_num < 0) screen_num = state->preferred_screen; - - /* Get screen */ + /* Get screens */ const xcb_setup_t *setup = xcb_get_setup(state->conn); + int screen_count = xcb_setup_roots_length(setup); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); - state->screen = NULL; + xcb_screen_t **screens = alloca(screen_count * sizeof(xcb_screen_t*)); - for (int i = 0; iter.rem > 0; i++) { - if (i == screen_num) { - state->screen = iter.data; - break; - } + for (int i = 0; i < screen_count; i++) { + screens[i] = iter.data; xcb_screen_next(&iter); } - if (state->screen == NULL) { - fprintf(stderr, _("Screen %i could not be found.\n"), - screen_num); - return -1; + /* Use default selection if no other selection is made */ + if (state->selection_count == 0) { + /* Select preferred screen if CRTC is selected but not a screen */ + if (state->selections->crtc_num != -1) + if (state->selections->screen_num == -1) + state->selections->screen_num = state->preferred_screen; + + /* Select CRTCs */ + if (state->selections->screen_num != -1) { + state->selections = realloc(state->selections, 2 * sizeof(randr_selection_t)); + state->selection_count = 1; + if (state->selections != NULL) + state->selections[1] = state->selections[0]; + } else { + state->selections = realloc(state->selections, + (screen_count + 1) * sizeof(randr_selection_t)); + state->selection_count = screen_count; + if (state->selections != NULL) { + int i; + for (i = 1; i <= screen_count; i++) { + state->selections[i] = *(state->selections); + state->selections[i].screen_num = i - 1; + } + } + } + if (state->selections == NULL) { + perror("realloc"); + return -1; + } } - /* Get list of CRTCs for the screen */ - xcb_randr_get_screen_resources_current_cookie_t res_cookie = - xcb_randr_get_screen_resources_current(state->conn, - state->screen->root); - xcb_randr_get_screen_resources_current_reply_t *res_reply = - xcb_randr_get_screen_resources_current_reply(state->conn, - res_cookie, - &error); + /* Prepare storage screen information */ + xcb_randr_get_screen_resources_current_reply_t **screen_reses = + alloca(screen_count * sizeof(xcb_randr_get_screen_resources_current_reply_t*)); + for (int i = 0; i < screen_count; i++) + screen_reses[i] = NULL; + + /* Load implied screens and CRTCs and screen information and verify indices */ + int selection_index; + for (selection_index = 1; selection_index <= state->selection_count; selection_index++) { + randr_selection_t *selection = state->selections + selection_index; + int screen_num = selection->screen_num; + + /* Verify screen index */ + if (screen_num >= screen_count) { + fprintf(stderr, _("Screen %d does not exist. "), + screen_num); + if (screen_count > 1) { + fprintf(stderr, _("Valid screens are [0-%d].\n"), + screen_count - 1); + } else { + fprintf(stderr, _("Only screen 0 exists.\n")); + } + fprintf(stderr, "Invalid screen.\n"); + goto fail; + } - if (error) { - fprintf(stderr, _("`%s' returned error %d\n"), - "RANDR Get Screen Resources Current", - error->error_code); - return -1; + /* Load screen information if not already loaded */ + if (screen_reses[screen_num] == NULL) { + /* Get list of CRTCs for the screens */ + xcb_randr_get_screen_resources_current_cookie_t res_cookie = + xcb_randr_get_screen_resources_current(state->conn, + screens[screen_num]->root); + xcb_randr_get_screen_resources_current_reply_t *res_reply = + xcb_randr_get_screen_resources_current_reply(state->conn, + res_cookie, + &error); + screen_reses[screen_num] = res_reply; + + if (error) { + fprintf(stderr, _("`%s' returned error %d\n"), + "RANDR Get Screen Resources Current", + error->error_code); + goto fail; + } + } + + xcb_randr_get_screen_resources_current_reply_t* res = screen_reses[screen_num]; + int crtc_count = res->num_crtcs; + + if (selection->crtc_num == -1) { + /* Select all CRTCs. */ + if (crtc_count < 1) + continue; + int n = state->selection_count + crtc_count + 1; + state->selections = realloc(state->selections, n * sizeof(randr_selection_t)); + selection = state->selections + selection_index; + if (state->selections == NULL) { + perror("realloc"); + goto fail; + } + int crtc_i; + for (crtc_i = 0; crtc_i < crtc_count; crtc_i++) { + randr_selection_t *sel = state->selections + ++(state->selection_count); + *sel = state->selections[selection_index]; + sel->crtc_num = crtc_i; + } + *selection = state->selections[state->selection_count--]; + } + + /* Verify CRT index. */ + if (selection->crtc_num >= crtc_count) { + fprintf(stderr, _("CRTC %d does not exist. "), + selection->crtc_num); + if (crtc_count > 1) { + fprintf(stderr, _("Valid CRTCs are [0-%d].\n"), + crtc_count - 1); + } else { + fprintf(stderr, _("Only CRTC 0 exists.\n")); + } + fprintf(stderr, "Invalid CRTC.\n"); + goto fail; + } } - state->crtc_count = res_reply->num_crtcs; - state->crtcs = calloc(state->crtc_count, sizeof(randr_crtc_state_t)); + /* Allocate memory for CRTCs */ + state->crtcs = calloc(state->selection_count, sizeof(randr_crtc_state_t)); if (state->crtcs == NULL) { perror("malloc"); - state->crtc_count = 0; - return -1; + goto fail; } - xcb_randr_crtc_t *crtcs = - xcb_randr_get_screen_resources_current_crtcs(res_reply); + /* Load CRTC information and store gamma */ + int skipped = 0; + for (selection_index = 1; selection_index <= state->selection_count; selection_index++) { + randr_selection_t *selection = state->selections + selection_index - skipped; + if (selection->crtc_num < 0) { + skipped++; + continue; + } + xcb_randr_get_screen_resources_current_reply_t *res = screen_reses[selection->screen_num]; + xcb_randr_crtc_t *crtcs = + xcb_randr_get_screen_resources_current_crtcs(res); + randr_crtc_state_t *crtc = &state->crtcs[state->crtcs_used++]; - /* Save CRTC identifier in state */ - for (int i = 0; i < state->crtc_count; i++) { - state->crtcs[i].crtc = crtcs[i]; - } + /* Store gamma correction from selection data */ + crtc->gamma[0] = selection->gamma[0]; + crtc->gamma[1] = selection->gamma[1]; + crtc->gamma[2] = selection->gamma[2]; - free(res_reply); + /* Save CRTC identifier in state */ + crtc->crtc = crtcs[selection->crtc_num]; - /* Save size and gamma ramps of all CRTCs. - Current gamma ramps are saved so we can restore them - at program exit. */ - for (int i = 0; i < state->crtc_count; i++) { - xcb_randr_crtc_t crtc = state->crtcs[i].crtc; + /* Save size and gamma ramps of all CRTCs. + Current gamma ramps are saved so we can restore them + at program exit. */ /* Request size of gamma ramps */ xcb_randr_get_crtc_gamma_size_cookie_t gamma_size_cookie = - xcb_randr_get_crtc_gamma_size(state->conn, crtc); + xcb_randr_get_crtc_gamma_size(state->conn, crtc->crtc); xcb_randr_get_crtc_gamma_size_reply_t *gamma_size_reply = xcb_randr_get_crtc_gamma_size_reply(state->conn, gamma_size_cookie, @@ -165,23 +274,23 @@ randr_start(randr_state_t *state) fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma Size", error->error_code); - return -1; + goto fail; } unsigned int ramp_size = gamma_size_reply->size; - state->crtcs[i].ramp_size = ramp_size; + crtc->ramp_size = ramp_size; free(gamma_size_reply); - if (ramp_size == 0) { + if (ramp_size <= 1) { fprintf(stderr, _("Gamma ramp size too small: %i\n"), ramp_size); - return -1; + goto fail; } /* Request current gamma ramps */ xcb_randr_get_crtc_gamma_cookie_t gamma_get_cookie = - xcb_randr_get_crtc_gamma(state->conn, crtc); + xcb_randr_get_crtc_gamma(state->conn, crtc->crtc); xcb_randr_get_crtc_gamma_reply_t *gamma_get_reply = xcb_randr_get_crtc_gamma_reply(state->conn, gamma_get_cookie, @@ -190,7 +299,7 @@ randr_start(randr_state_t *state) if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma", error->error_code); - return -1; + goto fail; } uint16_t *gamma_r = @@ -201,26 +310,54 @@ randr_start(randr_state_t *state) xcb_randr_get_crtc_gamma_blue(gamma_get_reply); /* Allocate space for saved gamma ramps */ - state->crtcs[i].saved_ramps = - malloc(3*ramp_size*sizeof(uint16_t)); - if (state->crtcs[i].saved_ramps == NULL) { + crtc->saved_ramps = malloc(3*ramp_size*sizeof(uint16_t)); + if (crtc->saved_ramps == NULL) { perror("malloc"); free(gamma_get_reply); - return -1; + goto fail; } /* Copy gamma ramps into CRTC state */ - memcpy(&state->crtcs[i].saved_ramps[0*ramp_size], gamma_r, + memcpy(&crtc->saved_ramps[0*ramp_size], gamma_r, ramp_size*sizeof(uint16_t)); - memcpy(&state->crtcs[i].saved_ramps[1*ramp_size], gamma_g, + memcpy(&crtc->saved_ramps[1*ramp_size], gamma_g, ramp_size*sizeof(uint16_t)); - memcpy(&state->crtcs[i].saved_ramps[2*ramp_size], gamma_b, + memcpy(&crtc->saved_ramps[2*ramp_size], gamma_b, ramp_size*sizeof(uint16_t)); free(gamma_get_reply); + + /* Allocate space for gamma ramps */ + uint16_t *gamma_ramps = malloc(3*ramp_size*sizeof(uint16_t)); + if (gamma_ramps == NULL) { + perror("malloc"); + goto fail; + } + + crtc->gamma_r = &gamma_ramps[0*ramp_size]; + crtc->gamma_g = &gamma_ramps[1*ramp_size]; + crtc->gamma_b = &gamma_ramps[2*ramp_size]; } + /* Release screen resources */ + for (int i = 0; i < screen_count; i++) + if (screen_reses[i] != NULL) + free(screen_reses[i]); + + /* We do not longer need raw selection information, free it */ + free(state->selections); + state->selections = NULL; + + state->selection_count -= skipped; return 0; + +fail: + /* Release screen resources */ + for (int i = 0; i < screen_count; i++) + if (screen_reses[i] != NULL) + free(screen_reses[i]); + + return -1; } void @@ -229,17 +366,17 @@ randr_restore(randr_state_t *state) xcb_generic_error_t *error; /* Restore CRTC gamma ramps */ - for (int i = 0; i < state->crtc_count; i++) { - xcb_randr_crtc_t crtc = state->crtcs[i].crtc; + for (int i = 0; i < state->crtcs_used; i++) { + randr_crtc_state_t* crtc = &state->crtcs[i]; - unsigned int ramp_size = state->crtcs[i].ramp_size; - uint16_t *gamma_r = &state->crtcs[i].saved_ramps[0*ramp_size]; - uint16_t *gamma_g = &state->crtcs[i].saved_ramps[1*ramp_size]; - uint16_t *gamma_b = &state->crtcs[i].saved_ramps[2*ramp_size]; + unsigned int ramp_size = crtc->ramp_size; + uint16_t *gamma_r = &crtc->saved_ramps[0*ramp_size]; + uint16_t *gamma_g = &crtc->saved_ramps[1*ramp_size]; + uint16_t *gamma_b = &crtc->saved_ramps[2*ramp_size]; /* Set gamma ramps */ xcb_void_cookie_t gamma_set_cookie = - xcb_randr_set_crtc_gamma_checked(state->conn, crtc, + xcb_randr_set_crtc_gamma_checked(state->conn, crtc->crtc, ramp_size, gamma_r, gamma_g, gamma_b); error = xcb_request_check(state->conn, gamma_set_cookie); @@ -255,14 +392,31 @@ randr_restore(randr_state_t *state) void randr_free(randr_state_t *state) { - /* Free CRTC state */ - for (int i = 0; i < state->crtc_count; i++) { - free(state->crtcs[i].saved_ramps); + /* Free saved gamma ramps */ + for (int i = 0; i < state->crtcs_used; i++) { + if (state->crtcs[i].saved_ramps != NULL) + free(state->crtcs[i].saved_ramps); + if (state->crtcs[i].gamma_r != NULL) + free(state->crtcs[i].gamma_r); + } + + /* Free CRTC states */ + if (state->crtcs != NULL) { + free(state->crtcs); + state->crtcs = NULL; } - free(state->crtcs); /* Close connection */ - xcb_disconnect(state->conn); + if (state->conn != NULL) { + xcb_disconnect(state->conn); + state->conn = NULL; + } + + /* Free raw selection information */ + if (state->selections != NULL) { + free(state->selections); + state->selections = NULL; + } } void @@ -279,12 +433,54 @@ randr_print_help(FILE *f) } int -randr_set_option(randr_state_t *state, const char *key, const char *value) +randr_set_option(randr_state_t *state, const char *key, const char *value, int section) { + if (section == state->selection_count) { + state->selections = realloc(state->selections, + (++(state->selection_count) + 1) * sizeof(randr_selection_t)); + + if (state->selections == NULL) { + perror("realloc"); + return -1; + } + + state->selections[section + 1] = *(state->selections); + state->selections[section + 1].screen_num = state->preferred_screen; + state->selections[section + 1].crtc_num = 0; + } + if (strcasecmp(key, "screen") == 0) { - state->screen_num = atoi(value); + int screen_num = atoi(value); + state->selections[section + 1].screen_num = screen_num; + if (screen_num < 0) { + fprintf(stderr, _("Screen must be a non-negative integer.\n")); + return -1; + } } else if (strcasecmp(key, "crtc") == 0) { - state->crtc_num = atoi(value); + int crtc_num = atoi(value); + state->selections[section + 1].crtc_num = crtc_num; + if (crtc_num < 0) { + fprintf(stderr, _("CRTC must be a non-negative integer.\n")); + return -1; + } + } else if (strcasecmp(key, "gamma") == 0) { + float gamma[3]; + if (parse_gamma_string(value, gamma) < 0) { + fputs(_("Malformed gamma setting.\n"), + stderr); + return -1; + } + if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || + gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || + gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { + fprintf(stderr, + _("Gamma value must be between %.1f and %.1f.\n"), + MIN_GAMMA, MAX_GAMMA); + return -1; + } + state->selections[section + 1].gamma[0] = gamma[0]; + state->selections[section + 1].gamma[1] = gamma[1]; + state->selections[section + 1].gamma[2] = gamma[2]; } else { fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); return -1; @@ -295,77 +491,42 @@ randr_set_option(randr_state_t *state, const char *key, const char *value) static int randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, int temp, - float brightness, const float gamma[3]) + float brightness) { + randr_crtc_state_t *crtc = &state->crtcs[crtc_num]; xcb_generic_error_t *error; - - if (crtc_num >= state->crtc_count || crtc_num < 0) { - fprintf(stderr, _("CRTC %d does not exist. "), - state->crtc_num); - if (state->crtc_count > 1) { - fprintf(stderr, _("Valid CRTCs are [0-%d].\n"), - state->crtc_count-1); - } else { - fprintf(stderr, _("Only CRTC 0 exists.\n")); - } - - return -1; - } - xcb_randr_crtc_t crtc = state->crtcs[crtc_num].crtc; - unsigned int ramp_size = state->crtcs[crtc_num].ramp_size; + unsigned int ramp_size = crtc->ramp_size; /* Create new gamma ramps */ - uint16_t *gamma_ramps = malloc(3*ramp_size*sizeof(uint16_t)); - if (gamma_ramps == NULL) { - perror("malloc"); - return -1; - } - - uint16_t *gamma_r = &gamma_ramps[0*ramp_size]; - uint16_t *gamma_g = &gamma_ramps[1*ramp_size]; - uint16_t *gamma_b = &gamma_ramps[2*ramp_size]; - - colorramp_fill(gamma_r, gamma_g, gamma_b, ramp_size, - temp, brightness, gamma); + colorramp_fill(crtc->gamma_r, crtc->gamma_g, crtc->gamma_b, + ramp_size, temp, brightness, crtc->gamma); /* Set new gamma ramps */ xcb_void_cookie_t gamma_set_cookie = - xcb_randr_set_crtc_gamma_checked(state->conn, crtc, - ramp_size, gamma_r, - gamma_g, gamma_b); + xcb_randr_set_crtc_gamma_checked(state->conn, crtc->crtc, + ramp_size, crtc->gamma_r, + crtc->gamma_g, crtc->gamma_b); error = xcb_request_check(state->conn, gamma_set_cookie); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Set CRTC Gamma", error->error_code); - free(gamma_ramps); return -1; } - free(gamma_ramps); - return 0; } int -randr_set_temperature(randr_state_t *state, int temp, float brightness, - const float gamma[3]) +randr_set_temperature(randr_state_t *state, int temp, float brightness) { int r; - /* If no CRTC number has been specified, - set temperature on all CRTCs. */ - if (state->crtc_num < 0) { - for (int i = 0; i < state->crtc_count; i++) { - r = randr_set_temperature_for_crtc(state, i, - temp, brightness, - gamma); - if (r < 0) return -1; - } - } else { - return randr_set_temperature_for_crtc(state, state->crtc_num, - temp, brightness, gamma); + for (int i = 0; i < state->crtcs_used; i++) { + r = randr_set_temperature_for_crtc(state, i, + temp, brightness); + if (r < 0) return -1; } return 0; diff --git a/src/gamma-randr.h b/src/gamma-randr.h index cef0021e..c9cebdd4 100644 --- a/src/gamma-randr.h +++ b/src/gamma-randr.h @@ -33,15 +33,24 @@ typedef struct { xcb_randr_crtc_t crtc; unsigned int ramp_size; uint16_t *saved_ramps; + float gamma[3]; + uint16_t *gamma_r; + uint16_t *gamma_g; + uint16_t *gamma_b; } randr_crtc_state_t; typedef struct { - xcb_connection_t *conn; - xcb_screen_t *screen; - int preferred_screen; int screen_num; int crtc_num; - unsigned int crtc_count; + float gamma[3]; +} randr_selection_t; + +typedef struct { + xcb_connection_t *conn; + int selection_count; + randr_selection_t *selections; + int preferred_screen; + int crtcs_used; randr_crtc_state_t *crtcs; } randr_state_t; @@ -51,11 +60,11 @@ int randr_start(randr_state_t *state); void randr_free(randr_state_t *state); void randr_print_help(FILE *f); -int randr_set_option(randr_state_t *state, const char *key, const char *value); +int randr_set_option(randr_state_t *state, const char *key, + const char *value, int section); void randr_restore(randr_state_t *state); -int randr_set_temperature(randr_state_t *state, int temp, float brightness, - const float gamma[3]); +int randr_set_temperature(randr_state_t *state, int temp, float brightness); #endif /* ! REDSHIFT_GAMMA_RANDR_H */ From bf7beffc1e9010e765ce3c07d79c4fde4c3785c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:20:12 +0100 Subject: [PATCH 06/11] =?UTF-8?q?Multi-monitor=E2=80=93multi-screen=20supp?= =?UTF-8?q?ort=20in=20gamma-vidmode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-vidmode.c | 315 ++++++++++++++++++++++++++++++++------------ src/gamma-vidmode.h | 24 +++- 2 files changed, 251 insertions(+), 88 deletions(-) diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c index 656ce007..06d73f74 100644 --- a/src/gamma-vidmode.c +++ b/src/gamma-vidmode.c @@ -15,6 +15,7 @@ along with Redshift. If not, see . Copyright (c) 2010 Jon Lund Steffensen + Copyright (c) 2014 Mattias Andrée */ #include @@ -34,19 +35,41 @@ #include "gamma-vidmode.h" #include "colorramp.h" +#include "redshift.h" int vidmode_init(vidmode_state_t *state) { - state->screen_num = -1; - state->saved_ramps = NULL; + state->selection_count = 0; + state->selections = malloc(1 * sizeof(vidmode_selection_t)); + if (state->selections == NULL) { + perror("malloc"); + return -1; + } + state->selections->screen_num = -1; + state->selections->gamma[0] = DEFAULT_GAMMA; + state->selections->gamma[1] = DEFAULT_GAMMA; + state->selections->gamma[2] = DEFAULT_GAMMA; + state->screens_used = 0; + state->screens = NULL; /* Open display */ state->display = XOpenDisplay(NULL); if (state->display == NULL) { fprintf(stderr, _("X request failed: %s\n"), "XOpenDisplay"); + free(state->selections); + state->selections = NULL; + return -1; + } + + state->screen_count = ScreenCount(state->display); + if (state->screen_count < 1) { + fprintf(stderr, _("X request failed: %s\n"), + "ScreenCount"); + free(state->selections); + state->selections = NULL; return -1; } @@ -57,10 +80,6 @@ int vidmode_start(vidmode_state_t *state) { int r; - int screen_num = state->screen_num; - - if (screen_num < 0) screen_num = DefaultScreen(state->display); - state->screen_num = screen_num; /* Query extension version */ int major, minor; @@ -71,40 +90,105 @@ vidmode_start(vidmode_state_t *state) return -1; } - /* Request size of gamma ramps */ - r = XF86VidModeGetGammaRampSize(state->display, state->screen_num, - &state->ramp_size); - if (!r) { - fprintf(stderr, _("X request failed: %s\n"), - "XF86VidModeGetGammaRampSize"); - return -1; - } - - if (state->ramp_size == 0) { - fprintf(stderr, _("Gamma ramp size too small: %i\n"), - state->ramp_size); - return -1; - } - - /* Allocate space for saved gamma ramps */ - state->saved_ramps = malloc(3*state->ramp_size*sizeof(uint16_t)); - if (state->saved_ramps == NULL) { - perror("malloc"); - return -1; + /* Use default selection if no other selection is made. */ + if (state->selection_count == 0) { + /* Select screens. */ + if (state->selections->screen_num != -1) { + state->selections = realloc(state->selections, 2 * sizeof(vidmode_selection_t)); + state->selection_count = 1; + if (state->selections != NULL) + state->selections[1] = state->selections[0]; + } else { + state->selections = realloc(state->selections, + (state->screen_count + 1) * sizeof(vidmode_selection_t)); + state->selection_count = state->screen_count; + if (state->selections != NULL) { + int i; + for (i = 1; i <= state->screen_count; i++) { + state->selections[i] = *(state->selections); + state->selections[i].screen_num = i - 1; + } + } + } + if (state->selections == NULL) { + perror("realloc"); + return -1; + } } - uint16_t *gamma_r = &state->saved_ramps[0*state->ramp_size]; - uint16_t *gamma_g = &state->saved_ramps[1*state->ramp_size]; - uint16_t *gamma_b = &state->saved_ramps[2*state->ramp_size]; - - /* Save current gamma ramps so we can restore them at program exit. */ - r = XF86VidModeGetGammaRamp(state->display, state->screen_num, - state->ramp_size, gamma_r, gamma_g, - gamma_b); - if (!r) { - fprintf(stderr, _("X request failed: %s\n"), - "XF86VidModeGetGammaRamp"); - return -1; + int selection_index; + for (selection_index = 1; selection_index <= state->selection_count; selection_index++) { + vidmode_selection_t *selection = state->selections + selection_index; + + /* Prepare for adding another screen */ + if (state->screens_used++ == 0) + state->screens = malloc(1 * sizeof(vidmode_screen_state_t)); + else + state->screens = realloc(state->screens, + state->screens_used * sizeof(vidmode_screen_state_t)); + if (state->screens == NULL) { + perror(state->screens_used == 1 ? "malloc" : "realloc"); + return -1; + } + + /* Create entry for other selected CRTC */ + vidmode_screen_state_t *screen = state->screens + state->screens_used - 1; + screen->screen_num = selection->screen_num; + screen->ramp_size = -1; + screen->saved_ramps = NULL; + screen->gamma[0] = selection->gamma[0]; + screen->gamma[1] = selection->gamma[1]; + screen->gamma[2] = selection->gamma[2]; + screen->gamma_r = NULL; + screen->gamma_g = NULL; + screen->gamma_b = NULL; + + /* Request size of gamma ramps */ + r = XF86VidModeGetGammaRampSize(state->display, screen->screen_num, + &screen->ramp_size); + if (!r) { + fprintf(stderr, _("X request failed: %s\n"), + "XF86VidModeGetGammaRampSize"); + return -1; + } + + if (screen->ramp_size <= 1) { + fprintf(stderr, _("Gamma ramp size too small: %i\n"), + screen->ramp_size); + return -1; + } + + /* Allocate space for saved gamma ramps */ + screen->saved_ramps = malloc(3*screen->ramp_size*sizeof(uint16_t)); + if (screen->saved_ramps == NULL) { + perror("malloc"); + return -1; + } + + uint16_t *gamma_r = &screen->saved_ramps[0*screen->ramp_size]; + uint16_t *gamma_g = &screen->saved_ramps[1*screen->ramp_size]; + uint16_t *gamma_b = &screen->saved_ramps[2*screen->ramp_size]; + + /* Save current gamma ramps so we can restore them at program exit. */ + r = XF86VidModeGetGammaRamp(state->display, screen->screen_num, + screen->ramp_size, gamma_r, gamma_g, + gamma_b); + if (!r) { + fprintf(stderr, _("X request failed: %s\n"), + "XF86VidModeGetGammaRamp"); + return -1; + } + + /* Allocate space for gamma ramps */ + uint16_t *gamma_ramps = malloc(3*screen->ramp_size*sizeof(uint16_t)); + if (gamma_ramps == NULL) { + perror("malloc"); + return -1; + } + + screen->gamma_r = &gamma_ramps[0*screen->ramp_size]; + screen->gamma_g = &gamma_ramps[1*screen->ramp_size]; + screen->gamma_b = &gamma_ramps[2*screen->ramp_size]; } return 0; @@ -113,11 +197,31 @@ vidmode_start(vidmode_state_t *state) void vidmode_free(vidmode_state_t *state) { - /* Free saved ramps */ - free(state->saved_ramps); + /* Free ramps */ + for (int i = 0; i < state->screens_used; i++) { + if (state->screens[i].saved_ramps != NULL) + free(state->screens[i].saved_ramps); + if (state->screens[i].gamma_r != NULL) + free(state->screens[i].gamma_r); + } + + /* Free screen selections */ + if (state->screens != NULL) { + free(state->screens); + state->screens = NULL; + } + + /* Free raw selection information */ + if (state->selections != NULL) { + free(state->selections); + state->selections = NULL; + } /* Close display connection */ - XCloseDisplay(state->display); + if (state->display != NULL) { + XCloseDisplay(state->display); + state->display = NULL; + } } void @@ -133,10 +237,58 @@ vidmode_print_help(FILE *f) } int -vidmode_set_option(vidmode_state_t *state, const char *key, const char *value) +vidmode_set_option(vidmode_state_t *state, const char *key, const char *value, int section) { + if (section == state->selection_count) { + state->selections = realloc(state->selections, + (++(state->selection_count) + 1) * sizeof(vidmode_selection_t)); + + if (state->selections == NULL) { + perror("realloc"); + return -1; + } + + state->selections[section + 1] = *(state->selections); + state->selections[section + 1].screen_num = 0; + } + if (strcasecmp(key, "screen") == 0) { - state->screen_num = atoi(value); + int screen_num = atoi(value); + state->selections[section + 1].screen_num = screen_num; + if (screen_num < 0) { + fprintf(stderr, _("Screen must be a non-negative integer.\n")); + return -1; + } + if (screen_num >= state->screen_count) { + fprintf(stderr, _("Screen %d does not exist. "), + screen_num); + if (state->screen_count > 1) { + fprintf(stderr, _("Valid screens are [0-%d].\n"), + state->screen_count - 1); + } else { + fprintf(stderr, _("Only screen 0 exists.\n")); + } + fprintf(stderr, "Invalid screen.\n"); + return -1; + } + } else if (strcasecmp(key, "gamma") == 0) { + float gamma[3]; + if (parse_gamma_string(value, gamma) < 0) { + fputs(_("Malformed gamma setting.\n"), + stderr); + return -1; + } + if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || + gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || + gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { + fprintf(stderr, + _("Gamma value must be between %.1f and %.1f.\n"), + MIN_GAMMA, MAX_GAMMA); + return -1; + } + state->selections[section + 1].gamma[0] = gamma[0]; + state->selections[section + 1].gamma[1] = gamma[1]; + state->selections[section + 1].gamma[2] = gamma[2]; } else { fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); return -1; @@ -148,52 +300,47 @@ vidmode_set_option(vidmode_state_t *state, const char *key, const char *value) void vidmode_restore(vidmode_state_t *state) { - uint16_t *gamma_r = &state->saved_ramps[0*state->ramp_size]; - uint16_t *gamma_g = &state->saved_ramps[1*state->ramp_size]; - uint16_t *gamma_b = &state->saved_ramps[2*state->ramp_size]; - - /* Restore gamma ramps */ - int r = XF86VidModeSetGammaRamp(state->display, state->screen_num, - state->ramp_size, gamma_r, gamma_g, - gamma_b); - if (!r) { - fprintf(stderr, _("X request failed: %s\n"), - "XF86VidModeSetGammaRamp"); - } + int screen_index; + for (screen_index = 0; screen_index < state->screens_used; screen_index++) { + vidmode_screen_state_t *screen = state->screens + screen_index; + + uint16_t *gamma_r = &screen->saved_ramps[0*screen->ramp_size]; + uint16_t *gamma_g = &screen->saved_ramps[1*screen->ramp_size]; + uint16_t *gamma_b = &screen->saved_ramps[2*screen->ramp_size]; + + /* Restore gamma ramps */ + int r = XF86VidModeSetGammaRamp(state->display, screen->screen_num, + screen->ramp_size, gamma_r, gamma_g, + gamma_b); + if (!r) { + fprintf(stderr, _("X request failed: %s\n"), + "XF86VidModeSetGammaRamp"); + } + } } int -vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness, - const float gamma[3]) +vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness) { - int r; - - /* Create new gamma ramps */ - uint16_t *gamma_ramps = malloc(3*state->ramp_size*sizeof(uint16_t)); - if (gamma_ramps == NULL) { - perror("malloc"); - return -1; + int screen_index; + for (screen_index = 0; screen_index < state->screens_used; screen_index++) { + vidmode_screen_state_t *screen = state->screens + screen_index; + int r; + + /* Create new gamma ramps */ + colorramp_fill(screen->gamma_r, screen->gamma_g, screen->gamma_b, + screen->ramp_size, temp, brightness, screen->gamma); + + /* Set new gamma ramps */ + r = XF86VidModeSetGammaRamp(state->display, screen->screen_num, + screen->ramp_size, screen->gamma_r, + screen->gamma_g, screen->gamma_b); + if (!r) { + fprintf(stderr, _("X request failed: %s\n"), + "XF86VidModeSetGammaRamp"); + return -1; + } } - uint16_t *gamma_r = &gamma_ramps[0*state->ramp_size]; - uint16_t *gamma_g = &gamma_ramps[1*state->ramp_size]; - uint16_t *gamma_b = &gamma_ramps[2*state->ramp_size]; - - colorramp_fill(gamma_r, gamma_g, gamma_b, state->ramp_size, - temp, brightness, gamma); - - /* Set new gamma ramps */ - r = XF86VidModeSetGammaRamp(state->display, state->screen_num, - state->ramp_size, gamma_r, gamma_g, - gamma_b); - if (!r) { - fprintf(stderr, _("X request failed: %s\n"), - "XF86VidModeSetGammaRamp"); - free(gamma_ramps); - return -1; - } - - free(gamma_ramps); - return 0; } diff --git a/src/gamma-vidmode.h b/src/gamma-vidmode.h index 8afd8fd2..3c87b80d 100644 --- a/src/gamma-vidmode.h +++ b/src/gamma-vidmode.h @@ -26,10 +26,27 @@ #include typedef struct { - Display *display; int screen_num; int ramp_size; uint16_t *saved_ramps; + float gamma[3]; + uint16_t *gamma_r; + uint16_t *gamma_g; + uint16_t *gamma_b; +} vidmode_screen_state_t; + +typedef struct { + int screen_num; + float gamma[3]; +} vidmode_selection_t; + +typedef struct { + Display *display; + int selection_count; + vidmode_selection_t *selections; + int screen_count; + int screens_used; + vidmode_screen_state_t *screens; } vidmode_state_t; @@ -39,11 +56,10 @@ void vidmode_free(vidmode_state_t *state); void vidmode_print_help(FILE *f); int vidmode_set_option(vidmode_state_t *state, const char *key, - const char *value); + const char *value, int section); void vidmode_restore(vidmode_state_t *state); -int vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness, - const float gamma[3]); +int vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness); #endif /* ! REDSHIFT_GAMMA_VIDMODE_H */ From 7ee90c134a57d89c7644f33ce94467727a9a53b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:21:04 +0100 Subject: [PATCH 07/11] =?UTF-8?q?Multi-monitor=E2=80=93multi-screen=20supp?= =?UTF-8?q?ort=20in=20gamma-drm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-drm.c | 450 +++++++++++++++++++++++++++++++++--------------- src/gamma-drm.h | 32 +++- 2 files changed, 331 insertions(+), 151 deletions(-) diff --git a/src/gamma-drm.c b/src/gamma-drm.c index e784b471..4754460e 100644 --- a/src/gamma-drm.c +++ b/src/gamma-drm.c @@ -40,17 +40,65 @@ #include "gamma-drm.h" #include "colorramp.h" +#include "redshift.h" int drm_init(drm_state_t *state) { + /* Check if we are in a display */ + char* env; + int in_a_dislay = 0; + if ((env = getenv("DISPLAY")) != NULL) { + if (strchr(env, ':')) + in_a_dislay = 1; + } else if ((env = getenv("WAYLAND_DISPLAY")) != NULL) { + if (strstr(env, "wayland-") == env) + in_a_dislay = 1; + } + if (in_a_dislay) { + fprintf(stderr, _("You appear to be inside a graphical environment\n" + "adjustments made using the DRM method will only\n" + "be applied when in a TTY.\n")); + } + + /* Count number of graphics cards. */ + long maxlen = strlen(DRM_DIR_NAME) + strlen(DRM_DEV_NAME) + 10; + char *pathname = alloca(maxlen * sizeof(char)); + int card_count; + for (card_count = 0;; card_count++) { + struct stat _attr; + sprintf(pathname, DRM_DEV_NAME, DRM_DIR_NAME, card_count); + if (stat(pathname, &_attr)) + break; + } + /* Initialize state. */ - state->card_num = 0; - state->crtc_num = -1; - state->fd = -1; - state->res = NULL; - state->crtcs = NULL; + state->selection_count = 0; + state->selections = malloc(sizeof(drm_selection_t)); + if (state->selections == NULL) { + perror("malloc"); + return -1; + } + state->selections->card_num = -1; + state->selections->crtc_num = -1; + state->selections->gamma[0] = DEFAULT_GAMMA; + state->selections->gamma[1] = DEFAULT_GAMMA; + state->selections->gamma[2] = DEFAULT_GAMMA; + state->card_count = card_count; + state->cards = card_count ? malloc(card_count * sizeof(drm_crtc_state_t)) : NULL; + if (state->cards == NULL) { + if (card_count) perror("malloc"); + else fprintf(stderr, _("Could not find any graphics card using DRM\n")); + return -1; + } + int card_index; + for (card_index = 0; card_index < card_count; card_index++) { + state->cards[card_index].fd = -1; + state->cards[card_index].res = NULL; + state->cards[card_index].crtcs_used = 0; + state->cards[card_index].crtcs = NULL; + } return 0; } @@ -58,153 +106,235 @@ drm_init(drm_state_t *state) int drm_start(drm_state_t *state) { - /* Acquire access to a graphics card. */ + /* Use default selection if no other selection is made. */ + if (state->selection_count == 0) { + /* Select card 0 if CRTC is selected but not a card. */ + if (state->selections->crtc_num != -1) + if (state->selections->card_num == -1) + state->selections->card_num = 0; + + /* Select CRTCs. */ + if (state->selections->card_num != -1) { + state->selections = realloc(state->selections, 2 * sizeof(drm_selection_t)); + state->selection_count = 1; + if (state->selections != NULL) + state->selections[1] = state->selections[0]; + } else { + state->selections = realloc(state->selections, + (state->card_count + 1) * sizeof(drm_selection_t)); + state->selection_count = state->card_count; + if (state->selections != NULL) { + int i; + for (i = 1; i <= state->card_count; i++) { + state->selections[i] = *(state->selections); + state->selections[i].card_num = i - 1; + } + } + } + if (state->selections == NULL) { + perror("realloc"); + return -1; + } + } + + /* Apply selections. */ long maxlen = strlen(DRM_DIR_NAME) + strlen(DRM_DEV_NAME) + 10; char *pathname = alloca(maxlen * sizeof(char)); + int skipped = 0; + int selection_index; + for (selection_index = 1; selection_index <= state->selection_count; selection_index++) { + drm_selection_t *selection = state->selections + selection_index - skipped; + drm_card_state_t *card = state->cards + selection->card_num; - sprintf(pathname, DRM_DEV_NAME, DRM_DIR_NAME, state->card_num); + if (card->fd == -1) { + /* Acquire access to a graphics card. */ + sprintf(pathname, DRM_DEV_NAME, DRM_DIR_NAME, selection->card_num); + card->fd = open(pathname, O_RDWR | O_CLOEXEC); + if (card->fd < 0) { + /* TODO check access permissions, normally root or + membership of the video group is required. */ + perror("open"); + return -1; + } - state->fd = open(pathname, O_RDWR | O_CLOEXEC); - if (state->fd < 0) { - /* TODO check if access permissions, normally root or - membership of the video group is required. */ - perror("open"); - return -1; - } + /* Acquire mode resources. */ + card->res = drmModeGetResources(card->fd); + if (card->res == NULL) { + fprintf(stderr, _("Failed to get DRM mode resources\n")); + return -1; + } + } - /* Acquire mode resources. */ - state->res = drmModeGetResources(state->fd); - if (state->res == NULL) { - fprintf(stderr, _("Failed to get DRM mode resources\n")); - close(state->fd); - state->fd = -1; - return -1; - } + int crtc_count = card->res->count_crtcs; - /* Create entries for selected CRTCs. */ - int crtc_count = state->res->count_crtcs; - if (state->crtc_num >= 0) { - if (state->crtc_num >= crtc_count) { + if (selection->crtc_num == -1) { + /* Select all CRTCs. */ + if (crtc_count < 1) + continue; + int n = state->selection_count + crtc_count + 1; + state->selections = realloc(state->selections, n * sizeof(drm_selection_t)); + selection = state->selections + selection_index; + if (state->selections == NULL) { + perror("realloc"); + return -1; + } + int crtc_i; + for (crtc_i = 0; crtc_i < crtc_count; crtc_i++) { + drm_selection_t *sel = state->selections + ++(state->selection_count); + *sel = *selection; + sel->crtc_num = crtc_i; + } + *selection = state->selections[state->selection_count--]; + } + + /* Verify CRT index. */ + if (selection->crtc_num >= crtc_count) { fprintf(stderr, _("CRTC %d does not exist. "), - state->crtc_num); + selection->crtc_num); if (crtc_count > 1) { fprintf(stderr, _("Valid CRTCs are [0-%d].\n"), - crtc_count-1); + crtc_count - 1); } else { fprintf(stderr, _("Only CRTC 0 exists.\n")); } - close(state->fd); - state->fd = -1; - drmModeFreeResources(state->res); - state->res = NULL; return -1; } - state->crtcs = malloc(2 * sizeof(drm_crtc_state_t)); - state->crtcs[1].crtc_num = -1; - - state->crtcs->crtc_num = state->crtc_num; - state->crtcs->crtc_id = -1; - state->crtcs->gamma_size = -1; - state->crtcs->r_gamma = NULL; - state->crtcs->g_gamma = NULL; - state->crtcs->b_gamma = NULL; - } else { - int crtc_num; - state->crtcs = malloc((crtc_count + 1) * sizeof(drm_crtc_state_t)); - state->crtcs[crtc_count].crtc_num = -1; - for (crtc_num = 0; crtc_num < crtc_count; crtc_num++) { - state->crtcs[crtc_num].crtc_num = crtc_num; - state->crtcs[crtc_num].crtc_id = -1; - state->crtcs[crtc_num].gamma_size = -1; - state->crtcs[crtc_num].r_gamma = NULL; - state->crtcs[crtc_num].g_gamma = NULL; - state->crtcs[crtc_num].b_gamma = NULL; + /* Prepare for adding another output. */ + if (card->crtcs_used++ == 0) + card->crtcs = malloc(1 * sizeof(drm_crtc_state_t)); + else + card->crtcs = realloc(card->crtcs, card->crtcs_used * sizeof(drm_crtc_state_t)); + if (card->crtcs == NULL) { + perror(card->crtcs_used == 1 ? "malloc" : "realloc"); + return -1; } - } - /* Load CRTC information and gamma ramps. */ - drm_crtc_state_t *crtcs = state->crtcs; - for (; crtcs->crtc_num >= 0; crtcs++) { - crtcs->crtc_id = state->res->crtcs[crtcs->crtc_num]; - drmModeCrtc* crtc_info = drmModeGetCrtc(state->fd, crtcs->crtc_id); + /* Create entry for other selected CRTC. */ + drm_crtc_state_t *crtc = card->crtcs + card->crtcs_used - 1; + crtc->crtc_num = selection->crtc_num; + crtc->crtc_id = -1; + crtc->gamma_size = -1; + crtc->saved_gamma_r = NULL; + crtc->saved_gamma_g = NULL; + crtc->saved_gamma_b = NULL; + crtc->gamma[0] = selection->gamma[0]; + crtc->gamma[1] = selection->gamma[1]; + crtc->gamma[2] = selection->gamma[2]; + crtc->gamma_r = NULL; + crtc->gamma_g = NULL; + crtc->gamma_b = NULL; + + /* Load CRTC information and gamma ramps. */ + crtc->crtc_id = card->res->crtcs[selection->crtc_num]; + drmModeCrtc* crtc_info = drmModeGetCrtc(card->fd, crtc->crtc_id); if (crtc_info == NULL) { - fprintf(stderr, _("CRTC %i lost, skipping\n"), crtcs->crtc_num); + fprintf(stderr, _("CRTC %i lost, skipping.\n"), crtc->crtc_num); + crtc->crtc_num = -1; continue; } - crtcs->gamma_size = crtc_info->gamma_size; + crtc->gamma_size = crtc_info->gamma_size; drmModeFreeCrtc(crtc_info); - if (crtcs->gamma_size <= 1) { - fprintf(stderr, _("Could not get gamma ramp size for CRTC %i\n" - "on graphics card %i, ignoring device.\n"), - crtcs->crtc_num, state->card_num); + if (crtc->gamma_size <= 1) { + fprintf(stderr, + _("DRM failed to use gamma ramps on CRTC %i\n" + "on graphics card %i, ignoring device.\n"), + crtc->crtc_num, selection->card_num); continue; } /* Valgrind complains about us reading uninitialize memory if we just use malloc. */ - crtcs->r_gamma = calloc(3 * crtcs->gamma_size, sizeof(uint16_t)); - crtcs->g_gamma = crtcs->r_gamma + crtcs->gamma_size; - crtcs->b_gamma = crtcs->g_gamma + crtcs->gamma_size; - if (crtcs->r_gamma != NULL) { - int r = drmModeCrtcGetGamma(state->fd, crtcs->crtc_id, crtcs->gamma_size, - crtcs->r_gamma, crtcs->g_gamma, crtcs->b_gamma); - if (r < 0) { - fprintf(stderr, _("DRM could not read gamma ramps on CRTC %i on\n" - "graphics card %i, ignoring device.\n"), - crtcs->crtc_num, state->card_num); - free(crtcs->r_gamma); - crtcs->r_gamma = NULL; - } - } else { + crtc->saved_gamma_r = calloc(3 * crtc->gamma_size, sizeof(uint16_t)); + crtc->saved_gamma_g = crtc->saved_gamma_r + crtc->gamma_size; + crtc->saved_gamma_b = crtc->saved_gamma_g + crtc->gamma_size; + if (crtc->saved_gamma_r == NULL) { + perror("malloc"); + return -1; + } + int r = drmModeCrtcGetGamma(card->fd, crtc->crtc_id, crtc->gamma_size, + crtc->saved_gamma_r, crtc->saved_gamma_g, + crtc->saved_gamma_b); + if (r < 0) { + free(crtc->saved_gamma_r); + crtc->saved_gamma_r = NULL; + fprintf(stderr, _("DRM could not read gamma ramps on CRTC %i\n" + "on graphics card %i, ignoring device.\n"), + crtc->crtc_num, selection->card_num); + } + + /* Allocate space for gamma ramps. */ + uint16_t *gamma_ramps = malloc(3 * crtc->gamma_size * sizeof(uint16_t)); + if (gamma_ramps == NULL) { perror("malloc"); - drmModeFreeResources(state->res); - state->res = NULL; - close(state->fd); - state->fd = -1; - while (crtcs-- != state->crtcs) - free(crtcs->r_gamma); - free(state->crtcs); - state->crtcs = NULL; return -1; } + + crtc->gamma_r = gamma_ramps; + crtc->gamma_g = crtc->gamma_r + crtc->gamma_size; + crtc->gamma_b = crtc->gamma_g + crtc->gamma_size; } + /* We do not longer need raw selection information, free it. */ + free(state->selections); + state->selections = NULL; + + state->selection_count -= skipped; return 0; } void drm_restore(drm_state_t *state) { - drm_crtc_state_t *crtcs = state->crtcs; - while (crtcs->crtc_num >= 0) { - if (crtcs->r_gamma != NULL) { - drmModeCrtcSetGamma(state->fd, crtcs->crtc_id, crtcs->gamma_size, - crtcs->r_gamma, crtcs->g_gamma, crtcs->b_gamma); + int card_index; + for (card_index = 0; card_index < state->card_count; card_index++) { + drm_card_state_t *card = state->cards + card_index; + drm_crtc_state_t *crtcs = card->crtcs; + int crtc_index; + for (crtc_index = 0; crtc_index < card->crtcs_used; crtc_index++) { + drm_crtc_state_t *crtc = card->crtcs + crtc_index; + if (crtc->gamma_size <= 1 || crtc->crtc_num < 0) + continue; + if (crtc->saved_gamma_r != NULL) + drmModeCrtcSetGamma(card->fd, crtcs->crtc_id, crtc->gamma_size, + crtc->saved_gamma_r, crtc->saved_gamma_g, + crtc->saved_gamma_b); } - crtcs++; } } void drm_free(drm_state_t *state) { - if (state->crtcs != NULL) { - drm_crtc_state_t *crtcs = state->crtcs; - while (crtcs->crtc_num >= 0) { - if (crtcs->r_gamma != NULL) - free(crtcs->r_gamma); - crtcs->crtc_num = -1; - crtcs++; + int card_index; + for (card_index = 0; card_index < state->card_count; card_index++) { + drm_card_state_t *card = state->cards + card_index; + if (card->crtcs != NULL) { + drm_crtc_state_t *crtcs = card->crtcs; + int crtc_index; + for (crtc_index = 0; crtc_index < card->crtcs_used; crtc_index++) { + if (crtcs[crtc_index].saved_gamma_r != NULL) + free(crtcs[crtc_index].saved_gamma_r); + if (crtcs[crtc_index].gamma_r != NULL) + free(crtcs[crtc_index].gamma_r); + } + free(card->crtcs); + card->crtcs = NULL; + } + if (card->res != NULL) { + drmModeFreeResources(card->res); + card->res = NULL; + } + if (card->fd >= 0) { + close(card->fd); + card->fd = -1; } - free(state->crtcs); - state->crtcs = NULL; } - if (state->res != NULL) { - drmModeFreeResources(state->res); - state->res = NULL; + if (state->cards != NULL) { + free(state->cards); + state->cards = NULL; } - if (state->fd >= 0) { - close(state->fd); - state->fd = -1; + if (state->selections != NULL) { + free(state->selections); + state->selections = NULL; } } @@ -222,16 +352,58 @@ drm_print_help(FILE *f) } int -drm_set_option(drm_state_t *state, const char *key, const char *value) +drm_set_option(drm_state_t *state, const char *key, const char *value, int section) { + if (section == state->selection_count) { + state->selections = realloc(state->selections, + (++(state->selection_count) + 1) * sizeof(drm_selection_t)); + + if (state->selections == NULL) { + perror("realloc"); + return -1; + } + + state->selections[section + 1] = *(state->selections); + state->selections[section + 1].card_num = 0; + state->selections[section + 1].crtc_num = 0; + } + if (strcasecmp(key, "card") == 0) { - state->card_num = atoi(value); + state->selections[section + 1].card_num = atoi(value); + if (state->selections[section + 1].card_num < 0) { + fprintf(stderr, _("Card must be a non-negative integer.\n")); + fprintf(stderr, "Invalid card.\n"); + return -1; + } else if (state->selections[section + 1].card_num >= state->card_count) { + fprintf(stderr, _("Valid Cards are [0-%d].\n"), + state->card_count - 1); + fprintf(stderr, "Invalid card.\n"); + return -1; + } } else if (strcasecmp(key, "crtc") == 0) { - state->crtc_num = atoi(value); - if (state->crtc_num < 0) { - fprintf(stderr, _("CRTC must be a non-negative integer\n")); + state->selections[section + 1].crtc_num = atoi(value); + if (state->selections[section + 1].crtc_num < 0) { + fprintf(stderr, _("CRTC must be a non-negative integer.\n")); + return -1; + } + } else if (strcasecmp(key, "gamma") == 0) { + float gamma[3]; + if (parse_gamma_string(value, gamma) < 0) { + fputs(_("Malformed gamma setting.\n"), + stderr); + return -1; + } + if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || + gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || + gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { + fprintf(stderr, + _("Gamma value must be between %.1f and %.1f.\n"), + MIN_GAMMA, MAX_GAMMA); return -1; } + state->selections[section + 1].gamma[0] = gamma[0]; + state->selections[section + 1].gamma[1] = gamma[1]; + state->selections[section + 1].gamma[2] = gamma[2]; } else { fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); return -1; @@ -241,40 +413,32 @@ drm_set_option(drm_state_t *state, const char *key, const char *value) } int -drm_set_temperature(drm_state_t *state, int temp, float brightness, const float gamma[3]) +drm_set_temperature(drm_state_t *state, int temp, float brightness) { - drm_crtc_state_t *crtcs = state->crtcs; - int last_gamma_size = 0; - uint16_t *r_gamma = NULL; - uint16_t *g_gamma = NULL; - uint16_t *b_gamma = NULL; - - for (; crtcs->crtc_num >= 0; crtcs++) { - if (crtcs->gamma_size <= 1) - continue; - if (crtcs->gamma_size != last_gamma_size) { - if (last_gamma_size == 0) { - r_gamma = malloc(3 * crtcs->gamma_size * sizeof(uint16_t)); - g_gamma = r_gamma + crtcs->gamma_size; - b_gamma = g_gamma + crtcs->gamma_size; - } else if (crtcs->gamma_size > last_gamma_size) { - r_gamma = realloc(r_gamma, 3 * crtcs->gamma_size * sizeof(uint16_t)); - g_gamma = r_gamma + crtcs->gamma_size; - b_gamma = g_gamma + crtcs->gamma_size; - } - if (r_gamma == NULL) { - perror(last_gamma_size == 0 ? "malloc" : "realloc"); - return -1; - } - last_gamma_size = crtcs->gamma_size; + int card_num; + + for (card_num = 0; card_num < state->card_count; card_num++) { + drm_card_state_t *card = state->cards + card_num; + int crtc_; + for (crtc_ = 0; crtc_ < card->crtcs_used; crtc_++) { + drm_crtc_state_t *crtc = card->crtcs + crtc_; + if (crtc->gamma_size <= 1 || crtc->crtc_num < 0) + continue; + + /* Fill gamma ramp and apply. */ + colorramp_fill(crtc->gamma_r, crtc->gamma_g, crtc->gamma_b, + crtc->gamma_size, temp, brightness, crtc->gamma); + drmModeCrtcSetGamma(card->fd, crtc->crtc_id, crtc->gamma_size, + crtc->gamma_r, crtc->gamma_g, crtc->gamma_b); + + /* If Direct Rendering Manager is used to change the gamma ramps + while an graphical session is active in the foreground (and X + display is running on the active VT) Direct Rendering Manager + will ignore the request and report that you do not have + sufficient permissions. This rejection is ignored so nothing + funny happens if the users opens a VT with a graphical session. */ } - colorramp_fill(r_gamma, g_gamma, b_gamma, crtcs->gamma_size, - temp, brightness, gamma); - drmModeCrtcSetGamma(state->fd, crtcs->crtc_id, crtcs->gamma_size, - r_gamma, g_gamma, b_gamma); } - free(r_gamma); - return 0; } diff --git a/src/gamma-drm.h b/src/gamma-drm.h index f4c0df53..decaa057 100644 --- a/src/gamma-drm.h +++ b/src/gamma-drm.h @@ -30,17 +30,33 @@ typedef struct { int crtc_num; int crtc_id; int gamma_size; - uint16_t* r_gamma; - uint16_t* g_gamma; - uint16_t* b_gamma; + uint16_t *saved_gamma_r; + uint16_t *saved_gamma_g; + uint16_t *saved_gamma_b; + float gamma[3]; + uint16_t *gamma_r; + uint16_t *gamma_g; + uint16_t *gamma_b; } drm_crtc_state_t; +typedef struct { + int fd; + drmModeRes *res; + int crtcs_used; + drm_crtc_state_t *crtcs; +} drm_card_state_t; + typedef struct { int card_num; int crtc_num; - int fd; - drmModeRes* res; - drm_crtc_state_t* crtcs; + float gamma[3]; +} drm_selection_t; + +typedef struct { + int selection_count; + drm_selection_t *selections; + int card_count; + drm_card_state_t *cards; } drm_state_t; @@ -49,10 +65,10 @@ int drm_start(drm_state_t *state); void drm_free(drm_state_t *state); void drm_print_help(FILE *f); -int drm_set_option(drm_state_t *state, const char *key, const char *value); +int drm_set_option(drm_state_t *state, const char *key, const char *value, int section); void drm_restore(drm_state_t *state); -int drm_set_temperature(drm_state_t *state, int temp, float brightness, const float gamma[3]); +int drm_set_temperature(drm_state_t *state, int temp, float brightness); #endif /* ! REDSHIFT_GAMMA_DRM_H */ From 33cb37d1a7fe7dd5a9c3e0504c3d2f0182310769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:21:31 +0100 Subject: [PATCH 08/11] =?UTF-8?q?Multi-monitor=E2=80=93multi-screen=20supp?= =?UTF-8?q?ort=20in=20gamma-w32gdi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-w32gdi.c | 72 ++++++++++++++++++++++++++++++++-------------- src/gamma-w32gdi.h | 9 ++++-- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/gamma-w32gdi.c b/src/gamma-w32gdi.c index 7193bc91..b301d580 100644 --- a/src/gamma-w32gdi.c +++ b/src/gamma-w32gdi.c @@ -19,6 +19,7 @@ #include #include +#include #ifndef WINVER # define WINVER 0x0500 @@ -35,6 +36,7 @@ #include "gamma-w32gdi.h" #include "colorramp.h" +#include "redshift.h" #define GAMMA_RAMP_SIZE 256 @@ -43,6 +45,12 @@ int w32gdi_init(w32gdi_state_t *state) { state->saved_ramps = NULL; + state->gamma[0] = DEFAULT_GAMMA; + state->gamma[1] = DEFAULT_GAMMA; + state->gamma[2] = DEFAULT_GAMMA; + state->gamma_r = NULL; + state->gamma_g = NULL; + state->gamma_b = NULL; return 0; } @@ -86,6 +94,18 @@ w32gdi_start(w32gdi_state_t *state) /* Release device context */ ReleaseDC(NULL, hDC); + /* Allocate space for gamma ramps */ + WORD* gamma_ramps = malloc(3*GAMMA_RAMP_SIZE*sizeof(WORD)); + if (gamma_ramps == NULL) { + perror("malloc"); + ReleaseDC(NULL, hDC); + return -1; + } + + state->gamma_r = gamma_ramps; + state->gamma_g = state->gamma_r + GAMMA_RAMP_SIZE; + state->gamma_b = state->gamma_g + GAMMA_RAMP_SIZE; + return 0; } @@ -94,6 +114,7 @@ w32gdi_free(w32gdi_state_t *state) { /* Free saved ramps */ free(state->saved_ramps); + free(state->gamma_r); } @@ -105,9 +126,32 @@ w32gdi_print_help(FILE *f) } int -w32gdi_set_option(w32gdi_state_t *state, const char *key, const char *value) +w32gdi_set_option(w32gdi_state_t *state, const char *key, const char *value, int section) { - return -1; + if (strcasecmp(key, "gamma") == 0) { + float gamma[3]; + if (parse_gamma_string(value, gamma) < 0) { + fputs(_("Malformed gamma setting.\n"), + stderr); + return -1; + } + if (gamma[0] < MIN_GAMMA || gamma[0] > MAX_GAMMA || + gamma[1] < MIN_GAMMA || gamma[1] > MAX_GAMMA || + gamma[2] < MIN_GAMMA || gamma[2] > MAX_GAMMA) { + fprintf(stderr, + _("Gamma value must be between %.1f and %.1f.\n"), + MIN_GAMMA, MAX_GAMMA); + return -1; + } + state->gamma[0] = gamma[0]; + state->gamma[1] = gamma[1]; + state->gamma[2] = gamma[2]; + } else { + fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); + return -1; + } + + return 0; } void @@ -129,8 +173,7 @@ w32gdi_restore(w32gdi_state_t *state) } int -w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness, - const float gamma[3]) +w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness) { BOOL r; @@ -142,34 +185,21 @@ w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness, } /* Create new gamma ramps */ - WORD *gamma_ramps = malloc(3*GAMMA_RAMP_SIZE*sizeof(WORD)); - if (gamma_ramps == NULL) { - perror("malloc"); - ReleaseDC(NULL, hDC); - return -1; - } - - WORD *gamma_r = &gamma_ramps[0*GAMMA_RAMP_SIZE]; - WORD *gamma_g = &gamma_ramps[1*GAMMA_RAMP_SIZE]; - WORD *gamma_b = &gamma_ramps[2*GAMMA_RAMP_SIZE]; - - colorramp_fill(gamma_r, gamma_g, gamma_b, GAMMA_RAMP_SIZE, - temp, brightness, gamma); + colorramp_fill(state->gamma_r, state->gamma_g, state->gamma_b, + GAMMA_RAMP_SIZE, temp, brightness, state->gamma); /* Set new gamma ramps */ - r = SetDeviceGammaRamp(hDC, gamma_ramps); + r = SetDeviceGammaRamp(hDC, state->gamma_r); if (!r) { /* TODO it happens that SetDeviceGammaRamp returns FALSE on occasions where the adjustment seems to be successful. Does this only happen with multiple monitors connected? */ fputs(_("Unable to set gamma ramps.\n"), stderr); - free(gamma_ramps); + free(state->gamma_r); ReleaseDC(NULL, hDC); return -1; } - free(gamma_ramps); - /* Release device context */ ReleaseDC(NULL, hDC); diff --git a/src/gamma-w32gdi.h b/src/gamma-w32gdi.h index e81f4c5e..1f1c7eb5 100644 --- a/src/gamma-w32gdi.h +++ b/src/gamma-w32gdi.h @@ -26,6 +26,10 @@ typedef struct { WORD *saved_ramps; + float gamma[]; + WORD *gamma_r; + WORD *gamma_g; + WORD *gamma_b; } w32gdi_state_t; @@ -35,11 +39,10 @@ void w32gdi_free(w32gdi_state_t *state); void w32gdi_print_help(FILE *f); int w32gdi_set_option(w32gdi_state_t *state, const char *key, - const char *value); + const char *value, int section); void w32gdi_restore(w32gdi_state_t *state); -int w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness, - const float gamma[3]); +int w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness); #endif /* ! REDSHIFT_GAMMA_W32GDI_H */ From 5f0e4c6bb788ff419c3da2827bf1a8d13032a60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:23:00 +0100 Subject: [PATCH 09/11] Suppress warnings, mostly unused parameter but also on signness difference in a comparision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-dummy.c | 8 ++++++++ src/location-manual.c | 1 + src/redshift.c | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gamma-dummy.c b/src/gamma-dummy.c index 9c77ecfa..14312b6f 100644 --- a/src/gamma-dummy.c +++ b/src/gamma-dummy.c @@ -34,12 +34,14 @@ int gamma_dummy_init(void *state) { + (void) state; return 0; } int gamma_dummy_start(void *state) { + (void) state; fputs(_("WARNING: Using dummy gamma method! Display will not be affected by this gamma method.\n"), stderr); return 0; } @@ -47,11 +49,13 @@ gamma_dummy_start(void *state) void gamma_dummy_restore(void *state) { + (void) state; } void gamma_dummy_free(void *state) { + (void) state; } void @@ -64,6 +68,8 @@ gamma_dummy_print_help(FILE *f) int gamma_dummy_set_option(void *state, const char *key, const char *value, int section) { + (void) state; + (void) section; if (strcasecmp(key, "gamma") == 0) { float gamma[3]; if (parse_gamma_string(value, gamma) < 0) { @@ -90,6 +96,8 @@ gamma_dummy_set_option(void *state, const char *key, const char *value, int sect int gamma_dummy_set_temperature(void *state, int temp, float brightness) { + (void) state; + (void) brightness; printf(_("Temperature: %i\n"), temp); return 0; } diff --git a/src/location-manual.c b/src/location-manual.c index 30dfc9c6..9f7d8ff0 100644 --- a/src/location-manual.c +++ b/src/location-manual.c @@ -57,6 +57,7 @@ location_manual_start(location_manual_state_t *state) void location_manual_free(location_manual_state_t *state) { + (void) state; } void diff --git a/src/redshift.c b/src/redshift.c index af388c61..f3918fcf 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -218,6 +218,7 @@ static volatile sig_atomic_t disable = 0; static void sigexit(int signo) { + (void) signo; exiting = 1; } @@ -225,6 +226,7 @@ sigexit(int signo) static void sigdisable(int signo) { + (void) signo; disable = 1; } @@ -424,7 +426,7 @@ provider_try_start(const location_provider_t *provider, and for backwards compatability. We add the proper keys here before calling set_option(). */ if (strcmp(provider->name, "manual") == 0 && - i < sizeof(manual_keys)/sizeof(manual_keys[0])) { + (unsigned)i < sizeof(manual_keys)/sizeof(manual_keys[0])) { key = manual_keys[i]; value = args; } else { From 9edd92a455e791788bb45973c2dba288d20526ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Sun, 23 Mar 2014 06:36:23 +0100 Subject: [PATCH 10/11] Base gamma adjustment on the gamma ramps at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- redshift.1 | 6 ++++++ src/colorramp.c | 34 +++++++++++++++++++++++++++++++++- src/colorramp.h | 3 ++- src/gamma-drm.c | 10 +++++++--- src/gamma-drm.h | 2 +- src/gamma-dummy.c | 4 +++- src/gamma-dummy.h | 3 ++- src/gamma-randr.c | 19 ++++++++++++++----- src/gamma-randr.h | 3 ++- src/gamma-vidmode.c | 13 +++++++++++-- src/gamma-vidmode.h | 3 ++- src/gamma-w32gdi.c | 13 +++++++++++-- src/gamma-w32gdi.h | 5 +++-- src/redshift.c | 22 +++++++++++++++++----- src/redshift.h | 2 +- 15 files changed, 115 insertions(+), 27 deletions(-) diff --git a/redshift.1 b/redshift.1 index fbf7bdf6..2533b4e6 100644 --- a/redshift.1 +++ b/redshift.1 @@ -60,6 +60,9 @@ One shot mode (do not continuously adjust color temperature) \fB\-O\fR TEMP One shot manual mode (set color temperature) .TP +\fB\-P\fR +Preserve current calibrations +.TP \fB\-p\fR Print mode (only print parameters and exit) .TP @@ -106,6 +109,9 @@ Screen brightness at night \fBgamma\fR = R:G:B Gamma adjustment to apply .TP +\fBpreserve-calibrations\fR = 0 or 1 +Disable or enable preservation of currently applied calibrations. +.TP \fBadjustment\-method\fR = name Select adjustment method. Options for the adjustment method can be given under the configuration file heading of the same name. diff --git a/src/colorramp.c b/src/colorramp.c index f1988d4c..752884e6 100644 --- a/src/colorramp.c +++ b/src/colorramp.c @@ -18,6 +18,7 @@ Copyright (c) 2013 Ingo Thies */ +#include #include #include @@ -282,7 +283,8 @@ interpolate_color(float a, const float *c1, const float *c2, float *c) void colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, - int size, int temp, float brightness, const float gamma[3]) + int size, int temp, float brightness, const float gamma[3], + uint16_t *calib_r, uint16_t *calib_g, uint16_t *calib_b) { /* Approximate white point */ float white_point[3]; @@ -298,4 +300,34 @@ colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, gamma_g[i] = F((float)i/size, 1) * (UINT16_MAX+1); gamma_b[i] = F((float)i/size, 2) * (UINT16_MAX+1); } + + /* Apply gamma ramps used when Redshift started on top of + the effects of Redshift. It would be easier to put + Redshift's effects on top if this, but then calibrations + whould become incorrect. */ + if (calib_r == NULL) + return; + uint16_t *calib[3]; + calib[0] = calib_r; + calib[1] = calib_g; + calib[2] = calib_b; + uint16_t *filter[3]; + filter[0] = gamma_r; + filter[1] = gamma_g; + filter[2] = gamma_b; + int size_ = size - 1; + for (int c = 0; c < 3; c++) { + uint16_t *cfilter = filter[c]; + uint16_t *ccalib = calib[c]; + for (int i = 0; i < size; i++) { + /* We a rounding a bit. We could do linear + interpolation or even (precalculated) + polynomial interpolation, but it is + probably not worth it. */ + int y = cfilter[i]; + y = (float)(y * size_) / UINT16_MAX + 0.5; + y = y < 0 ? 0 : (y > size_ ? size_ : y); + cfilter[i] = ccalib[y]; + } + } } diff --git a/src/colorramp.h b/src/colorramp.h index dd0fa97d..5a27f59c 100644 --- a/src/colorramp.h +++ b/src/colorramp.h @@ -23,6 +23,7 @@ #include void colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, - int size, int temp, float brightness, const float gamma[3]); + int size, int temp, float brightness, const float gamma[3], + uint16_t *calib_r, uint16_t *calib_g, uint16_t *calib_b); #endif /* ! REDSHIFT_COLORRAMP_H */ diff --git a/src/gamma-drm.c b/src/gamma-drm.c index 4754460e..b04b89b2 100644 --- a/src/gamma-drm.c +++ b/src/gamma-drm.c @@ -244,7 +244,7 @@ drm_start(drm_state_t *state) } /* Valgrind complains about us reading uninitialize memory if we just use malloc. */ crtc->saved_gamma_r = calloc(3 * crtc->gamma_size, sizeof(uint16_t)); - crtc->saved_gamma_g = crtc->saved_gamma_r + crtc->gamma_size; + crtc->saved_gamma_g = crtc->saved_gamma_r + crtc->gamma_size; crtc->saved_gamma_b = crtc->saved_gamma_g + crtc->gamma_size; if (crtc->saved_gamma_r == NULL) { perror("malloc"); @@ -413,7 +413,7 @@ drm_set_option(drm_state_t *state, const char *key, const char *value, int secti } int -drm_set_temperature(drm_state_t *state, int temp, float brightness) +drm_set_temperature(drm_state_t *state, int temp, float brightness, int calibrations) { int card_num; @@ -426,8 +426,12 @@ drm_set_temperature(drm_state_t *state, int temp, float brightness) continue; /* Fill gamma ramp and apply. */ + uint16_t *saved_gamma_r = calibrations ? crtc->saved_gamma_r : NULL; + uint16_t *saved_gamma_g = calibrations ? crtc->saved_gamma_g : NULL; + uint16_t *saved_gamma_b = calibrations ? crtc->saved_gamma_b : NULL; colorramp_fill(crtc->gamma_r, crtc->gamma_g, crtc->gamma_b, - crtc->gamma_size, temp, brightness, crtc->gamma); + crtc->gamma_size, temp, brightness, crtc->gamma, + saved_gamma_r, saved_gamma_g, saved_gamma_b); drmModeCrtcSetGamma(card->fd, crtc->crtc_id, crtc->gamma_size, crtc->gamma_r, crtc->gamma_g, crtc->gamma_b); diff --git a/src/gamma-drm.h b/src/gamma-drm.h index decaa057..c94d677b 100644 --- a/src/gamma-drm.h +++ b/src/gamma-drm.h @@ -68,7 +68,7 @@ void drm_print_help(FILE *f); int drm_set_option(drm_state_t *state, const char *key, const char *value, int section); void drm_restore(drm_state_t *state); -int drm_set_temperature(drm_state_t *state, int temp, float brightness); +int drm_set_temperature(drm_state_t *state, int temp, float brightness, int calibrations); #endif /* ! REDSHIFT_GAMMA_DRM_H */ diff --git a/src/gamma-dummy.c b/src/gamma-dummy.c index 14312b6f..cd3d99f1 100644 --- a/src/gamma-dummy.c +++ b/src/gamma-dummy.c @@ -70,6 +70,7 @@ gamma_dummy_set_option(void *state, const char *key, const char *value, int sect { (void) state; (void) section; + if (strcasecmp(key, "gamma") == 0) { float gamma[3]; if (parse_gamma_string(value, gamma) < 0) { @@ -94,10 +95,11 @@ gamma_dummy_set_option(void *state, const char *key, const char *value, int sect } int -gamma_dummy_set_temperature(void *state, int temp, float brightness) +gamma_dummy_set_temperature(void *state, int temp, float brightness, int calibrations) { (void) state; (void) brightness; + (void) calibrations; printf(_("Temperature: %i\n"), temp); return 0; } diff --git a/src/gamma-dummy.h b/src/gamma-dummy.h index 8270e7de..9ced3f04 100644 --- a/src/gamma-dummy.h +++ b/src/gamma-dummy.h @@ -31,7 +31,8 @@ void gamma_dummy_print_help(FILE *f); int gamma_dummy_set_option(void *state, const char *key, const char *value, int section); void gamma_dummy_restore(void *state); -int gamma_dummy_set_temperature(void *state, int temp, float brightness); +int gamma_dummy_set_temperature(void *state, int temp, float brightness, + int calibrations); #endif /* ! REDSHIFT_GAMMA_DUMMY_H */ diff --git a/src/gamma-randr.c b/src/gamma-randr.c index a5b01ba6..01f332c6 100644 --- a/src/gamma-randr.c +++ b/src/gamma-randr.c @@ -491,7 +491,7 @@ randr_set_option(randr_state_t *state, const char *key, const char *value, int s static int randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, int temp, - float brightness) + float brightness, int calibrations) { randr_crtc_state_t *crtc = &state->crtcs[crtc_num]; xcb_generic_error_t *error; @@ -499,8 +499,17 @@ randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, int temp, unsigned int ramp_size = crtc->ramp_size; /* Create new gamma ramps */ + uint16_t *saved_gamma_r = NULL; + uint16_t *saved_gamma_g = NULL; + uint16_t *saved_gamma_b = NULL; + if (calibrations) { + saved_gamma_r = &crtc->saved_ramps[0*crtc->ramp_size]; + saved_gamma_g = &crtc->saved_ramps[1*crtc->ramp_size]; + saved_gamma_b = &crtc->saved_ramps[2*crtc->ramp_size]; + } colorramp_fill(crtc->gamma_r, crtc->gamma_g, crtc->gamma_b, - ramp_size, temp, brightness, crtc->gamma); + ramp_size, temp, brightness, crtc->gamma, + saved_gamma_r, saved_gamma_g, saved_gamma_b); /* Set new gamma ramps */ xcb_void_cookie_t gamma_set_cookie = @@ -519,13 +528,13 @@ randr_set_temperature_for_crtc(randr_state_t *state, int crtc_num, int temp, } int -randr_set_temperature(randr_state_t *state, int temp, float brightness) +randr_set_temperature(randr_state_t *state, int temp, float brightness, int calibrations) { int r; for (int i = 0; i < state->crtcs_used; i++) { - r = randr_set_temperature_for_crtc(state, i, - temp, brightness); + r = randr_set_temperature_for_crtc(state, i, temp, + brightness, calibrations); if (r < 0) return -1; } diff --git a/src/gamma-randr.h b/src/gamma-randr.h index c9cebdd4..966c1426 100644 --- a/src/gamma-randr.h +++ b/src/gamma-randr.h @@ -64,7 +64,8 @@ int randr_set_option(randr_state_t *state, const char *key, const char *value, int section); void randr_restore(randr_state_t *state); -int randr_set_temperature(randr_state_t *state, int temp, float brightness); +int randr_set_temperature(randr_state_t *state, int temp, float brightness, + int calibrations); #endif /* ! REDSHIFT_GAMMA_RANDR_H */ diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c index 06d73f74..9a0b2155 100644 --- a/src/gamma-vidmode.c +++ b/src/gamma-vidmode.c @@ -320,7 +320,7 @@ vidmode_restore(vidmode_state_t *state) } int -vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness) +vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness, int calibrations) { int screen_index; for (screen_index = 0; screen_index < state->screens_used; screen_index++) { @@ -328,8 +328,17 @@ vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness) int r; /* Create new gamma ramps */ + uint16_t *saved_gamma_r = NULL; + uint16_t *saved_gamma_g = NULL; + uint16_t *saved_gamma_b = NULL; + if (calibrations) { + saved_gamma_r = &screen->saved_ramps[0*screen->ramp_size]; + saved_gamma_g = &screen->saved_ramps[1*screen->ramp_size]; + saved_gamma_b = &screen->saved_ramps[2*screen->ramp_size]; + } colorramp_fill(screen->gamma_r, screen->gamma_g, screen->gamma_b, - screen->ramp_size, temp, brightness, screen->gamma); + screen->ramp_size, temp, brightness, screen->gamma, + saved_gamma_r, saved_gamma_g, saved_gamma_b); /* Set new gamma ramps */ r = XF86VidModeSetGammaRamp(state->display, screen->screen_num, diff --git a/src/gamma-vidmode.h b/src/gamma-vidmode.h index 3c87b80d..47b6726c 100644 --- a/src/gamma-vidmode.h +++ b/src/gamma-vidmode.h @@ -59,7 +59,8 @@ int vidmode_set_option(vidmode_state_t *state, const char *key, const char *value, int section); void vidmode_restore(vidmode_state_t *state); -int vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness); +int vidmode_set_temperature(vidmode_state_t *state, int temp, float brightness, + int calibrations); #endif /* ! REDSHIFT_GAMMA_VIDMODE_H */ diff --git a/src/gamma-w32gdi.c b/src/gamma-w32gdi.c index b301d580..653e66d8 100644 --- a/src/gamma-w32gdi.c +++ b/src/gamma-w32gdi.c @@ -173,7 +173,7 @@ w32gdi_restore(w32gdi_state_t *state) } int -w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness) +w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness, int calibrations) { BOOL r; @@ -185,8 +185,17 @@ w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness) } /* Create new gamma ramps */ + uint16_t *saved_gamma_r = NULL; + uint16_t *saved_gamma_g = NULL; + uint16_t *saved_gamma_b = NULL; + if (calibrations) { + saved_gamma_r = &state->saved_ramps[0*GAMMA_RAMP_SIZE]; + saved_gamma_g = &state->saved_ramps[1*GAMMA_RAMP_SIZE]; + saved_gamma_b = &state->saved_ramps[2*GAMMA_RAMP_SIZE]; + } colorramp_fill(state->gamma_r, state->gamma_g, state->gamma_b, - GAMMA_RAMP_SIZE, temp, brightness, state->gamma); + GAMMA_RAMP_SIZE, temp, brightness, state->gamma, + saved_gamma_r, saved_gamma_g, saved_gamma_b); /* Set new gamma ramps */ r = SetDeviceGammaRamp(hDC, state->gamma_r); diff --git a/src/gamma-w32gdi.h b/src/gamma-w32gdi.h index 1f1c7eb5..892edc6c 100644 --- a/src/gamma-w32gdi.h +++ b/src/gamma-w32gdi.h @@ -26,7 +26,7 @@ typedef struct { WORD *saved_ramps; - float gamma[]; + float gamma[3]; WORD *gamma_r; WORD *gamma_g; WORD *gamma_b; @@ -42,7 +42,8 @@ int w32gdi_set_option(w32gdi_state_t *state, const char *key, const char *value, int section); void w32gdi_restore(w32gdi_state_t *state); -int w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness); +int w32gdi_set_temperature(w32gdi_state_t *state, int temp, float brightness, + int calibrations); #endif /* ! REDSHIFT_GAMMA_W32GDI_H */ diff --git a/src/redshift.c b/src/redshift.c index f3918fcf..074b358a 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -313,6 +313,7 @@ print_help(const char *program_name) " -o\t\tOne shot mode (do not continuously adjust" " color temperature)\n" " -O TEMP\tOne shot manual mode (set color temperature)\n" + " -P\t\tPreserve current calibrations\n" " -p\t\tPrint mode (only print parameters and exit)\n" " -x\t\tReset mode (remove adjustment from screen)\n" " -r\t\tDisable temperature transitions\n" @@ -667,6 +668,7 @@ main(int argc, char *argv[]) const location_provider_t *provider = NULL; char *provider_args = NULL; + int preserve_calibrations = -1; int transition = -1; program_mode_t mode = PROGRAM_MODE_CONTINUAL; int verbose = 0; @@ -680,7 +682,7 @@ main(int argc, char *argv[]) /* Parse command line arguments. */ int opt; - while ((opt = getopt(argc, argv, "b:c:g:hl:m:oO:prt:vVx")) != -1) { + while ((opt = getopt(argc, argv, "b:c:g:hl:m:oO:pPrt:vVx")) != -1) { float _gamma[3]; switch (opt) { case 'b': @@ -790,6 +792,9 @@ main(int argc, char *argv[]) case 'p': mode = PROGRAM_MODE_PRINT; break; + case 'P': + preserve_calibrations = 1; + break; case 'r': transition = 0; break; @@ -853,6 +858,11 @@ main(int argc, char *argv[]) if (transition < 0) { transition = !!atoi(setting->value); } + } else if (strcasecmp(setting->name, + "preserve-calibrations") == 0) { + if (preserve_calibrations < 0) { + preserve_calibrations = !!atoi(setting->value); + } } else if (strcasecmp(setting->name, "brightness") == 0) { if (isnan(brightness_day)) { @@ -919,6 +929,7 @@ main(int argc, char *argv[]) if (isnan(brightness_day)) brightness_day = DEFAULT_BRIGHTNESS; if (isnan(brightness_night)) brightness_night = DEFAULT_BRIGHTNESS; if (transition < 0) transition = 1; + if (preserve_calibrations < 0) preserve_calibrations = 0; float lat = NAN; float lon = NAN; @@ -1128,7 +1139,7 @@ main(int argc, char *argv[]) } /* Adjust temperature */ - r = method->set_temperature(&state, temp, brightness); + r = method->set_temperature(&state, temp, brightness, preserve_calibrations); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1141,7 +1152,7 @@ main(int argc, char *argv[]) if (verbose) printf(_("Color temperature: %uK\n"), temp_set); /* Adjust temperature */ - r = method->set_temperature(&state, temp_set, brightness_day); + r = method->set_temperature(&state, temp_set, brightness_day, preserve_calibrations); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1153,7 +1164,7 @@ main(int argc, char *argv[]) case PROGRAM_MODE_RESET: { /* Reset screen */ - r = method->set_temperature(&state, NEUTRAL_TEMP, 1.0); + r = method->set_temperature(&state, NEUTRAL_TEMP, 1.0, preserve_calibrations); if (r < 0) { fputs(_("Temperature adjustment failed.\n"), stderr); method->free(&state); @@ -1334,7 +1345,8 @@ main(int argc, char *argv[]) /* Adjust temperature */ if (!disabled || short_trans) { r = method->set_temperature(&state, - temp, brightness); + temp, brightness, + preserve_calibrations); if (r < 0) { fputs(_("Temperature adjustment" " failed.\n"), stderr); diff --git a/src/redshift.h b/src/redshift.h index 27f868c9..fcb72806 100644 --- a/src/redshift.h +++ b/src/redshift.h @@ -62,7 +62,7 @@ typedef int gamma_method_set_option_func(void *state, const char *key, const char *value, int section); typedef void gamma_method_restore_func(void *state); typedef int gamma_method_set_temperature_func(void *state, int temp, - float brightness); + float brightness, int calibrations); typedef struct { char *name; From f357fff3c458ab48048cc3e43b97a971a7a7c333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Mon, 24 Mar 2014 12:58:53 +0100 Subject: [PATCH 11/11] Ignore preserve-calibrations from redshift.conf unless mode == PROGRAM_MODE_CONTINUAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/redshift.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/redshift.c b/src/redshift.c index 074b358a..843e4add 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -860,7 +860,8 @@ main(int argc, char *argv[]) } } else if (strcasecmp(setting->name, "preserve-calibrations") == 0) { - if (preserve_calibrations < 0) { + if (preserve_calibrations < 0 && + mode == PROGRAM_MODE_CONTINUAL) { preserve_calibrations = !!atoi(setting->value); } } else if (strcasecmp(setting->name,