edges: simplify output edge validation

This commit is contained in:
Andrew J. Hesford 2024-02-01 09:41:54 -05:00 committed by Johan Malm
parent 01af000cd1
commit b82d4783ea

View file

@ -39,17 +39,20 @@ validate_edges(struct border *valid_edges,
struct border view, struct border target, struct border view, struct border target,
struct border region, edge_validator_t validator) struct border region, edge_validator_t validator)
{ {
/* When a view snaps to a region while moving to its target, it can do /*
* When a view snaps to another while moving to its target, it can do
* so in two ways: a view edge can snap to an "opposing" edge of the * so in two ways: a view edge can snap to an "opposing" edge of the
* region (left <-> right, top <-> bottom) or to an "aligned" edge * region (left <-> right, top <-> bottom) or to an "aligned" edge
* (left <-> left, right <-> right, top <-> top, bottom <-> bottom). * (left <-> left, right <-> right, top <-> top, bottom <-> bottom).
* *
* When a view hits the opposing edge of a region, it should be * When a view hits the opposing edge of a region, it should be
* separated by a gap; when a view hits the aligned edge, it should not * separated by any configured gap and will resist *entry* into the
* be separated. The view and its target already include necessary * region; when a view hits the aligned edge, it should not be
* padding to reflect the gap. The region does not. To make sure the * separated by a gap and will resist *departure* from the region. The
* "aligned" edges are properly aligned, add padding to the region * view and its target already include necessary padding to reflect the
* borders for aligned edges only. * gap. The region does not. To make sure the "aligned" edges are
* properly aligned with respect to the configured gap, add padding to
* the region borders for aligned edges only.
*/ */
struct border region_pad = { struct border region_pad = {
@ -76,6 +79,52 @@ validate_edges(struct border *valid_edges,
region.top, region_pad.bottom, /* lesser */ false); region.top, region_pad.bottom, /* lesser */ false);
} }
static void
validate_output_edges(struct border *valid_edges,
struct border view, struct border target,
struct wlr_box usable, edge_validator_t validator)
{
/*
* When a view snaps to an output that contains it, it can be
* transformed into either of two equivalent problems:
*
* 1. The output region can be treated as if it were bounded by four
* half-planes, one sharing each edge of the view and extending
* infinitely *away* from the output. The moving view should then be
* tested as it encounters the "opposing" edge of each external region.
*
* 2. The output region can be treated as if it were composed of four
* half-planes, one sharing each edge of the view and extending
* infinitely to *overlap* the output. The moving view should then be
* tested as it encounters the "aligned" edge of each overlapping
* region.
*
* Either one of these problems can be realized by four calls to
* validate_edges with suitably defined half-plane regions, but most of
* the work in those validations will just be comparing invalid
* infinite edges.
*
* To save a bit of effort, just choose Problem 1 and directly validate
* only the non-infinite edges.
*/
/* Left edge encounters a half-infinite region to the left of the output */
validator(&valid_edges->left, view.left, target.left,
usable.x, INT_MIN, /* lesser */ true);
/* Right edge encounters a half-infinite region to the right of the output */
validator(&valid_edges->right, view.right, target.right,
usable.x + usable.width, INT_MAX, /* lesser */ false);
/* Top edge encounters a half-infinite region above the output */
validator(&valid_edges->top, view.top, target.top,
usable.y, INT_MIN, /* lesser */ true);
/* Bottom edge encounters a half-infinite region below the output */
validator(&valid_edges->bottom, view.bottom, target.bottom,
usable.y + usable.height, INT_MAX, /* lesser */ false);
}
void void
edges_find_neighbors(struct border *nearest_edges, struct view *view, edges_find_neighbors(struct border *nearest_edges, struct view *view,
struct wlr_box target, struct output *output, struct wlr_box target, struct output *output,
@ -154,57 +203,8 @@ edges_find_outputs(struct border *nearest_edges, struct view *view,
continue; continue;
} }
/* validate_output_edges(nearest_edges,
* Split a single "leaving output" problem into four "entering view_edges, target_edges, usable, validator);
* complementary region" problems, treating the view, its
* target and the screen boundaries as half planes. This
* prevents unexpected snapping behavior like the bottom of a
* window snapping above the top of an output, where it would
* become invisible.
*/
struct border screen;
struct border view_eff;
struct border target_eff;
/* First problem: view toward upper half-plane */
edges_initialize(&screen);
edges_initialize(&view_eff);
edges_initialize(&target_eff);
screen.bottom = usable.y;
view_eff.top = view_edges.top;
target_eff.top = target_edges.top;
validate_edges(nearest_edges, view_eff, target_eff, screen, validator);
/* Second problem: view toward lower half-plane */
edges_initialize(&screen);
edges_initialize(&view_eff);
edges_initialize(&target_eff);
screen.top = usable.y + usable.height;
view_eff.bottom = view_edges.bottom;
target_eff.bottom = target_edges.bottom;
validate_edges(nearest_edges, view_eff, target_eff, screen, validator);
/* Third problem: view toward left half-plane */
edges_initialize(&screen);
edges_initialize(&view_eff);
edges_initialize(&target_eff);
screen.right = usable.x;
view_eff.left = view_edges.left;
target_eff.left = target_edges.left;
validate_edges(nearest_edges, view_eff, target_eff, screen, validator);
/* Fourth problem: view toward right half-plane */
edges_initialize(&screen);
edges_initialize(&view_eff);
edges_initialize(&target_eff);
screen.left = usable.x + usable.width;
view_eff.right = view_edges.right;
target_eff.right = target_edges.right;
validate_edges(nearest_edges, view_eff, target_eff, screen, validator);
} }
} }