]> git.mdlowis.com Git - proto/labwc.git/commitdiff
view: Anchor right/bottom edge only when resizing via top/left edge
authorJohn Lindgren <john@jlindgren.net>
Sat, 25 Feb 2023 17:05:22 +0000 (12:05 -0500)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sun, 5 Mar 2023 08:46:55 +0000 (08:46 +0000)
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
src/view-impl-common.c
src/xdg.c
src/xwayland.c

index 73f428b86f78b7363b78832284617b9f4377850e..0ee5a8dc7b3af936eb4dfde3bd22527a709bb8c7 100644 (file)
@@ -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 */
index 9dee49b43b92249cd23efc73453e74a57ea8b30c..e336fa6959616a2b1aa2a8cecae45ba220508d71 100644 (file)
@@ -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);
+       }
+}
index 82e59cedbf73bf662b3eb98549912c4ebfa6f7eb..6ab3a46373424af941e46b4cb7129d284ea14838 100644 (file)
--- 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);
        }
 }
 
index 49f290d3542085648395bb24263d89fdbc4eeb0c..f688dac1231a64f0d46ea39383e578f3103ad158 100644 (file)
@@ -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;
-       }
-
-       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;
+       /*
+        * 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);
        }
-       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.
         */