]> git.mdlowis.com Git - proto/labwc.git/commitdiff
resistance: refactor snap constraints, use in interactive resistance
authorAndrew J. Hesford <ajh@sideband.org>
Fri, 4 Jul 2025 19:17:35 +0000 (15:17 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sun, 6 Jul 2025 17:45:21 +0000 (18:45 +0100)
include/snap-constraints.h
src/resistance.c
src/snap-constraints.c
src/snap.c

index 294c53b6787e65266dc023aaf66b1b3b82fa13f1..8ad32a1b5c6fe9e9d05a4258e7bb84ec0f5ac838 100644 (file)
@@ -2,19 +2,21 @@
 #ifndef LABWC_SNAP_CONSTRAINTS_H
 #define LABWC_SNAP_CONSTRAINTS_H
 
+#include <wlr/util/edges.h>
+
 #include "common/border.h"
 #include "view.h"
 
 struct wlr_box;
 
 void snap_constraints_set(struct view *view,
-       enum view_edge direction, struct wlr_box geom);
+       enum wlr_edges direction, struct wlr_box geom);
 
 void snap_constraints_invalidate(struct view *view);
 
 void snap_constraints_update(struct view *view);
 
 struct wlr_box snap_constraints_effective(struct view *view,
-       enum view_edge direction);
+       enum wlr_edges direction, bool use_pending);
 
 #endif /* LABWC_SNAP_CONSTRAINTS_H */
index a20f3b3c105697bf5e8280b8fddeda7dd24ce3e3..d8eb29813723ac9ccb4703988783397002d84e06 100644 (file)
@@ -7,6 +7,7 @@
 #include "edges.h"
 #include "labwc.h"
 #include "resistance.h"
+#include "snap-constraints.h"
 #include "view.h"
 
 static void
@@ -165,19 +166,30 @@ resistance_resize_apply(struct view *view, struct wlr_box *new_geom)
        struct border next_edges;
        edges_initialize(&next_edges);
 
+       /* Use a constrained, effective geometry for snapping if appropriate */
+       enum wlr_edges resize_edges = view->server->resize_edges;
+       struct wlr_box origin =
+               snap_constraints_effective(view, resize_edges, /* use_pending */ false);
+
        if (rc.screen_edge_strength != 0) {
                /* Find any relevant output edges encountered by this move */
                edges_find_outputs(&next_edges, view,
-                       view->current, *new_geom, NULL, check_edge_output);
+                       origin, *new_geom, NULL, check_edge_output);
        }
 
        if (rc.window_edge_strength != 0) {
                /* Find any relevant window edges encountered by this move */
-               edges_find_neighbors(&next_edges, view, view->current, *new_geom,
+               edges_find_neighbors(&next_edges, view, origin, *new_geom,
                        NULL, check_edge_window, /* ignore_hidden */ true);
        }
 
        /* If any "best" edges were encountered during this move, snap motion */
        edges_adjust_resize_geom(view, next_edges,
                view->server->resize_edges, new_geom, /* use_pending */ false);
+
+       /*
+        * Record effective geometry after snapping in case the client opts to
+        * ignore or modify the configured geometry
+        */
+       snap_constraints_set(view, resize_edges, *new_geom);
 }
index 7171c53a843b211d00715aca616cc5b0c4b5e56b..24fe803c91bb6ff188595a1b1cbc9d2e510105c6 100644 (file)
@@ -37,8 +37,9 @@
 static struct {
        struct view *view;
        bool pending;
-       int offset;
-       enum view_edge direction;
+       int vertical_offset;
+       int horizontal_offset;
+       enum wlr_edges resize_edges;
        struct wlr_box geom;
 } last_snap_hit;
 
@@ -47,13 +48,14 @@ snap_constraints_reset(void)
 {
        last_snap_hit.view = NULL;
        last_snap_hit.pending = false;
-       last_snap_hit.offset = INT_MIN;
-       last_snap_hit.direction = VIEW_EDGE_INVALID;
+       last_snap_hit.horizontal_offset = INT_MIN;
+       last_snap_hit.vertical_offset = INT_MIN;
+       last_snap_hit.resize_edges = WLR_EDGE_NONE;
        memset(&last_snap_hit.geom, 0, sizeof(last_snap_hit.geom));
 }
 
 static bool
-snap_constraints_are_valid(struct view *view, enum view_edge direction)
+snap_constraints_are_valid(struct view *view, enum wlr_edges resize_edges)
 {
        assert(view);
 
@@ -62,53 +64,61 @@ snap_constraints_are_valid(struct view *view, enum view_edge direction)
                return false;
        }
 
-       /* Cache is not valid if direction has changed */
-       if (direction != last_snap_hit.direction) {
+       /* Cache is not valid if expected edges do not match */
+       if (resize_edges != last_snap_hit.resize_edges) {
                return false;
        }
 
-       /* Cache is not valid if offset is unbounded */
-       if (!BOUNDED_INT(last_snap_hit.offset)) {
+       /* Cache is not valid if edge offsets are invalid */
+       if (resize_edges & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
+               if (!BOUNDED_INT(last_snap_hit.horizontal_offset)) {
+                       return false;
+               }
+
+               if ((resize_edges & WLR_EDGE_LEFT) && (resize_edges & WLR_EDGE_RIGHT)) {
+                       return false;
+               }
+       } else if (resize_edges & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) {
+               if (!BOUNDED_INT(last_snap_hit.vertical_offset)) {
+                       return false;
+               }
+
+               if ((resize_edges & WLR_EDGE_TOP) && (resize_edges & WLR_EDGE_BOTTOM)) {
+                       return false;
+               }
+       } else {
                return false;
        }
 
-       /* Cache is valid iff pending view geometry matches expectation */
+       /* Cache is valid iff view geometry matches expectation */
        return wlr_box_equal(&view->pending, &last_snap_hit.geom);
 }
 
 void
 snap_constraints_set(struct view *view,
-               enum view_edge direction, struct wlr_box geom)
+               enum wlr_edges resize_edges, struct wlr_box geom)
 {
        assert(view);
 
-       int offset = INT_MIN;
-       switch (direction) {
-       case VIEW_EDGE_LEFT:
-               offset = geom.x;
-               break;
-       case VIEW_EDGE_RIGHT:
-               offset = geom.x + geom.width;
-               break;
-       case VIEW_EDGE_UP:
-               offset = geom.y;
-               break;
-       case VIEW_EDGE_DOWN:
-               offset = geom.y + geom.height;
-               break;
-       default:
-               break;
+       /* Set horizontal offset when resizing horizontal edges */
+       last_snap_hit.horizontal_offset = INT_MIN;
+       if (resize_edges & WLR_EDGE_LEFT) {
+               last_snap_hit.horizontal_offset = geom.x;
+       } else if (resize_edges & WLR_EDGE_RIGHT) {
+               last_snap_hit.horizontal_offset = geom.x + geom.width;
        }
 
-       if (!BOUNDED_INT(offset)) {
-               snap_constraints_reset();
-               return;
+       /* Set vertical offset when resizing vertical edges */
+       last_snap_hit.vertical_offset = INT_MIN;
+       if (resize_edges & WLR_EDGE_TOP) {
+               last_snap_hit.vertical_offset = geom.y;
+       } else if (resize_edges & WLR_EDGE_BOTTOM) {
+               last_snap_hit.vertical_offset = geom.y + geom.height;
        }
 
        /* Capture the current geometry and effective snapped edge */
        last_snap_hit.view = view;
-       last_snap_hit.offset = offset;
-       last_snap_hit.direction = direction;
+       last_snap_hit.resize_edges = resize_edges;
        last_snap_hit.geom = geom;
 
        /*
@@ -152,37 +162,40 @@ snap_constraints_update(struct view *view)
 }
 
 struct wlr_box
-snap_constraints_effective(struct view *view, enum view_edge direction)
+snap_constraints_effective(struct view *view,
+               enum wlr_edges resize_edges, bool use_pending)
 {
        assert(view);
 
+       struct wlr_box real_geom = use_pending ? view->pending : view->current;
+
        /* Use actual geometry when constraints do not apply */
-       if (!snap_constraints_are_valid(view, direction)) {
-               return view->pending;
+       if (!snap_constraints_are_valid(view, resize_edges)) {
+               return real_geom;
        }
 
        /* Override changing edge with constrained value */
-       struct wlr_box geom = view->pending;
-       switch (last_snap_hit.direction) {
-       case VIEW_EDGE_LEFT:
-               geom.x = last_snap_hit.offset;
-               break;
-       case VIEW_EDGE_RIGHT:
-               geom.width = last_snap_hit.offset - geom.x;
-               break;
-       case VIEW_EDGE_UP:
-               geom.y = last_snap_hit.offset;
-               break;
-       case VIEW_EDGE_DOWN:
-               geom.height = last_snap_hit.offset - geom.y;
-               break;
-       default:
-               return view->pending;
+       struct wlr_box geom = real_geom;
+
+       if (resize_edges & WLR_EDGE_LEFT) {
+               geom.x = last_snap_hit.horizontal_offset;
+       } else if (resize_edges & WLR_EDGE_RIGHT) {
+               geom.width = last_snap_hit.horizontal_offset - geom.x;
+       }
+
+       if (resize_edges & WLR_EDGE_TOP) {
+               geom.y = last_snap_hit.vertical_offset;
+       } else if (resize_edges & WLR_EDGE_BOTTOM) {
+               geom.height = last_snap_hit.vertical_offset - geom.y;
        }
 
        /* Fall back to actual geometry when constrained geometry is nonsense */
+       if (!BOUNDED_INT(geom.x) || !BOUNDED_INT(geom.y)) {
+               return real_geom;
+       }
+
        if (geom.width <= 0 || geom.height <= 0) {
-               return view->pending;
+               return real_geom;
        }
 
        return geom;
index f2e799656f5f1220de1ed2ef4cfa4dcc027f0d82..228572fa5bace6dcb267e95320cf4b48bf21eea8 100644 (file)
@@ -195,7 +195,8 @@ snap_grow_to_next_edge(struct view *view,
        edges_initialize(&next_edges);
 
        /* Use a constrained, effective geometry for snapping if appropriate */
-       struct wlr_box origin = snap_constraints_effective(view, direction);
+       struct wlr_box origin =
+               snap_constraints_effective(view, resize_edges, /* use_pending */ true);
 
        /* Limit motion to any intervening edge of other views on this output */
        edges_find_neighbors(&next_edges, view, origin, *geo,
@@ -208,7 +209,7 @@ snap_grow_to_next_edge(struct view *view,
         * Record effective geometry after snapping in case the client opts to
         * ignore or modify the configured geometry
         */
-       snap_constraints_set(view, direction, *geo);
+       snap_constraints_set(view, resize_edges, *geo);
 }
 
 void
@@ -261,7 +262,8 @@ snap_shrink_to_next_edge(struct view *view,
        edges_initialize(&next_edges);
 
        /* Use a constrained, effective geometry for snapping if appropriate */
-       struct wlr_box origin = snap_constraints_effective(view, direction);
+       struct wlr_box origin =
+               snap_constraints_effective(view, resize_edges, /* use_pending */ true);
 
        /* Snap to output edges if the moving edge started off-screen */
        edges_find_outputs(&next_edges, view,
@@ -278,5 +280,5 @@ snap_shrink_to_next_edge(struct view *view,
         * Record effective geometry after snapping in case the client opts to
         * ignore or modify the configured geometry
         */
-       snap_constraints_set(view, direction, *geo);
+       snap_constraints_set(view, resize_edges, *geo);
 }