From bec47f49e31f2c7dbe2b75746fb8675bce9a4880 Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Tue, 6 Jul 2021 23:54:51 -0300 Subject: [PATCH] Factor out event loop. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This rework is necessary because it will allow us to add signal handlers via signalfd and a varlink interface for IPC. Co-authored-by: Érico Nogueira --- event-loop.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ include/kanshi.h | 4 +++ main.c | 40 ++++++++++++++++++----------- meson.build | 1 + 4 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 event-loop.c diff --git a/event-loop.c b/event-loop.c new file mode 100644 index 0000000..c3e8cf0 --- /dev/null +++ b/event-loop.c @@ -0,0 +1,65 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kanshi.h" + +enum readfds_type { + FD_WAYLAND, + FD_COUNT, +}; + +int kanshi_main_loop(struct kanshi_state *state) { + struct pollfd readfds[FD_COUNT] = {0}; + readfds[FD_WAYLAND].fd = wl_display_get_fd(state->display); + readfds[FD_WAYLAND].events = POLLIN; + + while (state->running) { + while (wl_display_prepare_read(state->display) != 0) { + if (wl_display_dispatch_pending(state->display) == -1) { + return EXIT_FAILURE; + } + } + + int ret; + + while (true) { + ret = wl_display_flush(state->display); + if (ret != -1 || errno != EAGAIN) { + break; + } + } + + if (ret < 0 && errno != EPIPE) { + goto read_error; + } + + do { + ret = poll(readfds, sizeof(readfds) / sizeof(readfds[0]), -1); + } while (ret == -1 && errno == EINTR); + /* will only be -1 if errno wasn't EINTR */ + if (ret == -1) { + goto read_error; + } + + if (wl_display_read_events(state->display) == -1) { + return EXIT_FAILURE; + } + + if (wl_display_dispatch_pending(state->display) == -1) { + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; + +read_error: + wl_display_cancel_read(state->display); + return EXIT_FAILURE; +} diff --git a/include/kanshi.h b/include/kanshi.h index dd111f1..59a222e 100644 --- a/include/kanshi.h +++ b/include/kanshi.h @@ -41,6 +41,7 @@ struct kanshi_head { struct kanshi_state { bool running; + struct wl_display *display; struct zwlr_output_manager_v1 *output_manager; struct kanshi_config *config; @@ -48,6 +49,7 @@ struct kanshi_state { struct wl_list heads; uint32_t serial; struct kanshi_profile *current_profile; + struct kanshi_profile *pending_profile; }; struct kanshi_pending_profile { @@ -55,4 +57,6 @@ struct kanshi_pending_profile { struct kanshi_profile *profile; }; +int kanshi_main_loop(struct kanshi_state *state); + #endif diff --git a/main.c b/main.c index 8e21f76..75db773 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -187,13 +188,16 @@ static struct kanshi_mode *match_mode(struct kanshi_head *head, static void apply_profile(struct kanshi_state *state, struct kanshi_profile *profile, struct kanshi_profile_output **matches) { - if (state->current_profile == profile) { + if (state->pending_profile == profile || state->current_profile == profile) { return; } + fprintf(stderr, "applying profile '%s'\n", profile->name); + struct kanshi_pending_profile *pending = calloc(1, sizeof(*pending)); pending->state = state; pending->profile = profile; + state->pending_profile = profile; struct zwlr_output_configuration_v1 *config = zwlr_output_manager_v1_create_configuration(state->output_manager, @@ -406,21 +410,25 @@ static void output_manager_handle_head(void *data, zwlr_output_head_v1_add_listener(wlr_head, &head_listener, head); } -static void output_manager_handle_done(void *data, - struct zwlr_output_manager_v1 *manager, uint32_t serial) { - struct kanshi_state *state = data; - state->serial = serial; - +static bool try_apply_profiles(struct kanshi_state *state) { assert(wl_list_length(&state->heads) <= HEADS_MAX); // matches[i] gives the kanshi_profile_output for the i-th head struct kanshi_profile_output *matches[HEADS_MAX]; struct kanshi_profile *profile = match(state, matches); if (profile != NULL) { - fprintf(stderr, "applying profile '%s'\n", profile->name); apply_profile(state, profile, matches); - } else { - fprintf(stderr, "no profile matched\n"); + return true; } + fprintf(stderr, "no profile matched\n"); + return false; +} + +static void output_manager_handle_done(void *data, + struct zwlr_output_manager_v1 *manager, uint32_t serial) { + struct kanshi_state *state = data; + state->serial = serial; + + try_apply_profiles(state); } static void output_manager_handle_finished(void *data, @@ -520,8 +528,10 @@ int main(int argc, char *argv[]) { struct kanshi_state state = { .running = true, + .display = display, .config = config, }; + int ret = EXIT_SUCCESS; wl_list_init(&state.heads); struct wl_registry *registry = wl_display_get_registry(display); @@ -532,12 +542,14 @@ int main(int argc, char *argv[]) { if (state.output_manager == NULL) { fprintf(stderr, "compositor doesn't support " "wlr-output-management-unstable-v1\n"); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto done; } - while (state.running && wl_display_dispatch(display) != -1) { - // This space intentionally left blank - } + ret = kanshi_main_loop(&state); - return EXIT_SUCCESS; +done: + wl_display_disconnect(display); + + return ret; } diff --git a/meson.build b/meson.build index ce63635..d562cb6 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,7 @@ executable( files( 'main.c', 'parser.c', + 'event-loop.c', ), include_directories: include_directories('include'), dependencies: [wayland_client, client_protos],