diff options
-rw-r--r-- | include/sway/commands.h | 5 | ||||
-rw-r--r-- | sway/commands/resize.c | 246 | ||||
-rw-r--r-- | sway/input/seatop_resize_tiling.c | 67 |
3 files changed, 140 insertions, 178 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index 657f909e..68487879 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -92,9 +92,12 @@ struct cmd_results *add_color(char *buffer, const char *color); | |||
92 | /** | 92 | /** |
93 | * TODO: Move this function and its dependent functions to container.c. | 93 | * TODO: Move this function and its dependent functions to container.c. |
94 | */ | 94 | */ |
95 | void container_resize_tiled(struct sway_container *parent, enum wlr_edges edge, | 95 | void container_resize_tiled(struct sway_container *parent, uint32_t axis, |
96 | int amount); | 96 | int amount); |
97 | 97 | ||
98 | struct sway_container *container_find_resize_parent(struct sway_container *con, | ||
99 | uint32_t edge); | ||
100 | |||
98 | sway_cmd cmd_assign; | 101 | sway_cmd cmd_assign; |
99 | sway_cmd cmd_bar; | 102 | sway_cmd cmd_bar; |
100 | sway_cmd cmd_bindcode; | 103 | sway_cmd cmd_bindcode; |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index fad1ecb1..6cdeb90c 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -130,177 +130,117 @@ static bool is_horizontal(uint32_t axis) { | |||
130 | return axis & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); | 130 | return axis & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); |
131 | } | 131 | } |
132 | 132 | ||
133 | static int parallel_coord(struct sway_container *c, uint32_t axis) { | 133 | struct sway_container *container_find_resize_parent(struct sway_container *con, |
134 | return is_horizontal(axis) ? c->x : c->y; | 134 | uint32_t axis) { |
135 | } | 135 | enum sway_container_layout parallel_layout = |
136 | 136 | is_horizontal(axis) ? L_HORIZ : L_VERT; | |
137 | static int parallel_size(struct sway_container *c, uint32_t axis) { | 137 | bool allow_first = axis != WLR_EDGE_TOP && axis != WLR_EDGE_LEFT; |
138 | return is_horizontal(axis) ? c->width : c->height; | 138 | bool allow_last = axis != WLR_EDGE_RIGHT && axis != WLR_EDGE_BOTTOM; |
139 | } | 139 | |
140 | 140 | while (con) { | |
141 | static void container_recursive_resize(struct sway_container *container, | 141 | list_t *siblings = container_get_siblings(con); |
142 | double amount, enum wlr_edges edge) { | 142 | int index = container_sibling_index(con); |
143 | bool layout_match = true; | 143 | if (container_parent_layout(con) == parallel_layout && |
144 | wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); | 144 | siblings->length > 1 && (allow_first || index > 0) && |
145 | if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { | 145 | (allow_last || index < siblings->length - 1)) { |
146 | container->width += amount; | 146 | return con; |
147 | layout_match = container->layout == L_HORIZ; | ||
148 | } else if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { | ||
149 | container->height += amount; | ||
150 | layout_match = container->layout == L_VERT; | ||
151 | } | ||
152 | if (container->children) { | ||
153 | for (int i = 0; i < container->children->length; i++) { | ||
154 | struct sway_container *child = container->children->items[i]; | ||
155 | double amt = layout_match ? | ||
156 | amount / container->children->length : amount; | ||
157 | container_recursive_resize(child, amt, edge); | ||
158 | } | 147 | } |
148 | con = con->parent; | ||
159 | } | 149 | } |
150 | |||
151 | return NULL; | ||
160 | } | 152 | } |
161 | 153 | ||
162 | static void resize_tiled(struct sway_container *parent, int amount, | 154 | void container_resize_tiled(struct sway_container *con, |
163 | uint32_t axis) { | 155 | uint32_t axis, int amount) { |
164 | struct sway_container *focused = parent; | 156 | if (!con) { |
165 | if (!parent) { | ||
166 | return; | 157 | return; |
167 | } | 158 | } |
168 | 159 | ||
169 | enum sway_container_layout parallel_layout = | 160 | con = container_find_resize_parent(con, axis); |
170 | is_horizontal(axis) ? L_HORIZ : L_VERT; | 161 | if (!con) { |
171 | int minor_weight = 0; | ||
172 | int major_weight = 0; | ||
173 | while (parent) { | ||
174 | list_t *siblings = container_get_siblings(parent); | ||
175 | if (container_parent_layout(parent) == parallel_layout) { | ||
176 | for (int i = 0; i < siblings->length; i++) { | ||
177 | struct sway_container *sibling = siblings->items[i]; | ||
178 | |||
179 | int sibling_pos = parallel_coord(sibling, axis); | ||
180 | int focused_pos = parallel_coord(focused, axis); | ||
181 | int parent_pos = parallel_coord(parent, axis); | ||
182 | |||
183 | if (sibling_pos != focused_pos) { | ||
184 | if (sibling_pos < parent_pos) { | ||
185 | minor_weight++; | ||
186 | } else if (sibling_pos > parent_pos) { | ||
187 | major_weight++; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | if (major_weight || minor_weight) { | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | parent = parent->parent; | ||
196 | } | ||
197 | if (!parent) { | ||
198 | // Can't resize in this direction | 162 | // Can't resize in this direction |
199 | return; | 163 | return; |
200 | } | 164 | } |
201 | 165 | ||
202 | // Implement up/down/left/right direction by zeroing one of the weights | 166 | // For HORIZONTAL or VERTICAL, we are growing in two directions so select |
203 | if (axis == WLR_EDGE_TOP || axis == WLR_EDGE_LEFT) { | 167 | // both adjacent siblings. For RIGHT or DOWN, just select the next sibling. |
204 | major_weight = 0; | 168 | // For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to |
205 | } else if (axis == WLR_EDGE_RIGHT || axis == WLR_EDGE_BOTTOM) { | 169 | // the previous sibling. |
206 | minor_weight = 0; | 170 | struct sway_container *prev = NULL; |
207 | } | 171 | struct sway_container *next = NULL; |
208 | 172 | list_t *siblings = container_get_siblings(con); | |
209 | bool horizontal = is_horizontal(axis); | 173 | int index = container_sibling_index(con); |
210 | int min_sane = horizontal ? MIN_SANE_W : MIN_SANE_H; | 174 | |
211 | 175 | if (axis == AXIS_HORIZONTAL || axis == AXIS_VERTICAL) { | |
212 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | 176 | if (index == 0) { |
213 | // ^ ????? | 177 | next = siblings->items[1]; |
214 | list_t *siblings = container_get_siblings(parent); | 178 | } else if (index == siblings->length - 1) { |
215 | 179 | // Convert edge to top/left | |
216 | for (int i = 0; i < siblings->length; i++) { | 180 | next = con; |
217 | struct sway_container *sibling = siblings->items[i]; | 181 | con = siblings->items[index - 1]; |
218 | 182 | amount = -amount; | |
219 | int sibling_pos = parallel_coord(sibling, axis); | ||
220 | int focused_pos = parallel_coord(focused, axis); | ||
221 | int parent_pos = parallel_coord(parent, axis); | ||
222 | |||
223 | int sibling_size = parallel_size(sibling, axis); | ||
224 | int parent_size = parallel_size(parent, axis); | ||
225 | |||
226 | if (sibling_pos != focused_pos) { | ||
227 | if (sibling_pos < parent_pos && minor_weight) { | ||
228 | double pixels = -amount / minor_weight; | ||
229 | if (major_weight && (sibling_size + pixels / 2) < min_sane) { | ||
230 | return; // Too small | ||
231 | } else if (!major_weight && sibling_size + pixels < min_sane) { | ||
232 | return; // Too small | ||
233 | } | ||
234 | } else if (sibling_pos > parent_pos && major_weight) { | ||
235 | double pixels = -amount / major_weight; | ||
236 | if (minor_weight && (sibling_size + pixels / 2) < min_sane) { | ||
237 | return; // Too small | ||
238 | } else if (!minor_weight && sibling_size + pixels < min_sane) { | ||
239 | return; // Too small | ||
240 | } | ||
241 | } | ||
242 | } else { | 183 | } else { |
243 | double pixels = amount; | 184 | prev = siblings->items[index - 1]; |
244 | if (parent_size + pixels < min_sane) { | 185 | next = siblings->items[index + 1]; |
245 | return; // Too small | 186 | } |
246 | } | 187 | } else if (axis == WLR_EDGE_TOP || axis == WLR_EDGE_LEFT) { |
188 | if (!sway_assert(index > 0, "Didn't expect first child")) { | ||
189 | return; | ||
247 | } | 190 | } |
191 | next = con; | ||
192 | con = siblings->items[index - 1]; | ||
193 | amount = -amount; | ||
194 | } else { | ||
195 | if (!sway_assert(index < siblings->length - 1, | ||
196 | "Didn't expect last child")) { | ||
197 | return; | ||
198 | } | ||
199 | next = siblings->items[index + 1]; | ||
248 | } | 200 | } |
249 | 201 | ||
250 | enum wlr_edges minor_edge = horizontal ? WLR_EDGE_LEFT : WLR_EDGE_TOP; | 202 | // Apply new dimensions |
251 | enum wlr_edges major_edge = horizontal ? WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; | 203 | int sibling_amount = prev ? amount / 2 : amount; |
252 | 204 | ||
253 | for (int i = 0; i < siblings->length; i++) { | 205 | if (is_horizontal(axis)) { |
254 | struct sway_container *sibling = siblings->items[i]; | 206 | if (con->width + amount < MIN_SANE_W) { |
255 | 207 | return; | |
256 | int sibling_pos = parallel_coord(sibling, axis); | 208 | } |
257 | int focused_pos = parallel_coord(focused, axis); | 209 | if (next->width - sibling_amount < MIN_SANE_W) { |
258 | int parent_pos = parallel_coord(parent, axis); | 210 | return; |
259 | 211 | } | |
260 | if (sibling_pos != focused_pos) { | 212 | if (prev && prev->width - sibling_amount < MIN_SANE_W) { |
261 | if (sibling_pos < parent_pos && minor_weight) { | 213 | return; |
262 | double pixels = -1 * amount; | 214 | } |
263 | pixels /= minor_weight; | 215 | con->width += amount; |
264 | if (major_weight) { | 216 | next->width -= sibling_amount; |
265 | container_recursive_resize(sibling, pixels / 2, major_edge); | 217 | if (prev) { |
266 | } else { | 218 | prev->width -= sibling_amount; |
267 | container_recursive_resize(sibling, pixels, major_edge); | 219 | } |
268 | } | 220 | } else { |
269 | } else if (sibling_pos > parent_pos && major_weight) { | 221 | if (con->height + amount < MIN_SANE_H) { |
270 | double pixels = -1 * amount; | 222 | return; |
271 | pixels /= major_weight; | 223 | } |
272 | if (minor_weight) { | 224 | if (next->height - sibling_amount < MIN_SANE_H) { |
273 | container_recursive_resize(sibling, pixels / 2, minor_edge); | 225 | return; |
274 | } else { | 226 | } |
275 | container_recursive_resize(sibling, pixels, minor_edge); | 227 | if (prev && prev->height - sibling_amount < MIN_SANE_H) { |
276 | } | 228 | return; |
277 | } | 229 | } |
278 | } else { | 230 | con->height += amount; |
279 | if (major_weight != 0 && minor_weight != 0) { | 231 | next->height -= sibling_amount; |
280 | double pixels = amount; | 232 | if (prev) { |
281 | pixels /= 2; | 233 | prev->height -= sibling_amount; |
282 | container_recursive_resize(parent, pixels, minor_edge); | ||
283 | container_recursive_resize(parent, pixels, major_edge); | ||
284 | } else if (major_weight) { | ||
285 | container_recursive_resize(parent, amount, major_edge); | ||
286 | } else if (minor_weight) { | ||
287 | container_recursive_resize(parent, amount, minor_edge); | ||
288 | } | ||
289 | } | 234 | } |
290 | } | 235 | } |
291 | 236 | ||
292 | if (parent->parent) { | 237 | if (con->parent) { |
293 | arrange_container(parent->parent); | 238 | arrange_container(con->parent); |
294 | } else { | 239 | } else { |
295 | arrange_workspace(parent->workspace); | 240 | arrange_workspace(con->workspace); |
296 | } | 241 | } |
297 | } | 242 | } |
298 | 243 | ||
299 | void container_resize_tiled(struct sway_container *parent, | ||
300 | enum wlr_edges edge, int amount) { | ||
301 | resize_tiled(parent, amount, edge); | ||
302 | } | ||
303 | |||
304 | /** | 244 | /** |
305 | * Implement `resize <grow|shrink>` for a floating container. | 245 | * Implement `resize <grow|shrink>` for a floating container. |
306 | */ | 246 | */ |
@@ -379,7 +319,7 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis, | |||
379 | 319 | ||
380 | double old_width = current->width; | 320 | double old_width = current->width; |
381 | double old_height = current->height; | 321 | double old_height = current->height; |
382 | resize_tiled(current, amount->amount, axis); | 322 | container_resize_tiled(current, axis, amount->amount); |
383 | if (current->width == old_width && current->height == old_height) { | 323 | if (current->width == old_width && current->height == old_height) { |
384 | return cmd_results_new(CMD_INVALID, "Cannot resize any further"); | 324 | return cmd_results_new(CMD_INVALID, "Cannot resize any further"); |
385 | } | 325 | } |
@@ -407,7 +347,8 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
407 | width->unit = RESIZE_UNIT_PX; | 347 | width->unit = RESIZE_UNIT_PX; |
408 | } | 348 | } |
409 | if (width->unit == RESIZE_UNIT_PX) { | 349 | if (width->unit == RESIZE_UNIT_PX) { |
410 | resize_tiled(con, width->amount - con->width, AXIS_HORIZONTAL); | 350 | container_resize_tiled(con, AXIS_HORIZONTAL, |
351 | width->amount - con->width); | ||
411 | } | 352 | } |
412 | } | 353 | } |
413 | 354 | ||
@@ -427,7 +368,8 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
427 | height->unit = RESIZE_UNIT_PX; | 368 | height->unit = RESIZE_UNIT_PX; |
428 | } | 369 | } |
429 | if (height->unit == RESIZE_UNIT_PX) { | 370 | if (height->unit == RESIZE_UNIT_PX) { |
430 | resize_tiled(con, height->amount - con->height, AXIS_VERTICAL); | 371 | container_resize_tiled(con, AXIS_VERTICAL, |
372 | height->amount - con->height); | ||
431 | } | 373 | } |
432 | } | 374 | } |
433 | 375 | ||
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c index 30431f04..cb0f723d 100644 --- a/sway/input/seatop_resize_tiling.c +++ b/sway/input/seatop_resize_tiling.c | |||
@@ -1,15 +1,22 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
3 | #include <wlr/util/edges.h> | ||
3 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
4 | #include "sway/input/cursor.h" | 5 | #include "sway/input/cursor.h" |
5 | #include "sway/input/seat.h" | 6 | #include "sway/input/seat.h" |
6 | 7 | ||
7 | struct seatop_resize_tiling_event { | 8 | struct seatop_resize_tiling_event { |
8 | struct sway_container *con; | 9 | struct sway_container *con; // leaf container |
10 | |||
11 | // con, or ancestor of con which will be resized horizontally/vertically | ||
12 | struct sway_container *h_con; | ||
13 | struct sway_container *v_con; | ||
14 | |||
9 | enum wlr_edges edge; | 15 | enum wlr_edges edge; |
16 | enum wlr_edges edge_x, edge_y; | ||
10 | double ref_lx, ref_ly; // cursor's x/y at start of op | 17 | double ref_lx, ref_ly; // cursor's x/y at start of op |
11 | double ref_width, ref_height; // container's size at start of op | 18 | double h_con_orig_width; // width of the horizontal ancestor at start |
12 | double ref_con_lx, ref_con_ly; // container's x/y at start of op | 19 | double v_con_orig_height; // height of the vertical ancestor at start |
13 | }; | 20 | }; |
14 | 21 | ||
15 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 22 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { |
@@ -18,30 +25,27 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
18 | int amount_y = 0; | 25 | int amount_y = 0; |
19 | int moved_x = seat->cursor->cursor->x - e->ref_lx; | 26 | int moved_x = seat->cursor->cursor->x - e->ref_lx; |
20 | int moved_y = seat->cursor->cursor->y - e->ref_ly; | 27 | int moved_y = seat->cursor->cursor->y - e->ref_ly; |
21 | enum wlr_edges edge_x = WLR_EDGE_NONE; | 28 | |
22 | enum wlr_edges edge_y = WLR_EDGE_NONE; | 29 | if (e->h_con) { |
23 | struct sway_container *con = e->con; | 30 | if (e->edge & WLR_EDGE_LEFT) { |
24 | 31 | amount_x = (e->h_con_orig_width - moved_x) - e->h_con->width; | |
25 | if (e->edge & WLR_EDGE_TOP) { | 32 | } else if (e->edge & WLR_EDGE_RIGHT) { |
26 | amount_y = (e->ref_height - moved_y) - con->height; | 33 | amount_x = (e->h_con_orig_width + moved_x) - e->h_con->width; |
27 | edge_y = WLR_EDGE_TOP; | 34 | } |
28 | } else if (e->edge & WLR_EDGE_BOTTOM) { | ||
29 | amount_y = (e->ref_height + moved_y) - con->height; | ||
30 | edge_y = WLR_EDGE_BOTTOM; | ||
31 | } | 35 | } |
32 | if (e->edge & WLR_EDGE_LEFT) { | 36 | if (e->v_con) { |
33 | amount_x = (e->ref_width - moved_x) - con->width; | 37 | if (e->edge & WLR_EDGE_TOP) { |
34 | edge_x = WLR_EDGE_LEFT; | 38 | amount_y = (e->v_con_orig_height - moved_y) - e->v_con->height; |
35 | } else if (e->edge & WLR_EDGE_RIGHT) { | 39 | } else if (e->edge & WLR_EDGE_BOTTOM) { |
36 | amount_x = (e->ref_width + moved_x) - con->width; | 40 | amount_y = (e->v_con_orig_height + moved_y) - e->v_con->height; |
37 | edge_x = WLR_EDGE_RIGHT; | 41 | } |
38 | } | 42 | } |
39 | 43 | ||
40 | if (amount_x != 0) { | 44 | if (amount_x != 0) { |
41 | container_resize_tiled(e->con, edge_x, amount_x); | 45 | container_resize_tiled(e->h_con, e->edge_x, amount_x); |
42 | } | 46 | } |
43 | if (amount_y != 0) { | 47 | if (amount_y != 0) { |
44 | container_resize_tiled(e->con, edge_y, amount_y); | 48 | container_resize_tiled(e->v_con, e->edge_y, amount_y); |
45 | } | 49 | } |
46 | } | 50 | } |
47 | 51 | ||
@@ -81,10 +85,23 @@ void seatop_begin_resize_tiling(struct sway_seat *seat, | |||
81 | 85 | ||
82 | e->ref_lx = seat->cursor->cursor->x; | 86 | e->ref_lx = seat->cursor->cursor->x; |
83 | e->ref_ly = seat->cursor->cursor->y; | 87 | e->ref_ly = seat->cursor->cursor->y; |
84 | e->ref_con_lx = con->x; | 88 | |
85 | e->ref_con_ly = con->y; | 89 | if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { |
86 | e->ref_width = con->width; | 90 | e->edge_x = edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); |
87 | e->ref_height = con->height; | 91 | e->h_con = container_find_resize_parent(e->con, e->edge_x); |
92 | |||
93 | if (e->h_con) { | ||
94 | e->h_con_orig_width = e->h_con->width; | ||
95 | } | ||
96 | } | ||
97 | if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { | ||
98 | e->edge_y = edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM); | ||
99 | e->v_con = container_find_resize_parent(e->con, e->edge_y); | ||
100 | |||
101 | if (e->v_con) { | ||
102 | e->v_con_orig_height = e->v_con->height; | ||
103 | } | ||
104 | } | ||
88 | 105 | ||
89 | seat->seatop_impl = &seatop_impl; | 106 | seat->seatop_impl = &seatop_impl; |
90 | seat->seatop_data = e; | 107 | seat->seatop_data = e; |