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