2021-10-24 21:31:05 -04:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2024-01-20 21:59:46 -05:00
|
|
|
#include <assert.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include "common/border.h"
|
|
|
|
|
#include "common/macros.h"
|
2021-10-23 22:31:39 -04:00
|
|
|
#include "config/rcxml.h"
|
2024-01-23 13:44:40 -05:00
|
|
|
#include "edges.h"
|
2022-11-21 10:10:39 -05:00
|
|
|
#include "labwc.h"
|
2023-01-31 03:35:13 +01:00
|
|
|
#include "resistance.h"
|
2022-11-21 10:10:39 -05:00
|
|
|
#include "view.h"
|
2021-10-23 22:31:39 -04:00
|
|
|
|
2021-10-24 21:14:05 -04:00
|
|
|
static void
|
2024-02-02 14:43:52 -05:00
|
|
|
check_edge(int *next, struct edge current, struct edge target,
|
|
|
|
|
struct edge oppose, struct edge align, int tolerance)
|
2021-10-24 21:14:05 -04:00
|
|
|
{
|
2024-02-02 14:43:52 -05:00
|
|
|
int cur = current.offset;
|
|
|
|
|
int tgt = target.offset;
|
|
|
|
|
int opp = oppose.offset;
|
|
|
|
|
int aln = align.offset;
|
|
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
/* Ignore non-moving edges */
|
2024-02-02 14:43:52 -05:00
|
|
|
if (cur == tgt) {
|
2024-01-23 13:44:40 -05:00
|
|
|
return;
|
2024-01-21 12:56:37 -05:00
|
|
|
}
|
|
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
/*
|
|
|
|
|
* The edge defined by current and moving to target may encounter two
|
|
|
|
|
* edges of another region: the opposing edge of the region is that in
|
|
|
|
|
* the opposite orientation of the moving edge (i.e., left <-> right or
|
|
|
|
|
* top <-> bottom); the aligned edge of the region is that in the same
|
|
|
|
|
* orientation as the moving edge (i.e., left <->left, top <-> top,
|
|
|
|
|
* right <-> right, bottom <-> bottom).
|
|
|
|
|
*
|
|
|
|
|
* Any opposing or aligned edge of a region is considered "valid" in
|
|
|
|
|
* this search if the resist/attract zone (defined by tolerance) of
|
|
|
|
|
* that edge contains the target position of the moving edge.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Direction of motion for the edge */
|
2024-02-02 14:43:52 -05:00
|
|
|
const bool decreasing = tgt < cur;
|
2024-01-23 13:44:40 -05:00
|
|
|
|
|
|
|
|
/* Check the opposing edge */
|
|
|
|
|
bool valid = false;
|
|
|
|
|
if (decreasing) {
|
2024-02-02 14:43:52 -05:00
|
|
|
const int lo = clipped_sub(opp, abs(tolerance));
|
|
|
|
|
const int hi = clipped_sub(opp, MIN(tolerance, 0));
|
2024-02-06 10:00:48 -05:00
|
|
|
valid = tgt >= lo && tgt < hi && cur >= opp;
|
2024-01-23 13:44:40 -05:00
|
|
|
} else {
|
|
|
|
|
/* Check for increasing movement across opposing edge */
|
2024-02-02 14:43:52 -05:00
|
|
|
const int lo = clipped_add(opp, MIN(tolerance, 0));
|
|
|
|
|
const int hi = clipped_add(opp, abs(tolerance));
|
2024-02-06 10:00:48 -05:00
|
|
|
valid = tgt > lo && tgt <= hi && cur <= opp;
|
2024-01-21 12:56:37 -05:00
|
|
|
}
|
|
|
|
|
|
2024-02-02 14:43:52 -05:00
|
|
|
if (valid && edges_traverse_edge(current, target, oppose)) {
|
|
|
|
|
*next = edge_get_best(*next, opp, decreasing);
|
2021-10-24 21:14:05 -04:00
|
|
|
}
|
2024-01-20 21:59:46 -05:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
/* Check the aligned edge */
|
|
|
|
|
valid = false;
|
|
|
|
|
if (decreasing) {
|
2024-02-02 14:43:52 -05:00
|
|
|
const int lo = clipped_sub(aln, abs(tolerance));
|
|
|
|
|
const int hi = clipped_sub(aln, MIN(tolerance, 0));
|
2024-02-06 10:00:48 -05:00
|
|
|
valid = tgt >= lo && tgt < hi && cur >= aln;
|
2024-01-23 13:44:40 -05:00
|
|
|
} else {
|
2024-02-02 14:43:52 -05:00
|
|
|
const int lo = clipped_add(aln, MIN(tolerance, 0));
|
|
|
|
|
const int hi = clipped_add(aln, abs(tolerance));
|
2024-02-06 10:00:48 -05:00
|
|
|
valid = tgt > lo && tgt <= hi && cur <= aln;
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
|
|
|
|
|
2024-02-02 14:43:52 -05:00
|
|
|
if (valid && edges_traverse_edge(current, target, align)) {
|
|
|
|
|
*next = edge_get_best(*next, aln, decreasing);
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-23 22:31:39 -04:00
|
|
|
|
2024-01-20 21:59:46 -05:00
|
|
|
static void
|
2024-02-02 14:43:52 -05:00
|
|
|
check_edge_output(int *next, struct edge current, struct edge target,
|
|
|
|
|
struct edge oppose, struct edge align)
|
2024-01-20 21:59:46 -05:00
|
|
|
{
|
2024-01-23 13:44:40 -05:00
|
|
|
check_edge(next, current, target,
|
2024-02-02 14:43:52 -05:00
|
|
|
oppose, align, rc.screen_edge_strength);
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2024-02-02 14:43:52 -05:00
|
|
|
check_edge_window(int *next, struct edge current, struct edge target,
|
|
|
|
|
struct edge oppose, struct edge align)
|
2024-01-20 21:59:46 -05:00
|
|
|
{
|
2024-01-23 13:44:40 -05:00
|
|
|
check_edge(next, current, target,
|
2024-02-02 14:43:52 -05:00
|
|
|
oppose, align, rc.window_edge_strength);
|
2021-10-23 22:31:39 -04:00
|
|
|
}
|
2021-10-23 22:48:04 -04:00
|
|
|
|
|
|
|
|
void
|
2024-01-20 21:59:46 -05:00
|
|
|
resistance_move_apply(struct view *view, double *x, double *y)
|
2021-10-23 22:48:04 -04:00
|
|
|
{
|
2024-01-20 21:59:46 -05:00
|
|
|
assert(view);
|
|
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
struct border next_edges;
|
|
|
|
|
edges_initialize(&next_edges);
|
2024-01-20 21:59:46 -05:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
struct wlr_box target = {
|
2024-01-20 21:59:46 -05:00
|
|
|
.x = *x,
|
|
|
|
|
.y = *y,
|
|
|
|
|
.width = view->current.width,
|
|
|
|
|
.height = view->current.height,
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
if (rc.screen_edge_strength != 0) {
|
|
|
|
|
/* Find any relevant output edges encountered by this move */
|
|
|
|
|
edges_find_outputs(&next_edges, view, target, NULL,
|
|
|
|
|
check_edge_output, /* use_pending */ false);
|
2021-10-24 21:31:05 -04:00
|
|
|
}
|
2022-07-17 23:39:36 -04:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
if (rc.window_edge_strength != 0) {
|
|
|
|
|
/* Find any relevant window edges encountered by this move */
|
|
|
|
|
edges_find_neighbors(&next_edges, view, target, NULL,
|
|
|
|
|
check_edge_window, /* use_pending */ false);
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
2024-01-23 13:44:40 -05:00
|
|
|
|
|
|
|
|
/* If any "best" edges were encountered during this move, snap motion */
|
|
|
|
|
edges_adjust_move_coords(view, next_edges,
|
|
|
|
|
&target.x, &target.y, /* use_pending */ false);
|
|
|
|
|
|
|
|
|
|
*x = target.x;
|
|
|
|
|
*y = target.y;
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
2021-11-13 13:47:12 -05:00
|
|
|
|
2024-01-20 21:59:46 -05:00
|
|
|
void
|
|
|
|
|
resistance_resize_apply(struct view *view, struct wlr_box *new_geom)
|
|
|
|
|
{
|
|
|
|
|
assert(view);
|
|
|
|
|
assert(!view->shaded);
|
2021-11-13 13:47:12 -05:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
struct border next_edges;
|
|
|
|
|
edges_initialize(&next_edges);
|
2024-01-20 21:59:46 -05:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
if (rc.screen_edge_strength != 0) {
|
|
|
|
|
/* Find any relevant output edges encountered by this move */
|
|
|
|
|
edges_find_outputs(&next_edges, view, *new_geom, NULL,
|
|
|
|
|
check_edge_output, /* use_pending */ false);
|
2024-01-20 21:59:46 -05:00
|
|
|
}
|
2021-10-26 15:15:52 -04:00
|
|
|
|
2024-01-23 13:44:40 -05:00
|
|
|
if (rc.window_edge_strength != 0) {
|
|
|
|
|
/* Find any relevant window edges encountered by this move */
|
|
|
|
|
edges_find_neighbors(&next_edges, view, *new_geom, NULL,
|
|
|
|
|
check_edge_window, /* use_pending */ false);
|
2021-10-23 22:48:04 -04:00
|
|
|
}
|
2024-01-23 13:44:40 -05:00
|
|
|
|
|
|
|
|
/* 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);
|
2021-10-23 22:48:04 -04:00
|
|
|
}
|