tinywl: stabilize resize from top-left edges

When resizing from the left or top edges, wait until the client
commits its resized buffer before updating the scene node position.

This keeps the unmoved edge anchored to the committed geometry instead
of the requested configure size.

This fixes visible jitter when resizing weston-terminal with the mouse
from the top-left corner, where the terminal can quantize its size and
otherwise cause the window position to oscillate during interactive resize.
This commit is contained in:
YaoBing Xiao 2026-06-06 16:36:52 +08:00
parent a94cd29eb1
commit 42f615fe60
No known key found for this signature in database
GPG key ID: E53D050E0BA828D3

View file

@ -399,6 +399,30 @@ static void process_cursor_move(struct tinywl_server *server) {
server->cursor->y - server->grab_y); server->cursor->y - server->grab_y);
} }
static void update_resize_position(struct tinywl_toplevel *toplevel) {
struct tinywl_server *server = toplevel->server;
if (server->cursor_mode != TINYWL_CURSOR_RESIZE ||
server->grabbed_toplevel != toplevel) {
return;
}
struct wlr_box *geo_box = &toplevel->xdg_toplevel->base->geometry;
int lx = server->grab_geobox.x;
int ly = server->grab_geobox.y;
if (server->resize_edges & WLR_EDGE_LEFT) {
lx = server->grab_geobox.x + server->grab_geobox.width -
geo_box->width;
}
if (server->resize_edges & WLR_EDGE_TOP) {
ly = server->grab_geobox.y + server->grab_geobox.height -
geo_box->height;
}
wlr_scene_node_set_position(&toplevel->scene_tree->node,
lx - geo_box->x, ly - geo_box->y);
}
static void process_cursor_resize(struct tinywl_server *server) { static void process_cursor_resize(struct tinywl_server *server) {
/* /*
* Resizing the grabbed toplevel can be a little bit complicated, because we * Resizing the grabbed toplevel can be a little bit complicated, because we
@ -406,9 +430,8 @@ static void process_cursor_resize(struct tinywl_server *server) {
* toplevel on one or two axes, but can also move the toplevel if you resize * toplevel on one or two axes, but can also move the toplevel if you resize
* from the top or left edges (or top-left corner). * from the top or left edges (or top-left corner).
* *
* Note that some shortcuts are taken here. In a more fleshed-out * Movement is applied on commit so that surfaces which quantize their size
* compositor, you'd wait for the client to prepare a buffer at the new * can keep the unmoved edge stable.
* size, then commit any movement that was prepared.
*/ */
struct tinywl_toplevel *toplevel = server->grabbed_toplevel; struct tinywl_toplevel *toplevel = server->grabbed_toplevel;
double border_x = server->cursor->x - server->grab_x; double border_x = server->cursor->x - server->grab_x;
@ -441,10 +464,6 @@ static void process_cursor_resize(struct tinywl_server *server) {
} }
} }
struct wlr_box *geo_box = &toplevel->xdg_toplevel->base->geometry;
wlr_scene_node_set_position(&toplevel->scene_tree->node,
new_left - geo_box->x, new_top - geo_box->y);
int new_width = new_right - new_left; int new_width = new_right - new_left;
int new_height = new_bottom - new_top; int new_height = new_bottom - new_top;
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height); wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
@ -701,7 +720,10 @@ static void xdg_toplevel_commit(struct wl_listener *listener, void *data) {
* configures the xdg_toplevel with 0,0 size to let the client pick the * configures the xdg_toplevel with 0,0 size to let the client pick the
* dimensions itself. */ * dimensions itself. */
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, 0, 0); wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, 0, 0);
return;
} }
update_resize_position(toplevel);
} }
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {