spkp

Stacking wayland compositor
git clone git://git.z3bra.org/sp:kp.git
Log | Files | Refs

commit 8c9a50a1bd58997e0cdc1b528490878aefd90de6
parent b5c2b30267eadf2c181b68a9bc65f0d7a3e3151e
Author: Willy Goiffon <dev@z3bra.org>
Date:   Sun,  8 Nov 2020 15:51:05 +0100

Add seat and keyboard handling

Diffstat:
Mcompositor.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfig.mk | 2+-
2 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/compositor.c b/compositor.c @@ -11,6 +11,7 @@ #include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_output.h> #include <wlr/types/wlr_primary_selection_v1.h> @@ -29,12 +30,15 @@ struct state { struct wlr_backend *backend; struct wlr_renderer *renderer; struct wlr_xdg_shell *shell; + struct wlr_seat *seat; + struct wl_listener new_input; struct wl_listener new_output; struct wl_listener new_window; struct wl_list outputs; struct wl_list windows; + struct wl_list keyboards; }; /* compositor output */ @@ -64,6 +68,18 @@ struct window { struct wl_list link; }; +struct keyboard { + struct state *server; + struct wlr_input_device *device; + struct wl_listener destroy; + + struct wl_listener key; + struct wl_listener modifiers; + + /* pointer to the next keyboard */ + struct wl_list link; +}; + struct rdata { struct wlr_output *output; struct window *window; @@ -74,6 +90,7 @@ struct rdata { static void usage(char *); /* callback functions triggered when a new event occur */ +static void cb_new_input(struct wl_listener *, void *); static void cb_new_output(struct wl_listener *, void *); static void cb_destroy_output(struct wl_listener *, void *); static void cb_frame_output(struct wl_listener *, void *); @@ -83,7 +100,12 @@ static void cb_map_window(struct wl_listener *, void *); static void cb_unmap_window(struct wl_listener *, void *); static void cb_destroy_window(struct wl_listener *, void *); +static void cb_kb_mod(struct wl_listener *, void *); +static void cb_kb_key(struct wl_listener *, void *); + +static void add_keyboard(struct state *, struct wlr_input_device *); static void render(struct wlr_surface *, int, int, void *); +static int keybinding(struct state *, uint32_t, uint32_t); void usage(char *pgm) @@ -92,6 +114,69 @@ usage(char *pgm) } /* + * Configure a newly added keyboard + */ +void +add_keyboard(struct state *server, struct wlr_input_device *device) +{ + struct keyboard *kb; + struct xkb_context *context; + struct xkb_keymap *keymap; + struct xkb_rule_names rules = { 0 }; + + kb = calloc(1, sizeof(*kb)); + + kb->server = server; + kb->device = device; + + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); + + kb->key.notify = cb_kb_key; + kb->modifiers.notify = cb_kb_mod; + + wl_signal_add(&device->keyboard->events.key, &kb->key); + wl_signal_add(&device->keyboard->events.modifiers, &kb->modifiers); + + wlr_seat_set_keyboard(server->seat, device); + + wl_list_insert(&server->keyboards, &kb->link); +} + +/* + * A new input device is available + */ +void +cb_new_input(struct wl_listener *listener, void *data) +{ + uint32_t cap = 0; + struct state *server; + struct wlr_input_device *device; + + server = wl_container_of(listener, server, new_input); + device = data; + + switch(device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + add_keyboard(server, device); + break; + default: + break; + } + + /* used to notify clients what our seat is capable of */ + if (!wl_list_empty(&server->keyboards)) + cap |= WL_SEAT_CAPABILITY_KEYBOARD; + + wlr_seat_set_capabilities(server->seat, cap); +} + +/* * Triggered whenever a new output (eg, monitor) is connected to the * compositor. This output is configured (set "mode" if needed) and * added to the outputs list. @@ -233,17 +318,34 @@ cb_new_window(struct wl_listener *listener, void *data) wl_signal_add(&surface->events.destroy, &window->destroy); wl_list_insert(&server->windows, &window->link); + } +/* + * Request from a client to be mapped on-screen + */ void cb_map_window(struct wl_listener *listener, void *data) { struct window *w; + struct state *server; + struct wlr_keyboard *kb; w = wl_container_of(listener, w, map); + server = w->server; + w->mapped = 1; + + /* give window keyboard focus */ + kb = wlr_seat_get_keyboard(server->seat); + wlr_xdg_toplevel_set_activated(w->surface, true); + wlr_seat_keyboard_notify_enter(server->seat, w->surface->surface, + kb->keycodes, kb->num_keycodes, &kb->modifiers); } +/* + * Request from a client to be unmapped on-screen + */ void cb_unmap_window(struct wl_listener *listener, void *data) { @@ -253,6 +355,9 @@ cb_unmap_window(struct wl_listener *listener, void *data) w->mapped = 0; } +/* + * Release all resources associated to a window + */ void cb_destroy_window(struct wl_listener *listener, void *data) { @@ -264,6 +369,50 @@ cb_destroy_window(struct wl_listener *listener, void *data) } void +cb_kb_mod(struct wl_listener *listener, void *data) +{ + struct keyboard *kb; + + kb = wl_container_of(listener, kb, modifiers); + + wlr_seat_set_keyboard(kb->server->seat, kb->device); + wlr_seat_keyboard_notify_modifiers(kb->server->seat, &kb->device->keyboard->modifiers); +} + +void +cb_kb_key(struct wl_listener *listener, void *data) +{ + struct state *server; + struct keyboard *kb; + struct wlr_event_keyboard_key *ev; + struct wlr_seat *seat; + + int nsym; + uint32_t kc, mod; + const xkb_keysym_t *syms; + + ev = data; + kb = wl_container_of(listener, kb, key); + server = kb->server; + seat = server->seat; + + /* translate libinput keycode to xkbcommon */ + kc = ev->keycode + 8; + + nsym = xkb_state_key_get_syms(kb->device->keyboard->xkb_state, kc, &syms); + + mod = wlr_keyboard_get_modifiers(kb->device->keyboard); + for (int i = 0; i < nsym; i++) { + if (keybinding(server, mod, syms[i])) + continue; + + /* pass it onto the underlying client */ + wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_keyboard_notify_key(seat, ev->time_msec, ev->keycode, ev->state); + } +} + +void render(struct wlr_surface *surface, int x, int y, void *data) { float matrix[9]; @@ -292,6 +441,21 @@ render(struct wlr_surface *surface, int x, int y, void *data) } int +keybinding(struct state *server, uint32_t mod, uint32_t key) +{ + switch (key) { + case XKB_KEY_Escape: + if (mod & WLR_MODIFIER_LOGO) { + wl_display_terminate(server->dpy); + return 1; /* NOTREACHED */ + } + break; + } + + return 0; +} + +int main(int argc, char *argv[]) { char *argv0; @@ -312,6 +476,7 @@ main(int argc, char *argv[]) server.backend = wlr_backend_autocreate(server.dpy, NULL); server.renderer = wlr_backend_get_renderer(server.backend); server.shell = wlr_xdg_shell_create(server.dpy); + server.seat = wlr_seat_create(server.dpy, "seat0"); wl_list_init(&server.outputs); wl_list_init(&server.windows); @@ -319,9 +484,11 @@ main(int argc, char *argv[]) wlr_compositor_create(server.dpy, server.renderer); wlr_data_device_manager_create(server.dpy); + server.new_input.notify = cb_new_input; server.new_output.notify = cb_new_output; server.new_window.notify = cb_new_window; + wl_signal_add(&server.backend->events.new_input, &server.new_input); wl_signal_add(&server.backend->events.new_output, &server.new_output); wl_signal_add(&server.shell->events.new_surface, &server.new_window); diff --git a/config.mk b/config.mk @@ -8,5 +8,5 @@ CPPFLAGS = -DWLR_USE_UNSTABLE CFLAGS = -Wall -Wextra -pedantic -g LDFLAGS = WL_CFLAGS = -I./proto -I/usr/include/libdrm -I/usr/include/pixman-1 -WL_LIBS = -lwlroots -lwayland-server -lpixman-1 +WL_LIBS = -lwlroots -lwayland-server -lpixman-1 -lxkbcommon WL_PROTO = /usr/lib/wayland-protocols