aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r--sway/input/cursor.c242
1 files changed, 199 insertions, 43 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index c6a332b8..574186d7 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -10,6 +10,7 @@
10#include <wlr/types/wlr_box.h> 10#include <wlr/types/wlr_box.h>
11#include <wlr/types/wlr_cursor.h> 11#include <wlr/types/wlr_cursor.h>
12#include <wlr/types/wlr_idle.h> 12#include <wlr/types/wlr_idle.h>
13#include <wlr/types/wlr_tablet_v2.h>
13#include <wlr/types/wlr_xcursor_manager.h> 14#include <wlr/types/wlr_xcursor_manager.h>
14#include <wlr/util/region.h> 15#include <wlr/util/region.h>
15#include "list.h" 16#include "list.h"
@@ -20,6 +21,7 @@
20#include "sway/desktop/transaction.h" 21#include "sway/desktop/transaction.h"
21#include "sway/input/cursor.h" 22#include "sway/input/cursor.h"
22#include "sway/input/keyboard.h" 23#include "sway/input/keyboard.h"
24#include "sway/input/tablet.h"
23#include "sway/layers.h" 25#include "sway/layers.h"
24#include "sway/output.h" 26#include "sway/output.h"
25#include "sway/tree/arrange.h" 27#include "sway/tree/arrange.h"
@@ -443,72 +445,224 @@ static void apply_mapping_from_region(struct wlr_input_device *device,
443 *y = apply_mapping_from_coord(y1, y2, *y); 445 *y = apply_mapping_from_coord(y1, y2, *y);
444} 446}
445 447
448static void handle_tablet_tool_position(struct sway_cursor *cursor,
449 struct sway_tablet *tablet,
450 struct wlr_tablet_tool *tool,
451 bool change_x, bool change_y,
452 double x, double y, double dx, double dy,
453 int32_t time_msec) {
454 if (!change_x && !change_y) {
455 return;
456 }
457
458 struct sway_input_device *input_device = tablet->seat_device->input_device;
459 struct input_config *ic = input_device_get_config(input_device);
460 if (ic != NULL && ic->mapped_from_region != NULL) {
461 apply_mapping_from_region(input_device->wlr_device,
462 ic->mapped_from_region, &x, &y);
463 }
464
465 switch (tool->type) {
466 case WLR_TABLET_TOOL_TYPE_MOUSE:
467 wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy);
468 break;
469 default:
470 wlr_cursor_warp_absolute(cursor->cursor, input_device->wlr_device,
471 change_x ? x : NAN, change_y ? y : NAN);
472 }
473
474 double sx, sy;
475 struct wlr_surface *surface = NULL;
476 struct sway_seat *seat = cursor->seat;
477 node_at_coords(seat, cursor->cursor->x, cursor->cursor->y,
478 &surface, &sx, &sy);
479 struct sway_tablet_tool *sway_tool = tool->data;
480
481 if (!surface || !wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) {
482 wlr_tablet_v2_tablet_tool_notify_proximity_out(sway_tool->tablet_v2_tool);
483 cursor_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy);
484 return;
485 }
486
487 wlr_tablet_v2_tablet_tool_notify_proximity_in(sway_tool->tablet_v2_tool,
488 tablet->tablet_v2, surface);
489
490 wlr_tablet_v2_tablet_tool_notify_motion(sway_tool->tablet_v2_tool, sx, sy);
491}
492
446static void handle_tool_axis(struct wl_listener *listener, void *data) { 493static void handle_tool_axis(struct wl_listener *listener, void *data) {
447 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis); 494 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
448 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); 495 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
449 struct wlr_event_tablet_tool_axis *event = data; 496 struct wlr_event_tablet_tool_axis *event = data;
450 struct sway_input_device *input_device = event->device->data; 497 struct sway_tablet_tool *sway_tool = event->tool->data;
451 498
452 double x = NAN, y = NAN; 499 if (!sway_tool) {
453 if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { 500 sway_log(SWAY_DEBUG, "tool axis before proximity");
454 x = event->x; 501 return;
455 } 502 }
456 if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { 503
457 y = event->y; 504 handle_tablet_tool_position(cursor, sway_tool->tablet, event->tool,
505 event->updated_axes & WLR_TABLET_TOOL_AXIS_X,
506 event->updated_axes & WLR_TABLET_TOOL_AXIS_Y,
507 event->x, event->y, event->dx, event->dy, event->time_msec);
508
509 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) {
510 wlr_tablet_v2_tablet_tool_notify_pressure(
511 sway_tool->tablet_v2_tool, event->pressure);
458 } 512 }
459 513
460 struct input_config *ic = input_device_get_config(input_device); 514 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) {
461 if (ic != NULL && ic->mapped_from_region != NULL) { 515 wlr_tablet_v2_tablet_tool_notify_distance(
462 apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); 516 sway_tool->tablet_v2_tool, event->distance);
463 } 517 }
464 518
465 double lx, ly; 519 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) {
466 wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, 520 sway_tool->tilt_x = event->tilt_x;
467 x, y, &lx, &ly); 521 }
468 522
469 double dx = lx - cursor->cursor->x; 523 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) {
470 double dy = ly - cursor->cursor->y; 524 sway_tool->tilt_y = event->tilt_y;
525 }
471 526
472 cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); 527 if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) {
473 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 528 wlr_tablet_v2_tablet_tool_notify_tilt(
474 transaction_commit_dirty(); 529 sway_tool->tablet_v2_tool,
530 sway_tool->tilt_x, sway_tool->tilt_y);
531 }
532
533 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) {
534 wlr_tablet_v2_tablet_tool_notify_rotation(
535 sway_tool->tablet_v2_tool, event->rotation);
536 }
537
538 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) {
539 wlr_tablet_v2_tablet_tool_notify_slider(
540 sway_tool->tablet_v2_tool, event->slider);
541 }
542
543 if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) {
544 wlr_tablet_v2_tablet_tool_notify_wheel(
545 sway_tool->tablet_v2_tool, event->wheel_delta, 0);
546 }
475} 547}
476 548
477static void handle_tool_tip(struct wl_listener *listener, void *data) { 549static void handle_tool_tip(struct wl_listener *listener, void *data) {
478 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip); 550 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
479 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); 551 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
480 struct wlr_event_tablet_tool_tip *event = data; 552 struct wlr_event_tablet_tool_tip *event = data;
481 dispatch_cursor_button(cursor, event->device, event->time_msec, 553 struct sway_tablet_tool *sway_tool = event->tool->data;
482 BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? 554 struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
483 WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); 555 struct sway_seat *seat = cursor->seat;
484 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 556
485 transaction_commit_dirty(); 557 double sx, sy;
558 struct wlr_surface *surface = NULL;
559 node_at_coords(seat, cursor->cursor->x, cursor->cursor->y,
560 &surface, &sx, &sy);
561
562 if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
563 dispatch_cursor_button(cursor, event->device, event->time_msec,
564 BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ?
565 WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED);
566 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
567 transaction_commit_dirty();
568 return;
569 }
570
571 if (event->state == WLR_TABLET_TOOL_TIP_DOWN) {
572 wlr_tablet_v2_tablet_tool_notify_down(sway_tool->tablet_v2_tool);
573 wlr_tablet_tool_v2_start_implicit_grab(sway_tool->tablet_v2_tool);
574 } else {
575 wlr_tablet_v2_tablet_tool_notify_up(sway_tool->tablet_v2_tool);
576 }
577}
578
579static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor,
580 struct wlr_input_device *device) {
581 struct sway_tablet *tablet;
582 wl_list_for_each(tablet, &cursor->tablets, link) {
583 if (tablet->seat_device->input_device->wlr_device == device) {
584 return tablet;
585 }
586 }
587 return NULL;
588}
589
590static void handle_tool_proximity(struct wl_listener *listener, void *data) {
591 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_proximity);
592 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
593 struct wlr_event_tablet_tool_proximity *event = data;
594
595 struct wlr_tablet_tool *tool = event->tool;
596 if (!tool->data) {
597 struct sway_tablet *tablet = get_tablet_for_device(cursor, event->device);
598 if (!tablet) {
599 sway_log(SWAY_ERROR, "no tablet for tablet tool");
600 return;
601 }
602 sway_tablet_tool_configure(tablet, tool);
603 }
604
605 struct sway_tablet_tool *sway_tool = tool->data;
606 if (!sway_tool) {
607 sway_log(SWAY_ERROR, "tablet tool not initialized");
608 return;
609 }
610
611 if (event->state == WLR_TABLET_TOOL_PROXIMITY_OUT) {
612 wlr_tablet_v2_tablet_tool_notify_proximity_out(sway_tool->tablet_v2_tool);
613 return;
614 }
615
616 handle_tablet_tool_position(cursor, sway_tool->tablet, event->tool,
617 true, true, event->x, event->y, 0, 0, event->time_msec);
486} 618}
487 619
488static void handle_tool_button(struct wl_listener *listener, void *data) { 620static void handle_tool_button(struct wl_listener *listener, void *data) {
489 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button); 621 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button);
490 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); 622 wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
491 struct wlr_event_tablet_tool_button *event = data; 623 struct wlr_event_tablet_tool_button *event = data;
492 // TODO: the user may want to configure which tool buttons are mapped to 624 struct sway_tablet_tool *sway_tool = event->tool->data;
493 // which simulated pointer buttons 625 struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
494 switch (event->state) { 626 struct sway_seat *seat = cursor->seat;
495 case WLR_BUTTON_PRESSED: 627
496 if (cursor->tool_buttons == 0) { 628 if (!sway_tool) {
497 dispatch_cursor_button(cursor, event->device, 629 sway_log(SWAY_DEBUG, "tool button before proximity");
498 event->time_msec, BTN_RIGHT, event->state); 630 return;
499 } 631 }
500 cursor->tool_buttons++; 632
501 break; 633 double sx, sy;
502 case WLR_BUTTON_RELEASED: 634 struct wlr_surface *surface = NULL;
503 if (cursor->tool_buttons == 1) { 635
504 dispatch_cursor_button(cursor, event->device, 636 node_at_coords(seat, cursor->cursor->x, cursor->cursor->y,
505 event->time_msec, BTN_RIGHT, event->state); 637 &surface, &sx, &sy);
638
639 if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
640 // TODO: the user may want to configure which tool buttons are mapped to
641 // which simulated pointer buttons
642 switch (event->state) {
643 case WLR_BUTTON_PRESSED:
644 if (cursor->tool_buttons == 0) {
645 dispatch_cursor_button(cursor, event->device,
646 event->time_msec, BTN_RIGHT, event->state);
647 }
648 cursor->tool_buttons++;
649 break;
650 case WLR_BUTTON_RELEASED:
651 if (cursor->tool_buttons == 1) {
652 dispatch_cursor_button(cursor, event->device,
653 event->time_msec, BTN_RIGHT, event->state);
654 }
655 cursor->tool_buttons--;
656 break;
506 } 657 }
507 cursor->tool_buttons--; 658 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
508 break; 659 transaction_commit_dirty();
660 return;
509 } 661 }
510 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 662
511 transaction_commit_dirty(); 663 wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool,
664 (enum zwp_tablet_pad_v2_button_state)event->button,
665 (enum zwp_tablet_pad_v2_button_state)event->state);
512} 666}
513 667
514static void check_constraint_region(struct sway_cursor *cursor) { 668static void check_constraint_region(struct sway_cursor *cursor) {
@@ -698,9 +852,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
698 &cursor->touch_motion); 852 &cursor->touch_motion);
699 cursor->touch_motion.notify = handle_touch_motion; 853 cursor->touch_motion.notify = handle_touch_motion;
700 854
701 // TODO: tablet protocol support
702 // Note: We should emulate pointer events for clients that don't support the
703 // tablet protocol when the time comes
704 wl_signal_add(&wlr_cursor->events.tablet_tool_axis, 855 wl_signal_add(&wlr_cursor->events.tablet_tool_axis,
705 &cursor->tool_axis); 856 &cursor->tool_axis);
706 cursor->tool_axis.notify = handle_tool_axis; 857 cursor->tool_axis.notify = handle_tool_axis;
@@ -708,6 +859,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
708 wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); 859 wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip);
709 cursor->tool_tip.notify = handle_tool_tip; 860 cursor->tool_tip.notify = handle_tool_tip;
710 861
862 wl_signal_add(&wlr_cursor->events.tablet_tool_proximity, &cursor->tool_proximity);
863 cursor->tool_proximity.notify = handle_tool_proximity;
864
711 wl_signal_add(&wlr_cursor->events.tablet_tool_button, &cursor->tool_button); 865 wl_signal_add(&wlr_cursor->events.tablet_tool_button, &cursor->tool_button);
712 cursor->tool_button.notify = handle_tool_button; 866 cursor->tool_button.notify = handle_tool_button;
713 867
@@ -716,6 +870,8 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
716 cursor->request_set_cursor.notify = handle_request_set_cursor; 870 cursor->request_set_cursor.notify = handle_request_set_cursor;
717 871
718 wl_list_init(&cursor->constraint_commit.link); 872 wl_list_init(&cursor->constraint_commit.link);
873 wl_list_init(&cursor->tablets);
874 wl_list_init(&cursor->tablet_pads);
719 875
720 cursor->cursor = wlr_cursor; 876 cursor->cursor = wlr_cursor;
721 877