spkp

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

commit 5367b98d9a0350d5a77dcedae2bc48f8e24bb6a5
parent 79437cc17ee546a1c4f0215ac2f377b6cd2d8e71
Author: Willy Goiffon <dev@z3bra.org>
Date:   Mon,  9 Nov 2020 14:44:35 +0100

Refactor window focus event handling

- Pointer focus is set when the pointer enter a window
- Keyboard focus is set when clicking inside a window

Keyboard focus remains on a window until it is set somewhere else,
while pointer focus is only set when the pointer is above the window.

Diffstat:
Mcompositor.c | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 96 insertions(+), 14 deletions(-)

diff --git a/compositor.c b/compositor.c @@ -127,7 +127,9 @@ static void cb_paint_cursor(struct wl_listener *, void *); static void add_keyboard(struct state *, struct wlr_input_device *); static void add_pointer(struct state *, struct wlr_input_device *); static void render(struct wlr_surface *, int, int, void *); -static int keybinding(struct state *, uint32_t, uint32_t); +static void focus(struct window *, struct wlr_surface *); +static int keybinding(struct state *, uint32_t, uint32_t); +static struct window *underneath(struct state *, double, double); void usage(char *pgm) @@ -303,6 +305,10 @@ cb_new_window(struct wl_listener *listener, void *data) window->server = server; window->surface = surface; + window->x = 0; + window->y = 0; + window->mapped = 0; + window->map.notify = cb_map_window; window->unmap.notify = cb_unmap_window; window->destroy.notify = cb_destroy_window; @@ -322,25 +328,13 @@ void cb_map_window(struct wl_listener *listener, void *data) { struct window *w; - struct state *server; - struct wlr_keyboard *kb; (void)data; 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); - - wlr_seat_pointer_notify_enter(server->seat, w->surface->surface, - server->cursor->x, server->cursor->y); + focus(w, w->surface->surface); } /* @@ -439,35 +433,63 @@ void cb_motion(struct wl_listener *listener, void *data) { struct state *server; struct wlr_event_pointer_motion *ev; + struct window *w; server = wl_container_of(listener, server, motion); ev = data; wlr_cursor_move(server->cursor, ev->device, ev->delta_x, ev->delta_y); wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, "left_ptr", server->cursor); + + /* activate underneath window, if any */ + if ((w = underneath(server, server->cursor->x, server->cursor->y))) { + focus(w, w->surface->surface); + } else { + wlr_seat_pointer_clear_focus(server->seat); + } + } void cb_motion_absolute(struct wl_listener *listener, void *data) { struct state *server; struct wlr_event_pointer_motion_absolute *ev; + struct window *w; server = wl_container_of(listener, server, motion_absolute); ev = data; wlr_cursor_warp_absolute(server->cursor, ev->device, ev->x, ev->y); wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, "left_ptr", server->cursor); + + if ((w = underneath(server, server->cursor->x, server->cursor->y))) { + focus(w, w->surface->surface); + } else { + wlr_seat_pointer_clear_focus(server->seat); + } } void cb_click(struct wl_listener *listener, void *data) { struct state *server; struct wlr_event_pointer_button *ev; + struct window *w; server = wl_container_of(listener, server, click); ev = data; wlr_seat_pointer_notify_button(server->seat, ev->time_msec, ev->button, ev->state); + + if ((w = underneath(server, server->cursor->x, server->cursor->y))) { + /* reinsert window on top of the stack */ + wl_list_remove(&w->link); + wl_list_insert(&server->windows, &w->link); + + focus(w, w->surface->surface); + } else { + wlr_seat_pointer_clear_focus(server->seat); + } + } void cb_scroll(struct wl_listener *listener, void *data) @@ -566,6 +588,38 @@ render(struct wlr_surface *surface, int x, int y, void *data) wlr_surface_send_frame_done(surface, &rdata->when); } +/* + * Set keyboard focus on the given top-level window + */ +void +focus(struct window *window, struct wlr_surface *surface) +{ + struct state *server; + struct wlr_seat *seat; + struct wlr_keyboard *kb; + struct wlr_surface *focus; + struct wlr_xdg_surface *toplevel; + + server = window->server; + seat = server->seat; + kb = wlr_seat_get_keyboard(seat); + focus = seat->keyboard_state.focused_surface; + + if (focus == surface) + return; + + /* deactivate currently focused window */ + if (focus) { + toplevel = wlr_xdg_surface_from_wlr_surface(focus); + wlr_xdg_toplevel_set_activated(toplevel, false); + } + + /* keyboard + pointer focus */ + toplevel = window->surface; + wlr_seat_keyboard_notify_enter(seat, toplevel->surface, + kb->keycodes, kb->num_keycodes, &kb->modifiers); +} + int keybinding(struct state *server, uint32_t mod, uint32_t key) { @@ -581,6 +635,34 @@ keybinding(struct state *server, uint32_t mod, uint32_t key) return 0; } +struct window * +underneath(struct state *server, double x, double y) +{ + double sx, sy; + struct window *w; + struct wlr_surface *surface; + + wl_list_for_each(w, &server->windows, link) { + /* + * retrieve the subsurface at the given coordinates. + * coordinates are given relatively to the top level + * window coordinates on the output. Subsurfaces can + * however exist outside the bounds of the top level + * window, and thus have negative coordinates for example + * + * sx, sy will be updated with the pointer coordinates + * within the subsurface (always positive). + */ + surface = wlr_xdg_surface_surface_at(w->surface, + x - w->x, y - w->y, &sx, &sy); + + if (surface) + return w; + } + + return NULL; +} + int main(int argc, char *argv[]) {