From 476fd5f25e7ff0149214018d7c2d699df2dd2ca1 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Fri, 4 Jul 2025 15:17:35 -0400 Subject: [PATCH] resistance: refactor snap constraints, use in interactive resistance --- include/snap-constraints.h | 6 +- src/resistance.c | 16 ++++- src/snap-constraints.c | 117 ++++++++++++++++++++----------------- src/snap.c | 10 ++-- 4 files changed, 89 insertions(+), 60 deletions(-) diff --git a/include/snap-constraints.h b/include/snap-constraints.h index 294c53b6..8ad32a1b 100644 --- a/include/snap-constraints.h +++ b/include/snap-constraints.h @@ -2,19 +2,21 @@ #ifndef LABWC_SNAP_CONSTRAINTS_H #define LABWC_SNAP_CONSTRAINTS_H +#include + #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 */ diff --git a/src/resistance.c b/src/resistance.c index a20f3b3c..d8eb2981 100644 --- a/src/resistance.c +++ b/src/resistance.c @@ -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); } diff --git a/src/snap-constraints.c b/src/snap-constraints.c index 7171c53a..24fe803c 100644 --- a/src/snap-constraints.c +++ b/src/snap-constraints.c @@ -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; diff --git a/src/snap.c b/src/snap.c index f2e79965..228572fa 100644 --- a/src/snap.c +++ b/src/snap.c @@ -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); } -- 2.52.0