aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-03-23 18:14:28 +0100
committerMattias Andrée <m@maandree.se>2025-03-23 18:14:28 +0100
commit9f5051694fa0a5bf7f7555514ae1c45254419c38 (patch)
treec8c8ce4667b1af75d6cd9a70ce16766957445b7b
parentRestore support for preserve-gamma, with corrected order of application (diff)
downloadredshift-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--README26
-rw-r--r--TODO5
-rw-r--r--redshift.154
-rw-r--r--src/backend-direct.c156
-rw-r--r--src/common.h10
5 files changed, 243 insertions, 8 deletions
diff --git a/README b/README
index 2296fba..d75353a 100644
--- a/README
+++ b/README
@@ -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).
diff --git a/TODO b/TODO
index 237f850..27a9418 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/redshift.1 b/redshift.1
index 544cb8e..54a971c 100644
--- a/redshift.1
+++ b/redshift.1
@@ -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
*