tAdd seat and keyboard handling - spkp - Stacking wayland compositor
(HTM) git clone git://git.z3bra.org/spkp.git
(DIR) Log
(DIR) Files
(DIR) Refs
---
(DIR) commit 8c9a50a1bd58997e0cdc1b528490878aefd90de6
(DIR) parent b5c2b30267eadf2c181b68a9bc65f0d7a3e3151e
(HTM) Author: Willy Goiffon <dev@z3bra.org>
Date: Sun, 8 Nov 2020 15:51:05 +0100
Add seat and keyboard handling
Diffstat:
M compositor.c | 167 +++++++++++++++++++++++++++++++
M config.mk | 2 +-
2 files changed, 168 insertions(+), 1 deletion(-)
---
(DIR) diff --git a/compositor.c b/compositor.c
t@@ -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>
t@@ -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 */
t@@ -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;
t@@ -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 *);
t@@ -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)
t@@ -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.
t@@ -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)
{
t@@ -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)
{
t@@ -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];
t@@ -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;
t@@ -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);
t@@ -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);
(DIR) diff --git a/config.mk b/config.mk
t@@ -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