From 0b34b9f69fc547f3de5237c37ec073f3a05adcc6 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Sat, 25 Feb 2023 12:05:22 -0500 Subject: [PATCH] view: Anchor right/bottom edge only when resizing via top/left edge Currently, we anchor the right/bottom edge of the view whenever the top/ left edge is moving (current.x/y != pending.x/y). Doing so doesn't make much sense when the right/bottom edge is also moving. In that case it's probably best to move the view (or at least its top/left corner) directly to its final position. The most noticeable effect of this change is with views that don't accept their requested size exactly when tiled or maximized (examples: havoc, xfce4-terminal). Previously, their right-bottom corner would be aligned with the screen edge, leaving gaps on the left and top. Now the top-left corner will be aligned and the gaps will be on the right and bottom. This is still not ideal, but IMHO less surprising to the user. --- include/view-impl-common.h | 8 ++++++ src/view-impl-common.c | 55 ++++++++++++++++++++++++++++++++++++++ src/xdg.c | 21 +++------------ src/xwayland.c | 28 +++++++------------ 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/include/view-impl-common.h b/include/view-impl-common.h index 73f428b8..0ee5a8dc 100644 --- a/include/view-impl-common.h +++ b/include/view-impl-common.h @@ -7,8 +7,16 @@ * Please note: only xdg-shell-toplevel-view and xwayland-view view_impl * functions should call these functions. */ +struct view; void view_impl_move_to_front(struct view *view); void view_impl_map(struct view *view); +/* + * Updates view geometry at commit based on current position/size, + * pending move/resize, and committed surface size. The computed + * position may not match pending.x/y exactly in some cases. + */ +void view_impl_apply_geometry(struct view *view, int w, int h); + #endif /* __LABWC_VIEW_IMPL_COMMON_H */ diff --git a/src/view-impl-common.c b/src/view-impl-common.c index 9dee49b4..e336fa69 100644 --- a/src/view-impl-common.c +++ b/src/view-impl-common.c @@ -22,3 +22,58 @@ view_impl_map(struct view *view) view_update_title(view); view_update_app_id(view); } + +static bool +resizing_edge(struct view *view, uint32_t edge) +{ + struct server *server = view->server; + return server->input_mode == LAB_INPUT_STATE_RESIZE + && server->grabbed_view == view + && (server->resize_edges & edge); +} + +void +view_impl_apply_geometry(struct view *view, int w, int h) +{ + struct wlr_box *current = &view->current; + struct wlr_box *pending = &view->pending; + struct wlr_box old = *current; + + /* + * Anchor right edge if resizing via left edge. + * + * Note that answering the question "are we resizing?" is a bit + * tricky. The most obvious method is to look at the server + * flags; but that method will not account for any late commits + * that occur after the mouse button is released, as the client + * catches up with pending configure requests. So as a fallback, + * we resort to a geometry-based heuristic -- also not 100% + * reliable on its own. The combination of the two methods + * should catch 99% of resize cases that we care about. + */ + bool resizing_left_edge = resizing_edge(view, WLR_EDGE_LEFT); + if (resizing_left_edge || (current->x != pending->x + && current->x + current->width == + pending->x + pending->width)) { + current->x = pending->x + pending->width - w; + } else { + current->x = pending->x; + } + + /* Anchor bottom edge if resizing via top edge */ + bool resizing_top_edge = resizing_edge(view, WLR_EDGE_TOP); + if (resizing_top_edge || (current->y != pending->y + && current->y + current->height == + pending->y + pending->height)) { + current->y = pending->y + pending->height - h; + } else { + current->y = pending->y; + } + + current->width = w; + current->height = h; + + if (!wlr_box_equal(current, &old)) { + view_moved(view); + } +} diff --git a/src/xdg.c b/src/xdg.c index 82e59ced..6ab3a463 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -74,31 +74,18 @@ handle_commit(struct wl_listener *listener, void *data) wlr_xdg_surface_get_geometry(xdg_surface, &size); struct wlr_box *current = &view->current; - struct wlr_box *pending = &view->pending; - bool update_required = false; - - if (current->width != size.width || current->height != size.height) { - update_required = true; - current->width = size.width; - current->height = size.height; - } + bool update_required = current->width != size.width + || current->height != size.height; uint32_t serial = view->pending_configure_serial; if (serial > 0 && serial >= xdg_surface->current.configure_serial) { - if (current->x != pending->x) { - update_required = true; - current->x = pending->x + pending->width - size.width; - } - if (current->y != pending->y) { - update_required = true; - current->y = pending->y + pending->height - size.height; - } + update_required = true; if (serial == xdg_surface->current.configure_serial) { view->pending_configure_serial = 0; } } if (update_required) { - view_moved(view); + view_impl_apply_geometry(view, size.width, size.height); } } diff --git a/src/xwayland.c b/src/xwayland.c index 49f290d3..f688dac1 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -116,24 +116,16 @@ handle_commit(struct wl_listener *listener, void *data) /* Must receive commit signal before accessing surface->current* */ struct wlr_surface_state *state = &view->surface->current; struct wlr_box *current = &view->current; - struct wlr_box *pending = &view->pending; - if (current->width == state->width && current->height == state->height) { - return; + /* + * If there is a pending move/resize, wait until the surface + * size changes to update geometry. The hope is to update both + * the position and the size of the view at the same time, + * reducing visual glitches. + */ + if (current->width != state->width || current->height != state->height) { + view_impl_apply_geometry(view, state->width, state->height); } - - current->width = state->width; - current->height = state->height; - - if (current->x != pending->x) { - /* Adjust x for queued up configure events */ - current->x = pending->x + pending->width - current->width; - } - if (current->y != pending->y) { - /* Adjust y for queued up configure events */ - current->y = pending->y + pending->height - current->height; - } - view_moved(view); } static void @@ -143,7 +135,7 @@ handle_request_move(struct wl_listener *listener, void *data) * This event is raised when a client would like to begin an interactive * move, typically because the user clicked on their client-side * decorations. Note that a more sophisticated compositor should check - * the provied serial against a list of button press serials sent to + * the provided serial against a list of button press serials sent to * this client, to prevent the client from requesting this whenever they * want. */ @@ -158,7 +150,7 @@ handle_request_resize(struct wl_listener *listener, void *data) * This event is raised when a client would like to begin an interactive * resize, typically because the user clicked on their client-side * decorations. Note that a more sophisticated compositor should check - * the provied serial against a list of button press serials sent to + * the provided serial against a list of button press serials sent to * this client, to prevent the client from requesting this whenever they * want. */