diff options
Diffstat (limited to 'redshift/common.h')
-rw-r--r-- | redshift/common.h | 1690 |
1 files changed, 1690 insertions, 0 deletions
diff --git a/redshift/common.h b/redshift/common.h new file mode 100644 index 0000000..d9a268d --- /dev/null +++ b/redshift/common.h @@ -0,0 +1,1690 @@ +/*- + * 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 |