ec6567e899a5bbb8e6fe59afd9d62c1892ad894b — Leon Plickat 2 months 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 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 @@   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 @@ }
  }
  
- 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ }
  
  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;
  		}
  	}