aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/cursor.c
diff options
context:
space:
mode:
authorLibravatar John Chadwick <johnwchadwick@gmail.com>2019-09-17 21:46:29 -0700
committerLibravatar Drew DeVault <sir@cmpwn.com>2019-09-25 23:10:33 -0400
commit7e420cb6e4a334dea7296060820de12a768b76da (patch)
tree143678e6ff0a4b4223e2dfe30086eb5e2d2ab174 /sway/input/cursor.c
parentAdd support for fullscreen view direct scan-out (diff)
downloadsway-7e420cb6e4a334dea7296060820de12a768b76da.tar.gz
sway-7e420cb6e4a334dea7296060820de12a768b76da.tar.zst
sway-7e420cb6e4a334dea7296060820de12a768b76da.zip
input: Add support for tablet protocol.
Sway has basic support for drawing tablets, but does not expose properties such as pressure sensitivity. This implements the wlr tablet v2 protocol, providing tablet events to Wayland clients.
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