diff options
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 160 |
1 files changed, 156 insertions, 4 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 69a019bb..dc66d82d 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -26,6 +26,10 @@ | |||
26 | #include "sway/tree/workspace.h" | 26 | #include "sway/tree/workspace.h" |
27 | #include "wlr-layer-shell-unstable-v1-protocol.h" | 27 | #include "wlr-layer-shell-unstable-v1-protocol.h" |
28 | 28 | ||
29 | // When doing a tiling drag, this is the thickness of the dropzone | ||
30 | // when dragging to the edge of a layout container. | ||
31 | #define DROP_LAYOUT_BORDER 30 | ||
32 | |||
29 | static uint32_t get_current_time_msec() { | 33 | static uint32_t get_current_time_msec() { |
30 | struct timespec now; | 34 | struct timespec now; |
31 | clock_gettime(CLOCK_MONOTONIC, &now); | 35 | clock_gettime(CLOCK_MONOTONIC, &now); |
@@ -218,7 +222,7 @@ static void handle_down_motion(struct sway_seat *seat, | |||
218 | seat->op_moved = true; | 222 | seat->op_moved = true; |
219 | } | 223 | } |
220 | 224 | ||
221 | static void handle_move_motion(struct sway_seat *seat, | 225 | static void handle_move_floating_motion(struct sway_seat *seat, |
222 | struct sway_cursor *cursor) { | 226 | struct sway_cursor *cursor) { |
223 | struct sway_container *con = seat->op_container; | 227 | struct sway_container *con = seat->op_container; |
224 | desktop_damage_whole_container(con); | 228 | desktop_damage_whole_container(con); |
@@ -228,6 +232,143 @@ static void handle_move_motion(struct sway_seat *seat, | |||
228 | desktop_damage_whole_container(con); | 232 | desktop_damage_whole_container(con); |
229 | } | 233 | } |
230 | 234 | ||
235 | static void resize_box(struct wlr_box *box, enum wlr_edges edge, | ||
236 | int thickness) { | ||
237 | switch (edge) { | ||
238 | case WLR_EDGE_TOP: | ||
239 | box->height = thickness; | ||
240 | break; | ||
241 | case WLR_EDGE_LEFT: | ||
242 | box->width = thickness; | ||
243 | break; | ||
244 | case WLR_EDGE_RIGHT: | ||
245 | box->x = box->x + box->width - thickness; | ||
246 | box->width = thickness; | ||
247 | break; | ||
248 | case WLR_EDGE_BOTTOM: | ||
249 | box->y = box->y + box->height - thickness; | ||
250 | box->height = thickness; | ||
251 | break; | ||
252 | case WLR_EDGE_NONE: | ||
253 | box->x += thickness; | ||
254 | box->y += thickness; | ||
255 | box->width -= thickness * 2; | ||
256 | box->height -= thickness * 2; | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static void handle_move_tiling_motion(struct sway_seat *seat, | ||
262 | struct sway_cursor *cursor) { | ||
263 | struct wlr_surface *surface = NULL; | ||
264 | double sx, sy; | ||
265 | struct sway_node *node = node_at_coords(seat, | ||
266 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
267 | // Damage the old location | ||
268 | desktop_damage_box(&seat->op_drop_box); | ||
269 | |||
270 | if (!node) { | ||
271 | // Eg. hovered over a layer surface such as swaybar | ||
272 | seat->op_target_node = NULL; | ||
273 | seat->op_target_edge = WLR_EDGE_NONE; | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | if (node->type == N_WORKSPACE) { | ||
278 | // Emtpy workspace | ||
279 | seat->op_target_node = node; | ||
280 | seat->op_target_edge = WLR_EDGE_NONE; | ||
281 | workspace_get_box(node->sway_workspace, &seat->op_drop_box); | ||
282 | desktop_damage_box(&seat->op_drop_box); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | // Deny moving within own workspace if this is the only child | ||
287 | struct sway_container *con = node->sway_container; | ||
288 | if (workspace_num_tiling_views(seat->op_container->workspace) == 1 && | ||
289 | con->workspace == seat->op_container->workspace) { | ||
290 | seat->op_target_node = NULL; | ||
291 | seat->op_target_edge = WLR_EDGE_NONE; | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | // Traverse the ancestors, trying to find a layout container perpendicular | ||
296 | // to the edge. Eg. close to the top or bottom of a horiz layout. | ||
297 | while (con) { | ||
298 | enum wlr_edges edge = WLR_EDGE_NONE; | ||
299 | enum sway_container_layout layout = container_parent_layout(con); | ||
300 | struct wlr_box parent; | ||
301 | con->parent ? container_get_box(con->parent, &parent) : | ||
302 | workspace_get_box(con->workspace, &parent); | ||
303 | if (layout == L_HORIZ || layout == L_TABBED) { | ||
304 | if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) { | ||
305 | edge = WLR_EDGE_TOP; | ||
306 | } else if (cursor->cursor->y > parent.y + parent.height | ||
307 | - DROP_LAYOUT_BORDER) { | ||
308 | edge = WLR_EDGE_BOTTOM; | ||
309 | } | ||
310 | } else if (layout == L_VERT || layout == L_STACKED) { | ||
311 | if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) { | ||
312 | edge = WLR_EDGE_LEFT; | ||
313 | } else if (cursor->cursor->x > parent.x + parent.width | ||
314 | - DROP_LAYOUT_BORDER) { | ||
315 | edge = WLR_EDGE_RIGHT; | ||
316 | } | ||
317 | } | ||
318 | if (edge) { | ||
319 | seat->op_target_node = node_get_parent(&con->node); | ||
320 | seat->op_target_edge = edge; | ||
321 | node_get_box(seat->op_target_node, &seat->op_drop_box); | ||
322 | resize_box(&seat->op_drop_box, edge, DROP_LAYOUT_BORDER); | ||
323 | desktop_damage_box(&seat->op_drop_box); | ||
324 | return; | ||
325 | } | ||
326 | con = con->parent; | ||
327 | } | ||
328 | |||
329 | // Use the hovered view - but we must be over the actual surface | ||
330 | con = node->sway_container; | ||
331 | if (!con->view->surface || node == &seat->op_container->node) { | ||
332 | seat->op_target_node = NULL; | ||
333 | seat->op_target_edge = WLR_EDGE_NONE; | ||
334 | return; | ||
335 | } | ||
336 | |||
337 | // Find the closest edge | ||
338 | size_t thickness = fmin(con->view->width, con->view->height) * 0.3; | ||
339 | size_t closest_dist = INT_MAX; | ||
340 | size_t dist; | ||
341 | seat->op_target_edge = WLR_EDGE_NONE; | ||
342 | if ((dist = cursor->cursor->y - con->y) < closest_dist) { | ||
343 | closest_dist = dist; | ||
344 | seat->op_target_edge = WLR_EDGE_TOP; | ||
345 | } | ||
346 | if ((dist = cursor->cursor->x - con->x) < closest_dist) { | ||
347 | closest_dist = dist; | ||
348 | seat->op_target_edge = WLR_EDGE_LEFT; | ||
349 | } | ||
350 | if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) { | ||
351 | closest_dist = dist; | ||
352 | seat->op_target_edge = WLR_EDGE_RIGHT; | ||
353 | } | ||
354 | if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) { | ||
355 | closest_dist = dist; | ||
356 | seat->op_target_edge = WLR_EDGE_BOTTOM; | ||
357 | } | ||
358 | |||
359 | if (closest_dist > thickness) { | ||
360 | seat->op_target_edge = WLR_EDGE_NONE; | ||
361 | } | ||
362 | |||
363 | seat->op_target_node = node; | ||
364 | seat->op_drop_box.x = con->view->x; | ||
365 | seat->op_drop_box.y = con->view->y; | ||
366 | seat->op_drop_box.width = con->view->width; | ||
367 | seat->op_drop_box.height = con->view->height; | ||
368 | resize_box(&seat->op_drop_box, seat->op_target_edge, thickness); | ||
369 | desktop_damage_box(&seat->op_drop_box); | ||
370 | } | ||
371 | |||
231 | static void calculate_floating_constraints(struct sway_container *con, | 372 | static void calculate_floating_constraints(struct sway_container *con, |
232 | int *min_width, int *max_width, int *min_height, int *max_height) { | 373 | int *min_width, int *max_width, int *min_height, int *max_height) { |
233 | if (config->floating_minimum_width == -1) { // no minimum | 374 | if (config->floating_minimum_width == -1) { // no minimum |
@@ -402,8 +543,11 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
402 | case OP_DOWN: | 543 | case OP_DOWN: |
403 | handle_down_motion(seat, cursor, time_msec); | 544 | handle_down_motion(seat, cursor, time_msec); |
404 | break; | 545 | break; |
405 | case OP_MOVE: | 546 | case OP_MOVE_FLOATING: |
406 | handle_move_motion(seat, cursor); | 547 | handle_move_floating_motion(seat, cursor); |
548 | break; | ||
549 | case OP_MOVE_TILING: | ||
550 | handle_move_tiling_motion(seat, cursor); | ||
407 | break; | 551 | break; |
408 | case OP_RESIZE_FLOATING: | 552 | case OP_RESIZE_FLOATING: |
409 | handle_resize_floating_motion(seat, cursor); | 553 | handle_resize_floating_motion(seat, cursor); |
@@ -719,7 +863,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
719 | while (cont->parent) { | 863 | while (cont->parent) { |
720 | cont = cont->parent; | 864 | cont = cont->parent; |
721 | } | 865 | } |
722 | seat_begin_move(seat, cont, button); | 866 | seat_begin_move_floating(seat, cont, button); |
723 | return; | 867 | return; |
724 | } | 868 | } |
725 | } | 869 | } |
@@ -751,6 +895,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
751 | } | 895 | } |
752 | } | 896 | } |
753 | 897 | ||
898 | // Handle moving a tiling container | ||
899 | if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED && | ||
900 | !is_floating_or_child && !cont->is_fullscreen) { | ||
901 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
902 | seat_begin_move_tiling(seat, cont, button); | ||
903 | return; | ||
904 | } | ||
905 | |||
754 | // Handle mousedown on a container surface | 906 | // Handle mousedown on a container surface |
755 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | 907 | if (surface && cont && state == WLR_BUTTON_PRESSED) { |
756 | seat_set_focus_container(seat, cont); | 908 | seat_set_focus_container(seat, cont); |