seatop_resize_floating.c (6488B) - View raw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195#include <limits.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_xcursor_manager.h> #include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/tree/arrange.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "sway/tree/container.h" struct seatop_resize_floating_event { struct sway_container *con; enum wlr_edges edge; bool preserve_ratio; double ref_lx, ref_ly; // cursor's x/y at start of op double ref_width, ref_height; // container's size at start of op double ref_con_lx, ref_con_ly; // container's x/y at start of op }; static void handle_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wl_pointer_button_state state) { struct seatop_resize_floating_event *e = seat->seatop_data; struct sway_container *con = e->con; if (seat->cursor->pressed_button_count == 0) { container_set_resizing(con, false); arrange_container(con); // Send configure w/o resizing hint transaction_commit_dirty(); seatop_begin_default(seat); } } static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { struct seatop_resize_floating_event *e = seat->seatop_data; struct sway_container *con = e->con; enum wlr_edges edge = e->edge; struct sway_cursor *cursor = seat->cursor; // The amount the mouse has moved since the start of the resize operation // Positive is down/right double mouse_move_x = cursor->cursor->x - e->ref_lx; double mouse_move_y = cursor->cursor->y - e->ref_ly; if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { mouse_move_x = 0; } if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { mouse_move_y = 0; } double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x; double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y; if (e->preserve_ratio) { double x_multiplier = grow_width / e->ref_width; double y_multiplier = grow_height / e->ref_height; double max_multiplier = fmax(x_multiplier, y_multiplier); grow_width = e->ref_width * max_multiplier; grow_height = e->ref_height * max_multiplier; } struct sway_container_state *state = &con->current; double border_width = 0.0; if (con->current.border == B_NORMAL || con->current.border == B_PIXEL) { border_width = state->border_thickness * 2; } double border_height = 0.0; if (con->current.border == B_NORMAL) { border_height += container_titlebar_height(); border_height += state->border_thickness; } else if (con->current.border == B_PIXEL) { border_height += state->border_thickness * 2; } // Determine new width/height, and accommodate for floating min/max values double width = e->ref_width + grow_width; double height = e->ref_height + grow_height; int min_width, max_width, min_height, max_height; floating_calculate_constraints(&min_width, &max_width, &min_height, &max_height); width = fmin(width, max_width - border_width); width = fmax(width, min_width + border_width); width = fmax(width, 1); height = fmin(height, max_height - border_height); height = fmax(height, min_height + border_height); height = fmax(height, 1); // Apply the view's min/max size if (con->view) { double view_min_width, view_max_width, view_min_height, view_max_height; view_get_constraints(con->view, &view_min_width, &view_max_width, &view_min_height, &view_max_height); width = fmin(width, view_max_width - border_width); width = fmax(width, view_min_width + border_width); width = fmax(width, 1); height = fmin(height, view_max_height - border_height); height = fmax(height, view_min_height + border_height); height = fmax(height, 1); } // Recalculate these, in case we hit a min/max limit grow_width = width - e->ref_width; grow_height = height - e->ref_height; // Determine grow x/y values - these are relative to the container's x/y at // the start of the resize operation. double grow_x = 0, grow_y = 0; if (edge & WLR_EDGE_LEFT) { grow_x = -grow_width; } else if (edge & WLR_EDGE_RIGHT) { grow_x = 0; } else { grow_x = -grow_width / 2; } if (edge & WLR_EDGE_TOP) { grow_y = -grow_height; } else if (edge & WLR_EDGE_BOTTOM) { grow_y = 0; } else { grow_y = -grow_height / 2; } // Determine the amounts we need to bump everything relative to the current // size. int relative_grow_width = width - con->pending.width; int relative_grow_height = height - con->pending.height; int relative_grow_x = (e->ref_con_lx + grow_x) - con->pending.x; int relative_grow_y = (e->ref_con_ly + grow_y) - con->pending.y; // Actually resize stuff con->pending.x += relative_grow_x; con->pending.y += relative_grow_y; con->pending.width += relative_grow_width; con->pending.height += relative_grow_height; con->pending.content_x += relative_grow_x; con->pending.content_y += relative_grow_y; con->pending.content_width += relative_grow_width; con->pending.content_height += relative_grow_height; arrange_container(con); transaction_commit_dirty(); } static void handle_unref(struct sway_seat *seat, struct sway_container *con) { struct seatop_resize_floating_event *e = seat->seatop_data; if (e->con == con) { seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { .button = handle_button, .pointer_motion = handle_pointer_motion, .unref = handle_unref, }; void seatop_begin_resize_floating(struct sway_seat *seat, struct sway_container *con, enum wlr_edges edge) { seatop_end(seat); struct seatop_resize_floating_event *e = calloc(1, sizeof(struct seatop_resize_floating_event)); if (!e) { return; } e->con = con; struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); e->preserve_ratio = keyboard && (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; e->ref_lx = seat->cursor->cursor->x; e->ref_ly = seat->cursor->cursor->y; e->ref_con_lx = con->pending.x; e->ref_con_ly = con->pending.y; e->ref_width = con->pending.width; e->ref_height = con->pending.height; seat->seatop_impl = &seatop_impl; seat->seatop_data = e; container_set_resizing(con, true); container_raise_floating(con); transaction_commit_dirty(); const char *image = edge == WLR_EDGE_NONE ? "se-resize" : wlr_xcursor_get_resize_name(edge); cursor_set_image(seat->cursor, image, NULL); wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); }