diff options
-rw-r--r-- | sway/input/cursor.c | 190 |
1 files changed, 94 insertions, 96 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 4b689535..d4dc617a 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -175,7 +175,7 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
175 | return true; | 175 | return true; |
176 | } | 176 | } |
177 | 177 | ||
178 | static enum wlr_edges find_resize_edge(struct sway_container *cont, | 178 | static enum wlr_edges find_edge(struct sway_container *cont, |
179 | struct sway_cursor *cursor) { | 179 | struct sway_cursor *cursor) { |
180 | if (cont->type != C_VIEW) { | 180 | if (cont->type != C_VIEW) { |
181 | return WLR_EDGE_NONE; | 181 | return WLR_EDGE_NONE; |
@@ -199,10 +199,19 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont, | |||
199 | edge |= WLR_EDGE_BOTTOM; | 199 | edge |= WLR_EDGE_BOTTOM; |
200 | } | 200 | } |
201 | 201 | ||
202 | return edge; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * If the cursor is over a _resizable_ edge, return the edge. | ||
207 | * Edges that can't be resized are edges of the workspace. | ||
208 | */ | ||
209 | static enum wlr_edges find_resize_edge(struct sway_container *cont, | ||
210 | struct sway_cursor *cursor) { | ||
211 | enum wlr_edges edge = find_edge(cont, cursor); | ||
202 | if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) { | 212 | if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) { |
203 | return WLR_EDGE_NONE; | 213 | return WLR_EDGE_NONE; |
204 | } | 214 | } |
205 | |||
206 | return edge; | 215 | return edge; |
207 | } | 216 | } |
208 | 217 | ||
@@ -500,57 +509,6 @@ static void handle_cursor_motion_absolute( | |||
500 | transaction_commit_dirty(); | 509 | transaction_commit_dirty(); |
501 | } | 510 | } |
502 | 511 | ||
503 | static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | ||
504 | uint32_t time_msec, uint32_t button, enum wlr_button_state state, | ||
505 | struct wlr_surface *surface, double sx, double sy, | ||
506 | struct sway_container *cont) { | ||
507 | struct sway_seat *seat = cursor->seat; | ||
508 | |||
509 | seat_set_focus(seat, cont); | ||
510 | |||
511 | // Deny moving or resizing a fullscreen container | ||
512 | if (container_is_fullscreen_or_child(cont)) { | ||
513 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
514 | return; | ||
515 | } | ||
516 | struct sway_container *floater = cont; | ||
517 | while (floater->parent->layout != L_FLOATING) { | ||
518 | floater = floater->parent; | ||
519 | } | ||
520 | |||
521 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | ||
522 | bool mod_pressed = keyboard && | ||
523 | (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); | ||
524 | enum wlr_edges edge = find_resize_edge(floater, cursor); | ||
525 | bool over_title = edge == WLR_EDGE_NONE && !surface; | ||
526 | |||
527 | // Check for beginning move | ||
528 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | ||
529 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | ||
530 | (mod_pressed || over_title)) { | ||
531 | seat_begin_move(seat, floater, button); | ||
532 | return; | ||
533 | } | ||
534 | |||
535 | // Check for beginning resize | ||
536 | bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE; | ||
537 | uint32_t btn_resize = config->floating_mod_inverse ? BTN_LEFT : BTN_RIGHT; | ||
538 | bool resizing_via_mod = button == btn_resize && mod_pressed; | ||
539 | if ((resizing_via_border || resizing_via_mod) && | ||
540 | state == WLR_BUTTON_PRESSED) { | ||
541 | if (edge == WLR_EDGE_NONE) { | ||
542 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? | ||
543 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | ||
544 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? | ||
545 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | ||
546 | } | ||
547 | seat_begin_resize_floating(seat, floater, button, edge); | ||
548 | return; | ||
549 | } | ||
550 | |||
551 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
552 | } | ||
553 | |||
554 | /** | 512 | /** |
555 | * Remove a button (and duplicates) to the sorted list of currently pressed buttons | 513 | * Remove a button (and duplicates) to the sorted list of currently pressed buttons |
556 | */ | 514 | */ |
@@ -630,26 +588,36 @@ static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *c | |||
630 | 588 | ||
631 | void dispatch_cursor_button(struct sway_cursor *cursor, | 589 | void dispatch_cursor_button(struct sway_cursor *cursor, |
632 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { | 590 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { |
591 | if (time_msec == 0) { | ||
592 | time_msec = get_current_time_msec(); | ||
593 | } | ||
594 | struct sway_seat *seat = cursor->seat; | ||
595 | |||
596 | // Handle ending seat operation | ||
633 | if (cursor->seat->operation != OP_NONE && | 597 | if (cursor->seat->operation != OP_NONE && |
634 | button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) { | 598 | button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) { |
635 | seat_end_mouse_operation(cursor->seat); | 599 | seat_end_mouse_operation(seat); |
636 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | 600 | seat_pointer_notify_button(seat, time_msec, button, state); |
637 | return; | 601 | return; |
638 | } | 602 | } |
639 | if (time_msec == 0) { | ||
640 | time_msec = get_current_time_msec(); | ||
641 | } | ||
642 | 603 | ||
604 | // Determine what's under the cursor | ||
643 | struct wlr_surface *surface = NULL; | 605 | struct wlr_surface *surface = NULL; |
644 | double sx, sy; | 606 | double sx, sy; |
645 | struct sway_container *cont = container_at_coords(cursor->seat, | 607 | struct sway_container *cont = container_at_coords(seat, |
646 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 608 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
609 | bool is_floating = cont && container_is_floating(cont); | ||
610 | bool is_floating_or_child = cont && container_is_floating_or_child(cont); | ||
611 | bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont); | ||
612 | enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; | ||
613 | enum wlr_edges resize_edge = edge ? | ||
614 | find_resize_edge(cont, cursor) : WLR_EDGE_NONE; | ||
615 | bool on_border = edge != WLR_EDGE_NONE; | ||
616 | bool on_contents = cont && !on_border && surface; | ||
617 | bool on_titlebar = cont && !on_border && !surface; | ||
647 | 618 | ||
648 | // Handle mouse bindings | 619 | // Handle mouse bindings |
649 | bool on_border = cont && (find_resize_edge(cont, cursor) != WLR_EDGE_NONE); | 620 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
650 | bool on_contents = !on_border && surface; | ||
651 | bool on_titlebar = !on_border && !surface; | ||
652 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); | ||
653 | uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; | 621 | uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; |
654 | 622 | ||
655 | struct sway_binding *binding = NULL; | 623 | struct sway_binding *binding = NULL; |
@@ -665,51 +633,78 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
665 | state_erase_button(cursor, button); | 633 | state_erase_button(cursor, button); |
666 | } | 634 | } |
667 | if (binding) { | 635 | if (binding) { |
668 | seat_execute_command(cursor->seat, binding); | 636 | seat_execute_command(seat, binding); |
669 | // TODO: do we want to pass on the event? | 637 | return; |
670 | } | 638 | } |
671 | 639 | ||
672 | enum wlr_edges edge = cont ? find_resize_edge(cont, cursor) : WLR_EDGE_NONE; | 640 | // Handle clicking a layer surface |
673 | |||
674 | if (surface && wlr_surface_is_layer_surface(surface)) { | 641 | if (surface && wlr_surface_is_layer_surface(surface)) { |
675 | struct wlr_layer_surface *layer = | 642 | struct wlr_layer_surface *layer = |
676 | wlr_layer_surface_from_wlr_surface(surface); | 643 | wlr_layer_surface_from_wlr_surface(surface); |
677 | if (layer->current.keyboard_interactive) { | 644 | if (layer->current.keyboard_interactive) { |
678 | seat_set_focus_layer(cursor->seat, layer); | 645 | seat_set_focus_layer(seat, layer); |
646 | } | ||
647 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
648 | return; | ||
649 | } | ||
650 | |||
651 | // Handle tiling resize via border | ||
652 | if (resize_edge && button == BTN_LEFT && !is_floating) { | ||
653 | seat_set_focus(seat, cont); | ||
654 | seat_begin_resize_tiling(seat, cont, button, edge); | ||
655 | return; | ||
656 | } | ||
657 | |||
658 | // Handle beginning floating move | ||
659 | bool mod_pressed = keyboard && | ||
660 | (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); | ||
661 | |||
662 | if (is_floating_or_child && !is_fullscreen_or_child) { | ||
663 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | ||
664 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | ||
665 | (mod_pressed || on_titlebar)) { | ||
666 | while (cont->parent->layout != L_FLOATING) { | ||
667 | cont = cont->parent; | ||
668 | } | ||
669 | seat_begin_move(seat, cont, button); | ||
670 | return; | ||
679 | } | 671 | } |
680 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | 672 | } |
681 | } else if (edge && button == BTN_LEFT && | 673 | |
682 | !container_is_floating(cont)) { | 674 | // Handle beginning floating resize |
683 | seat_set_focus(cursor->seat, cont); | 675 | if (is_floating_or_child && !is_fullscreen_or_child && |
684 | seat_begin_resize_tiling(cursor->seat, cont, BTN_LEFT, edge); | 676 | state == WLR_BUTTON_PRESSED) { |
685 | } else if (cont && container_is_floating_or_child(cont)) { | 677 | // Via border |
686 | dispatch_cursor_button_floating(cursor, time_msec, button, state, | 678 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { |
687 | surface, sx, sy, cont); | 679 | seat_begin_resize_floating(seat, cont, button, resize_edge); |
688 | } else if (surface && cont && cont->type != C_VIEW) { | 680 | return; |
689 | // Avoid moving keyboard focus from a surface that accepts it to one | ||
690 | // that does not unless the change would move us to a new workspace. | ||
691 | // | ||
692 | // This prevents, for example, losing focus when clicking on swaybar. | ||
693 | struct sway_container *new_ws = cont; | ||
694 | if (new_ws && new_ws->type != C_WORKSPACE) { | ||
695 | new_ws = container_parent(new_ws, C_WORKSPACE); | ||
696 | } | 681 | } |
697 | struct sway_container *old_ws = seat_get_focus(cursor->seat); | 682 | |
698 | if (old_ws && old_ws->type != C_WORKSPACE) { | 683 | // Via mod+click |
699 | old_ws = container_parent(old_ws, C_WORKSPACE); | 684 | struct sway_container *floater = cont; |
685 | while (floater->parent->layout != L_FLOATING) { | ||
686 | floater = floater->parent; | ||
700 | } | 687 | } |
701 | if (new_ws != old_ws) { | 688 | uint32_t btn_resize = config->floating_mod_inverse ? |
702 | seat_set_focus(cursor->seat, cont); | 689 | BTN_LEFT : BTN_RIGHT; |
690 | if (button == btn_resize) { | ||
691 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? | ||
692 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | ||
693 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? | ||
694 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | ||
695 | seat_begin_resize_floating(seat, floater, button, edge); | ||
696 | return; | ||
703 | } | 697 | } |
704 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | ||
705 | } else if (cont) { | ||
706 | seat_set_focus(cursor->seat, cont); | ||
707 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | ||
708 | } else { | ||
709 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | ||
710 | } | 698 | } |
711 | 699 | ||
712 | transaction_commit_dirty(); | 700 | // Handle clicking a container surface |
701 | if (cont) { | ||
702 | seat_set_focus(seat, cont); | ||
703 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
704 | return; | ||
705 | } | ||
706 | |||
707 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
713 | } | 708 | } |
714 | 709 | ||
715 | static void handle_cursor_button(struct wl_listener *listener, void *data) { | 710 | static void handle_cursor_button(struct wl_listener *listener, void *data) { |
@@ -718,6 +713,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { | |||
718 | struct wlr_event_pointer_button *event = data; | 713 | struct wlr_event_pointer_button *event = data; |
719 | dispatch_cursor_button(cursor, | 714 | dispatch_cursor_button(cursor, |
720 | event->time_msec, event->button, event->state); | 715 | event->time_msec, event->button, event->state); |
716 | transaction_commit_dirty(); | ||
721 | } | 717 | } |
722 | 718 | ||
723 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { | 719 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { |
@@ -865,6 +861,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { | |||
865 | dispatch_cursor_button(cursor, event->time_msec, | 861 | dispatch_cursor_button(cursor, event->time_msec, |
866 | BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? | 862 | BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? |
867 | WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); | 863 | WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); |
864 | transaction_commit_dirty(); | ||
868 | } | 865 | } |
869 | 866 | ||
870 | static void handle_tool_button(struct wl_listener *listener, void *data) { | 867 | static void handle_tool_button(struct wl_listener *listener, void *data) { |
@@ -889,6 +886,7 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { | |||
889 | cursor->tool_buttons--; | 886 | cursor->tool_buttons--; |
890 | break; | 887 | break; |
891 | } | 888 | } |
889 | transaction_commit_dirty(); | ||
892 | } | 890 | } |
893 | 891 | ||
894 | static void handle_request_set_cursor(struct wl_listener *listener, | 892 | static void handle_request_set_cursor(struct wl_listener *listener, |