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