tinywl: Fix wrong anchor point while resizing a window

Previously, when dragging the left border of a window with the mouse in tinywl,
there was a bug where it snap the top level surface's geometry X coordinate
directly to the position of the mouse, as if you started the resize right on the
border. This also affected the other (right, top and bottom) borders.

I think that the previous resize code was hard to understand. Honestly I
have not spent a lot of time trying to understand why it didn't work and
I wrote another resize algorithm instead: now, instead of working directly
with widths and heights which are complicated, we work with the borders (left,
right, top, bottom). This is easier to understand IMO.

Note: I originally fixed this [in the waybox compositor](https://github.com/wizbright/waybox/pull/23) but
then I realized that the code was taken from tinywl and that it had the same
issues so I copied my fix for tinywl.
This commit is contained in:
Greg Depoire--Ferrer 2020-04-26 17:45:45 +02:00 committed by Drew DeVault
parent 321537ee92
commit 21397e2b4a
1 changed files with 45 additions and 27 deletions

View File

@ -55,8 +55,7 @@ struct tinywl_server {
enum tinywl_cursor_mode cursor_mode; enum tinywl_cursor_mode cursor_mode;
struct tinywl_view *grabbed_view; struct tinywl_view *grabbed_view;
double grab_x, grab_y; double grab_x, grab_y;
struct wlr_box grab_geo_box; struct wlr_box grab_geobox;
int grab_width, grab_height;
uint32_t resize_edges; uint32_t resize_edges;
struct wlr_output_layout *output_layout; struct wlr_output_layout *output_layout;
@ -370,33 +369,44 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
* commit any movement that was prepared. * commit any movement that was prepared.
*/ */
struct tinywl_view *view = server->grabbed_view; struct tinywl_view *view = server->grabbed_view;
double dx = server->cursor->x - server->grab_x; double border_x = server->cursor->x - server->grab_x;
double dy = server->cursor->y - server->grab_y; double border_y = server->cursor->y - server->grab_y;
double x = view->x; int new_left = server->grab_geobox.x;
double y = view->y; int new_right = server->grab_geobox.x + server->grab_geobox.width;
int width = server->grab_width; int new_top = server->grab_geobox.y;
int height = server->grab_height; int new_bottom = server->grab_geobox.y + server->grab_geobox.height;
if (server->resize_edges & WLR_EDGE_TOP) { if (server->resize_edges & WLR_EDGE_TOP) {
y = server->grab_y + dy - server->grab_geo_box.y; new_top = border_y;
height -= dy + server->grab_geo_box.y; if (new_top >= new_bottom) {
if (height < 1) { new_top = new_bottom - 1;
y += height;
} }
} else if (server->resize_edges & WLR_EDGE_BOTTOM) { } else if (server->resize_edges & WLR_EDGE_BOTTOM) {
height += dy + server->grab_geo_box.y; new_bottom = border_y;
if (new_bottom <= new_top) {
new_bottom = new_top + 1;
}
} }
if (server->resize_edges & WLR_EDGE_LEFT) { if (server->resize_edges & WLR_EDGE_LEFT) {
x = server->grab_x + dx - server->grab_geo_box.x; new_left = border_x;
width -= dx + server->grab_geo_box.x; if (new_left >= new_right) {
if (width < 1) { new_left = new_right - 1;
x += width;
} }
} else if (server->resize_edges & WLR_EDGE_RIGHT) { } else if (server->resize_edges & WLR_EDGE_RIGHT) {
width += dx + server->grab_geo_box.x; new_right = border_x;
if (new_right <= new_left) {
new_right = new_left + 1;
} }
view->x = x; }
view->y = y;
wlr_xdg_toplevel_set_size(view->xdg_surface, width, height); struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box);
view->x = new_left - geo_box.x;
view->y = new_top - geo_box.y;
int new_width = new_right - new_left;
int new_height = new_bottom - new_top;
wlr_xdg_toplevel_set_size(view->xdg_surface, new_width, new_height);
} }
static void process_cursor_motion(struct tinywl_server *server, uint32_t time) { static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
@ -725,18 +735,26 @@ static void begin_interactive(struct tinywl_view *view,
} }
server->grabbed_view = view; server->grabbed_view = view;
server->cursor_mode = mode; server->cursor_mode = mode;
wlr_xdg_surface_get_geometry(view->xdg_surface, &server->grab_geo_box);
if (mode == TINYWL_CURSOR_MOVE) { if (mode == TINYWL_CURSOR_MOVE) {
server->grab_x = server->cursor->x - view->x; server->grab_x = server->cursor->x - view->x;
server->grab_y = server->cursor->y - view->y; server->grab_y = server->cursor->y - view->y;
} else { } else {
server->grab_x = server->cursor->x + server->grab_geo_box.x; struct wlr_box geo_box;
server->grab_y = server->cursor->y + server->grab_geo_box.y; wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box);
}
server->grab_width = server->grab_geo_box.width; double border_x = (view->x + geo_box.x) + ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
server->grab_height = server->grab_geo_box.height; double border_y = (view->y + geo_box.y) + ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
server->grab_x = server->cursor->x - border_x;
server->grab_y = server->cursor->y - border_y;
server->grab_geobox = geo_box;
server->grab_geobox.x += view->x;
server->grab_geobox.y += view->y;
server->resize_edges = edges; server->resize_edges = edges;
} }
}
static void xdg_toplevel_request_move( static void xdg_toplevel_request_move(
struct wl_listener *listener, void *data) { struct wl_listener *listener, void *data) {