diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-27 18:36:26 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-27 18:36:26 +0100 |
commit | 037b945a9f253b97faffc02d8475574e75203516 (patch) | |
tree | b008e7d77e9daaeaaa8e7854728d715df5aafb77 /src | |
parent | todo list housekeeping (diff) | |
download | redshift-ng-037b945a9f253b97faffc02d8475574e75203516.tar.gz redshift-ng-037b945a9f253b97faffc02d8475574e75203516.tar.bz2 redshift-ng-037b945a9f253b97faffc02d8475574e75203516.tar.xz |
one dir per subproject
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 66 | ||||
-rw-r--r-- | src/arg.h | 379 | ||||
-rw-r--r-- | src/backend-direct.c | 941 | ||||
-rw-r--r-- | src/colour.c | 97 | ||||
-rw-r--r-- | src/common.h | 1690 | ||||
-rw-r--r-- | src/config-ini.c | 267 | ||||
-rw-r--r-- | src/config.c | 1172 | ||||
-rw-r--r-- | src/config.mk | 20 | ||||
-rw-r--r-- | src/gamma-coopgamma.c | 535 | ||||
-rw-r--r-- | src/gamma-drm.c | 51 | ||||
-rw-r--r-- | src/gamma-dummy.c | 89 | ||||
-rw-r--r-- | src/gamma-quartz.c | 51 | ||||
-rw-r--r-- | src/gamma-randr.c | 51 | ||||
-rw-r--r-- | src/gamma-vidmode.c | 51 | ||||
-rw-r--r-- | src/gamma-wingdi.c | 51 | ||||
-rw-r--r-- | src/gamma.c | 139 | ||||
-rw-r--r-- | src/hooks.c | 249 | ||||
-rw-r--r-- | src/location-corelocation.m | 311 | ||||
-rw-r--r-- | src/location-geoclue2.c | 451 | ||||
-rw-r--r-- | src/location-geofile.c | 114 | ||||
-rw-r--r-- | src/location-manual.c | 118 | ||||
-rw-r--r-- | src/location-timezone.c | 108 | ||||
-rw-r--r-- | src/location.c | 249 | ||||
-rw-r--r-- | src/redshift.c | 543 | ||||
-rw-r--r-- | src/signals.c | 209 | ||||
-rw-r--r-- | src/util.c | 317 | ||||
-rw-r--r-- | src/windows/appicon.rc | 1 | ||||
-rw-r--r-- | src/windows/redshift.ico | bin | 87891 -> 0 bytes | |||
-rw-r--r-- | src/windows/versioninfo.rc | 20 |
29 files changed, 0 insertions, 8340 deletions
diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 417d001..0000000 --- a/src/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -.POSIX: - -CONFIGFILE = config.mk -include $(CONFIGFILE) - - -VERSION_STRING = redshift-ng 1.13 - - -OBJ =\ - backend-direct.o\ - colour.o\ - config.o\ - config-ini.o\ - gamma.o\ - gamma-coopgamma.o\ - gamma-drm.o\ - gamma-dummy.o\ - gamma-quartz.o\ - gamma-randr.o\ - gamma-vidmode.o\ - gamma-wingdi.o\ - hooks.o\ - location.o\ - location-geoclue2.o\ - location-manual.o\ - location-geofile.o\ - location-timezone.o\ - redshift.o\ - signals.o\ - util.o - - -CPPFLAGS_STRINGS =\ - -D'PACKAGE="$(PACKAGE)"'\ - -D'VERSION_STRING="$(VERSION_STRING)"'\ - -D'LOCALEDIR="$(LOCALEDIR)"' - - -all: redshift -$(OBJ): common.h arg.h - -.c.o: - $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) $(CPPFLAGS_STRINGS) - -redshift: $(OBJ) - $(CC) -o $@ $(OBJ) $(LDFLAGS) - -install: redshift - mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" - mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/" - cp -- redshift "$(DESTDIR)$(PREFIX)/bin/" - cp -- redshift.1 "$(DESTDIR)$(MANPREFIX)/man1/" - -uninstall: - -rm -f -- "$(DESTDIR)$(PREFIX)/bin/redshift" - -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/redshift.1" - -clean: - -rm -f -- *.o *.a *.lo *.su - -rm -f -- redshift - -.SUFFIXES: -.SUFFIXES: .o .c - -.PHONY: all install uninstall clean diff --git a/src/arg.h b/src/arg.h deleted file mode 100644 index 2ff6dfc..0000000 --- a/src/arg.h +++ /dev/null @@ -1,379 +0,0 @@ -/*- - * This file is taken, with some parts removed, from libsimple - * - * ISC License - * - * © 2017, 2018, 2021, 2022, 2023, 2024, 2025 Mattias Andrée <m@maandree.se> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - -/** - * The zeroth command line argument, the name of the process, - * set by the command line parsing macros - */ -extern char *argv0; - - -/** - * Map from a long option to a short option - * - * NB! Long options with optional arguments should - * have to map entries, one where `.long_flag` ends - * with '=' and `.with_arg` is non-zero, and one - * where `.long_flag` does not end with '=' and - * `.with_arg` is zero. These *cannot* have the same - * `.short_flag` - */ -struct longopt { - /** - * The long option, if the value must be attached - * to the flag, this must end with '=' - */ - const char *long_flag; - - /** - * The equivalent short option - * - * The first symbol in the short option - * (normally '-') will be `.long_flag[0]` - */ - char short_flag; - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -#endif - - /** - * Whether the option takes an argument - */ - int with_arg; - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -}; - - -/** - * `ARGBEGIN {} ARGEND;` creates a switch statement - * instead a loop that parses the command line arguments - * according to the POSIX specification for default - * behaviour (extensions of the behaviour is possible) - * - * This macro requires that the variables `argc` and - * `argv` are defined and that `argv[argc]` is `NULL`, - * `argc` shall be a non-negative `int` that tells - * how many elements (all non-`NULL`) are available in - * `argv`, the list of command line arguments - * - * When parsing stops, `argc` and `argv` are updated - * shuch that all parsed arguments are removed; the - * contents of `argv` will not be modified, rather - * the pointer `argv` will be updated to `&argv[n]` - * where `n` is the number of parsed elements in `argv` - * - * Inside `{}` in `ARGBEGIN {} ARGEND;` there user - * shall specify `case` statements for each recognised - * command line option, and `default` for unrecognised - * option. For example: - * - * ARGBEGIN { - * case 'a': - * // handle -a - * break; - * case 'b': - * // handle -b - * break; - * case ARGNUM: - * // handle -0, -1, -2, ..., -9 - * break; - * default: - * // print usage information for other flags - * usage(); - * } ARGEND; - */ -#define ARGBEGIN ARGBEGIN2(1, 0) - -/** - * `SUBARGBEGIN {} ARGEND;` is similar to - * `ARGBEGIN {} ARGEND;`, however, `argv0` - * is not set to `argv[0]`, instead `argv[0]` - * is handled like any other element in `argv` - */ -#define SUBARGBEGIN ARGBEGIN2(0, 0) - -/** - * Flexible alternative to `ARGBEGIN` - * - * @param WITH_ARGV0 If 0, behave like `SUBARGBEGIN`, - * otherwise, behave like `ARGBEGIN` - * @param KEEP_DASHDASH If and only if 0, "--" is not removed - * `argv` before parsing is stopped when it - * is encountered - */ -#define ARGBEGIN2(WITH_ARGV0, KEEP_DASHDASH)\ - do {\ - char flag_, *lflag_, *arg_;\ - int brk_ = 0, again_;\ - size_t i_, n_;\ - if (WITH_ARGV0) {\ - argv0 = *argv;\ - argv += !!argv0;\ - argc -= !!argv0;\ - }\ - (void) arg_;\ - (void) i_;\ - (void) n_;\ - for (; argv[0] && argv[0][0] && argv[0][1]; argc--, argv++) {\ - lflag_ = argv[0];\ - if (argv[0][0] == '-') {\ - if (argv[0][1] == '-' && !argv[0][2]) {\ - if (!(KEEP_DASHDASH))\ - argv++, argc--;\ - break;\ - }\ - for (argv[0]++; argv[0][0]; argv[0]++) {\ - flag_ = argv[0][0];\ - if (flag_ == '-' && &argv[0][-1] != lflag_)\ - usage();\ - arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ - do {\ - again_ = 0;\ - switch (flag_) { - -/** - * Test multiple long options and go to - * corresponding short option case - * - * If the long option is found (see documentation - * for `struct longopt` for details), the keyword - * `break` is used to break the `case` (or `default`), - * and at the next iteration of the parsing loop, the - * case will be `.short_flag` for the entry where the - * argument matched `.long_flag` and `.with_arg` - * - * @param LONGOPTS:struct longopt * The options, list shall end - * with `NULL` as `.long_flag` - */ -#define ARGMAPLONG(LONGOPTS)\ - for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\ - if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\ - flag_ = (LONGOPTS)[i_].short_flag;\ - again_ = 1;\ - break;\ - }\ - }\ - if (again_)\ - break - -/** - * Allows flags to start with another symbol than '-' - * - * Usage example: - * ARGBEGIN { - * case 'a': // handle -a - * break; - * default: - * usage(); - * } ARGALT('+') { - * case 'a': // handle +a - * break; - * default: - * usage(); - * } ARGALT('/') { - * case 'a': // handle /a - * break; - * default: - * usage(); - * } ARGEND; - * - * @param SYMBOL:char The symbol flags should begin with - */ -#define ARGALT(SYMBOL)\ - }\ - } while (again_);\ - if (brk_) {\ - argc -= arg_ == argv[1];\ - argv += arg_ == argv[1];\ - brk_ = 0;\ - break;\ - }\ - }\ - } else if (argv[0][0] == SYMBOL) {\ - if (argv[0][1] == SYMBOL && !argv[0][2])\ - break;\ - for (argv[0]++; argv[0][0]; argv[0]++) {\ - flag_ = argv[0][0];\ - if (flag_ == SYMBOL && &argv[0][-1] != lflag_)\ - usage();\ - arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ - do {\ - again_ = 0;\ - switch (flag_) { - -/** - * Refer to `ARGBEGIN`, `SUBARGBEGIN`, and `ARGBEGIN2` - */ -#define ARGEND\ - }\ - } while (again_);\ - if (brk_) {\ - argc -= arg_ == argv[1];\ - argv += arg_ == argv[1];\ - brk_ = 0;\ - break;\ - }\ - }\ - } else {\ - break;\ - }\ - }\ - } while (0) - - -/** - * `case ARGNUM` creates a switch statement case for each digit - */ -#define ARGNUM '0': case '1': case '2': case '3': case '4':\ - case '5': case '6': case '7': case '8': case '9' - -/** - * Get the flag character, for example in `case 'a'`, - * 'a' is returned - * - * @return :char The option's identifying character - */ -#define FLAG() (flag_) - -/** - * Get the entire argument that is being parsed - * - * Note that an argument can contain multiple options - * and it can contain the last options value but the - * value can also be in the next argument - * - * @return :char * The current command line argument - */ -#define LFLAG() (lflag_) - -/** - * Get the current option's value, if it - * does not have a value, call `usage` - * (which terminates the process) - * - * Using this macro lets the parser knows - * that the option has a value - * - * @return :char * The option's value, never `NULL` - */ -#define ARG() (arg_ ? (brk_ = 1, arg_) : (usage(), NULL)) - -/** - * Get the current option's value, if the option - * does not have a value, `NULL` is returned - * - * Note that the value may appear at the next - * argument (next element in `argv`) which in that - * case is returned - * - * Using this macro lets the parser knows - * that the option has a value - * - * @return :char * The option's value, `NULL` if - * the option does not have a value - */ -#define ARGNULL() (arg_ ? (brk_ = 1, arg_) : NULL) - -/** - * Get the remaining part of the current command - * line argument (element in `argv`) — as well as - * the character that specifies the flag — as the - * value of the argument - * - * Using this macro lets the parser knows - * that the option has a value - * - * Usage example: - * - * char *arg; - * ARGBEGIN { - * case ARGNUM: - * arg = ARGHERE(); - * // `arg` is the number after '-', for example, - * // if the command line contains the argument - * // "-12345", `arg` will be `12345` - * break; - * case 'n': - * arg = &ARGHERE()[1]; - * if (*arg) { - * // flag 'n' has a value (`argv`) - * } else { - * // flag 'n' does not have a value - * } - * default: - * usage(); - * } ARGEND; - * - * @return :char * The option's value include the flag - * character, never `NULL` or "" - */ -#define ARGHERE() (brk_ = 1, argv[0]) - - -/** - * Test if the argument is a specific long option - * - * Example: - * - * ARGBEGIN { - * case 'x': - * handle_dash_x: - * // handle -x - * break; - * case '-': - * if (TESTLONG("--xdev", 0)) - * goto handle_dash_x; - * else - * usage(); - * break; - * default: - * usage(); - * } ARGEND; - * - * @param FLAG:const char * The flag, must end with '=' if the - * value must be attached to the flag, - * must not have side-effects - * @param WARG:int Whether the option takes an argument, - * should not have side-effects - */ -#define TESTLONG(FLG, WARG)\ - ((WARG)\ - ? ((!strncmp(lflag_, (FLG), (n_ = strlen(FLG), n_ -= ((FLG)[n_ - !!n_] == '='))) && lflag_[n_] == '=')\ - ? (lflag_[n_] = '\0',\ - (arg_ = &lflag_[n_ + 1]),\ - (brk_ = 1))\ - : (!strcmp(lflag_, (FLG))\ - ? (argv[1]\ - ? ((arg_ = argv[1]),\ - (brk_ = 1))\ - : (usage(), 0))\ - : 0))\ - : (!strcmp(lflag_, (FLG))\ - ? (brk_ = 1)\ - : 0)) diff --git a/src/backend-direct.c b/src/backend-direct.c deleted file mode 100644 index 9f62c4d..0000000 --- a/src/backend-direct.c +++ /dev/null @@ -1,941 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -/** - * Union of libgamma gamma ramp structures - */ -union gamma_ramps { - /** - * Gamma ramp sizes - */ - struct { - size_t red; /**< Size of the gamma ramp for the red channel */ - size_t green; /**< Size of the gamma ramp for the green channel */ - size_t blue; /**< Size of the gamma ramp for the blue channel */ - } size; - - /* Ramp structures */ -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - struct libgamma_gamma_##RAMPS RAMPS - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X -}; - - -/** - * State for partition (e.g. X screen or graphics card) - */ -struct partition_state { - /** - * libgamma state - */ - struct libgamma_partition_state state; - - /** - * Index of CRTC when indexing spans multiple X screens - */ - size_t crtc_num_offset; -}; - - -/** - * CRTC state - */ -struct crtc_state { - /** - * libgamma state - */ - struct libgamma_crtc_state state; - - /** - * Gamma ramp depth, 0 if uninitialised, - * -1 if single-precision float, - * -2 if double-precision float, - * otherwise the number of bits (of unsigned integer) - */ - signed gamma_depth; - - /** - * Gamma ramps used by the gamma adjustment function - */ - union gamma_ramps gamma_ramps; - - /** - * Original state of gamma ramps - */ - union gamma_ramps saved_gamma_ramps; -}; - - -/** - * CRTC number, either overall number or partion and number within partition - */ -struct crtc_number { - /** - * The partition of the EDID, -1 if using overall ordinal - */ - ssize_t partition; - - /** - * CRTC number within the partition, or overall if no partition is specified - */ - size_t crtc; -}; - - -struct gamma_state { - /** - * libgamma state for the site (e.g. X display) - */ - 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 - */ - unsigned multiple_sites : 1; - - /** - * Whether the adjustment method supports multiple partitions - * per site - */ - unsigned multiple_partitions : 1; - - /** - * Whether the adjustment method supports multiple CRTC:s - * per partition per site - */ - unsigned multiple_crtcs : 1; - - /** - * Whether partitions are graphics cards - */ - unsigned partitions_are_graphics_cards : 1; - - /** - * Whether a parition has been selected - */ - unsigned partitions_selected : 1; - - /** - * Whether CRTCs have been selected - */ - unsigned crtcs_selected : 1; - - /** - * Whether the program has connected to the site - */ - unsigned connected : 1; - - /** - * The libgamma constant for the adjustment method - */ - int method; - - /** - * Number of selected CRTCs - */ - size_t ncrtcs; - - /** - * Number of selected EDIDs - */ - size_t nedids; - - /** - * Number of selected parition - */ - size_t npartitions; - - /** - * Selected paritions (if `partitions_selected`) - */ - size_t *selected_partitions; - - /** - * Selected CRTC numbers - * - * Deallocated by when no longer needed - */ - struct crtc_number *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 - */ - char *site_name; - - /** - * State for selected paritions - */ - struct partition_state *partitions; - - /** - * State for selected CRTCs - */ - struct crtc_state *crtcs; -}; - - -int -direct_create(struct gamma_state **state_out, int method, const char *method_name) -{ - struct libgamma_method_capabilities caps; - struct gamma_state *state; - int err; - - *state_out = NULL; - - if (!libgamma_is_method_available(method)) { - weprintf(_("Adjustment method `%s' is not available"), method_name); - return -1; - } - - err = libgamma_method_capabilities(&caps, sizeof(caps), method); - if (err) { - weprintf("libgamma_method_capabilities %s: %s", libgamma_const_of_method(method), libgamma_strerror(err)); - return -1; - } - - state = *state_out = ecalloc(1, sizeof(**state_out)); - state->selected_crtcs = NULL; - 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; - state->partitions_are_graphics_cards = caps.partitions_are_graphics_cards; - - if (state->multiple_sites) - return 0; - - err = libgamma_site_initialise(&state->site, method, NULL); - if (err) { - weprintf("libgamma_site_initialise %s NULL: %s", libgamma_const_of_method(method), libgamma_strerror(err)); - free(state); - *state_out = NULL; - return -1; - } - - return 0; -} - - -void -direct_print_help(int method) -{ - struct libgamma_method_capabilities caps; - - if (libgamma_method_capabilities(&caps, sizeof(caps), method)) { - printf(_("Adjustment method not available\n")); - printf("\n"); - return; - } - - if (caps.multiple_sites) - printf(" display=%s %s\n", _("NAME "), _("Display server instance to apply adjustments to")); - - if (caps.multiple_partitions && caps.partitions_are_graphics_cards) { - /* TRANSLATORS: "N" represents "ordinal"; right-pad with spaces to preserve display width */ - printf(" card=%s %s\n", _("N "), _("Graphics card to apply adjustments to")); - } else if (caps.multiple_partitions) { - /* TRANSLATORS: "N" represents "ordinal"; right-pad with spaces to preserve display width */ - printf(" screen=%s %s\n", _("N "), _("List of comma-separated X screens to apply adjustments to")); - } - - if (caps.multiple_crtcs) { - /* TRANSLATORS: "N" represents "number"; right-pad with spaces to preserve display width */ - printf(" 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)) { - printf(" 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) - printf("\n"); -} - - -int -direct_set_option(struct gamma_state *state, const char *key, const char *value) -{ - if (state->multiple_sites && !strcasecmp(key, "display")) { - return direct_set_site(state, key, value); - } else if (state->multiple_partitions && !strcasecmp(key, state->partitions_are_graphics_cards ? "card" : "screen")) { - 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; - } else { - weprintf(_("Unknown method parameter: `%s'."), key); - return -1; - } -} - - -int -direct_set_site(struct gamma_state *state, const char *key, const char *value) -{ - if (state->site_name) { - weprintf(_("`%s' option specified multiple times, using last selection."), key); - free(state->site_name); - } - state->site_name = estrdup(value); - return 0; -} - - -int -direct_set_partitions(struct gamma_state *state, const char *key, const char *value) -{ - const char *end, *p; - uintmax_t num; - size_t count; - - /* Check previously unspecified */ - if (state->partitions_selected) - weprintf(_("`%s' option specified multiple times, using last selection."), key); - state->partitions_selected = 1; - - /* Check if all are selected */ - state->npartitions = 0; - free(state->selected_partitions); - state->selected_partitions = NULL; - if (!*value || !strcasecmp(value, "all")) - return 0; - - /* Get number count */ - for (p = value, count = 1; *p; p++) - if (*p == ',') - count++; - state->selected_partitions = ecalloc(count, sizeof(*state->selected_partitions)); - - /* Parse numbers */ - errno = 0; - for (p = value; *p; p = end) { - num = strtoumax(p, (void *)&end, 10); - state->selected_partitions[state->npartitions++] = (size_t)num; - 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 == ',']; - } - - return 0; -} - - -int -direct_set_crtcs(struct gamma_state *state, const char *key, const char *value) -{ - const char *end, *p; - uintmax_t num; - size_t count; - - /* Check previously unspecified */ - if (state->crtcs_selected) - weprintf(_("`%s' option specified multiple times, using last selection."), key); - state->crtcs_selected = 1; - - /* Check if all are selected */ - state->ncrtcs = 0; - free(state->selected_crtcs); - state->selected_crtcs = NULL; - if (!*value || !strcasecmp(value, "all")) - return 0; - - /* Get number count */ - for (p = value, count = 1; *p; p++) - if (*p == ',') - count++; - state->selected_crtcs = ecalloc(count, sizeof(*state->selected_crtcs)); - - /* Parse numbers */ - errno = 0; - for (p = value; *p; p = end) { - num = strtoumax(p, (void *)&end, 10); - state->selected_crtcs[state->ncrtcs].partition = -1; - state->selected_crtcs[state->ncrtcs].crtc = (size_t)num; - if (num > (uintmax_t)SIZE_MAX || (*end && *end != ',' && *end != '.') || !isdigit(*p) || errno) { - invalid: - weprintf(_("Invalid value of `%s' option: `%s'."), key, value); - return -1; - } - if (*end == '.') { - if (!state->multiple_partitions || num > (uintmax_t)SSIZE_MAX) - goto invalid; - state->selected_crtcs[state->ncrtcs].partition = (ssize_t)num; - p = &end[1]; - num = strtoumax(p, (void *)&end, 10); - state->selected_crtcs[state->ncrtcs].crtc = (size_t)num; - if (num > (uintmax_t)SIZE_MAX || (*end && *end != ',') || !isdigit(*p) || errno) - goto invalid; - } - end = &end[*end == ',']; - state->ncrtcs++; - } - - return 0; -} - - -int -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 nresolved_edids = 0; - size_t i, j, k, num, part, count; - int err; - - /* Connect to display server */ - if (state->multiple_sites) { - if (state->site_name && !*state->site_name) { - free(state->site_name); - state->site_name = NULL; - } - err = libgamma_site_initialise(&state->site, state->method, state->site_name); - state->site_name = NULL; - if (err) { - weprintf("libgamma_site_initialise %s %s: %s", - libgamma_const_of_method(state->method), - state->site_name ? state->site_name : "NULL", - libgamma_strerror(err)); - return -1; - } - state->connected = 1; - } - - /* Allocate partition states */ - if (state->npartitions) { - state->partitions = ecalloc(state->npartitions, sizeof(*state->partitions)); - for (i = 0; i < state->npartitions; i++) { - state->partitions[i].state.partition = state->selected_partitions[i]; - state->partitions[i].state.data = NULL; - } - free(state->selected_partitions); - state->selected_partitions = NULL; - } else if (!state->site.partitions_available) { - if (state->partitions_are_graphics_cards) - weprintf(_("No graphics card found.")); - else - weprintf(_("No X screen found.")); - return -1; - } else { - state->npartitions = state->site.partitions_available; - state->partitions = ecalloc(state->npartitions, sizeof(*state->partitions)); - for (i = 0; i < state->npartitions; i++) { - state->partitions[i].state.partition = i; - state->partitions[i].state.data = NULL; - } - } - - /* Map the partition indices in CRTC numbers from indices of selected - * partitions, and allocate partitions specified via CRTC numbers */ - for (i = 0; i < state->ncrtcs; i++) { - if (state->selected_crtcs[i].partition < 0) - continue; - for (j = 0; j < state->npartitions; j++) { - if ((size_t)state->selected_crtcs[i].partition == state->partitions[j].state.partition) { - state->selected_crtcs[i].partition = (ssize_t)j; - break; - } - } - if (j == state->npartitions) { - state->partitions = realloc(state->partitions, (state->npartitions + 1U) * sizeof(*state->partitions)); - state->partitions[state->npartitions].state.partition = (size_t)state->selected_crtcs[i].partition; - state->partitions[state->npartitions].state.data = NULL; - state->npartitions++; - } - } - - /* Initialise partitions */ - for (i = 0; i < state->npartitions; i++) { - num = state->partitions[i].state.partition; - err = libgamma_partition_initialise(&state->partitions[i].state, &state->site, num); - if (err) { - weprintf("libgamma_partition_initialise %zu: %s", num, libgamma_strerror(err)); - return -1; - } - state->partitions[i].crtc_num_offset = crtc_num_offset; - 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); - } - count = state->ncrtcs + 1U; - state->selected_crtcs = erealloc(state->selected_crtcs, count * sizeof(*state->crtcs)); - state->selected_crtcs[state->ncrtcs].partition = (ssize_t)resolved_edids[i].partition; - state->selected_crtcs[state->ncrtcs].crtc = resolved_edids[i].crtc; - state->ncrtcs++; - 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)); - for (i = 0; i < state->ncrtcs; i++) { - state->crtcs[i].state.data = NULL; - state->crtcs[i].state.partition = NULL; - if (state->selected_crtcs[i].partition >= 0) - state->crtcs[i].state.partition = &state->partitions[state->selected_crtcs[i].partition].state; - state->crtcs[i].state.crtc = state->selected_crtcs[i].crtc; - } - for (i = 0; i < state->ncrtcs; i++) { - if (state->crtcs[i].state.partition) - continue; - for (j = 1; j < state->npartitions; j++) - if (state->crtcs[i].state.crtc < state->partitions[j].crtc_num_offset) - break; - state->crtcs[i].state.partition = &state->partitions[j - 1U].state; - state->crtcs[i].state.crtc -= state->partitions[j - 1U].crtc_num_offset; - } - } else if (!crtc_num_offset) { - weprintf(_("No CRTCs found.")); - return -1; - } else { - state->ncrtcs = crtc_num_offset; - state->crtcs = ecalloc(state->ncrtcs, sizeof(*state->crtcs)); - for (j = 0, i = 0; j < state->npartitions; j++) { - for (k = 0; k < state->partitions[j].state.crtcs_available; k++, i++) { - state->crtcs[i].state.data = NULL; - state->crtcs[i].state.partition = &state->partitions[j].state; - state->crtcs[i].state.crtc = k; - } - } - } - - /* Initialise CRTCs and fetch original gamma adjustments */ - for (i = 0; i < state->ncrtcs; i++) { - /* Get CRTC */ - part = state->crtcs[i].state.partition->partition; - num = state->crtcs[i].state.crtc; - err = libgamma_crtc_initialise(&state->crtcs[i].state, state->crtcs[i].state.partition, num); - if (err) { - weprintf("libgamma_crtc_initialise %zu %zu: %s", part, num, libgamma_strerror(err)); - return -1; - } - - /* Get gamma ramp inforamtion for CRTC */ - libgamma_get_crtc_information(&crtc_info, sizeof(crtc_info), &state->crtcs[i].state, - LIBGAMMA_CRTC_INFO_GAMMA_SIZE | - LIBGAMMA_CRTC_INFO_GAMMA_DEPTH | - LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); - if (crtc_info.gamma_size_error || crtc_info.gamma_depth_error) { - libgamma_crtc_destroy(&state->crtcs[i].state); - state->crtcs[i].state.data = NULL; - crtcs_removed++; - goto no_gamma_support; - } - if (!crtc_info.gamma_support_error && crtc_info.gamma_support == LIBGAMMA_NO) { - no_gamma_support: - if (state->multiple_crtcs) { - if (!state->multiple_partitions) - weprintf(_("Adjustments are not supported on CRTC %zu."), num); - else if (state->partitions_are_graphics_cards) - weprintf(_("Adjustments are not supported on CRTC %zu on graphics card %zu."), num, part); - else - weprintf(_("Adjustments are not supported on CRTC %zu on X screen %zu."), num, part); - } else { - if (!state->multiple_partitions) - weprintf(_("Adjustments are not supported.")); - else if (state->partitions_are_graphics_cards) - weprintf(_("Adjustments are not supported on graphics card %zu."), part); - else - weprintf(_("Adjustments are not supported on X screen %zu."), part); - } - if (!state->crtcs[i].state.data) - goto next; - } - - /* Initialise and fetch gamma adjustments */ - state->crtcs[i].gamma_ramps.size.red = crtc_info.red_gamma_size; - state->crtcs[i].gamma_ramps.size.green = crtc_info.green_gamma_size; - state->crtcs[i].gamma_ramps.size.blue = crtc_info.blue_gamma_size; - state->crtcs[i].saved_gamma_ramps.size.red = crtc_info.red_gamma_size; - state->crtcs[i].saved_gamma_ramps.size.green = crtc_info.green_gamma_size; - state->crtcs[i].saved_gamma_ramps.size.blue = crtc_info.blue_gamma_size; - switch (crtc_info.gamma_depth) { -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - if (libgamma_gamma_##RAMPS##_initialise(&state->crtcs[i].gamma_ramps.RAMPS) ||\ - libgamma_gamma_##RAMPS##_initialise(&state->crtcs[i].saved_gamma_ramps.RAMPS))\ - eprintf("libgamma_gamma_"#RAMPS"_initialise:");\ - j = 0;\ - do {\ - err = libgamma_crtc_get_gamma_##RAMPS(&state->crtcs[i].state,\ - &state->crtcs[i].saved_gamma_ramps.RAMPS);\ - } while (err && j++ < 10);\ - if (!err) {\ - state->crtcs[i].gamma_depth = DEPTH;\ - break;\ - }\ - if (state->multiple_crtcs) {\ - if (!state->multiple_partitions)\ - weprintf(_("Could not get current adjustments for CRTC %zu."), num);\ - else if (state->partitions_are_graphics_cards)\ - weprintf(_("Could not get current adjustments for CRTC %zu on graphics card %zu."),\ - num, part);\ - else\ - weprintf(_("Could not get current adjustments for CRTC %zu on X screen %zu."), num, part);\ - } else {\ - if (!state->multiple_partitions)\ - weprintf(_("Could not get current adjustments."));\ - else if (state->partitions_are_graphics_cards)\ - weprintf(_("Could not get current adjustments for graphics card %zu."), part);\ - else\ - weprintf(_("Could not get current adjustments for X screen %zu."), part);\ - }\ - libgamma_gamma_##RAMPS##_destroy(&state->crtcs[i].gamma_ramps.RAMPS);\ - libgamma_gamma_##RAMPS##_destroy(&state->crtcs[i].saved_gamma_ramps.RAMPS);\ - libgamma_crtc_destroy(&state->crtcs[i].state);\ - state->crtcs[i].state.data = NULL;\ - crtcs_removed++;\ - goto next - - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - - default: - if (state->multiple_crtcs) { - if (!state->multiple_partitions) - weprintf(_("Unsupported gamma ramp type on CRTC %zu."), num); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unsupported gamma ramp type on CRTC %zu on graphics card %zu."), num, part); - else - weprintf(_("Unsupported gamma ramp type on CRTC %zu on X screen %zu."), num, part); - } else { - if (!state->multiple_partitions) - weprintf(_("Unsupported gamma ramp type.")); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unsupported gamma ramp type on graphics card %zu."), part); - else - weprintf(_("Unsupported gamma ramp type on X screen %zu."), part); - } - return -1; - } - - next: - libgamma_crtc_information_destroy(&crtc_info); - } - - /* Unlist removed CRTCs */ - if (crtcs_removed) { - num = state->ncrtcs - crtcs_removed; - for (i = j = 0; crtcs_removed; i++, j++) - if (!state->crtcs[i].state.data) - break; - for (; crtcs_removed; i++) { - if (state->crtcs[i].state.data) - crtcs_removed--; - else - memmove(&state->crtcs[j++], &state->crtcs[i], sizeof(*state->crtcs)); - } - memmove(&state->crtcs[j], &state->crtcs[i], (state->ncrtcs - i) * sizeof(*state->crtcs)); - state->ncrtcs = num; - } - if (!state->ncrtcs) { - weprintf(_("No usable CRTCs available.")); - return -1; - } - - free(state->selected_crtcs); - state->selected_crtcs = NULL; - return 0; -} - - -int -direct_apply(struct gamma_state *state, const struct colour_setting *setting, int preserve) -{ - size_t i, err_count = 0, crtc, part; - const char *errstr; - int err; - - for (i = 0; i < state->ncrtcs; i++) { - switch (state->crtcs[i].gamma_depth) { -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - fill_ramps_##SUFFIX(state->crtcs[i].gamma_ramps.RAMPS.red,\ - state->crtcs[i].gamma_ramps.RAMPS.green,\ - state->crtcs[i].gamma_ramps.RAMPS.blue,\ - preserve ? state->crtcs[i].saved_gamma_ramps.RAMPS.red : NULL,\ - preserve ? state->crtcs[i].saved_gamma_ramps.RAMPS.green : NULL,\ - preserve ? state->crtcs[i].saved_gamma_ramps.RAMPS.blue : NULL,\ - state->crtcs[i].gamma_ramps.size.red,\ - state->crtcs[i].gamma_ramps.size.green,\ - state->crtcs[i].gamma_ramps.size.blue,\ - setting);\ - err = libgamma_crtc_set_gamma_##RAMPS(&state->crtcs[i].state, &state->crtcs[i].gamma_ramps.RAMPS);\ - break - - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - - default: - err_count++; - err = 0; - break; - } - - if (err) { - err_count++; - crtc = state->crtcs[i].state.crtc; - part = state->crtcs[i].state.partition->partition; - errstr = libgamma_strerror(err); - if (state->multiple_crtcs) { - if (!state->multiple_partitions) - weprintf(_("Unable to set adjustments for CRTC %zu: %s."), crtc, errstr); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unable to set adjustments for CRTC %zu on graphics card %zu: %s."), - crtc, part, errstr); - else - weprintf(_("Unable to set adjustments for CRTC %zu on X screen %zu: %s."), - crtc, part, errstr); - } else { - if (!state->multiple_partitions) - weprintf(_("Unable to set adjustments: %s."), errstr); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unable to set adjustments for graphics card %zu: %s."), part, errstr); - else - weprintf(_("Unable to set adjustments for X screen %zu: %s."), part, errstr); - } - } - } - - return err_count == state->ncrtcs ? -1 : 0; -} - - -void -direct_restore(struct gamma_state *state) -{ - size_t i, crtc, part; - const char *errstr; - int err; - - for (i = 0; i < state->ncrtcs; i++) { - switch (state->crtcs[i].gamma_depth) { -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - err = libgamma_crtc_set_gamma_##RAMPS(&state->crtcs[i].state, &state->crtcs[i].saved_gamma_ramps.RAMPS);\ - break - - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - - default: - err = 0; - break; - } - - if (err) { - crtc = state->crtcs[i].state.crtc; - part = state->crtcs[i].state.partition->partition; - errstr = libgamma_strerror(err); - if (state->multiple_crtcs) { - if (!state->multiple_partitions) - weprintf(_("Unable to restore adjustments for CRTC %zu: %s."), crtc, errstr); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unable to restore adjustments for CRTC %zu on graphics card %zu: %s."), - crtc, part, errstr); - else - weprintf(_("Unable to restore adjustments for CRTC %zu on X screen %zu: %s."), - crtc, part, errstr); - } else { - if (!state->multiple_partitions) - weprintf(_("Unable to restore adjustments: %s."), errstr); - else if (state->partitions_are_graphics_cards) - weprintf(_("Unable to restore adjustments for graphics card %zu: %s."), part, errstr); - else - weprintf(_("Unable to restore adjustments for X screen %zu: %s."), part, errstr); - } - } - } -} - - -void -direct_free(struct gamma_state *state) -{ - size_t i; - if (state->crtcs) { - for (i = 0; i < state->ncrtcs; i++) { - switch (state->crtcs[i].gamma_depth) { -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - libgamma_gamma_##RAMPS##_destroy(&state->crtcs[i].gamma_ramps.RAMPS);\ - libgamma_gamma_##RAMPS##_destroy(&state->crtcs[i].saved_gamma_ramps.RAMPS);\ - break - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - default: - case 0: /* not initialised */ - break; - } - if (state->crtcs[i].state.data) - libgamma_crtc_destroy(&state->crtcs[i].state); - } - free(state->crtcs); - } - if (state->partitions) { - for (i = 0; i < state->npartitions; i++) - if (state->partitions[i].state.data) - libgamma_partition_destroy(&state->partitions[i].state); - free(state->partitions); - } - free(state->selected_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); - free(state); -} diff --git a/src/colour.c b/src/colour.c deleted file mode 100644 index 4d85cb5..0000000 --- a/src/colour.c +++ /dev/null @@ -1,97 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -void -interpolate_colour_settings(const struct colour_setting *a, const struct colour_setting *b, - double t, struct colour_setting *result) -{ - int i; - t = CLAMP(0.0, t, 1.0); - result->temperature = (1.0 - t) * a->temperature + t * b->temperature; - result->brightness = (1.0 - t) * a->brightness + t * b->brightness; - for (i = 0; i < 3; i++) - result->gamma[i] = (1.0 - t) * a->gamma[i] + t * b->gamma[i]; -} - - -int -colour_setting_diff_is_major(const struct colour_setting *a, const struct colour_setting *b) -{ - return MAX(a->temperature, b->temperature) - MIN(a->temperature, b->temperature) > 25UL || - fabs(a->brightness - b->brightness) > 0.1 || - fabs(a->gamma[0] - b->gamma[0]) > 0.1 || - fabs(a->gamma[1] - b->gamma[1]) > 0.1 || - fabs(a->gamma[2] - b->gamma[2]) > 0.1; -} - - -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - /** - * Fill a gamma ramp - * - * @param ramp The gamma ramp - * @param saved Saved gamma ramp with calibrations to preserver, or `NULL` - * @param size The gamma ramp size (number of stops) - * @param brightness The brightness (between 0 and 1) of the channel, which is - * the overall applied brightness multiplied but the effect - * on the channel from the colour temperature - * @param gamma The gamma to apply to the channel - */\ - static void\ - fill_ramp_##SUFFIX(TYPE *ramp, const TYPE *saved, size_t size, double brightness, double gamma)\ - {\ - size_t i;\ - double v;\ - brightness /= (size - 1U);\ - if (exact_eq(gamma, 1.0)) {\ - brightness *= (MAX);\ - for (i = 0; i < size; i++)\ - ramp[i] = (TYPE)(i * brightness);\ - } else {\ - gamma = 1.0 / gamma;\ - for (i = 0; i < size; i++) {\ - v = pow(i * brightness, gamma) * (MAX);\ - ramp[i] = (TYPE)v;\ - }\ - }\ - if (saved) {\ - for (i = 0; i < size; i++) {\ - v = (double)ramp[i] / (MAX) * (size - 1U);\ - ramp[i] = saved[(size_t)v];\ - }\ - }\ - }\ - \ - void\ - fill_ramps_##SUFFIX(TYPE *gamma_r, TYPE *gamma_g, TYPE *gamma_b,\ - const TYPE *saved_r, const TYPE *saved_g, const TYPE *saved_b,\ - size_t size_r, size_t size_g, size_t size_b,\ - const struct colour_setting *setting)\ - {\ - double r = 1, g = 1, b = 1;\ - libred_get_colour(setting->temperature, &r, &g, &b);\ - fill_ramp_##SUFFIX(gamma_r, saved_r, size_r, setting->brightness * r, setting->gamma[0]);\ - fill_ramp_##SUFFIX(gamma_g, saved_g, size_g, setting->brightness * g, setting->gamma[1]);\ - fill_ramp_##SUFFIX(gamma_b, saved_b, size_b, setting->brightness * b, setting->gamma[2]);\ - } - -LIST_RAMPS_STOP_VALUE_TYPES(X,) diff --git a/src/common.h b/src/common.h deleted file mode 100644 index d9a268d..0000000 --- a/src/common.h +++ /dev/null @@ -1,1690 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef WINDOWS -# if defined(__WIN32__) || defined(_WIN32) -# define WINDOWS -# endif -#endif - - -#include "arg.h" - -#include <sys/stat.h> -#include <sys/types.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <limits.h> -#include <locale.h> -#include <math.h> -#include <signal.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <time.h> -#include <unistd.h> -#ifdef _POSIX_TIMERS -# include <sys/time.h> -#endif -#ifdef WINDOWS -# include <windows.h> -# define localtime_r(T, TM) localtime_s((TM), (T)) -# define pause() millisleep(100U) -#else -# include <sys/file.h> -# include <poll.h> -# include <pwd.h> -# include <time.h> -#endif - -#include <libgamma.h> -#include <libgeome.h> -#include <libred.h> - - -#ifdef ENABLE_NLS -# include <libintl.h> -#else -# define gettext(s) s -#endif - -/** - * List for translation, and translate in place - * - * @param s:string-literal Translatable string - * @return :const char * Translation of `s` - */ -#define _(s) gettext(s) - -/** - * List for translation without translating in place - * - * @param s:string-literal Translatable string - * @return :string-literal `s` as is - */ -#define N_(s) s - - -#if defined(__clang__) -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* broken in clang 19.1.7 */ -# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" /* warns about system headers (also a stupid warning) */ -# pragma clang diagnostic ignored "-Wassign-enum" /* warns about bit field enums */ -# pragma clang diagnostic ignored "-Wpadded" /* only relevant for library headers */ -# pragma clang diagnostic ignored "-Wcomma" /* comma is useful in loop conditions */ -# pragma clang diagnostic ignored "-Wcovered-switch-default" /* stupid warning: not necessary true */ -#elif defined(__GNUC__) -# pragma GCC diagnostic ignored "-Wunsuffixed-float-constants" /* stupid warning */ -# pragma GCC diagnostic ignored "-Wpadded" /* only relevant for library headers */ -#endif - - -#if defined(__GNUC__) -# define GCC_ONLY(...) __VA_ARGS__ -#else -# define GCC_ONLY(...) -#endif - - -/** - * Truncate a value into a closed range - * - * @param LO The lower bound - * @param X The value to truncated - * @param UP The upper bound - * @return `X` truncated such that it is at least `LO` and at most `UP` - */ -#define CLAMP(LO, X, UP) (((LO) > (X)) ? (LO) : (((X) < (UP)) ? (X) : (UP))) - -/** - * Check whether a value is within a closed range - * - * @param LO The lower bound - * @param X The value to check - * @param UP The upper bound - * @return :int 1 if `X` is within [`LO`, `UP`], 0 otherwise - */ -#define WITHIN(LO, X, UP) ((LO) <= (X) && (X) <= (UP)) - -/** - * Check whether a value is within a bounded, open range - * - * @param LO The lower bound - * @param X The value to check - * @param UP The upper bound - * @return :int 1 if `X` is within (`LO`, `UP`), 0 otherwise - */ -#define BETWEEN(LO, X, UP) ((LO) < (X) && (X) < (UP)) - -/** - * Quiet not-a-number `double` - */ -#define FNAN ((double)NAN) /* because clang warns when implicitly promoted to double */ - -/** - * Get the number of elements in an array - * - * @param ARR The array, must not be a pointer - * @return :size_t The number of elements in `ARR` (constant - * expression, unless its size is dynamic) - */ -#define ELEMSOF(ARR) (sizeof(ARR) / (sizeof(*(ARR)))) - -/** - * Get the smallest of two numerical values - * - * @param A One of the values - * @param B The other value - * @return The smallest of `A` and `B` - */ -#define MIN(A, B) ((A) < (B) ? (A) : (B)) - -/** - * Get the largest of two numerical values - * - * @param A One of the values - * @param B The other value - * @return The largest of `A` and `B` - */ -#define MAX(A, B) ((A) > (B) ? (A) : (B)) - - -/** - * Symbol used to delimit paths in environment - * variables listing multiple paths - */ -#ifdef WINDOWS -# define PATH_DELIMITER ';' -#else -# define PATH_DELIMITER ':' -#endif - -/** - * The number of seconds in a day - */ -#define ONE_DAY ((time_t)(24L * 60L * 60L)) - - -/** - * Minimum valid latitude - */ -#define MIN_LATITUDE -90.0 - -/** - * Maximum valid latitude - */ -#define MAX_LATITUDE 90.0 - -/** - * Minimum valid longitude - */ -#define MIN_LONGITUDE -180.0 - -/** - * Maximum valid longitude - */ -#define MAX_LONGITUDE 180.0 - -/** - * Minimum allowed colour temperature - */ -#define MIN_TEMPERATURE ((unsigned long int)LIBRED_LOWEST_TEMPERATURE) - -/** - * Maximum allowed colour temperature - */ -#define MAX_TEMPERATURE ULONG_MAX - -/** - * Minimum allowed whitepoint brightness - */ -#define MIN_BRIGHTNESS 0.1 - -/** - * Maximum allowed whitepoint brightness - */ -#define MAX_BRIGHTNESS 1.0 - -/** - * Minimum allowed gamma - */ -#define MIN_GAMMA 0.1 - -/** - * Maximum allowed gamma - */ -#define MAX_GAMMA 10.0 - - -/** - * The colour temperature corresponding to no effect - */ -#define NEUTRAL_TEMPERATURE 6500UL - -/** - * The whitepoint brightness corresponding to - * full brightness (no effect) - */ -#define NEUTRAL_BRIGHTNESS 1.0 - -/** - * The gamma corresponding to no effect (linear output level curve) - */ -#define NEUTRAL_GAMMA 1.0 - - -/** - * Default daytime colour temperature - */ -#define DEFAULT_DAY_TEMPERATURE 6500UL - -/** - * Default night colour temperature - */ -#define DEFAULT_NIGHT_TEMPERATURE 4500UL - -/** - * Default daytime whitepoint brightness level - */ -#define DEFAULT_DAY_BRIGHTNESS NEUTRAL_BRIGHTNESS - -/** - * Default night whitepoint brightness level - */ -#define DEFAULT_NIGHT_BRIGHTNESS NEUTRAL_BRIGHTNESS - -/** - * Default daytime gamma value - */ -#define DEFAULT_DAY_GAMMA NEUTRAL_GAMMA - -/** - * Default night gamma value - */ -#define DEFAULT_NIGHT_GAMMA NEUTRAL_GAMMA - -/** - * The solar elevation, in degrees, that marks the - * threshold to daytime - */ -#define DEFAULT_HIGH_ELEVATION 3.0 - -/** - * The solar elevation, in degrees, that marks the - * threshold to night - */ -#define DEFAULT_LOW_ELEVATION LIBRED_SOLAR_ELEVATION_CIVIL_DUSK_DAWN - - -/** - * Initialiser for `struct colour_setting` - * - * Sets all values to their neutral values (no effects applied) - */ -#define COLOUR_SETTING_NEUTRAL\ - ((struct colour_setting){\ - NEUTRAL_TEMPERATURE,\ - NEUTRAL_BRIGHTNESS,\ - {NEUTRAL_GAMMA, NEUTRAL_GAMMA, NEUTRAL_GAMMA}\ - }) - - -/** - * State of an adjustment method - * - * Each method has their own definition of this structure - */ -typedef struct gamma_state GAMMA_STATE; - -/** - * State of a location provider - * - * Each provider has their own definition of this structure - */ -typedef struct location_state LOCATION_STATE; - - -/** - * The time of the day: day, night, or twilight - */ -enum period { - /** - * None applied - */ - PERIOD_NONE, - - /** - * Full daytime - */ - PERIOD_DAYTIME, - - /** - * Full nighttime - */ - PERIOD_NIGHT, - - /** - * Transitioning between day and night - * (either direction) (twilight) - */ - PERIOD_TRANSITION -}; - - -/** - * The mode the program is running in - */ -enum program_mode { - /** - * Run in foreground continually update temperature - */ - PROGRAM_MODE_CONTINUAL, - - /** - * Update temperature once then exit - */ - PROGRAM_MODE_ONE_SHOT, - - /** - * Update temperature once and reset when killed - */ - PROGRAM_MODE_UNTIL_DEATH, - - /** - * Print setting and exit - */ - PROGRAM_MODE_PRINT, - - /** - * Remove effects and exit - */ - PROGRAM_MODE_RESET -}; - - -/** - * By what the effects of the application change - */ -enum scheme_type { - /** - * Effects are dependent on the Sun's elevation - */ - SOLAR_SCHEME, - - /** - * Effects are dependent on the wall clock time - */ - CLOCK_SCHEME, - - /** - * Effects do not change - */ - STATIC_SCHEME -}; - -/** - * Scheme has not been specified - */ -#define UNSPECIFIED_SCHEME STATIC_SCHEME - - -/** - * The sources where an setting was been loaded from - * - * Higher valued sources have higher priority - * - * This is a bitmask `enum` - */ -enum setting_source { - /** - * No setting loaded, default value set - */ - SETTING_DEFAULT = 0x00, - - /** - * Setting loaded from configuration file - */ - SETTING_CONFIGFILE = 0x01, - - /** - * Setting loaded from command line arguments - */ - SETTING_CMDLINE = 0x02 -}; - - -/** - * SIGUSR2 signal values as bitmask values - */ -enum signals { - /** - * Block SIGUSR2 until all signals have been processed - */ - SIGNAL_ORDER_BARRIER = 1 << 0, - - /** - * Disable the effects of redshift - */ - SIGNAL_DISABLE = 1 << 1, - - /** - * Enable the effects of redshift - */ - SIGNAL_ENABLE = 1 << 2, - - /** - * Reload the configuration file - * - * Settings from the command line will be overriden - */ - SIGNAL_RELOAD = 1 << 3, - - /** - * Execute into the currently installed version of redshift - */ - SIGNAL_REEXEC = 1 << 4, - - /** - * Set the "fade" setting to off - */ - SIGNAL_USE_FADE_OFF = 1 << 5, - - /** - * Set the "fade" setting to on - */ - SIGNAL_USE_FADE_ON = 1 << 6, - - /** - * Set the "preserve-gamma" setting to off - */ - SIGNAL_PRESERVE_GAMMA_OFF = 1 << 7, - - /** - * Set the "preserve-gamma" setting to on - */ - SIGNAL_PRESERVE_GAMMA_ON = 1 << 8, - - /** - * Exit the process without removing the its effects - * - * If the used adjustment method does not support - * leaving the effects, they will be removed - */ - SIGNAL_EXIT_WITHOUT_RESET = 1 << 9, - - /** - * Do not terminate redshift the standard output - * and standard error are closed - */ - SIGNAL_IGNORE_SIGPIPE = 1 << 10, - - /** - * Enable verbose mode - */ - SIGNAL_VERBOSE_ON = 1 << 11, - - /** - * Disable verbose mode - * - * Ignore if started in verbose mode (-v option) - */ - SIGNAL_VERBOSE_OFF = 1 << 12 -}; - - -/** - * Specification for a path that consists of a two parts: - * the first being defined by the environment, and the - * seocnd being a static string - */ -struct env_path { - /** - * Whether the environment variable referenced by `.prefix` - * should be split at each colon (:) into multiple paths to - * test - * - * On Windows semicolon (;) is used instead of colon - */ - int multidir_env; - - /** - * Environment variable to use as the first part of the path - * - * `NULL` if the user's home directory should be used - * - * The empty string if `.suffix` should be used as is - */ - const char *prefix_env; - - /** - * The second part of the path - */ - const char *suffix; -}; - - -/** - * Geographical location, using GPS coordinates - */ -struct location { - /** - * Degrees north of the equator - */ - double latitude; - - /** - * Degrees east of the prime meridian - */ - double longitude; -}; - - -/** - * Colour setting to apply - */ -struct colour_setting { - /** - * Colour temperature, in Kelvin - */ - unsigned long int temperature; - - /** - * Whitepoint brightness level - */ - double brightness; - - /** - * Gamma correct, for the each RGB channel - * in the order: red, green, and blue - */ - double gamma[3]; -}; - - -/** - * Linked list of time periods for `CLOCK_SCHEME` - */ -struct time_period { - /** - * The number of seconds after midnight the period starts - */ - time_t start; - - /** - * 1 if at daytime at the the time `.start`, - * 0 if at nighttime at the the time `.start` - */ - double day_level; - - /** - * `.next->day_level - .day_level` dividied by - * the duration of the period, in seconds - * - * `.day_level` is added to the number of seconds - * elapsed since `.start` multiplied by this number - * to get the dayness level at that time - */ - double diff_over_duration; - - /** - * The following time period - */ - const struct time_period *next; -}; - - -/** - * Dayness level scheme - */ -union scheme { - /** - * The scheme type - * - * If `STATIC_SCHEME`, the union contains no scheme data - */ - enum scheme_type type; - - /** - * Used if `.type == SOLAR_SCHEME` - */ - struct solar_scheme { - /** - * `SOLAR_SCHEME` - */ - enum scheme_type type; - - /** - * The lowest solar elevation of daytime - */ - double high; - - /** - * The highest solar elevation of nighttime - */ - double low; - - /** - * `.high - .low` - */ - double range; - } elevation; - - /** - * Used if `.type == CLOCK_SCHEME` - */ - struct clock_scheme { - /** - * `CLOCK_SCHEME` - */ - enum scheme_type type; - - /** - * Circularly linked list of time periods - * - * The application will update this to always - * point to the current time period - */ - const struct time_period *periods; - - /** - * The memory allocation for the nodes in `.periods` - */ - struct time_period periods_array[4]; - } time; -}; - - -struct config_ini_setting { - struct config_ini_setting *next; - char *name; - char *value; -}; - - -struct config_ini_section { - struct config_ini_section *next; - char *name; - struct config_ini_setting *settings; -}; - - -struct config_ini_state { - struct config_ini_section *sections; -}; - - -/** - * `int` valued setting (used for booleans) with setting source - */ -struct setting_i { - enum setting_source source; /**< Setting source */ - int value; /**< Setting value */ -}; - -/** - * `unsigned long int` valued setting with setting source - */ -struct setting_lu { - enum setting_source source; /**< Setting source */ - unsigned long int value; /**< Setting value */ -}; - -/** - * `double` valued setting with setting source - */ -struct setting_f { - enum setting_source source; /**< Setting source */ - double value; /**< Setting value */ -}; - -/** - * `double[3]` valued setting with setting source - */ -struct setting_f3 { - enum setting_source source; /**< Setting source */ - double value[3]; /**< Setting values */ -}; - -/** - * `time_t` valued setting with setting source - */ -struct setting_time { - enum setting_source source; /**< Setting source */ - time_t value; /**< Setting value */ -}; - -/** - * `char *` valued setting with setting source - */ -struct setting_str { - enum setting_source source; /**< Setting source */ - char *value; /**< Setting value */ -}; - -/** - * Intermediate settings representation of colour settings - * (for a non-transitional period) with settings sources - * used for determining whether settings from the configuration - * file (which is parsed after the command line) applied or are - * specified multiple times in the configuration file - */ -struct setting_colour { - /** - * Colour temperature, in Kelvin - * - * Set by the "-t" and "-o" options and the "temperature" - * ("temp") settings, optionally suffixed "-day" if - * a daytime setting or "-night" if a nighttime setting - */ - struct setting_lu temperature; - - /** - * Whitepoint brightness level, as a [0, 1] value - * - * Set by the "-b" option and the "brightness" settings, - * optionally suffixed "-day" if a daytime setting or - * "-night" if a nighttime setting - */ - struct setting_f brightness; - - /** - * Gamma values, in the order red, green, blue - * - * Set by the "-g" option and the "gamma" settings, - * optionally suffixed "-day" if a daytime setting or - * "-night" if a nighttime setting - */ - struct setting_f3 gamma; -}; - -/** - * Intermediate settings representation with settings sources - * used for determining whether settings from the configuration - * file (which is parsed after the command line) applied or - * are specified multiple times in the configuration file - * - * Settings without a source can only be specified in the - * command line - */ -struct settings { - /** - * The path to the configuration, `NULL` if unspecified - * (search default paths) - * - * This represents the "-c" option - */ - const char *config_file; - - /** - * Scheme type to use as according the the command line - * options, `UNSPECIFIED_SCHEME` if not unspecified - */ - enum scheme_type scheme_type; - - /** - * Whether the program should, if ran in one-shot mode, - * pause after applying the effect and reset them when - * killed - * - * This represents the "-d" option - */ - int until_death; - - /** - * The path to the hook file or hook directory, `NULL` - * if unspecified (search default paths) - * - * This represents the "hook" setting and "-H" option - */ - struct setting_str hook_file; - - /** - * Whether the program should preserve preapplied - * colour calibrations - * - * This represents the "preserve-gamma" setting and - * "-P" (off) and "+P" (on) options - */ - struct setting_i preserve_gamma; - - /** - * Whether smooth transitions shall be applied when - * a large change in colour settings occurs - * - * This represents the "fade" setting (or the deprecated - * alias "transition") and "-r" (off) and "+r" (on) options - */ - struct setting_i use_fade; - - /** - * Whether the program should start in disabled mode - * - * This represents the "start-disabled" setting and - * "-D" (off) and "+D" (on) options - */ - struct setting_i disabled; - - /** - * The colour settings to apply at daytime - */ - struct setting_colour day; - - /** - * The colour settings to apply at nighttime - */ - struct setting_colour night; - - /** - * The lowest solar elevation, in degrees, at daytime, - * when using solar scheme - * - * This represents the "elevation-high" setting and the - * left value of the -e option - */ - struct setting_f elevation_high; - - /** - * The highest solar elevation, in degrees, at nighttime, - * when using solar scheme - * - * This represents the "elevation-low" setting - * - * This represents the "elevation-low" setting and the - * right value of the -e option - */ - struct setting_f elevation_low; - - /** - * The wall-clock time that marks the end of nighttime, - * when using clock scheme - * - * This represents the left value of the "dawn-time" setting - */ - struct setting_time dawn_start; /* TODO no cmdline option */ - - /** - * The wall-clock time that marks the start of daytime, - * when using clock scheme - * - * This represents the right value of the "dawn-time" setting - */ - struct setting_time dawn_end; /* TODO no cmdline option */ - - /** - * The wall-clock time that marks the end of daytime, - * when using clock scheme - * - * This represents the left value of the "dusk-time" setting - */ - struct setting_time dusk_start; /* TODO no cmdline option */ - - /** - * The wall-clock time that marks the start of nighttime, - * when using clock scheme - * - * This represents the right value of the "dusk-time" setting - */ - struct setting_time dusk_end; /* TODO no cmdline option */ - - /* Selected gamma method */ - const struct gamma_method *method; - /* Arguments for gamma method */ - char *method_args; - - /* Selected location provider */ - const struct location_provider *provider; - /* Arguments for location provider */ - char *provider_args; - - struct config_ini_state config; -}; - - -/** - * Adjustment method information and interface - */ -struct gamma_method { - /** - * The name of the adjustment method - */ - const char *name; - - /** - * 1 if the method should be tried if none is explicitly chosen, - * 0 otherwise - */ - int autostart; - - /** - * 1 if the method automatically resets the adjustments when disconnected, - * 0 otherwise - */ - int autoreset; - - /** - * Check if the adjustment method is available in the used backend - * - * @return 1 if the adjustment method is available, 0 otherwise - */ - int (*is_available)(void); - - /** - * Create an initialised state object - * - * @param state_out Output parameter for the state object - * @return 0 on success, -1 on failure - * - * `*state_out` is set (potentially to `NULL`) on failure - */ - int (*create)(GAMMA_STATE **state_out); - - /** - * Configure the adjustment method - * - * @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 (*set_option)(GAMMA_STATE *state, const char *key, const char *value); - - /** - * Print help on options for the adjustment method - */ - void (*print_help)(void); - - /** - * Finalise option-dependent initialisation and connections - * - * @param state State object for the adjustment method - * @return 0 on success, -1 on failure - */ - int (*start)(GAMMA_STATE *state); - - /** - * Apply colour settings - * - * @param state State object for the adjustment method - * @param settings The colour settings to apply - * @param preserve Whether currently applied adjustments (assumed - * to be colour calibration) shall remain applied - * @return 0 on success, -1 on failure - */ - int (*apply)(GAMMA_STATE *state, const struct colour_setting *setting, int preserve); - - /** - * Restore the adjustments to the `.state` before start was called - * - * @param state State object for the adjustment method - */ - void (*restore)(GAMMA_STATE *state); - - /** - * Close connections and deallocate all state resources - * - * @param state The state to terminate - * - * The pointer `state` will become invalid - */ - void (*free)(GAMMA_STATE *state); -}; - -/** - * Initialiser for `struct gamma_method` - * - * @param NAME:const char * Value for `.name` - * @param AUTOSTART:int Value for `.autostart` - * @param AUTORESET:int Value for `.autoreset` - * @param PREFIX:identifier The text, sans terminal underscore (_), prefixed to the - * names of each function implementing the adjustment method - */ -#define GAMMA_METHOD_INIT(NAME, AUTOSTART, AUTORESET, PREFIX)\ - {\ - .name = (NAME),\ - .autostart = (AUTOSTART),\ - .autoreset = (AUTORESET),\ - .is_available = &PREFIX##_is_available,\ - .create = &PREFIX##_create,\ - .set_option = &PREFIX##_set_option,\ - .print_help = &PREFIX##_print_help,\ - .start = &PREFIX##_start,\ - .free = &PREFIX##_free,\ - .restore = &PREFIX##_restore,\ - .apply = &PREFIX##_apply\ - } - - -/** - * Location provider information and interface - */ -struct location_provider { - /** - * The name of the location provider - */ - const char *name; - - /** - * Create an initialised state object - * - * @param state_out Output parameter for the state object - * @return 0 on success, -1 on failure - * - * `*state_out` is set (potentially to `NULL`) on failure - */ - int (*create)(LOCATION_STATE **state_out); - - /** - * Configure the location provider - * - * @param state State object for the location provider - * @param key Option to configure - * @param value Option value to set - * @return 0 on success, -1 on failure - */ - int (*set_option)(LOCATION_STATE *state, const char *key, const char *value); - - /** - * Print help on options for the location provider - */ - void (*print_help)(void); - - /** - * Finalise option-dependent initialisation and connections - * - * @param state State object for the location provider - * @return 0 on success, -1 on failure - */ - int (*start)(LOCATION_STATE *state); - - /** - * Get the file descriptor used by the location provider - * - * The application may use it for detecting when there - * is data available for `.handle` to act upon - * - * @param state State object for the location provider - * @return The file descriptor used by location provider, -1 if none - */ - int (*get_fd)(LOCATION_STATE *state); - - /** - * Get the current location - * - * This function shall only be caused if `.get_fd` returns -1 - * or the file descriptor it returns has data available on it - * as indicated by input polling, otherwise `*location` and - * `*available` will not be set - * - * @param state State object for the location provider - * @param location_out Output parameter for the current location - * @param available_out Output parameter for whether the location provider - * is currently available - * @return 0 on success, -1 on unrecoverable failure - */ - int (*fetch)(LOCATION_STATE *state, struct location *location, int *available); - - /** - * Close connections and deallocate all state resources - * - * @param state The state to terminate - * - * The pointer `state` will become invalid - */ - void (*free)(LOCATION_STATE *state); -}; - -/** - * Initialiser for `struct location_provider` - * - * @param NAME:const char * Value for `.name` - * @param PREFIX:identifier The text, sans terminal underscore (_), prefixed to the - * names of each function implementing the location provider - */ -#define LOCATION_PROVIDER_INIT(NAME, PREFIX)\ - {\ - .name = (NAME),\ - .create = &PREFIX##_create,\ - .set_option = &PREFIX##_set_option,\ - .print_help = &PREFIX##_print_help,\ - .start = &PREFIX##_start,\ - .get_fd = &PREFIX##_get_fd,\ - .fetch = &PREFIX##_fetch,\ - .free = &PREFIX##_free\ - } - - -/** - * `NULL` terminated list of adjustment methods - */ -extern const struct gamma_method *gamma_methods[]; - -/** - * `NULL` terminated list of location providers - */ -extern const struct location_provider *location_providers[]; - -/** - * Set to 1 once the process has received a signal to terminate - */ -extern volatile sig_atomic_t exiting; - -/** - * Set to 1 once the process has received a signal to remove its effect - */ -extern volatile sig_atomic_t disable; - -/** - * Bitwise or OR of received SIGUSR2 signal values - */ -extern volatile enum signals signals; - -/** - * The colour settings applied at daytime - */ -extern struct colour_setting day_settings; - -/** - * The colour settings applied at nighttime - */ -extern struct colour_setting night_settings; - -/** - * The colour settings applied at nighttime - */ -extern union scheme scheme; - -/** - * The mode the application is running in - */ -extern enum program_mode mode; - -/** - * Whether initially applied adjustments (assumed - * to be colour calibration) shall remain applied - */ -extern int preserve_gamma; - -/** - * Whether smooth transitions shall be applied when - * a large change in colour settings occurs - */ -extern int use_fade; - -/** - * Whether the application is in verbose mode - */ -extern int verbose; - -/** - * The path to the hook file or hook directory, `NULL` - * if unspecified (search default paths) - */ -extern char *hook_file; - - -/* backend-direct.c */ - -/** - * Create an initialised state object for direct gamma adjustments - * - * @param state_out Output parameter for the state object - * @param method libgamma constant for the adjustment method - * @param method_name redshift's name for the adjustment method - * @return 0 on success, -1 on failure - * - * `*state_out` is set (potentially to `NULL`) on failure - */ -int direct_create(GAMMA_STATE **state_out, int method, const char *method_name); - -/** - * Print help on options for the adjustment method using direct gamma adjustments - * - * @param method libgamma constant for the adjustment method - */ -void direct_print_help(int method); - -/** - * Configure the adjustment method 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_option(GAMMA_STATE *state, const char *key, const char *value); - -/** - * Select site 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_site(GAMMA_STATE *state, const char *key, const char *value); - -/** - * Select partitions 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_partitions(GAMMA_STATE *state, const char *key, const char *value); - -/** - * Select CRTCs 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_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 - * - * @param state State object for the adjustment method - * @return 0 on success, -1 on failure - */ -int direct_start(GAMMA_STATE *state); - -/** - * Apply colour settings using direct gamma adjustments - * - * @param state State object for the adjustment method - * @param settings The colour settings to apply - * @param preserve Whether currently applied adjustments (assumed - * to be colour calibration) shall remain applied - * @return 0 on success, -1 on failure - */ -int direct_apply(GAMMA_STATE *state, const struct colour_setting *setting, int preserve); - -/** - * Restore the adjustments to the `.state` before start was called - * using direct gamma adjustments - * - * @param state State object for the adjustment method - */ -void direct_restore(GAMMA_STATE *state); - -/** - * Close connections and deallocate all state resources - * for direct gamma adjustments - * - * @param state The state to terminate - * - * The pointer `state` will become invalid - */ -void direct_free(GAMMA_STATE *state); - - -/* colour.c */ - -/** - * Interpolate between two colour settings - * - * @param a The first colour setting, used wholly when `t` is 0 - * @param b The second colour setting, used wholly when `t` is 1 - * @param t The degree to which `second` second be applied - * @param result Output parameter for `(1 - t) * a + t * b` - */ -void interpolate_colour_settings(const struct colour_setting *a, const struct colour_setting *b, - double t, struct colour_setting *result); - -/** - * Check whether the differences between two colours settings - * are large enough to warrant fading between the two - * - * @param a The first colour setting - * @param b The second colour setting - * @return 1 if the difference between `a` and `b` is large, 0 otherwise - */ -GCC_ONLY(__attribute__((__pure__))) -int colour_setting_diff_is_major(const struct colour_setting *a, const struct colour_setting *b); - -#define LIST_RAMPS_STOP_VALUE_TYPES(X, D)\ - X(u8, ramps8, uint8_t, UINT8_MAX, 8) D \ - X(u16, ramps16, uint16_t, UINT16_MAX, 16) D\ - X(u32, ramps32, uint32_t, UINT32_MAX, 32) D\ - X(u64, ramps64, uint64_t, UINT64_MAX, 64) D\ - X(float, rampsf, float, 1, -1) D\ - X(double, rampsd, double, 1, -2) - -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - /** - * Fill the gamma ramps - * - * @param gamma_r The gamma ramp for the red channel - * @param gamma_g The gamma ramp for the green channel - * @param gamma_b The gamma ramp for the blue channel - * @param saved_r Saved gamma ramp with calibrations for - * the red channel to preserve, or `NULL` - * @param saved_g Saved gamma ramp with calibrations for - * the green channel to preserve, or `NULL` - * @param saved_b Saved gamma ramp with calibrations for - * the blue channel to preserve, or `NULL` - * @param size_r The number of stops in `gamma_r` - * @param size_g The number of stops in `gamma_g` - * @param size_b The number of stops in `gamma_b` - * @param settings The colour settings to apply (temperature, brightness, gamma) - */\ - void fill_ramps_##SUFFIX(TYPE *gamma_r, TYPE *gamma_g, TYPE *gamma_b,\ - const TYPE *saved_r, const TYPE *saved_g, const TYPE *saved_b,\ - size_t size_r, size_t size_g, size_t size_b,\ - const struct colour_setting *setting) -LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - - -/* config-ini.c */ - -/** - * Load the configuration file - * - * @param state Output parameter for the configurations - * @param path The path to the configuration file, or `NULL` if the - * application should look for it in the default paths - * @param pathbuf_out Output parameter for the memory allocated for the - * return value - * @return The path to the loaded configuration file, `NULL` if none - */ -const char *config_ini_init(struct config_ini_state *state, const char *path, char **pathbuf_out); - -/** - * Deallocate the settings loaded - * from the configurations file - * - * @param state The configurations - */ -void config_ini_free(struct config_ini_state *state); - -/** - * Get a section from the configuration file - * - * @param state The configurations - * @param name The name of the section - * @return The section; `NULL` if missing - */ -GCC_ONLY(__attribute__((__pure__))) -struct config_ini_section *config_ini_get_section(struct config_ini_state *state, const char *name); - - -/* config.c */ - -/** - * Load settings - * - * @param settings Output parameter for the settings - * @param argc Number of command line arguments - * @param argv `NULL` terminated list of command line arguments, - * including argument zero - */ -void load_settings(struct settings *settings, int argc, char *argv[]); - - -/* gamma.c */ - -/** - * Get and configure adjustment method - * - * @param settings The loaded application settings, will be updated - * to point `settings->method` to the adjustment method - * @param method_state_out Output parameter for the state of the adjustment method - * - * The function will print an error message and exit the - * process if no adjustment method is available - */ -void acquire_adjustment_method(struct settings *settings, GAMMA_STATE **method_state_out); - - -/* location.c */ - -/** - * Get the current location from the location provider - * - * @param provider The location provider functions - * @param state The location provider state - * @param timeout The number of milliseconds to wait, -1 for indefinitely - * @param location_out Output parameter for the location, in GPS coordinates - * @return 1 if `*location_out` was updated, - * 0 if the timeout was reached, - * -1 on error - */ -int get_location(const struct location_provider *provider, LOCATION_STATE *state, int timeout, struct location *location_out); - -/** - * Get and configure location provider - * - * @param settings The loaded application settings, will be updated - * to point `settings->provider` to the location provider - * @param location_state_out Output parameter for the state of the location provider - * - * The function will print an error message and exit the - * process if no location provider is available - */ -void acquire_location_provider(struct settings *settings, LOCATION_STATE **location_state_out); - -/** - * Check whether location is valid - * - * If the message is invalid, and error message is printed - * - * @param location The location to check - * @return 1 if the location is valid, 0 otherwise - */ -int location_is_valid(const struct location *location); - -/** - * Print the current location to standard output - * - * @param location The current location - */ -void print_location(const struct location *location); - - -/* hooks.c */ - -/** - * Run hooks with a signal that the period changed - * - * @param prev_period The previous period - * @param period The new current period - */ -void run_period_change_hooks(enum period prev_period, enum period period); - - -/* signals.c */ - -/** - * Install signal handlers for the process - */ -void install_signal_handlers(void); - -/** - * Install signal handlers for forcefully terminating - * the process - * - * This is useful if slave thread is blocked - * - * SIGINT, SIGTERM, and SIGQUIT are set to at the - * first arrival arm a SIGARLM timer with a short - * expiration time, and on the second arrival - * immediately terminate the process. SIGARLM is - * set to immediately terminate the process. - */ -#ifndef WINDOWS -void install_forceful_exit_signal_handlers(void); -#endif - - -/* util.c */ - -/** - * Remove trailing whitespace - * - * @param s The string to trim, will be truncated - * @param end The current end of `s`; will be looked up if `NULL` - * @return `s` - */ -char *rtrim(char *s, char *end); - -/** - * Remove leading whitespace - * - * @param s The string to trim (will not be modified) - * @return `s` with an offset - */ -GCC_ONLY(__attribute__((__warn_unused_result__, __pure__))) -char *ltrim(char *s); - -/** - * Get the user's home directory - * - * This function looks up the user's home directory - * once and caches the result, later calls to this - * function will use the cached result - * - * @return The user's home directory; the empty string if not found - */ -const char *get_home(void); - -/** - * Search for a file and open it for reading - * - * @param path_spec Specification for the path to try - * @param path_out Output parameter for the found file - * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * shall be free(3)d by the caller - * @return `FILE` object for the reading the file; `NULL` if not found - */ -FILE *try_path_fopen(const struct env_path *path_spec, const char **path_out, char **pathbuf_out); - -/** - * Search for a directory and open it for reading - * - * @param path_spec Specification for the path to try - * @param path_out Output parameter for the found directory - * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * shall be free(3)d by the caller - * @return `DIR` object for the reading the directory; `NULL` if not found - */ -DIR *try_path_opendir(const struct env_path *path_spec, const char **path_out, char **pathbuf_out); - -#ifndef WINDOWS -/** - * Create a pipe(7) where both ends have `O_CLOEXEC`, - * the read-end will also have `O_NONBLOCK` applied - * - * @param pipefds Output parameter for the pipe's file descriptors: - * 0) reading file descriptor, and - * 1) writing file descriptor - */ -void pipe_rdnonblock(int pipefds[2]); -#endif - -/** - * Wrapper for calloc(3) that prints and error message - * and terminates the process on failure - * - * @param n Number of elements to allocate memory for - * @param m The size, in bytes, of each element - * @return Pointer to zero-initialised storage of at least `n*m` bytes, with default alignment - */ -GCC_ONLY(__attribute__((__warn_unused_result__, __malloc__, __alloc_size__(1, 2), __returns_nonnull__))) -void *ecalloc(size_t n, size_t m); - -/** - * Wrapper for malloc(3) that prints and error message - * and terminates the process on failure - * - * @param n Number of bytes to allocate - * @return Pointer to uninitialised storage of at least `n` bytes, with default alignment - */ -GCC_ONLY(__attribute__((__warn_unused_result__, __malloc__, __alloc_size__(1), __returns_nonnull__))) -void *emalloc(size_t n); - -/** - * Wrapper for realloc(3) that prints and error message - * and terminates the process on failure - * - * @param ptr Pointer to reallocate - * @param n Despired allocation size in bytes - * @return Replacement pointer for `ptr`, pointing to storage of at least `n` bytes, - * any byte that could be copied from `ptr` is copied over, and additional - * memory is uninitialised - */ -GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__, __alloc_size__(2)))) -void *erealloc(void *ptr, size_t n); - -/** - * Wrapper for strdup(3) that prints and error message - * and terminates the process on failure - * - * @param s String to copy - * @return Copy of `s` - */ -GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__, __malloc__, __assume_aligned__(1), __nonnull__))) -char *estrdup(const char *s); - -/** - * Print a message, prefixed with the process name (followed by ": "), - * to standard error - * - * @param fmt Message text format string, see fprintf(3) - * @param args Message text arguments - */ -GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 0)))) -void vweprintf(const char *fmt, va_list args); - -/** - * Print a message, prefixed with the process name (followed by ": "), - * to standard error - * - * @param fmt Message text format string, see fprintf(3) - * @param ... Message text arguments - */ -GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2)))) -void weprintf(const char *fmt, ...); - -/** - * Print a message, prefixed with the process name (followed by ": "), - * to standard error and terminate the process with exit value - * indicating error - * - * @param fmt Message text format string, see fprintf(3) - * @param ... Message text arguments - */ -GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2), __noreturn__))) -void eprintf(const char *fmt, ...); - - -extern const struct gamma_method dummy_gamma_method; -#ifdef ENABLE_COOPGAMMA -extern const struct gamma_method coopgamma_gamma_method; -#endif -extern const struct gamma_method randr_gamma_method; -extern const struct gamma_method vidmode_gamma_method; -extern const struct gamma_method drm_gamma_method; -extern const struct gamma_method quartz_gamma_method; -extern const struct gamma_method wingdi_gamma_method; - -extern const struct location_provider manual_location_provider; -#ifdef ENABLE_GEOCLUE2 -extern const struct location_provider geoclue2_location_provider; -#endif -#ifdef ENABLE_CORELOCATION -extern const struct location_provider corelocation_location_provider; -#endif -#ifndef WINDOWS -extern const struct location_provider geofile_location_provider; -extern const struct location_provider timezone_location_provider; -#endif - - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-equal" -#endif -static inline int -exact_eq(double a, double b) -{ - return a == b; -} -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif diff --git a/src/config-ini.c b/src/config-ini.c deleted file mode 100644 index 13aaa57..0000000 --- a/src/config-ini.c +++ /dev/null @@ -1,267 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -/** - * Paths, in order of priority, to test when looking for - * the configuration file for redshift - */ -static const struct env_path paths[] = { - {0, "XDG_CONFIG_HOME", "/redshift-ng/redshift.conf"}, - {0, "XDG_CONFIG_HOME", "/redshift/redshift.conf"}, - {0, "XDG_CONFIG_HOME", "/redshift.conf"}, -#if defined(WINDOWS) - {0, "localappdata", "/redshift-ng/redshift.conf"}, - {0, "localappdata", "/redshift/redshift.conf"}, - {0, "localappdata", "/redshift.conf"}, -#endif - {0, "HOME", "/.config/redshift-ng/redshift.conf"}, - {0, "HOME", "/.config/redshift/redshift.conf"}, - {0, "HOME", "/.config/redshift.conf"}, - {0, "HOME", "/.redshift.conf"}, - {0, NULL, "/.config/redshift-ng/redshift.conf"}, - {0, NULL, "/.config/redshift/redshift.conf"}, - {0, NULL, "/.config/redshift.conf"}, - {0, NULL, "/.redshift.conf"}, - {1, "XDG_CONFIG_DIRS", "/redshift-ng/redshift.conf"}, - {1, "XDG_CONFIG_DIRS", "/redshift/redshift.conf"}, - {1, "XDG_CONFIG_DIRS", "/redshift.conf"}, -#if !defined(WINDOWS) - {0, "", "/etc/redshift-ng/redshift.conf"}, - {0, "", "/etc/redshift/redshift.conf"}, - {0, "", "/etc/redshift.conf"} -#endif -}; - - -/** - * Open the configuration file for reading - * - * @param path The path to the configuration file, or `NULL` if the - * application should look for it in the default paths - * @param path_out Output parameter for the configuration file path - * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * will be set to `NULL` unless `path` is `NULL`; shall be - * free(3)d by the caller - * @param should_close_out Output parameter for whether the file should be closed - * @return `FILE` object for the reading the file; `NULL` if not - * found and `path` is `NULL` - */ -static FILE * -open_config_file(const char *path, const char **path_out, char **pathbuf_out, int *should_close_out) -{ - FILE *f = NULL; - size_t i; -#ifndef WINDOWS - const char *s; - int fd, old_fd = -1; -#endif - - *path_out = path; - *pathbuf_out = NULL; - *should_close_out = 1; - - if (!path) { - for (i = 0; !f && i < ELEMSOF(paths); i++) - f = try_path_fopen(&paths[i], path_out, pathbuf_out); - if (f) - weprintf(_("Found configuration file `%s'."), *path_out); - else - weprintf(_("No configuration file found.")); - } else if (!strcmp(path, "/dev/null")) { /* needed to allow /dev/null to be specified on Windows */ - return NULL; - } else if (!strcmp(path, "-")) { - *should_close_out = 0; - return stdin; -#ifndef WINDOWS - } else if (!strcmp(path, "/dev/stdin")) { - *should_close_out = 0; - return stdin; - } else if (!strcmp(path, "/dev/stdout")) { - fd = STDOUT_FILENO; - goto use_fd; - } else if (!strcmp(path, "/dev/stderr")) { - fd = STDERR_FILENO; - goto use_fd; - } else if (!strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1U)) { - s = &path[sizeof("/dev/fd/") - 1U]; -# if defined(__linux__) - goto parse_fd; - } else if (!strncmp(path, "/proc/self/fd/", sizeof("/proc/self/fd/") - 1U)) { - s = &path[sizeof("/proc/self/fd/") - 1U]; - parse_fd: -# endif - fd = 0; - if (!*s) - goto fallback; - while (isdigit(*s)) { - if (fd > (INT_MAX - (*s & 15)) / 10) - goto fallback; - fd = fd * 10 + (*s & 15); - } - if (*s) - goto fallback; - use_fd: - if (fd > 2) { - fd = dup(old_fd = fd); - if (fd < 0) - eprintf("dup %i:", old_fd); - } - f = fdopen(fd, "r"); - if (!f) { - if (old_fd < 0) - eprintf("fdopen %i \"r\":", fd); - else - eprintf("fdopen <duplicate of %i> \"r\":", old_fd); - } -#endif - } else { -#ifndef WINDOWS - fallback: -#endif - f = fopen(path, "r"); - if (!f) - eprintf("fopen %s \"r\":", path); - } - - return f; -} - - -const char * -config_ini_init(struct config_ini_state *state, const char *path, char **pathbuf_out) -{ - struct config_ini_section *section = NULL; - struct config_ini_setting *setting; - char *line = NULL, *s, *p, *value, *end; - char *next_line = NULL, *name; - size_t size = 0; - ssize_t len = 0; /* initialised to silence false warning from clang */ - FILE *f; - int should_close; - - state->sections = NULL; - *pathbuf_out = NULL; - - f = open_config_file(path, &path, pathbuf_out, &should_close); - if (!f) - return NULL; - -#ifndef WINDOWS -again: -#endif - while ((s = next_line) || (len = getline(&line, &size, f)) >= 0) { - if (!s && (s = line, strlen(s) != (size_t)len)) - eprintf(_("Config file contains NUL byte.")); - - s = ltrim(s); - next_line = NULL; - end = &s[strcspn(s, "\r\n")]; - if (*end) { - p = end; - do { - *p++ = '\0'; - } while (*p == '\r' || *p == '\n'); - if (*p) - next_line = p; - } - rtrim(s, end); - - switch (*s) { - case ';': /* comment line */ - case '#': /* comment line */ - case '\0': /* blank line */ - break; - - case '[': /* "[%s]", section */ - end = strchr(name = &s[1], ']'); - if (!end || end[1] || end == name) - eprintf(_("Malformed section header in config file.")); - *end = '\0'; - section = emalloc(sizeof(*section)); - section->name = estrdup(name); - section->settings = NULL; - section->next = state->sections; - state->sections = section; - break; - - default: /* "%s = %s", name, value */ - value = p = strchr(name = s, '='); - if (!value || value == name) - eprintf(_("Malformed assignment in config file.")); - *value++ = '\0'; - if (!section) - eprintf(_("Assignment outside section in config file.")); - setting = emalloc(sizeof(*setting)); - setting->name = estrdup(rtrim(name, p)); - setting->value = estrdup(rtrim(ltrim(value), NULL)); - setting->next = section->settings; - section->settings = setting; - break; - } - } - if (ferror(f)) { -#ifndef WINDOWS - if (errno == EINTR) { - clearerr(f); - goto again; - } -#endif - eprintf("getline %s:", path); - } - - free(line); - if (should_close) - fclose(f); - - return path; -} - - -void -config_ini_free(struct config_ini_state *state) -{ - struct config_ini_section *section, *section_next; - struct config_ini_setting *setting, *setting_next; - for (section = state->sections; section; section = section_next) { - section_next = section->next; - for (setting = section->settings; setting; setting = setting_next) { - setting_next = setting->next; - free(setting->name); - free(setting->value); - free(setting); - } - free(section->name); - free(section); - } -} - - -struct config_ini_section * -config_ini_get_section(struct config_ini_state *state, const char *name) -{ - /* TODO deal with multiple section definitions */ - struct config_ini_section *section; - for (section = state->sections; section; section = section->next) - if (!strcasecmp(section->name, name)) - return section; - return NULL; -} diff --git a/src/config.c b/src/config.c deleted file mode 100644 index 29c5a53..0000000 --- a/src/config.c +++ /dev/null @@ -1,1172 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -/** - * Output usage synopsis, without exiting - * - * @param f Output sink - */ -static void -usage_no_exit(FILE *f) -{ - fprintf(f, _("Usage: %s %s\n"), argv0, - _("[-b brightness] [-c config-file] [-D | +D] [-E | +E | -e elevations] " - "[-g gamma] [-H hook-file] [-l latitude:longitude | -l provider[:options]] " - "[-m method[:options]] [-P | +P] [-r | +r] [-dv] " - "[-O temperature | -o | -p | -t temperature | -x] | -h | -V")); -} - - -/** - * Output usage synopsis and exit - */ -static void -usage(void) -{ - usage_no_exit(stderr); - exit(1); -} - - -struct colour_setting day_settings; -struct colour_setting night_settings; -union scheme scheme = {.type = SOLAR_SCHEME}; -enum program_mode mode = PROGRAM_MODE_CONTINUAL; -int preserve_gamma; -int use_fade; -int verbose = 0; -char *hook_file; - - -/** - * Print general help text - */ -static void -print_help(void) -{ - usage_no_exit(stdout); - printf("\n"); - - printf(_("Automatically adjust display colour temperature according the Sun\n")); - printf("\n"); - - printf(_(" -b day:night Select whitepoint brightness (Default: 1:1)\n")); - printf(_(" -c file Load settings from specified configuration file\n")); - printf(_(" -D Start in enabled state (Default)\n")); - printf(_(" +D Start in disabled state\n")); - printf(_(" -d Keep the process alive and remove the colour effects when killed\n")); - printf(_(" -E Use wall-clock based schedule\n")); - printf(_(" +E Use solar elevation based schedule\n")); - printf(_(" -e day:night Select solar elevation thresholds for day and night (Default: %g:%g)\n"), - DEFAULT_HIGH_ELEVATION, DEFAULT_LOW_ELEVATION); - printf(_(" -g day:night Additional gamma correction (Default: 1:1:1:1:1:1)\n")); - printf(_(" -H hook-file Select hook file or directrory\n")); - printf(_(" -h Display this help message\n")); - printf(_(" -l lat:lon Specific geographical location\n")); - printf(_(" -l provider[:options] Select location provider to get geographical location\n")); - printf(_(" (Use `-l list' to list available providers)\n")); - printf(_(" -m method[:options] Select adjustment method for applying colour settings\n")); - printf(_(" (Use `-m list' to list adjustment methods)\n")); - printf(_(" -O day:night Select colour temperature and apply once\n")); - printf(_(" -o Apply colour settings once, then exit\n")); - printf(_(" -P Remove preexisting colour adjustments\n")); - printf(_(" +P Preserve preexisting colour adjustments (Default)\n")); - printf(_(" -p Print parameters and exit\n")); - printf(_(" -r Disable fading between colour adjustments\n")); - printf(_(" +r Enable fading between colour adjustments (Default)\n")); - printf(_(" -t day:night Select colour temperature and apply continually (Default: %lu:%lu\n"), - DEFAULT_DAY_TEMPERATURE, DEFAULT_NIGHT_TEMPERATURE); - printf(_(" -V Show program implementation and version\n")); - printf(_(" -v Enable verbose output\n")); - printf(_(" -x Remove adjustments from screen\n")); - - printf("\n"); - printf(_("This is a breif summary, see `%s' for more information.\n"), "man redshift"); - printf("\n"); - printf(_("The neutral temperature is %luK. Using this value will not change the color\n" - "temperature of the display. Setting the color temperature to a value higher\n" - "than this results in more blue light, and setting a lower value will result in\n" - "more red light.\n"), NEUTRAL_TEMPERATURE); - printf("\n"); -} - - -/** - * Parse a boolean string - * - * @param s The string to parse - * @param key The name of the configuration assigned the value `s` - * @return 1 if `s` represents true, 0 if `s` represents false - */ -GCC_ONLY(__attribute__((__pure__))) -static int -get_boolean(const char *s, const char *key) -{ - int ret; - if (s[0] == '0' || s[0] == '1') { - ret = s[0] - '0'; - if (s[1]) - goto bad; - } else { - bad: - eprintf(_("Value of configuration `%s' must be either `1' or `0'."), key); - } - return ret; -} - - -/** - * atof(3)-like wrapper for strtod(3) that checks that the string is valid - * - * @param s The string to parse - * @param key The name of the configuration assigned the value `s` - * @return The encoded value - */ -static double -checked_atof(const char *s, const char *key) -{ - double ret; - errno = 0; - ret = strtod(s, (void *)&s); - if (errno || *s) - eprintf(_("Value of configuration `%s' is not a value decimal value."), key); - return ret; -} - - -/** - * Split a list of values, and remove leading and trailing whitespace - * from each value - * - * @param s The string to split; will be modified - * @param count The number of despired strings - * @param strs Output array for the strings; each element will - * be set to `NULL` or `s` with an offset - * @param delim The character `s` shall be split by, cannot be - * a whitespace character - * @return 1 if `s` is valid, 0 otherwise - * - * If `count` is 1, - * the value most be specified, - * if `count` is 2, - * at least one of values must be specified - * if `count` is 3, - * all values most be specified, otherwise `s` must only contain - * on value, and no colon, which will be used from each output value, or - * if `count` is 6, - * `s` must be on one of the formats: - * `a`: - * the specified value is used for each output value, - * `a:b`: - * the three lower output values will be set to `a`, which may be empty/`NULL`, and - * the three upper output values will be set to `b`, which may be empty/`NULL`; - * at least `a` or `b` must be non-empty, - * `a:b:c`: - * each value most be specified, `s` will be interpreted as `a:b:c:a:b:c`, - * `:a:b:c`: - * each value most be specified, the lower three values be set to `NULL`, - * and `a`, `b`, `c` will be used fo the upper three values, - * `a:b:c:`: - * each value most be specified, the upper three values be set to `NULL`, - * and `a`, `b`, `c` will be used fo the lower three values, or - * `a:b:c:d:e:f`: - * each value most be specified; - * where ':' represents `delim` - * - * Summarily said, `s` may contain a scalar value or a 3-tuple, and it may - * also contain a value or one value for daytime and one value or nighttime. - * If configured to use 3-tuple but scalar is provided, the provided value is - * used for each of the 3 requested values. If configured to use daytime and - * nighttime, but only one is specified it is used for both, but if `s` - * starts with `delim`, daytime is skipped but if `s` ends with `delim`, - * nighttime, is skipped; but both cannot be skipped. - */ -static int -get_strings(char *s, int count, char *strs[], char delim) -{ - int i = 0, n; - - /* Split by colon and left-trim */ - for (i = 0; i < count;) { - strs[i++] = s = ltrim(s); - s = strchr(s, delim); - if (!s) - break; - *s++ = '\0'; - } - n = i; - - /* Confirm no excess strings */ - if (s && *ltrim(s)) - return 0; - - /* Right-trim and replace empty strings with NULL */ - for (i = 0; i < n; i++) - if (!*rtrim(strs[i], NULL)) - strs[i] = NULL; - - /* Validate NULLs */ - switch (n) { - case 1: - /* must be specified */ - if (!strs[0]) - return 0; - break; - case 2: - /* at least one most be specified */ - if (!strs[0] && !strs[1]) - return 0; - break; - case 3: - /* each most be specified */ - if (!strs[0] || !strs[1] || !strs[2]) - return 0; - break; - case 4: - /* exactly either the first or the last shall be NULL */ - if (!strs[0] == !strs[3] || !strs[1] || !strs[2]) - return 0; - break; - case 6: - /* each most be specified */ - if (!strs[0] || !strs[1] || !strs[2] || !strs[3] || !strs[4] || !strs[5]) - return 0; - break; - default: - /* n==5 is always invalid */ - return 0; - } - - /* Duplicate to fill `strs` */ - switch (count) { - case 2: - if (n == 1) - strs[1] = strs[0]; - break; - case 3: - if (n == 1) - strs[2] = strs[1] = strs[0]; - else if (n == 2) - return 0; - break; - case 6: - if (n == 1) { - strs[5] = strs[4] = strs[3] = strs[2] = strs[1] = strs[0]; - } else if (n == 2) { - strs[5] = strs[4] = strs[3] = strs[1]; - strs[2] = strs[1] = strs[0]; - } else if (n == 3) { - strs[5] = strs[2]; - strs[4] = strs[1]; - strs[3] = strs[0]; - } else if (n == 4 && !strs[0]) { - strs[5] = strs[3]; - strs[4] = strs[2]; - strs[3] = strs[1]; - strs[2] = NULL; - strs[1] = NULL; - } else if (n == 4) { - strs[5] = NULL; - strs[4] = NULL; - } - break; - default: - break; - } - - return 1; -} - - -/** - * Parse and set temperature settings - * - * @param str The temperature specification to parse - * @param day The currently specified temperature for daytime, - * will be updated; `NULL` if it shall not be set - * @param night The currently specified temperature for nighttime, - * will be updated; `NULL` if it shall not be set - * @param key The configuration file setting being parsed, - * `NULL` if parsing the command line - */ -static void -set_temperature(char *str, struct setting_lu *day, struct setting_lu *night, const char *key) -{ - struct setting_lu *settings[] = {day, night}; - enum setting_source source = key ? SETTING_CONFIGFILE : SETTING_CMDLINE; - char *strs[2], *end; - size_t i, j; - - if (!get_strings(str, !!day + !!night, strs, ':')) { - invalid: - weprintf(_("Malformed temperature argument.")); - eprintf(_("Try `-h' for more information.")); - } - - errno = 0; - for (i = 0, j = 0; i < ELEMSOF(settings); j += settings[i++] ? 1 : 0) { - if (!settings[i] || !strs[j] || settings[i]->source > source) - continue; - if (settings[i]->source & SETTING_CONFIGFILE) { - if (i == 0) - weprintf(_("Daytime temperature specified multiple times in configuration file.")); - else - weprintf(_("Night temperature specified multiple times in configuration file.")); - } - settings[i]->source |= source; - settings[i]->value = strtoul(strs[j], &end, 10); - if (errno || end[*end == 'K']) - goto invalid; - if (!WITHIN(MIN_TEMPERATURE, settings[i]->value, MAX_TEMPERATURE)) - eprintf(_("Temperature must be between %luK and %luK."), MIN_TEMPERATURE, MAX_TEMPERATURE); - } -} - - -/** - * Parse and set whitepoint brightness settings - * - * @param str The brightness specification to parse - * @param day The currently specified brightness for daytime, - * will be updated; `NULL` if it shall not be set - * @param night The currently specified brightness for nighttime, - * will be updated; `NULL` if it shall not be set - * @param key The configuration file setting being parsed, - * `NULL` if parsing the command line - */ -static void -set_brightness(char *str, struct setting_f *day, struct setting_f *night, const char *key) -{ - struct setting_f *settings[] = {day, night}; - enum setting_source source = key ? SETTING_CONFIGFILE : SETTING_CMDLINE; - char *strs[2], *end; - size_t i, j; - - if (!get_strings(str, !!day + !!night, strs, ':')) { - invalid: - weprintf(_("Malformed brightness argument.")); - eprintf(_("Try `-h' for more information.")); - } - - errno = 0; - for (i = 0, j = 0; i < ELEMSOF(settings); j += settings[i++] ? 1 : 0) { - if (!settings[i] || !strs[j] || settings[i]->source > source) - continue; - if (settings[i]->source & SETTING_CONFIGFILE) { - if (i == 0) - weprintf(_("Daytime brightness specified multiple times in configuration file.")); - else - weprintf(_("Night brightness specified multiple times in configuration file.")); - } - settings[i]->source |= source; - settings[i]->value = strtod(strs[j], &end); - if (errno || *end) - goto invalid; - if (!WITHIN(MIN_BRIGHTNESS, settings[i]->value, MAX_BRIGHTNESS)) - eprintf(_("Brightness values must be between %.1f and %.1f."), MIN_BRIGHTNESS, MAX_BRIGHTNESS); - } -} - - -/** - * Parse and set gamma settings - * - * @param str The gamma specification to parse - * @param day The currently specified gamma for daytime, - * will be updated; `NULL` if it shall not be set - * @param night The currently specified gamma for nighttime, - * will be updated; `NULL` if it shall not be set - * @param key The configuration file setting being parsed, - * `NULL` if parsing the command line - */ -static void -set_gamma(char *str, struct setting_f3 *day, struct setting_f3 *night, const char *key) -{ - struct setting_f3 *settings[] = {day, night}; - enum setting_source source = key ? SETTING_CONFIGFILE : SETTING_CMDLINE; - char *strs[6], *end; - size_t i, j, k; - - if (!get_strings(str, 3 * (!!day + !!night), strs, ':')) { - invalid: - weprintf(_("Malformed gamma argument.")); - eprintf(_("Try `-h' for more information.")); - } - - errno = 0; - for (i = 0, j = 0; i < ELEMSOF(settings); j += settings[i++] ? 3 : 0) { - if (!settings[i] || !strs[j] || settings[i]->source > source) - continue; - if (settings[i]->source & SETTING_CONFIGFILE) { - if (i == 0) - weprintf(_("Daytime gamma specified multiple times in configuration file.")); - else - weprintf(_("Night gamma specified multiple times in configuration file.")); - } - settings[i]->source |= source; - for (k = 0; k < 3; k++) { - settings[i]->value[k] = strtod(strs[j + k], &end); - if (errno || *end) - goto invalid; - if (!WITHIN(MIN_GAMMA, settings[i]->value[k], MAX_GAMMA)) - eprintf(_("Gamma values must be between %.1f and %.1f."), MIN_GAMMA, MAX_GAMMA); - } - } -} - - -/** - * Parse and set solar elevation settings - * - * The fucntion assumes that the setting source is the command line - * - * @param str The gamma specification to parse - * @param day The currently specified lowest solar elevation for - * daytime, will be updated; `NULL` if it shall not be set - * @param night The currently specified highest solar elevation for - * nighttime, will be updated; `NULL` if it shall not be set - */ -static void -set_elevations(char *str, struct setting_f *day, struct setting_f *night) -{ - struct setting_f *settings[] = {day, night}; - const enum setting_source source = SETTING_CMDLINE; - char *strs[2], *end; - size_t i, j; - - if (!get_strings(str, !!day + !!night, strs, ':')) { - invalid: - weprintf(_("Malformed solar elevation argument.")); - eprintf(_("Try `-h' for more information.")); - } - - errno = 0; - for (i = 0, j = 0; i < ELEMSOF(settings); j += settings[i++] ? 1 : 0) { - if (!settings[i] || !strs[j] || settings[i]->source > source) - continue; - settings[i]->source |= source; - settings[i]->value = strtod(strs[j], &end); - if (errno || *end) - goto invalid; - } -} - - -/** - * Parse a time string on either of the formats "HH:MM" and "HH:MM:SS" - * - * Times up to, but excluding, 48:00 are supported. - * - * Leap seconds are not supported - * - * @param str String to parse - * @return The represented time, -1 if malformed - */ -static time_t -parse_time(char *str) -{ - time_t ret; - unsigned long int v; - - errno = 0; - - if (!isdigit(*str)) - return -1; - v = strtoul(str, &str, 10); - if (errno || *str++ != ':' || v >= 48UL) - return -1; - ret = (time_t)(v * 60UL * 60UL); - - if (!isdigit(*str)) - return -1; - v = strtoul(str, &str, 10); - if (errno || v >= 60UL) - return -1; - ret += (time_t)(v * 60UL); - - if (*str) { - if (*str++ != ':') - return -1; - if (!isdigit(*str)) - return -1; - v = strtoul(str, &str, 10); - if (errno || *str || v >= 60UL) - return -1; - ret += (time_t)v; - } - - return ret; -} - - -/** - * Parse and set a transition time setting - * - * @param str The transition time to parse - * @param start The currently specified transition start, will be updated - * @param end The currently specified transition end, will be updated - * @param key The configuration file setting being parsed, - * `NULL` if parsing the command line - * @return Normally 1, 0 if `str` is malformeda - */ -static int -set_transition_time(char *str, struct setting_time *start, struct setting_time *end, const char *key) -{ - struct setting_time *settings[] = {start, end}; - enum setting_source source = key ? SETTING_CONFIGFILE : SETTING_CMDLINE; - char *strs[ELEMSOF(settings)]; - int i; - - if (!get_strings(str, ELEMSOF(strs), strs, '-')) - return 0; - - for (i = 0; i < (int)ELEMSOF(settings); i++) { - if (!strs[i] || settings[i]->source > source) - continue; - if (settings[i]->source & SETTING_CONFIGFILE) { - if (i == 0) - weprintf(_("Start value for `%s' specified multiple times in configuration file."), key); - else - weprintf(_("End value for `%s' specified multiple times in configuration file."), key); - } - settings[i]->source |= source; - settings[i]->value = parse_time(strs[i]); - if (settings[i]->value < 0) - return 0; - } - - return 1; -} - - -/** - * Print list of available adjustment methods, - * and some helpful information - */ -static void -print_method_list(void) -{ - size_t i; - printf(_("Available adjustment methods:\n")); - for (i = 0; gamma_methods[i]; i++) - if (gamma_methods[i]->is_available()) - printf(" %s\n", gamma_methods[i]->name); - - printf("\n"); - printf(_("Specify colon-separated options with `-m METHOD:OPTIONS'.\n")); - /* TRANSLATORS: `help' must not be translated. */ - printf(_("Try `-m METHOD:help' for help.\n")); -} - - -/** - * Print list of available location providers, - * and some helpful information - */ -static void -print_provider_list(void) -{ - size_t i; - printf(_("Available location providers:\n")); - for (i = 0; location_providers[i]; i++) - printf(" %s\n", location_providers[i]->name); - - printf("\n"); - printf(_("Specify colon-separated options with `-l PROVIDER:OPTIONS'.\n")); - /* TRANSLATORS: `help' must not be translated. */ - printf(_("Try `-l PROVIDER:help' for help.\n")); -} - - -/** - * Get adjustment method by name - * - * @param name The name of the adjustment method to return - * @return The adjustment method - */ -GCC_ONLY(__attribute__((__pure__, __returns_nonnull__))) -static const struct gamma_method * -find_gamma_method(const char *name) -{ - size_t i; - for (i = 0; gamma_methods[i]; i++) - if (!strcasecmp(name, gamma_methods[i]->name)) - return gamma_methods[i]; - /* TRANSLATORS: This refers to the method used to adjust colours e.g. VidMode */ - eprintf(_("Unknown adjustment method `%s'."), name); -} - - -/** - * Get location provider by name - * - * @param name The name of the location provider to return - * @return The location provider - */ -GCC_ONLY(__attribute__((__pure__, __returns_nonnull__))) -static const struct location_provider * -find_location_provider(const char *name) -{ - size_t i; - for (i = 0; location_providers[i]; i++) - if (!strcasecmp(name, location_providers[i]->name)) - return location_providers[i]; - eprintf(_("Unknown location provider `%s'."), name); -} - - -/** - * Load default settings - * - * @param settings Output parameter for the settings - */ -static void -load_defaults(struct settings *settings) -{ - memset(settings, 0, sizeof(*settings)); /* set each `.source` to `SETTING_DEFAULT` and booleans to 0 */ - - settings->config_file = NULL; - settings->scheme_type = UNSPECIFIED_SCHEME; - - settings->day.temperature.value = DEFAULT_DAY_TEMPERATURE; - settings->day.brightness.value = DEFAULT_DAY_BRIGHTNESS; - settings->day.gamma.value[0] = DEFAULT_DAY_GAMMA; - settings->day.gamma.value[1] = DEFAULT_DAY_GAMMA; - settings->day.gamma.value[2] = DEFAULT_DAY_GAMMA; - - settings->night.temperature.value = DEFAULT_NIGHT_TEMPERATURE; - settings->night.brightness.value = DEFAULT_NIGHT_BRIGHTNESS; - settings->night.gamma.value[0] = DEFAULT_NIGHT_GAMMA; - settings->night.gamma.value[1] = DEFAULT_NIGHT_GAMMA; - settings->night.gamma.value[2] = DEFAULT_NIGHT_GAMMA; - - settings->hook_file.value = NULL; - settings->preserve_gamma.value = 1; - settings->use_fade.value = 1; - - settings->elevation_high.value = DEFAULT_HIGH_ELEVATION; - settings->elevation_low.value = DEFAULT_LOW_ELEVATION; - - settings->method = NULL; - settings->method_args = NULL; - - settings->provider = NULL; - settings->provider_args = NULL; -} - - -/** - * Load settings from the command line - * - * @param settings The currently loaded settings, will be updated - * @param argc Number of command line arguments - * @param argv `NULL` terminated list of command line arguments, - * including argument zero - */ -static void -load_from_cmdline(struct settings *settings, int argc, char *argv[]) -{ - const char *provider_name; - char *s, *end, *value; - - ARGBEGIN { - case 'b': - set_brightness(ARG(), &settings->day.brightness, &settings->night.brightness, NULL); - break; - - case 'c': - settings->config_file = ARG(); - break; - - case 'D': - settings->disabled.source |= SETTING_CMDLINE; - settings->disabled.value = 0; - break; - - case 'd': - settings->until_death = 1; - break; - - case 'E': - settings->scheme_type = CLOCK_SCHEME; - break; - - case 'e': - set_elevations(ARG(), &settings->elevation_high, &settings->elevation_low); - settings->scheme_type = SOLAR_SCHEME; - break; - - case 'g': - set_gamma(ARG(), &settings->day.gamma, &settings->night.gamma, NULL); - break; - - case 'H': - settings->hook_file.source |= SETTING_CMDLINE; - free(settings->hook_file.value); - settings->hook_file.value = ARG(); - break; - - case 'h': - print_help(); - exit(0); - - case 'l': - value = ARG(); - - /* Print list of providers if argument is `list' */ - if (!strcasecmp(value, "list")) { - print_provider_list(); - exit(0); - } - - provider_name = NULL; - - /* Don't save the result of strtof(); we simply want - to know if value can be parsed as a float. */ - errno = 0; - strtof(value, &end); - if (!errno && *end == ':') { - /* Use instead as arguments to `manual'. */ - provider_name = "manual"; - settings->provider_args = value; - } else { - /* Split off provider arguments. */ - s = strchr(value, ':'); - if (s) { - *s++ = '\0'; - settings->provider_args = s; - } - - provider_name = value; - } - - /* Lookup provider from name. */ - settings->provider = find_location_provider(provider_name); - - /* Print provider help if arg is `help'. */ - if (settings->provider_args && !strcasecmp(settings->provider_args, "help")) { - settings->provider->print_help(); - exit(0); - } - break; - - case 'm': - value = ARG(); - - /* Print list of methods if argument is `list' */ - if (!strcasecmp(value, "list")) { - print_method_list(); - exit(0); - } - - /* Split off method arguments. */ - s = strchr(value, ':'); - if (s) { - *s++ = '\0'; - settings->method_args = s; - } - - /* Find adjustment method by name. */ - settings->method = find_gamma_method(value); - - /* Print method help if arg is `help'. */ - if (settings->method_args && !strcasecmp(settings->method_args, "help")) { - settings->method->print_help(); - exit(0); - } - break; - - case 'O': - mode = PROGRAM_MODE_ONE_SHOT; - set_temperature(ARG(), &settings->day.temperature, &settings->night.temperature, NULL); - break; - - case 'o': - mode = PROGRAM_MODE_ONE_SHOT; - break; - - case 'P': - settings->preserve_gamma.source |= SETTING_CMDLINE; - settings->preserve_gamma.value = 0; - break; - - case 'p': - mode = PROGRAM_MODE_PRINT; - break; - - case 'r': - settings->use_fade.source |= SETTING_CMDLINE; - settings->use_fade.value = 0; - break; - - case 't': - set_temperature(ARG(), &settings->day.temperature, &settings->night.temperature, NULL); - break; - - case 'V': - printf("%s\n", VERSION_STRING); - exit(0); - - case 'v': - verbose = 1; - break; - - case 'x': - mode = PROGRAM_MODE_RESET; - break; - - default: - usage(); - - } ARGALT('+') { - case 'D': - settings->disabled.source |= SETTING_CMDLINE; - settings->disabled.value = 1; - break; - - case 'E': - settings->scheme_type = SOLAR_SCHEME; - break; - - case 'P': - settings->preserve_gamma.source |= SETTING_CMDLINE; - settings->preserve_gamma.value = 1; - break; - - case 'r': - settings->use_fade.source |= SETTING_CMDLINE; - settings->use_fade.value = 1; - break; - - default: - usage(); - } ARGEND; - - if (argc) - usage(); -} - - -/** - * Load an setting, form the "redshift" section, from the configuration file - * - * @param settings The currently loaded settings, will be updated - * @param key The name of the configuration - * @param value The value of the configuration - */ -static void -load_from_config_ini(struct settings *settings, const char *key, char *value) -{ - if (!strcasecmp(key, "temp") || !strcasecmp(key, "temperature")) { - set_temperature(value, &settings->day.temperature, &settings->night.temperature, key); - } else if (!strcasecmp(key, "temp-day") || !strcasecmp(key, "temperature-day")) { - set_temperature(value, &settings->day.temperature, NULL, key); - } else if (!strcasecmp(key, "temp-night") || !strcasecmp(key, "temperature-night")) { - set_temperature(value, NULL, &settings->night.temperature, key); - - } else if (!strcasecmp(key, "brightness")) { - set_brightness(value, &settings->day.brightness, &settings->night.brightness, key); - } else if (!strcasecmp(key, "brightness-day")) { - set_brightness(value, &settings->day.brightness, NULL, key); - } else if (!strcasecmp(key, "brightness-night")) { - set_brightness(value, NULL, &settings->night.brightness, key); - - } else if (!strcasecmp(key, "gamma")) { - set_gamma(value, &settings->day.gamma, &settings->night.gamma, key); - } else if (!strcasecmp(key, "gamma-day")) { - set_gamma(value, &settings->day.gamma, NULL, key); - } else if (!strcasecmp(key, "gamma-night")) { - set_gamma(value, NULL, &settings->night.gamma, key); - - } else if (!strcasecmp(key, "transition")) { - weprintf(_("`transition' is deprecated and has been replaced with `fade'.")); - goto set_use_fade; - } else if (!strcasecmp(key, "fade")) { - set_use_fade: - if (settings->use_fade.source & SETTING_CONFIGFILE) - weprintf(_("`fade' setting specified multiple times in configuration file.")); - settings->use_fade.source |= SETTING_CONFIGFILE; - if (settings->use_fade.source <= SETTING_CONFIGFILE) - settings->use_fade.value = get_boolean(value, key); - - } else if (!strcasecmp(key, "hook")) { - if (settings->hook_file.source & SETTING_CONFIGFILE) - weprintf(_("`hook' setting specified multiple times in configuration file.")); - settings->hook_file.source |= SETTING_CONFIGFILE; - if (settings->hook_file.source <= SETTING_CONFIGFILE) { - free(settings->hook_file.value); - settings->hook_file.value = estrdup(value); - } - - } else if (!strcasecmp(key, "preserve-gamma")) { - if (settings->preserve_gamma.source & SETTING_CONFIGFILE) - weprintf(_("`preserve-gamma' setting specified multiple times in configuration file.")); - settings->preserve_gamma.source |= SETTING_CONFIGFILE; - if (settings->preserve_gamma.source <= SETTING_CONFIGFILE) - settings->preserve_gamma.value = get_boolean(value, key); - - } else if (!strcasecmp(key, "start-disabled")) { - if (settings->disabled.source & SETTING_CONFIGFILE) - weprintf(_("`start-disabled' setting specified multiple times in configuration file.")); - settings->disabled.source |= SETTING_CONFIGFILE; - if (settings->disabled.source <= SETTING_CONFIGFILE) - settings->disabled.value = get_boolean(value, key); - - } else if (!strcasecmp(key, "elevation-high")) { - if (settings->elevation_high.source & SETTING_CONFIGFILE) - weprintf(_("`elevation-high' setting specified multiple times in configuration file.")); - settings->elevation_high.source |= SETTING_CONFIGFILE; - if (settings->elevation_high.source <= SETTING_CONFIGFILE) - settings->elevation_high.value = checked_atof(value, key); - - } else if (!strcasecmp(key, "elevation-low")) { - if (settings->elevation_low.source & SETTING_CONFIGFILE) - weprintf(_("`elevation-low' setting specified multiple times in configuration file.")); - settings->elevation_low.source |= SETTING_CONFIGFILE; - if (settings->elevation_low.source <= SETTING_CONFIGFILE) - settings->elevation_low.value = checked_atof(value, key); - - } else if (!strcasecmp(key, "dawn-time")) { - if (!set_transition_time(value, &settings->dawn_start, &settings->dawn_end, key)) - eprintf(_("Malformed dawn-time setting `%s'."), value); - - } else if (!strcasecmp(key, "dusk-time")) { - if (!set_transition_time(value, &settings->dusk_start, &settings->dusk_end, key)) - eprintf(_("Malformed dusk-time setting `%s'."), value); - - } else if (!strcasecmp(key, "adjustment-method")) { - if (!settings->method) - settings->method = find_gamma_method(value); - - } else if (!strcasecmp(key, "location-provider")) { - if (!settings->provider) - settings->provider = find_location_provider(value); - - } else { - weprintf(_("Unknown configuration setting `%s'."), key); - } -} - - -void -load_settings(struct settings *settings, int argc, char *argv[]) -{ - struct config_ini_section *section; - struct config_ini_setting *setting; - const struct time_period *first, *current; - const char *conf_path, *p; - char *conf_pathbuf, *s; - int i, j, n; - time_t duration; - size_t len; - - /* Clear unused bit so they do not interfere with comparsion */ - memset(&day_settings, 0, sizeof(day_settings)); - memset(&night_settings, 0, sizeof(night_settings)); - - /* Load settings; some validation takes place */ - load_defaults(settings); - load_from_cmdline(settings, argc, argv); - conf_path = config_ini_init(&settings->config, settings->config_file, &conf_pathbuf); - if ((section = config_ini_get_section(&settings->config, "redshift"))) - for (setting = section->settings; setting; setting = setting->next) - load_from_config_ini(settings, setting->name, setting->value); - - /* Further validate settings and select scheme */ - n = !!settings->dawn_start.source + !!settings->dawn_end.source; - n += !!settings->dusk_start.source + !!settings->dusk_end.source; - if (settings->scheme_type == SOLAR_SCHEME) { - n = 0; - } else if (settings->scheme_type == CLOCK_SCHEME) { - if (!n) - eprintf(_("`-E' option used with a time-configuration configured.")); - } - if (n) { - scheme.type = CLOCK_SCHEME; - if (n != 4) - eprintf(_("Partial time-configuration not supported!")); - - if (settings->dawn_start.value >= ONE_DAY || settings->dusk_start.value >= ONE_DAY || - labs((long)settings->dawn_end.value - (long)settings->dawn_start.value) > (long)ONE_DAY || - labs((long)settings->dusk_end.value - (long)settings->dusk_start.value) > (long)ONE_DAY) - goto invalid_twilight; - - /* TODO deal with edge-case where one of the twilights last 24 hour */ - settings->dawn_end.value %= ONE_DAY; - settings->dusk_end.value %= ONE_DAY; - if (settings->dawn_start.value <= settings->dawn_end.value) { - if (BETWEEN(settings->dawn_start.value, settings->dusk_start.value, settings->dawn_end.value) || - BETWEEN(settings->dawn_start.value, settings->dusk_end.value, settings->dawn_end.value)) - goto invalid_twilight; - } else { - if (!WITHIN(settings->dawn_end.value, settings->dusk_start.value, settings->dawn_start.value) || - !WITHIN(settings->dawn_end.value, settings->dusk_end.value, settings->dawn_start.value)) - goto invalid_twilight; - } - } - if (settings->elevation_high.value < settings->elevation_low.value) - eprintf(_("High transition elevation cannot be lower than the low transition elevation.")); - - /* If resetting effects, use neutral colour settings (static scheme) and do not preserve gamma */ - if (mode == PROGRAM_MODE_RESET) { - scheme.type = STATIC_SCHEME; - settings->preserve_gamma.value = 0; - day_settings = COLOUR_SETTING_NEUTRAL; - night_settings = COLOUR_SETTING_NEUTRAL; - goto settings_published; - } - - /* Make hook file absolute if set from config file (relative to config file) */ - if (settings->hook_file.source == SETTING_CONFIGFILE && conf_path) { -#ifdef WINDOWS - /* Regular absolute path */ - if (isalpha(settings->hook_file.value[0]) && settings->hook_file.value[1] == ':') - goto absolute_hook_path; - /* Absolute extended path or network path (relative extended paths do not exist) */ - if (settings->hook_file.value[0] == '\\' && settings->hook_file.value[1] == '\\') - goto absolute_hook_path; - /* Path relative to root */ - if (settings->hook_file.value[0] == '\\' || settings->hook_file.value[0] == '/') { - /* This is safe as we know that `conf_path` is a valid path */ - if (isalpha(conf_path[0]) && conf_path[1] == ':') { - p = &conf_path[3]; - goto base_found; - } else if (conf_path[0] == '\\' && conf_path[1] == '\\') { - p = &conf_path[2]; - while (*p == '\\') - p++; - while (*p != '/' && *p != '\\') - p++; - goto base_found; - } - } -#else - if (settings->hook_file.value[0] == '/') - goto absolute_hook_path; -#endif - p = strrchr(conf_path, '/'); - p = p ? &p[1] : conf_path; -#ifdef WINDOWS - if (strrchr(p, '\\')) - p = &strrchr(p, '\\')[1]; - base_found: -#endif - len = (size_t)(p - conf_path); - s = emalloc(len + strlen(settings->hook_file.value) + 1U); - memcpy(s, conf_path, len); - stpcpy(&s[len], settings->hook_file.value); - free(settings->hook_file.value); - settings->hook_file.value = s; -#ifdef WINDOWS - /* Used extended path is too long */ - if (settings->hook_file.value[0] != '\\' && (len = strlen(settings->hook_file.value)) >= 260) { - /* We have already made sure the path is absolute, so \ prefix is always extended or network path */ - settings->hook_file.value = erealloc(settings->hook_file.value, len + sizeof("\\\\?\\")); - memmove(&settings->hook_file.value[4], &settings->hook_file.value, len + 1U); - settings->hook_file.value[0] = '\\'; - settings->hook_file.value[1] = '\\'; - settings->hook_file.value[2] = '?'; - settings->hook_file.value[3] = '\\'; - } -#endif - } - free(conf_pathbuf); -absolute_hook_path: - - /* Publish loaded settings */ - if (mode == PROGRAM_MODE_ONE_SHOT && settings->until_death) - mode = PROGRAM_MODE_UNTIL_DEATH; - hook_file = settings->hook_file.value, settings->hook_file.value = NULL; - preserve_gamma = settings->preserve_gamma.value; - use_fade = settings->use_fade.value; - disable ^= settings->disabled.value; - day_settings.temperature = settings->day.temperature.value; - day_settings.brightness = settings->day.brightness.value; - day_settings.gamma[0] = settings->day.gamma.value[0]; - day_settings.gamma[1] = settings->day.gamma.value[1]; - day_settings.gamma[2] = settings->day.gamma.value[2]; - night_settings.temperature = settings->night.temperature.value; - night_settings.brightness = settings->night.brightness.value; - night_settings.gamma[0] = settings->night.gamma.value[0]; - night_settings.gamma[1] = settings->night.gamma.value[1]; - night_settings.gamma[2] = settings->night.gamma.value[2]; - if (!memcmp(&day_settings, &night_settings, sizeof(day_settings))) { - /* If the effects are the same throughout the day, do not use a transition scheme */ - scheme.type = STATIC_SCHEME; - } else if (scheme.type == SOLAR_SCHEME) { - scheme.elevation.high = settings->elevation_high.value; - scheme.elevation.low = settings->elevation_low.value; - scheme.elevation.range = scheme.elevation.high - scheme.elevation.low; - } else if (scheme.type == CLOCK_SCHEME) { - scheme.time.periods = &scheme.time.periods_array[0]; - scheme.time.periods_array[0].start = settings->dawn_start.value; - scheme.time.periods_array[0].day_level = 0.0; - scheme.time.periods_array[1].start = settings->dawn_end.value; - scheme.time.periods_array[1].day_level = 1.0; - scheme.time.periods_array[2].start = settings->dusk_start.value; - scheme.time.periods_array[2].day_level = 1.0; - scheme.time.periods_array[3].start = settings->dusk_end.value; - scheme.time.periods_array[3].day_level = 0.0; - for (i = 0; i < 4; i++) { - j = (i + 1) % 4; - scheme.time.periods_array[i].next = &scheme.time.periods_array[j]; - duration = scheme.time.periods_array[j].start - scheme.time.periods_array[i].start; - if (duration < 0) - duration += ONE_DAY; - scheme.time.periods_array[i].diff_over_duration = scheme.time.periods_array[j].day_level; - scheme.time.periods_array[i].diff_over_duration -= scheme.time.periods_array[i].day_level; - scheme.time.periods_array[i].diff_over_duration /= duration ? (double)duration : 1.0; - } - } -settings_published: - - /* Output settings */ - if (verbose) { - if (scheme.type == SOLAR_SCHEME) { - /* TRANSLATORS: Append degree symbols if possible. */ - printf(_("Solar elevations: day above %.1f, night below %.1f\n"), - scheme.elevation.high, scheme.elevation.low); - } else if (scheme.type == CLOCK_SCHEME) { - printf(_("Schedule:\n")); - current = first = scheme.time.periods; - do { - printf(_(" %.2f%% day at %02u:%02u:%02u\n"), - current->day_level * 100, (unsigned)(current->start / 60 / 60 % 24), - (unsigned)(current->start / 60 % 60), (unsigned)(current->start % 60)); - } while ((current = current->next) != first); - printf(_("(End of schedule)\n")); - } - printf(_("Temperatures: %luK at day, %luK at night\n"), - day_settings.temperature, night_settings.temperature); - printf(_("Brightness: %.2f:%.2f\n"), settings->day.brightness.value, settings->night.brightness.value); - /* TRANSLATORS: The string in parenthesis is either Daytime or Night (translated). */ - printf(_("Gamma (%s): %.3f, %.3f, %.3f\n"), _("Daytime"), - day_settings.gamma[0], day_settings.gamma[1], day_settings.gamma[2]); - printf(_("Gamma (%s): %.3f, %.3f, %.3f\n"), _("Night"), - night_settings.gamma[0], night_settings.gamma[1], night_settings.gamma[2]); - } - - return; - -invalid_twilight: - eprintf(_("Invalid dawn/dusk time configuration!")); -} diff --git a/src/config.mk b/src/config.mk deleted file mode 100644 index 00a032c..0000000 --- a/src/config.mk +++ /dev/null @@ -1,20 +0,0 @@ -PREFIX = /usr -MANPREFIX = $(PREFIX)/share/man -LOCALEDIR = $(PREFIX)/share/locale - -PACKAGE = redshift-ng - -CC = c99 - -PKGCONFIG = pkg-config -PKGCONFIG_CFLAGS = $(PKGCONFIG) --cflags -PKGCONFIG_LDFLAGS = $(PKGCONFIG) --libs - -GEOCLUE_LIBS = glib-2.0 gio-2.0 - -LIBS_PKGCONFIG = $(GEOCLUE_LIBS) libgamma - -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE\ - -DENABLE_GEOCLUE2 -DENABLE_COOPGAMMA -CFLAGS = $$($(PKGCONFIG_CFLAGS) $(LIBS_PKGCONFIG)) -LDFLAGS = $$($(PKGCONFIG_LDFLAGS) $(LIBS_PKGCONFIG)) -lm -lcoopgamma -lred -lgeome diff --git a/src/gamma-coopgamma.c b/src/gamma-coopgamma.c deleted file mode 100644 index f51c0ee..0000000 --- a/src/gamma-coopgamma.c +++ /dev/null @@ -1,535 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - -#include <libcoopgamma.h> - -#if defined(__clang__) -# pragma clang diagnostic ignored "-Wkeyword-macro" -#endif - - -struct coopgamma_output_id { - char *edid; - size_t index; -}; - - -struct coopgamma_crtc_state { - libcoopgamma_filter_t filter; - libcoopgamma_ramps_t plain_ramps; - size_t rampsize; -}; - - -struct gamma_state { - libcoopgamma_context_t ctx; - struct coopgamma_crtc_state *crtcs; - size_t n_crtcs; - char **methods; - char *method; - char *site; - int64_t priority; - int list_outputs; - struct coopgamma_output_id *outputs; - size_t n_outputs; - size_t a_outputs; -}; - - -struct signal_blockage {int dummy;}; - - -static int -unblocked_signal(int signo, struct signal_blockage *prev) -{ - /* TODO */ - (void) signo; - (void) prev; - return 0; -} - - -static int -restore_signal_blockage(int signo, const struct signal_blockage *blockage) -{ - /* TODO */ - (void) signo; - (void) blockage; - return 0; -} - - -static int -update(struct gamma_state *state) -{ - size_t i; - for (i = 0; i < state->n_crtcs; i++) - libcoopgamma_set_gamma_sync(&state->crtcs[i].filter, &state->ctx); - return 0; -} - - -static void -print_error(struct gamma_state *state) -{ - unsigned long long int ec = (unsigned long long int)state->ctx.error.number; - if (state->ctx.error.custom) { - if (ec && state->ctx.error.description) { - if (state->ctx.error.server_side) - weprintf(_("Server-side error number %llu: %s."), ec, state->ctx.error.description); - else - weprintf(_("Client-side error number %llu: %s."), ec, state->ctx.error.description); - } else if (ec) { - if (state->ctx.error.server_side) - weprintf(_("Server-side error number %llu."), ec); - else - weprintf(_("Client-side error number %llu."), ec); - } else if (state->ctx.error.description) { - if (state->ctx.error.server_side) - weprintf(_("Server-side error: %s."), state->ctx.error.description); - else - weprintf(_("Client-side error: %s."), state->ctx.error.description); - } - } else if (state->ctx.error.description) { - if (state->ctx.error.server_side) - weprintf(_("Server-side error: %s."), state->ctx.error.description); - else - weprintf(_("Client-side error: %s."), state->ctx.error.description); - } else { - if (state->ctx.error.server_side) - weprintf(_("Server-side error: %s."), strerror(state->ctx.error.number)); - else - weprintf(_("Client-side error: %s."), strerror(state->ctx.error.number)); - } -} - - -static int -coopgamma_is_available(void) -{ - return 1; -} - - -static int -coopgamma_create(struct gamma_state **state_out) -{ - struct gamma_state *state; - struct signal_blockage signal_blockage; - - state = *state_out = ecalloc(1, sizeof(**state_out)); - - if (libcoopgamma_context_initialise(&state->ctx)) { - weprintf("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; - state->methods = libcoopgamma_get_methods(); - if (state->methods == NULL) { - weprintf("libcoopgamma_get_methods:"); - if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) - exit(1); - return -1; - } - if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) - return -1; - - state->priority = 0x0800000000000000LL; - - return 0; -} - - -static int -coopgamma_start(struct gamma_state *state) -{ - 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: - lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - break; - case PROGRAM_MODE_CONTINUAL: - case PROGRAM_MODE_UNTIL_DEATH: - lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - break; - default: - case PROGRAM_MODE_PRINT: - abort(); - } - - 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) - weprintf("libcoopgamma_connect:"); - else - weprintf(_("libcoopgamma_connect: could not start coopgamma server.")); - if (restore_signal_blockage(SIGCHLD, &signal_blockage) < 0) - exit(1); - 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) { - print_error(state); - return -1; - } - printf(_("Available outputs:\n")); - for (i = 0; outputs[i]; i++) - printf(" %s\n", outputs[i]); - if (ferror(stdout)) - eprintf("printf:"); - exit(0); - } - - /* Translate crtc=N to edid=EDID */ - for (i = 0; i < state->n_outputs; i++) { - if (state->outputs[i].edid) - continue; - if (state->outputs[i].index >= n_outputs) { - weprintf(_("Monitor number %zu does not exist, available monitors are [0, %zu]"), - state->outputs[i].index, n_outputs - 1); - return -1; - } - state->outputs[i].edid = estrdup(outputs[state->outputs[i].index]); - } - - /* Use all outputs if none were specified */ - if (state->n_outputs == 0) { - state->n_outputs = state->a_outputs = n_outputs; - state->outputs = emalloc(n_outputs * sizeof(*state->outputs)); - for (i = 0; i < n_outputs; i++) - state->outputs[i].edid = estrdup(outputs[i]); - } - - free(outputs); - - /* Initialise information for each output */ - state->crtcs = ecalloc(state->n_outputs, sizeof(*state->crtcs)); - for (i = 0; i < state->n_outputs; i++) { - libcoopgamma_crtc_info_t info; - struct coopgamma_crtc_state *crtc = state->crtcs + state->n_crtcs; - - crtc->filter.priority = state->priority; - crtc->filter.crtc = state->outputs[i].edid; - crtc->filter.lifespan = lifespan; -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" -#endif - crtc->filter.class = PACKAGE "::redshift::standard"; -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - - if (libcoopgamma_get_gamma_info_sync(crtc->filter.crtc, &info, &state->ctx) < 0) { - int saved_errno = errno; - weprintf(_("Failed to retrieve information for output `%s':\n"), outputs[i]); - errno = saved_errno; - print_error(state); - return -1; - } - if (!info.cooperative) { - weprintf(_("coopgamma is not available.\n")); - return -1; - } - if (info.supported == LIBCOOPGAMMA_NO) { - weprintf(_("Output `%s' does not support gamma adjustments, skipping."), outputs[i]); - continue; - } - - /* Get total size of the ramps */ - switch (info.depth) { -#define X(SUFFIX, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - crtc->rampsize = sizeof(TYPE);\ - break - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - default: - if (info.depth > 0) { - weprintf(_("output `%s' uses an unsupported depth " - "for its gamma ramps: %i bits, skipping\n"), - outputs[i], info.depth); - } else { - weprintf(_("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, RAMPS, TYPE, 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 * (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 * (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 * (MAX);\ - }\ - break - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#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(struct gamma_state *state) -{ - free(state->methods); - free(state->method); - free(state->site); - - 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); - } - free(state->crtcs); - - libcoopgamma_context_destroy(&state->ctx, 1); - while (state->n_outputs--) - free(state->outputs[state->n_outputs].edid); - state->n_outputs = 0; - free(state->outputs); - - free(state); -} - - -static void -coopgamma_print_help(void) /* TODO not documented in readme and manpage */ -{ - printf(_("Adjust gamma ramps with coopgamma.\n")); - printf("\n"); - - printf(" display=%s %s\n", _("NAME "), _("Display server instance to apply adjustments to")); - printf(" crtc=%s %s\n", _("N "), _("Index of CRTC to apply adjustments to")); - printf(" edid=%s %s\n", _("EDID "), _("EDID of monitor to apply adjustments to, " - "enter `list' to list available monitors")); - printf(" priority=%s %s\n", _("N "), _("The application order of the adjustments, " - "default value is 576460752303423488")); - printf(" method=%s %s\n", _("NAME "), _("Underlaying adjustment method, " - "enter `list' to list available methods")); - printf("\n"); -} - - -static int -coopgamma_set_option(struct gamma_state *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) { - weprintf(_("Value of method parameter `crtc' must be a integer in [%lli, %lli]."), - (long long int)INT64_MIN, (long long int)INT64_MAX); - return -1; - } - state->priority = priority; - } else if (!strcasecmp(key, "method")) { - if (state->method != NULL) { - weprintf(_("Method parameter `method' can only be used once.")); - 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)) - eprintf("printf:"); - exit(0); - } - state->method = estrdup(value); - } else if (!strcasecmp(key, "display")) { - if (state->site != NULL) { - weprintf(_("Method parameter `display' can only be used once.")); - return -1; - } - state->site = estrdup(value); - } else if (!strcasecmp(key, "edid") || !strcasecmp(key, "crtc")) { - if (state->n_outputs == state->a_outputs) { - state->a_outputs += 8; - state->outputs = erealloc(state->outputs, state->a_outputs * sizeof(*state->outputs)); - } - if (!strcasecmp(key, "edid")) { - state->outputs[state->n_outputs].edid = estrdup(value); - 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) { - weprintf(_("Value of method parameter `crtc' must be a non-negative integer.")); - return -1; - } - } - state->n_outputs++; - } else { - weprintf(_("Unknown method parameter: `%s'."), key); - return -1; - } - - return 0; -} - - -static void -coopgamma_restore(struct gamma_state *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_apply(struct gamma_state *state, const struct colour_setting *setting, int perserve) -{ - libcoopgamma_filter_t *filter; - libcoopgamma_filter_t *last_filter = NULL; - size_t i; - - (void) perserve; - - 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 && - 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, RAMPS, TYPE, MAX, DEPTH)\ - case DEPTH:\ - fill_ramps_##SUFFIX((void *)(filter->ramps.u8.red),\ - (void *)(filter->ramps.u8.green),\ - (void *)(filter->ramps.u8.blue),\ - NULL, NULL, NULL,\ - filter->ramps.u8.red_size,\ - filter->ramps.u8.green_size,\ - filter->ramps.u8.blue_size,\ - setting);\ - break - LIST_RAMPS_STOP_VALUE_TYPES(X, ;); -#undef X - default: - abort(); - } - } - - return update(state); -} - - -const struct gamma_method coopgamma_gamma_method = GAMMA_METHOD_INIT("coopgamma", 1, 0, coopgamma); diff --git a/src/gamma-drm.c b/src/gamma-drm.c deleted file mode 100644 index cecc836..0000000 --- a/src/gamma-drm.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -drm_is_available(void) -{ - return libgamma_is_method_available(LIBGAMMA_METHOD_LINUX_DRM); -} - - -static int -drm_create(struct gamma_state **state_out) -{ - return direct_create(state_out, LIBGAMMA_METHOD_LINUX_DRM, "drm"); -} - - -static void -drm_print_help(void) -{ - printf(_("Adjust gamma ramps with Direct Rendering Manager.\n")); - printf("\n"); - direct_print_help(LIBGAMMA_METHOD_LINUX_DRM); -} - - -#define drm_set_option direct_set_option -#define drm_start direct_start -#define drm_apply direct_apply -#define drm_restore direct_restore -#define drm_free direct_free -const struct gamma_method drm_gamma_method = GAMMA_METHOD_INIT("drm", 0, 0, drm); diff --git a/src/gamma-dummy.c b/src/gamma-dummy.c deleted file mode 100644 index de4b687..0000000 --- a/src/gamma-dummy.c +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -dummy_is_available(void) -{ - return 1; -} - - -static int -dummy_create(struct gamma_state **state_out) -{ - *state_out = NULL; - return 0; -} - - -static int -dummy_start(struct gamma_state *state) -{ - (void) state; - weprintf(_("WARNING: Using dummy gamma method! Display will not be affected by this gamma method.\n")); - return 0; -} - - -static void -dummy_restore(struct gamma_state *state) -{ - (void) state; -} - - -static void -dummy_free(struct gamma_state *state) -{ - (void) state; -} - - -static void -dummy_print_help(void) -{ - printf(_("Does not affect the display but prints the color temperature to the terminal.\n")); - printf("\n"); -} - - -static int -dummy_set_option(struct gamma_state *state, const char *key, const char *value) -{ - (void) state; - (void) value; - weprintf(_("Unknown method parameter: `%s'."), key); - return -1; -} - - -static int -dummy_apply(struct gamma_state *state, const struct colour_setting *setting, int preserve) -{ - (void) state; - (void) preserve; - printf(_("Temperature: %lu\n"), setting->temperature); - return 0; -} - - -const struct gamma_method dummy_gamma_method = GAMMA_METHOD_INIT("dummy", 0, 0, dummy); diff --git a/src/gamma-quartz.c b/src/gamma-quartz.c deleted file mode 100644 index c303031..0000000 --- a/src/gamma-quartz.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -quartz_is_available(void) -{ - return libgamma_is_method_available(LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS); -} - - -static int -quartz_create(struct gamma_state **state_out) -{ - return direct_create(state_out, LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS, "quartz"); -} - - -static void -quartz_print_help(void) -{ - printf(_("Adjust gamma ramps on macOS using Quartz.\n")); - printf("\n"); - direct_print_help(LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS); -} - - -#define quartz_set_option direct_set_option -#define quartz_start direct_start -#define quartz_apply direct_apply -#define quartz_restore direct_restore -#define quartz_free direct_free -const struct gamma_method quartz_gamma_method = GAMMA_METHOD_INIT("quartz", 1, 1, quartz); diff --git a/src/gamma-randr.c b/src/gamma-randr.c deleted file mode 100644 index 1ccd277..0000000 --- a/src/gamma-randr.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -randr_is_available(void) -{ - return libgamma_is_method_available(LIBGAMMA_METHOD_X_RANDR); -} - - -static int -randr_create(struct gamma_state **state_out) -{ - return direct_create(state_out, LIBGAMMA_METHOD_X_RANDR, "randr"); -} - - -static void -randr_print_help(void) -{ - printf(_("Adjust gamma ramps with the X RANDR extension.\n")); - printf("\n"); - direct_print_help(LIBGAMMA_METHOD_X_RANDR); -} - - -#define randr_set_option direct_set_option -#define randr_start direct_start -#define randr_apply direct_apply -#define randr_restore direct_restore -#define randr_free direct_free -const struct gamma_method randr_gamma_method = GAMMA_METHOD_INIT("randr", 1, 0, randr); diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c deleted file mode 100644 index 5c2bdf3..0000000 --- a/src/gamma-vidmode.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -vidmode_is_available(void) -{ - return libgamma_is_method_available(LIBGAMMA_METHOD_X_VIDMODE); -} - - -static int -vidmode_create(struct gamma_state **state_out) -{ - return direct_create(state_out, LIBGAMMA_METHOD_X_VIDMODE, "vidmode"); -} - - -static void -vidmode_print_help(void) -{ - printf(_("Adjust gamma ramps with the X VidMode extension.\n")); - printf("\n"); - direct_print_help(LIBGAMMA_METHOD_X_VIDMODE); -} - - -#define vidmode_set_option direct_set_option -#define vidmode_start direct_start -#define vidmode_apply direct_apply -#define vidmode_restore direct_restore -#define vidmode_free direct_free -const struct gamma_method vidmode_gamma_method = GAMMA_METHOD_INIT("vidmode", 1, 0, vidmode); diff --git a/src/gamma-wingdi.c b/src/gamma-wingdi.c deleted file mode 100644 index 6d983c5..0000000 --- a/src/gamma-wingdi.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -static int -wingdi_is_available(void) -{ - return libgamma_is_method_available(LIBGAMMA_METHOD_W32_GDI); -} - - -static int -wingdi_create(struct gamma_state **state_out) -{ - return direct_create(state_out, LIBGAMMA_METHOD_W32_GDI, "wingdi"); -} - - -static void -wingdi_print_help(void) -{ - printf(_("Adjust gamma ramps with the Windows GDI.\n")); - printf("\n"); - direct_print_help(LIBGAMMA_METHOD_W32_GDI); -} - - -#define wingdi_set_option direct_set_option -#define wingdi_start direct_start -#define wingdi_apply direct_apply -#define wingdi_restore direct_restore -#define wingdi_free direct_free -const struct gamma_method wingdi_gamma_method = GAMMA_METHOD_INIT("wingdi", 1, 0, wingdi); diff --git a/src/gamma.c b/src/gamma.c deleted file mode 100644 index 8dbb99b..0000000 --- a/src/gamma.c +++ /dev/null @@ -1,139 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -const struct gamma_method *gamma_methods[] = { -#ifdef ENABLE_COOPGAMMA - &coopgamma_gamma_method, -#endif - &drm_gamma_method, - &randr_gamma_method, - &vidmode_gamma_method, - &quartz_gamma_method, - &wingdi_gamma_method, - &dummy_gamma_method, - NULL -}; - - -/** - * Attempt to start a specific adjustment method - * - * @param method The adjustment method - * @param state_out Output parameter for the adjustment method state - * @param config Loaded information file - * @param args `NULL` or option part of the command line argument for the adjustment method - * @return 0 on success, -1 on failure - */ -static int -try_start(const struct gamma_method *method, GAMMA_STATE **state_out, struct config_ini_state *config, char *args) -{ - struct config_ini_section *section; - struct config_ini_setting *setting; - char *next_arg, *value; - const char *key; - - if (method->create(state_out) < 0) { - weprintf(_("Initialization of %s failed."), method->name); - goto fail; - } - - /* Set method options from config file */ - if ((section = config_ini_get_section(config, method->name))) - for (setting = section->settings; setting; setting = setting->next) - if (method->set_option(*state_out, setting->name, setting->value) < 0) - goto set_option_fail; - - /* Set method options from command line */ - for (; args && *args; args = next_arg) { - if (!strncasecmp(args, "display=", sizeof("display=") - 1U)) - next_arg = &args[strcspn(args, ";")]; - else - next_arg = &args[strcspn(args, ";:")]; - if (*next_arg) - *next_arg++ = '\0'; - - key = args; - value = strchr(args, '='); - if (!value) { - weprintf(_("Failed to parse option `%s'."), args); - goto fail; - } - *value++ = '\0'; - - if (method->set_option(*state_out, key, value) < 0) - goto set_option_fail; - } - - /* Start method */ - if (method->start(*state_out) < 0) { - weprintf(_("Failed to start adjustment method %s."), method->name); - goto fail; - } - - return 0; - -set_option_fail: - weprintf(_("Failed to set %s option."), method->name); - /* TRANSLATORS: `help' must not be translated. */ - weprintf(_("Try `-m %s:help' for more information."), method->name); -fail: - if (*state_out) { - method->free(*state_out); - *state_out = NULL; - } - return -1; -} - - -void -acquire_adjustment_method(struct settings *settings, GAMMA_STATE **method_state_out) -{ - size_t i; - - if (settings->method) { - /* Use method specified on command line */ - if (try_start(settings->method, method_state_out, &settings->config, settings->method_args) < 0) - exit(1); - } else { - /* Try all methods, use the first that works */ - for (i = 0; gamma_methods[i]; i++) { - if (!gamma_methods[i]->autostart) - continue; - if (!gamma_methods[i]->is_available()) - continue; - - if (try_start(gamma_methods[i], method_state_out, &settings->config, NULL) < 0) { - weprintf(_("Trying next method...")); - continue; - } - - /* Found method that works */ - printf(_("Using method `%s'.\n"), gamma_methods[i]->name); - settings->method = gamma_methods[i]; - break; - } - - /* Failure if no methods were successful at this point */ - if (!settings->method) - eprintf(_("No more methods to try.")); - } -} diff --git a/src/hooks.c b/src/hooks.c deleted file mode 100644 index 96f6f83..0000000 --- a/src/hooks.c +++ /dev/null @@ -1,249 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -/** - * Names of periods supplied to scripts - */ -static const char *period_names[] = { - [PERIOD_NONE] = "none", - [PERIOD_DAYTIME] = "daytime", - [PERIOD_NIGHT] = "night", - [PERIOD_TRANSITION] = "transition" -}; - - -/** - * Path name of the hook directory, `NULL` if not found - */ -static char *dirpath = NULL; - -/** - * The allocation size of `dirpath` - */ -static size_t dirpathsize; - -/** - * The length of the string in `dirpath` - */ -static size_t dirpathlen; - - -/** - * Paths, in order of priority, to test when looking for - * the hook directory for redshift - */ -static const struct env_path paths[] = { - {0, "XDG_CONFIG_HOME", "/redshift-ng/hooks"}, - {0, "XDG_CONFIG_HOME", "/redshift/hooks"}, -#if defined(WINDOWS) - {0, "localappdata", "/redshift-ng/hooks"}, - {0, "localappdata", "/redshift/hooks"}, -#endif - {0, "HOME", "/.config/redshift-ng/hooks"}, - {0, "HOME", "/.config/redshift/hooks"}, - {0, NULL, "/.config/redshift-ng/hooks"}, - {0, NULL, "/.config/redshift/hooks"}, - {1, "XDG_CONFIG_DIRS", "/redshift-ng/hooks"}, - {1, "XDG_CONFIG_DIRS", "/redshift/hooks"}, -#if !defined(WINDOWS) - {0, "", "/etc/redshift-ng/hooks"}, - {0, "", "/etc/redshift/hooks"} -#endif -}; - - -/** - * Deallocates `dirpath` - */ -static void -cleanup(void) -{ - free(dirpath); - dirpath = NULL; -} - - -/** - * Search for and open the hook directory for reading - * - * @param path_out Output parameter for the hook directroy path - * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * will be set to `NULL`; shall be free(3)d by the caller - * @return `DIR` object for the reading the directory; `NULL` if not found - */ -static DIR * -open_hooks_dir(const char **path_out, char **pathbuf_out) -{ - DIR *dir = NULL; - size_t i; - - *path_out = NULL; - *pathbuf_out = NULL; - - for (i = 0; !dir && i < ELEMSOF(paths); i++) - dir = try_path_opendir(&paths[i], path_out, pathbuf_out); - if (dir) - weprintf(_("Found hook directory `%s'."), *path_out); - else - weprintf(_("No hook directory found.")); - - return dir; -} - - -/** - * Run hook file - * - * @param path The path to the hook file - * @param argv `NULL` terminated list of command line arguments - * for the hooks; must contain an unused initial slot, - * which the function will use to provide the zeroth - * argument - */ -static void -run_hook(const char *path, const char *argv[]) -{ -#ifdef WINDOWS - /* TODO [Windows] hooks are not support on Windows */ -#else - switch (fork()) { - case -1: - weprintf("fork:"); - break; - - case 0: - if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) { - weprintf("dup2 <stdout> <stderr>:"); - _exit(1); - } - argv[0] = path; - execv(path, (const void *)argv); - if (errno != EACCES) - weprintf("execv %s:", path); - _exit(1); - - default: - /* SIGCHLD is ignored */ - break; - } -#endif -} - - -/** - * Run hooks - * - * @param argv `NULL` terminated list of command line arguments - * for the hooks; must contain an unused initial slot, - * which the function will use to provide the zeroth - * argument - */ -static void -run_hooks(const char *argv[]) -{ - static int looked_up_dir = 0; - static int hook_file_is_regular = 0; - static int hook_file_checked = 0; - - DIR *dir; - struct dirent *f; - size_t required; - const char *dirpath_static; - - if (hook_file_is_regular) { - goto run_hook_file; - - } else if (hook_file) { - if (!hook_file_checked) { - hook_file_checked = 1; - if (!strcmp(hook_file, "/dev/null") || - !strcmp(hook_file, "/var/empty") || - !strcmp(hook_file, "/var/empty/")) - goto no_hooks; - } - - dir = opendir(hook_file); - if (!dir) { - if (errno == ENOTDIR) { - hook_file_is_regular = 1; - run_hook_file: - run_hook(hook_file, argv); - return; - } - weprintf("opendir %s:", hook_file); - no_hooks: - free(hook_file); - hook_file = NULL; - looked_up_dir = 1; - dirpath = NULL; - return; - } - - } else if (!looked_up_dir) { - looked_up_dir = 1; - dir = open_hooks_dir(&dirpath_static, &dirpath); - if (!dir) - return; - if (!dirpath) - dirpath = estrdup(dirpath_static); - dirpathsize = dirpathlen = strlen(dirpath); - atexit(&cleanup); - - } else if (dirpath) { - dir = opendir(dirpath); - if (!dir) { - weprintf("opendir %s:", dirpath); - cleanup(); - return; - } - - } else { - return; - } - - while ((errno = 0, f = readdir(dir))) { - if (f->d_name[0] == '.' || !f->d_name[0] || strchr(f->d_name, '\0')[-1] == '~') - continue; - - required = dirpathlen + sizeof("/") + strlen(f->d_name); - if (required > dirpathsize) - dirpath = erealloc(dirpath, dirpathsize = required); - stpcpy(stpcpy(&dirpath[dirpathlen], "/"), f->d_name); - - run_hook(dirpath, argv); - - dirpath[dirpathlen] = '\0'; - } - - if (errno) - weprintf("readdir %s:", dirpath); - - closedir(dir); -} - - -void -run_period_change_hooks(enum period prev_period, enum period period) -{ - const char *argv[] = {NULL, "period-changed", period_names[prev_period], period_names[period], NULL}; - run_hooks(argv); -} diff --git a/src/location-corelocation.m b/src/location-corelocation.m deleted file mode 100644 index 1b94137..0000000 --- a/src/location-corelocation.m +++ /dev/null @@ -1,311 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - -#import <Foundation/Foundation.h> -#import <CoreLocation/CoreLocation.h> - - -/** - * Location data - */ -struct location_data { - /** - * The user's geographical location - */ - struct location location; - - /** - * Whether the location provider is available - */ - int available; - - /** - * Whether an unrecoverable error has occurred - */ - int error; -}; - - -struct location_state { - /** - * Slave thread, used to receive location updates - */ - NSThread *thread; - - /** - * Read-end of piped used to send location data - * from the slave thread to the master thread - */ - int pipe_fd_read; - - /** - * Write-end of piped used to send location data - * from the slave thread to the master thread - */ - int pipe_fd_write; - - /** - * Location data available from the slave thread - */ - struct location_data data; - - /** - * Location data sent to the master thread - */ - struct location_data saved_data; -}; - - -@interface LocationDelegate : NSObject <CLLocationManagerDelegate> - @property (strong, nonatomic) CLLocationManager *locationManager; - @property (nonatomic) struct location_state *state; -@end - - -static void -send_data(struct location_state *state) -{ - while (write(state->pipe_fd_write, &state->data, sizeof(state->data)) == -1 && errno == EINTR); -} - - -@implementation LocationDelegate; - -- (void)start -{ - CLAuthorizationStatus authStatus; - - self.locationManager = [[CLLocationManager alloc] init]; - self.locationManager.delegate = self; - self.locationManager.distanceFilter = 50000; - self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; - - authStatus = [CLLocationManager authorizationStatus]; - - if (authStatus != kCLAuthorizationStatusNotDetermined && - authStatus != kCLAuthorizationStatusAuthorized) { - weprintf(_("Not authorized to obtain location from CoreLocation.")); - [self markError]; - } else { - [self.locationManager startUpdatingLocation]; - } -} - -- (void)markError -{ - self.state->data.error = 1; - send_data(self.state); -} - -- (void)markUnavailable -{ - self.state->data.available = 0; - send_data(self.state); -} - -- (void)locationManager:(CLLocationManager *)manager - didUpdateLocations:(NSArray *)locations -{ - CLLocation *newLocation = [locations firstObject]; - - self.state->data.location.lat = newLocation.coordinate.latitude; - self.state->data.location.lon = newLocation.coordinate.longitude; - self.state->data.available = 1; - send_data(self.state); -} - -- (void)locationManager:(CLLocationManager *)manager - didFailWithError:(NSError *)error -{ - weprintf(_("Error obtaining location from CoreLocation: %s"), [[error localizedDescription] UTF8String]); - if ([error code] == kCLErrorDenied) - [self markError]; - else - [self markUnavailable]; -} - -- (void)locationManager:(CLLocationManager *)manager - didChangeAuthorizationStatus:(CLAuthorizationStatus)status -{ - if (status == kCLAuthorizationStatusNotDetermined) { - weprintf(_("Waiting for authorization to obtain location...")); - } else if (status != kCLAuthorizationStatusAuthorized) { - weprintf(_("Request for location was not authorized!")); - [self markError]; - } -} - -@end - - -// Callback when the pipe is closed. -// -// Stops the run loop causing the thread to end. -static void -pipe_close_callback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) -{ - CFFileDescriptorInvalidate(fdref); - CFRelease(fdref); - - CFRunLoopStop(CFRunLoopGetCurrent()); -} - - -@interface LocationThread : NSThread - @property (nonatomic) struct location_state *state; -@end - - -@implementation LocationThread; - -// Run loop for location provider thread. -- (void)main -{ - @autoreleasepool { - LocationDelegate *locationDelegate; - CFFileDescriptorRef fdref; - CFRunLoopSourceRef source; - - locationDelegate = [[LocationDelegate alloc] init]; - locationDelegate.state = self.state; - - // Start the location delegate on the run loop in this thread. - [locationDelegate performSelector:@selector(start) withObject:nil afterDelay:0]; - - // Create a callback that is triggered when the pipe is closed. This will - // trigger the main loop to quit and the thread to stop. - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, self.state->pipe_fd_write, - false, pipe_close_callback, NULL); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); - - // Run the loop - CFRunLoopRun(); - - close(self.state->pipe_fd_write); - } -} - -@end - - -static int -corelocation_create(struct location_state **state_out) -{ - *state_out = emalloc(sizeof(**state_out)); - return 0; -} - - -static int -corelocation_start(struct location_state *state) -{ - LocationThread *thread; - int pipefds[2]; - - state->pipe_fd_read = -1; - state->pipe_fd_write = -1; - - state->data.available = 0; - state->data.error = 0; - state->data.location.lat = 0; - state->data.location.lon = 0; - state->saved_data = state->data; - - pipe_rdnonblock(pipefds); - state->pipe_fd_read = pipefds[0]; - state->pipe_fd_write = pipefds[1]; - - send_data(state); /* TODO why? */ - - thread = [[LocationThread alloc] init]; - thread.state = state; - [thread start]; - state->thread = thread; - - return 0; -} - - -static void -corelocation_free(struct location_state *state) -{ - if (state->pipe_fd_read >= 0) - close(state->pipe_fd_read); - free(state); -} - - -static void -corelocation_print_help(void) -{ - printf(_("Use the location as discovered by the Corelocation provider.\n")); - printf("\n"); -} - - -static int -corelocation_set_option(struct location_state *state, const char *key, const char *value) -{ - (void) state; - (void) value; - weprintf(_("Unknown provider parameter: `%s'."), key); - return -1; -} - - -static int -corelocation_get_fd(struct location_state *state) -{ - return state->pipe_fd_read; -} - - -static int -corelocation_fetch(struct location_state *state, struct location *location_out, int *available_out) -{ - struct location_data data; - ssize_t r; - - for (;;) { - r = read(state->pipe_fd_read, &data, sizeof(data)); - if (r == (ssize_t)sizeof(data)) { - state->saved_data = data; - } else if (r > 0) { - /* writes of 512 bytes or less are always atomic on pipes */ - weprintf("read <pipe>: %s", _("Unexpected message size")); - } else if (!r || errno == EAGAIN) { - break; - } else if (errno != EINTR) { - weprintf("read <pipe>:"); - state->saved_data.error = 1; - break; - } - } - - *location_out = state->saved_data.location; - *available_out = state->saved_data.available; - return state->saved_data.error ? -1 : 0; -} - - -const location_provider_t corelocation_location_provider = LOCATION_PROVIDER_INIT("corelocation", corelocation); diff --git a/src/location-geoclue2.c b/src/location-geoclue2.c deleted file mode 100644 index 9eb49fe..0000000 --- a/src/location-geoclue2.c +++ /dev/null @@ -1,451 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wreserved-identifier" -# pragma clang diagnostic ignored "-Wreserved-macro-identifier" -# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -# pragma clang diagnostic ignored "-Wdocumentation" -# pragma clang diagnostic ignored "-Wpadded" -#endif -#include <glib.h> -#include <glib/gprintf.h> -#include <gio/gio.h> -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - - -/** - * D-Bus error indicating denial of access - */ -#define DBUS_ACCESS_ERROR "org.freedesktop.DBus.Error.AccessDenied" - - -/** - * Location data - */ -struct location_data { - /** - * The user's geographical location - */ - struct location location; - - /** - * Whether the location provider is available - */ - int available; - - /** - * Whether an unrecoverable error has occurred - */ - int error; -}; - - -struct location_state { - GMainLoop *loop; - - /** - * Slave thread, used to receive location updates - */ - GThread *thread; - - /** - * Read-end of piped used to send location data - * from the slave thread to the master thread - */ - int pipe_fd_read; - - /** - * Write-end of piped used to send location data - * from the slave thread to the master thread - */ - int pipe_fd_write; - - /** - * Location data available from the slave thread - */ - struct location_data data; - - /** - * Location data sent to the master thread - */ - struct location_data saved_data; -}; - - -/* Print the message explaining denial from GeoClue */ -static void -print_denial_message(void) -{ - g_printerr(_( - "Access to the current location was denied by GeoClue!\n" - "Make sure that location services are enabled and that" - " Redshift is permitted\nto use location services." - " See https://github.com/jonls/redshift#faq for more\n" - "information.\n")); -} - - -static void -send_data(struct location_state *state) -{ - while (write(state->pipe_fd_write, &state->data, sizeof(state->data)) == -1 && errno == EINTR); -} - - -/* Indicate an unrecoverable error during GeoClue2 communication */ -static void -mark_error(struct location_state *state) -{ - state->data.error = 1; - send_data(state); -} - - -/* Handle position change callbacks */ -static void -geoclue_client_signal_cb(GDBusProxy *client, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) -{ - struct location_state *state = user_data; - const gchar *location_path; - GDBusProxy *location; - GError *error; - GVariant *lat_v, *lon_v; - - (void) sender_name; - - /* Only handle LocationUpdated signals */ - if (g_strcmp0(signal_name, "LocationUpdated")) - return; - - /* Obtain location path */ - g_variant_get_child(parameters, 1, "&o", &location_path); - - /* Obtain location */ - error = NULL; - location = g_dbus_proxy_new_sync(g_dbus_proxy_get_connection(client), G_DBUS_PROXY_FLAGS_NONE, - NULL, "org.freedesktop.GeoClue2", location_path, - "org.freedesktop.GeoClue2.Location", NULL, &error); - if (!location) { - weprintf(_("Unable to obtain location: %s."), error->message); - g_error_free(error); - mark_error(state); - return; - } - - /* Read location properties */ - lat_v = g_dbus_proxy_get_cached_property(location, "Latitude"); - state->data.location.latitude = g_variant_get_double(lat_v); - lon_v = g_dbus_proxy_get_cached_property(location, "Longitude"); - state->data.location.longitude = g_variant_get_double(lon_v); - state->data.available = 1; - - send_data(state); -} - - -/* Callback when GeoClue name appears on the bus */ -static void -on_name_appeared(GDBusConnection *conn, const gchar *name, const gchar *name_owner, gpointer user_data) -{ - struct location_state *state = user_data; - const gchar *client_path; - GDBusProxy *geoclue_client; - GVariant *client_path_v; - GDBusProxy *geoclue_manager; - GError *error; - GVariant *ret_v; - gchar *dbus_error; - - (void) name; - (void) name_owner; - - /* Obtain GeoClue Manager */ - error = NULL; - geoclue_manager = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL, - "org.freedesktop.GeoClue2", "/org/freedesktop/GeoClue2/Manager", - "org.freedesktop.GeoClue2.Manager", NULL, &error); - if (!geoclue_manager) { - weprintf(_("Unable to obtain GeoClue Manager: %s."), error->message); - g_error_free(error); - mark_error(state); - return; - } - - /* Obtain GeoClue Client path */ - error = NULL; - client_path_v = g_dbus_proxy_call_sync(geoclue_manager, "GetClient", NULL, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (!client_path_v) { - weprintf(_("Unable to obtain GeoClue client path: %s."), error->message); - g_error_free(error); - g_object_unref(geoclue_manager); - mark_error(state); - return; - } - - g_variant_get(client_path_v, "(&o)", &client_path); - - /* Obtain GeoClue client */ - error = NULL; - geoclue_client = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.GeoClue2", - client_path, "org.freedesktop.GeoClue2.Client", NULL, &error); - if (!geoclue_client) { - weprintf(_("Unable to obtain GeoClue Client: %s."), error->message); - g_error_free(error); - g_variant_unref(client_path_v); - g_object_unref(geoclue_manager); - mark_error(state); - return; - } - - g_variant_unref(client_path_v); - - /* Set desktop id (basename of the .desktop file) */ - error = NULL; - ret_v = g_dbus_proxy_call_sync(geoclue_client, "org.freedesktop.DBus.Properties.Set", - g_variant_new("(ssv)", "org.freedesktop.GeoClue2.Client", - "DesktopId", g_variant_new("s", "redshift")), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (!ret_v) { - /* Ignore this error for now. The property is not available - * in early versions of GeoClue2. */ - } else { - g_variant_unref(ret_v); - } - - /* Set distance threshold */ - error = NULL; - ret_v = g_dbus_proxy_call_sync(geoclue_client, "org.freedesktop.DBus.Properties.Set", - g_variant_new("(ssv)", "org.freedesktop.GeoClue2.Client", - "DistanceThreshold", g_variant_new("u", 50000)), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (!ret_v) { - weprintf(_("Unable to set distance threshold: %s."), error->message); - g_error_free(error); - g_object_unref(geoclue_client); - g_object_unref(geoclue_manager); - mark_error(state); - return; - } - - g_variant_unref(ret_v); - - /* Attach signal callback to client */ - g_signal_connect(geoclue_client, "g-signal", G_CALLBACK(geoclue_client_signal_cb), user_data); - - /* Start GeoClue client */ - error = NULL; - ret_v = g_dbus_proxy_call_sync(geoclue_client, "Start", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (!ret_v) { - weprintf(_("Unable to start GeoClue client: %s."), error->message); - if (g_dbus_error_is_remote_error(error)) { - dbus_error = g_dbus_error_get_remote_error( error); - if (!g_strcmp0(dbus_error, DBUS_ACCESS_ERROR)) - print_denial_message(); - g_free(dbus_error); - } - g_error_free(error); - g_object_unref(geoclue_client); - g_object_unref(geoclue_manager); - mark_error(state); - return; - } - - g_variant_unref(ret_v); -} - - -/* Callback when GeoClue disappears from the bus */ -static void -on_name_vanished(GDBusConnection *connection, const gchar *name, gpointer user_data) -{ - struct location_state *state = user_data; - - (void) connection; - (void) name; - - state->data.available = 0; - send_data(state); -} - - -/* Callback when the pipe to the main thread is closed */ -static gboolean -on_pipe_closed(GIOChannel *channel, GIOCondition condition, gpointer user_data) -{ - struct location_state *state = user_data; - g_main_loop_quit(state->loop); - - (void) channel; - (void) condition; - return FALSE; -} - - -/* Run loop for location provider thread */ -static void * -run_geoclue2_loop(void *state_) -{ - struct location_state *state = state_; - GMainContext *context; - guint watcher_id; - GIOChannel *pipe_channel; - GSource *pipe_source; - - context = g_main_context_new(); - g_main_context_push_thread_default(context); - state->loop = g_main_loop_new(context, FALSE); - - watcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, "org.freedesktop.GeoClue2", - G_BUS_NAME_WATCHER_FLAGS_AUTO_START, - on_name_appeared, on_name_vanished, state, NULL); - - /* Listen for closure of pipe */ - pipe_channel = g_io_channel_unix_new(state->pipe_fd_write); - pipe_source = g_io_create_watch(pipe_channel, G_IO_IN | G_IO_HUP | G_IO_ERR); - g_source_set_callback(pipe_source, (GSourceFunc)on_pipe_closed, state, NULL); - g_source_attach(pipe_source, context); - - g_main_loop_run(state->loop); - - g_source_unref(pipe_source); - g_io_channel_unref(pipe_channel); - close(state->pipe_fd_write); - - g_bus_unwatch_name(watcher_id); - - g_main_loop_unref(state->loop); - g_main_context_unref(context); - - return NULL; -} - - -static int -geoclue2_create(struct location_state **state_out) -{ -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif - *state_out = emalloc(sizeof(**state_out)); - return 0; -} - - -static int -geoclue2_start(struct location_state *state) -{ - int pipefds[2]; - - state->pipe_fd_read = -1; - state->pipe_fd_write = -1; - - state->data.available = 0; - state->data.error = 0; - state->data.location.latitude = 0; - state->data.location.longitude = 0; - state->saved_data = state->data; - - pipe_rdnonblock(pipefds); - state->pipe_fd_read = pipefds[0]; - state->pipe_fd_write = pipefds[1]; - - send_data(state); /* TODO why? */ - - state->thread = g_thread_new("geoclue2", run_geoclue2_loop, state); - - return 0; -} - - -static void -geoclue2_free(struct location_state *state) -{ - if (state->pipe_fd_read >= 0) - close(state->pipe_fd_read); - - /* Closing the pipe should cause the thread to exit, but it may be blocked by I/O */ - install_forceful_exit_signal_handlers(); - g_thread_join(state->thread); - state->thread = NULL; - - free(state); -} - - -static void -geoclue2_print_help(void) -{ - printf(_("Use the location as discovered by a GeoClue2 provider.\n")); - printf("\n"); -} - - -static int -geoclue2_set_option(struct location_state *state, const char *key, const char *value) -{ - (void) state; - (void) value; - weprintf(_("Unknown provider parameter: `%s'."), key); - return -1; -} - - -static int -geoclue2_get_fd(struct location_state *state) -{ - return state->pipe_fd_read; -} - - -static int -geoclue2_fetch(struct location_state *state, struct location *location_out, int *available_out) -{ - struct location_data data; - ssize_t r; - - for (;;) { - r = read(state->pipe_fd_read, &data, sizeof(data)); - if (r == (ssize_t)sizeof(data)) { - state->saved_data = data; - } else if (r > 0) { - /* writes of 512 bytes or less are always atomic on pipes */ - weprintf("read <pipe>: %s", _("Unexpected message size")); - } else if (!r || errno == EAGAIN) { - break; - } else if (errno != EINTR) { - weprintf("read <pipe>:"); - state->saved_data.error = 1; - break; - } - } - - *location_out = state->saved_data.location; - *available_out = state->saved_data.available; - return state->saved_data.error ? -1 : 0; -} - - -const struct location_provider geoclue2_location_provider = LOCATION_PROVIDER_INIT("geoclue2", geoclue2); diff --git a/src/location-geofile.c b/src/location-geofile.c deleted file mode 100644 index 62d6b26..0000000 --- a/src/location-geofile.c +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -struct location_state { - /** - * The loaded location - */ - struct location location; - - /** - * File to read location from, `NULL` for default - */ - char *file; -}; - - -static int -geofile_create(struct location_state **state_out) -{ - *state_out = emalloc(sizeof(**state_out)); - (*state_out)->file = NULL; - return 0; -} - - -GCC_ONLY(__attribute__((__pure__))) -static int -geofile_start(struct location_state *state) -{ - struct libgeome_data data = {.requested_data = LIBGEOME_DATUM_LATITUDE | LIBGEOME_DATUM_LONGITUDE}; - struct libgeome_context ctx; - int r; - libgeome_basic_context(&ctx, argv0); - r = libgeome_get_from_file(&ctx, &data, state->file); - free(state->file); - state->file = NULL; - if (r || data.requested_data != (LIBGEOME_DATUM_LATITUDE | LIBGEOME_DATUM_LONGITUDE)) - return -1; - state->location.latitude = data.latitude; - state->location.longitude = data.longitude; - return 0; -} - - -static void -geofile_free(struct location_state *state) -{ - free(state->file); - free(state); -} - - -static void -geofile_print_help(void) -{ - printf(_("Specify location via file.\n")); - printf("\n"); - - printf(" file=%s %s\n", _("FILE "), _("File to read location from (empty for default)")); - printf("\n"); -} - - -static int -geofile_set_option(struct location_state *state, const char *key, const char *value) -{ - if (!strcasecmp(key, "file")) { - free(state->file); - state->file = *value ? estrdup(value) : NULL; - return 0; - } else { - weprintf(_("Unknown provider parameter: `%s'."), key); - return -1; - } -} - - -static int -geofile_get_fd(struct location_state *state) -{ - (void) state; - return -1; -} - - -static int -geofile_fetch(struct location_state *state, struct location *location_out, int *available_out) -{ - *location_out = state->location; - *available_out = 1; - return 0; -} - - -const struct location_provider geofile_location_provider = LOCATION_PROVIDER_INIT("geofile", geofile); diff --git a/src/location-manual.c b/src/location-manual.c deleted file mode 100644 index 2928f37..0000000 --- a/src/location-manual.c +++ /dev/null @@ -1,118 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -struct location_state { - /** - * The specified location, any unspecified coordinate is set to NAN - */ - struct location location; -}; - - -static int -manual_create(struct location_state **state_out) -{ - *state_out = emalloc(sizeof(**state_out)); - (*state_out)->location.latitude = FNAN; - (*state_out)->location.longitude = FNAN; - return 0; -} - - -GCC_ONLY(__attribute__((__pure__))) -static int -manual_start(struct location_state *state) -{ - if (isnan(state->location.latitude) || isnan(state->location.longitude)) - eprintf(_("Latitude and longitude must be set.")); - return 0; -} - - -static void -manual_free(struct location_state *state) -{ - free(state); -} - - -static void -manual_print_help(void) -{ - printf(_("Specify location manually.\n")); - printf("\n"); - - /* TRANSLATORS: "N" represents "cardinal"; right-pad with spaces to preserve display width */ - printf(" lat=%s %s\n", _("N "), _("Latitude")); - printf(" lon=%s %s\n", _("N "), _("Longitude")); - printf("\n"); - - printf(_("Both values are expected to be floating point numbers,\n" - "negative values representing west / south, respectively.\n")); - printf("\n"); -} - - -static int -manual_set_option(struct location_state *state, const char *key, const char *value) -{ - char *end; - double v; - - errno = 0; - v = strtod(value, &end); - if (errno || *end) { - weprintf(_("Malformed argument.")); - return -1; - } - - if (!strcasecmp(key, "lat")) { - state->location.latitude = v; - } else if (!strcasecmp(key, "lon")) { - state->location.longitude = v; - } else { - weprintf(_("Unknown provider parameter: `%s'."), key); - return -1; - } - - return 0; -} - - -static int -manual_get_fd(struct location_state *state) -{ - (void) state; - return -1; -} - - -static int -manual_fetch(struct location_state *state, struct location *location_out, int *available_out) -{ - *location_out = state->location; - *available_out = 1; - return 0; -} - - -const struct location_provider manual_location_provider = LOCATION_PROVIDER_INIT("manual", manual); diff --git a/src/location-timezone.c b/src/location-timezone.c deleted file mode 100644 index 58bf0cf..0000000 --- a/src/location-timezone.c +++ /dev/null @@ -1,108 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -struct location_state { - /** - * The loaded location - */ - struct location location; -}; - - -static int -timezone_create(struct location_state **state_out) -{ - *state_out = emalloc(sizeof(**state_out)); - return 0; -} - - -GCC_ONLY(__attribute__((__pure__))) -static int -timezone_start(struct location_state *state) -{ - struct libgeome_data data; - struct libgeome_context ctx; - int r; - libgeome_basic_context(&ctx, argv0); - - data.requested_data = LIBGEOME_DATUM_LATITUDE | LIBGEOME_DATUM_LONGITUDE; - r = libgeome_get_from_timezone(&ctx, &data); - if (r) { - data.requested_data = LIBGEOME_DATUM_LATITUDE | LIBGEOME_DATUM_LONGITUDE; - r = libgeome_get_from_time(&ctx, &data); - } - - if (r || !(data.requested_data & LIBGEOME_DATUM_LONGITUDE)) - return -1; - if (data.requested_data & LIBGEOME_DATUM_LATITUDE) - state->location.latitude = data.latitude; - else - state->location.latitude = 0; - state->location.longitude = data.longitude; - return 0; -} - - -static void -timezone_free(struct location_state *state) -{ - free(state); -} - - -static void -timezone_print_help(void) -{ - printf(_("Get rough location from timezone.\n")); - printf("\n"); -} - - -static int -timezone_set_option(struct location_state *state, const char *key, const char *value) -{ - (void) state; - (void) value; - weprintf(_("Unknown provider parameter: `%s'."), key); - return -1; -} - - -static int -timezone_get_fd(struct location_state *state) -{ - (void) state; - return -1; -} - - -static int -timezone_fetch(struct location_state *state, struct location *location_out, int *available_out) -{ - *location_out = state->location; - *available_out = 1; - return 0; -} - - -const struct location_provider timezone_location_provider = LOCATION_PROVIDER_INIT("timezone", timezone); diff --git a/src/location.c b/src/location.c deleted file mode 100644 index 5979a2d..0000000 --- a/src/location.c +++ /dev/null @@ -1,249 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -const struct location_provider *location_providers[] = { -#ifdef ENABLE_GEOCLUE2 - &geoclue2_location_provider, -#endif -#ifdef ENABLE_CORELOCATION - &corelocation_location_provider, -#endif - &manual_location_provider, -#ifndef WINDOWS - &geofile_location_provider, - &timezone_location_provider, -#endif - NULL -}; - - -/** - * Get the current monotonic time in milliseconds - * - * @return The number of milliseconds elapsed since some arbitrary fixed time - */ -static long long int -get_monotonic_millis(void) -{ -#if defined(WINDOWS) - return (long long int)GetTickCount64(); -#else - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now)) - eprintf("clock_gettime CLOCK_MONOTONIC:"); - return (long long int)now.tv_sec * 1000LL + (long long int)now.tv_nsec / 1000000LL; -#endif -} - - -/** - * Attempt to start a specific location provider - * - * @param provider The location provider - * @param state_out Output parameter for the location provider state - * @param config Loaded information file - * @param args `NULL` or option part of the command line argument for the location provider - * @return 0 on success, -1 on failure - */ -static int -try_start(const struct location_provider *provider, LOCATION_STATE **state_out, struct config_ini_state *config, char *args) -{ - const char *manual_keys[] = {"lat", "lon"}; - struct config_ini_section *section; - struct config_ini_setting *setting; - char *next_arg, *value; - const char *key; - int i; - - if (provider->create(state_out) < 0) { - weprintf(_("Initialization of %s failed."), provider->name); - goto fail; - } - - /* Set provider options from config file */ - if ((section = config_ini_get_section(config, provider->name))) - for (setting = section->settings; setting; setting = setting->next) - if (provider->set_option(*state_out, setting->name, setting->value) < 0) - goto set_option_fail; - - /* Set provider options from command line */ - for (i = 0; args && *args; i++, args = next_arg) { - next_arg = &args[strcspn(args, ";:")]; - if (*next_arg) - *next_arg++ = '\0'; - - key = args; - value = strchr(args, '='); - if (!value) { - /* The options for the "manual" method can be set - * without keys on the command line for convencience - * and for backwards compatability. We add the proper - * keys here before calling set_option(). */ - if (!strcmp(provider->name, "manual") && i < (int)ELEMSOF(manual_keys)) { - key = manual_keys[i]; - value = args; - } else { - weprintf(_("Failed to parse option `%s'."), args); - goto fail; - } - } else { - *value++ = '\0'; - } - - if (provider->set_option(*state_out, key, value) < 0) - goto set_option_fail; - } - - /* Start provider */ - if (provider->start(*state_out) < 0) { - weprintf(_("Failed to start provider %s."), provider->name); - goto fail; - } - - return 0; - -set_option_fail: - weprintf(_("Failed to set %s option."), provider->name); - /* TRANSLATORS: `help' must not be translated. */ - weprintf(_("Try `-l %s:help' for more information."), provider->name); -fail: - if (*state_out) { - provider->free(*state_out); - *state_out = NULL; - } - return -1; -} - - -int -get_location(const struct location_provider *provider, LOCATION_STATE *state, int timeout, struct location *location_out) -{ -#ifdef WINDOWS /* we don't have poll on Windows, but neither do with have any dynamic location providers */ - int available; - return provider->fetch(state, location_out, &available) < 0 ? -1 : available; - -#else - int r, available = 0; - struct pollfd pollfds[1]; - long long int now = get_monotonic_millis(); - long long int end = now + (long long int)timeout; - - do { - pollfds[0].fd = provider->get_fd(state); - if (pollfds[0].fd >= 0) { - /* Poll on file descriptor until ready */ - pollfds[0].events = POLLIN; - timeout = (int)MAX(end - now, 0); - r = poll(pollfds, 1, timeout); - if (r > 0) { - now = get_monotonic_millis(); - } else if (r < 0) { -#ifndef WINDOWS - if (errno == EINTR) - continue; -#endif - weprintf("poll {{.fd=<location provider>, .events=EPOLLIN}} 1 %i:", timeout); - return -1; - } else { - return 0; - } - } - - if (provider->fetch(state, location_out, &available) < 0) - return -1; - } while (!available && !exiting); - - if (exiting) - eprintf(_("Terminated by user.")); - - return 1; -#endif -} - - -void -acquire_location_provider(struct settings *settings, LOCATION_STATE **location_state_out) -{ - size_t i; - - if (settings->provider) { - /* Use provider specified on command line */ - if (try_start(settings->provider, location_state_out, &settings->config, settings->provider_args) < 0) - exit(1); - } else { - /* Try all providers, use the first that works */ - for (i = 0; location_providers[i]; i++) { - weprintf(_("Trying location provider `%s'..."), location_providers[i]->name); - if (try_start(location_providers[i], location_state_out, &settings->config, NULL) < 0) { - weprintf(_("Trying next provider...")); - continue; - } - - /* Found provider that works */ - printf(_("Using provider `%s'.\n"), location_providers[i]->name); - settings->provider = location_providers[i]; - break; - } - - /* Failure if no providers were successful at this point */ - if (!settings->provider) - eprintf(_("No more location providers to try.")); - } -} - - -int -location_is_valid(const struct location *location) -{ - if (!WITHIN(MIN_LATITUDE, location->latitude, MAX_LATITUDE)) { - /* TRANSLATORS: Append degree symbols if possible. */ - weprintf(_("Latitude must be between %.1f and %.1f."), MIN_LATITUDE, MAX_LATITUDE); - return 0; - } - if (!WITHIN(MIN_LONGITUDE, location->longitude, MAX_LONGITUDE)) { - /* TRANSLATORS: Append degree symbols if possible. */ - weprintf(_("Longitude must be between %.1f and %.1f."), MIN_LONGITUDE, MAX_LONGITUDE); - return 0; - } - return 1; -} - - -void -print_location(const struct location *location) -{ - /* TRANSLATORS: Abbreviation for `north' */ - const char *north = _("N"); - /* TRANSLATORS: Abbreviation for `south' */ - const char *south = _("S"); - /* TRANSLATORS: Abbreviation for `east' */ - const char *east = _("E"); - /* TRANSLATORS: Abbreviation for `west' */ - const char *west = _("W"); - - /* TRANSLATORS: Append degree symbols after %f if possible. - * The string following each number is an abreviation for - * north, source, east or west (N, S, E, W). */ - printf(_("Location: %.2f %s, %.2f %s\n"), - fabs(location->latitude), signbit(location->latitude) ? south : north, - fabs(location->longitude), signbit(location->longitude) ? west : east); -} diff --git a/src/redshift.c b/src/redshift.c deleted file mode 100644 index 5bc172e..0000000 --- a/src/redshift.c +++ /dev/null @@ -1,543 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -/** - * The number of milliseconds to sleep normally between colour updates - */ -#define SLEEP_DURATION 5000U - -/** - * The number of milliseconds to sleep between each step during - * fade between large colour settings - */ -#define SLEEP_DURATION_SHORT 25U - -/** - * The fade time, for when making large changes in colour - * settings, divided by `SLEEP_DURATION_SHORT` - */ -#define FADE_LENGTH 160U - - -char *argv0; - - -/** - * The user's current geographical location - */ -static struct location location; - -/** - * Whether the location provider is available - */ -static int location_available; - -/** - * State of location provider, `NULL` if none - */ -static LOCATION_STATE *provider_state; - -/** - * Locaiton provider functions - */ -static const struct location_provider *provider; - -/** - * State of the gamma ramp adjustment method, `NULL` if none (print mode) - */ -static GAMMA_STATE *method_state; - -/** - * Gamma ramp adjustment functions - */ -static const struct gamma_method *method; - - -/** - * Suspend the process for a short time - * - * The process may be resumed earily, specifically - * if it receives a signal - * - * @param msecs The number of milliseconds to sleep - */ -static void -millisleep(unsigned int msecs) -{ -#ifdef WINDOWS - Sleep(msecs); /* TODO [Windows] not interruptible */ -#else - struct timespec ts; - ts.tv_sec = (time_t)(msecs / 1000U); - ts.tv_nsec = (long)(msecs % 1000U) * 1000000L; - nanosleep(&ts, NULL); -#endif -} - - -/** - * Get the number of seconds since midnight - * - * @return The number of seconds since midnight - */ -static time_t -get_time_since_midnight(void) -{ - time_t t = time(NULL); - struct tm tm; - localtime_r(&t, &tm); - t = (time_t)tm.tm_sec; - t += (time_t)tm.tm_min * 60; - t += (time_t)tm.tm_hour * 3600; - return t; -} - - -/** - * Print the current period of the day - * - * @param period The current period of the day - * @param day_level The current dayness level - */ -static void -print_period(enum period period, double day_level) -{ - static const char *period_names[] = { - /* TRANSLATORS: Name printed when period of day is unknown */ - [PERIOD_NONE] = N_("None"), - [PERIOD_DAYTIME] = N_("Daytime"), - [PERIOD_NIGHT] = N_("Night"), - [PERIOD_TRANSITION] = N_("Transition") - }; - - if (period == PERIOD_TRANSITION) - printf(_("Period: %s (%.2f%% day)\n"), gettext(period_names[period]), day_level * 100); - else - printf(_("Period: %s\n"), gettext(period_names[period])); -} - - -/** - * Get the current period of day and the colour settings - * applicable to the current time of the day - * - * @param colour_out Output parameter for the colour settings - * @param period_out Output parameter for the period of the day - * @param day_level_out Output parameter for the dayness level - */ -static void -get_colour_settings(struct colour_setting *colour_out, enum period *period_out, double *day_level_out) -{ - time_t time_offset; - double t, elevation; - - /* Get dayness level */ - if (scheme.type == CLOCK_SCHEME) { - time_offset = get_time_since_midnight(); - while (time_offset >= scheme.time.periods->next->start) - scheme.time.periods = scheme.time.periods->next; - time_offset -= scheme.time.periods->start; - if (time_offset < 0) - time_offset += ONE_DAY; - t = (double)time_offset; - *day_level_out = fma(t, scheme.time.periods->diff_over_duration, scheme.time.periods->day_level); - - } else if (scheme.type == SOLAR_SCHEME) { - if (libred_solar_elevation(location.latitude, location.longitude, &elevation)) - eprintf("libred_solar_elevation:"); - if (verbose) { - /* TRANSLATORS: Append degree symbol if possible. */ - printf(_("Solar elevation: %f\n"), elevation); - } - *day_level_out = (elevation - scheme.elevation.low) / scheme.elevation.range; - /* TODO ensure scheme.elevation.range==0 is supported */ - - } else { - /* Static scheme, no dayness-level or peroid; day_settings == nigh_settings, use either */ - *day_level_out = FNAN; - *period_out = PERIOD_NONE; - *colour_out = day_settings; - return; - } - - /* Clamp dayness level and get colour */ - if (*day_level_out <= 0.0) { - *day_level_out = 0.0; - *period_out = PERIOD_NIGHT; - *colour_out = night_settings; - - } else if (*day_level_out >= 1.0) { - *day_level_out = 1.0; - *period_out = PERIOD_DAYTIME; - *colour_out = day_settings; - - } else { - *period_out = PERIOD_TRANSITION; - interpolate_colour_settings(&night_settings, &day_settings, *day_level_out, colour_out); - } -} - - -/** - * Easing function used for fade effect - * - * See https://github.com/mietek/ease-tween - * - * @param t Raw fade progress - * @return Fade progress to apply - */ -GCC_ONLY(__attribute__((__const__))) -static double -ease_fade(double t) -{ - if (t <= 0) return 0; - if (t >= 1) return 1; - return 1.0042954579734844 * exp(-6.4041738958415664 * exp(-7.2908241330981340 * t)); -} - - -#ifndef WINDOWS /* we don't have poll on Windows, but neither do with have any dynamic location providers */ -/** - * Get the current location - * - * The function will return once any of the following has occured: - * - the specified timeout duration has elapsed, - * - a location message has been received (could be location or error), or - * - a signal(7) was received - * - * @param timeout The number of milliseconds to wait before - * returning without updating the location - * @param location_fd File descriptor to wait on to receive input event - */ -static void -pull_location(unsigned int timeout, int location_fd) -{ - struct pollfd pollfds[1]; - struct location new_location; - int r, new_available; - - /* Await new location information */ - pollfds[0].fd = location_fd; - pollfds[0].events = POLLIN; - r = poll(pollfds, 1, (int)timeout); - if (r < 0) { -#ifndef WINDOWS - if (errno == EINTR) - return; -#endif - weprintf("poll:"); - eprintf(_("Unable to get location from provider.")); - } else if (!r) { - return; - } - - /* Get new location and availability information */ - if (provider->fetch(provider_state, &new_location, &new_available) < 0) - eprintf(_("Unable to get location from provider.")); - if (new_available < location_available) { - weprintf(_("Location is temporarily unavailable; using previous" - " location until it becomes available...")); - location_available = 0; - return; - } - - /* Store and announce new location */ - if (new_available > location_available || - !exact_eq(new_location.latitude, location.latitude) || - !exact_eq(new_location.longitude, location.longitude)) { - location_available = 1; - location = new_location; - print_location(&location); - if (!location_is_valid(&location)) - eprintf(_("Invalid location returned from provider.")); - } -} -#endif - - -/** - * Loop for `PROGRAM_MODE_CONTINUAL` - */ -static void -run_continual_mode(void) -{ - enum period period, prev_period = PERIOD_NONE; - double day_level = FNAN, prev_day_level = FNAN; - int disabled = disable, prev_disabled = !disable; - int prev_use_fade = !use_fade; - int prev_preserve_gamma = !preserve_gamma; - int done = 0; - struct colour_setting colour; - struct colour_setting target_colour, prev_target_colour; - struct colour_setting fade_start_colour; - unsigned int fade_length = 0; - unsigned int fade_time = 0; - unsigned int delay; - double fade_progress, eased_fade_progress; -#ifndef WINDOWS - int location_fd; - sigset_t sigusr2_mask, old_mask; - enum signals commands; - - sigemptyset(&sigusr2_mask); - sigaddset(&sigusr2_mask, SIGUSR2); -#endif - - disable = 0; - - prev_target_colour = COLOUR_SETTING_NEUTRAL; - colour = COLOUR_SETTING_NEUTRAL; - - for (;;) { - /* Act on signals */ - if (disable && !done) { - disabled ^= 1; - disable = 0; - } - if (exiting) { - disabled = 1; - exiting = 0; - if (done || (disabled && !fade_length)) - break; /* On second signal stop the ongoing fade */ - done = 1; - } -#ifndef WINDOWS - while (signals) { - if (sigprocmask(SIG_BLOCK, &sigusr2_mask, &old_mask)) - eprintf("sigprocmask:"); - commands = signals; - signals = 0; - - if (commands & SIGNAL_ORDER_BARRIER) sigdelset(&old_mask, SIGUSR2); - if (commands & SIGNAL_DISABLE) disabled = 1; - if (commands & SIGNAL_ENABLE) disabled = 0; - if (commands & SIGNAL_RELOAD) {} /* TODO */ - if (commands & SIGNAL_USE_FADE_OFF) use_fade = 0; - if (commands & SIGNAL_USE_FADE_ON) use_fade = 1; - if (commands & SIGNAL_PRESERVE_GAMMA_OFF) preserve_gamma = 0; - if (commands & SIGNAL_PRESERVE_GAMMA_ON) preserve_gamma = 1; - if (commands & SIGNAL_EXIT_WITHOUT_RESET) {} /* TODO */ - if (commands & SIGNAL_VERBOSE_ON) verbose |= 2; - if (commands & SIGNAL_VERBOSE_OFF) verbose &= ~2; - - if (commands & SIGNAL_IGNORE_SIGPIPE) - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - weprintf("signal SIGPIPE SIG_IGN:"); - - if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) - eprintf("sigprocmask:"); - -# if defined(__linux__) - if (commands & SIGNAL_REEXEC) { /* TODO */ - } -# endif - } -#endif - if (verbose) { - if (disabled != prev_disabled) - printf(_("Status: %s\n"), disabled ? _("Disabled") : _("Enabled")); - if (use_fade != prev_use_fade) - printf(_("Fade: %s\n"), use_fade ? _("Disabled") : _("Enabled")); - if (preserve_gamma != prev_preserve_gamma) - printf(_("Preserve gamma: %s\n"), use_fade ? _("Disabled") : _("Enabled")); - } - prev_disabled = disabled; - prev_use_fade = use_fade; - prev_preserve_gamma = preserve_gamma; - - /* Get dayness level and corresponding colour settings */ - if (disabled) { - period = PERIOD_NONE; - target_colour = COLOUR_SETTING_NEUTRAL; - } else { - get_colour_settings(&target_colour, &period, &day_level); - } - if (verbose && (period != prev_period || !exact_eq(day_level, prev_day_level))) - print_period(period, day_level); - if (period != prev_period) - run_period_change_hooks(prev_period, period); - prev_period = period; - prev_day_level = day_level; - if (verbose) { - if (prev_target_colour.temperature != target_colour.temperature) - printf(_("Color temperature: %luK\n"), target_colour.temperature); - if (!exact_eq(prev_target_colour.brightness, target_colour.brightness)) - printf(_("Brightness: %.2f\n"), target_colour.brightness); - if (memcmp(prev_target_colour.gamma, target_colour.gamma, sizeof(target_colour.gamma))) { - printf(_("Gamma: %.3f, %.3f, %.3f\n"), - target_colour.gamma[0], target_colour.gamma[1], target_colour.gamma[2]); - } - } - - /* Fade if the parameter differences are too big to apply instantly */ - if (use_fade && colour_setting_diff_is_major(&target_colour, fade_length ? &prev_target_colour : &colour)) { - fade_length = FADE_LENGTH; - fade_time = 0; - fade_start_colour = colour; - } - if (fade_length) { - fade_progress = ++fade_time / (double)fade_length; - eased_fade_progress = ease_fade(fade_progress); - interpolate_colour_settings(&fade_start_colour, &target_colour, eased_fade_progress, &colour); - if (fade_time == fade_length) { - fade_time = 0; - fade_length = 0; - } - } else { - colour = target_colour; - } - prev_target_colour = target_colour; - - /* Break loop when done and final fade is over */ - if (done && !fade_length) - break; - - /* Adjust temperature and sleep */ - if (method->apply(method_state, &colour, preserve_gamma) < 0) - eprintf(_("Temperature adjustment failed.")); - delay = fade_length ? SLEEP_DURATION_SHORT : SLEEP_DURATION; -#ifndef WINDOWS - location_fd = scheme.type == SOLAR_SCHEME ? provider->get_fd(provider_state) : -1; - if (location_fd >= 0) - pull_location(delay, location_fd); - else -#endif - millisleep(delay); - /* SLEEP_DURATION_SHORT is short enough for remaining time after interruption to be ignored */ - } - - method->restore(method_state); -} - - -int -main(int argc, char *argv[]) -{ - struct settings settings; - double day_level; - enum period period; - struct colour_setting colour; -#ifndef WINDOWS - int fd; -#endif - - argv0 = argv[0]; - - /* Set up localisation */ -#ifdef ENABLE_NLS - setlocale(LC_CTYPE, ""); - setlocale(LC_MESSAGES, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); -#endif - - /* Ensure standard file descriptors exist */ -#ifndef WINDOWS - fd = open("/dev/null", O_RDWR); - while (fd < 2) { - if (fd < 0) - eprintf("open /dev/null O_RDWR:"); - fd = dup(fd); - } - if (fd > 2) - close(fd); -#endif - - /* Set up interprocess communication */ - install_signal_handlers(); - - /* Get configurations and configure */ - load_settings(&settings, argc, argv); - if (scheme.type == SOLAR_SCHEME) { - acquire_location_provider(&settings, &provider_state); - provider = settings.provider; - } - if (mode != PROGRAM_MODE_PRINT) { - acquire_adjustment_method(&settings, &method_state); - method = settings.method; - } - config_ini_free(&settings.config); - - /* Get location if required */ - if (scheme.type == SOLAR_SCHEME) { - if (provider->get_fd(provider_state) >= 0) - weprintf(_("Waiting for current location to become available...")); - if (get_location(provider, provider_state, -1, &location) < 0) - eprintf(_("Unable to get location from provider.")); - if (!location_is_valid(&location)) - eprintf(_("Invalid location returned from provider.")); - print_location(&location); - location_available = 1; - } - - /* Get and print colour to set or if continual mode the initial colour */ - get_colour_settings(&colour, &period, &day_level); /* needed in contiual mode for `period` and `day_level` */ - if (mode == PROGRAM_MODE_CONTINUAL) - colour = COLOUR_SETTING_NEUTRAL; - if (verbose || mode == PROGRAM_MODE_PRINT) { - if (scheme.type != STATIC_SCHEME) - print_period(period, day_level); - printf(_("Color temperature: %luK\n"), colour.temperature); - printf(_("Brightness: %.2f\n"), colour.brightness); - printf(_("Gamma: %.3f, %.3f, %.3f\n"), colour.gamma[0], colour.gamma[1], colour.gamma[2]); - } - - switch (mode) { - case PROGRAM_MODE_PRINT: - break; - - case PROGRAM_MODE_ONE_SHOT: - case PROGRAM_MODE_UNTIL_DEATH: - case PROGRAM_MODE_RESET: - if (method->apply(method_state, &colour, preserve_gamma) < 0) - eprintf(_("Temperature adjustment failed.")); - if (mode == PROGRAM_MODE_UNTIL_DEATH || method->autoreset) { - weprintf(_("Press ctrl-c to stop...")); - while (!exiting) { - pause(); - if (signals & SIGNAL_EXIT_WITHOUT_RESET) { - /* TODO disable reset if if using coopgamma */ - goto out; - } - } - /* TODO reset if not using coopgamma */ - } - break; - - case PROGRAM_MODE_CONTINUAL: - run_continual_mode(); - break; - -#if defined(__GNUC__) - default: - __builtin_unreachable(); -#endif - } - -out: - if (provider_state) - provider->free(provider_state); - if (method_state) - method->free(method_state); - free(hook_file); - return 0; -} diff --git a/src/signals.c b/src/signals.c deleted file mode 100644 index cd23773..0000000 --- a/src/signals.c +++ /dev/null @@ -1,209 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -volatile sig_atomic_t exiting = 0; -volatile sig_atomic_t disable = 0; -volatile enum signals signals = 0; - - -/** - * Signal handler for exit signals (SIGINT, SIGTERM, SIGQUIT) - * - * @param signo The received signal - */ -static void -sigexit(int signo) -{ - exiting = 1; -#ifdef WINDOWS - signal(signo, &sigexit); -#endif - (void) signo; -} - - -#ifndef WINDOWS - -/** - * Signal handler for disable signal (SIGUSR1) - * - * @param signo The received signal - */ -static void -sigdisable(int signo) -{ - disable = 1; - (void) signo; -} - - -/** - * Signal handler for forceful exiting; installed by - * `install_forceful_exit_signal_handlers` - * - * @param signo The received signal - */ -static void -sigalrm(int signo) -{ - if (exiting || signo == SIGALRM) - exit(0); - exiting = 1; - alarm(1U); -} - - -/** - * Signal handler for SIGUSR2 - * - * @param signo The received signal - * @param info The received signal data - * @param uctx Interrupted stack context - */ -static void -sigipc(int signo, siginfo_t *info, void *uctx) -{ - int set, mask; - sigset_t sigusr2_mask; - - (void) signo; - (void) uctx; - - if (info->si_code != SI_QUEUE) - return; - - switch (info->si_value.sival_int) { - case 1: - case 2: - mask = 3 << 1; - break; - - case 5: - case 6: - mask = 3 << 5; - break; - - case 7: - case 8: - mask = 3 << 7; - break; - - case 11: - case 12: - mask = 3 << 11; - break; - - case 0: - case 3: - case 4: - case 9: - case 10: - mask = 0; - break; - - default: - return; - } - - signals |= set = 1 << info->si_value.sival_int; - signals &= ~mask | set; - - if (set == SIGNAL_ORDER_BARRIER) { - sigemptyset(&sigusr2_mask); - sigaddset(&sigusr2_mask, SIGUSR2); - if (sigprocmask(SIG_BLOCK, &sigusr2_mask, NULL)) - eprintf("sigprocmask:"); - } -} - -#endif - - -void -install_signal_handlers(void) -{ -#ifdef WINDOWS - if (signal(SIGINT, &sigexit) == SIG_ERR) - eprintf("signal SIGINT <function pointer>:"); - if (signal(SIGTERM, &sigexit) == SIG_ERR) - eprintf("signal SIGTERM <function pointer>:"); - -#else - struct sigaction sigact; - sigset_t sigset; - - memset(&sigact, 0, sizeof(sigact)); - sigemptyset(&sigset); - sigact.sa_mask = sigset; - - sigact.sa_flags = SA_NODEFER; - - sigact.sa_handler = &sigexit; - if (sigaction(SIGINT, &sigact, NULL)) - eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); - if (sigaction(SIGTERM, &sigact, NULL)) - eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); - if (sigaction(SIGQUIT, &sigact, NULL)) - eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); - - sigact.sa_handler = &sigdisable; - if (sigaction(SIGUSR1, &sigact, NULL)) - eprintf("sigaction SIGUSR1 &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); - - sigact.sa_flags = 0; - - sigact.sa_handler = SIG_IGN; /* cause child processes (hooks) to be reaped automatically */ - if (sigaction(SIGCHLD, &sigact, NULL)) - eprintf("sigaction SIGCHLD &{.sa_handler=SIG_IGN, .sa_mask={}, .sa_flags=0} NULL:"); - - sigact.sa_flags = SA_SIGINFO; - - sigact.sa_sigaction = &sigipc; - if (sigaction(SIGUSR2, &sigact, NULL)) - eprintf("sigaction SIGUSR2 &{.sa_sigaction=<function pointer>, .sa_mask={}, .sa_flags=SA_SIGINFO} NULL:"); -#endif -} - - -#ifndef WINDOWS -void -install_forceful_exit_signal_handlers(void) -{ - struct sigaction sigact; - sigset_t sigset; - - exiting = 0; - memset(&sigact, 0, sizeof(sigact)); - sigemptyset(&sigset); - sigact.sa_mask = sigset; - sigact.sa_flags = 0; - sigact.sa_handler = &sigalrm; - if (sigaction(SIGINT, &sigact, NULL)) - eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); - if (sigaction(SIGTERM, &sigact, NULL)) - eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); - if (sigaction(SIGQUIT, &sigact, NULL)) - eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); - if (sigaction(SIGALRM, &sigact, NULL)) - eprintf("sigaction SIGALRM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); -} -#endif diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 26e09a7..0000000 --- a/src/util.c +++ /dev/null @@ -1,317 +0,0 @@ -/*- - * redshift-ng - Automatically adjust display colour temperature according the Sun - * - * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> - * - * redshift-ng 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-ng 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-ng. If not, see <http://www.gnu.org/licenses/>. - */ -#include "common.h" - - -char * -rtrim(char *s, char *end) -{ - end = end ? end : strchr(s, '\0'); - while (end != s && (end[-1] == ' ' || end[-1] == '\t')) - end--; - *end = '\0'; - return s; -} - - -char * -ltrim(char *s) -{ - while (*s == ' ' || *s == '\t') - s++; - return s; -} - - -const char * -get_home(void) -{ -#ifdef WINDOWS - return NULL; -#else - static const char *home = NULL; - struct passwd *pw; - if (!home) { - pw = getpwuid(getuid()); - if (pw) { - home = pw->pw_dir; - if (home && *home) - return home; - weprintf(_("Cannot determine your home directory, " - "it is from the system's user table.")); - } else if (errno) { - weprintf("getpwuid:"); - } else { - weprintf(_("Cannot determine your home directory, your" - " user ID is missing from the system's user table.")); - /* `errno` can either be set to any number of error codes, - * or be zero if the user does not have a passwd entry */ - } - home = ""; - } - return home; -#endif -} - - -/** - * Search for a file and open it in some manner - * - * @param path_spec Specification for the path to try - * @param path_out Output parameter for the found file - * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * shall be free(3)d by the caller - * @param open_cb Pointer to function used to open the file, unless it - * returns `NULL` it's return value is returned by the - * function (`try_path`); `NULL` shall be returned if the - * file `path` does not exist - * @return File access object to the found file; `NULL` if not found - */ -static void * -try_path(const struct env_path *path_spec, const char **path_out, char **pathbuf_out, void *(*open_cb)(const char *path)) -{ - const char *prefix, *p, *q; - char *path; - size_t len; - void *f = NULL; - - *path_out = NULL; - *pathbuf_out = NULL; - - if (!path_spec->prefix_env) { - prefix = get_home(); - } else if (*path_spec->prefix_env) { - prefix = getenv(path_spec->prefix_env); - } else { - f = (*open_cb)(path_spec->suffix); - if (f) - *path_out = path_spec->suffix; - return f; - } - if (!prefix || !*prefix) - return NULL; - - path = emalloc(strlen(prefix) + strlen(path_spec->suffix) + 1U); - - if (path_spec->multidir_env) { - for (p = prefix; !f && *p; p = &q[!!*q]) { -#ifdef strchrnul - q = strchrnul(p, PATH_DELIMITER); -#else - q = strchr(p, PATH_DELIMITER); - q = q ? q : strchr(p, '\0'); -#endif - len = (size_t)(q - p); - if (!len) - continue; - - memcpy(path, p, len); - stpcpy(&path[len], path_spec->suffix); - f = (*open_cb)(path); - } - } else { - stpcpy(stpcpy(path, prefix), path_spec->suffix); - f = (*open_cb)(path); - } - - if (f) - *path_out = *pathbuf_out = path; - else - free(path); - return f; -} - - -/** - * Open a file for reading, if it exists - * - * @param path The path to the file - * @return `FILE` object for reading the file, - * `NULL` if it doesn't exist - */ -static void * -open_file(const char *path) -{ - FILE *f = fopen(path, "r"); - if (!f && errno != ENOENT) - eprintf("fopen %s \"r\":", path); - return f; -} - - -FILE * -try_path_fopen(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) -{ - return try_path(path_spec, path_out, pathbuf_out, &open_file); -} - - -/** - * Open a directory for reading, if it exists - * - * @param path The path to the directory - * @return `DIR` object for reading the directory, - * `NULL` if it doesn't exist - */ -static void * -open_dir(const char *path) -{ - DIR *f = opendir(path); - if (!f && errno != ENOENT) - eprintf("opendir %s:", path); - return f; -} - - -DIR * -try_path_opendir(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) -{ - return try_path(path_spec, path_out, pathbuf_out, &open_dir); -} - - - -#ifndef WINDOWS -void -pipe_rdnonblock(int pipefds[2]) -{ - int i, flags; - - /* Try to use pipe2(2) create O_CLOEXEC pipe */ -# if defined(__linux__) && !defined(MISSING_PIPE2) - if (!pipe2(pipefds, O_CLOEXEC)) - goto apply_nonblock; - else if (errno != ENOSYS) - eprintf("pipe2 <buffer> O_CLOEXEC:"); -# endif - - /* Fallback for when pipe2(2) is not available */ - if (pipe(pipefds)) - eprintf("pipe:"); - for (i = 0; i < 2; i++) { - flags = fcntl(pipefds[i], F_GETFD); - if (flags == -1) - eprintf("fcntl <pipe> F_GETFD:"); - if (fcntl(pipefds[i], F_SETFD, flags | O_CLOEXEC)) - eprintf("fcntl <pipe> F_SETFD +O_CLOEXEC:"); - } - - /* Make the read-end non-blocking */ -# if defined(__linux__) && !defined(MISSING_PIPE2) -apply_nonblock: -# endif - flags = fcntl(pipefds[0], F_GETFL); - if (flags == -1) - eprintf("fcntl <pipe> F_GETFL:"); - if (fcntl(pipefds[0], F_SETFL, flags | O_NONBLOCK)) - eprintf("fcntl <pipe> F_SETFL +O_NONBLOCK:"); -} -#endif - - -void * -ecalloc(size_t n, size_t m) -{ - char *ret = calloc(n, m); - if (!ret) - eprintf("calloc:"); - return ret; -} - - -void * -emalloc(size_t n) -{ - char *ret = malloc(n); - if (!ret) - eprintf("malloc:"); - return ret; -} - - -void * -erealloc(void *ptr, size_t n) -{ - char *ret = realloc(ptr, n); - if (!ret) - eprintf("realloc:"); - return ret; -} - - -char * -estrdup(const char *s) -{ - char *ret = strdup(s); - if (!ret) - eprintf("strdup:"); - return ret; -} - - -void -vweprintf(const char *fmt, va_list args) -{ - int saved_errno; - const char *errstrprefix, *errstr; - - saved_errno = errno; - if (!*fmt) { - errstrprefix = ""; - errstr = strerror(saved_errno); - } else if (strchr(fmt, '\0')[-1] == '\n') { - errstrprefix = ""; - errstr = NULL; - } else if (strchr(fmt, '\0')[-1] == ':') { - errstrprefix = " "; - errstr = strerror(saved_errno); - } else { - errstrprefix = ""; - errstr = ""; - } - - fprintf(stderr, "%s: ", argv0); - vfprintf(stderr, fmt, args); - if (errstr) - fprintf(stderr, "%s%s\n", errstrprefix, errstr); - - errno = saved_errno; -} - - -void -weprintf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vweprintf(fmt, args); - va_end(args); -} - - -void -eprintf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vweprintf(fmt, args); - va_end(args); - exit(1); -} diff --git a/src/windows/appicon.rc b/src/windows/appicon.rc deleted file mode 100644 index 9980b7e..0000000 --- a/src/windows/appicon.rc +++ /dev/null @@ -1 +0,0 @@ -AppIcon ICON redshift.ico diff --git a/src/windows/redshift.ico b/src/windows/redshift.ico Binary files differdeleted file mode 100644 index 751e6fa..0000000 --- a/src/windows/redshift.ico +++ /dev/null diff --git a/src/windows/versioninfo.rc b/src/windows/versioninfo.rc deleted file mode 100644 index 9ede49d..0000000 --- a/src/windows/versioninfo.rc +++ /dev/null @@ -1,20 +0,0 @@ -#include "config.h" - -1 VERSIONINFO -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904E4" - BEGIN - VALUE "CompanyName", "Redshift Open Source Project" - VALUE "FileDescription", "Redshift" - VALUE "OriginalFilename", "redshift.exe" - VALUE "ProductName", "Redshift" - VALUE "ProductVersion", PACKAGE_VERSION - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END |