diff options
author | Mattias Andrée <m@maandree.se> | 2025-02-04 21:47:35 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-02-04 21:47:35 +0100 |
commit | 8e6f8d4e24c0e0e95081bf61f7a55c4f85469950 (patch) | |
tree | 251ca8e47a2c53412e14484a790fbcfc83feb8c2 /radharc.c | |
parent | Update TODO (diff) | |
download | radharc-8e6f8d4e24c0e0e95081bf61f7a55c4f85469950.tar.gz radharc-8e6f8d4e24c0e0e95081bf61f7a55c4f85469950.tar.bz2 radharc-8e6f8d4e24c0e0e95081bf61f7a55c4f85469950.tar.xz |
Add support for SIGINT and SIGHUP
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'radharc.c')
-rw-r--r-- | radharc.c | 191 |
1 files changed, 179 insertions, 12 deletions
@@ -3,6 +3,7 @@ #include <sys/timerfd.h> #include <errno.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -91,6 +92,27 @@ static int dflag = 0; */ static int xflag = 0; + +/** + * If 0, SIGINT has not been received, + * if 1, SIGINT has been received once as the effect + * should be faded out and then the effect should + * be removed and the program terminated, + * if 2, SIGINT has been received at least twice and + * the effect should be removed immediately + * and the program terminated + */ +static volatile sig_atomic_t sigint_received = 0; + +/** + * If 0, SIGHUP has not been received, + * if 1, SIGHUP has been received and the effect + * shall be made `LIBCOOPGAMMA_UNTIL_REMOVAL` and + * the program terminated + */ +static volatile sig_atomic_t sighup_received = 0; + + /** * Print usage information and exit */ @@ -104,6 +126,7 @@ usage(void) exit(1); } + /** * Parse a non-negative double encoded as a string * @@ -124,6 +147,7 @@ parse_double(double *out, const char *str) return 0; } + /** * Handle a command line option * @@ -209,6 +233,7 @@ handle_opt(char *opt, char *arg) return 0; } + /** * This function is called after the last * call to `handle_opt` @@ -228,6 +253,7 @@ handle_args(int argc, char *argv[], char *prio) (void) prio; } + /** * Fill a filter * @@ -254,6 +280,7 @@ LIST_DEPTHS } } + /** * Set the gamma ramps * @@ -273,15 +300,19 @@ set_ramps(double red, double green, double blue) libclut_model_standard_to_linear(&red, &green, &blue); for (i = 0, r = 1; i < filters_n; i++) { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) + if (!crtc_updates[i].master || !crtc_info[crtc_updates[i].crtc].supported) continue; - fill_filter(&(crtc_updates[i].filter), red, green, blue); - r = update_filter(i, 0); + fill_filter(&crtc_updates[i].filter, red, green, blue); + do { + r = update_filter(i, 0); + } while (r == -1 && errno == EINTR); if (r == -2 || (r == -1 && errno != EAGAIN)) return r; if (crtc_updates[i].slaves) { for (j = 0; crtc_updates[i].slaves[j] != 0; j++) { - r = update_filter(crtc_updates[i].slaves[j], 0); + do { + r = update_filter(crtc_updates[i].slaves[j], 0); + } while (r == -1 && errno == EINTR); if (r == -2 || (r == -1 && errno != EAGAIN)) return r; } @@ -290,11 +321,13 @@ set_ramps(double red, double green, double blue) while (r != 1) if ((r = synchronise(-1)) < 0) - return r; + if (r != -1 || errno != EINTR) + return r; return 0; } + /** * Get the colour temperature for the current time * @@ -321,6 +354,32 @@ get_temperature(double *tp) /** + * Called when SIGINT is received + * + * @param sig Always `SIGINT` + */ +static void +sigint_handler(int sig) +{ + (void) sig; + sigint_received = sigint_received ? 2 : 1; +} + + +/** + * Called when SIGHUP is received + * + * @param sig Always `SIGHUP` + */ +static void +sighup_handler(int sig) +{ + (void) sig; + sighup_received = 1; +} + + +/** * The main function for the program-specific code * * @return 0: Success @@ -333,8 +392,20 @@ start(void) { int r, tfd; size_t i; - double temperature, red, green, blue; + double target_temperature; + long int original_temperature; + long int current_temperature = 6500; + double red = 1, green = 1, blue = 1; uint64_t overrun; + struct sigaction sa; + struct timespec sleep_timeout; + const char *side; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &sigint_handler; + sigaction(SIGINT, &sa, NULL); + sa.sa_handler = &sighup_handler; + sigaction(SIGHUP, &sa, NULL); if (xflag) for (i = 0; i < filters_n; i++) @@ -366,16 +437,26 @@ start(void) return -1; for (i = 0; i < (size_t)fade_in_cs;) { + if (sigint_received) { + double cs = (double)i / fade_in_cs * fade_out_cs + 0.5; + fade_out_cs = (unsigned long int)cs; + goto fade_out_have_timer; + } + if (i % 600 == 0) - if ((r = get_temperature(&temperature)) < 0) + if ((r = get_temperature(&target_temperature)) < 0) return r; - if (libred_get_colour((long int)(6500 - (6500 - temperature) * i / fade_in_cs), &red, &green, &blue)) + current_temperature = (long int)(6500 - (6500 - target_temperature) * i / fade_in_cs); + if (libred_get_colour(current_temperature, &red, &green, &blue)) return -1; if ((r = set_ramps(red, green, blue)) < 0) return r; - if (read(tfd, &overrun, sizeof(overrun)) != sizeof(overrun)) + while (read(tfd, &overrun, sizeof(overrun)) != sizeof(overrun)) { + if (errno == EINTR) + continue; return -1; + } if (overrun > fade_in_cs - i) overrun = fade_in_cs - i; i += overrun; @@ -385,9 +466,19 @@ start(void) no_fade_in: for (;;) { - if ((r = get_temperature(&temperature)) < 0) + if (sigint_received) + goto fade_out; + + if (sighup_received) { + for (i = 0; i < filters_n; i++) + crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; + return set_ramps(red, green, blue); + } + + if ((r = get_temperature(&target_temperature)) < 0) return r; - if (libred_get_colour((long int)temperature, &red, &green, &blue)) + current_temperature = (long int)target_temperature; + if (libred_get_colour(current_temperature, &red, &green, &blue)) return -1; if ((r = set_ramps(red, green, blue)) < 0) return r; @@ -395,6 +486,82 @@ no_fade_in: if (!dflag) return 0; - sleep(6); + sleep_timeout.tv_sec = 6; + sleep_timeout.tv_nsec = 0; + while ((errno = clock_nanosleep(CLOCK_BOOTTIME, 0, &sleep_timeout, &sleep_timeout))) { + if (errno == EINTR) { + if (sigint_received || sighup_received) + break; + continue; + } + return -1; + } + } + +fade_out: + tfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (tfd < 0) + goto fade_out_fail; + if (timerfd_settime(tfd, 0, &(struct itimerspec){{0, 10000000L}, {0, 10000000L}}, NULL)) + goto fade_out_fail; + +fade_out_have_timer: + original_temperature = current_temperature; + for (i = 0; i < (size_t)fade_out_cs;) { + if (sigint_received > 1) + break; + + current_temperature = original_temperature + (double)(6500 - original_temperature) * i / fade_out_cs; + if (libred_get_colour(current_temperature, &red, &green, &blue)) + goto fade_out_fail; + if ((r = set_ramps(red, green, blue)) < 0) + goto fade_out_fail_use_r; + + while (read(tfd, &overrun, sizeof(overrun)) != sizeof(overrun)) { + if (errno == EINTR) + continue; + goto fade_out_fail; + } + if (overrun > fade_in_cs - i) + overrun = fade_in_cs - i; + i += overrun; } + + close(tfd); + + for (i = 0; i < filters_n; i++) + crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; + return set_ramps(1, 1, 1); + +fade_out_fail_use_r: + switch (r) { + case -1: + fade_out_fail: + perror(argv0); + break; + case -2: + side = cg.error.server_side ? "server" : "client"; + if (cg.error.custom) { + if (cg.error.number && cg.error.description) { + fprintf(stderr, "%s: %s-side error number %" PRIu64 ": %s\n", + argv0, side, cg.error.number, cg.error.description); + } else if (cg.error.number) { + fprintf(stderr, "%s: %s-side error number %" PRIu64 "\n", argv0, side, cg.error.number); + } else if (cg.error.description) { + fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); + } + } else if (cg.error.description) { + fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); + } else { + fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, strerror((int)cg.error.number)); + } + break; + default: + break; + } + + for (i = 0; i < filters_n; i++) + crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; + r = set_ramps(1, 1, 1); + return r ? r : -3; } |