resistance: refactor snap constraints, use in interactive resistance

This commit is contained in:
Andrew J. Hesford 2025-07-04 15:17:35 -04:00 committed by Johan Malm
parent 3aab0c3b91
commit 476fd5f25e
4 changed files with 89 additions and 60 deletions

View file

@ -2,19 +2,21 @@
#ifndef LABWC_SNAP_CONSTRAINTS_H #ifndef LABWC_SNAP_CONSTRAINTS_H
#define LABWC_SNAP_CONSTRAINTS_H #define LABWC_SNAP_CONSTRAINTS_H
#include <wlr/util/edges.h>
#include "common/border.h" #include "common/border.h"
#include "view.h" #include "view.h"
struct wlr_box; struct wlr_box;
void snap_constraints_set(struct view *view, 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_invalidate(struct view *view);
void snap_constraints_update(struct view *view); void snap_constraints_update(struct view *view);
struct wlr_box snap_constraints_effective(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 */ #endif /* LABWC_SNAP_CONSTRAINTS_H */

View file

@ -7,6 +7,7 @@
#include "edges.h" #include "edges.h"
#include "labwc.h" #include "labwc.h"
#include "resistance.h" #include "resistance.h"
#include "snap-constraints.h"
#include "view.h" #include "view.h"
static void static void
@ -165,19 +166,30 @@ resistance_resize_apply(struct view *view, struct wlr_box *new_geom)
struct border next_edges; struct border next_edges;
edges_initialize(&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) { if (rc.screen_edge_strength != 0) {
/* Find any relevant output edges encountered by this move */ /* Find any relevant output edges encountered by this move */
edges_find_outputs(&next_edges, view, 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) { if (rc.window_edge_strength != 0) {
/* Find any relevant window edges encountered by this move */ /* 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); NULL, check_edge_window, /* ignore_hidden */ true);
} }
/* If any "best" edges were encountered during this move, snap motion */ /* If any "best" edges were encountered during this move, snap motion */
edges_adjust_resize_geom(view, next_edges, edges_adjust_resize_geom(view, next_edges,
view->server->resize_edges, new_geom, /* use_pending */ false); 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);
} }

View file

@ -37,8 +37,9 @@
static struct { static struct {
struct view *view; struct view *view;
bool pending; bool pending;
int offset; int vertical_offset;
enum view_edge direction; int horizontal_offset;
enum wlr_edges resize_edges;
struct wlr_box geom; struct wlr_box geom;
} last_snap_hit; } last_snap_hit;
@ -47,13 +48,14 @@ snap_constraints_reset(void)
{ {
last_snap_hit.view = NULL; last_snap_hit.view = NULL;
last_snap_hit.pending = false; last_snap_hit.pending = false;
last_snap_hit.offset = INT_MIN; last_snap_hit.horizontal_offset = INT_MIN;
last_snap_hit.direction = VIEW_EDGE_INVALID; 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)); memset(&last_snap_hit.geom, 0, sizeof(last_snap_hit.geom));
} }
static bool 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); assert(view);
@ -62,53 +64,61 @@ snap_constraints_are_valid(struct view *view, enum view_edge direction)
return false; return false;
} }
/* Cache is not valid if direction has changed */ /* Cache is not valid if expected edges do not match */
if (direction != last_snap_hit.direction) { if (resize_edges != last_snap_hit.resize_edges) {
return false; return false;
} }
/* Cache is not valid if offset is unbounded */ /* Cache is not valid if edge offsets are invalid */
if (!BOUNDED_INT(last_snap_hit.offset)) { if (resize_edges & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
if (!BOUNDED_INT(last_snap_hit.horizontal_offset)) {
return false; return false;
} }
/* Cache is valid iff pending view geometry matches expectation */ 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 view geometry matches expectation */
return wlr_box_equal(&view->pending, &last_snap_hit.geom); return wlr_box_equal(&view->pending, &last_snap_hit.geom);
} }
void void
snap_constraints_set(struct view *view, 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); assert(view);
int offset = INT_MIN; /* Set horizontal offset when resizing horizontal edges */
switch (direction) { last_snap_hit.horizontal_offset = INT_MIN;
case VIEW_EDGE_LEFT: if (resize_edges & WLR_EDGE_LEFT) {
offset = geom.x; last_snap_hit.horizontal_offset = geom.x;
break; } else if (resize_edges & WLR_EDGE_RIGHT) {
case VIEW_EDGE_RIGHT: last_snap_hit.horizontal_offset = geom.x + geom.width;
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;
} }
if (!BOUNDED_INT(offset)) { /* Set vertical offset when resizing vertical edges */
snap_constraints_reset(); last_snap_hit.vertical_offset = INT_MIN;
return; 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 */ /* Capture the current geometry and effective snapped edge */
last_snap_hit.view = view; last_snap_hit.view = view;
last_snap_hit.offset = offset; last_snap_hit.resize_edges = resize_edges;
last_snap_hit.direction = direction;
last_snap_hit.geom = geom; last_snap_hit.geom = geom;
/* /*
@ -152,37 +162,40 @@ snap_constraints_update(struct view *view)
} }
struct wlr_box 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); assert(view);
struct wlr_box real_geom = use_pending ? view->pending : view->current;
/* Use actual geometry when constraints do not apply */ /* Use actual geometry when constraints do not apply */
if (!snap_constraints_are_valid(view, direction)) { if (!snap_constraints_are_valid(view, resize_edges)) {
return view->pending; return real_geom;
} }
/* Override changing edge with constrained value */ /* Override changing edge with constrained value */
struct wlr_box geom = view->pending; struct wlr_box geom = real_geom;
switch (last_snap_hit.direction) {
case VIEW_EDGE_LEFT: if (resize_edges & WLR_EDGE_LEFT) {
geom.x = last_snap_hit.offset; geom.x = last_snap_hit.horizontal_offset;
break; } else if (resize_edges & WLR_EDGE_RIGHT) {
case VIEW_EDGE_RIGHT: geom.width = last_snap_hit.horizontal_offset - geom.x;
geom.width = last_snap_hit.offset - geom.x; }
break;
case VIEW_EDGE_UP: if (resize_edges & WLR_EDGE_TOP) {
geom.y = last_snap_hit.offset; geom.y = last_snap_hit.vertical_offset;
break; } else if (resize_edges & WLR_EDGE_BOTTOM) {
case VIEW_EDGE_DOWN: geom.height = last_snap_hit.vertical_offset - geom.y;
geom.height = last_snap_hit.offset - geom.y;
break;
default:
return view->pending;
} }
/* Fall back to actual geometry when constrained geometry is nonsense */ /* 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) { if (geom.width <= 0 || geom.height <= 0) {
return view->pending; return real_geom;
} }
return geom; return geom;

View file

@ -195,7 +195,8 @@ snap_grow_to_next_edge(struct view *view,
edges_initialize(&next_edges); edges_initialize(&next_edges);
/* Use a constrained, effective geometry for snapping if appropriate */ /* 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 */ /* Limit motion to any intervening edge of other views on this output */
edges_find_neighbors(&next_edges, view, origin, *geo, 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 * Record effective geometry after snapping in case the client opts to
* ignore or modify the configured geometry * ignore or modify the configured geometry
*/ */
snap_constraints_set(view, direction, *geo); snap_constraints_set(view, resize_edges, *geo);
} }
void void
@ -261,7 +262,8 @@ snap_shrink_to_next_edge(struct view *view,
edges_initialize(&next_edges); edges_initialize(&next_edges);
/* Use a constrained, effective geometry for snapping if appropriate */ /* 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 */ /* Snap to output edges if the moving edge started off-screen */
edges_find_outputs(&next_edges, view, 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 * Record effective geometry after snapping in case the client opts to
* ignore or modify the configured geometry * ignore or modify the configured geometry
*/ */
snap_constraints_set(view, direction, *geo); snap_constraints_set(view, resize_edges, *geo);
} }