spkp

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

commit 6b5e9460e54665f88a08f4b026a97d41ece948f6
parent 9f817e64de62b1853ef5d79737d0ea9a013764c3
Author: Willy Goiffon <dev@z3bra.org>
Date:   Tue, 10 Nov 2020 11:30:36 +0100

Add topmost surface attributes to the window

When checking which window is underneath the pointer, we also have the
information of the topmost surface pertaining to this window, and the
cursor position within that surface.

By saving these attributes in the window structure, we save multiple
calls to wlr_xdg_surface_surface_at() to retrieve the surface when trying
to give pointer focus to a window.

This also makes the focus() function much more simple, as the window
structure now contains all the informations needed for focusing logic.

Diffstat:
Mcompositor.c | 93+++++++++++++++++++++++++++++--------------------------------------------------
1 file changed, 34 insertions(+), 59 deletions(-)

diff --git a/compositor.c b/compositor.c @@ -82,8 +82,13 @@ struct output { /* Client surface window */ struct window { struct state *server; - struct wlr_xdg_surface *surface; - int mapped, x, y; + struct wlr_xdg_surface *toplevel; + double x, y; + + int mapped; + + struct wlr_surface *topmost; + double sx, sy; struct wl_listener map; struct wl_listener unmap; @@ -156,10 +161,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 void focus(struct window *, struct wlr_surface *); +static void focus(struct window *); static int keybinding(struct state *, uint32_t, uint32_t); static struct window *underneath(struct state *, double, double); -static struct wlr_surface *topsurface(struct window *, double, double, double *, double *); /* keybinding functions, see config.h */ static void kb_terminate(struct state *, union keyarg *); @@ -311,7 +315,7 @@ cb_frame_output(struct wl_listener *listener, void *data) rdata.window = window; rdata.renderer = renderer; clock_gettime(CLOCK_MONOTONIC, &rdata.when); - wlr_xdg_surface_for_each_surface(window->surface, render, &rdata); + wlr_xdg_surface_for_each_surface(window->toplevel, render, &rdata); } /* render cursor by software in case the GPU doesn't handle it */ @@ -345,7 +349,7 @@ cb_new_window(struct wl_listener *listener, void *data) window = calloc(1, sizeof(*window)); window->server = server; - window->surface = surface; + window->toplevel = surface; window->x = 0; window->y = 0; @@ -375,7 +379,7 @@ cb_map_window(struct wl_listener *listener, void *data) w = wl_container_of(listener, w, map); w->mapped = 1; - focus(w, w->surface->surface); + focus(w); } /* @@ -483,10 +487,8 @@ cb_req_cursor(struct wl_listener *listener, void *data) void cb_motion(struct state *server, uint32_t time) { - double x, y, sx, sy; struct window *w; struct wlr_seat *seat; - struct wlr_surface *surface; seat = server->seat; @@ -495,16 +497,16 @@ cb_motion(struct state *server, uint32_t time) struct wlr_box geom; switch(server->grabmode) { case MOVE: - wlr_xdg_surface_get_geometry(w->surface, &geom); + wlr_xdg_surface_get_geometry(w->toplevel, &geom); w->x = server->cursor->x - geom.width/2; w->y = server->cursor->y - geom.height/2; return; /* NOTREACHED */; break; case RESIZE: - wlr_xdg_surface_get_geometry(w->surface, &geom); + wlr_xdg_surface_get_geometry(w->toplevel, &geom); geom.width = server->cursor->x - w->x; geom.height = server->cursor->y - w->y; - wlr_xdg_toplevel_set_size(w->surface, geom.width, geom.height); + wlr_xdg_toplevel_set_size(w->toplevel, geom.width, geom.height); return; /* NOTREACHED */; break; } @@ -521,18 +523,14 @@ cb_motion(struct state *server, uint32_t time) return; } - x = server->cursor->x - w->x; - y = server->cursor->y - w->y; - surface = topsurface(w, x, y, &sx, &sy); - - if (surface) { - if (seat->pointer_state.focused_surface == surface) - wlr_seat_pointer_notify_motion(seat, time, sx, sy); + if (w->topmost) { + if (seat->pointer_state.focused_surface == w->topmost) + wlr_seat_pointer_notify_motion(seat, time, w->sx, w->sy); else - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_enter(seat, w->topmost, w->sx, w->sy); } - focus(w, w->surface->surface); + focus(w); } /* @@ -579,11 +577,9 @@ cb_motion_absolute(struct wl_listener *listener, void *data) void cb_click(struct wl_listener *listener, void *data) { - double x, y, sx, sy; struct state *server; struct wlr_event_pointer_button *ev; struct window *w; - struct wlr_surface *surface; struct wlr_keyboard *kb; server = wl_container_of(listener, server, click); @@ -620,14 +616,9 @@ cb_click(struct wl_listener *listener, void *data) wl_list_remove(&w->link); wl_list_insert(&server->windows, &w->link); - x = server->cursor->x - w->x; - y = server->cursor->y - w->y; - surface = topsurface(w, x, y, &sx, &sy); + wlr_seat_pointer_notify_enter(server->seat, w->topmost, w->sx, w->sy); - if (surface) - wlr_seat_pointer_notify_enter(server->seat, surface, sx, sy); - - focus(w, surface); + focus(w); } /* @@ -744,7 +735,7 @@ render(struct wlr_surface *surface, int x, int y, void *data) * Set keyboard focus on the given top-level window. */ void -focus(struct window *window, struct wlr_surface *surface) +focus(struct window *window) { struct state *server; struct wlr_seat *seat; @@ -757,7 +748,8 @@ focus(struct window *window, struct wlr_surface *surface) kb = wlr_seat_get_keyboard(seat); focus = seat->keyboard_state.focused_surface; - if (focus == surface) + /* skip if window is already focused */ + if (focus == window->topmost) return; /* deactivate currently focused window */ @@ -766,9 +758,8 @@ focus(struct window *window, struct wlr_surface *surface) wlr_xdg_toplevel_set_activated(toplevel, false); } - /* keyboard + pointer focus */ - toplevel = window->surface; - wlr_seat_keyboard_notify_enter(seat, toplevel->surface, + /* give keyboard focus to the toplevel window */ + wlr_seat_keyboard_notify_enter(seat, window->toplevel->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); } @@ -792,14 +783,16 @@ keybinding(struct state *server, uint32_t mod, uint32_t key) } /* - * Return the topmost window pointer at the given position. + * Returns a pointer to the toplevel window at the given position. + * If a toplevel window is found, the topmost surface pertaining to this + * toplevel window will be saved, as well as the pointer coordinates + * relative to that surface. + * These informations are needed to relay pointer events to the window. */ 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) { /* @@ -812,10 +805,10 @@ underneath(struct state *server, double x, double y) * 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); + w->topmost = wlr_xdg_surface_surface_at(w->toplevel, + x - w->x, y - w->y, &w->sx, &w->sy); - if (surface) + if (w->topmost) return w; } @@ -823,24 +816,6 @@ underneath(struct state *server, double x, double y) } /* - * Return the topmost wlr_surface at the given position. - * The x, y coordinates relative to that surface are also returned if - * a pointer to sx, sy is given. - * This function is mostly used to relay pointer events to and underlying - * surface. - */ -struct wlr_surface * -topsurface(struct window *window, double x, double y, double *sx, double *sy) -{ - struct wlr_surface *surface; - - surface = wlr_xdg_surface_surface_at(window->surface, - x - window->x, y - window->y, sx, sy); - - return surface; -} - -/* * Keybind: Terminate the wayland compositor */ void kb_terminate(struct state *server, union keyarg *arg)