Leonid Bobrov: 1 Resize views accurately 5 files changed, 352 insertions(+), 178 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~sircmpwn/wio/patches/11214/mbox | git am -3Learn more about email & git
As promised, I did: * avoid some, but not all, duplicate code; * resize views when dragging corner borders; * width and height never become negative to avoid rendering bugs while reflecting; * reflection behaves like in Rio; * minimal size is enforced on red box like in Rio. TODO: input.c needs int scale --- include/server.h | 6 +- include/view.h | 18 +-- input.c | 281 ++++++++++++++++++++++++++++------------------- output.c | 179 ++++++++++++++++++++++++------ view.c | 46 ++++---- 5 files changed, 352 insertions(+), 178 deletions(-) diff --git a/include/server.h b/include/server.h index 60842e1..f49b2dd 100644 --- a/include/server.h +++ b/include/server.h @@ -26,9 +26,13 @@ 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_RIGHT, + 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_DELETE_SELECT, INPUT_STATE_HIDE_SELECT, diff --git a/include/view.h b/include/view.h index 36303fa..e7631de 100644 --- a/include/view.h +++ b/include/view.h @@ -3,10 +3,14 @@ #include <wlr/types/wlr_xdg_shell.h> #include <wayland-server.h> +#define MINWIDTH 100 +#define MINHEIGHT 100 + struct wio_server; struct wio_view { int x, y; + int area; struct wlr_xdg_surface *xdg_surface; struct wio_server *server; struct wl_list link; @@ -15,19 +19,19 @@ struct wio_view { }; enum wio_view_area { - VIEW_AREA_SURFACE = 0, - VIEW_AREA_BORDER_TOP, - VIEW_AREA_BORDER_RIGHT, - VIEW_AREA_BORDER_BOTTOM, - VIEW_AREA_BORDER_LEFT, + 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, }; 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, - int *view_area); + struct wlr_surface **surface, double *sx, double *sy); void wio_view_move(struct wio_view *view, int x, int y); #endif diff --git a/input.c b/input.c index e4e4fbf..84c16b0 100644 --- a/input.c +++ b/input.c @@ -14,6 +14,10 @@ #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 void keyboard_handle_modifiers( struct wl_listener *listener, void *data) { struct wio_keyboard *keyboard = @@ -112,12 +116,10 @@ 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, - &view_area); + server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (!view) { switch (server->input_state) { case INPUT_STATE_MOVE_SELECT: @@ -131,8 +133,13 @@ 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: + wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, + "top_right_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; @@ -140,22 +147,27 @@ static void process_cursor_motion(struct wio_server *server, uint32_t time) { wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, "top_side", server->cursor); break; - case INPUT_STATE_BORDER_DRAG_RIGHT: + 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, - "right_side", server->cursor); + "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_LEFT: + case INPUT_STATE_BORDER_DRAG_RIGHT: wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, - "left_side", server->cursor); + "right_side", server->cursor); break; - case INPUT_STATE_RESIZE_END: - case INPUT_STATE_NEW_END: + case INPUT_STATE_BORDER_DRAG_LEFT: wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, - "bottom_right_corner", server->cursor); + "left_side", server->cursor); break; default: wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, @@ -245,27 +257,26 @@ static void view_end_interactive(struct wio_server *server) { static void new_view(struct wio_server *server) { int x1 = server->interactive.sx, x2 = server->cursor->x; int y1 = server->interactive.sy, y2 = server->cursor->y; - if (x2 < x1) { - int _ = x1; - x1 = x2; - x2 = _; + 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 (y2 < y1) { - int _ = y1; - y1 = y2; - y2 = _; + if (height < MINHEIGHT && (y1 - server->interactive.sy) < 0) { + y1 -= MINHEIGHT - height; } - struct wio_new_view *view = calloc(1, sizeof(struct wio_new_view)); - view->box.x = x1; - view->box.y = y1; - view->box.width = x2 - x1; - view->box.height = y2 - y1; - if (view->box.width < 100){ - view->box.width = 100; + if (width < MINWIDTH) { + width = MINWIDTH; } - if (view->box.height < 100){ - view->box.height = 100; + if (height < MINHEIGHT) { + height = MINHEIGHT; } + view->box.x = x1; + view->box.y = y1; + view->box.width = width; + view->box.height = height; int fd[2]; if (pipe(fd) != 0) { wlr_log(WLR_ERROR, "Unable to create pipe for fork"); @@ -358,11 +369,9 @@ 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, - &view_area); + server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (view != NULL) { view_begin_interactive(view, surface, sx, sy, "bottom_right_corner", INPUT_STATE_RESIZE_START); @@ -378,105 +387,141 @@ static void handle_button_internal( server->input_state = INPUT_STATE_RESIZE_END; } break; - case INPUT_STATE_BORDER_DRAG_TOP: - y1 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height; - y2 = server->cursor->y; + 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; - if (y2 < y1) { - int _ = y1; - y1 = y2; - y2 = _; + 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; } - wio_view_move(server->interactive.view, - x1, y1); + 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 < 100) { - height = 100; + if (height < MINHEIGHT + && (y1 - server->interactive.view->y) < (server->interactive.view->xdg_surface->surface->current.height)) { + y1 -= MINHEIGHT - height; } - wlr_xdg_toplevel_set_size( - server->interactive.view->xdg_surface, width, height); - view_end_interactive(server); - break; - case INPUT_STATE_BORDER_DRAG_LEFT: - x1 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width; + goto Done; + case INPUT_STATE_BORDER_DRAG_BOTTOM_RIGHT: + x1 = server->interactive.view->x; x2 = server->cursor->x; y1 = server->interactive.view->y; - if (x2 < x1) { - int _ = x1; - x1 = x2; - x2 = _; + 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; } - wio_view_move(server->interactive.view, - x1, y1); + 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; - height = server->interactive.view->xdg_surface->surface->current.height; - if (width < 100) { - width = 100; + if (width < MINWIDTH + && (x1 - server->interactive.view->x) < (server->interactive.view->xdg_surface->surface->current.width)) { + x1 -= MINWIDTH - width; } - wlr_xdg_toplevel_set_size( - server->interactive.view->xdg_surface, width, height); - view_end_interactive(server); - break; + 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; - if (y2 < y1) { - int _ = y1; - y1 = y2; - y2 = _; - } - wio_view_move(server->interactive.view, - x1, y1); + 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 (width < 100) { - width = 100; + if (height < MINHEIGHT && (y1 - server->interactive.view->y) < 0) { + y1 -= MINHEIGHT - height; } - wlr_xdg_toplevel_set_size( - server->interactive.view->xdg_surface, width, height); - view_end_interactive(server); - break; + goto Done; case INPUT_STATE_BORDER_DRAG_RIGHT: - x1 = server->interactive.view->x, x2 = server->cursor->x; + x1 = server->interactive.view->x; + x2 = server->cursor->x; y1 = server->interactive.view->y; - if (x2 < x1) { - int _ = x1; - x1 = x2; - x2 = _; - } - wio_view_move(server->interactive.view, - x1, y1); + 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; - if (width < 100) { - width = 100; + 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; } - wlr_xdg_toplevel_set_size( - server->interactive.view->xdg_surface, width, height); - view_end_interactive(server); - break; + height = server->interactive.view->xdg_surface->surface->current.height; + goto Done; case INPUT_STATE_RESIZE_END: x1 = server->interactive.sx, x2 = server->cursor->x; y1 = server->interactive.sy, y2 = server->cursor->y; - if (x2 < x1) { - int _ = x1; - x1 = x2; - x2 = _; + less_swap2(x2, x1); + less_swap2(y2, y1); + width = x2 - x1; + if (width < MINWIDTH && (x1 - server->interactive.sx) < 0) { + x1 -= MINWIDTH - width; } - if (y2 < y1) { - int _ = y1; - y1 = y2; - y2 = _; + height = y2 - y1; + if (height < MINHEIGHT && (y1 - server->interactive.sy) < 0) { + y1 -= MINHEIGHT - height; } + Done: wio_view_move(server->interactive.view, x1, y1); - width = x2 - x1, height = y2 - y1; - if (width < 100) { - width = 100; + if (width < MINWIDTH) { + width = MINWIDTH; } - if (height < 100) { - height = 100; + if (height < MINHEIGHT) { + height = MINHEIGHT; } wlr_xdg_toplevel_set_size( server->interactive.view->xdg_surface, width, height); @@ -485,11 +530,9 @@ 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, - &view_area); + server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (view != NULL) { view_begin_interactive(view, surface, sx, sy, "grabbing", INPUT_STATE_MOVE); @@ -507,11 +550,9 @@ 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, - &view_area); + server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (view != NULL) { wlr_xdg_toplevel_send_close(view->xdg_surface); } @@ -530,29 +571,43 @@ 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, - &view_area); + server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (server->input_state == INPUT_STATE_NONE && view) { wio_view_focus(view, surface); - switch (view_area) { + 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_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_RIGHT: + case VIEW_AREA_BORDER_BOTTOM|VIEW_AREA_BORDER_RIGHT: view_begin_interactive(view, surface, view->x, view->y, - "right_side", INPUT_STATE_BORDER_DRAG_RIGHT); + "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: view_begin_interactive(view, surface, view->x, view->y, "left_side", INPUT_STATE_BORDER_DRAG_LEFT); diff --git a/output.c b/output.c index 6a059f5..88f827b 100644 --- a/output.c +++ b/output.c @@ -272,6 +272,7 @@ 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 timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -307,39 +308,134 @@ 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: - render_view_border(renderer, output, view, - view->x, - server->cursor->y, - view->xdg_surface->surface->current.width, - view->xdg_surface->surface->current.height - (server->cursor->y - server->interactive.sy), - 1); - break; - case INPUT_STATE_BORDER_DRAG_LEFT: - render_view_border(renderer, output, view, - server->cursor->x, - view->y, - view->xdg_surface->surface->current.width - (server->cursor->x - server->interactive.sx), - view->xdg_surface->surface->current.height, - 1); - break; + 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: - render_view_border(renderer, output, view, - view->x, - view->y, - view->xdg_surface->surface->current.width, - server->cursor->y - server->interactive.sy, - 1); - break; + 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: - render_view_border(renderer, output, view, - view->x, - view->y, - server->cursor->x - server->interactive.sx, - view->xdg_surface->surface->current.height, - 1); - break; + 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_MOVE: render_view_border(renderer, output, view, server->cursor->x - server->interactive.sx, @@ -350,11 +446,26 @@ static void output_frame(struct wl_listener *listener, void *data) { break; case INPUT_STATE_NEW_END: case INPUT_STATE_RESIZE_END: - render_view_border(renderer, output, NULL, - server->interactive.sx, server->interactive.sy, - server->cursor->x - server->interactive.sx, - server->cursor->y - server->interactive.sy, - 1); + x = server->interactive.sx; + 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; + } + if (height < 0) { + height *= -1; + y -= ((height < MINHEIGHT) ? MINHEIGHT : height) + window_border * 2 * scale; + } + if (width < MINWIDTH) { + width = MINWIDTH; + } + if (height < MINHEIGHT) { + height = MINHEIGHT; + } + render_view_border(renderer, output, NULL, x, y, width, height, 1); break; default: break; diff --git a/view.c b/view.c index 37ad734..259a7b1 100644 --- a/view.c +++ b/view.c @@ -123,56 +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, - int *view_area) { + struct wlr_surface **surface, double *sx, double *sy) { 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) { + view->area = VIEW_AREA_NONE; + // Surface if (view_at(view, lx, ly, surface, sx, sy)) { - *view_area = VIEW_AREA_SURFACE; + 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.width = view->xdg_surface->surface->current.width + window_border * 2; + 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; - return view; + 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.height = view->xdg_surface->surface->current.height; + 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; + 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; + 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; + // 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_BOTTOM; + view->area |= VIEW_AREA_BORDER_LEFT; 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; + if (view->area != VIEW_AREA_NONE) { return view; } } -- 2.27.0
It still looks terrible: * input.c and output.c have their own logics for calculating x and y, width and height, there should be a way to place it in one function; * VIEW_AREA_* can be calculated more efficiently; * hovering mouse over border doesn't change its cursor to appropriate arrow; * forcing MINWIDTH and MIDHEIGHT in output.c to New and Resize commands is my mistake; * maybe it's better to calculate coordinates from borders? Rio has nicer code to handle all of these and more in 1 file: http://9p.io/sources/plan9/sys/src/cmd/rio/rio.c