From 81cfb0b4f8e44db9e5ecb36222a24d53a953e6aa Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 2 Jun 2023 11:53:00 +0200 Subject: [PATCH] Force mode on SIGUSR1 Sending SIGUSR1 will make wlsunset cycle between forcing the temperature high, forcing it low, and returning to automatic temperature control. --- main.c | 116 +++++++++++++++++++++++++++++++++++++++---------- wlsunset.1.scd | 8 ++++ 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/main.c b/main.c index beb0782..ba25a3a 100644 --- a/main.c +++ b/main.c @@ -116,6 +116,13 @@ enum state { STATE_NORMAL, STATE_TRANSITION, STATE_STATIC, + STATE_FORCED, +}; + +enum force_state { + FORCE_OFF, + FORCE_HIGH, + FORCE_LOW, }; struct context { @@ -135,6 +142,8 @@ struct context { struct wl_list outputs; timer_t timer; + enum force_state forced_state; + struct zwlr_gamma_control_manager_v1 *gamma_control_manager; struct zxdg_output_manager_v1 *xdg_output_manager; }; @@ -190,6 +199,11 @@ static void recalc_stops(struct context *ctx, time_t now) { return; } + if (ctx->forced_state != FORCE_OFF) { + ctx->state = STATE_FORCED; + return; + } + time_t last_day = ctx->calc_day; ctx->calc_day = day; @@ -316,6 +330,15 @@ static int get_temperature(const struct context *ctx, time_t now) { case STATE_STATIC: return ctx->condition == MIDNIGHT_SUN ? ctx->config.high_temp : ctx->config.low_temp; + case STATE_FORCED: + switch (ctx->forced_state) { + case FORCE_HIGH: + return ctx->config.high_temp; + case FORCE_LOW: + return ctx->config.low_temp; + default: + abort(); + } default: abort(); } @@ -359,6 +382,7 @@ static void update_timer(const struct context *ctx, timer_t timer, time_t now) { deadline = get_deadline_transition(ctx, now); break; case STATE_STATIC: + case STATE_FORCED: deadline = tomorrow(now, ctx->longitude_time_offset); break; default: @@ -622,7 +646,8 @@ static void set_temperature(struct wl_list *outputs, int temp, double gamma) { } static int timer_fired = 0; -static int timer_signal_fds[2]; +static int usr1_fired = 0; +static int signal_fds[2]; static int display_dispatch(struct wl_display *display, int timeout) { if (wl_display_prepare_read(display) == -1) { @@ -631,7 +656,7 @@ static int display_dispatch(struct wl_display *display, int timeout) { struct pollfd pfd[2]; pfd[0].fd = wl_display_get_fd(display); - pfd[1].fd = timer_signal_fds[0]; + pfd[1].fd = signal_fds[0]; pfd[0].events = POLLOUT; // If we hit EPIPE we might have hit a protocol error. Continue reading @@ -662,11 +687,26 @@ static int display_dispatch(struct wl_display *display, int timeout) { if (pfd[1].revents & POLLIN) { // Empty signal fd - char garbage[8]; - if (read(timer_signal_fds[0], &garbage, sizeof garbage) == -1 - && errno != EAGAIN) { + int signal; + int res = read(signal_fds[0], &signal, sizeof signal); + if (res == -1) { + if (errno != EAGAIN) { + return -1; + } + } else if (res != 4) { + fprintf(stderr, "could not read full signal ID\n"); return -1; } + + switch (signal) { + case SIGALRM: + timer_fired = true; + break; + case SIGUSR1: + // do something + usr1_fired = true; + break; + } } if ((pfd[0].revents & POLLIN) == 0) { @@ -681,10 +721,8 @@ static int display_dispatch(struct wl_display *display, int timeout) { return wl_display_dispatch_pending(display); } -static void timer_signal(int signal) { - (void)signal; - timer_fired = true; - if (write(timer_signal_fds[1], "\0", 1) == -1 && errno != EAGAIN) { +static void signal_handler(int signal) { + if (write(signal_fds[1], &signal, sizeof signal) == -1 && errno != EAGAIN) { // This is unfortunate. } } @@ -698,24 +736,29 @@ static int set_nonblock(int fd) { return 0; } -static int setup_timer(struct context *ctx) { - struct sigaction timer_action = { - .sa_handler = timer_signal, +static int setup_signals(struct context *ctx) { + struct sigaction signal_action = { + .sa_handler = signal_handler, .sa_flags = 0, }; - if (pipe(timer_signal_fds) == -1) { + if (pipe(signal_fds) == -1) { fprintf(stderr, "could not create signal pipe: %s\n", strerror(errno)); return -1; } - if (set_nonblock(timer_signal_fds[0]) == -1 || - set_nonblock(timer_signal_fds[1]) == -1) { + if (set_nonblock(signal_fds[0]) == -1 || + set_nonblock(signal_fds[1]) == -1) { fprintf(stderr, "could not set nonblock on signal pipe: %s\n", strerror(errno)); return -1; } - if (sigaction(SIGALRM, &timer_action, NULL) == -1) { - fprintf(stderr, "could not configure alarm handler: %s\n", + if (sigaction(SIGALRM, &signal_action, NULL) == -1) { + fprintf(stderr, "could not configure SIGALRM handler: %s\n", + strerror(errno)); + return -1; + } + if (sigaction(SIGUSR1, &signal_action, NULL) == -1) { + fprintf(stderr, "could not configure SIGUSR1 handler: %s\n", strerror(errno)); return -1; } @@ -744,7 +787,7 @@ static int wlrun(struct config cfg) { wl_list_init(&ctx.outputs); - if (setup_timer(&ctx) == -1) { + if (setup_signals(&ctx) == -1) { return EXIT_FAILURE; } @@ -786,9 +829,40 @@ static int wlrun(struct config cfg) { int old_temp = temp; while (display_dispatch(display, -1) != -1) { + if (ctx.new_output) { + ctx.new_output = false; + + // Force set_temperature + old_temp = 0; + timer_fired = true; + } + + if (usr1_fired) { + usr1_fired = false; + switch (ctx.forced_state) { + case FORCE_OFF: + ctx.forced_state = FORCE_HIGH; + fprintf(stderr, "forcing high temperature\n"); + break; + case FORCE_HIGH: + ctx.forced_state = FORCE_LOW; + fprintf(stderr, "forcing low temperature\n"); + break; + case FORCE_LOW: + ctx.forced_state = FORCE_OFF; + fprintf(stderr, "disabling forced temperature\n"); + break; + default: + abort(); + } + + // Force re-calculation + ctx.calc_day = 0; + timer_fired = true; + } + if (timer_fired) { timer_fired = false; - now = get_time_sec(); recalc_stops(&ctx, now); update_timer(&ctx, ctx.timer, now); @@ -798,10 +872,6 @@ static int wlrun(struct config cfg) { ctx.new_output = false; set_temperature(&ctx.outputs, temp, ctx.config.gamma); } - } else if (ctx.new_output) { - ctx.new_output = false; - - set_temperature(&ctx.outputs, temp, ctx.config.gamma); } } diff --git a/wlsunset.1.scd b/wlsunset.1.scd index c62f2bc..ea5f126 100644 --- a/wlsunset.1.scd +++ b/wlsunset.1.scd @@ -40,6 +40,14 @@ wlr-gamma-control-unstable-v1 *-g* set gamma (default: 1.0) +# RUNTIME CONTROL + +Sending SIGUSR1 to wlsunset causes it to cycle through the following modes: + +1. Forcing use of the high temperature +2. Forcing use of the low temperature +3. Automatic temperature calculation + # EXAMPLE ```