diff options
| -rw-r--r-- | swt.c | 240 | ||||
| -rw-r--r-- | wayland.h | 26 |
2 files changed, 239 insertions, 27 deletions
@@ -1,5 +1,14 @@ +#include <bits/time.h> +#include <sys/mman.h> +#include <sys/timerfd.h> +#include <unistd.h> #include <string.h> #include <stdio.h> +#include <wayland-client-protocol.h> +#include <xkbcommon/xkbcommon.h> +#include <time.h> +#include <poll.h> +#include <errno.h> #include "wayland.h" #include "drw.h" @@ -27,24 +36,32 @@ typedef struct { } Window; +static void setup(); static void buffer_release(void *data, struct wl_buffer *buffer); static void draw_frame(); static void surface_configure(void *data, struct xdg_surface *surface, uint32_t serial); -static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states); +static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients); static void toplevel_close(void *data, struct xdg_toplevel *toplevel); static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial); static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name); +static void seat_capabilities(void *dat, struct wl_seat *seat, uint32_t capabilities); +static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size); +static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t client); +static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); +static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay); +static void handle_keyboard_event(); +static void dummy() {} /* global variables */ static const struct wl_registry_listener registry_listener = { .global = registry_global, - .global_remove = registry_global_remove + .global_remove = registry_global_remove, }; static const struct wl_buffer_listener buffer_listener = { - .release = buffer_release + .release = buffer_release, }; static const struct xdg_surface_listener surface_listener = { @@ -53,14 +70,30 @@ static const struct xdg_surface_listener surface_listener = { static const struct xdg_toplevel_listener toplevel_listener = { .configure = toplevel_configure, - .close = toplevel_close + .close = toplevel_close, + .configure_bounds = dummy, + .wm_capabilities = dummy }; static const struct xdg_wm_base_listener wm_base_listener = { - .ping = wm_base_ping + .ping = wm_base_ping, }; -struct client_state state = { 0 }; +static const struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info, + .enter = dummy, + .leave = dummy, +}; + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_capabilities, + .name = dummy +}; + +Client client = { 0 }; Window win = { 0 }; int running = 1; @@ -91,7 +124,7 @@ surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) if (win.canvas != 0) { free_drw(win.canvas); } - win.canvas = create_drw(state.shm, win.width, win.height); + win.canvas = create_drw(client.shm, win.width, win.height); draw_frame(); wl_surface_attach(win.surface.wl, win.canvas->buffer, 0, 0); @@ -101,7 +134,7 @@ surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) void -toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) +toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients) { if (width == 0 || height == 0) { win.width = 800; @@ -130,11 +163,11 @@ wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { - match_then_bind(state.shm, wl_shm_interface, 1) - or_match match_then_bind(state.compositor, wl_compositor_interface, 4) - or_match match_then_bind(state.wm_base, xdg_wm_base_interface, 1) - /* TODO: or_match match_then_bind(state.seat, wl_seat_interface, 7) - wl_seat_add_listener(state.seat, &seat_listener, &state);*/ + match_then_bind(client.shm, wl_shm_interface, 1) + or_match match_then_bind(client.compositor, wl_compositor_interface, 4) + or_match match_then_bind(client.wm_base, xdg_wm_base_interface, 1) + or_match match_then_bind(client.seat, wl_seat_interface, 7) + wl_seat_add_listener(client.seat, &seat_listener, &client); end_match } @@ -142,32 +175,189 @@ registry_global(void *data, struct wl_registry *registry, uint32_t name, const c void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) { - /* TODO */ + /* TODO: Check if this is necessary */ } -int main() +void +seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) +{ + int has_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD; + + if (has_keyboard && client.kb.keyboard == 0) { + client.kb.keyboard = wl_seat_get_keyboard(client.seat); + wl_keyboard_add_listener(client.kb.keyboard, &keyboard_listener, &client); + } else { + wl_keyboard_release(client.kb.keyboard); + client.kb.keyboard = 0; + } +} + + +void +keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) +{ + char *key_shm; + struct xkb_keymap *keymap; + struct xkb_state *state; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + return; + + key_shm = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); + + if (key_shm == MAP_FAILED) + return; + + keymap = xkb_keymap_new_from_string(client.kb.context, key_shm, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS + ); + + munmap(key_shm, size); + close(fd); + + state = xkb_state_new(keymap); + xkb_keymap_unref(client.kb.keymap); + xkb_state_unref(client.kb.state); + + client.kb.state = state; + client.kb.keymap = keymap; +} + + +void +keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + struct itimerspec spec = { 0 }; + uint32_t keycode = key + 8; + + client.kb.event.sym = xkb_state_key_get_one_sym(client.kb.state, keycode); + client.kb.event.state = state; + + handle_keyboard_event(); + + if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_PRESSED && client.kb.repeat.period >= 0) { + spec.it_value.tv_sec = client.kb.repeat.delay / 1000; + spec.it_value.tv_nsec = (client.kb.repeat.delay % 1000) * 1000000; + timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); + } else if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_RELEASED) { + timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); + } +} + + +void +keyboard_modifiers(void *data, struct wl_keyboard *keybaord, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) +{ + xkb_state_update_mask(client.kb.state, depressed, latched, locked, 0, 0, group); + + client.kb.event.mods.alt = xkb_state_mod_name_is_active( + client.kb.state, + XKB_MOD_NAME_ALT, + XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED + ); + client.kb.event.mods.ctrl = xkb_state_mod_name_is_active( + client.kb.state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED + ); + client.kb.event.mods.shift = xkb_state_mod_name_is_active( + client.kb.state, + XKB_MOD_NAME_SHIFT, + XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED + ); +} + + +void +keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) { - state.display = wl_display_connect(0); - state.registry = wl_display_get_registry(state.display); - wl_registry_add_listener(state.registry, ®istry_listener, &state); - wl_display_roundtrip(state.display); + client.kb.repeat.delay = delay; - xdg_wm_base_add_listener(state.wm_base, &wm_base_listener, &state); - wl_display_roundtrip(state.display); + if (rate > 0) + client.kb.repeat.period = 1000 / rate; + else + client.kb.repeat.period = -1; +} + + +void +handle_keyboard_event() +{ + char buf[8]; + + if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if (xkb_keysym_to_utf8(client.kb.event.sym, buf, sizeof(buf))) { + fprintf(stderr, "keypress: %s\n", buf); + } + } +} - win.surface.wl = wl_compositor_create_surface(state.compositor); - win.surface.xdg = xdg_wm_base_get_xdg_surface(state.wm_base, win.surface.wl); + +void +setup() +{ + client.kb.repeat.timer = timerfd_create(CLOCK_MONOTONIC, 0); + client.kb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + client.display = wl_display_connect(0); + client.registry = wl_display_get_registry(client.display); + wl_registry_add_listener(client.registry, ®istry_listener, &client); + wl_display_roundtrip(client.display); + + xdg_wm_base_add_listener(client.wm_base, &wm_base_listener, &client); + wl_display_roundtrip(client.display); + + win.surface.wl = wl_compositor_create_surface(client.compositor); + win.surface.xdg = xdg_wm_base_get_xdg_surface(client.wm_base, win.surface.wl); xdg_surface_add_listener(win.surface.xdg, &surface_listener, &win); win.surface.toplevel = xdg_surface_get_toplevel(win.surface.xdg); xdg_toplevel_add_listener(win.surface.toplevel, &toplevel_listener, &win); xdg_toplevel_set_title(win.surface.toplevel, "swt"); wl_surface_commit(win.surface.wl); +} + + +int main() +{ + struct itimerspec spec = { 0 }; + struct pollfd fds[2]; + + setup(); + + fds[0].fd = wl_display_get_fd(client.display); + fds[0].events = POLLIN; + fds[1].fd = client.kb.repeat.timer; + fds[1].events = POLLIN; + + while (running) { + if (wl_display_flush(client.display) < 0) { + if (errno == EAGAIN) + continue; + break; + } + + if (poll(fds, sizeof(fds) / sizeof(*fds), -1) < 0) { + if (errno == EAGAIN) + continue; + break; + } + + if (fds[0].revents & POLLIN) { + if (wl_display_dispatch(client.display) < 0) { + running = 0; + } + } - while (wl_display_dispatch(state.display) && running) { + if (fds[1].revents & POLLIN) { + handle_keyboard_event(); + spec.it_value.tv_sec = client.kb.repeat.period / 1000; + spec.it_value.tv_nsec = (client.kb.repeat.period % 1000) / 1000000; + timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); + } } - wl_display_disconnect(state.display); + wl_display_disconnect(client.display); return 0; } @@ -1,17 +1,39 @@ #ifndef WAYLAND_H #define WAYLAND_H +#include <xkbcommon/xkbcommon.h> #include <wayland-client.h> #include "xdg-shell-client-protocol.h" -struct client_state { + +typedef struct { struct wl_display *display; struct wl_registry *registry; struct wl_shm *shm; struct wl_compositor *compositor; struct xdg_wm_base *wm_base; struct wl_seat *seat; -}; + struct { + struct xkb_state *state; + struct xkb_keymap *keymap; + struct xkb_context *context; + struct wl_keyboard *keyboard; + struct { + uint32_t state; + uint32_t sym; + struct { + uint32_t ctrl; + uint32_t alt; + uint32_t shift; + } mods; + } event; + struct { + int timer; + int delay; + int period; + } repeat; + } kb; +} Client; int allocate_shm_file(size_t size); |