diff options
author | Drew DeVault <sir@cmpwn.com> | 2019-01-13 20:38:34 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-13 20:38:34 -0500 |
commit | 23ab56bbf746e7aa4a940caa343d447a969fa37e (patch) | |
tree | 087201fd4d39c3a551c925c4f5479311e10e6623 /sway/input | |
parent | Merge pull request #3388 from RedSoxFan/reset-inputs-on-reload (diff) | |
parent | Refactor seat operations to use an interface (diff) | |
download | sway-23ab56bbf746e7aa4a940caa343d447a969fa37e.tar.gz sway-23ab56bbf746e7aa4a940caa343d447a969fa37e.tar.zst sway-23ab56bbf746e7aa4a940caa343d447a969fa37e.zip |
Merge pull request #3402 from RyanDwyer/refactor-seatops
Refactor seat operations to use an interface
Diffstat (limited to 'sway/input')
-rw-r--r-- | sway/input/cursor.c | 396 | ||||
-rw-r--r-- | sway/input/seat.c | 236 | ||||
-rw-r--r-- | sway/input/seatop_down.c | 77 | ||||
-rw-r--r-- | sway/input/seatop_move_floating.c | 65 | ||||
-rw-r--r-- | sway/input/seatop_move_tiling.c | 335 | ||||
-rw-r--r-- | sway/input/seatop_resize_floating.c | 199 | ||||
-rw-r--r-- | sway/input/seatop_resize_tiling.c | 92 |
7 files changed, 825 insertions, 575 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 9af7ef57..06294b8b 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -27,10 +27,6 @@ | |||
27 | #include "sway/tree/workspace.h" | 27 | #include "sway/tree/workspace.h" |
28 | #include "wlr-layer-shell-unstable-v1-protocol.h" | 28 | #include "wlr-layer-shell-unstable-v1-protocol.h" |
29 | 29 | ||
30 | // When doing a tiling drag, this is the thickness of the dropzone | ||
31 | // when dragging to the edge of a layout container. | ||
32 | #define DROP_LAYOUT_BORDER 30 | ||
33 | |||
34 | static uint32_t get_current_time_msec(void) { | 30 | static uint32_t get_current_time_msec(void) { |
35 | struct timespec now; | 31 | struct timespec now; |
36 | clock_gettime(CLOCK_MONOTONIC, &now); | 32 | clock_gettime(CLOCK_MONOTONIC, &now); |
@@ -59,7 +55,7 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, | |||
59 | * Returns the node at the cursor's position. If there is a surface at that | 55 | * Returns the node at the cursor's position. If there is a surface at that |
60 | * location, it is stored in **surface (it may not be a view). | 56 | * location, it is stored in **surface (it may not be a view). |
61 | */ | 57 | */ |
62 | static struct sway_node *node_at_coords( | 58 | struct sway_node *node_at_coords( |
63 | struct sway_seat *seat, double lx, double ly, | 59 | struct sway_seat *seat, double lx, double ly, |
64 | struct wlr_surface **surface, double *sx, double *sy) { | 60 | struct wlr_surface **surface, double *sx, double *sy) { |
65 | // check for unmanaged views first | 61 | // check for unmanaged views first |
@@ -226,347 +222,6 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont, | |||
226 | return edge; | 222 | return edge; |
227 | } | 223 | } |
228 | 224 | ||
229 | static void handle_down_motion(struct sway_seat *seat, | ||
230 | struct sway_cursor *cursor, uint32_t time_msec) { | ||
231 | struct sway_container *con = seat->op_container; | ||
232 | if (seat_is_input_allowed(seat, con->view->surface)) { | ||
233 | double moved_x = cursor->cursor->x - seat->op_ref_lx; | ||
234 | double moved_y = cursor->cursor->y - seat->op_ref_ly; | ||
235 | double sx = seat->op_ref_con_lx + moved_x; | ||
236 | double sy = seat->op_ref_con_ly + moved_y; | ||
237 | wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); | ||
238 | } | ||
239 | seat->op_moved = true; | ||
240 | } | ||
241 | |||
242 | static void handle_move_floating_motion(struct sway_seat *seat, | ||
243 | struct sway_cursor *cursor) { | ||
244 | struct sway_container *con = seat->op_container; | ||
245 | desktop_damage_whole_container(con); | ||
246 | container_floating_translate(con, | ||
247 | cursor->cursor->x - cursor->previous.x, | ||
248 | cursor->cursor->y - cursor->previous.y); | ||
249 | desktop_damage_whole_container(con); | ||
250 | } | ||
251 | |||
252 | static void resize_box(struct wlr_box *box, enum wlr_edges edge, | ||
253 | int thickness) { | ||
254 | switch (edge) { | ||
255 | case WLR_EDGE_TOP: | ||
256 | box->height = thickness; | ||
257 | break; | ||
258 | case WLR_EDGE_LEFT: | ||
259 | box->width = thickness; | ||
260 | break; | ||
261 | case WLR_EDGE_RIGHT: | ||
262 | box->x = box->x + box->width - thickness; | ||
263 | box->width = thickness; | ||
264 | break; | ||
265 | case WLR_EDGE_BOTTOM: | ||
266 | box->y = box->y + box->height - thickness; | ||
267 | box->height = thickness; | ||
268 | break; | ||
269 | case WLR_EDGE_NONE: | ||
270 | box->x += thickness; | ||
271 | box->y += thickness; | ||
272 | box->width -= thickness * 2; | ||
273 | box->height -= thickness * 2; | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static void handle_move_tiling_motion(struct sway_seat *seat, | ||
279 | struct sway_cursor *cursor) { | ||
280 | struct wlr_surface *surface = NULL; | ||
281 | double sx, sy; | ||
282 | struct sway_node *node = node_at_coords(seat, | ||
283 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
284 | // Damage the old location | ||
285 | desktop_damage_box(&seat->op_drop_box); | ||
286 | |||
287 | if (!node) { | ||
288 | // Eg. hovered over a layer surface such as swaybar | ||
289 | seat->op_target_node = NULL; | ||
290 | seat->op_target_edge = WLR_EDGE_NONE; | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | if (node->type == N_WORKSPACE) { | ||
295 | // Emtpy workspace | ||
296 | seat->op_target_node = node; | ||
297 | seat->op_target_edge = WLR_EDGE_NONE; | ||
298 | workspace_get_box(node->sway_workspace, &seat->op_drop_box); | ||
299 | desktop_damage_box(&seat->op_drop_box); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | // Deny moving within own workspace if this is the only child | ||
304 | struct sway_container *con = node->sway_container; | ||
305 | if (workspace_num_tiling_views(seat->op_container->workspace) == 1 && | ||
306 | con->workspace == seat->op_container->workspace) { | ||
307 | seat->op_target_node = NULL; | ||
308 | seat->op_target_edge = WLR_EDGE_NONE; | ||
309 | return; | ||
310 | } | ||
311 | |||
312 | // Traverse the ancestors, trying to find a layout container perpendicular | ||
313 | // to the edge. Eg. close to the top or bottom of a horiz layout. | ||
314 | while (con) { | ||
315 | enum wlr_edges edge = WLR_EDGE_NONE; | ||
316 | enum sway_container_layout layout = container_parent_layout(con); | ||
317 | struct wlr_box parent; | ||
318 | con->parent ? container_get_box(con->parent, &parent) : | ||
319 | workspace_get_box(con->workspace, &parent); | ||
320 | if (layout == L_HORIZ || layout == L_TABBED) { | ||
321 | if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) { | ||
322 | edge = WLR_EDGE_TOP; | ||
323 | } else if (cursor->cursor->y > parent.y + parent.height | ||
324 | - DROP_LAYOUT_BORDER) { | ||
325 | edge = WLR_EDGE_BOTTOM; | ||
326 | } | ||
327 | } else if (layout == L_VERT || layout == L_STACKED) { | ||
328 | if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) { | ||
329 | edge = WLR_EDGE_LEFT; | ||
330 | } else if (cursor->cursor->x > parent.x + parent.width | ||
331 | - DROP_LAYOUT_BORDER) { | ||
332 | edge = WLR_EDGE_RIGHT; | ||
333 | } | ||
334 | } | ||
335 | if (edge) { | ||
336 | seat->op_target_node = node_get_parent(&con->node); | ||
337 | seat->op_target_edge = edge; | ||
338 | node_get_box(seat->op_target_node, &seat->op_drop_box); | ||
339 | resize_box(&seat->op_drop_box, edge, DROP_LAYOUT_BORDER); | ||
340 | desktop_damage_box(&seat->op_drop_box); | ||
341 | return; | ||
342 | } | ||
343 | con = con->parent; | ||
344 | } | ||
345 | |||
346 | // Use the hovered view - but we must be over the actual surface | ||
347 | con = node->sway_container; | ||
348 | if (!con->view->surface || node == &seat->op_container->node) { | ||
349 | seat->op_target_node = NULL; | ||
350 | seat->op_target_edge = WLR_EDGE_NONE; | ||
351 | return; | ||
352 | } | ||
353 | |||
354 | // Find the closest edge | ||
355 | size_t thickness = fmin(con->content_width, con->content_height) * 0.3; | ||
356 | size_t closest_dist = INT_MAX; | ||
357 | size_t dist; | ||
358 | seat->op_target_edge = WLR_EDGE_NONE; | ||
359 | if ((dist = cursor->cursor->y - con->y) < closest_dist) { | ||
360 | closest_dist = dist; | ||
361 | seat->op_target_edge = WLR_EDGE_TOP; | ||
362 | } | ||
363 | if ((dist = cursor->cursor->x - con->x) < closest_dist) { | ||
364 | closest_dist = dist; | ||
365 | seat->op_target_edge = WLR_EDGE_LEFT; | ||
366 | } | ||
367 | if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) { | ||
368 | closest_dist = dist; | ||
369 | seat->op_target_edge = WLR_EDGE_RIGHT; | ||
370 | } | ||
371 | if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) { | ||
372 | closest_dist = dist; | ||
373 | seat->op_target_edge = WLR_EDGE_BOTTOM; | ||
374 | } | ||
375 | |||
376 | if (closest_dist > thickness) { | ||
377 | seat->op_target_edge = WLR_EDGE_NONE; | ||
378 | } | ||
379 | |||
380 | seat->op_target_node = node; | ||
381 | seat->op_drop_box.x = con->content_x; | ||
382 | seat->op_drop_box.y = con->content_y; | ||
383 | seat->op_drop_box.width = con->content_width; | ||
384 | seat->op_drop_box.height = con->content_height; | ||
385 | resize_box(&seat->op_drop_box, seat->op_target_edge, thickness); | ||
386 | desktop_damage_box(&seat->op_drop_box); | ||
387 | } | ||
388 | |||
389 | static void handle_move_tiling_threshold_motion(struct sway_seat *seat, | ||
390 | struct sway_cursor *cursor) { | ||
391 | double cx = seat->cursor->cursor->x; | ||
392 | double cy = seat->cursor->cursor->y; | ||
393 | double sx = seat->op_ref_lx; | ||
394 | double sy = seat->op_ref_ly; | ||
395 | |||
396 | // Get the scaled threshold for the output. Even if the operation goes | ||
397 | // across multiple outputs of varying scales, just use the scale for the | ||
398 | // output that the cursor is currently on for simplicity. | ||
399 | struct wlr_output *wlr_output = wlr_output_layout_output_at( | ||
400 | root->output_layout, cx, cy); | ||
401 | double output_scale = wlr_output ? wlr_output->scale : 1; | ||
402 | double threshold = config->tiling_drag_threshold * output_scale; | ||
403 | threshold *= threshold; | ||
404 | |||
405 | // If the threshold has been exceeded, start the actual drag | ||
406 | if ((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy) > threshold) { | ||
407 | seat->operation = OP_MOVE_TILING; | ||
408 | cursor_set_image(cursor, "grab", NULL); | ||
409 | handle_move_tiling_motion(seat, cursor); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static void calculate_floating_constraints(struct sway_container *con, | ||
414 | int *min_width, int *max_width, int *min_height, int *max_height) { | ||
415 | if (config->floating_minimum_width == -1) { // no minimum | ||
416 | *min_width = 0; | ||
417 | } else if (config->floating_minimum_width == 0) { // automatic | ||
418 | *min_width = 75; | ||
419 | } else { | ||
420 | *min_width = config->floating_minimum_width; | ||
421 | } | ||
422 | |||
423 | if (config->floating_minimum_height == -1) { // no minimum | ||
424 | *min_height = 0; | ||
425 | } else if (config->floating_minimum_height == 0) { // automatic | ||
426 | *min_height = 50; | ||
427 | } else { | ||
428 | *min_height = config->floating_minimum_height; | ||
429 | } | ||
430 | |||
431 | if (config->floating_maximum_width == -1) { // no maximum | ||
432 | *max_width = INT_MAX; | ||
433 | } else if (config->floating_maximum_width == 0) { // automatic | ||
434 | *max_width = con->workspace->width; | ||
435 | } else { | ||
436 | *max_width = config->floating_maximum_width; | ||
437 | } | ||
438 | |||
439 | if (config->floating_maximum_height == -1) { // no maximum | ||
440 | *max_height = INT_MAX; | ||
441 | } else if (config->floating_maximum_height == 0) { // automatic | ||
442 | *max_height = con->workspace->height; | ||
443 | } else { | ||
444 | *max_height = config->floating_maximum_height; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | static void handle_resize_floating_motion(struct sway_seat *seat, | ||
449 | struct sway_cursor *cursor) { | ||
450 | struct sway_container *con = seat->op_container; | ||
451 | enum wlr_edges edge = seat->op_resize_edge; | ||
452 | |||
453 | // The amount the mouse has moved since the start of the resize operation | ||
454 | // Positive is down/right | ||
455 | double mouse_move_x = cursor->cursor->x - seat->op_ref_lx; | ||
456 | double mouse_move_y = cursor->cursor->y - seat->op_ref_ly; | ||
457 | |||
458 | if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { | ||
459 | mouse_move_x = 0; | ||
460 | } | ||
461 | if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { | ||
462 | mouse_move_y = 0; | ||
463 | } | ||
464 | |||
465 | double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x; | ||
466 | double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y; | ||
467 | |||
468 | if (seat->op_resize_preserve_ratio) { | ||
469 | double x_multiplier = grow_width / seat->op_ref_width; | ||
470 | double y_multiplier = grow_height / seat->op_ref_height; | ||
471 | double max_multiplier = fmax(x_multiplier, y_multiplier); | ||
472 | grow_width = seat->op_ref_width * max_multiplier; | ||
473 | grow_height = seat->op_ref_height * max_multiplier; | ||
474 | } | ||
475 | |||
476 | // Determine new width/height, and accommodate for floating min/max values | ||
477 | double width = seat->op_ref_width + grow_width; | ||
478 | double height = seat->op_ref_height + grow_height; | ||
479 | int min_width, max_width, min_height, max_height; | ||
480 | calculate_floating_constraints(con, &min_width, &max_width, | ||
481 | &min_height, &max_height); | ||
482 | width = fmax(min_width, fmin(width, max_width)); | ||
483 | height = fmax(min_height, fmin(height, max_height)); | ||
484 | |||
485 | // Apply the view's min/max size | ||
486 | if (con->view) { | ||
487 | double view_min_width, view_max_width, view_min_height, view_max_height; | ||
488 | view_get_constraints(con->view, &view_min_width, &view_max_width, | ||
489 | &view_min_height, &view_max_height); | ||
490 | width = fmax(view_min_width, fmin(width, view_max_width)); | ||
491 | height = fmax(view_min_height, fmin(height, view_max_height)); | ||
492 | } | ||
493 | |||
494 | // Recalculate these, in case we hit a min/max limit | ||
495 | grow_width = width - seat->op_ref_width; | ||
496 | grow_height = height - seat->op_ref_height; | ||
497 | |||
498 | // Determine grow x/y values - these are relative to the container's x/y at | ||
499 | // the start of the resize operation. | ||
500 | double grow_x = 0, grow_y = 0; | ||
501 | if (edge & WLR_EDGE_LEFT) { | ||
502 | grow_x = -grow_width; | ||
503 | } else if (edge & WLR_EDGE_RIGHT) { | ||
504 | grow_x = 0; | ||
505 | } else { | ||
506 | grow_x = -grow_width / 2; | ||
507 | } | ||
508 | if (edge & WLR_EDGE_TOP) { | ||
509 | grow_y = -grow_height; | ||
510 | } else if (edge & WLR_EDGE_BOTTOM) { | ||
511 | grow_y = 0; | ||
512 | } else { | ||
513 | grow_y = -grow_height / 2; | ||
514 | } | ||
515 | |||
516 | // Determine the amounts we need to bump everything relative to the current | ||
517 | // size. | ||
518 | int relative_grow_width = width - con->width; | ||
519 | int relative_grow_height = height - con->height; | ||
520 | int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x; | ||
521 | int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y; | ||
522 | |||
523 | // Actually resize stuff | ||
524 | con->x += relative_grow_x; | ||
525 | con->y += relative_grow_y; | ||
526 | con->width += relative_grow_width; | ||
527 | con->height += relative_grow_height; | ||
528 | |||
529 | con->content_x += relative_grow_x; | ||
530 | con->content_y += relative_grow_y; | ||
531 | con->content_width += relative_grow_width; | ||
532 | con->content_height += relative_grow_height; | ||
533 | |||
534 | arrange_container(con); | ||
535 | } | ||
536 | |||
537 | static void handle_resize_tiling_motion(struct sway_seat *seat, | ||
538 | struct sway_cursor *cursor) { | ||
539 | int amount_x = 0; | ||
540 | int amount_y = 0; | ||
541 | int moved_x = cursor->cursor->x - seat->op_ref_lx; | ||
542 | int moved_y = cursor->cursor->y - seat->op_ref_ly; | ||
543 | enum wlr_edges edge_x = WLR_EDGE_NONE; | ||
544 | enum wlr_edges edge_y = WLR_EDGE_NONE; | ||
545 | struct sway_container *con = seat->op_container; | ||
546 | |||
547 | if (seat->op_resize_edge & WLR_EDGE_TOP) { | ||
548 | amount_y = (seat->op_ref_height - moved_y) - con->height; | ||
549 | edge_y = WLR_EDGE_TOP; | ||
550 | } else if (seat->op_resize_edge & WLR_EDGE_BOTTOM) { | ||
551 | amount_y = (seat->op_ref_height + moved_y) - con->height; | ||
552 | edge_y = WLR_EDGE_BOTTOM; | ||
553 | } | ||
554 | if (seat->op_resize_edge & WLR_EDGE_LEFT) { | ||
555 | amount_x = (seat->op_ref_width - moved_x) - con->width; | ||
556 | edge_x = WLR_EDGE_LEFT; | ||
557 | } else if (seat->op_resize_edge & WLR_EDGE_RIGHT) { | ||
558 | amount_x = (seat->op_ref_width + moved_x) - con->width; | ||
559 | edge_x = WLR_EDGE_RIGHT; | ||
560 | } | ||
561 | |||
562 | if (amount_x != 0) { | ||
563 | container_resize_tiled(seat->op_container, edge_x, amount_x); | ||
564 | } | ||
565 | if (amount_y != 0) { | ||
566 | container_resize_tiled(seat->op_container, edge_y, amount_y); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec, | 225 | static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec, |
571 | struct sway_node *node, struct wlr_surface *surface, | 226 | struct sway_node *node, struct wlr_surface *surface, |
572 | double sx, double sy) { | 227 | double sx, double sy) { |
@@ -669,29 +324,8 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, | |||
669 | struct sway_seat *seat = cursor->seat; | 324 | struct sway_seat *seat = cursor->seat; |
670 | struct wlr_seat *wlr_seat = seat->wlr_seat; | 325 | struct wlr_seat *wlr_seat = seat->wlr_seat; |
671 | 326 | ||
672 | if (seat->operation != OP_NONE) { | 327 | if (seat_doing_seatop(seat)) { |
673 | switch (seat->operation) { | 328 | seatop_motion(seat, time_msec); |
674 | case OP_DOWN: | ||
675 | handle_down_motion(seat, cursor, time_msec); | ||
676 | break; | ||
677 | case OP_MOVE_FLOATING: | ||
678 | handle_move_floating_motion(seat, cursor); | ||
679 | break; | ||
680 | case OP_MOVE_TILING_THRESHOLD: | ||
681 | handle_move_tiling_threshold_motion(seat, cursor); | ||
682 | break; | ||
683 | case OP_MOVE_TILING: | ||
684 | handle_move_tiling_motion(seat, cursor); | ||
685 | break; | ||
686 | case OP_RESIZE_FLOATING: | ||
687 | handle_resize_floating_motion(seat, cursor); | ||
688 | break; | ||
689 | case OP_RESIZE_TILING: | ||
690 | handle_resize_tiling_motion(seat, cursor); | ||
691 | break; | ||
692 | case OP_NONE: | ||
693 | break; | ||
694 | } | ||
695 | cursor->previous.x = cursor->cursor->x; | 329 | cursor->previous.x = cursor->cursor->x; |
696 | cursor->previous.y = cursor->cursor->y; | 330 | cursor->previous.y = cursor->cursor->y; |
697 | return; | 331 | return; |
@@ -868,9 +502,9 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
868 | struct sway_seat *seat = cursor->seat; | 502 | struct sway_seat *seat = cursor->seat; |
869 | 503 | ||
870 | // Handle existing seat operation | 504 | // Handle existing seat operation |
871 | if (cursor->seat->operation != OP_NONE) { | 505 | if (seat_doing_seatop(seat)) { |
872 | if (button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) { | 506 | if (button == seat->seatop_button && state == WLR_BUTTON_RELEASED) { |
873 | seat_end_mouse_operation(seat); | 507 | seatop_finish(seat); |
874 | seat_pointer_notify_button(seat, time_msec, button, state); | 508 | seat_pointer_notify_button(seat, time_msec, button, state); |
875 | } | 509 | } |
876 | if (state == WLR_BUTTON_PRESSED) { | 510 | if (state == WLR_BUTTON_PRESSED) { |
@@ -943,7 +577,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
943 | if (cont && resize_edge && button == BTN_LEFT && | 577 | if (cont && resize_edge && button == BTN_LEFT && |
944 | state == WLR_BUTTON_PRESSED && !is_floating) { | 578 | state == WLR_BUTTON_PRESSED && !is_floating) { |
945 | seat_set_focus_container(seat, cont); | 579 | seat_set_focus_container(seat, cont); |
946 | seat_begin_resize_tiling(seat, cont, button, edge); | 580 | seatop_begin_resize_tiling(seat, cont, button, edge); |
947 | return; | 581 | return; |
948 | } | 582 | } |
949 | 583 | ||
@@ -973,7 +607,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
973 | } | 607 | } |
974 | cursor_set_image(seat->cursor, image, NULL); | 608 | cursor_set_image(seat->cursor, image, NULL); |
975 | seat_set_focus_container(seat, cont); | 609 | seat_set_focus_container(seat, cont); |
976 | seat_begin_resize_tiling(seat, cont, button, edge); | 610 | seatop_begin_resize_tiling(seat, cont, button, edge); |
977 | return; | 611 | return; |
978 | } | 612 | } |
979 | } | 613 | } |
@@ -988,7 +622,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
988 | cont = cont->parent; | 622 | cont = cont->parent; |
989 | } | 623 | } |
990 | seat_set_focus_container(seat, cont); | 624 | seat_set_focus_container(seat, cont); |
991 | seat_begin_move_floating(seat, cont, button); | 625 | seatop_begin_move_floating(seat, cont, button); |
992 | return; | 626 | return; |
993 | } | 627 | } |
994 | } | 628 | } |
@@ -998,7 +632,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
998 | state == WLR_BUTTON_PRESSED) { | 632 | state == WLR_BUTTON_PRESSED) { |
999 | // Via border | 633 | // Via border |
1000 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { | 634 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { |
1001 | seat_begin_resize_floating(seat, cont, button, resize_edge); | 635 | seatop_begin_resize_floating(seat, cont, button, resize_edge); |
1002 | return; | 636 | return; |
1003 | } | 637 | } |
1004 | 638 | ||
@@ -1015,7 +649,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
1015 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 649 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
1016 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? | 650 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? |
1017 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 651 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
1018 | seat_begin_resize_floating(seat, floater, button, edge); | 652 | seatop_begin_resize_floating(seat, floater, button, edge); |
1019 | return; | 653 | return; |
1020 | } | 654 | } |
1021 | } | 655 | } |
@@ -1035,9 +669,9 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
1035 | 669 | ||
1036 | // If moving a container by it's title bar, use a threshold for the drag | 670 | // If moving a container by it's title bar, use a threshold for the drag |
1037 | if (!mod_pressed && config->tiling_drag_threshold > 0) { | 671 | if (!mod_pressed && config->tiling_drag_threshold > 0) { |
1038 | seat_begin_move_tiling_threshold(seat, cont, button); | 672 | seatop_begin_move_tiling_threshold(seat, cont, button); |
1039 | } else { | 673 | } else { |
1040 | seat_begin_move_tiling(seat, cont, button); | 674 | seatop_begin_move_tiling(seat, cont, button); |
1041 | } | 675 | } |
1042 | return; | 676 | return; |
1043 | } | 677 | } |
@@ -1046,7 +680,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
1046 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | 680 | if (surface && cont && state == WLR_BUTTON_PRESSED) { |
1047 | seat_set_focus_container(seat, cont); | 681 | seat_set_focus_container(seat, cont); |
1048 | seat_pointer_notify_button(seat, time_msec, button, state); | 682 | seat_pointer_notify_button(seat, time_msec, button, state); |
1049 | seat_begin_down(seat, cont, button, sx, sy); | 683 | seatop_begin_down(seat, cont, button, sx, sy); |
1050 | return; | 684 | return; |
1051 | } | 685 | } |
1052 | 686 | ||
@@ -1350,7 +984,7 @@ static void handle_request_set_cursor(struct wl_listener *listener, | |||
1350 | void *data) { | 984 | void *data) { |
1351 | struct sway_cursor *cursor = | 985 | struct sway_cursor *cursor = |
1352 | wl_container_of(listener, cursor, request_set_cursor); | 986 | wl_container_of(listener, cursor, request_set_cursor); |
1353 | if (cursor->seat->operation != OP_NONE) { | 987 | if (seat_doing_seatop(cursor->seat)) { |
1354 | return; | 988 | return; |
1355 | } | 989 | } |
1356 | struct wlr_seat_pointer_request_set_cursor_event *event = data; | 990 | struct wlr_seat_pointer_request_set_cursor_event *event = data; |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 09acab0d..a63999b6 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -308,7 +308,7 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) { | |||
308 | wl_list_insert(&root->drag_icons, &icon->link); | 308 | wl_list_insert(&root->drag_icons, &icon->link); |
309 | 309 | ||
310 | drag_icon_update_position(icon); | 310 | drag_icon_update_position(icon); |
311 | seat_end_mouse_operation(seat); | 311 | seatop_abort(seat); |
312 | } | 312 | } |
313 | 313 | ||
314 | static void collect_focus_iter(struct sway_node *node, void *data) { | 314 | static void collect_focus_iter(struct sway_node *node, void *data) { |
@@ -662,18 +662,6 @@ static int handle_urgent_timeout(void *data) { | |||
662 | return 0; | 662 | return 0; |
663 | } | 663 | } |
664 | 664 | ||
665 | static void container_raise_floating(struct sway_container *con) { | ||
666 | // Bring container to front by putting it at the end of the floating list. | ||
667 | struct sway_container *floater = con; | ||
668 | while (floater->parent) { | ||
669 | floater = floater->parent; | ||
670 | } | ||
671 | if (container_is_floating(floater)) { | ||
672 | list_move_to_end(floater->workspace->floating, floater); | ||
673 | node_set_dirty(&floater->workspace->node); | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static void set_workspace(struct sway_seat *seat, | 665 | static void set_workspace(struct sway_seat *seat, |
678 | struct sway_workspace *new_ws) { | 666 | struct sway_workspace *new_ws) { |
679 | if (seat->workspace == new_ws) { | 667 | if (seat->workspace == new_ws) { |
@@ -1062,187 +1050,6 @@ struct seat_config *seat_get_config_by_name(const char *name) { | |||
1062 | return NULL; | 1050 | return NULL; |
1063 | } | 1051 | } |
1064 | 1052 | ||
1065 | void seat_begin_down(struct sway_seat *seat, struct sway_container *con, | ||
1066 | uint32_t button, double sx, double sy) { | ||
1067 | seat->operation = OP_DOWN; | ||
1068 | seat->op_container = con; | ||
1069 | seat->op_button = button; | ||
1070 | seat->op_ref_lx = seat->cursor->cursor->x; | ||
1071 | seat->op_ref_ly = seat->cursor->cursor->y; | ||
1072 | seat->op_ref_con_lx = sx; | ||
1073 | seat->op_ref_con_ly = sy; | ||
1074 | seat->op_moved = false; | ||
1075 | |||
1076 | container_raise_floating(con); | ||
1077 | } | ||
1078 | |||
1079 | void seat_begin_move_floating(struct sway_seat *seat, | ||
1080 | struct sway_container *con, uint32_t button) { | ||
1081 | if (!seat->cursor) { | ||
1082 | wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device"); | ||
1083 | return; | ||
1084 | } | ||
1085 | seat->operation = OP_MOVE_FLOATING; | ||
1086 | seat->op_container = con; | ||
1087 | seat->op_button = button; | ||
1088 | |||
1089 | container_raise_floating(con); | ||
1090 | |||
1091 | cursor_set_image(seat->cursor, "grab", NULL); | ||
1092 | } | ||
1093 | |||
1094 | void seat_begin_move_tiling_threshold(struct sway_seat *seat, | ||
1095 | struct sway_container *con, uint32_t button) { | ||
1096 | seat->operation = OP_MOVE_TILING_THRESHOLD; | ||
1097 | seat->op_container = con; | ||
1098 | seat->op_button = button; | ||
1099 | seat->op_target_node = NULL; | ||
1100 | seat->op_target_edge = 0; | ||
1101 | seat->op_ref_lx = seat->cursor->cursor->x; | ||
1102 | seat->op_ref_ly = seat->cursor->cursor->y; | ||
1103 | } | ||
1104 | |||
1105 | void seat_begin_move_tiling(struct sway_seat *seat, | ||
1106 | struct sway_container *con, uint32_t button) { | ||
1107 | seat->operation = OP_MOVE_TILING; | ||
1108 | seat->op_container = con; | ||
1109 | seat->op_button = button; | ||
1110 | seat->op_target_node = NULL; | ||
1111 | seat->op_target_edge = 0; | ||
1112 | cursor_set_image(seat->cursor, "grab", NULL); | ||
1113 | } | ||
1114 | |||
1115 | void seat_begin_resize_floating(struct sway_seat *seat, | ||
1116 | struct sway_container *con, uint32_t button, enum wlr_edges edge) { | ||
1117 | if (!seat->cursor) { | ||
1118 | wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device"); | ||
1119 | return; | ||
1120 | } | ||
1121 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | ||
1122 | seat->operation = OP_RESIZE_FLOATING; | ||
1123 | seat->op_container = con; | ||
1124 | seat->op_resize_preserve_ratio = keyboard && | ||
1125 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); | ||
1126 | seat->op_resize_edge = edge == WLR_EDGE_NONE ? | ||
1127 | WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; | ||
1128 | seat->op_button = button; | ||
1129 | seat->op_ref_lx = seat->cursor->cursor->x; | ||
1130 | seat->op_ref_ly = seat->cursor->cursor->y; | ||
1131 | seat->op_ref_con_lx = con->x; | ||
1132 | seat->op_ref_con_ly = con->y; | ||
1133 | seat->op_ref_width = con->width; | ||
1134 | seat->op_ref_height = con->height; | ||
1135 | |||
1136 | container_raise_floating(con); | ||
1137 | |||
1138 | const char *image = edge == WLR_EDGE_NONE ? | ||
1139 | "se-resize" : wlr_xcursor_get_resize_name(edge); | ||
1140 | cursor_set_image(seat->cursor, image, NULL); | ||
1141 | } | ||
1142 | |||
1143 | void seat_begin_resize_tiling(struct sway_seat *seat, | ||
1144 | struct sway_container *con, uint32_t button, enum wlr_edges edge) { | ||
1145 | seat->operation = OP_RESIZE_TILING; | ||
1146 | seat->op_container = con; | ||
1147 | seat->op_resize_edge = edge; | ||
1148 | seat->op_button = button; | ||
1149 | seat->op_ref_lx = seat->cursor->cursor->x; | ||
1150 | seat->op_ref_ly = seat->cursor->cursor->y; | ||
1151 | seat->op_ref_con_lx = con->x; | ||
1152 | seat->op_ref_con_ly = con->y; | ||
1153 | seat->op_ref_width = con->width; | ||
1154 | seat->op_ref_height = con->height; | ||
1155 | } | ||
1156 | |||
1157 | static bool is_parallel(enum sway_container_layout layout, | ||
1158 | enum wlr_edges edge) { | ||
1159 | bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED; | ||
1160 | bool edge_is_horiz = edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT; | ||
1161 | return layout_is_horiz == edge_is_horiz; | ||
1162 | } | ||
1163 | |||
1164 | static void seat_end_move_tiling(struct sway_seat *seat) { | ||
1165 | struct sway_container *con = seat->op_container; | ||
1166 | struct sway_container *old_parent = con->parent; | ||
1167 | struct sway_workspace *old_ws = con->workspace; | ||
1168 | struct sway_node *target_node = seat->op_target_node; | ||
1169 | struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? | ||
1170 | target_node->sway_workspace : target_node->sway_container->workspace; | ||
1171 | enum wlr_edges edge = seat->op_target_edge; | ||
1172 | int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; | ||
1173 | |||
1174 | container_detach(con); | ||
1175 | |||
1176 | // Moving container into empty workspace | ||
1177 | if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { | ||
1178 | workspace_add_tiling(new_ws, con); | ||
1179 | } else if (target_node->type == N_CONTAINER) { | ||
1180 | // Moving container before/after another | ||
1181 | struct sway_container *target = target_node->sway_container; | ||
1182 | enum sway_container_layout layout = container_parent_layout(target); | ||
1183 | if (edge && !is_parallel(layout, edge)) { | ||
1184 | enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || | ||
1185 | edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; | ||
1186 | container_split(target, new_layout); | ||
1187 | } | ||
1188 | container_add_sibling(target, con, after); | ||
1189 | } else { | ||
1190 | // Target is a workspace which requires splitting | ||
1191 | enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || | ||
1192 | edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; | ||
1193 | workspace_split(new_ws, new_layout); | ||
1194 | workspace_insert_tiling(new_ws, con, after); | ||
1195 | } | ||
1196 | |||
1197 | if (old_parent) { | ||
1198 | container_reap_empty(old_parent); | ||
1199 | } | ||
1200 | |||
1201 | // This is a bit dirty, but we'll set the dimensions to that of a sibling. | ||
1202 | // I don't think there's any other way to make it consistent without | ||
1203 | // changing how we auto-size containers. | ||
1204 | list_t *siblings = container_get_siblings(con); | ||
1205 | if (siblings->length > 1) { | ||
1206 | int index = list_find(siblings, con); | ||
1207 | struct sway_container *sibling = index == 0 ? | ||
1208 | siblings->items[1] : siblings->items[index - 1]; | ||
1209 | con->width = sibling->width; | ||
1210 | con->height = sibling->height; | ||
1211 | } | ||
1212 | |||
1213 | arrange_workspace(old_ws); | ||
1214 | if (new_ws != old_ws) { | ||
1215 | arrange_workspace(new_ws); | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | void seat_end_mouse_operation(struct sway_seat *seat) { | ||
1220 | enum sway_seat_operation operation = seat->operation; | ||
1221 | if (seat->operation == OP_MOVE_FLOATING) { | ||
1222 | // We "move" the container to its own location so it discovers its | ||
1223 | // output again. | ||
1224 | struct sway_container *con = seat->op_container; | ||
1225 | container_floating_move_to(con, con->x, con->y); | ||
1226 | } else if (seat->operation == OP_MOVE_TILING && seat->op_target_node) { | ||
1227 | seat_end_move_tiling(seat); | ||
1228 | } | ||
1229 | seat->operation = OP_NONE; | ||
1230 | seat->op_container = NULL; | ||
1231 | if (operation == OP_DOWN) { | ||
1232 | // Set the cursor's previous coords to the x/y at the start of the | ||
1233 | // operation, so the container change will be detected if using | ||
1234 | // focus_follows_mouse and the cursor moved off the original container | ||
1235 | // during the operation. | ||
1236 | seat->cursor->previous.x = seat->op_ref_lx; | ||
1237 | seat->cursor->previous.y = seat->op_ref_ly; | ||
1238 | if (seat->op_moved) { | ||
1239 | cursor_send_pointer_motion(seat->cursor, 0); | ||
1240 | } | ||
1241 | } else { | ||
1242 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, | 1053 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, |
1247 | uint32_t button, enum wlr_button_state state) { | 1054 | uint32_t button, enum wlr_button_state state) { |
1248 | seat->last_button = button; | 1055 | seat->last_button = button; |
@@ -1275,3 +1082,44 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) { | |||
1275 | wl_event_source_timer_update(seat->cursor->hide_source, cursor_get_timeout(seat->cursor)); | 1082 | wl_event_source_timer_update(seat->cursor->hide_source, cursor_get_timeout(seat->cursor)); |
1276 | } | 1083 | } |
1277 | } | 1084 | } |
1085 | |||
1086 | bool seat_doing_seatop(struct sway_seat *seat) { | ||
1087 | return seat->seatop_impl != NULL; | ||
1088 | } | ||
1089 | |||
1090 | void seatop_unref(struct sway_seat *seat, struct sway_container *con) { | ||
1091 | if (seat->seatop_impl && seat->seatop_impl->unref) { | ||
1092 | seat->seatop_impl->unref(seat, con); | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | void seatop_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
1097 | if (seat->seatop_impl && seat->seatop_impl->motion) { | ||
1098 | seat->seatop_impl->motion(seat, time_msec); | ||
1099 | } | ||
1100 | } | ||
1101 | |||
1102 | void seatop_finish(struct sway_seat *seat) { | ||
1103 | if (seat->seatop_impl && seat->seatop_impl->finish) { | ||
1104 | seat->seatop_impl->finish(seat); | ||
1105 | } | ||
1106 | free(seat->seatop_data); | ||
1107 | seat->seatop_data = NULL; | ||
1108 | seat->seatop_impl = NULL; | ||
1109 | } | ||
1110 | |||
1111 | void seatop_abort(struct sway_seat *seat) { | ||
1112 | if (seat->seatop_impl && seat->seatop_impl->abort) { | ||
1113 | seat->seatop_impl->abort(seat); | ||
1114 | } | ||
1115 | free(seat->seatop_data); | ||
1116 | seat->seatop_data = NULL; | ||
1117 | seat->seatop_impl = NULL; | ||
1118 | } | ||
1119 | |||
1120 | void seatop_render(struct sway_seat *seat, struct sway_output *output, | ||
1121 | pixman_region32_t *damage) { | ||
1122 | if (seat->seatop_impl && seat->seatop_impl->render) { | ||
1123 | seat->seatop_impl->render(seat, output, damage); | ||
1124 | } | ||
1125 | } | ||
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c new file mode 100644 index 00000000..ad11c5ca --- /dev/null +++ b/sway/input/seatop_down.c | |||
@@ -0,0 +1,77 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <wlr/types/wlr_cursor.h> | ||
3 | #include "sway/input/cursor.h" | ||
4 | #include "sway/input/seat.h" | ||
5 | #include "sway/tree/view.h" | ||
6 | |||
7 | struct seatop_down_event { | ||
8 | struct sway_container *con; | ||
9 | double ref_lx, ref_ly; // cursor's x/y at start of op | ||
10 | double ref_con_lx, ref_con_ly; // container's x/y at start of op | ||
11 | bool moved; | ||
12 | }; | ||
13 | |||
14 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
15 | struct seatop_down_event *e = seat->seatop_data; | ||
16 | struct sway_container *con = e->con; | ||
17 | if (seat_is_input_allowed(seat, con->view->surface)) { | ||
18 | double moved_x = seat->cursor->cursor->x - e->ref_lx; | ||
19 | double moved_y = seat->cursor->cursor->y - e->ref_ly; | ||
20 | double sx = e->ref_con_lx + moved_x; | ||
21 | double sy = e->ref_con_ly + moved_y; | ||
22 | wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); | ||
23 | } | ||
24 | e->moved = true; | ||
25 | } | ||
26 | |||
27 | static void handle_finish(struct sway_seat *seat) { | ||
28 | struct seatop_down_event *e = seat->seatop_data; | ||
29 | // Set the cursor's previous coords to the x/y at the start of the | ||
30 | // operation, so the container change will be detected if using | ||
31 | // focus_follows_mouse and the cursor moved off the original container | ||
32 | // during the operation. | ||
33 | seat->cursor->previous.x = e->ref_lx; | ||
34 | seat->cursor->previous.y = e->ref_ly; | ||
35 | if (e->moved) { | ||
36 | cursor_send_pointer_motion(seat->cursor, 0); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | static void handle_abort(struct sway_seat *seat) { | ||
41 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
42 | } | ||
43 | |||
44 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | ||
45 | struct seatop_down_event *e = seat->seatop_data; | ||
46 | if (e->con == con) { | ||
47 | seatop_abort(seat); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | static const struct sway_seatop_impl seatop_impl = { | ||
52 | .motion = handle_motion, | ||
53 | .finish = handle_finish, | ||
54 | .abort = handle_abort, | ||
55 | .unref = handle_unref, | ||
56 | }; | ||
57 | |||
58 | void seatop_begin_down(struct sway_seat *seat, | ||
59 | struct sway_container *con, uint32_t button, int sx, int sy) { | ||
60 | seatop_abort(seat); | ||
61 | |||
62 | struct seatop_down_event *e = | ||
63 | calloc(1, sizeof(struct seatop_down_event)); | ||
64 | if (!e) { | ||
65 | return; | ||
66 | } | ||
67 | e->con = con; | ||
68 | e->ref_lx = seat->cursor->cursor->x; | ||
69 | e->ref_ly = seat->cursor->cursor->y; | ||
70 | e->ref_con_lx = sx; | ||
71 | e->ref_con_ly = sy; | ||
72 | e->moved = false; | ||
73 | |||
74 | seat->seatop_impl = &seatop_impl; | ||
75 | seat->seatop_data = e; | ||
76 | seat->seatop_button = button; | ||
77 | } | ||
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c new file mode 100644 index 00000000..08e3a5a4 --- /dev/null +++ b/sway/input/seatop_move_floating.c | |||
@@ -0,0 +1,65 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <wlr/types/wlr_cursor.h> | ||
3 | #include "sway/desktop.h" | ||
4 | #include "sway/input/cursor.h" | ||
5 | #include "sway/input/seat.h" | ||
6 | |||
7 | struct seatop_move_floating_event { | ||
8 | struct sway_container *con; | ||
9 | }; | ||
10 | |||
11 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
12 | struct seatop_move_floating_event *e = seat->seatop_data; | ||
13 | desktop_damage_whole_container(e->con); | ||
14 | container_floating_translate(e->con, | ||
15 | seat->cursor->cursor->x - seat->cursor->previous.x, | ||
16 | seat->cursor->cursor->y - seat->cursor->previous.y); | ||
17 | desktop_damage_whole_container(e->con); | ||
18 | } | ||
19 | |||
20 | static void handle_finish(struct sway_seat *seat) { | ||
21 | struct seatop_move_floating_event *e = seat->seatop_data; | ||
22 | |||
23 | // We "move" the container to its own location | ||
24 | // so it discovers its output again. | ||
25 | container_floating_move_to(e->con, e->con->x, e->con->y); | ||
26 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
27 | } | ||
28 | |||
29 | static void handle_abort(struct sway_seat *seat) { | ||
30 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
31 | } | ||
32 | |||
33 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | ||
34 | struct seatop_move_floating_event *e = seat->seatop_data; | ||
35 | if (e->con == con) { | ||
36 | seatop_abort(seat); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | static const struct sway_seatop_impl seatop_impl = { | ||
41 | .motion = handle_motion, | ||
42 | .finish = handle_finish, | ||
43 | .abort = handle_abort, | ||
44 | .unref = handle_unref, | ||
45 | }; | ||
46 | |||
47 | void seatop_begin_move_floating(struct sway_seat *seat, | ||
48 | struct sway_container *con, uint32_t button) { | ||
49 | seatop_abort(seat); | ||
50 | |||
51 | struct seatop_move_floating_event *e = | ||
52 | calloc(1, sizeof(struct seatop_move_floating_event)); | ||
53 | if (!e) { | ||
54 | return; | ||
55 | } | ||
56 | e->con = con; | ||
57 | |||
58 | seat->seatop_impl = &seatop_impl; | ||
59 | seat->seatop_data = e; | ||
60 | seat->seatop_button = button; | ||
61 | |||
62 | container_raise_floating(con); | ||
63 | |||
64 | cursor_set_image(seat->cursor, "grab", NULL); | ||
65 | } | ||
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c new file mode 100644 index 00000000..8b541f80 --- /dev/null +++ b/sway/input/seatop_move_tiling.c | |||
@@ -0,0 +1,335 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | ||
3 | #include <wlr/types/wlr_cursor.h> | ||
4 | #include <wlr/util/edges.h> | ||
5 | #include "sway/desktop.h" | ||
6 | #include "sway/input/cursor.h" | ||
7 | #include "sway/input/seat.h" | ||
8 | #include "sway/output.h" | ||
9 | #include "sway/tree/arrange.h" | ||
10 | #include "sway/tree/node.h" | ||
11 | #include "sway/tree/view.h" | ||
12 | #include "sway/tree/workspace.h" | ||
13 | |||
14 | // Thickness of the dropzone when dragging to the edge of a layout container | ||
15 | #define DROP_LAYOUT_BORDER 30 | ||
16 | |||
17 | struct seatop_move_tiling_event { | ||
18 | struct sway_container *con; | ||
19 | struct sway_node *target_node; | ||
20 | enum wlr_edges target_edge; | ||
21 | struct wlr_box drop_box; | ||
22 | double ref_lx, ref_ly; // cursor's x/y at start of op | ||
23 | bool threshold_reached; | ||
24 | }; | ||
25 | |||
26 | static void handle_render(struct sway_seat *seat, | ||
27 | struct sway_output *output, pixman_region32_t *damage) { | ||
28 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
29 | if (!e->threshold_reached) { | ||
30 | return; | ||
31 | } | ||
32 | if (e->target_node && node_get_output(e->target_node) == output) { | ||
33 | float color[4]; | ||
34 | memcpy(&color, config->border_colors.focused.indicator, | ||
35 | sizeof(float) * 4); | ||
36 | premultiply_alpha(color, 0.5); | ||
37 | struct wlr_box box; | ||
38 | memcpy(&box, &e->drop_box, sizeof(struct wlr_box)); | ||
39 | scale_box(&box, output->wlr_output->scale); | ||
40 | render_rect(output->wlr_output, damage, &box, color); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void handle_motion_prethreshold(struct sway_seat *seat) { | ||
45 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
46 | double cx = seat->cursor->cursor->x; | ||
47 | double cy = seat->cursor->cursor->y; | ||
48 | double sx = e->ref_lx; | ||
49 | double sy = e->ref_ly; | ||
50 | |||
51 | // Get the scaled threshold for the output. Even if the operation goes | ||
52 | // across multiple outputs of varying scales, just use the scale for the | ||
53 | // output that the cursor is currently on for simplicity. | ||
54 | struct wlr_output *wlr_output = wlr_output_layout_output_at( | ||
55 | root->output_layout, cx, cy); | ||
56 | double output_scale = wlr_output ? wlr_output->scale : 1; | ||
57 | double threshold = config->tiling_drag_threshold * output_scale; | ||
58 | threshold *= threshold; | ||
59 | |||
60 | // If the threshold has been exceeded, start the actual drag | ||
61 | if ((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy) > threshold) { | ||
62 | e->threshold_reached = true; | ||
63 | cursor_set_image(seat->cursor, "grab", NULL); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static void resize_box(struct wlr_box *box, enum wlr_edges edge, | ||
68 | int thickness) { | ||
69 | switch (edge) { | ||
70 | case WLR_EDGE_TOP: | ||
71 | box->height = thickness; | ||
72 | break; | ||
73 | case WLR_EDGE_LEFT: | ||
74 | box->width = thickness; | ||
75 | break; | ||
76 | case WLR_EDGE_RIGHT: | ||
77 | box->x = box->x + box->width - thickness; | ||
78 | box->width = thickness; | ||
79 | break; | ||
80 | case WLR_EDGE_BOTTOM: | ||
81 | box->y = box->y + box->height - thickness; | ||
82 | box->height = thickness; | ||
83 | break; | ||
84 | case WLR_EDGE_NONE: | ||
85 | box->x += thickness; | ||
86 | box->y += thickness; | ||
87 | box->width -= thickness * 2; | ||
88 | box->height -= thickness * 2; | ||
89 | break; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void handle_motion_postthreshold(struct sway_seat *seat) { | ||
94 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
95 | struct wlr_surface *surface = NULL; | ||
96 | double sx, sy; | ||
97 | struct sway_cursor *cursor = seat->cursor; | ||
98 | struct sway_node *node = node_at_coords(seat, | ||
99 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
100 | // Damage the old location | ||
101 | desktop_damage_box(&e->drop_box); | ||
102 | |||
103 | if (!node) { | ||
104 | // Eg. hovered over a layer surface such as swaybar | ||
105 | e->target_node = NULL; | ||
106 | e->target_edge = WLR_EDGE_NONE; | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | if (node->type == N_WORKSPACE) { | ||
111 | // Emtpy workspace | ||
112 | e->target_node = node; | ||
113 | e->target_edge = WLR_EDGE_NONE; | ||
114 | workspace_get_box(node->sway_workspace, &e->drop_box); | ||
115 | desktop_damage_box(&e->drop_box); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | // Deny moving within own workspace if this is the only child | ||
120 | struct sway_container *con = node->sway_container; | ||
121 | if (workspace_num_tiling_views(e->con->workspace) == 1 && | ||
122 | con->workspace == e->con->workspace) { | ||
123 | e->target_node = NULL; | ||
124 | e->target_edge = WLR_EDGE_NONE; | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | // Traverse the ancestors, trying to find a layout container perpendicular | ||
129 | // to the edge. Eg. close to the top or bottom of a horiz layout. | ||
130 | while (con) { | ||
131 | enum wlr_edges edge = WLR_EDGE_NONE; | ||
132 | enum sway_container_layout layout = container_parent_layout(con); | ||
133 | struct wlr_box parent; | ||
134 | con->parent ? container_get_box(con->parent, &parent) : | ||
135 | workspace_get_box(con->workspace, &parent); | ||
136 | if (layout == L_HORIZ || layout == L_TABBED) { | ||
137 | if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) { | ||
138 | edge = WLR_EDGE_TOP; | ||
139 | } else if (cursor->cursor->y > parent.y + parent.height | ||
140 | - DROP_LAYOUT_BORDER) { | ||
141 | edge = WLR_EDGE_BOTTOM; | ||
142 | } | ||
143 | } else if (layout == L_VERT || layout == L_STACKED) { | ||
144 | if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) { | ||
145 | edge = WLR_EDGE_LEFT; | ||
146 | } else if (cursor->cursor->x > parent.x + parent.width | ||
147 | - DROP_LAYOUT_BORDER) { | ||
148 | edge = WLR_EDGE_RIGHT; | ||
149 | } | ||
150 | } | ||
151 | if (edge) { | ||
152 | e->target_node = node_get_parent(&con->node); | ||
153 | e->target_edge = edge; | ||
154 | node_get_box(e->target_node, &e->drop_box); | ||
155 | resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER); | ||
156 | desktop_damage_box(&e->drop_box); | ||
157 | return; | ||
158 | } | ||
159 | con = con->parent; | ||
160 | } | ||
161 | |||
162 | // Use the hovered view - but we must be over the actual surface | ||
163 | con = node->sway_container; | ||
164 | if (!con->view->surface || node == &e->con->node) { | ||
165 | e->target_node = NULL; | ||
166 | e->target_edge = WLR_EDGE_NONE; | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | // Find the closest edge | ||
171 | size_t thickness = fmin(con->content_width, con->content_height) * 0.3; | ||
172 | size_t closest_dist = INT_MAX; | ||
173 | size_t dist; | ||
174 | e->target_edge = WLR_EDGE_NONE; | ||
175 | if ((dist = cursor->cursor->y - con->y) < closest_dist) { | ||
176 | closest_dist = dist; | ||
177 | e->target_edge = WLR_EDGE_TOP; | ||
178 | } | ||
179 | if ((dist = cursor->cursor->x - con->x) < closest_dist) { | ||
180 | closest_dist = dist; | ||
181 | e->target_edge = WLR_EDGE_LEFT; | ||
182 | } | ||
183 | if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) { | ||
184 | closest_dist = dist; | ||
185 | e->target_edge = WLR_EDGE_RIGHT; | ||
186 | } | ||
187 | if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) { | ||
188 | closest_dist = dist; | ||
189 | e->target_edge = WLR_EDGE_BOTTOM; | ||
190 | } | ||
191 | |||
192 | if (closest_dist > thickness) { | ||
193 | e->target_edge = WLR_EDGE_NONE; | ||
194 | } | ||
195 | |||
196 | e->target_node = node; | ||
197 | e->drop_box.x = con->content_x; | ||
198 | e->drop_box.y = con->content_y; | ||
199 | e->drop_box.width = con->content_width; | ||
200 | e->drop_box.height = con->content_height; | ||
201 | resize_box(&e->drop_box, e->target_edge, thickness); | ||
202 | desktop_damage_box(&e->drop_box); | ||
203 | } | ||
204 | |||
205 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
206 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
207 | if (e->threshold_reached) { | ||
208 | handle_motion_postthreshold(seat); | ||
209 | } else { | ||
210 | handle_motion_prethreshold(seat); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void handle_abort(struct sway_seat *seat) { | ||
215 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
216 | } | ||
217 | |||
218 | static bool is_parallel(enum sway_container_layout layout, | ||
219 | enum wlr_edges edge) { | ||
220 | bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED; | ||
221 | bool edge_is_horiz = edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT; | ||
222 | return layout_is_horiz == edge_is_horiz; | ||
223 | } | ||
224 | |||
225 | static void handle_finish(struct sway_seat *seat) { | ||
226 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
227 | |||
228 | if (!e->target_node) { | ||
229 | handle_abort(seat); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | struct sway_container *con = e->con; | ||
234 | struct sway_container *old_parent = con->parent; | ||
235 | struct sway_workspace *old_ws = con->workspace; | ||
236 | struct sway_node *target_node = e->target_node; | ||
237 | struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? | ||
238 | target_node->sway_workspace : target_node->sway_container->workspace; | ||
239 | enum wlr_edges edge = e->target_edge; | ||
240 | int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; | ||
241 | |||
242 | container_detach(con); | ||
243 | |||
244 | // Moving container into empty workspace | ||
245 | if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { | ||
246 | workspace_add_tiling(new_ws, con); | ||
247 | } else if (target_node->type == N_CONTAINER) { | ||
248 | // Moving container before/after another | ||
249 | struct sway_container *target = target_node->sway_container; | ||
250 | enum sway_container_layout layout = container_parent_layout(target); | ||
251 | if (edge && !is_parallel(layout, edge)) { | ||
252 | enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || | ||
253 | edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; | ||
254 | container_split(target, new_layout); | ||
255 | } | ||
256 | container_add_sibling(target, con, after); | ||
257 | } else { | ||
258 | // Target is a workspace which requires splitting | ||
259 | enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || | ||
260 | edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; | ||
261 | workspace_split(new_ws, new_layout); | ||
262 | workspace_insert_tiling(new_ws, con, after); | ||
263 | } | ||
264 | |||
265 | if (old_parent) { | ||
266 | container_reap_empty(old_parent); | ||
267 | } | ||
268 | |||
269 | // This is a bit dirty, but we'll set the dimensions to that of a sibling. | ||
270 | // I don't think there's any other way to make it consistent without | ||
271 | // changing how we auto-size containers. | ||
272 | list_t *siblings = container_get_siblings(con); | ||
273 | if (siblings->length > 1) { | ||
274 | int index = list_find(siblings, con); | ||
275 | struct sway_container *sibling = index == 0 ? | ||
276 | siblings->items[1] : siblings->items[index - 1]; | ||
277 | con->width = sibling->width; | ||
278 | con->height = sibling->height; | ||
279 | } | ||
280 | |||
281 | arrange_workspace(old_ws); | ||
282 | if (new_ws != old_ws) { | ||
283 | arrange_workspace(new_ws); | ||
284 | } | ||
285 | |||
286 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
287 | } | ||
288 | |||
289 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | ||
290 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
291 | if (e->target_node == &con->node) { // Drop target | ||
292 | e->target_node = NULL; | ||
293 | } | ||
294 | if (e->con == con) { // The container being moved | ||
295 | seatop_abort(seat); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static const struct sway_seatop_impl seatop_impl = { | ||
300 | .motion = handle_motion, | ||
301 | .finish = handle_finish, | ||
302 | .abort = handle_abort, | ||
303 | .unref = handle_unref, | ||
304 | .render = handle_render, | ||
305 | }; | ||
306 | |||
307 | void seatop_begin_move_tiling_threshold(struct sway_seat *seat, | ||
308 | struct sway_container *con, uint32_t button) { | ||
309 | seatop_abort(seat); | ||
310 | |||
311 | struct seatop_move_tiling_event *e = | ||
312 | calloc(1, sizeof(struct seatop_move_tiling_event)); | ||
313 | if (!e) { | ||
314 | return; | ||
315 | } | ||
316 | e->con = con; | ||
317 | e->ref_lx = seat->cursor->cursor->x; | ||
318 | e->ref_ly = seat->cursor->cursor->y; | ||
319 | |||
320 | seat->seatop_impl = &seatop_impl; | ||
321 | seat->seatop_data = e; | ||
322 | seat->seatop_button = button; | ||
323 | |||
324 | container_raise_floating(con); | ||
325 | } | ||
326 | |||
327 | void seatop_begin_move_tiling(struct sway_seat *seat, | ||
328 | struct sway_container *con, uint32_t button) { | ||
329 | seatop_begin_move_tiling_threshold(seat, con, button); | ||
330 | struct seatop_move_tiling_event *e = seat->seatop_data; | ||
331 | if (e) { | ||
332 | e->threshold_reached = true; | ||
333 | cursor_set_image(seat->cursor, "grab", NULL); | ||
334 | } | ||
335 | } | ||
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c new file mode 100644 index 00000000..12851b40 --- /dev/null +++ b/sway/input/seatop_resize_floating.c | |||
@@ -0,0 +1,199 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | ||
3 | #include <wlr/types/wlr_cursor.h> | ||
4 | #include <wlr/types/wlr_xcursor_manager.h> | ||
5 | #include "sway/input/cursor.h" | ||
6 | #include "sway/input/seat.h" | ||
7 | #include "sway/tree/arrange.h" | ||
8 | #include "sway/tree/view.h" | ||
9 | #include "sway/tree/workspace.h" | ||
10 | |||
11 | struct seatop_resize_floating_event { | ||
12 | struct sway_container *con; | ||
13 | enum wlr_edges edge; | ||
14 | bool preserve_ratio; | ||
15 | double ref_lx, ref_ly; // cursor's x/y at start of op | ||
16 | double ref_width, ref_height; // container's size at start of op | ||
17 | double ref_con_lx, ref_con_ly; // container's x/y at start of op | ||
18 | }; | ||
19 | |||
20 | static void calculate_floating_constraints(struct sway_container *con, | ||
21 | int *min_width, int *max_width, int *min_height, int *max_height) { | ||
22 | if (config->floating_minimum_width == -1) { // no minimum | ||
23 | *min_width = 0; | ||
24 | } else if (config->floating_minimum_width == 0) { // automatic | ||
25 | *min_width = 75; | ||
26 | } else { | ||
27 | *min_width = config->floating_minimum_width; | ||
28 | } | ||
29 | |||
30 | if (config->floating_minimum_height == -1) { // no minimum | ||
31 | *min_height = 0; | ||
32 | } else if (config->floating_minimum_height == 0) { // automatic | ||
33 | *min_height = 50; | ||
34 | } else { | ||
35 | *min_height = config->floating_minimum_height; | ||
36 | } | ||
37 | |||
38 | if (config->floating_maximum_width == -1) { // no maximum | ||
39 | *max_width = INT_MAX; | ||
40 | } else if (config->floating_maximum_width == 0) { // automatic | ||
41 | *max_width = con->workspace->width; | ||
42 | } else { | ||
43 | *max_width = config->floating_maximum_width; | ||
44 | } | ||
45 | |||
46 | if (config->floating_maximum_height == -1) { // no maximum | ||
47 | *max_height = INT_MAX; | ||
48 | } else if (config->floating_maximum_height == 0) { // automatic | ||
49 | *max_height = con->workspace->height; | ||
50 | } else { | ||
51 | *max_height = config->floating_maximum_height; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
56 | struct seatop_resize_floating_event *e = seat->seatop_data; | ||
57 | struct sway_container *con = e->con; | ||
58 | enum wlr_edges edge = e->edge; | ||
59 | struct sway_cursor *cursor = seat->cursor; | ||
60 | |||
61 | // The amount the mouse has moved since the start of the resize operation | ||
62 | // Positive is down/right | ||
63 | double mouse_move_x = cursor->cursor->x - e->ref_lx; | ||
64 | double mouse_move_y = cursor->cursor->y - e->ref_ly; | ||
65 | |||
66 | if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { | ||
67 | mouse_move_x = 0; | ||
68 | } | ||
69 | if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { | ||
70 | mouse_move_y = 0; | ||
71 | } | ||
72 | |||
73 | double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x; | ||
74 | double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y; | ||
75 | |||
76 | if (e->preserve_ratio) { | ||
77 | double x_multiplier = grow_width / e->ref_width; | ||
78 | double y_multiplier = grow_height / e->ref_height; | ||
79 | double max_multiplier = fmax(x_multiplier, y_multiplier); | ||
80 | grow_width = e->ref_width * max_multiplier; | ||
81 | grow_height = e->ref_height * max_multiplier; | ||
82 | } | ||
83 | |||
84 | // Determine new width/height, and accommodate for floating min/max values | ||
85 | double width = e->ref_width + grow_width; | ||
86 | double height = e->ref_height + grow_height; | ||
87 | int min_width, max_width, min_height, max_height; | ||
88 | calculate_floating_constraints(con, &min_width, &max_width, | ||
89 | &min_height, &max_height); | ||
90 | width = fmax(min_width, fmin(width, max_width)); | ||
91 | height = fmax(min_height, fmin(height, max_height)); | ||
92 | |||
93 | // Apply the view's min/max size | ||
94 | if (con->view) { | ||
95 | double view_min_width, view_max_width, view_min_height, view_max_height; | ||
96 | view_get_constraints(con->view, &view_min_width, &view_max_width, | ||
97 | &view_min_height, &view_max_height); | ||
98 | width = fmax(view_min_width, fmin(width, view_max_width)); | ||
99 | height = fmax(view_min_height, fmin(height, view_max_height)); | ||
100 | } | ||
101 | |||
102 | // Recalculate these, in case we hit a min/max limit | ||
103 | grow_width = width - e->ref_width; | ||
104 | grow_height = height - e->ref_height; | ||
105 | |||
106 | // Determine grow x/y values - these are relative to the container's x/y at | ||
107 | // the start of the resize operation. | ||
108 | double grow_x = 0, grow_y = 0; | ||
109 | if (edge & WLR_EDGE_LEFT) { | ||
110 | grow_x = -grow_width; | ||
111 | } else if (edge & WLR_EDGE_RIGHT) { | ||
112 | grow_x = 0; | ||
113 | } else { | ||
114 | grow_x = -grow_width / 2; | ||
115 | } | ||
116 | if (edge & WLR_EDGE_TOP) { | ||
117 | grow_y = -grow_height; | ||
118 | } else if (edge & WLR_EDGE_BOTTOM) { | ||
119 | grow_y = 0; | ||
120 | } else { | ||
121 | grow_y = -grow_height / 2; | ||
122 | } | ||
123 | |||
124 | // Determine the amounts we need to bump everything relative to the current | ||
125 | // size. | ||
126 | int relative_grow_width = width - con->width; | ||
127 | int relative_grow_height = height - con->height; | ||
128 | int relative_grow_x = (e->ref_con_lx + grow_x) - con->x; | ||
129 | int relative_grow_y = (e->ref_con_ly + grow_y) - con->y; | ||
130 | |||
131 | // Actually resize stuff | ||
132 | con->x += relative_grow_x; | ||
133 | con->y += relative_grow_y; | ||
134 | con->width += relative_grow_width; | ||
135 | con->height += relative_grow_height; | ||
136 | |||
137 | con->content_x += relative_grow_x; | ||
138 | con->content_y += relative_grow_y; | ||
139 | con->content_width += relative_grow_width; | ||
140 | con->content_height += relative_grow_height; | ||
141 | |||
142 | arrange_container(con); | ||
143 | } | ||
144 | |||
145 | static void handle_finish(struct sway_seat *seat) { | ||
146 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
147 | } | ||
148 | |||
149 | static void handle_abort(struct sway_seat *seat) { | ||
150 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
151 | } | ||
152 | |||
153 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | ||
154 | struct seatop_resize_floating_event *e = seat->seatop_data; | ||
155 | if (e->con == con) { | ||
156 | seatop_abort(seat); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static const struct sway_seatop_impl seatop_impl = { | ||
161 | .motion = handle_motion, | ||
162 | .finish = handle_finish, | ||
163 | .abort = handle_abort, | ||
164 | .unref = handle_unref, | ||
165 | }; | ||
166 | |||
167 | void seatop_begin_resize_floating(struct sway_seat *seat, | ||
168 | struct sway_container *con, uint32_t button, enum wlr_edges edge) { | ||
169 | seatop_abort(seat); | ||
170 | |||
171 | struct seatop_resize_floating_event *e = | ||
172 | calloc(1, sizeof(struct seatop_resize_floating_event)); | ||
173 | if (!e) { | ||
174 | return; | ||
175 | } | ||
176 | e->con = con; | ||
177 | |||
178 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | ||
179 | e->preserve_ratio = keyboard && | ||
180 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); | ||
181 | |||
182 | e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; | ||
183 | e->ref_lx = seat->cursor->cursor->x; | ||
184 | e->ref_ly = seat->cursor->cursor->y; | ||
185 | e->ref_con_lx = con->x; | ||
186 | e->ref_con_ly = con->y; | ||
187 | e->ref_width = con->width; | ||
188 | e->ref_height = con->height; | ||
189 | |||
190 | seat->seatop_impl = &seatop_impl; | ||
191 | seat->seatop_data = e; | ||
192 | seat->seatop_button = button; | ||
193 | |||
194 | container_raise_floating(con); | ||
195 | |||
196 | const char *image = edge == WLR_EDGE_NONE ? | ||
197 | "se-resize" : wlr_xcursor_get_resize_name(edge); | ||
198 | cursor_set_image(seat->cursor, image, NULL); | ||
199 | } | ||
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c new file mode 100644 index 00000000..30431f04 --- /dev/null +++ b/sway/input/seatop_resize_tiling.c | |||
@@ -0,0 +1,92 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <wlr/types/wlr_cursor.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/input/cursor.h" | ||
5 | #include "sway/input/seat.h" | ||
6 | |||
7 | struct seatop_resize_tiling_event { | ||
8 | struct sway_container *con; | ||
9 | enum wlr_edges edge; | ||
10 | 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 | ||
12 | double ref_con_lx, ref_con_ly; // container's x/y at start of op | ||
13 | }; | ||
14 | |||
15 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | ||
16 | struct seatop_resize_tiling_event *e = seat->seatop_data; | ||
17 | int amount_x = 0; | ||
18 | int amount_y = 0; | ||
19 | int moved_x = seat->cursor->cursor->x - e->ref_lx; | ||
20 | int moved_y = seat->cursor->cursor->y - e->ref_ly; | ||
21 | enum wlr_edges edge_x = WLR_EDGE_NONE; | ||
22 | enum wlr_edges edge_y = WLR_EDGE_NONE; | ||
23 | struct sway_container *con = e->con; | ||
24 | |||
25 | if (e->edge & WLR_EDGE_TOP) { | ||
26 | amount_y = (e->ref_height - moved_y) - con->height; | ||
27 | edge_y = WLR_EDGE_TOP; | ||
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 | } | ||
32 | if (e->edge & WLR_EDGE_LEFT) { | ||
33 | amount_x = (e->ref_width - moved_x) - con->width; | ||
34 | edge_x = WLR_EDGE_LEFT; | ||
35 | } else if (e->edge & WLR_EDGE_RIGHT) { | ||
36 | amount_x = (e->ref_width + moved_x) - con->width; | ||
37 | edge_x = WLR_EDGE_RIGHT; | ||
38 | } | ||
39 | |||
40 | if (amount_x != 0) { | ||
41 | container_resize_tiled(e->con, edge_x, amount_x); | ||
42 | } | ||
43 | if (amount_y != 0) { | ||
44 | container_resize_tiled(e->con, edge_y, amount_y); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | static void handle_finish(struct sway_seat *seat) { | ||
49 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
50 | } | ||
51 | |||
52 | static void handle_abort(struct sway_seat *seat) { | ||
53 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
54 | } | ||
55 | |||
56 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | ||
57 | struct seatop_resize_tiling_event *e = seat->seatop_data; | ||
58 | if (e->con == con) { | ||
59 | seatop_abort(seat); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | static const struct sway_seatop_impl seatop_impl = { | ||
64 | .motion = handle_motion, | ||
65 | .finish = handle_finish, | ||
66 | .abort = handle_abort, | ||
67 | .unref = handle_unref, | ||
68 | }; | ||
69 | |||
70 | void seatop_begin_resize_tiling(struct sway_seat *seat, | ||
71 | struct sway_container *con, uint32_t button, enum wlr_edges edge) { | ||
72 | seatop_abort(seat); | ||
73 | |||
74 | struct seatop_resize_tiling_event *e = | ||
75 | calloc(1, sizeof(struct seatop_resize_tiling_event)); | ||
76 | if (!e) { | ||
77 | return; | ||
78 | } | ||
79 | e->con = con; | ||
80 | e->edge = edge; | ||
81 | |||
82 | e->ref_lx = seat->cursor->cursor->x; | ||
83 | e->ref_ly = seat->cursor->cursor->y; | ||
84 | e->ref_con_lx = con->x; | ||
85 | e->ref_con_ly = con->y; | ||
86 | e->ref_width = con->width; | ||
87 | e->ref_height = con->height; | ||
88 | |||
89 | seat->seatop_impl = &seatop_impl; | ||
90 | seat->seatop_data = e; | ||
91 | seat->seatop_button = button; | ||
92 | } | ||