mirror of
https://github.com/labwc/labwc.git
synced 2026-06-13 14:33:18 -04:00
view: clamp position to prevent windows moving fully off-screen
Add overshoot detection based on squared distance of window corners from the output layout. view_move_relative() now only permits movement that brings windows closer to being fully inside the layout, and recursively halves the step size to nudge windows flush against the edge.
This commit is contained in:
parent
f42e1895d4
commit
19ba61a834
1 changed files with 61 additions and 0 deletions
61
src/view.c
61
src/view.c
|
|
@ -609,6 +609,33 @@ view_resize_relative(struct view *view, int left, int right, int top, int bottom
|
|||
view_set_untiled(view);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the total squared distance of the box's four corners from the
|
||||
* output layout. A return value of 0 means the box is fully inside.
|
||||
*/
|
||||
static double
|
||||
box_layout_overshoot(struct wlr_box *box)
|
||||
{
|
||||
struct wlr_output_layout *layout = server.output_layout;
|
||||
double overshoot = 0;
|
||||
double corners[4][2] = {
|
||||
{box->x, box->y},
|
||||
{box->x + box->width - 1, box->y},
|
||||
{box->x, box->y + box->height - 1},
|
||||
{box->x + box->width - 1, box->y + box->height - 1},
|
||||
};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
double closest_x, closest_y;
|
||||
wlr_output_layout_closest_point(layout, NULL,
|
||||
corners[i][0], corners[i][1],
|
||||
&closest_x, &closest_y);
|
||||
double dx = corners[i][0] - closest_x;
|
||||
double dy = corners[i][1] - closest_y;
|
||||
overshoot += dx * dx + dy * dy;
|
||||
}
|
||||
return overshoot;
|
||||
}
|
||||
|
||||
void
|
||||
view_move_relative(struct view *view, int x, int y)
|
||||
{
|
||||
|
|
@ -621,6 +648,40 @@ view_move_relative(struct view *view, int x, int y)
|
|||
view_set_untiled(view);
|
||||
view_move_resize(view, view->natural_geometry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only proceed if movement brings the window closer to being fully
|
||||
* inside the output layout. This allows a partially-outside window
|
||||
* to be moved back inside, while still preventing a fully-inside
|
||||
* window from being moved outside.
|
||||
*/
|
||||
struct border border = ssd_thickness(view);
|
||||
struct wlr_box current_box = {
|
||||
.x = view->pending.x - border.left,
|
||||
.y = view->pending.y - border.top,
|
||||
.width = view->pending.width + border.left + border.right,
|
||||
.height = view->pending.height + border.top + border.bottom,
|
||||
};
|
||||
struct wlr_box dest = current_box;
|
||||
dest.x += x;
|
||||
dest.y += y;
|
||||
double current_overshoot = box_layout_overshoot(¤t_box);
|
||||
double dest_overshoot = box_layout_overshoot(&dest);
|
||||
if (dest_overshoot > 0 && dest_overshoot >= current_overshoot) {
|
||||
if (abs(x) > 1 || abs(y) > 1) {
|
||||
/*
|
||||
* It is reasonable to assume that users will specify
|
||||
* big numbers (like 20) for the MoveRelative x or y
|
||||
* value. When moving towards a layout outer edge, we
|
||||
* would not want the window to stop a distance away
|
||||
* from the edge, so recursively nudge it nearer until
|
||||
* it is touching.
|
||||
*/
|
||||
view_move_relative(view, x / 2, y / 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
view_move(view, view->pending.x + x, view->pending.y + y);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue