~sircmpwn/wio

Resize views accurately v1 PROPOSED

Leonid Bobrov
Leonid Bobrov: 1
 Resize views accurately

 6 files changed, 210 insertions(+), 379 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/wio/patches/11232/mbox | git am -3
Learn more about email & git
View this thread in the archives

Re: [PATCH] Resize views accurately Export this patch

Leonid Bobrov
And it still behaves worse than Rio...

Also I made New and Resize commands behave like in Rio.
---
 include/colors.h |   4 +
 include/server.h |   9 +-
 include/view.h   |  19 ++--
 input.c          | 220 ++++++-----------------------------------------
 output.c         | 149 +++-----------------------------
 view.c           | 188 ++++++++++++++++++++++++++++++++--------
 6 files changed, 210 insertions(+), 379 deletions(-)

diff --git a/include/colors.h b/include/colors.h
index f8d40dc..b1f83d3 100644
--- a/include/colors.h
+++ b/include/colors.h
@@ -29,4 +29,8 @@ static const float menu_border[4] = {
	0x78 / 255.0f, 0xAD / 255.0f, 0x84 / 255.0f, 1.0f,
};

static const float surface[4] = {
	0xFF / 255.0f, 0xFF / 255.0f, 0xFF / 255.0f, 1.0f,
};

#endif
diff --git a/include/server.h b/include/server.h
index f49b2dd..b6eaaa6 100644
--- a/include/server.h
+++ b/include/server.h
@@ -26,14 +26,7 @@ enum wio_input_state {
	INPUT_STATE_RESIZE_SELECT,
	INPUT_STATE_RESIZE_START,
	INPUT_STATE_RESIZE_END,
	INPUT_STATE_BORDER_DRAG_TOP_RIGHT,
	INPUT_STATE_BORDER_DRAG_TOP_LEFT,
	INPUT_STATE_BORDER_DRAG_TOP,
	INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT,
	INPUT_STATE_BORDER_DRAG_BOTTOM_LEFT,
	INPUT_STATE_BORDER_DRAG_BOTTOM,
	INPUT_STATE_BORDER_DRAG_RIGHT,
	INPUT_STATE_BORDER_DRAG_LEFT,
	INPUT_STATE_BORDER_DRAG,
	INPUT_STATE_DELETE_SELECT,
	INPUT_STATE_HIDE_SELECT,
};
diff --git a/include/view.h b/include/view.h
index e7631de..e1a8bbf 100644
--- a/include/view.h
+++ b/include/view.h
@@ -5,6 +5,9 @@

#define MINWIDTH 100
#define MINHEIGHT 100
// TODO: scale
#define less_swap1(A, B) { if (A < B) { int C = A; A = B + window_border * 2; B = C + window_border * 2; } }
#define less_swap2(A, B) { if (A < B) { int C = A; A = B - window_border * 2; B = C - window_border * 2; } }

struct wio_server;

@@ -19,17 +22,21 @@ struct wio_view {
};

enum wio_view_area {
	VIEW_AREA_NONE = 0,
	VIEW_AREA_SURFACE = 1,
	VIEW_AREA_BORDER_TOP = 2,
	VIEW_AREA_BORDER_BOTTOM = 4,
	VIEW_AREA_BORDER_RIGHT = 8,
	VIEW_AREA_BORDER_LEFT = 16,
	VIEW_AREA_BORDER_TOP_LEFT = 0,
	VIEW_AREA_BORDER_TOP,
	VIEW_AREA_BORDER_TOP_RIGHT,
	VIEW_AREA_BORDER_LEFT,
	VIEW_AREA_SURFACE,
	VIEW_AREA_BORDER_RIGHT,
	VIEW_AREA_BORDER_BOTTOM_LEFT,
	VIEW_AREA_BORDER_BOTTOM,
	VIEW_AREA_BORDER_BOTTOM_RIGHT,
};

void server_new_xdg_surface(struct wl_listener *listener, void *data);

void wio_view_focus(struct wio_view *view, struct wlr_surface *surface);
struct wlr_box which_box(struct wio_server *server);
struct wio_view *wio_view_at(struct wio_server *server, double lx, double ly,
		struct wlr_surface **surface, double *sx, double *sy);
void wio_view_move(struct wio_view *view, int x, int y);
diff --git a/input.c b/input.c
index 84c16b0..8f7b31e 100644
--- a/input.c
+++ b/input.c
@@ -14,9 +14,12 @@
#include "server.h"
#include "view.h"

// TODO: scale
#define less_swap1(A, B) { if (A < B) { int C = A; A = B + window_border * 2; B = C + window_border * 2; } }
#define less_swap2(A, B) { if (A < B) { int C = A; A = B - window_border * 2; B = C - window_border * 2; } }
static char *corners[9] = {
	"top_left_corner", "top_side", "top_right_corner",
	"left_side", NULL, "right_side",
	"bottom_left_corner", "bottom_side", "bottom_right_corner",
};
static char *corner = NULL;

static void keyboard_handle_modifiers(
		struct wl_listener *listener, void *data) {
@@ -118,8 +121,10 @@ static void process_cursor_motion(struct wio_server *server, uint32_t time) {
	double sx, sy;
	struct wlr_seat *seat = server->seat;
	struct wlr_surface *surface = NULL;
	struct wio_view *view = wio_view_at(
			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy);
	struct wio_view *view = NULL;
	if (server->input_state != INPUT_STATE_BORDER_DRAG) {
		view = wio_view_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy);
	}
	if (!view) {
		switch (server->input_state) {
		case INPUT_STATE_MOVE_SELECT:
@@ -133,42 +138,20 @@ static void process_cursor_motion(struct wio_server *server, uint32_t time) {
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"grabbing", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_TOP_RIGHT:
		case INPUT_STATE_BORDER_DRAG:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"top_right_corner", server->cursor);
					corner, server->cursor);
			break;
		case INPUT_STATE_RESIZE_START:
		case INPUT_STATE_NEW_START:
		case INPUT_STATE_BORDER_DRAG_TOP_LEFT:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"top_left_corner", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_TOP:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"top_side", server->cursor);
			break;
		case INPUT_STATE_RESIZE_END:
		case INPUT_STATE_NEW_END:
		case INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"bottom_right_corner", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_BOTTOM_LEFT:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"bottom_left_corner", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_BOTTOM:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"bottom_side", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_RIGHT:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"right_side", server->cursor);
			break;
		case INPUT_STATE_BORDER_DRAG_LEFT:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"left_side", server->cursor);
			break;
		default:
			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
					"left_ptr", server->cursor);
@@ -260,19 +243,10 @@ static void new_view(struct wio_server *server) {
	less_swap2(x2, x1);
	less_swap2(y2, y1);
	int width = x2 - x1, height = y2 - y1;
	struct wio_new_view *view = calloc(1, sizeof(struct wio_new_view));
	if (width < MINWIDTH && (x1 - server->interactive.sx) < 0) {
		x1 -= MINWIDTH - width;
	}
	if (height < MINHEIGHT && (y1 - server->interactive.sy) < 0) {
		y1 -= MINHEIGHT - height;
	}
	if (width < MINWIDTH) {
		width = MINWIDTH;
	}
	if (height < MINHEIGHT) {
		height = MINHEIGHT;
	if (width < MINWIDTH || height < MINHEIGHT) {
		return;
	}
	struct wio_new_view *view = calloc(1, sizeof(struct wio_new_view));
	view->box.x = x1;
	view->box.y = y1;
	view->box.width = width;
@@ -333,6 +307,7 @@ static void handle_button_internal(
		.x = server->menu.x, .y = server->menu.y,
		.width = server->menu.width, .height = server->menu.height,
	};
	struct wlr_box box;
	int x1, x2, y1, y2;
	uint32_t width, height;
	switch (server->input_state) {
@@ -387,119 +362,9 @@ static void handle_button_internal(
			server->input_state = INPUT_STATE_RESIZE_END;
		}
		break;
	case INPUT_STATE_BORDER_DRAG_TOP_RIGHT:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		less_swap1(y2, y1);
		less_swap2(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_TOP_LEFT:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		less_swap1(y2, y1);
		less_swap1(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_TOP:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->interactive.view->x;
		less_swap1(y2, y1);
		width = server->interactive.view->xdg_surface->surface->current.width;
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT:
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap2(x2, x1);
		less_swap2(y2, y1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM_LEFT:
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap1(x2, x1);
		less_swap2(y2, y1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM:
		x1 = server->interactive.view->x;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap2(y2, y1);
		width = server->interactive.view->xdg_surface->surface->current.width;
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_RIGHT:
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		y1 = server->interactive.view->y;
		less_swap2(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = server->interactive.view->xdg_surface->surface->current.height;
		goto Done;
	case INPUT_STATE_BORDER_DRAG_LEFT:
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		y1 = server->interactive.view->y;
		less_swap1(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = server->interactive.view->xdg_surface->surface->current.height;
	case INPUT_STATE_BORDER_DRAG:
		box = which_box(server);
		x1 = box.x, y1 = box.y, width = box.width, height = box.height;
		goto Done;
	case INPUT_STATE_RESIZE_END:
		x1 = server->interactive.sx, x2 = server->cursor->x;
@@ -507,22 +372,14 @@ static void handle_button_internal(
		less_swap2(x2, x1);
		less_swap2(y2, y1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.sx) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.sy) < 0) {
			y1 -= MINHEIGHT - height;
		if (width < MINWIDTH || height < MINHEIGHT) {
			view_end_interactive(server);
			break;
		}
	Done:
		wio_view_move(server->interactive.view,
				x1, y1);
		if (width < MINWIDTH) {
			width = MINWIDTH;
		}
		if (height < MINHEIGHT) {
			height = MINHEIGHT;
		}
		wlr_xdg_toplevel_set_size(
				server->interactive.view->xdg_surface, width, height);
		view_end_interactive(server);
@@ -580,37 +437,10 @@ void server_cursor_button(struct wl_listener *listener, void *data) {
			wlr_seat_pointer_notify_button(server->seat,
					event->time_msec, event->button, event->state);
			break;
		case VIEW_AREA_BORDER_TOP|VIEW_AREA_BORDER_RIGHT:
			view_begin_interactive(view, surface, view->x, view->y,
					"top_right_corner", INPUT_STATE_BORDER_DRAG_TOP_RIGHT);
			break;
		case VIEW_AREA_BORDER_TOP|VIEW_AREA_BORDER_LEFT:
			view_begin_interactive(view, surface, view->x, view->y,
					"top_left_corner", INPUT_STATE_BORDER_DRAG_TOP_LEFT);
			break;
		case VIEW_AREA_BORDER_TOP:
			view_begin_interactive(view, surface, view->x, view->y,
					"top_side", INPUT_STATE_BORDER_DRAG_TOP);
			break;
		case VIEW_AREA_BORDER_BOTTOM|VIEW_AREA_BORDER_RIGHT:
			view_begin_interactive(view, surface, view->x, view->y,
					"bottom_right_corner", INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT);
			break;
		case VIEW_AREA_BORDER_BOTTOM|VIEW_AREA_BORDER_LEFT:
			view_begin_interactive(view, surface, view->x, view->y,
					"bottom_left_corner", INPUT_STATE_BORDER_DRAG_BOTTOM_LEFT);
			break;
		case VIEW_AREA_BORDER_BOTTOM:
			view_begin_interactive(view, surface, view->x, view->y,
					"bottom_side", INPUT_STATE_BORDER_DRAG_BOTTOM);
			break;
		case VIEW_AREA_BORDER_RIGHT:
			view_begin_interactive(view, surface, view->x, view->y,
					"right_side", INPUT_STATE_BORDER_DRAG_RIGHT);
			break;
		case VIEW_AREA_BORDER_LEFT:
		default:
			corner = corners[view->area];
			view_begin_interactive(view, surface, view->x, view->y,
					"left_side", INPUT_STATE_BORDER_DRAG_LEFT);
					corner, INPUT_STATE_BORDER_DRAG);
			break;
		}
	} else {
diff --git a/output.c b/output.c
index 88f827b..3ec64a8 100644
--- a/output.c
+++ b/output.c
@@ -272,7 +272,9 @@ static void output_frame(struct wl_listener *listener, void *data) {
	struct wio_output *output = wl_container_of(listener, output, frame);
	struct wio_server *server = output->server;
	struct wlr_renderer *renderer = server->renderer;
	int x, y, width, height, scale;
	struct wlr_box box;
	int x, y, width, height;
	float color[4];

	struct timespec now;
	clock_gettime(CLOCK_MONOTONIC, &now);
@@ -308,134 +310,11 @@ static void output_frame(struct wl_listener *listener, void *data) {
				render_surface, &rdata);
	}
	view = server->interactive.view;
	scale = output->wlr_output->scale;
	switch (server->input_state) {
	case INPUT_STATE_BORDER_DRAG_TOP_RIGHT:
		x = view->x;
		y = server->cursor->y;
		width = server->cursor->x - server->interactive.sx;
		height = view->xdg_surface->surface->current.height - (server->cursor->y - server->interactive.sy);
		if (height < MINHEIGHT && height > -MINHEIGHT) {
			if (height < 0) {
				height *= -1;
				y -= height - window_border * 2 * scale;
			} else {
				y -= MINHEIGHT - height;
			}
			height = MINHEIGHT;
		}
		if (height < 0) {
			height *= -1;
			y -= height - window_border * 2 * scale;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_TOP_LEFT:
		x = server->cursor->x;
		y = server->cursor->y;
		width = view->xdg_surface->surface->current.width - (server->cursor->x - server->interactive.sx);
		height = view->xdg_surface->surface->current.height - (server->cursor->y - server->interactive.sy);
		if (width < MINWIDTH && width > -MINWIDTH) {
			if (width < 0) {
				width *= -1;
				x -= width - window_border * 2 * scale;
			} else {
				x -= MINWIDTH - width;
			}
			width = MINWIDTH;
		}
		if (height < MINHEIGHT && height > -MINHEIGHT) {
			if (height < 0) {
				height *= -1;
				y -= height - window_border * 2 * scale;
			} else {
				y -= MINHEIGHT - height;
			}
			height = MINHEIGHT;
		}
		if (width < 0) {
			width *= -1;
			x -= width - window_border * 2 * scale;
		}
		if (height < 0) {
			height *= -1;
			y -= height - window_border * 2 * scale;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_TOP:
		x = view->x;
		y = server->cursor->y;
		width = view->xdg_surface->surface->current.width;
		height = view->xdg_surface->surface->current.height - (server->cursor->y - server->interactive.sy);
		if (height < MINHEIGHT && height > -MINHEIGHT) {
			if (height < 0) {
				height *= -1;
				y -= height - window_border * 2 * scale;
			} else {
				y -= MINHEIGHT - height;
			}
			height = MINHEIGHT;
		}
		if (height < 0) {
			height *= -1;
			y -= height - window_border * 2 * scale;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT:
		x = view->x;
		y = view->y;
		width = server->cursor->x - server->interactive.sx;
		height = server->cursor->y - server->interactive.sy;
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM_LEFT:
		x = server->cursor->x;
		y = view->y;
		width = view->xdg_surface->surface->current.width - (server->cursor->x - server->interactive.sx);
		height = server->cursor->y - server->interactive.sy;
		if (width < MINWIDTH && width > -MINWIDTH) {
			if (width < 0) {
				width *= -1;
				x -= width - window_border * 2 * scale;
			} else {
				x -= MINWIDTH - width;
			}
			width = MINWIDTH;
		}
		if (width < 0) {
			width *= -1;
			x -= width - window_border * 2 * scale;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG_BOTTOM:
		x = view->x;
		y = view->y;
		width = view->xdg_surface->surface->current.width;
		height = server->cursor->y - server->interactive.sy;
		goto Done;
	case INPUT_STATE_BORDER_DRAG_RIGHT:
		x = view->x;
		y = view->y;
		width = server->cursor->x - server->interactive.sx;
		height = view->xdg_surface->surface->current.height;
		goto Done;
	case INPUT_STATE_BORDER_DRAG_LEFT:
		x = server->cursor->x;
		y = view->y;
		width = view->xdg_surface->surface->current.width - (server->cursor->x - server->interactive.sx);
		height = view->xdg_surface->surface->current.height;
		if (width < MINWIDTH && width > -MINWIDTH) {
			if (width < 0) {
				width *= -1;
				x -= width - window_border * 2 * scale;
			} else {
				x -= MINWIDTH - width;
			}
			width = MINWIDTH;
		}
		if (width < 0) {
			width *= -1;
			x -= width - window_border * 2 * scale;
		}
		goto Done;
	case INPUT_STATE_BORDER_DRAG:
		box = which_box(server);
		render_view_border(renderer, output, NULL, box.x, box.y, box.width, box.height, 1);
		break;
	case INPUT_STATE_MOVE:
		render_view_border(renderer, output, view,
			server->cursor->x - server->interactive.sx,
@@ -450,20 +329,18 @@ static void output_frame(struct wl_listener *listener, void *data) {
		y = server->interactive.sy;
		width = server->cursor->x - server->interactive.sx;
		height = server->cursor->y - server->interactive.sy;
	Done:
		if (width < 0) {
			width *= -1;
			x -= ((width < MINWIDTH) ? MINWIDTH : width) + window_border * 2 * scale;
			x -= width + window_border * 2;
		}
		if (height < 0) {
			height *= -1;
			y -= ((height < MINHEIGHT) ? MINHEIGHT : height) + window_border * 2 * scale;
		}
		if (width < MINWIDTH) {
			width = MINWIDTH;
			y -= height + window_border * 2;
		}
		if (height < MINHEIGHT) {
			height = MINHEIGHT;
		if (width > 0 && height > 0) {
			box.x = x, box.y = y, box.width = width, box.height = height;
			memcpy(color, surface, sizeof(color));
			wlr_render_rect(renderer, &box, color, output->wlr_output->transform_matrix);
		}
		render_view_border(renderer, output, NULL, x, y, width, height, 1);
		break;
diff --git a/view.c b/view.c
index 259a7b1..1e93a13 100644
--- a/view.c
+++ b/view.c
@@ -122,6 +122,157 @@ static bool view_at(struct wio_view *view,
	return false;
}

static int portion(int x, int lo, int width) {
	x -= lo;
	if (x < 20) {
		return 0;
	}
	if (x > width-20) {
		return 2;
	}
	return 1;
}

static int which_corner(struct wlr_box *box, int x, int y) {
	int i, j;

	i = portion(x, box->x, box->width);
	j = portion(y, box->y, box->height);
	return 3*j+i;
}

struct wlr_box which_box(struct wio_server *server) {
	struct wlr_box box;
	int x1, x2, y1, y2, width, height;
	switch (server->interactive.view->area) {
	case VIEW_AREA_BORDER_TOP_LEFT:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		less_swap1(y2, y1);
		less_swap1(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		break;
	case VIEW_AREA_BORDER_TOP:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->interactive.view->x;
		less_swap1(y2, y1);
		width = server->interactive.view->xdg_surface->surface->current.width;
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		break;
	case VIEW_AREA_BORDER_TOP_RIGHT:
		y1 = server->cursor->y;
		y2 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		less_swap1(y2, y1);
		less_swap2(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT
			&& (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) {
			y1 -= MINHEIGHT - height;
		}
		break;
	case VIEW_AREA_BORDER_LEFT:
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		y1 = server->interactive.view->y;
		less_swap1(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = server->interactive.view->xdg_surface->surface->current.height;
		break;
	case VIEW_AREA_BORDER_RIGHT:
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		y1 = server->interactive.view->y;
		less_swap2(x2, x1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = server->interactive.view->xdg_surface->surface->current.height;
		break;
	case VIEW_AREA_BORDER_BOTTOM_LEFT:
		x1 = server->cursor->x;
		x2 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap1(x2, x1);
		less_swap2(y2, y1);
		width = x2 - x1;
		if (width < MINWIDTH
			&& (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		break;
	case VIEW_AREA_BORDER_BOTTOM:
		x1 = server->interactive.view->x;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap2(y2, y1);
		width = server->interactive.view->xdg_surface->surface->current.width;
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		break;
	case VIEW_AREA_BORDER_BOTTOM_RIGHT:
		x1 = server->interactive.view->x;
		x2 = server->cursor->x;
		y1 = server->interactive.view->y;
		y2 = server->cursor->y;
		less_swap2(x2, x1);
		less_swap2(y2, y1);
		width = x2 - x1;
		if (width < MINWIDTH && (x1 - server->interactive.view->x) < 0) {
			x1 -= MINWIDTH - width;
		}
		height = y2 - y1;
		if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) {
			y1 -= MINHEIGHT - height;
		}
		break;
	}
	if (width < MINWIDTH) {
		width = MINWIDTH;
	}
	if (height < MINHEIGHT) {
		height = MINHEIGHT;
	}
	box.x = x1;
	box.y = y1;
	box.width = width;
	box.height = height;
	return box;
}

struct wio_view *wio_view_at(struct wio_server *server, double lx, double ly,
		struct wlr_surface **surface, double *sx, double *sy) {
	struct wlr_box border_box = {
@@ -130,49 +281,18 @@ struct wio_view *wio_view_at(struct wio_server *server, double lx, double ly,
	};
	struct wio_view *view;
	wl_list_for_each(view, &server->views, link) {
		view->area = VIEW_AREA_NONE;

		// Surface
		if (view_at(view, lx, ly, surface, sx, sy)) {
			view->area = VIEW_AREA_SURFACE;
			return view;
		}

		// Top border
		border_box.height = window_border;
		border_box.width = view->xdg_surface->surface->current.width + window_border * 2;
		// Border
		border_box.x = view->x - window_border;
		border_box.y = view->y - window_border;
		if (wlr_box_contains_point(&border_box, server->cursor->x, server->cursor->y)) {
			view->area = VIEW_AREA_BORDER_TOP;
			goto SideBorder;
		}

		// Bottom border
		border_box.y = view->y + view->xdg_surface->surface->current.height;
		if (wlr_box_contains_point(&border_box, server->cursor->x, server->cursor->y)) {
			view->area = VIEW_AREA_BORDER_BOTTOM;
		}

	SideBorder:
		// Right border
		border_box.width = view->xdg_surface->surface->current.width + window_border * 2;
		border_box.height = view->xdg_surface->surface->current.height + window_border * 2;
		border_box.width = window_border;
		border_box.x = view->x + view->xdg_surface->surface->current.width;
		border_box.y = view->y - window_border;
		if (wlr_box_contains_point(&border_box, server->cursor->x, server->cursor->y)) {
			view->area |= VIEW_AREA_BORDER_RIGHT;
			return view;
		}

		// Left border
		border_box.x = view->x - window_border;
		if (wlr_box_contains_point(&border_box, server->cursor->x, server->cursor->y)) {
			view->area |= VIEW_AREA_BORDER_LEFT;
			return view;
		}

		if (view->area != VIEW_AREA_NONE) {
			view->area = which_corner(&border_box, server->cursor->x, server->cursor->y);
			return view;
		}
	}
-- 
2.27.0