diff options
Diffstat (limited to 'src/redshift.c')
-rw-r--r-- | src/redshift.c | 543 |
1 files changed, 0 insertions, 543 deletions
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; -} |