~sircmpwn/wio

ec6567e899a5bbb8e6fe59afd9d62c1892ad894b — Leon Plickat 5 years ago 65176f9
Bug-Fix: Can no longer select borders hidden under views

This fixes the bug where clicking on a border would enable border
dragging even if the border was hidden under a view.

Letting wio_view_at() report where the given coordinates are on a view
enables us to check for views and borders of views in the same loop,
easily solving this problem.

Additionally this makes the border dragging code cleaner and enables
other functions as well to see where on a view was clicked.
3 files changed, 94 insertions(+), 75 deletions(-)

M include/view.h
M input.c
M view.c
M include/view.h => include/view.h +10 -1
@@ 14,11 14,20 @@ struct wio_view {
	struct wl_listener destroy;
};

enum wio_view_area {
	VIEW_AREA_SURFACE = 0,
	VIEW_AREA_BORDER_TOP,
	VIEW_AREA_BORDER_RIGHT,
	VIEW_AREA_BORDER_BOTTOM,
	VIEW_AREA_BORDER_LEFT,
};

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

void wio_view_focus(struct wio_view *view, struct wlr_surface *surface);
struct wio_view *wio_view_at(struct wio_server *server, double lx, double ly,
		struct wlr_surface **surface, double *sx, double *sy);
		struct wlr_surface **surface, double *sx, double *sy,
		int *view_area);
void wio_view_move(struct wio_view *view, int x, int y);

#endif

M input.c => input.c +37 -73
@@ 112,10 112,12 @@ void server_new_input(struct wl_listener *listener, void *data) {

static void process_cursor_motion(struct wio_server *server, uint32_t time) {
	double sx, sy;
	int view_area;
	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);
			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy,
			&view_area);
	if (!view) {
		switch (server->input_state) {
		case INPUT_STATE_MOVE_SELECT:


@@ 312,69 314,6 @@ static void new_view(struct wio_server *server) {
	}
}

bool wio_border_drag(
		struct wio_server *server, struct wlr_event_pointer_button *event) {
	if (event->button != BTN_RIGHT) {
		return false;
	}
	struct wlr_box border_box = {
		.x = 0, .y = 0,
		.width = 0, .height = 0,
	};
	struct wio_view *view;
	struct wlr_surface *surface = NULL;
	wl_list_for_each(view, &server->views, link) {
		// Top border
		border_box.height = window_border;
		border_box.width = view->xdg_surface->surface->current.width;
		border_box.x = view->x;
		border_box.y = view->y - window_border;
		if (wlr_box_contains_point(
					&border_box, server->cursor->x, server->cursor->y)) {
			view_begin_interactive(view, surface, view->x, view->y,
					"top_side", INPUT_STATE_BORDER_DRAG_TOP);
			return true;
		}

		// Right border
		border_box.height = view->xdg_surface->surface->current.height;
		border_box.width = window_border;
		border_box.x = view->x + view->xdg_surface->surface->current.width;
		border_box.y = view->y;
		if (wlr_box_contains_point(
					&border_box, server->cursor->x, server->cursor->y)) {
			view_begin_interactive(view, surface, view->x, view->y,
					"right_side", INPUT_STATE_BORDER_DRAG_RIGHT);
			return true;
		}

		// Bottom border
		border_box.height = window_border;
		border_box.width = view->xdg_surface->surface->current.width;
		border_box.x = view->x;
		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_begin_interactive(view, surface, view->x, view->y,
					"bottom_side", INPUT_STATE_BORDER_DRAG_BOTTOM);
			return true;
		}

		// Left border
		border_box.height = view->xdg_surface->surface->current.height;
		border_box.width = window_border;
		border_box.x = view->x - window_border;
		border_box.y = view->y;
		if (wlr_box_contains_point(
					&border_box, server->cursor->x, server->cursor->y)) {
			view_begin_interactive(view, surface, view->x, view->y,
					"left_side", INPUT_STATE_BORDER_DRAG_LEFT);
			return true;
		}
	}
	return false;
}

static void handle_button_internal(
		struct wio_server *server, struct wlr_event_pointer_button *event) {
	// TODO: open menu if the client doesn't handle the button press


@@ 419,9 358,11 @@ static void handle_button_internal(
	case INPUT_STATE_RESIZE_SELECT:
		if (event->state == WLR_BUTTON_PRESSED) {
			double sx, sy;
			int view_area;
			struct wlr_surface *surface = NULL;
			struct wio_view *view = wio_view_at(server,
					server->cursor->x, server->cursor->y, &surface, &sx, &sy);
					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
					&view_area);
			if (view != NULL) {
				view_begin_interactive(view, surface, sx, sy,
						"bottom_right_corner", INPUT_STATE_RESIZE_START);


@@ 544,9 485,11 @@ static void handle_button_internal(
	case INPUT_STATE_MOVE_SELECT:
		if (event->state == WLR_BUTTON_PRESSED) {
			double sx, sy;
			int view_area;
			struct wlr_surface *surface = NULL;
			struct wio_view *view = wio_view_at(server,
					server->cursor->x, server->cursor->y, &surface, &sx, &sy);
					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
					&view_area);
			if (view != NULL) {
				view_begin_interactive(view, surface, sx, sy,
						"grabbing", INPUT_STATE_MOVE);


@@ 564,9 507,11 @@ static void handle_button_internal(
	case INPUT_STATE_DELETE_SELECT:
		if (event->state == WLR_BUTTON_PRESSED) {
			double sx, sy;
			int view_area;
			struct wlr_surface *surface = NULL;
			struct wio_view *view = wio_view_at(server,
					server->cursor->x, server->cursor->y, &surface, &sx, &sy);
					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
					&view_area);
			if (view != NULL) {
				wlr_xdg_toplevel_send_close(view->xdg_surface);
			}


@@ 585,15 530,34 @@ void server_cursor_button(struct wl_listener *listener, void *data) {
	struct wlr_event_pointer_button *event = data;
	double sx, sy;
	struct wlr_surface *surface = NULL;
	int view_area;
	struct wio_view *view = wio_view_at(
			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy);
	if (wio_border_drag(server, event)) {
		return;
	}
			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy,
			&view_area);
	if (server->input_state == INPUT_STATE_NONE && view) {
		wio_view_focus(view, surface);
		wlr_seat_pointer_notify_button(server->seat,
				event->time_msec, event->button, event->state);
		switch (view_area) {
		case VIEW_AREA_SURFACE:
			wlr_seat_pointer_notify_button(server->seat,
					event->time_msec, event->button, event->state);
			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_RIGHT:
			view_begin_interactive(view, surface, view->x, view->y,
					"right_side", INPUT_STATE_BORDER_DRAG_RIGHT);
			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_LEFT:
			view_begin_interactive(view, surface, view->x, view->y,
					"left_side", INPUT_STATE_BORDER_DRAG_LEFT);
			break;
		}
	} else {
		handle_button_internal(server, event);
	}

M view.c => view.c +47 -1
@@ 123,10 123,56 @@ static bool view_at(struct wio_view *view,
}

struct wio_view *wio_view_at(struct wio_server *server, double lx, double ly,
		struct wlr_surface **surface, double *sx, double *sy) {
		struct wlr_surface **surface, double *sx, double *sy,
		int *view_area) {
	struct wlr_box border_box = {
		.x = 0, .y = 0,
		.width = 0, .height = 0,
	};
	struct wio_view *view;
	wl_list_for_each(view, &server->views, link) {
		// 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;
		border_box.x = view->x;
		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;
			return view;
		}

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

		// Bottom border
		border_box.height = window_border;
		border_box.width = view->xdg_surface->surface->current.width;
		border_box.x = view->x;
		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;
			return view;
		}

		// Left border
		border_box.height = view->xdg_surface->surface->current.height;
		border_box.width = window_border;
		border_box.x = view->x - window_border;
		border_box.y = view->y;
		if (wlr_box_contains_point(&border_box, server->cursor->x, server->cursor->y)) {
			*view_area = VIEW_AREA_BORDER_LEFT;
			return view;
		}
	}