From cf713edc1052943ceaf33fd3b41242b5775fd924 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 3 Nov 2017 14:49:15 +0100 Subject: [PATCH] Fix moving views when resizing below min size --- include/rootston/view.h | 8 +++- rootston/cursor.c | 23 ++++++----- rootston/desktop.c | 31 ++++++++++----- rootston/wl_shell.c | 2 +- rootston/xdg_shell_v6.c | 75 +++++++++++++++++++++++++++-------- rootston/xwayland.c | 86 ++++++++++++++++++++++++++++------------- 6 files changed, 159 insertions(+), 66 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 993ff654..0913b42e 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -73,15 +73,19 @@ struct roots_view { // elsewhere void (*get_size)(struct roots_view *view, struct wlr_box *box); void (*activate)(struct roots_view *view, bool active); + void (*move)(struct roots_view *view, double x, double y); void (*resize)(struct roots_view *view, uint32_t width, uint32_t height); - void (*set_position)(struct roots_view *view, double x, double y); + void (*move_resize)(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height); void (*close)(struct roots_view *view); }; void view_get_size(struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); +void view_move(struct roots_view *view, double x, double y); void view_resize(struct roots_view *view, uint32_t width, uint32_t height); -void view_set_position(struct roots_view *view, double x, double y); +void view_move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height); void view_close(struct roots_view *view); bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); diff --git a/rootston/cursor.c b/rootston/cursor.c index 31001a9f..b153e8c8 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -117,8 +117,8 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { if (input->active_view) { double dx = input->cursor->x - input->offs_x; double dy = input->cursor->y - input->offs_y; - view_set_position(input->active_view, - input->view_x + dx, input->view_y + dy); + view_move(input->active_view, input->view_x + dx, + input->view_y + dy); } break; case ROOTS_CURSOR_RESIZE: @@ -132,15 +132,19 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { active_y = input->view_y + dy; height -= dy; - } - if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) { + if (height < 0) { + active_y += height; + } + } else if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) { height += dy; } if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) { active_x = input->view_x + dx; width -= dx; - } - if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { + if (width < 0) { + active_x += width; + } + } else if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { width += dx; } @@ -151,12 +155,13 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { height = 0; } - // TODO we might need one configure event for this if (active_x != input->active_view->x || active_y != input->active_view->y) { - view_set_position(input->active_view, active_x, active_y); + view_move_resize(input->active_view, active_x, active_y, + width, height); + } else { + view_resize(input->active_view, width, height); } - view_resize(input->active_view, width, height); } break; case ROOTS_CURSOR_ROTATE: diff --git a/rootston/desktop.c b/rootston/desktop.c index f93d1df8..29f78ac7 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -45,9 +45,15 @@ void view_get_size(struct roots_view *view, struct wlr_box *box) { box->height = view->wlr_surface->current->height; } -void view_set_position(struct roots_view *view, double x, double y) { - if (view->set_position) { - view->set_position(view, x, y); +void view_activate(struct roots_view *view, bool activate) { + if (view->activate) { + view->activate(view, activate); + } +} + +void view_move(struct roots_view *view, double x, double y) { + if (view->move) { + view->move(view, x, y); return; } @@ -55,18 +61,23 @@ void view_set_position(struct roots_view *view, double x, double y) { view->y = y; } -void view_activate(struct roots_view *view, bool activate) { - if (view->activate) { - view->activate(view, activate); - } -} - void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { if (view->resize) { view->resize(view, width, height); } } +void view_move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + if (view->move_resize) { + view->move_resize(view, x, y, width, height); + return; + } + + view_move(view, x, y); + view_resize(view, width, height); +} + void view_close(struct roots_view *view) { if (view->close) { view->close(view); @@ -101,7 +112,7 @@ bool view_center(struct roots_view *view) { double view_x = (double)(width - size.width) / 2 + l_output->x; double view_y = (double)(height - size.height) / 2 + l_output->y; - view_set_position(view, view_x, view_y); + view_move(view, view_x, view_y); return true; } diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index e5366672..e38eb697 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -120,7 +120,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { surface->parent); if (i != -1) { struct roots_view *parent = desktop->views->items[i]; - view_set_position(view, + view_move(view, parent->x + surface->transient_state->x, parent->y + surface->transient_state->y); } diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 704ccb1e..ca33c582 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -25,27 +25,63 @@ static void activate(struct roots_view *view, bool active) { } } +static void apply_size_constraints(struct wlr_xdg_surface_v6 *surf, + uint32_t width, uint32_t height, uint32_t *dest_width, + uint32_t *dest_height) { + *dest_width = width; + *dest_height = height; + + struct wlr_xdg_toplevel_v6_state *state = + &surf->toplevel_state->current; + if (width < state->min_width) { + *dest_width = state->min_width; + } else if (state->max_width > 0 && + width > state->max_width) { + *dest_width = state->max_width; + } + if (height < state->min_height) { + *dest_height = state->min_height; + } else if (state->max_height > 0 && + height > state->max_height) { + *dest_height = state->max_height; + } +} + static void resize(struct roots_view *view, uint32_t width, uint32_t height) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surf = view->xdg_surface_v6; - if (surf->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - struct wlr_xdg_toplevel_v6_state *state = - &surf->toplevel_state->current; - if (width < state->min_width) { - width = state->min_width; - } else if (state->max_width > 0 && - width > state->max_width) { - width = state->max_width; - } - if (height < state->min_height) { - height = state->min_height; - } else if (state->max_height > 0 && - height > state->max_height) { - height = state->max_height; - } - - wlr_xdg_toplevel_v6_set_size(surf, width, height); + if (surf->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; } + + uint32_t contrained_width, contrained_height; + apply_size_constraints(surf, width, height, &contrained_width, + &contrained_height); + + wlr_xdg_toplevel_v6_set_size(surf, contrained_width, contrained_height); +} + +static void move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); + struct wlr_xdg_surface_v6 *surf = view->xdg_surface_v6; + if (surf->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; + } + + uint32_t contrained_width, contrained_height; + apply_size_constraints(surf, width, height, &contrained_width, + &contrained_height); + + x = x + width - contrained_width; + y = y + height - contrained_height; + + // TODO: we should wait for an ack_configure event before updating the + // position + view->x = x; + view->y = y; + + wlr_xdg_toplevel_v6_set_size(surf, contrained_width, contrained_height); } static void close(struct roots_view *view) { @@ -130,6 +166,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { &roots_surface->request_resize); struct roots_view *view = calloc(1, sizeof(struct roots_view)); + if (!view) { + free(roots_surface); + return; + } view->type = ROOTS_XDG_SHELL_V6_VIEW; view->xdg_surface_v6 = surface; view->roots_xdg_surface_v6 = roots_surface; @@ -137,6 +177,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->get_size = get_size; view->activate = activate; view->resize = resize; + view->move_resize = move_resize; view->close = close; view->desktop = desktop; roots_surface->view = view; diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 2d7fe946..e3fc1c84 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -15,32 +15,7 @@ static void activate(struct roots_view *view, bool active) { wlr_xwayland_surface_activate(xwayland, view->xwayland_surface, active); } -static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; - - struct wlr_xwayland_surface_size_hints *size_hints = - xwayland_surface->size_hints; - if (size_hints != NULL) { - if (width < (uint32_t)size_hints->min_width) { - width = size_hints->min_width; - } else if (size_hints->max_width > 0 && - width > (uint32_t)size_hints->max_width) { - width = size_hints->max_width; - } - if (height < (uint32_t)size_hints->min_height) { - height = size_hints->min_height; - } else if (size_hints->max_height > 0 && - height > (uint32_t)size_hints->max_height) { - height = size_hints->max_height; - } - } - - wlr_xwayland_surface_configure(view->desktop->xwayland, xwayland_surface, - xwayland_surface->x, xwayland_surface->y, width, height); -} - -static void set_position(struct roots_view *view, double x, double y) { +static void move(struct roots_view *view, double x, double y) { assert(view->type == ROOTS_XWAYLAND_VIEW); struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; view->x = x; @@ -49,6 +24,62 @@ static void set_position(struct roots_view *view, double x, double y) { x, y, xwayland_surface->width, xwayland_surface->height); } +static void apply_size_constraints( + struct wlr_xwayland_surface *xwayland_surface, uint32_t width, + uint32_t height, uint32_t *dest_width, uint32_t *dest_height) { + *dest_width = width; + *dest_height = height; + + struct wlr_xwayland_surface_size_hints *size_hints = + xwayland_surface->size_hints; + if (size_hints != NULL) { + if (width < (uint32_t)size_hints->min_width) { + *dest_width = size_hints->min_width; + } else if (size_hints->max_width > 0 && + width > (uint32_t)size_hints->max_width) { + *dest_width = size_hints->max_width; + } + if (height < (uint32_t)size_hints->min_height) { + *dest_height = size_hints->min_height; + } else if (size_hints->max_height > 0 && + height > (uint32_t)size_hints->max_height) { + *dest_height = size_hints->max_height; + } + } +} + +static void resize(struct roots_view *view, uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XWAYLAND_VIEW); + struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + + uint32_t contrained_width, contrained_height; + apply_size_constraints(xwayland_surface, width, height, &contrained_width, + &contrained_height); + + wlr_xwayland_surface_configure(view->desktop->xwayland, xwayland_surface, + xwayland_surface->x, xwayland_surface->y, contrained_width, + contrained_height); +} + +static void move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XWAYLAND_VIEW); + struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + + uint32_t contrained_width, contrained_height; + apply_size_constraints(xwayland_surface, width, height, &contrained_width, + &contrained_height); + + x = x + width - contrained_width; + y = y + height - contrained_height; + + view->x = x; + view->y = y; + + wlr_xwayland_surface_configure(view->desktop->xwayland, xwayland_surface, + x, y, contrained_width, contrained_height); +} + static void close(struct roots_view *view) { assert(view->type == ROOTS_XWAYLAND_VIEW); wlr_xwayland_surface_close(view->desktop->xwayland, view->xwayland_surface); @@ -204,7 +235,8 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->desktop = desktop; view->activate = activate; view->resize = resize; - view->set_position = set_position; + view->move = move; + view->move_resize = move_resize; view->close = close; roots_surface->view = view; wlr_list_add(desktop->views, view);