From d9a083960b0c54111b062996f1df556964cd4507 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Tue, 26 May 2020 12:56:33 +0100 Subject: [PATCH] Refactor interactive resize/move Define server->grab_{x,y} as the cursor position at point of grab --- labwc.h | 9 +++ output.c | 35 +++--------- server.c | 163 ++++++++++++++++++++++--------------------------------- view.c | 46 ++++++++++++++++ 4 files changed, 127 insertions(+), 126 deletions(-) diff --git a/labwc.h b/labwc.h index 26f7bcf8..5823dd45 100644 --- a/labwc.h +++ b/labwc.h @@ -144,6 +144,15 @@ void xwl_surface_destroy(struct wl_listener *listener, void *data); void xwl_surface_configure(struct wl_listener *listener, void *data); void xwl_surface_new(struct wl_listener *listener, void *data); +/** + * view_get_surface_geometry - geometry relative to view + * @view: toplevel containing the surface to process + * Note: XDG views sometimes have an invisible border, so x and y can be + * greater than zero. + */ +struct wlr_box view_get_surface_geometry(struct view *view); +struct wlr_box view_geometry(struct view *view); +void view_resize(struct view *view, struct wlr_box geo); bool view_want_deco(struct view *view); void view_focus(struct view *view); struct view *view_front_toplevel(struct server *server); diff --git a/output.c b/output.c index 8cd684bb..60bc22ae 100644 --- a/output.c +++ b/output.c @@ -7,31 +7,6 @@ struct render_data { struct timespec *when; }; -static void render_grab(struct output *output) -{ - if (output->server->cursor_mode == TINYWL_CURSOR_PASSTHROUGH) - return; - - if (output->server->cursor_mode == TINYWL_CURSOR_RESIZE) { - float grab_box_color[] = { 0.0, 1.0, 0.0, 0.3 }; - wlr_render_rect(output->server->renderer, - &output->server->grab_box, grab_box_color, - output->wlr_output->transform_matrix); - } - - float grab_point_color[] = { 1.0, 0.0, 1.0, 1.0 }; - struct wlr_box point = { .x = output->server->grab_x + - output->server->grabbed_view->x - 1, - .y = output->server->grab_y + - output->server->grabbed_view->y - 1, - .width = 3, - .height = 3 }; - fprintf(stderr, "XX grab_x=%f; grab_y=%f\n", output->server->grab_x, - output->server->grab_y); - wlr_render_rect(output->server->renderer, &point, grab_point_color, - output->wlr_output->transform_matrix); -} - static void render_cycle_box(struct output *output) { if (!output->server->cycle_view) @@ -40,7 +15,14 @@ static void render_cycle_box(struct output *output) wl_list_for_each_reverse (view, &output->server->views, link) { if (view != output->server->cycle_view) continue; - struct wlr_box box = deco_max_extents(view); + struct wlr_box box; + if ((view->type == LAB_XWAYLAND_VIEW) || LAB_DISABLE_CSD) { + box = deco_max_extents(view); + } else { + box = view_get_surface_geometry(view); + box.x += view->x; + box.y += view->y; + } float cycle_color[] = { 0.0, 0.0, 0.0, 0.2 }; wlr_render_rect(output->server->renderer, &box, cycle_color, output->wlr_output->transform_matrix); @@ -187,7 +169,6 @@ void output_frame(struct wl_listener *listener, void *data) /* If in cycle (alt-tab) mode, highlight selected view */ render_cycle_box(output); - render_grab(output); /* Hardware cursors are rendered by the GPU on a separate plane, and can * be moved around without re-rendering what's beneath them - which is diff --git a/server.c b/server.c index 52b89ee2..ae4706b2 100644 --- a/server.c +++ b/server.c @@ -1,65 +1,39 @@ #include "labwc.h" -static struct wlr_box view_geometry(struct view *view) -{ - struct wlr_box box = { 0 }; - switch (view->type) { - case LAB_XDG_SHELL_VIEW: - wlr_xdg_surface_get_geometry(view->xdg_surface, &box); - break; - case LAB_XWAYLAND_VIEW: - box.width = view->xwayland_surface->width; - box.height = view->xwayland_surface->height; - break; - } - return box; -} +#define MIN_VIEW_WIDTH (100) +#define MIN_VIEW_HEIGHT (60) void begin_interactive(struct view *view, enum cursor_mode mode, uint32_t edges) { - /* This function sets up an interactive move or resize operation, where + /* + * This function sets up an interactive move or resize operation, where * the compositor stops propegating pointer events to clients and - * instead consumes them itself, to move or resize windows. */ + * instead consumes them itself, to move or resize windows. + */ struct server *server = view->server; server->grabbed_view = view; server->cursor_mode = mode; - switch (mode) { - case TINYWL_CURSOR_MOVE: - server->grab_x = server->cursor->x - view->x; - server->grab_y = server->cursor->y - view->y; - break; - case TINYWL_CURSOR_RESIZE: { - struct wlr_box geo_box = view_geometry(view); - double border_x = - (view->x + geo_box.x) + - ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); - double border_y = - (view->y + geo_box.y) + - ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); - server->grab_x = server->cursor->x - border_x; - server->grab_y = server->cursor->y - border_y; - server->grab_box = geo_box; - server->grab_box.x += view->x; - server->grab_box.y += view->y; - server->resize_edges = edges; - } break; - default: - break; - } + /* Remember view and cursor positions at start of move/resize */ + server->grab_x = server->cursor->x; + server->grab_y = server->cursor->y; + server->grab_box = view_geometry(view); + server->resize_edges = edges; } static void keyboard_handle_modifiers(struct wl_listener *listener, void *data) { - /* This event is raised when a modifier key, such as shift or alt, is - * pressed. We simply communicate this to the client. */ + /* + * This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. + */ struct keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); /* * A seat can only have one keyboard, but this is a limitation of the * Wayland protocol - not wlroots. We assign all connected keyboards to - * the same seat. You can swap out the underlying wlr_keyboard like this - * and wlr_seat handles this transparently. + * the same seat. You can swap out the underlying wlr_keyboard like + * this and wlr_seat handles this transparently. */ wlr_seat_set_keyboard(keyboard->server->seat, keyboard->device); /* Send modifiers to the client. */ @@ -160,8 +134,10 @@ static void server_new_keyboard(struct server *server, keyboard->server = server; keyboard->device = device; - /* We need to prepare an XKB keymap and assign it to the keyboard. This - * assumes the defaults (e.g. layout = "us"). */ + /* + * We need to prepare an XKB keymap and assign it to the keyboard. This + * assumes the defaults (e.g. layout = "us"). + */ struct xkb_rule_names rules = { 0 }; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_keymap *keymap = xkb_map_new_from_names( @@ -188,17 +164,16 @@ static void server_new_keyboard(struct server *server, static void server_new_pointer(struct server *server, struct wlr_input_device *device) { - /* We don't do anything special with pointers. All of our pointer - * handling is proxied through wlr_cursor. On another compositor, you - * might take this opportunity to do libinput configuration on the - * device to set acceleration, etc. */ + /* TODO: Configure libinput on device to set tap, acceleration, etc */ wlr_cursor_attach_input_device(server->cursor, device); } void server_new_input(struct wl_listener *listener, void *data) { - /* This event is raised by the backend when a new input device becomes - * available. */ + /* + * This event is raised by the backend when a new input device becomes + * available. + */ struct server *server = wl_container_of(listener, server, new_input); struct wlr_input_device *device = data; switch (device->type) { @@ -211,10 +186,11 @@ void server_new_input(struct wl_listener *listener, void *data) default: break; } - /* We need to let the wlr_seat know what our capabilities are, which is - * communiciated to the client. In TinyWL we always have a cursor, even - * if there are no pointer devices, so we always include that - * capability. */ + + /* + * We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. + */ uint32_t caps = WL_SEAT_CAPABILITY_POINTER; if (!wl_list_empty(&server->keyboards)) { caps |= WL_SEAT_CAPABILITY_KEYBOARD; @@ -226,11 +202,14 @@ void seat_request_cursor(struct wl_listener *listener, void *data) { struct server *server = wl_container_of(listener, server, request_cursor); - /* This event is rasied by the seat when a client provides a cursor - * image */ + /* + * This event is rasied by the seat when a client provides a cursor + * image + */ struct wlr_seat_pointer_request_set_cursor_event *event = data; struct wlr_seat_client *focused_client = server->seat->pointer_state.focused_client; + /* This can be sent by any client, so we check to make sure this one is * actually has pointer focus first. */ if (focused_client == event->seat_client) { @@ -254,17 +233,18 @@ void seat_request_set_selection(struct wl_listener *listener, void *data) static void process_cursor_move(struct server *server, uint32_t time) { /* Move the grabbed view to the new position. */ - server->grabbed_view->x = server->cursor->x - server->grab_x; - server->grabbed_view->y = server->cursor->y - server->grab_y; + double dx = server->cursor->x - server->grab_x; + double dy = server->cursor->y - server->grab_y; + server->grabbed_view->x = server->grab_box.x + dx; + server->grabbed_view->y = server->grab_box.y + dy; + + if (server->grabbed_view->type != LAB_XWAYLAND_VIEW) + return; struct view *view = server->grabbed_view; - if (view->type == LAB_XWAYLAND_VIEW) { - wlr_xwayland_surface_configure(view->xwayland_surface, - server->grabbed_view->x, - server->grabbed_view->y, - view->xwayland_surface->width, - view->xwayland_surface->height); - } + wlr_xwayland_surface_configure(view->xwayland_surface, view->x, view->y, + view->xwayland_surface->width, + view->xwayland_surface->height); } static void process_cursor_resize(struct server *server, uint32_t time) @@ -273,49 +253,34 @@ static void process_cursor_resize(struct server *server, uint32_t time) * TODO: Wait for the client to prepare a buffer at the new size, then * commit any movement that was prepared. */ + double dx = server->cursor->x - server->grab_x; + double dy = server->cursor->y - server->grab_y; + struct view *view = server->grabbed_view; - double border_x = server->cursor->x - server->grab_x; - double border_y = server->cursor->y - server->grab_y; - int new_left = server->grab_box.x; - int new_right = server->grab_box.x + server->grab_box.width; - int new_top = server->grab_box.y; - int new_bottom = server->grab_box.y + server->grab_box.height; + struct wlr_box new_view_geo = view_geometry(view); if (server->resize_edges & WLR_EDGE_TOP) { - new_top = border_y; - if (new_top >= new_bottom) - new_top = new_bottom - 1; + new_view_geo.y = server->grab_box.y + dy; + new_view_geo.height = server->grab_box.height - dy; } else if (server->resize_edges & WLR_EDGE_BOTTOM) { - new_bottom = border_y; - if (new_bottom <= new_top) - new_bottom = new_top + 1; + new_view_geo.height = server->grab_box.height + dy; } if (server->resize_edges & WLR_EDGE_LEFT) { - new_left = border_x; - if (new_left >= new_right) - new_left = new_right - 1; + new_view_geo.x = server->grab_box.x + dx; + new_view_geo.width = server->grab_box.width - dx; } else if (server->resize_edges & WLR_EDGE_RIGHT) { - new_right = border_x; - if (new_right <= new_left) - new_right = new_left + 1; + new_view_geo.width = server->grab_box.width + dx; } + if ((new_view_geo.height < MIN_VIEW_HEIGHT) || + (new_view_geo.width < MIN_VIEW_WIDTH)) + return; - struct wlr_box geo_box = view_geometry(view); - view->x = new_left - geo_box.x; - view->y = new_top - geo_box.y; + /* Move */ + view->x = new_view_geo.x; + view->y = new_view_geo.y; - int new_width = new_right - new_left; - int new_height = new_bottom - new_top; - switch (view->type) { - case LAB_XDG_SHELL_VIEW: - wlr_xdg_toplevel_set_size(view->xdg_surface, new_width, - new_height); - break; - case LAB_XWAYLAND_VIEW: - wlr_xwayland_surface_configure(view->xwayland_surface, view->x, - view->y, new_width, new_height); - break; - } + /* Resize */ + view_resize(view, new_view_geo); } static void process_cursor_motion(struct server *server, uint32_t time) diff --git a/view.c b/view.c index ea0b33c2..3dc03070 100644 --- a/view.c +++ b/view.c @@ -1,5 +1,51 @@ #include "labwc.h" +struct wlr_box view_get_surface_geometry(struct view *view) +{ + struct wlr_box box = { 0 }; + switch (view->type) { + case LAB_XDG_SHELL_VIEW: + wlr_xdg_surface_get_geometry(view->xdg_surface, &box); + break; + case LAB_XWAYLAND_VIEW: + box.width = view->xwayland_surface->width; + box.height = view->xwayland_surface->height; + break; + } + return box; +} + +/* Get geometry relative to screen */ +struct wlr_box view_geometry(struct view *view) +{ + struct wlr_box b = view_get_surface_geometry(view); + /* Add XDG view invisible border if it exists */ + b.width += 2 * b.x; + b.height += 2 * b.y; + /* Make co-ordinates relative to screen */ + b.x = view->x; + b.y = view->y; + return b; +} + +void view_resize(struct view *view, struct wlr_box geo) +{ + struct wlr_box border = view_get_surface_geometry(view); + switch (view->type) { + case LAB_XDG_SHELL_VIEW: + wlr_xdg_toplevel_set_size(view->xdg_surface, + geo.width - 2 * border.x, + geo.height - 2 * border.y); + break; + case LAB_XWAYLAND_VIEW: + wlr_xwayland_surface_configure(view->xwayland_surface, view->x, + view->y, geo.width, geo.height); + break; + default: + break; + } +} + static bool is_toplevel(struct view *view) { switch (view->type) { -- 2.52.0