diff --git a/libs/wl/init.c b/libs/wl/init.c index a34ade5..ce005c2 100644 --- a/libs/wl/init.c +++ b/libs/wl/init.c @@ -60,8 +60,7 @@ void handle_wl(void) { match(); create_drawable(&state); - while (wl_display_dispatch(state.display) != -1) { - } + await_dispatch(&state); - wl_display_disconnect(state.display); + disconnect_display(&state); } diff --git a/libs/wl/wayland.c b/libs/wl/wayland.c index 972abc4..d768ebb 100644 --- a/libs/wl/wayland.c +++ b/libs/wl/wayland.c @@ -161,9 +161,9 @@ void keypress_wl(struct state *state, enum wl_keyboard_key_state key_state, xkb_ } else { sp.allowkeys = !sp.allowkeys; } - - drawmenu(); } + + drawmenu(); } void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { @@ -196,6 +196,17 @@ void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t r } } +void keyboard_repeat(struct state *state) { + keypress_wl(state, state->repeat_key_state, state->repeat_sym); + + struct itimerspec spec = { 0 }; + + spec.it_value.tv_sec = state->period / 1000; + spec.it_value.tv_nsec = (state->period % 1000) * 1000000l; + + timerfd_settime(state->timer, 0, &spec, NULL); +} + void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state) { struct state *state = data; @@ -539,6 +550,49 @@ int connect_display(struct state *state) { } } +int disconnect_display(struct state *state) { + wl_display_disconnect(state->display); + + return 0; +} + +int await_dispatch(struct state *state) { + struct pollfd fds[] = { + { wl_display_get_fd(state->display), POLLIN, 0 }, + { state->timer, POLLIN, 0 }, + }; + + const int nfds = sizeof(fds) / sizeof(*fds); + + for (;;) { + errno = 0; + + do { + if (wl_display_flush(state->display) == -1 && errno != EAGAIN) { + fprintf(stderr, "spmenu: wl_display_flush failed: %s\n", strerror(errno)); + break; + } + } while (errno == EAGAIN); + + if (poll(fds, nfds, -1) < 0) { + fprintf(stderr, "spmenu: poll failed: %s\n", strerror(errno)); + break; + } + + if (fds[0].revents & POLLIN) { + if (wl_display_dispatch(state->display) < 0) { + break; + } + } + + if (fds[1].revents & POLLIN) { + keyboard_repeat(state); + } + } + + return 0; +} + /* If this function returns 1, something went wrong. * This may be that the user is using X11, or a compositor like Mutter. * In this case, it may be a good idea to fall back to X11. diff --git a/libs/wl/wayland.h b/libs/wl/wayland.h index 01d71a9..3f529ed 100644 --- a/libs/wl/wayland.h +++ b/libs/wl/wayland.h @@ -132,6 +132,7 @@ static void surface_enter(void *data, struct wl_surface *surface, struct wl_outp static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size); static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state); static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); +static void keyboard_repeat(struct state *state); static void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay); static void keypress_wl(struct state *state, enum wl_keyboard_key_state key_state, xkb_keysym_t sym); static void pointer_button_handler(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); @@ -142,6 +143,8 @@ static int is_correct_modifier(struct state *state, char *modifier); static int roundtrip(struct state *state); static int init_disp(struct state *state); static int connect_display(struct state *state); +static int disconnect_display(struct state *state); +static int await_dispatch(struct state *state); static int init_keys(struct state *state); static int create_layer(struct state *state, char *name); static int anchor_layer(struct state *state, int position);