diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-05 09:14:17 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-05 09:14:17 +0100 |
commit | 6c518351ef1a7fc144d3689165fbe582d1ee72fc (patch) | |
tree | daf5f57999a889a14506de4af7136d025476d338 /src | |
parent | Update my e-mail address (diff) | |
parent | Add coopgamma backend (diff) | |
download | redshift-ng-6c518351ef1a7fc144d3689165fbe582d1ee72fc.tar.gz redshift-ng-6c518351ef1a7fc144d3689165fbe582d1ee72fc.tar.bz2 redshift-ng-6c518351ef1a7fc144d3689165fbe582d1ee72fc.tar.xz |
Merge branch 'coopgamma' of https://github.com/maandree/redshift
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 1 | ||||
-rw-r--r-- | src/colorramp.c | 57 | ||||
-rw-r--r-- | src/colorramp.h | 18 | ||||
-rw-r--r-- | src/config.mk | 5 | ||||
-rw-r--r-- | src/gamma-coopgamma.c | 571 | ||||
-rw-r--r-- | src/gamma-coopgamma.h | 29 | ||||
-rw-r--r-- | src/gamma-drm.c | 12 | ||||
-rw-r--r-- | src/gamma-dummy.c | 2 | ||||
-rw-r--r-- | src/gamma-quartz.c | 4 | ||||
-rw-r--r-- | src/gamma-randr.c | 6 | ||||
-rw-r--r-- | src/gamma-vidmode.c | 6 | ||||
-rw-r--r-- | src/gamma-w32gdi.c | 6 | ||||
-rw-r--r-- | src/redshift.c | 18 | ||||
-rw-r--r-- | src/redshift.h | 2 |
14 files changed, 671 insertions, 66 deletions
diff --git a/src/Makefile b/src/Makefile index 802fdea..c906e20 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,6 +6,7 @@ include $(CONFIGFILE) OBJ =\ colorramp.o\ config-ini.o\ + gamma-coopgamma.o\ gamma-drm.o\ gamma-dummy.o\ gamma-randr.o\ diff --git a/src/colorramp.c b/src/colorramp.c index fda75f2..2c67969 100644 --- a/src/colorramp.c +++ b/src/colorramp.c @@ -21,6 +21,7 @@ #include <stdint.h> #include <math.h> +#include "colorramp.h" #include "redshift.h" /* Whitepoint values for temperatures at 100K intervals. @@ -285,43 +286,29 @@ interpolate_color(float a, const float *c1, const float *c2, float *c) #define F(Y, C) pow((Y) * setting->brightness * \ white_point[C], 1.0/setting->gamma[C]) -void -colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, - int size, const color_setting_t *setting) -{ - /* Approximate white point */ - float white_point[3]; - float alpha = (setting->temperature % 100) / 100.0; - int temp_index = ((setting->temperature - 1000) / 100)*3; - interpolate_color(alpha, &blackbody_color[temp_index], - &blackbody_color[temp_index+3], white_point); - for (int i = 0; i < size; i++) { - 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); +#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\ + void\ + colorramp_fill_##SUFFIX(TYPE *gamma_r, TYPE *gamma_g, TYPE *gamma_b,\ + size_t size_r, size_t size_g, size_t size_b,\ + const color_setting_t *setting)\ + {\ + /* Approximate white point */\ + float white_point[3];\ + float alpha = (setting->temperature % 100) / 100.0;\ + int temp_index = ((setting->temperature - 1000) / 100) * 3;\ + interpolate_color(alpha, &blackbody_color[temp_index],\ + &blackbody_color[temp_index+3], white_point);\ + \ + for (size_t i = 0; i < size_r; i++)\ + gamma_r[i] = F((double)gamma_r[i] / (MAX), 0) * (MAX);\ + for (size_t i = 0; i < size_g; i++)\ + gamma_g[i] = F((double)gamma_g[i] / (MAX), 1) * (MAX);\ + for (size_t i = 0; i < size_b; i++)\ + gamma_b[i] = F((double)gamma_b[i] / (MAX), 2) * (MAX);\ } -} - -void -colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b, - int size, const color_setting_t *setting) -{ - /* Approximate white point */ - float white_point[3]; - float alpha = (setting->temperature % 100) / 100.0; - int temp_index = ((setting->temperature - 1000) / 100)*3; - interpolate_color(alpha, &blackbody_color[temp_index], - &blackbody_color[temp_index+3], white_point); - for (int i = 0; i < size; i++) { - 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); - } -} +LIST_RAMPS_STOP_VALUE_TYPES +#undef X #undef F diff --git a/src/colorramp.h b/src/colorramp.h index 438c563..8802844 100644 --- a/src/colorramp.h +++ b/src/colorramp.h @@ -24,9 +24,19 @@ #include "redshift.h" -void colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, - int size, const color_setting_t *setting); -void colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b, - int size, const color_setting_t *setting); +#define LIST_RAMPS_STOP_VALUE_TYPES\ + X(u8, uint8_t, UINT8_MAX + 1ULL, UINT8_MAX, 8)\ + X(u16, uint16_t, UINT16_MAX + 1ULL, UINT16_MAX, 16)\ + X(u32, uint32_t, UINT32_MAX + 1ULL, UINT32_MAX, 32)\ + X(u64, uint64_t, UINT64_MAX, UINT64_MAX, 64)\ + X(float, float, 1, 1, -1)\ + X(double, double, 1, 1, -2) + +#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\ + void colorramp_fill_##SUFFIX(TYPE *gamma_r, TYPE *gamma_g, TYPE *gamma_b,\ + size_t size_r, size_t size_g, size_t size_b,\ + const color_setting_t *setting); +LIST_RAMPS_STOP_VALUE_TYPES +#undef X #endif /* ! REDSHIFT_COLORRAMP_H */ diff --git a/src/config.mk b/src/config.mk index f956ffb..0e0b2fd 100644 --- a/src/config.mk +++ b/src/config.mk @@ -15,6 +15,7 @@ VIDMODE_LIBS = x11 xxf86vm LIBS_PKGCONFIG = $(DRM_LIBS) $(GEOCLUE_LIBS) $(RANDR_LIBS) $(VIDMODE_LIBS) CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE\ - -DENABLE_DRM -DENABLE_GEOCLUE2 -DENABLE_RANDR -DENABLE_VIDMODE + -DENABLE_DRM -DENABLE_GEOCLUE2 -DENABLE_RANDR -DENABLE_VIDMODE\ + -DENABLE_COOPGAMMA CFLAGS = $$($(PKGCONFIG_CFLAGS) $(LIBS_PKGCONFIG)) -LDFLAGS = $$($(PKGCONFIG_LDFLAGS) $(LIBS_PKGCONFIG)) -lm +LDFLAGS = $$($(PKGCONFIG_LDFLAGS) $(LIBS_PKGCONFIG)) -lm -lcoopgamma diff --git a/src/gamma-coopgamma.c b/src/gamma-coopgamma.c new file mode 100644 index 0000000..41a9d2b --- /dev/null +++ b/src/gamma-coopgamma.c @@ -0,0 +1,571 @@ +/* gamma-coopgamma.h -- coopgamma gamma adjustment source + This file is part of Redshift. + + Redshift is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Redshift is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Redshift. If not, see <http://www.gnu.org/licenses/>. + + Copyright (c) 2016, 2025 Mattias Andrée <m@maandree.se> +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define PACKAGE "redshift" +#endif + +#include <errno.h> +#include <inttypes.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef ENABLE_NLS +# include <libintl.h> +# define _(s) gettext(s) +#else +# define _(s) s +#endif + +#include "gamma-coopgamma.h" +#include "colorramp.h" + + +typedef struct { + char *edid; + size_t index; +} coopgamma_output_id_t; + +typedef struct { + libcoopgamma_filter_t filter; + libcoopgamma_ramps_t plain_ramps; + size_t rampsize; +} coopgamma_crtc_state_t; + +typedef struct { + libcoopgamma_context_t ctx; + coopgamma_crtc_state_t *crtcs; + size_t n_crtcs; + char **methods; + char *method; + char *site; + int64_t priority; + int list_outputs; + coopgamma_output_id_t *outputs; + size_t n_outputs; + size_t a_outputs; +} coopgamma_state_t; + + +struct signal_blockage { +}; + +static int +unblocked_signal(int signo, struct signal_blockage *prev) +{ + /* TODO */ + return 0; +} + + +static int +restore_signal_blockage(int signo, const struct signal_blockage *blockage) +{ + /* TODO */ + return 0; +} + + +static int +update(coopgamma_state_t *state) +{ + for (size_t i = 0; i < state->n_crtcs; i++) + libcoopgamma_set_gamma_sync(&state->crtcs[i].filter, &state->ctx); + return 0; +} + + +static void +print_error(coopgamma_state_t *state) +{ + const char* side = state->ctx.error.server_side ? _("server-side") : _("client-side"); + if (state->ctx.error.custom) { + if (state->ctx.error.number != 0 && state->ctx.error.description != NULL) + fprintf(stderr, "%s error number %llu: %s\n", + side, (unsigned long long int)state->ctx.error.number, + state->ctx.error.description); + else if (state->ctx.error.number != 0) + fprintf(stderr, _("%s error number %llu\n"), + side, (unsigned long long int)state->ctx.error.number); + else if (state->ctx.error.description != NULL) + fprintf(stderr, _("%s error: %s\n"), side, state->ctx.error.description); + } else if (state->ctx.error.description != NULL) { + fprintf(stderr, _("%s error: %s\n"), side, state->ctx.error.description); + } else { + fprintf(stderr, _("%s error: %s\n"), side, strerror(state->ctx.error.number)); + } +} + + +static int +coopgamma_init(coopgamma_state_t **state) +{ + *state = malloc(sizeof(coopgamma_state_t)); + if (*state == NULL) return -1; + + coopgamma_state_t *s = *state; + + struct signal_blockage signal_blockage; + memset(s, 0, sizeof(*s)); + if (libcoopgamma_context_initialise(&s->ctx)) { + perror("libcoopgamma_context_initialise"); + return -1; + } + + /* This is done this early to check if coopgamma is available */ + if (unblocked_signal(SIGCHLD, &signal_blockage) < 0) + return -1; + s->methods = libcoopgamma_get_methods(); + if (s->methods == NULL) { + perror("libcoopgamma_get_methods"); + if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) + exit(EXIT_FAILURE); + return -1; + } + if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) + return -1; + + s->priority = 0x0800000000000000LL; + + return 0; +} + +static int +coopgamma_start(coopgamma_state_t *state, program_mode_t mode) +{ + struct signal_blockage signal_blockage; + libcoopgamma_lifespan_t lifespan; + char** outputs; + size_t i, j, n_outputs; + int r; + double d; + + switch (mode) { + case PROGRAM_MODE_RESET: + lifespan = LIBCOOPGAMMA_REMOVE; + break; + case PROGRAM_MODE_ONE_SHOT: + case PROGRAM_MODE_MANUAL: + lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; + break; + default: + lifespan = LIBCOOPGAMMA_UNTIL_DEATH; + break; + } + + free(state->methods); + state->methods = NULL; + + /* Connect to server */ + if (unblocked_signal(SIGCHLD, &signal_blockage) < 0) + return -1; + if (libcoopgamma_connect(state->method, state->site, &state->ctx) < 0) { + if (errno) + perror("libcoopgamma_connect"); + else + fprintf(stderr, _("libcoopgamma_connect: could not " + "start coopgamma server\n")); + if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) + exit(EXIT_FAILURE); + return -1; + } + if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) + return -1; + free(state->method); + state->method = NULL; + free(state->site); + state->site = NULL; + + /* Get available outputs */ + outputs = libcoopgamma_get_crtcs_sync(&state->ctx); + for (n_outputs = 0; outputs[n_outputs]; n_outputs++); + + /* List available output if edid=list was used */ + if (state->list_outputs) { + if (outputs == NULL) { + print_error(state); + return -1; + } + printf(_("Available outputs:\n")); + for (i = 0; outputs[i]; i++) + printf(" %s\n", outputs[i]); + if (ferror(stdout)) { + perror("printf"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + + /* Translate crtc=N to edid=EDID */ + for (i = 0; i < state->n_outputs; i++) { + if (state->outputs[i].edid != NULL) + continue; + if (state->outputs[i].index >= n_outputs) { + fprintf(stderr, _("monitor number %zu does not exist," + "available monitors are [0, %zu]\n"), + state->outputs[i].index, n_outputs - 1); + return -1; + } + state->outputs[i].edid = strdup(outputs[state->outputs[i].index]); + if (state->outputs[i].edid == NULL) { + perror("strdup"); + return -1; + } + } + + /* Use all outputs if none were specified */ + if (state->n_outputs == 0) { + state->n_outputs = state->a_outputs = n_outputs; + state->outputs = malloc(n_outputs * sizeof(*state->outputs)); + if (state->outputs == NULL) { + perror("malloc"); + return -1; + } + for (i = 0; i < n_outputs; i++) { + state->outputs[i].edid = strdup(outputs[i]); + if (state->outputs[i].edid == NULL) { + perror("strdup"); + return -1; + } + } + } + + free(outputs); + + /* Initialise information for each output */ + state->crtcs = calloc(state->n_outputs, sizeof(*state->crtcs)); + if (state->crtcs == NULL) { + perror("calloc"); + return -1; + } + for (i = 0; i < state->n_outputs; i++) { + libcoopgamma_crtc_info_t info; + coopgamma_crtc_state_t *crtc = state->crtcs + state->n_crtcs; + + crtc->filter.priority = state->priority; + crtc->filter.crtc = state->outputs[i].edid; + crtc->filter.class = PACKAGE "::redshift::standard"; + crtc->filter.lifespan = lifespan; + + if (libcoopgamma_get_gamma_info_sync(crtc->filter.crtc, &info, &state->ctx) < 0) { + int saved_errno = errno; + fprintf(stderr, _("failed to retrieve information for output `%s':\n"), + outputs[i]); + errno = saved_errno; + print_error(state); + return -1; + } + if (!info.cooperative) { + fprintf(stderr, _("coopgamma is not available\n")); + return -1; + } + if (info.supported == LIBCOOPGAMMA_NO) { + fprintf(stderr, _("output `%s' does not support gamma " + "adjustments, skipping\n"), outputs[i]); + continue; + } + + /* Get total size of the ramps */ + switch (info.depth) { +#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\ + case DEPTH:\ + crtc->rampsize = sizeof(TYPE);\ + break; + LIST_RAMPS_STOP_VALUE_TYPES +#undef X + default: + if (info.depth > 0) + fprintf(stderr, _("output `%s' uses an unsupported depth " + "for its gamma ramps: %i bits, skipping\n"), + outputs[i], info.depth); + else + fprintf(stderr, _("output `%s' uses an unrecognised depth, " + "for its gamma ramps, with the code %i, " + "skipping\n"), outputs[i], info.depth); + continue; + } + crtc->rampsize *= info.red_size + info.green_size + info.blue_size; + + crtc->filter.depth = info.depth; + crtc->filter.ramps.u8.red_size = info.red_size; + crtc->filter.ramps.u8.green_size = info.green_size; + crtc->filter.ramps.u8.blue_size = info.blue_size; + crtc->plain_ramps.u8.red_size = info.red_size; + crtc->plain_ramps.u8.green_size = info.green_size; + crtc->plain_ramps.u8.blue_size = info.blue_size; + + /* Initialise plain ramp and working ramp */ +#define float f +#define double d + switch (info.depth) { +#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\ + case DEPTH:\ + r = libcoopgamma_ramps_initialise(&crtc->filter.ramps.SUFFIX);\ + if (r < 0) {\ + perror("libcoopgamma_ramps_initialise");\ + return -1;\ + }\ + r = libcoopgamma_ramps_initialise(&crtc->plain_ramps.SUFFIX);\ + if (r < 0) {\ + perror("libcoopgamma_ramps_initialise");\ + return -1;\ + }\ + for (j = 0; j < crtc->plain_ramps.SUFFIX.red_size; j++) {\ + d = j;\ + d /= crtc->plain_ramps.SUFFIX.red_size;\ + crtc->plain_ramps.SUFFIX.red[j] = d * TRUE_MAX;\ + }\ + for (j = 0; j < crtc->plain_ramps.SUFFIX.green_size; j++) {\ + d = j;\ + d /= crtc->plain_ramps.SUFFIX.green_size;\ + crtc->plain_ramps.SUFFIX.green[j] = d * TRUE_MAX;\ + }\ + for (j = 0; j < crtc->plain_ramps.SUFFIX.blue_size; j++) {\ + d = j;\ + d /= crtc->plain_ramps.SUFFIX.blue_size;\ + crtc->plain_ramps.SUFFIX.blue[j] = d * TRUE_MAX;\ + }\ + break; + LIST_RAMPS_STOP_VALUE_TYPES +#undef X + default: + abort(); + } +#undef float +#undef double + + state->outputs[i].edid = NULL; + state->n_crtcs++; + } + + free(state->outputs); + state->outputs = NULL; + state->n_outputs = 0; + + return 0; +} + +static void +coopgamma_free(coopgamma_state_t *state) +{ + free(state->methods); + state->methods = NULL; + free(state->method); + state->method = NULL; + free(state->site); + state->site = NULL; + + while (state->n_crtcs--) { + state->crtcs[state->n_crtcs].filter.class = NULL; + libcoopgamma_filter_destroy(&state->crtcs[state->n_crtcs].filter); + libcoopgamma_ramps_destroy(&state->crtcs[state->n_crtcs].plain_ramps); + } + state->n_crtcs = 0; + free(state->crtcs); + state->crtcs = NULL; + + libcoopgamma_context_destroy(&state->ctx, 1); + while (state->n_outputs--) + free(state->outputs[state->n_outputs].edid); + state->n_outputs = 0; + free(state->outputs); + state->outputs = NULL; +} + +static void +coopgamma_print_help(FILE *f) +{ + fputs(_("Adjust gamma ramps with coopgamma.\n"), f); + fputs("\n", f); + + /* TRANSLATORS: coopgamma help output + left column must not be translated */ + fputs(_(" edid=EDID \tEDID of monitor to apply adjustments to, enter " + "`list' to list available monitors\n" + " crtc=N \tIndex of CRTC to apply adjustments to\n" + " priority=N \tThe application order of the adjustments, " + "default value is 576460752303423488.\n" + " method=METHOD \tUnderlaying adjustment method, enter " + "`list' to list available methods\n" + " display=DISPLAY\tThe display to apply adjustments to\n"), + f); + fputs("\n", f); +} + +static int +coopgamma_set_option(coopgamma_state_t *state, const char *key, const char *value) +{ + size_t i; + char *end; + long long int priority; + + if (!strcasecmp(key, "priority")) { + errno = 0; + priority = strtoll(value, &end, 10); + if (errno || *end || priority < INT64_MIN || priority > INT64_MAX) { + fprintf(stderr, _("value of method parameter `crtc' " + "must be a integer in [%lli, %lli]\n"), + (long long int)INT64_MIN, (long long int)INT64_MAX); + return -1; + } + state->priority = priority; + } else if (!strcasecmp(key, "method")) { + if (state->method != NULL) { + fprintf(stderr, _("method parameter `method' " + "can only be used once\n")); + return -1; + } + if (!strcasecmp(value, "list")) { + /* TRANSLATORS: coopgamma help output + the word "coopgamma" must not be translated */ + printf(_("Available adjustment methods for coopgamma:\n")); + for (i = 0; state->methods[i]; i++) + printf(" %s\n", state->methods[i]); + if (ferror(stdout)) { + perror("printf"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + state->method = strdup(value); + if (state->method == NULL) { + perror("strdup"); + return -1; + } + } else if (!strcasecmp(key, "display")) { + if (state->site != NULL) { + fprintf(stderr, _("method parameter `display' " + "can only be used once\n")); + return -1; + } + state->site = strdup(value); + if (state->site == NULL) { + perror("strdup"); + return -1; + } + } else if (!strcasecmp(key, "edid") || !strcasecmp(key, "crtc")) { + if (state->n_outputs == state->a_outputs) { + state->a_outputs += 8; + state->outputs = realloc(state->outputs, + state->a_outputs * sizeof(*state->outputs)); + if (state->outputs == NULL) { + perror("realloc"); + return -1; + } + } + if (!strcasecmp(key, "edid")) { + state->outputs[state->n_outputs].edid = strdup(value); + if (state->outputs[state->n_outputs].edid == NULL) { + perror("strdup"); + return -1; + } + if (!strcasecmp(state->outputs[state->n_outputs].edid, "list")) + state->list_outputs = 1; + } else { + state->outputs[state->n_outputs].edid = NULL; + errno = 0; + state->outputs[state->n_outputs].index = (size_t)strtoul(value, &end, 10); + if (!*end && errno == ERANGE && + state->outputs[state->n_outputs].index == SIZE_MAX) { + state->outputs[state->n_outputs].index = SIZE_MAX; + } else if (errno || *end) { + fprintf(stderr, _("value of method parameter `crtc' " + "must be a non-negative integer\n")); + return -1; + } + } + state->n_outputs++; + } else { + fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key); + return -1; + } + + return 0; +} + +static void +coopgamma_restore(coopgamma_state_t *state) +{ + size_t i; + for (i = 0; i < state->n_crtcs; i++) + state->crtcs[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; + update(state); + for (i = 0; i < state->n_crtcs; i++) + state->crtcs[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; +} + +static int +coopgamma_set_temperature(coopgamma_state_t *state, const color_setting_t *setting) +{ + libcoopgamma_filter_t *filter; + libcoopgamma_filter_t *last_filter = NULL; + size_t i; + + for (i = 0; i < state->n_crtcs; i++, last_filter = filter) { + filter = &state->crtcs[i].filter; + + /* Copy ramps for previous CRTC if its ramps is of same size and depth */ + if (last_filter != NULL && + last_filter->ramps.u8.red_size == filter->ramps.u8.red_size && + last_filter->ramps.u8.green_size == filter->ramps.u8.green_size && + last_filter->ramps.u8.blue_size == filter->ramps.u8.blue_size) { + memcpy(filter->ramps.u8.red, last_filter->ramps.u8.red, + state->crtcs[i].rampsize); + continue; + } + + /* Otherwise, create calculate the ramps */ + memcpy(filter->ramps.u8.red, state->crtcs[i].plain_ramps.u8.red, + state->crtcs[i].rampsize); + switch (filter->depth) { +#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\ + case DEPTH:\ + colorramp_fill_##SUFFIX((void *)(filter->ramps.u8.red),\ + (void *)(filter->ramps.u8.green),\ + (void *)(filter->ramps.u8.blue),\ + filter->ramps.u8.red_size,\ + filter->ramps.u8.green_size,\ + filter->ramps.u8.blue_size,\ + setting);\ + break; + LIST_RAMPS_STOP_VALUE_TYPES +#undef X + default: + abort(); + } + } + + return update(state); +} + + +const gamma_method_t coopgamma_gamma_method = { + "coopgamma", 1, + (gamma_method_init_func *)coopgamma_init, + (gamma_method_start_func *)coopgamma_start, + (gamma_method_free_func *)coopgamma_free, + (gamma_method_print_help_func *)coopgamma_print_help, + (gamma_method_set_option_func *)coopgamma_set_option, + (gamma_method_restore_func *)coopgamma_restore, + (gamma_method_set_temperature_func *)coopgamma_set_temperature +}; diff --git a/src/gamma-coopgamma.h b/src/gamma-coopgamma.h new file mode 100644 index 0000000..a46f863 --- /dev/null +++ b/src/gamma-coopgamma.h @@ -0,0 +1,29 @@ +/* gamma-coopgamma.h -- coopgamma gamma adjustment header + This file is part of Redshift. + + Redshift is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Redshift is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Redshift. If not, see <http://www.gnu.org/licenses/>. + + Copyright (c) 2016, 2025 Mattias Andrée <m@maandree.se> +*/ + +#ifndef REDSHIFT_GAMMA_COOPGAMMA_H +#define REDSHIFT_GAMMA_COOPGAMMA_H + +#include <libcoopgamma.h> + +#include "redshift.h" + +extern const gamma_method_t coopgamma_gamma_method; + +#endif /* ! REDSHIFT_GAMMA_COOPGAMMA_H */ diff --git a/src/gamma-drm.c b/src/gamma-drm.c index 088957d..dec7074 100644 --- a/src/gamma-drm.c +++ b/src/gamma-drm.c @@ -85,7 +85,7 @@ drm_init(drm_state_t **state) } static int -drm_start(drm_state_t *state) +drm_start(drm_state_t *state, program_mode_t mode) { /* Acquire access to a graphics card. */ long maxlen = strlen(DRM_DIR_NAME) + strlen(DRM_DEV_NAME) + 10; @@ -277,7 +277,7 @@ drm_set_temperature( drm_state_t *state, const color_setting_t *setting, int preserve) { drm_crtc_state_t *crtcs = state->crtcs; - int last_gamma_size = 0; + uint32_t last_gamma_size = 0; uint16_t *r_gamma = NULL; uint16_t *g_gamma = NULL; uint16_t *b_gamma = NULL; @@ -303,16 +303,16 @@ drm_set_temperature( } /* Initialize gamma ramps to pure state */ - int ramp_size = crtcs->gamma_size; - for (int i = 0; i < ramp_size; i++) { + uint32_t ramp_size = crtcs->gamma_size; + for (uint32_t 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); + colorramp_fill_u16(r_gamma, g_gamma, b_gamma, crtcs->gamma_size, + crtcs->gamma_size, crtcs->gamma_size, setting); drmModeCrtcSetGamma(state->fd, crtcs->crtc_id, crtcs->gamma_size, r_gamma, g_gamma, b_gamma); } diff --git a/src/gamma-dummy.c b/src/gamma-dummy.c index 1730743..559fcea 100644 --- a/src/gamma-dummy.c +++ b/src/gamma-dummy.c @@ -42,7 +42,7 @@ gamma_dummy_init(void **state) } static int -gamma_dummy_start(void *state) +gamma_dummy_start(void *state, program_mode_t mode) { fputs(_("WARNING: Using dummy gamma method! Display will not be affected by this gamma method.\n"), stderr); return 0; diff --git a/src/gamma-quartz.c b/src/gamma-quartz.c index adbf823..74ceaf0 100644 --- a/src/gamma-quartz.c +++ b/src/gamma-quartz.c @@ -62,7 +62,7 @@ quartz_init(quartz_state_t **state) } static int -quartz_start(quartz_state_t *state) +quartz_start(quartz_state_t *state, program_mode_t mode) { CGError error; uint32_t display_count; @@ -221,7 +221,7 @@ quartz_set_temperature_for_display( } colorramp_fill_float(gamma_r, gamma_g, gamma_b, ramp_size, - setting); + ramp_size, ramp_size, setting); CGError error = CGSetDisplayTransferByTable(display, ramp_size, diff --git a/src/gamma-randr.c b/src/gamma-randr.c index 388f322..358ab58 100644 --- a/src/gamma-randr.c +++ b/src/gamma-randr.c @@ -118,7 +118,7 @@ randr_init(randr_state_t **state) } static int -randr_start(randr_state_t *state) +randr_start(randr_state_t *state, program_mode_t mode) { xcb_generic_error_t *error; @@ -425,8 +425,8 @@ randr_set_temperature_for_crtc( } } - colorramp_fill(gamma_r, gamma_g, gamma_b, ramp_size, - setting); + colorramp_fill_u16(gamma_r, gamma_g, gamma_b, ramp_size, + ramp_size, ramp_size, setting); /* Set new gamma ramps */ xcb_void_cookie_t gamma_set_cookie = diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c index e604c3b..1ea585e 100644 --- a/src/gamma-vidmode.c +++ b/src/gamma-vidmode.c @@ -70,7 +70,7 @@ vidmode_init(vidmode_state_t **state) } static int -vidmode_start(vidmode_state_t *state) +vidmode_start(vidmode_state_t *state, program_mode_t mode) { int r; int screen_num = state->screen_num; @@ -218,8 +218,8 @@ vidmode_set_temperature( } } - colorramp_fill(gamma_r, gamma_g, gamma_b, state->ramp_size, - setting); + colorramp_fill_u16(gamma_r, gamma_g, gamma_b, state->ramp_size, + state->ramp_size, state->ramp_size, setting); /* Set new gamma ramps */ r = XF86VidModeSetGammaRamp(state->display, state->screen_num, diff --git a/src/gamma-w32gdi.c b/src/gamma-w32gdi.c index 730cd0c..da5461e 100644 --- a/src/gamma-w32gdi.c +++ b/src/gamma-w32gdi.c @@ -62,7 +62,7 @@ w32gdi_init(w32gdi_state_t **state) } static int -w32gdi_start(w32gdi_state_t *state) +w32gdi_start(w32gdi_state_t *state, program_mode_t mode) { BOOL r; @@ -200,8 +200,8 @@ w32gdi_set_temperature( } } - colorramp_fill(gamma_r, gamma_g, gamma_b, GAMMA_RAMP_SIZE, - setting); + colorramp_fill_u16(gamma_r, gamma_g, gamma_b, GAMMA_RAMP_SIZE, + GAMMA_RAMP_SIZE, GAMMA_RAMP_SIZE, setting); /* Set new gamma ramps */ r = FALSE; diff --git a/src/redshift.c b/src/redshift.c index b880457..d2e79f6 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -75,6 +75,10 @@ int poll(struct pollfd *fds, int nfds, int timeout) { abort(); return -1; } #include "gamma-dummy.h" +#ifdef ENABLE_COOPGAMMA +# include "gamma-coopgamma.h" +#endif + #ifdef ENABLE_DRM # include "gamma-drm.h" #endif @@ -129,7 +133,6 @@ int poll(struct pollfd *fds, int nfds, int timeout) { abort(); return -1; } /* Length of fade in numbers of short sleep durations. */ #define FADE_LENGTH 40 - /* Names of periods of day */ static const char *period_names[] = { /* TRANSLATORS: Name printed when period of day is unknown */ @@ -411,8 +414,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) +method_try_start(const gamma_method_t *method, gamma_state_t **state, + program_mode_t mode, config_ini_state_t *config, char *args) { int r; @@ -477,7 +480,7 @@ method_try_start(const gamma_method_t *method, } /* Start method. */ - r = method->start(*state); + r = method->start(*state, mode); if (r < 0) { method->free(*state); fprintf(stderr, _("Failed to start adjustment method %s.\n"), @@ -907,6 +910,9 @@ main(int argc, char *argv[]) /* List of gamma methods. */ const gamma_method_t gamma_methods[] = { +#ifdef ENABLE_COOPGAMMA + coopgamma_gamma_method, +#endif #ifdef ENABLE_DRM drm_gamma_method, #endif @@ -1130,7 +1136,7 @@ main(int argc, char *argv[]) if (options.method != NULL) { /* Use method specified on command line. */ r = method_try_start( - options.method, &method_state, &config_state, + options.method, &method_state, options.mode, &config_state, options.method_args); if (r < 0) exit(EXIT_FAILURE); } else { @@ -1140,7 +1146,7 @@ main(int argc, char *argv[]) if (!m->autostart) continue; r = method_try_start( - m, &method_state, &config_state, NULL); + m, &method_state, options.mode, &config_state, NULL); if (r < 0) { fputs(_("Trying next method...\n"), stderr); continue; diff --git a/src/redshift.h b/src/redshift.h index 0282d83..896ee28 100644 --- a/src/redshift.h +++ b/src/redshift.h @@ -82,7 +82,7 @@ typedef struct { typedef struct gamma_state gamma_state_t; typedef int gamma_method_init_func(gamma_state_t **state); -typedef int gamma_method_start_func(gamma_state_t *state); +typedef int gamma_method_start_func(gamma_state_t *state, program_mode_t mode); typedef void gamma_method_free_func(gamma_state_t *state); typedef void gamma_method_print_help_func(FILE *f); typedef int gamma_method_set_option_func(gamma_state_t *state, const char *key, |