diff options
| author | Jari Vetoniemi <mailroxas@gmail.com> | 2014-11-02 06:48:53 +0200 | 
|---|---|---|
| committer | Jari Vetoniemi <mailroxas@gmail.com> | 2014-11-02 06:48:53 +0200 | 
| commit | 0d5cdc2c962179bfbfb04ba1f87a4be7d6e44913 (patch) | |
| tree | 1a80b3a33a04d4128d9866d6ff20a227c5f65e9f /lib | |
| parent | ee3c41f162a9068505efdb5025c415b889cf414d (diff) | |
| download | bemenu-0d5cdc2c962179bfbfb04ba1f87a4be7d6e44913.tar.gz bemenu-0d5cdc2c962179bfbfb04ba1f87a4be7d6e44913.tar.bz2 bemenu-0d5cdc2c962179bfbfb04ba1f87a4be7d6e44913.zip | |
Key repeats.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/renderers/wayland/registry.c | 93 | ||||
| -rw-r--r-- | lib/renderers/wayland/wayland.c | 55 | ||||
| -rw-r--r-- | lib/renderers/wayland/wayland.h | 17 | ||||
| -rw-r--r-- | lib/renderers/wayland/window.c | 19 | 
4 files changed, 157 insertions, 27 deletions
| diff --git a/lib/renderers/wayland/registry.c b/lib/renderers/wayland/registry.c index 4e5e6dd..1faef18 100644 --- a/lib/renderers/wayland/registry.c +++ b/lib/renderers/wayland/registry.c @@ -1,7 +1,9 @@ +#define _DEFAULT_SOURCE  #include "wayland.h"  #include <unistd.h>  #include <sys/mman.h> +#include <sys/timerfd.h>  const char *BM_XKB_MASK_NAMES[MASK_LAST] = {      XKB_MOD_NAME_SHIFT, @@ -104,7 +106,24 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial,  static void  keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)  { -    (void)data, (void)keyboard, (void)serial, (void)surface; +    (void)keyboard, (void)serial, (void)surface; +    struct input *input = data; +    struct itimerspec its; +    its.it_interval.tv_sec = 0; +    its.it_interval.tv_nsec = 0; +    its.it_value.tv_sec = 0; +    its.it_value.tv_nsec = 0; +    timerfd_settime(*input->repeat_fd, 0, &its, NULL); +} + +static void +press(struct input *input, xkb_keysym_t sym, uint32_t key, enum wl_keyboard_key_state state) +{ +    input->sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol); +    input->code = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? key + 8 : 0); + +    if (input->notify.key) +        input->notify.key(state, sym, key);  }  static void @@ -117,35 +136,26 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, u      if (!input->xkb.state)          return; -    uint32_t code = key + 8; -    xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, code); - -    input->sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol); -    input->code = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? code : 0); +    xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, key + 8); +    press(input, sym, key, state); -    if (input->notify.key) -        input->notify.key(state, sym, code); - -#if 0 -    if (state == WL_KEYBOARD_KEY_STATE_RELEASED && -            key == input->repeat_key) { -        its.it_interval.tv_sec = 0; -        its.it_interval.tv_nsec = 0; -        its.it_value.tv_sec = 0; -        its.it_value.tv_nsec = 0; -        timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); -    } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED && -            xkb_keymap_key_repeats(input->xkb.keymap, code)) { +    if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(input->xkb.keymap, input->code)) { +        struct itimerspec its;          input->repeat_sym = sym;          input->repeat_key = key; -        input->repeat_time = time;          its.it_interval.tv_sec = input->repeat_rate_sec;          its.it_interval.tv_nsec = input->repeat_rate_nsec;          its.it_value.tv_sec = input->repeat_delay_sec;          its.it_value.tv_nsec = input->repeat_delay_nsec; -        timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); +        timerfd_settime(*input->repeat_fd, 0, &its, NULL); +    } else if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat_key) { +        struct itimerspec its; +        its.it_interval.tv_sec = 0; +        its.it_interval.tv_nsec = 0; +        its.it_value.tv_sec = 0; +        its.it_value.tv_nsec = 0; +        timerfd_settime(*input->repeat_fd, 0, &its, NULL);      } -#endif  }  static void @@ -168,9 +178,32 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t ser  }  static void +set_repeat_info(struct input *input, int32_t rate, int32_t delay) +{ +    assert(input); + +    input->repeat_rate_sec = input->repeat_rate_nsec = 0; +    input->repeat_delay_sec = input->repeat_delay_nsec = 0; + +    /* a rate of zero disables any repeating, regardless of the delay's value */ +    if (rate == 0) +        return; + +    if (rate == 1) +        input->repeat_rate_sec = 1; +    else +        input->repeat_rate_nsec = 1000000000 / rate; + +    input->repeat_delay_sec = delay / 1000; +    delay -= (input->repeat_delay_sec * 1000); +    input->repeat_delay_nsec = delay * 1000 * 1000; +} + +static void  keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)  { -    (void)data, (void)keyboard, (void)rate, (void)delay; +    (void)keyboard; +    set_repeat_info(data, rate, delay);  }  static const struct wl_keyboard_listener keyboard_listener = { @@ -242,6 +275,19 @@ static const struct wl_registry_listener registry_listener = {  };  void +bm_wl_repeat(struct wayland *wayland) +{ +    uint64_t exp; +    if (read(wayland->fds.repeat, &exp, sizeof(exp)) != sizeof(exp)) +        return; + +    if (wayland->input.notify.key) +        wayland->input.notify.key(WL_KEYBOARD_KEY_STATE_PRESSED, wayland->input.repeat_sym, wayland->input.repeat_key + 8); + +    press(&wayland->input, wayland->input.repeat_sym, wayland->input.repeat_key, WL_KEYBOARD_KEY_STATE_PRESSED); +} + +void  bm_wl_registry_destroy(struct wayland *wayland)  {      assert(wayland); @@ -282,6 +328,7 @@ bm_wl_registry_register(struct wayland *wayland)      if (!wayland->input.keyboard || !(wayland->formats & (1 << WL_SHM_FORMAT_ARGB8888)))          return false; +    set_repeat_info(&wayland->input, 40, 400);      return true;  } diff --git a/lib/renderers/wayland/wayland.c b/lib/renderers/wayland/wayland.c index 4325fa9..c447b6e 100644 --- a/lib/renderers/wayland/wayland.c +++ b/lib/renderers/wayland/wayland.c @@ -1,3 +1,4 @@ +#define _DEFAULT_SOURCE  #include "internal.h"  #include "version.h"  #include "wayland.h" @@ -6,19 +7,41 @@  #include <string.h>  #include <stdbool.h>  #include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/epoll.h> +#include <sys/timerfd.h> + +static int efd;  static void  render(const struct bm_menu *menu)  {      struct wayland *wayland = menu->renderer->internal; +    wl_display_dispatch_pending(wayland->display); + +    if (wl_display_flush(wayland->display) < 0 && errno != EAGAIN) { +        wayland->input.sym = XKB_KEY_Escape; +        return; +    } + +    struct epoll_event ep[16]; +    uint32_t num = epoll_wait(efd, ep, 16, -1); +    for (uint32_t i = 0; i < num; ++i) { +        if (ep[i].data.ptr == &wayland->fds.display) { +            if (ep[i].events & EPOLLERR || ep[i].events & EPOLLHUP || +               ((ep[i].events & EPOLLIN) && wl_display_dispatch(wayland->display) < 0)) +                wayland->input.sym = XKB_KEY_Escape; +        } else if (ep[i].data.ptr == &wayland->fds.repeat) { +            bm_wl_repeat(wayland); +        } +    }      uint32_t count;      bm_menu_get_filtered_items(menu, &count);      uint32_t lines = (count < menu->lines ? count : menu->lines) + 1;      bm_wl_window_render(&wayland->window, menu, lines); - -    if (wl_display_dispatch(wayland->display) < 0) -        wayland->input.sym = XKB_KEY_Escape;  }  static enum bm_key @@ -31,13 +54,17 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)      if (wayland->input.sym == XKB_KEY_NoSymbol)          return BM_KEY_UNICODE; +    xkb_keysym_t sym = wayland->input.sym;      uint32_t mods = wayland->input.modifiers;      *unicode = xkb_state_key_get_utf32(wayland->input.xkb.state, wayland->input.code);      if (!*unicode && wayland->input.code == 23 && (mods & MOD_SHIFT))          return BM_KEY_SHIFT_TAB; -    switch (wayland->input.sym) { +    wayland->input.sym = XKB_KEY_NoSymbol; +    wayland->input.code = 0; + +    switch (sym) {          case XKB_KEY_Up:              return BM_KEY_UP; @@ -138,6 +165,9 @@ destructor(struct bm_menu *menu)      xkb_context_unref(wayland->input.xkb.context);      if (wayland->display) { +        epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.repeat, NULL); +        epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.display, NULL); +        close(wayland->fds.repeat);          wl_display_flush(wayland->display);          wl_display_disconnect(wayland->display);      } @@ -169,7 +199,24 @@ constructor(struct bm_menu *menu)      if (!bm_wl_window_create(&wayland->window, wayland->shm, wayland->shell, wayland->xdg_shell, surface))          goto fail; +    if (!efd && (efd = epoll_create(EPOLL_CLOEXEC)) < 0) +        goto fail; + +    wayland->fds.display = wl_display_get_fd(wayland->display); +    wayland->fds.repeat = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + +    struct epoll_event ep; +    ep.events = EPOLLIN | EPOLLERR | EPOLLHUP; +    ep.data.ptr = &wayland->fds.display; +    epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.display, &ep); + +    struct epoll_event ep2; +    ep2.events = EPOLLIN; +    ep2.data.ptr = &wayland->fds.repeat; +    epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.repeat, &ep2); +      wayland->window.notify.render = bm_cairo_paint; +    wayland->input.repeat_fd = &wayland->fds.repeat;      return true;  fail: diff --git a/lib/renderers/wayland/wayland.h b/lib/renderers/wayland/wayland.h index a9c79b3..db837e9 100644 --- a/lib/renderers/wayland/wayland.h +++ b/lib/renderers/wayland/wayland.h @@ -44,6 +44,8 @@ struct xkb {  };  struct input { +    int *repeat_fd; +      struct wl_keyboard *keyboard;      struct xkb xkb; @@ -51,6 +53,14 @@ struct input {      uint32_t code;      uint32_t modifiers; +    xkb_keysym_t repeat_sym; +    uint32_t repeat_key; + +    int32_t repeat_rate_sec; +    int32_t repeat_rate_nsec; +    int32_t repeat_delay_sec; +    int32_t repeat_delay_nsec; +      struct {          void (*key)(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code);      } notify; @@ -66,6 +76,7 @@ struct buffer {  struct window {      struct wl_surface *surface;      struct wl_shell_surface *shell_surface; +    struct wl_callback *frame_cb;      struct xdg_surface *xdg_surface;      struct wl_shm *shm;      struct buffer buffers[2]; @@ -78,6 +89,11 @@ struct window {  };  struct wayland { +    struct { +        int32_t display; +        int32_t repeat; +    } fds; +      struct wl_display *display;      struct wl_registry *registry;      struct wl_compositor *compositor; @@ -90,6 +106,7 @@ struct wayland {      uint32_t formats;  }; +void bm_wl_repeat(struct wayland *wayland);  bool bm_wl_registry_register(struct wayland *wayland);  void bm_wl_registry_destroy(struct wayland *wayland);  void bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines); diff --git a/lib/renderers/wayland/window.c b/lib/renderers/wayland/window.c index 4282e13..057863d 100644 --- a/lib/renderers/wayland/window.c +++ b/lib/renderers/wayland/window.c @@ -246,11 +246,27 @@ static const struct xdg_surface_listener xdg_surface_listener = {      .close = xdg_surface_close,  }; +static void +frame_callback(void *data, struct wl_callback *callback, uint32_t time) +{ +    (void)time; +    struct window *window = data; +    wl_callback_destroy(callback); +    window->frame_cb = NULL; +} + +static const struct wl_callback_listener listener = { +    frame_callback +}; +  void  bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines)  {      assert(window && menu); +    if (window->frame_cb) +        return; +      struct buffer *buffer;      if (!(buffer = next_buffer(window)))          return; @@ -265,6 +281,9 @@ bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t      if (window->notify.render)          window->displayed = window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu); +    window->frame_cb = wl_surface_frame(window->surface); +    wl_callback_add_listener(window->frame_cb, &listener, window); +      wl_surface_damage(window->surface, 0, 0, buffer->width, buffer->height);      wl_surface_attach(window->surface, buffer->buffer, 0, 0);      wl_surface_commit(window->surface); | 
