diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-23 18:14:28 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-23 18:14:28 +0100 |
commit | 9f5051694fa0a5bf7f7555514ae1c45254419c38 (patch) | |
tree | c8c8ce4667b1af75d6cd9a70ce16766957445b7b | |
parent | Restore support for preserve-gamma, with corrected order of application (diff) | |
download | redshift-ng-9f5051694fa0a5bf7f7555514ae1c45254419c38.tar.gz redshift-ng-9f5051694fa0a5bf7f7555514ae1c45254419c38.tar.bz2 redshift-ng-9f5051694fa0a5bf7f7555514ae1c45254419c38.tar.xz |
Add support for output selection by EDID
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r-- | README | 26 | ||||
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | redshift.1 | 54 | ||||
-rw-r--r-- | src/backend-direct.c | 156 | ||||
-rw-r--r-- | src/common.h | 10 |
5 files changed, 243 insertions, 8 deletions
@@ -322,6 +322,12 @@ STDOUT The list is terminated by an empty line. Additional information for human users is printed after the empty line. + When "list" is specified for the "edid" suboption to "-m", a list + of available monitors will be printed to the standard output, + with the header "Available outputs:\n", in the format + + "%s%s\n", <arbitrary whitespace>, <monitor identifier>. + When "-m method:help", "-l provider:help", or "-h" is specified help information is printed on in unspecified format, intended only for human users. @@ -620,6 +626,16 @@ EXTENDED DESCRIPTION The index of the first CRTC is 0. + edid = name list or list + Comma-separated (,) list of EDIDs of monitors to apply + adjustments to. + + If "list" is specified, all available EDIDs will be + printed to the standard output and the program exits. + + This list must not be empty; to select all monitors, + instead specify crtc=all. + Options for the location provider "vidmode" (fallback method for X) are: display = name @@ -645,6 +661,16 @@ EXTENDED DESCRIPTION The index of the first CRTC is 0. + edid = name list or list + Comma-separated (,) list of EDIDs of monitors to apply + adjustments to. + + If "list" is specified, all available EDIDs will be + printed to the standard output and the program exits. + + This list must not be empty; to select all monitors, + instead specify crtc=all. + There are no options for the adjustment methods "wingdi" (available on Windows), "quartz" (available on Mac OS X), and "dummy" (used for debugging, does not apply any colour effects). @@ -147,3 +147,8 @@ Document option delimiter for -l and -m Add support for selecting multiple screens Add support for prefixing CRTC with screen/card number (e.g. "1.2" for CRTC 2 on screen 1) Properly document how provider/method options are separated +The method option "display" requires support for ":", use ";" delimit after "display" + ":" cannot be changed to ";" for all options are this would break backwards + compatibility; however ";" could be supported in addition to ":" for all options +remove FILE argument for print_help +print, for use by frontends, what mode redshift was started in @@ -459,6 +459,24 @@ The list is terminated by an empty line. Additional information for human users is printed after the empty line. .PP When +.B list +is specified for the +.B edid +suboption to +.BR -m , +a list of available monitors will be printed to the standard output, +with the header +.BR "\(dqAvailable outputs:\en\(dq" , +in the format +.RS +.nf + +\fB\(dq%s%s\en\(dq, \fI<arbitrary whitespace>\fP, \fP<monitor identifier>\fR. + +.fi +.RE +.PP +When .BR "-m method:help" , .BR "-l provider:help" , or @@ -943,7 +961,9 @@ X screen to apply adjustments to. All will be used if not specified. .TP .BI crtc\fR\ =\ "integer list or " all -Comma-separated (,) list of CRTC indices for monitors to +Comma-separated +.RB ( , ) +list of CRTC indices for monitors to apply adjustments to. All available CRTCs are used if the list is empty or if the setting is omitted. @@ -951,6 +971,20 @@ list is empty or if the setting is omitted. may be specified as a synonym for an empty list. The index of the first CRTC is 0. +.TP +.BI edid\fR\ =\ "name list or " list +Comma-separated +.RB ( , ) +list of EDIDs of monitors to apply adjustments to. + +If +.B list +is specified, all available EDIDs will be +printed to the standard output and the program exits. + +This list must not be empty; to select all monitors, +instead specify +.BR crtc=all . .PP Options for the location provider .B vidmode @@ -973,7 +1007,9 @@ Options for the location provider Index of graphics card to apply adjustments to. .TP .BI crtc\fR\ =\ "integer list or " all -Comma-separated (,) list of CRTC indices for monitors to +Comma-separated +.RB ( , ) +list of CRTC indices for monitors to apply adjustments to. All available CRTCs are used if the list is empty or if the setting is omitted. @@ -981,6 +1017,20 @@ list is empty or if the setting is omitted. may be specified as a synonym for an empty list. The index of the first CRTC is 0. +.TP +.BI edid\fR\ =\ "name list or " list +Comma-separated +.RB ( , ) +list of EDIDs of monitors to apply adjustments to. + +If +.B list +is specified, all available EDIDs will be +printed to the standard output and the program exits. + +This list must not be empty; to select all monitors, +instead specify +.BR crtc=all . .PP There are no options for the adjustment methods .B wingdi diff --git a/src/backend-direct.c b/src/backend-direct.c index ea60676..62fe2fa 100644 --- a/src/backend-direct.c +++ b/src/backend-direct.c @@ -93,6 +93,12 @@ struct gamma_state { struct libgamma_site_state site; /** + * Whether the adjustment method supports fetching + * EDIDs from the outputs + */ + unsigned supports_edid : 1; + + /** * Whether the adjustment method supports multiple * sites rather than just the default site */ @@ -146,6 +152,11 @@ struct gamma_state { size_t ncrtcs; /** + * Number of selected EDIDs + */ + size_t nedids; + + /** * Number of selected parition */ size_t npartitions; @@ -158,6 +169,13 @@ struct gamma_state { size_t *selected_crtcs; /** + * Selected EDIDs + * + * Deallocated by when no longer needed + */ + char **selected_edids; + + /** * Name of site to connect to, `NULL` if not selected * or once connected to the site */ @@ -200,6 +218,7 @@ direct_create(struct gamma_state **state_out, int method, const char *method_nam state->partitions = NULL; state->site_name = NULL; state->method = method; + state->supports_edid = (caps.crtc_information & LIBGAMMA_CRTC_INFO_EDID) ? 1 : 0; state->multiple_sites = caps.multiple_sites; state->multiple_partitions = caps.multiple_partitions; state->multiple_crtcs = caps.multiple_crtcs; @@ -242,6 +261,9 @@ direct_print_help(FILE *f, int method) if (caps.multiple_crtcs) fprintf(f, " crtc=%s %s\n", _("N "), _("List of comma-separated CRTCs to apply adjustments to")); + if (caps.multiple_crtcs && (caps.crtc_information & LIBGAMMA_CRTC_INFO_EDID)) + fprintf(f, " edid=%s %s\n", _("EDID "), _("List of comma-separated EDIDS of monitors to apply " + "adjustments to, enter `list' to list available monitors")); if (caps.multiple_sites || caps.multiple_partitions || caps.multiple_crtcs) fprintf(f, "\n"); @@ -257,6 +279,8 @@ direct_set_option(struct gamma_state *state, const char *key, const char *value) return direct_set_partitions(state, key, value); } else if (state->multiple_crtcs && !strcasecmp(key, "crtc")) { return direct_set_crtcs(state, key, value); + } else if (state->multiple_crtcs && state->supports_edid && !strcasecmp(key, "edid")) { + return direct_set_edids(state, key, value); } else if (!strcasecmp(key, "preserve")) { weprintf(_("Deprecated method parameter ignored: `%s'."), key); return 0; @@ -294,8 +318,10 @@ direct_set_partitions(struct gamma_state *state, const char *key, const char *va errno = 0; num = strtoumax(value, (void *)&end, 10); state->selected_partition = (size_t)num; - if (num > (uintmax_t)SIZE_MAX || *end || !isdigit(*value) || errno) - eprintf(_("Invalid value of `%s' option: `%s'."), key, value); + if (num > (uintmax_t)SIZE_MAX || *end || !isdigit(*value) || errno) { + weprintf(_("Invalid value of `%s' option: `%s'."), key, value); + return -1; + } return 0; } @@ -331,8 +357,10 @@ direct_set_crtcs(struct gamma_state *state, const char *key, const char *value) for (p = value; *p; p = end) { num = strtoumax(p, (void *)&end, 10); state->selected_crtcs[state->ncrtcs++] = (size_t)num; - if (num > (uintmax_t)SIZE_MAX || (*end && *end != ',') || !isdigit(*p) || errno) - eprintf(_("Invalid value of `%s' option: `%s'."), key, value); + if (num > (uintmax_t)SIZE_MAX || (*end && *end != ',') || !isdigit(*p) || errno) { + weprintf(_("Invalid value of `%s' option: `%s'."), key, value); + return -1; + } end = &end[*end == ',']; } @@ -341,13 +369,59 @@ direct_set_crtcs(struct gamma_state *state, const char *key, const char *value) int -direct_start(struct gamma_state *state) +direct_set_edids(GAMMA_STATE *state, const char *key, const char *value) { + const char *end, *p; + size_t count, len; + + /* Check previously unspecified */ + if (state->nedids) { + weprintf(_("`%s' option specified multiple times, using last selection."), key); + while (state->nedids) + free(state->selected_edids[--state->nedids]); + free(state->selected_edids); + state->selected_edids = NULL; + state->nedids = 0; + } + /* Get number count */ + for (p = value, count = 1; *p; p++) + if (*p == ',') + count++; + state->selected_edids = ecalloc(count, sizeof(*state->selected_edids)); + + /* Split */ + for (p = value;; p = end) { + end = strchr(p, ','); + if (!end) { + state->selected_edids[state->nedids++] = estrdup(p); + break; + } + len = (size_t)(end++ - p); + state->selected_edids[state->nedids] = emalloc(len + 1U); + memcpy(state->selected_edids[state->nedids], p, len); + state->selected_edids[state->nedids][len] = '\0'; + state->nedids++; + } + + return 0; +} + + +int +direct_start(struct gamma_state *state) +{ + struct { + size_t partition; + size_t crtc; + char *edid; + } *resolved_edids = NULL; struct libgamma_crtc_information crtc_info; + struct libgamma_crtc_state crtc_state; size_t crtc_num_offset = 0; size_t crtcs_removed = 0; - size_t i, j, k, num, part; + size_t nresolved_edids = 0; + size_t i, j, k, num, part, count; int err; /* Connect to display server */ @@ -402,6 +476,71 @@ direct_start(struct gamma_state *state) crtc_num_offset += state->partitions[i].state.crtcs_available; } + /* Resolve EDIDs */ + if (state->nedids) { + for (i = 0; i < state->npartitions; i++) { + count = state->partitions[i].state.crtcs_available; + if (!count) + continue; + resolved_edids = erealloc(resolved_edids, (nresolved_edids + count) + sizeof(*resolved_edids)); + for (j = 0; j < count; j++) { + if (libgamma_crtc_initialise(&crtc_state, &state->partitions[i].state, j)) + continue; + libgamma_get_crtc_information(&crtc_info, sizeof(crtc_info), &crtc_state, LIBGAMMA_CRTC_INFO_EDID); + if (crtc_info.edid_error) + goto next_crtc; + resolved_edids[nresolved_edids].partition = i; + resolved_edids[nresolved_edids].crtc = j; + resolved_edids[nresolved_edids].edid = libgamma_behex_edid(crtc_info.edid, crtc_info.edid_length); + if (!resolved_edids[nresolved_edids].edid) + eprintf("libgamma_behex_edid:"); + nresolved_edids++; + next_crtc: + libgamma_crtc_information_destroy(&crtc_info); + libgamma_crtc_destroy(&crtc_state); + } + } + for (i = 0; i < state->nedids; i++) { + if (!strcasecmp(state->selected_edids[i], "list")) { + printf(_("Available outputs:\n")); + for (i = 0; i < nresolved_edids; i++) + printf(" %s\n", resolved_edids[i].edid); + direct_free(state); + exit(0); + } + for (j = 0; j < nresolved_edids; j++) { + if (!strcasecmp(state->selected_edids[i], resolved_edids[i].edid)) { + if (!state->multiple_partitions) { + weprintf("Resolved output `%s' to CRTC %zu", + resolved_edids[i].edid, resolved_edids[i].crtc); + } else if (state->partitions_are_graphics_cards) { + weprintf("Resolved output `%s' to CRTC %zu on graphics card %zu", + resolved_edids[i].edid, resolved_edids[i].crtc, + resolved_edids[i].partition); + } else { + weprintf("Resolved output `%s' to CRTC %zu on X screen %zu", + resolved_edids[i].edid, resolved_edids[i].crtc, + resolved_edids[i].partition); + } + num = state->ncrtcs + 1U; + state->selected_crtcs = erealloc(state->selected_crtcs, num * sizeof(*state->crtcs)); + num = state->partitions[resolved_edids[i].partition].crtc_num_offset; + state->selected_crtcs[state->ncrtcs++] = num + resolved_edids[i].crtc; + goto next_edid; + } + } + weprintf(_("Output `%s' found."), state->selected_edids[i]); + next_edid: + free(state->selected_edids[i]); + state->selected_edids[i] = NULL; + } + while (nresolved_edids) + free(resolved_edids[--nresolved_edids].edid); + free(resolved_edids); + free(state->selected_edids); + state->selected_edids = NULL; + } + /* Allocate CRTCs states and map to partition–CRTC pairs */ if (state->ncrtcs) { state->crtcs = ecalloc(state->ncrtcs, sizeof(*state->crtcs)); @@ -710,6 +849,11 @@ direct_free(struct gamma_state *state) free(state->partitions); } free(state->selected_crtcs); + if (state->selected_edids) { + for (i = 0; i < state->nedids; i++) + free(state->selected_edids[i]); + free(state->selected_edids); + } if (state->connected) libgamma_site_destroy(&state->site); free(state->site_name); diff --git a/src/common.h b/src/common.h index e6e1339..1b352f2 100644 --- a/src/common.h +++ b/src/common.h @@ -1250,6 +1250,16 @@ int direct_set_partitions(GAMMA_STATE *state, const char *key, const char *value int direct_set_crtcs(GAMMA_STATE *state, const char *key, const char *value); /** + * Select EDIDs of outputs to apply adjustments to using direct gamma adjustments + * + * @param state State object for the adjustment method + * @param key Option to configure + * @param value Option value to set + * @return 0 on success, -1 on failure + */ +int direct_set_edids(GAMMA_STATE *state, const char *key, const char *value); + +/** * Finalise option-dependent initialisation and connections * for direct gamma adjustments * |