diff options
Diffstat (limited to 'sway/input/seatop_default.c')
-rw-r--r-- | sway/input/seatop_default.c | 541 |
1 files changed, 457 insertions, 84 deletions
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index a583ed62..c56330fd 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c | |||
@@ -2,12 +2,17 @@ | |||
2 | #include <float.h> | 2 | #include <float.h> |
3 | #include <libevdev/libevdev.h> | 3 | #include <libevdev/libevdev.h> |
4 | #include <wlr/types/wlr_cursor.h> | 4 | #include <wlr/types/wlr_cursor.h> |
5 | #include <wlr/types/wlr_subcompositor.h> | ||
5 | #include <wlr/types/wlr_tablet_v2.h> | 6 | #include <wlr/types/wlr_tablet_v2.h> |
6 | #include <wlr/types/wlr_xcursor_manager.h> | 7 | #include <wlr/types/wlr_xcursor_manager.h> |
8 | #include "gesture.h" | ||
9 | #include "sway/desktop/transaction.h" | ||
7 | #include "sway/input/cursor.h" | 10 | #include "sway/input/cursor.h" |
8 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
9 | #include "sway/input/tablet.h" | 12 | #include "sway/input/tablet.h" |
13 | #include "sway/layers.h" | ||
10 | #include "sway/output.h" | 14 | #include "sway/output.h" |
15 | #include "sway/scene_descriptor.h" | ||
11 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
12 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
13 | #include "log.h" | 18 | #include "log.h" |
@@ -19,6 +24,7 @@ struct seatop_default_event { | |||
19 | struct sway_node *previous_node; | 24 | struct sway_node *previous_node; |
20 | uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; | 25 | uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; |
21 | size_t pressed_button_count; | 26 | size_t pressed_button_count; |
27 | struct gesture_tracker gestures; | ||
22 | }; | 28 | }; |
23 | 29 | ||
24 | /*-----------------------------------------\ | 30 | /*-----------------------------------------\ |
@@ -50,6 +56,9 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
50 | while (cont) { | 56 | while (cont) { |
51 | if (container_parent_layout(cont) == layout) { | 57 | if (container_parent_layout(cont) == layout) { |
52 | list_t *siblings = container_get_siblings(cont); | 58 | list_t *siblings = container_get_siblings(cont); |
59 | if (!siblings) { | ||
60 | return false; | ||
61 | } | ||
53 | int index = list_find(siblings, cont); | 62 | int index = list_find(siblings, cont); |
54 | if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { | 63 | if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { |
55 | return false; | 64 | return false; |
@@ -59,7 +68,7 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
59 | return false; | 68 | return false; |
60 | } | 69 | } |
61 | } | 70 | } |
62 | cont = cont->parent; | 71 | cont = cont->pending.parent; |
63 | } | 72 | } |
64 | return true; | 73 | return true; |
65 | } | 74 | } |
@@ -69,25 +78,25 @@ static enum wlr_edges find_edge(struct sway_container *cont, | |||
69 | if (!cont->view || (surface && cont->view->surface != surface)) { | 78 | if (!cont->view || (surface && cont->view->surface != surface)) { |
70 | return WLR_EDGE_NONE; | 79 | return WLR_EDGE_NONE; |
71 | } | 80 | } |
72 | if (cont->border == B_NONE || !cont->border_thickness || | 81 | if (cont->pending.border == B_NONE || !cont->pending.border_thickness || |
73 | cont->border == B_CSD) { | 82 | cont->pending.border == B_CSD) { |
74 | return WLR_EDGE_NONE; | 83 | return WLR_EDGE_NONE; |
75 | } | 84 | } |
76 | if (cont->fullscreen_mode) { | 85 | if (cont->pending.fullscreen_mode) { |
77 | return WLR_EDGE_NONE; | 86 | return WLR_EDGE_NONE; |
78 | } | 87 | } |
79 | 88 | ||
80 | enum wlr_edges edge = 0; | 89 | enum wlr_edges edge = 0; |
81 | if (cursor->cursor->x < cont->x + cont->border_thickness) { | 90 | if (cursor->cursor->x < cont->pending.x + cont->pending.border_thickness) { |
82 | edge |= WLR_EDGE_LEFT; | 91 | edge |= WLR_EDGE_LEFT; |
83 | } | 92 | } |
84 | if (cursor->cursor->y < cont->y + cont->border_thickness) { | 93 | if (cursor->cursor->y < cont->pending.y + cont->pending.border_thickness) { |
85 | edge |= WLR_EDGE_TOP; | 94 | edge |= WLR_EDGE_TOP; |
86 | } | 95 | } |
87 | if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { | 96 | if (cursor->cursor->x >= cont->pending.x + cont->pending.width - cont->pending.border_thickness) { |
88 | edge |= WLR_EDGE_RIGHT; | 97 | edge |= WLR_EDGE_RIGHT; |
89 | } | 98 | } |
90 | if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { | 99 | if (cursor->cursor->y >= cont->pending.y + cont->pending.height - cont->pending.border_thickness) { |
91 | edge |= WLR_EDGE_BOTTOM; | 100 | edge |= WLR_EDGE_BOTTOM; |
92 | } | 101 | } |
93 | 102 | ||
@@ -225,13 +234,15 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
225 | struct sway_container *cont = node && node->type == N_CONTAINER ? | 234 | struct sway_container *cont = node && node->type == N_CONTAINER ? |
226 | node->sway_container : NULL; | 235 | node->sway_container : NULL; |
227 | 236 | ||
228 | if (wlr_surface_is_layer_surface(surface)) { | 237 | struct wlr_layer_surface_v1 *layer; |
238 | #if HAVE_XWAYLAND | ||
239 | struct wlr_xwayland_surface *xsurface; | ||
240 | #endif | ||
241 | if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) && | ||
242 | layer->current.keyboard_interactive) { | ||
229 | // Handle tapping a layer surface | 243 | // Handle tapping a layer surface |
230 | struct wlr_layer_surface_v1 *layer = | 244 | seat_set_focus_layer(seat, layer); |
231 | wlr_layer_surface_v1_from_wlr_surface(surface); | 245 | transaction_commit_dirty(); |
232 | if (layer->current.keyboard_interactive) { | ||
233 | seat_set_focus_layer(seat, layer); | ||
234 | } | ||
235 | } else if (cont) { | 246 | } else if (cont) { |
236 | bool is_floating_or_child = container_is_floating_or_child(cont); | 247 | bool is_floating_or_child = container_is_floating_or_child(cont); |
237 | bool is_fullscreen_or_child = container_is_fullscreen_or_child(cont); | 248 | bool is_fullscreen_or_child = container_is_fullscreen_or_child(cont); |
@@ -249,26 +260,24 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
249 | 260 | ||
250 | // Handle moving a tiling container | 261 | // Handle moving a tiling container |
251 | if (config->tiling_drag && mod_pressed && !is_floating_or_child && | 262 | if (config->tiling_drag && mod_pressed && !is_floating_or_child && |
252 | cont->fullscreen_mode == FULLSCREEN_NONE) { | 263 | cont->pending.fullscreen_mode == FULLSCREEN_NONE) { |
253 | seatop_begin_move_tiling(seat, cont); | 264 | seatop_begin_move_tiling(seat, cont); |
254 | return; | 265 | return; |
255 | } | 266 | } |
256 | 267 | ||
257 | // Handle tapping on a container surface | 268 | // Handle tapping on a container surface |
258 | seat_set_focus_container(seat, cont); | 269 | seat_set_focus_container(seat, cont); |
259 | seatop_begin_down(seat, node->sway_container, time_msec, sx, sy); | 270 | seatop_begin_down(seat, node->sway_container, sx, sy); |
260 | } | 271 | } |
261 | #if HAVE_XWAYLAND | 272 | #if HAVE_XWAYLAND |
262 | // Handle tapping on an xwayland unmanaged view | 273 | // Handle tapping on an xwayland unmanaged view |
263 | else if (wlr_surface_is_xwayland_surface(surface)) { | 274 | else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && |
264 | struct wlr_xwayland_surface *xsurface = | 275 | xsurface->override_redirect && |
265 | wlr_xwayland_surface_from_wlr_surface(surface); | 276 | wlr_xwayland_or_surface_wants_focus(xsurface)) { |
266 | if (xsurface->override_redirect && | 277 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
267 | wlr_xwayland_or_surface_wants_focus(xsurface)) { | 278 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
268 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 279 | seat_set_focus_surface(seat, xsurface->surface, false); |
269 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 280 | transaction_commit_dirty(); |
270 | seat_set_focus_surface(seat, xsurface->surface, false); | ||
271 | } | ||
272 | } | 281 | } |
273 | #endif | 282 | #endif |
274 | 283 | ||
@@ -356,17 +365,21 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
356 | if (node && node->type == N_WORKSPACE) { | 365 | if (node && node->type == N_WORKSPACE) { |
357 | if (state == WLR_BUTTON_PRESSED) { | 366 | if (state == WLR_BUTTON_PRESSED) { |
358 | seat_set_focus(seat, node); | 367 | seat_set_focus(seat, node); |
368 | transaction_commit_dirty(); | ||
359 | } | 369 | } |
360 | seat_pointer_notify_button(seat, time_msec, button, state); | 370 | seat_pointer_notify_button(seat, time_msec, button, state); |
361 | return; | 371 | return; |
362 | } | 372 | } |
363 | 373 | ||
364 | // Handle clicking a layer surface | 374 | // Handle clicking a layer surface and its popups/subsurfaces |
365 | if (surface && wlr_surface_is_layer_surface(surface)) { | 375 | struct wlr_layer_surface_v1 *layer = NULL; |
366 | struct wlr_layer_surface_v1 *layer = | 376 | if ((layer = toplevel_layer_surface_from_surface(surface))) { |
367 | wlr_layer_surface_v1_from_wlr_surface(surface); | ||
368 | if (layer->current.keyboard_interactive) { | 377 | if (layer->current.keyboard_interactive) { |
369 | seat_set_focus_layer(seat, layer); | 378 | seat_set_focus_layer(seat, layer); |
379 | transaction_commit_dirty(); | ||
380 | } | ||
381 | if (state == WLR_BUTTON_PRESSED) { | ||
382 | seatop_begin_down_on_surface(seat, surface, sx, sy); | ||
370 | } | 383 | } |
371 | seat_pointer_notify_button(seat, time_msec, button, state); | 384 | seat_pointer_notify_button(seat, time_msec, button, state); |
372 | return; | 385 | return; |
@@ -381,7 +394,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
381 | struct sway_container *cont_to_focus = cont; | 394 | struct sway_container *cont_to_focus = cont; |
382 | enum sway_container_layout layout = container_parent_layout(cont); | 395 | enum sway_container_layout layout = container_parent_layout(cont); |
383 | if (layout == L_TABBED || layout == L_STACKED) { | 396 | if (layout == L_TABBED || layout == L_STACKED) { |
384 | cont_to_focus = seat_get_focus_inactive_view(seat, &cont->parent->node); | 397 | cont_to_focus = seat_get_focus_inactive_view(seat, &cont->pending.parent->node); |
385 | } | 398 | } |
386 | 399 | ||
387 | seat_set_focus_container(seat, cont_to_focus); | 400 | seat_set_focus_container(seat, cont_to_focus); |
@@ -397,9 +410,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
397 | BTN_LEFT : BTN_RIGHT; | 410 | BTN_LEFT : BTN_RIGHT; |
398 | if (button == btn_resize) { | 411 | if (button == btn_resize) { |
399 | edge = 0; | 412 | edge = 0; |
400 | edge |= cursor->cursor->x > cont->x + cont->width / 2 ? | 413 | edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ? |
401 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 414 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
402 | edge |= cursor->cursor->y > cont->y + cont->height / 2 ? | 415 | edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ? |
403 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 416 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
404 | 417 | ||
405 | const char *image = NULL; | 418 | const char *image = NULL; |
@@ -419,13 +432,31 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
419 | } | 432 | } |
420 | } | 433 | } |
421 | 434 | ||
435 | // Handle changing focus when clicking on a container | ||
436 | if (cont && state == WLR_BUTTON_PRESSED) { | ||
437 | // Default case: focus the container that was just clicked. | ||
438 | node = &cont->node; | ||
439 | |||
440 | // If the container is a tab/stacked container and the click happened | ||
441 | // on a tab, switch to the tab. If the tab contents were already | ||
442 | // focused, focus the tab container itself. If the tab container was | ||
443 | // already focused, cycle back to focusing the tab contents. | ||
444 | if (on_titlebar) { | ||
445 | struct sway_container *focus = seat_get_focused_container(seat); | ||
446 | if (focus == cont || !container_has_ancestor(focus, cont)) { | ||
447 | node = seat_get_focus_inactive(seat, &cont->node); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | seat_set_focus(seat, node); | ||
452 | transaction_commit_dirty(); | ||
453 | } | ||
454 | |||
422 | // Handle beginning floating move | 455 | // Handle beginning floating move |
423 | if (cont && is_floating_or_child && !is_fullscreen_or_child && | 456 | if (cont && is_floating_or_child && !is_fullscreen_or_child && |
424 | state == WLR_BUTTON_PRESSED) { | 457 | state == WLR_BUTTON_PRESSED) { |
425 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | 458 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
426 | if (button == btn_move && (mod_pressed || on_titlebar)) { | 459 | if (button == btn_move && (mod_pressed || on_titlebar)) { |
427 | seat_set_focus_container(seat, | ||
428 | seat_get_focus_inactive_view(seat, &cont->node)); | ||
429 | seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); | 460 | seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); |
430 | return; | 461 | return; |
431 | } | 462 | } |
@@ -436,6 +467,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
436 | state == WLR_BUTTON_PRESSED) { | 467 | state == WLR_BUTTON_PRESSED) { |
437 | // Via border | 468 | // Via border |
438 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { | 469 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { |
470 | seat_set_focus_container(seat, cont); | ||
439 | seatop_begin_resize_floating(seat, cont, resize_edge); | 471 | seatop_begin_resize_floating(seat, cont, resize_edge); |
440 | return; | 472 | return; |
441 | } | 473 | } |
@@ -446,10 +478,11 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
446 | if (mod_pressed && button == btn_resize) { | 478 | if (mod_pressed && button == btn_resize) { |
447 | struct sway_container *floater = container_toplevel_ancestor(cont); | 479 | struct sway_container *floater = container_toplevel_ancestor(cont); |
448 | edge = 0; | 480 | edge = 0; |
449 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? | 481 | edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ? |
450 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 482 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
451 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? | 483 | edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ? |
452 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 484 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
485 | seat_set_focus_container(seat, floater); | ||
453 | seatop_begin_resize_floating(seat, floater, edge); | 486 | seatop_begin_resize_floating(seat, floater, edge); |
454 | return; | 487 | return; |
455 | } | 488 | } |
@@ -458,52 +491,42 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
458 | // Handle moving a tiling container | 491 | // Handle moving a tiling container |
459 | if (config->tiling_drag && (mod_pressed || on_titlebar) && | 492 | if (config->tiling_drag && (mod_pressed || on_titlebar) && |
460 | state == WLR_BUTTON_PRESSED && !is_floating_or_child && | 493 | state == WLR_BUTTON_PRESSED && !is_floating_or_child && |
461 | cont && cont->fullscreen_mode == FULLSCREEN_NONE) { | 494 | cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { |
462 | struct sway_container *focus = seat_get_focused_container(seat); | 495 | // If moving a container by its title bar, use a threshold for the drag |
463 | bool focused = focus == cont || container_has_ancestor(focus, cont); | ||
464 | if (on_titlebar && !focused) { | ||
465 | node = seat_get_focus_inactive(seat, &cont->node); | ||
466 | seat_set_focus(seat, node); | ||
467 | } | ||
468 | |||
469 | // If moving a container by it's title bar, use a threshold for the drag | ||
470 | if (!mod_pressed && config->tiling_drag_threshold > 0) { | 496 | if (!mod_pressed && config->tiling_drag_threshold > 0) { |
471 | seatop_begin_move_tiling_threshold(seat, cont); | 497 | seatop_begin_move_tiling_threshold(seat, cont); |
472 | } else { | 498 | } else { |
473 | seatop_begin_move_tiling(seat, cont); | 499 | seatop_begin_move_tiling(seat, cont); |
474 | } | 500 | } |
501 | |||
475 | return; | 502 | return; |
476 | } | 503 | } |
477 | 504 | ||
478 | // Handle mousedown on a container surface | 505 | // Handle mousedown on a container surface |
479 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | 506 | if (surface && cont && state == WLR_BUTTON_PRESSED) { |
480 | seat_set_focus_container(seat, cont); | 507 | seatop_begin_down(seat, cont, sx, sy); |
481 | seatop_begin_down(seat, cont, time_msec, sx, sy); | ||
482 | seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); | 508 | seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); |
483 | return; | 509 | return; |
484 | } | 510 | } |
485 | 511 | ||
486 | // Handle clicking a container surface or decorations | 512 | // Handle clicking a container surface or decorations |
487 | if (cont && state == WLR_BUTTON_PRESSED) { | 513 | if (cont && state == WLR_BUTTON_PRESSED) { |
488 | node = seat_get_focus_inactive(seat, &cont->node); | ||
489 | seat_set_focus(seat, node); | ||
490 | seat_pointer_notify_button(seat, time_msec, button, state); | 514 | seat_pointer_notify_button(seat, time_msec, button, state); |
491 | return; | 515 | return; |
492 | } | 516 | } |
493 | 517 | ||
494 | #if HAVE_XWAYLAND | 518 | #if HAVE_XWAYLAND |
495 | // Handle clicking on xwayland unmanaged view | 519 | // Handle clicking on xwayland unmanaged view |
496 | if (surface && wlr_surface_is_xwayland_surface(surface)) { | 520 | struct wlr_xwayland_surface *xsurface; |
497 | struct wlr_xwayland_surface *xsurface = | 521 | if (surface && |
498 | wlr_xwayland_surface_from_wlr_surface(surface); | 522 | (xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && |
499 | if (xsurface->override_redirect && | 523 | xsurface->override_redirect && |
500 | wlr_xwayland_or_surface_wants_focus(xsurface)) { | 524 | wlr_xwayland_or_surface_wants_focus(xsurface)) { |
501 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 525 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
502 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 526 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
503 | seat_set_focus_surface(seat, xsurface->surface, false); | 527 | seat_set_focus_surface(seat, xsurface->surface, false); |
504 | seat_pointer_notify_button(seat, time_msec, button, state); | 528 | transaction_commit_dirty(); |
505 | return; | 529 | seat_pointer_notify_button(seat, time_msec, button, state); |
506 | } | ||
507 | } | 530 | } |
508 | #endif | 531 | #endif |
509 | 532 | ||
@@ -526,10 +549,26 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
526 | if (wlr_output == NULL) { | 549 | if (wlr_output == NULL) { |
527 | return; | 550 | return; |
528 | } | 551 | } |
552 | |||
553 | struct wlr_surface *surface = NULL; | ||
554 | double sx, sy; | ||
555 | node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y, | ||
556 | &surface, &sx, &sy); | ||
557 | |||
558 | // Focus topmost layer surface | ||
559 | struct wlr_layer_surface_v1 *layer = NULL; | ||
560 | if ((layer = toplevel_layer_surface_from_surface(surface)) && | ||
561 | layer->current.keyboard_interactive) { | ||
562 | seat_set_focus_layer(seat, layer); | ||
563 | transaction_commit_dirty(); | ||
564 | return; | ||
565 | } | ||
566 | |||
529 | struct sway_output *hovered_output = wlr_output->data; | 567 | struct sway_output *hovered_output = wlr_output->data; |
530 | if (focus && hovered_output != node_get_output(focus)) { | 568 | if (focus && hovered_output != node_get_output(focus)) { |
531 | struct sway_workspace *ws = output_get_active_workspace(hovered_output); | 569 | struct sway_workspace *ws = output_get_active_workspace(hovered_output); |
532 | seat_set_focus(seat, &ws->node); | 570 | seat_set_focus(seat, &ws->node); |
571 | transaction_commit_dirty(); | ||
533 | } | 572 | } |
534 | return; | 573 | return; |
535 | } | 574 | } |
@@ -541,6 +580,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
541 | struct sway_output *hovered_output = node_get_output(hovered_node); | 580 | struct sway_output *hovered_output = node_get_output(hovered_node); |
542 | if (hovered_output != focused_output) { | 581 | if (hovered_output != focused_output) { |
543 | seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); | 582 | seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); |
583 | transaction_commit_dirty(); | ||
544 | } | 584 | } |
545 | return; | 585 | return; |
546 | } | 586 | } |
@@ -556,6 +596,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
556 | if (hovered_node != e->previous_node || | 596 | if (hovered_node != e->previous_node || |
557 | config->focus_follows_mouse == FOLLOWS_ALWAYS) { | 597 | config->focus_follows_mouse == FOLLOWS_ALWAYS) { |
558 | seat_set_focus(seat, hovered_node); | 598 | seat_set_focus(seat, hovered_node); |
599 | transaction_commit_dirty(); | ||
559 | } | 600 | } |
560 | } | 601 | } |
561 | } | 602 | } |
@@ -583,12 +624,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
583 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); | 624 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); |
584 | } | 625 | } |
585 | 626 | ||
586 | struct sway_drag_icon *drag_icon; | 627 | drag_icons_update_position(seat); |
587 | wl_list_for_each(drag_icon, &root->drag_icons, link) { | ||
588 | if (drag_icon->seat == seat) { | ||
589 | drag_icon_update_position(drag_icon); | ||
590 | } | ||
591 | } | ||
592 | 628 | ||
593 | e->previous_node = node; | 629 | e->previous_node = node; |
594 | } | 630 | } |
@@ -618,21 +654,46 @@ static void handle_tablet_tool_motion(struct sway_seat *seat, | |||
618 | wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); | 654 | wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); |
619 | } | 655 | } |
620 | 656 | ||
621 | struct sway_drag_icon *drag_icon; | 657 | drag_icons_update_position(seat); |
622 | wl_list_for_each(drag_icon, &root->drag_icons, link) { | ||
623 | if (drag_icon->seat == seat) { | ||
624 | drag_icon_update_position(drag_icon); | ||
625 | } | ||
626 | } | ||
627 | 658 | ||
628 | e->previous_node = node; | 659 | e->previous_node = node; |
629 | } | 660 | } |
630 | 661 | ||
662 | static void handle_touch_down(struct sway_seat *seat, | ||
663 | struct wlr_touch_down_event *event, double lx, double ly) { | ||
664 | struct wlr_surface *surface = NULL; | ||
665 | struct wlr_seat *wlr_seat = seat->wlr_seat; | ||
666 | struct sway_cursor *cursor = seat->cursor; | ||
667 | double sx, sy; | ||
668 | node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy); | ||
669 | |||
670 | if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) { | ||
671 | if (seat_is_input_allowed(seat, surface)) { | ||
672 | cursor->simulating_pointer_from_touch = false; | ||
673 | seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly); | ||
674 | } | ||
675 | } else if (!cursor->simulating_pointer_from_touch && | ||
676 | (!surface || seat_is_input_allowed(seat, surface))) { | ||
677 | // Fallback to cursor simulation. | ||
678 | // The pointer_touch_id state is needed, so drags are not aborted when over | ||
679 | // a surface supporting touch and multi touch events don't interfere. | ||
680 | cursor->simulating_pointer_from_touch = true; | ||
681 | cursor->pointer_touch_id = seat->touch_id; | ||
682 | double dx, dy; | ||
683 | dx = seat->touch_x - cursor->cursor->x; | ||
684 | dy = seat->touch_y - cursor->cursor->y; | ||
685 | pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy, | ||
686 | dx, dy); | ||
687 | dispatch_cursor_button(cursor, &event->touch->base, event->time_msec, | ||
688 | BTN_LEFT, WLR_BUTTON_PRESSED); | ||
689 | } | ||
690 | } | ||
691 | |||
631 | /*----------------------------------------\ | 692 | /*----------------------------------------\ |
632 | * Functions used by handle_pointer_axis / | 693 | * Functions used by handle_pointer_axis / |
633 | *--------------------------------------*/ | 694 | *--------------------------------------*/ |
634 | 695 | ||
635 | static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) { | 696 | static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) { |
636 | switch (event->orientation) { | 697 | switch (event->orientation) { |
637 | case WLR_AXIS_ORIENTATION_VERTICAL: | 698 | case WLR_AXIS_ORIENTATION_VERTICAL: |
638 | return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; | 699 | return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; |
@@ -645,9 +706,9 @@ static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) { | |||
645 | } | 706 | } |
646 | 707 | ||
647 | static void handle_pointer_axis(struct sway_seat *seat, | 708 | static void handle_pointer_axis(struct sway_seat *seat, |
648 | struct wlr_event_pointer_axis *event) { | 709 | struct wlr_pointer_axis_event *event) { |
649 | struct sway_input_device *input_device = | 710 | struct sway_input_device *input_device = |
650 | event->device ? event->device->data : NULL; | 711 | event->pointer ? event->pointer->base.data : NULL; |
651 | struct input_config *ic = | 712 | struct input_config *ic = |
652 | input_device ? input_device_get_config(input_device) : NULL; | 713 | input_device ? input_device_get_config(input_device) : NULL; |
653 | struct sway_cursor *cursor = seat->cursor; | 714 | struct sway_cursor *cursor = seat->cursor; |
@@ -664,7 +725,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
664 | bool on_border = edge != WLR_EDGE_NONE; | 725 | bool on_border = edge != WLR_EDGE_NONE; |
665 | bool on_titlebar = cont && !on_border && !surface; | 726 | bool on_titlebar = cont && !on_border && !surface; |
666 | bool on_titlebar_border = cont && on_border && | 727 | bool on_titlebar_border = cont && on_border && |
667 | cursor->cursor->y < cont->content_y; | 728 | cursor->cursor->y < cont->pending.content_y; |
668 | bool on_contents = cont && !on_border && surface; | 729 | bool on_contents = cont && !on_border && surface; |
669 | bool on_workspace = node && node->type == N_WORKSPACE; | 730 | bool on_workspace = node && node->type == N_WORKSPACE; |
670 | float scroll_factor = | 731 | float scroll_factor = |
@@ -693,6 +754,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
693 | 754 | ||
694 | // Scrolling on a tabbed or stacked title bar (handled as press event) | 755 | // Scrolling on a tabbed or stacked title bar (handled as press event) |
695 | if (!handled && (on_titlebar || on_titlebar_border)) { | 756 | if (!handled && (on_titlebar || on_titlebar_border)) { |
757 | struct sway_node *new_focus; | ||
696 | enum sway_container_layout layout = container_parent_layout(cont); | 758 | enum sway_container_layout layout = container_parent_layout(cont); |
697 | if (layout == L_TABBED || layout == L_STACKED) { | 759 | if (layout == L_TABBED || layout == L_STACKED) { |
698 | struct sway_node *tabcontainer = node_get_parent(node); | 760 | struct sway_node *tabcontainer = node_get_parent(node); |
@@ -700,7 +762,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
700 | seat_get_active_tiling_child(seat, tabcontainer); | 762 | seat_get_active_tiling_child(seat, tabcontainer); |
701 | list_t *siblings = container_get_siblings(cont); | 763 | list_t *siblings = container_get_siblings(cont); |
702 | int desired = list_find(siblings, active->sway_container) + | 764 | int desired = list_find(siblings, active->sway_container) + |
703 | round(scroll_factor * event->delta_discrete); | 765 | roundf(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP); |
704 | if (desired < 0) { | 766 | if (desired < 0) { |
705 | desired = 0; | 767 | desired = 0; |
706 | } else if (desired >= siblings->length) { | 768 | } else if (desired >= siblings->length) { |
@@ -709,13 +771,16 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
709 | 771 | ||
710 | struct sway_container *new_sibling_con = siblings->items[desired]; | 772 | struct sway_container *new_sibling_con = siblings->items[desired]; |
711 | struct sway_node *new_sibling = &new_sibling_con->node; | 773 | struct sway_node *new_sibling = &new_sibling_con->node; |
712 | struct sway_node *new_focus = | ||
713 | seat_get_focus_inactive(seat, new_sibling); | ||
714 | // Use the focused child of the tabbed/stacked container, not the | 774 | // Use the focused child of the tabbed/stacked container, not the |
715 | // container the user scrolled on. | 775 | // container the user scrolled on. |
716 | seat_set_focus(seat, new_focus); | 776 | new_focus = seat_get_focus_inactive(seat, new_sibling); |
717 | handled = true; | 777 | } else { |
778 | new_focus = seat_get_focus_inactive(seat, &cont->node); | ||
718 | } | 779 | } |
780 | |||
781 | seat_set_focus(seat, new_focus); | ||
782 | transaction_commit_dirty(); | ||
783 | handled = true; | ||
719 | } | 784 | } |
720 | 785 | ||
721 | // Handle mouse bindings - x11 mouse buttons 4-7 - release event | 786 | // Handle mouse bindings - x11 mouse buttons 4-7 - release event |
@@ -731,8 +796,307 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
731 | 796 | ||
732 | if (!handled) { | 797 | if (!handled) { |
733 | wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, | 798 | wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, |
734 | event->orientation, scroll_factor * event->delta, | 799 | event->orientation, scroll_factor * event->delta, |
735 | round(scroll_factor * event->delta_discrete), event->source); | 800 | roundf(scroll_factor * event->delta_discrete), event->source, |
801 | event->relative_direction); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | /*------------------------------------\ | ||
806 | * Functions used by gesture support / | ||
807 | *----------------------------------*/ | ||
808 | |||
809 | /** | ||
810 | * Check gesture binding for a specific gesture type and finger count. | ||
811 | * Returns true if binding is present, false otherwise | ||
812 | */ | ||
813 | static bool gesture_binding_check(list_t *bindings, enum gesture_type type, | ||
814 | uint8_t fingers, struct sway_input_device *device) { | ||
815 | char *input = | ||
816 | device ? input_device_get_identifier(device->wlr_device) : strdup("*"); | ||
817 | |||
818 | for (int i = 0; i < bindings->length; ++i) { | ||
819 | struct sway_gesture_binding *binding = bindings->items[i]; | ||
820 | |||
821 | // Check type and finger count | ||
822 | if (!gesture_check(&binding->gesture, type, fingers)) { | ||
823 | continue; | ||
824 | } | ||
825 | |||
826 | // Check that input matches | ||
827 | if (strcmp(binding->input, "*") != 0 && | ||
828 | strcmp(binding->input, input) != 0) { | ||
829 | continue; | ||
830 | } | ||
831 | |||
832 | free(input); | ||
833 | |||
834 | return true; | ||
835 | } | ||
836 | |||
837 | free(input); | ||
838 | |||
839 | return false; | ||
840 | } | ||
841 | |||
842 | /** | ||
843 | * Return the gesture binding which matches gesture type, finger count | ||
844 | * and direction, otherwise return null. | ||
845 | */ | ||
846 | static struct sway_gesture_binding* gesture_binding_match( | ||
847 | list_t *bindings, struct gesture *gesture, const char *input) { | ||
848 | struct sway_gesture_binding *current = NULL; | ||
849 | |||
850 | // Find best matching binding | ||
851 | for (int i = 0; i < bindings->length; ++i) { | ||
852 | struct sway_gesture_binding *binding = bindings->items[i]; | ||
853 | bool exact = binding->flags & BINDING_EXACT; | ||
854 | |||
855 | // Check gesture matching | ||
856 | if (!gesture_match(&binding->gesture, gesture, exact)) { | ||
857 | continue; | ||
858 | } | ||
859 | |||
860 | // Check input matching | ||
861 | if (strcmp(binding->input, "*") != 0 && | ||
862 | strcmp(binding->input, input) != 0) { | ||
863 | continue; | ||
864 | } | ||
865 | |||
866 | // If we already have a match ... | ||
867 | if (current) { | ||
868 | // ... check if input matching is equivalent | ||
869 | if (strcmp(current->input, binding->input) == 0) { | ||
870 | |||
871 | // ... - do not override an exact binding | ||
872 | if (!exact && current->flags & BINDING_EXACT) { | ||
873 | continue; | ||
874 | } | ||
875 | |||
876 | // ... - and ensure direction matching is better or equal | ||
877 | if (gesture_compare(¤t->gesture, &binding->gesture) > 0) { | ||
878 | continue; | ||
879 | } | ||
880 | } else if (strcmp(binding->input, "*") == 0) { | ||
881 | // ... do not accept worse input match | ||
882 | continue; | ||
883 | } | ||
884 | } | ||
885 | |||
886 | // Accept newer or better match | ||
887 | current = binding; | ||
888 | |||
889 | // If exact binding and input is found, quit search | ||
890 | if (strcmp(current->input, input) == 0 && | ||
891 | gesture_compare(¤t->gesture, gesture) == 0) { | ||
892 | break; | ||
893 | } | ||
894 | } // for all gesture bindings | ||
895 | |||
896 | return current; | ||
897 | } | ||
898 | |||
899 | // Wrapper around gesture_tracker_end to use tracker with sway bindings | ||
900 | static struct sway_gesture_binding* gesture_tracker_end_and_match( | ||
901 | struct gesture_tracker *tracker, struct sway_input_device* device) { | ||
902 | // Determine name of input that received gesture | ||
903 | char *input = device | ||
904 | ? input_device_get_identifier(device->wlr_device) | ||
905 | : strdup("*"); | ||
906 | |||
907 | // Match tracking result to binding | ||
908 | struct gesture *gesture = gesture_tracker_end(tracker); | ||
909 | struct sway_gesture_binding *binding = gesture_binding_match( | ||
910 | config->current_mode->gesture_bindings, gesture, input); | ||
911 | free(gesture); | ||
912 | free(input); | ||
913 | |||
914 | return binding; | ||
915 | } | ||
916 | |||
917 | // Small wrapper around seat_execute_command to work on gesture bindings | ||
918 | static void gesture_binding_execute(struct sway_seat *seat, | ||
919 | struct sway_gesture_binding *binding) { | ||
920 | struct sway_binding *dummy_binding = | ||
921 | calloc(1, sizeof(struct sway_binding)); | ||
922 | dummy_binding->type = BINDING_GESTURE; | ||
923 | dummy_binding->command = binding->command; | ||
924 | |||
925 | char *description = gesture_to_string(&binding->gesture); | ||
926 | sway_log(SWAY_DEBUG, "executing gesture binding: %s", description); | ||
927 | free(description); | ||
928 | |||
929 | seat_execute_command(seat, dummy_binding); | ||
930 | |||
931 | free(dummy_binding); | ||
932 | } | ||
933 | |||
934 | static void handle_hold_begin(struct sway_seat *seat, | ||
935 | struct wlr_pointer_hold_begin_event *event) { | ||
936 | // Start tracking gesture if there is a matching binding ... | ||
937 | struct sway_input_device *device = | ||
938 | event->pointer ? event->pointer->base.data : NULL; | ||
939 | list_t *bindings = config->current_mode->gesture_bindings; | ||
940 | if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) { | ||
941 | struct seatop_default_event *seatop = seat->seatop_data; | ||
942 | gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers); | ||
943 | } else { | ||
944 | // ... otherwise forward to client | ||
945 | struct sway_cursor *cursor = seat->cursor; | ||
946 | wlr_pointer_gestures_v1_send_hold_begin( | ||
947 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
948 | event->time_msec, event->fingers); | ||
949 | } | ||
950 | } | ||
951 | |||
952 | static void handle_hold_end(struct sway_seat *seat, | ||
953 | struct wlr_pointer_hold_end_event *event) { | ||
954 | // Ensure that gesture is being tracked and was not cancelled | ||
955 | struct seatop_default_event *seatop = seat->seatop_data; | ||
956 | if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) { | ||
957 | struct sway_cursor *cursor = seat->cursor; | ||
958 | wlr_pointer_gestures_v1_send_hold_end( | ||
959 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
960 | event->time_msec, event->cancelled); | ||
961 | return; | ||
962 | } | ||
963 | if (event->cancelled) { | ||
964 | gesture_tracker_cancel(&seatop->gestures); | ||
965 | return; | ||
966 | } | ||
967 | |||
968 | // End gesture tracking and execute matched binding | ||
969 | struct sway_input_device *device = | ||
970 | event->pointer ? event->pointer->base.data : NULL; | ||
971 | struct sway_gesture_binding *binding = gesture_tracker_end_and_match( | ||
972 | &seatop->gestures, device); | ||
973 | |||
974 | if (binding) { | ||
975 | gesture_binding_execute(seat, binding); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | static void handle_pinch_begin(struct sway_seat *seat, | ||
980 | struct wlr_pointer_pinch_begin_event *event) { | ||
981 | // Start tracking gesture if there is a matching binding ... | ||
982 | struct sway_input_device *device = | ||
983 | event->pointer ? event->pointer->base.data : NULL; | ||
984 | list_t *bindings = config->current_mode->gesture_bindings; | ||
985 | if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) { | ||
986 | struct seatop_default_event *seatop = seat->seatop_data; | ||
987 | gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers); | ||
988 | } else { | ||
989 | // ... otherwise forward to client | ||
990 | struct sway_cursor *cursor = seat->cursor; | ||
991 | wlr_pointer_gestures_v1_send_pinch_begin( | ||
992 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
993 | event->time_msec, event->fingers); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | static void handle_pinch_update(struct sway_seat *seat, | ||
998 | struct wlr_pointer_pinch_update_event *event) { | ||
999 | // Update any ongoing tracking ... | ||
1000 | struct seatop_default_event *seatop = seat->seatop_data; | ||
1001 | if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { | ||
1002 | gesture_tracker_update(&seatop->gestures, event->dx, event->dy, | ||
1003 | event->scale, event->rotation); | ||
1004 | } else { | ||
1005 | // ... otherwise forward to client | ||
1006 | struct sway_cursor *cursor = seat->cursor; | ||
1007 | wlr_pointer_gestures_v1_send_pinch_update( | ||
1008 | server.input->pointer_gestures, | ||
1009 | cursor->seat->wlr_seat, | ||
1010 | event->time_msec, event->dx, event->dy, | ||
1011 | event->scale, event->rotation); | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | static void handle_pinch_end(struct sway_seat *seat, | ||
1016 | struct wlr_pointer_pinch_end_event *event) { | ||
1017 | // Ensure that gesture is being tracked and was not cancelled | ||
1018 | struct seatop_default_event *seatop = seat->seatop_data; | ||
1019 | if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { | ||
1020 | struct sway_cursor *cursor = seat->cursor; | ||
1021 | wlr_pointer_gestures_v1_send_pinch_end( | ||
1022 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
1023 | event->time_msec, event->cancelled); | ||
1024 | return; | ||
1025 | } | ||
1026 | if (event->cancelled) { | ||
1027 | gesture_tracker_cancel(&seatop->gestures); | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | // End gesture tracking and execute matched binding | ||
1032 | struct sway_input_device *device = | ||
1033 | event->pointer ? event->pointer->base.data : NULL; | ||
1034 | struct sway_gesture_binding *binding = gesture_tracker_end_and_match( | ||
1035 | &seatop->gestures, device); | ||
1036 | |||
1037 | if (binding) { | ||
1038 | gesture_binding_execute(seat, binding); | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | static void handle_swipe_begin(struct sway_seat *seat, | ||
1043 | struct wlr_pointer_swipe_begin_event *event) { | ||
1044 | // Start tracking gesture if there is a matching binding ... | ||
1045 | struct sway_input_device *device = | ||
1046 | event->pointer ? event->pointer->base.data : NULL; | ||
1047 | list_t *bindings = config->current_mode->gesture_bindings; | ||
1048 | if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) { | ||
1049 | struct seatop_default_event *seatop = seat->seatop_data; | ||
1050 | gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers); | ||
1051 | } else { | ||
1052 | // ... otherwise forward to client | ||
1053 | struct sway_cursor *cursor = seat->cursor; | ||
1054 | wlr_pointer_gestures_v1_send_swipe_begin( | ||
1055 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
1056 | event->time_msec, event->fingers); | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | static void handle_swipe_update(struct sway_seat *seat, | ||
1061 | struct wlr_pointer_swipe_update_event *event) { | ||
1062 | |||
1063 | // Update any ongoing tracking ... | ||
1064 | struct seatop_default_event *seatop = seat->seatop_data; | ||
1065 | if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { | ||
1066 | gesture_tracker_update(&seatop->gestures, | ||
1067 | event->dx, event->dy, NAN, NAN); | ||
1068 | } else { | ||
1069 | // ... otherwise forward to client | ||
1070 | struct sway_cursor *cursor = seat->cursor; | ||
1071 | wlr_pointer_gestures_v1_send_swipe_update( | ||
1072 | server.input->pointer_gestures, cursor->seat->wlr_seat, | ||
1073 | event->time_msec, event->dx, event->dy); | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | static void handle_swipe_end(struct sway_seat *seat, | ||
1078 | struct wlr_pointer_swipe_end_event *event) { | ||
1079 | // Ensure gesture is being tracked and was not cancelled | ||
1080 | struct seatop_default_event *seatop = seat->seatop_data; | ||
1081 | if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { | ||
1082 | struct sway_cursor *cursor = seat->cursor; | ||
1083 | wlr_pointer_gestures_v1_send_swipe_end(server.input->pointer_gestures, | ||
1084 | cursor->seat->wlr_seat, event->time_msec, event->cancelled); | ||
1085 | return; | ||
1086 | } | ||
1087 | if (event->cancelled) { | ||
1088 | gesture_tracker_cancel(&seatop->gestures); | ||
1089 | return; | ||
1090 | } | ||
1091 | |||
1092 | // End gesture tracking and execute matched binding | ||
1093 | struct sway_input_device *device = | ||
1094 | event->pointer ? event->pointer->base.data : NULL; | ||
1095 | struct sway_gesture_binding *binding = gesture_tracker_end_and_match( | ||
1096 | &seatop->gestures, device); | ||
1097 | |||
1098 | if (binding) { | ||
1099 | gesture_binding_execute(seat, binding); | ||
736 | } | 1100 | } |
737 | } | 1101 | } |
738 | 1102 | ||
@@ -765,6 +1129,15 @@ static const struct sway_seatop_impl seatop_impl = { | |||
765 | .pointer_axis = handle_pointer_axis, | 1129 | .pointer_axis = handle_pointer_axis, |
766 | .tablet_tool_tip = handle_tablet_tool_tip, | 1130 | .tablet_tool_tip = handle_tablet_tool_tip, |
767 | .tablet_tool_motion = handle_tablet_tool_motion, | 1131 | .tablet_tool_motion = handle_tablet_tool_motion, |
1132 | .hold_begin = handle_hold_begin, | ||
1133 | .hold_end = handle_hold_end, | ||
1134 | .pinch_begin = handle_pinch_begin, | ||
1135 | .pinch_update = handle_pinch_update, | ||
1136 | .pinch_end = handle_pinch_end, | ||
1137 | .swipe_begin = handle_swipe_begin, | ||
1138 | .swipe_update = handle_swipe_update, | ||
1139 | .swipe_end = handle_swipe_end, | ||
1140 | .touch_down = handle_touch_down, | ||
768 | .rebase = handle_rebase, | 1141 | .rebase = handle_rebase, |
769 | .allow_set_cursor = true, | 1142 | .allow_set_cursor = true, |
770 | }; | 1143 | }; |
@@ -775,8 +1148,8 @@ void seatop_begin_default(struct sway_seat *seat) { | |||
775 | struct seatop_default_event *e = | 1148 | struct seatop_default_event *e = |
776 | calloc(1, sizeof(struct seatop_default_event)); | 1149 | calloc(1, sizeof(struct seatop_default_event)); |
777 | sway_assert(e, "Unable to allocate seatop_default_event"); | 1150 | sway_assert(e, "Unable to allocate seatop_default_event"); |
1151 | |||
778 | seat->seatop_impl = &seatop_impl; | 1152 | seat->seatop_impl = &seatop_impl; |
779 | seat->seatop_data = e; | 1153 | seat->seatop_data = e; |
780 | |||
781 | seatop_rebase(seat, 0); | 1154 | seatop_rebase(seat, 0); |
782 | } | 1155 | } |