Force mode on SIGUSR1
Sending SIGUSR1 will make wlsunset cycle between forcing the temperature high, forcing it low, and returning to automatic temperature control.master
parent
eac926fc21
commit
81cfb0b4f8
116
main.c
116
main.c
|
@ -116,6 +116,13 @@ enum state {
|
||||||
STATE_NORMAL,
|
STATE_NORMAL,
|
||||||
STATE_TRANSITION,
|
STATE_TRANSITION,
|
||||||
STATE_STATIC,
|
STATE_STATIC,
|
||||||
|
STATE_FORCED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum force_state {
|
||||||
|
FORCE_OFF,
|
||||||
|
FORCE_HIGH,
|
||||||
|
FORCE_LOW,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
|
@ -135,6 +142,8 @@ struct context {
|
||||||
struct wl_list outputs;
|
struct wl_list outputs;
|
||||||
timer_t timer;
|
timer_t timer;
|
||||||
|
|
||||||
|
enum force_state forced_state;
|
||||||
|
|
||||||
struct zwlr_gamma_control_manager_v1 *gamma_control_manager;
|
struct zwlr_gamma_control_manager_v1 *gamma_control_manager;
|
||||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||||
};
|
};
|
||||||
|
@ -190,6 +199,11 @@ static void recalc_stops(struct context *ctx, time_t now) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->forced_state != FORCE_OFF) {
|
||||||
|
ctx->state = STATE_FORCED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
time_t last_day = ctx->calc_day;
|
time_t last_day = ctx->calc_day;
|
||||||
ctx->calc_day = day;
|
ctx->calc_day = day;
|
||||||
|
|
||||||
|
@ -316,6 +330,15 @@ static int get_temperature(const struct context *ctx, time_t now) {
|
||||||
case STATE_STATIC:
|
case STATE_STATIC:
|
||||||
return ctx->condition == MIDNIGHT_SUN ? ctx->config.high_temp :
|
return ctx->condition == MIDNIGHT_SUN ? ctx->config.high_temp :
|
||||||
ctx->config.low_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:
|
default:
|
||||||
abort();
|
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);
|
deadline = get_deadline_transition(ctx, now);
|
||||||
break;
|
break;
|
||||||
case STATE_STATIC:
|
case STATE_STATIC:
|
||||||
|
case STATE_FORCED:
|
||||||
deadline = tomorrow(now, ctx->longitude_time_offset);
|
deadline = tomorrow(now, ctx->longitude_time_offset);
|
||||||
break;
|
break;
|
||||||
default:
|
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_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) {
|
static int display_dispatch(struct wl_display *display, int timeout) {
|
||||||
if (wl_display_prepare_read(display) == -1) {
|
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];
|
struct pollfd pfd[2];
|
||||||
pfd[0].fd = wl_display_get_fd(display);
|
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;
|
pfd[0].events = POLLOUT;
|
||||||
// If we hit EPIPE we might have hit a protocol error. Continue reading
|
// 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) {
|
if (pfd[1].revents & POLLIN) {
|
||||||
// Empty signal fd
|
// Empty signal fd
|
||||||
char garbage[8];
|
int signal;
|
||||||
if (read(timer_signal_fds[0], &garbage, sizeof garbage) == -1
|
int res = read(signal_fds[0], &signal, sizeof signal);
|
||||||
&& errno != EAGAIN) {
|
if (res == -1) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (res != 4) {
|
||||||
|
fprintf(stderr, "could not read full signal ID\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case SIGALRM:
|
||||||
|
timer_fired = true;
|
||||||
|
break;
|
||||||
|
case SIGUSR1:
|
||||||
|
// do something
|
||||||
|
usr1_fired = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pfd[0].revents & POLLIN) == 0) {
|
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);
|
return wl_display_dispatch_pending(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void timer_signal(int signal) {
|
static void signal_handler(int signal) {
|
||||||
(void)signal;
|
if (write(signal_fds[1], &signal, sizeof signal) == -1 && errno != EAGAIN) {
|
||||||
timer_fired = true;
|
|
||||||
if (write(timer_signal_fds[1], "\0", 1) == -1 && errno != EAGAIN) {
|
|
||||||
// This is unfortunate.
|
// This is unfortunate.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,24 +736,29 @@ static int set_nonblock(int fd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_timer(struct context *ctx) {
|
static int setup_signals(struct context *ctx) {
|
||||||
struct sigaction timer_action = {
|
struct sigaction signal_action = {
|
||||||
.sa_handler = timer_signal,
|
.sa_handler = signal_handler,
|
||||||
.sa_flags = 0,
|
.sa_flags = 0,
|
||||||
};
|
};
|
||||||
if (pipe(timer_signal_fds) == -1) {
|
if (pipe(signal_fds) == -1) {
|
||||||
fprintf(stderr, "could not create signal pipe: %s\n",
|
fprintf(stderr, "could not create signal pipe: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (set_nonblock(timer_signal_fds[0]) == -1 ||
|
if (set_nonblock(signal_fds[0]) == -1 ||
|
||||||
set_nonblock(timer_signal_fds[1]) == -1) {
|
set_nonblock(signal_fds[1]) == -1) {
|
||||||
fprintf(stderr, "could not set nonblock on signal pipe: %s\n",
|
fprintf(stderr, "could not set nonblock on signal pipe: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (sigaction(SIGALRM, &timer_action, NULL) == -1) {
|
if (sigaction(SIGALRM, &signal_action, NULL) == -1) {
|
||||||
fprintf(stderr, "could not configure alarm handler: %s\n",
|
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));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -744,7 +787,7 @@ static int wlrun(struct config cfg) {
|
||||||
|
|
||||||
wl_list_init(&ctx.outputs);
|
wl_list_init(&ctx.outputs);
|
||||||
|
|
||||||
if (setup_timer(&ctx) == -1) {
|
if (setup_signals(&ctx) == -1) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,9 +829,40 @@ static int wlrun(struct config cfg) {
|
||||||
|
|
||||||
int old_temp = temp;
|
int old_temp = temp;
|
||||||
while (display_dispatch(display, -1) != -1) {
|
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) {
|
if (timer_fired) {
|
||||||
timer_fired = false;
|
timer_fired = false;
|
||||||
|
|
||||||
now = get_time_sec();
|
now = get_time_sec();
|
||||||
recalc_stops(&ctx, now);
|
recalc_stops(&ctx, now);
|
||||||
update_timer(&ctx, ctx.timer, now);
|
update_timer(&ctx, ctx.timer, now);
|
||||||
|
@ -798,10 +872,6 @@ static int wlrun(struct config cfg) {
|
||||||
ctx.new_output = false;
|
ctx.new_output = false;
|
||||||
set_temperature(&ctx.outputs, temp, ctx.config.gamma);
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,14 @@ wlr-gamma-control-unstable-v1
|
||||||
*-g* <gamma>
|
*-g* <gamma>
|
||||||
set gamma (default: 1.0)
|
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
|
# EXAMPLE
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue