aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/input/cursor.h3
-rw-r--r--include/sway/input/seat.h2
-rw-r--r--include/sway/input/tablet.h62
-rw-r--r--include/sway/server.h2
-rw-r--r--protocols/meson.build1
-rw-r--r--sway/input/cursor.c242
-rw-r--r--sway/input/seat.c29
-rw-r--r--sway/input/tablet.c345
-rw-r--r--sway/meson.build1
-rw-r--r--sway/server.c3
10 files changed, 644 insertions, 46 deletions
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h
index 516718c9..e46c9b18 100644
--- a/include/sway/input/cursor.h
+++ b/include/sway/input/cursor.h
@@ -21,6 +21,8 @@ struct sway_cursor {
21 struct sway_node *node; 21 struct sway_node *node;
22 } previous; 22 } previous;
23 struct wlr_xcursor_manager *xcursor_manager; 23 struct wlr_xcursor_manager *xcursor_manager;
24 struct wl_list tablets;
25 struct wl_list tablet_pads;
24 26
25 const char *image; 27 const char *image;
26 struct wl_client *image_client; 28 struct wl_client *image_client;
@@ -42,6 +44,7 @@ struct sway_cursor {
42 44
43 struct wl_listener tool_axis; 45 struct wl_listener tool_axis;
44 struct wl_listener tool_tip; 46 struct wl_listener tool_tip;
47 struct wl_listener tool_proximity;
45 struct wl_listener tool_button; 48 struct wl_listener tool_button;
46 uint32_t tool_buttons; 49 uint32_t tool_buttons;
47 50
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index c963de9b..24a6fed4 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -28,6 +28,8 @@ struct sway_seat_device {
28 struct sway_input_device *input_device; 28 struct sway_input_device *input_device;
29 struct sway_keyboard *keyboard; 29 struct sway_keyboard *keyboard;
30 struct sway_switch *switch_device; 30 struct sway_switch *switch_device;
31 struct sway_tablet *tablet;
32 struct sway_tablet_pad *tablet_pad;
31 struct wl_list link; // sway_seat::devices 33 struct wl_list link; // sway_seat::devices
32}; 34};
33 35
diff --git a/include/sway/input/tablet.h b/include/sway/input/tablet.h
new file mode 100644
index 00000000..f30e232a
--- /dev/null
+++ b/include/sway/input/tablet.h
@@ -0,0 +1,62 @@
1#ifndef _SWAY_INPUT_TABLET_H
2#define _SWAY_INPUT_TABLET_H
3#include <wlr/types/wlr_layer_shell_v1.h>
4
5struct sway_seat;
6struct wlr_tablet_tool;
7
8struct sway_tablet {
9 struct wl_list link;
10 struct sway_seat_device *seat_device;
11 struct wlr_tablet_v2_tablet *tablet_v2;
12};
13
14struct sway_tablet_tool {
15 struct sway_seat *seat;
16 struct sway_tablet *tablet;
17 struct wlr_tablet_v2_tablet_tool *tablet_v2_tool;
18
19 double tilt_x, tilt_y;
20
21 struct wl_listener set_cursor;
22 struct wl_listener tool_destroy;
23};
24
25struct sway_tablet_pad {
26 struct wl_list link;
27 struct sway_seat_device *seat_device;
28 struct sway_tablet *tablet;
29 struct wlr_tablet_v2_tablet_pad *tablet_v2_pad;
30
31 struct wl_listener attach;
32 struct wl_listener button;
33 struct wl_listener ring;
34 struct wl_listener strip;
35
36 struct wlr_surface *current_surface;
37 struct wl_listener surface_destroy;
38
39 struct wl_listener tablet_destroy;
40};
41
42struct sway_tablet *sway_tablet_create(struct sway_seat *seat,
43 struct sway_seat_device *device);
44
45void sway_configure_tablet(struct sway_tablet *tablet);
46
47void sway_tablet_destroy(struct sway_tablet *tablet);
48
49void sway_tablet_tool_configure(struct sway_tablet *tablet,
50 struct wlr_tablet_tool *wlr_tool);
51
52struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
53 struct sway_seat_device *device);
54
55void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad);
56
57void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad);
58
59void sway_tablet_pad_notify_enter(struct sway_tablet_pad *tablet_pad,
60 struct wlr_surface *surface);
61
62#endif
diff --git a/include/sway/server.h b/include/sway/server.h
index a43cbf72..cd411d3b 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -44,6 +44,8 @@ struct sway_server {
44 struct wlr_xdg_shell *xdg_shell; 44 struct wlr_xdg_shell *xdg_shell;
45 struct wl_listener xdg_shell_surface; 45 struct wl_listener xdg_shell_surface;
46 46
47 struct wlr_tablet_manager_v2 *tablet_v2;
48
47#if HAVE_XWAYLAND 49#if HAVE_XWAYLAND
48 struct sway_xwayland xwayland; 50 struct sway_xwayland xwayland;
49 struct wl_listener xwayland_surface; 51 struct wl_listener xwayland_surface;
diff --git a/protocols/meson.build b/protocols/meson.build
index 4ba6f723..f2f90dad 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -14,6 +14,7 @@ protocols = [
14 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 14 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
15 [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], 15 [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
16 [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], 16 [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
17 [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'],
17 ['wlr-layer-shell-unstable-v1.xml'], 18 ['wlr-layer-shell-unstable-v1.xml'],
18 ['idle.xml'], 19 ['idle.xml'],
19 ['wlr-input-inhibitor-unstable-v1.xml'], 20 ['wlr-input-inhibitor-unstable-v1.xml'],
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
diff --git a/sway/input/seat.c b/sway/input/seat.c
index b2243fe3..ebd40343 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -8,6 +8,7 @@
8#include <wlr/types/wlr_data_device.h> 8#include <wlr/types/wlr_data_device.h>
9#include <wlr/types/wlr_output_layout.h> 9#include <wlr/types/wlr_output_layout.h>
10#include <wlr/types/wlr_primary_selection.h> 10#include <wlr/types/wlr_primary_selection.h>
11#include <wlr/types/wlr_tablet_v2.h>
11#include <wlr/types/wlr_xcursor_manager.h> 12#include <wlr/types/wlr_xcursor_manager.h>
12#include "config.h" 13#include "config.h"
13#include "list.h" 14#include "list.h"
@@ -18,6 +19,7 @@
18#include "sway/input/keyboard.h" 19#include "sway/input/keyboard.h"
19#include "sway/input/seat.h" 20#include "sway/input/seat.h"
20#include "sway/input/switch.h" 21#include "sway/input/switch.h"
22#include "sway/input/tablet.h"
21#include "sway/ipc-server.h" 23#include "sway/ipc-server.h"
22#include "sway/layers.h" 24#include "sway/layers.h"
23#include "sway/output.h" 25#include "sway/output.h"
@@ -34,6 +36,8 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
34 } 36 }
35 37
36 sway_keyboard_destroy(seat_device->keyboard); 38 sway_keyboard_destroy(seat_device->keyboard);
39 sway_tablet_destroy(seat_device->tablet);
40 sway_tablet_pad_destroy(seat_device->tablet_pad);
37 wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor, 41 wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
38 seat_device->input_device->wlr_device); 42 seat_device->input_device->wlr_device);
39 wl_list_remove(&seat_device->link); 43 wl_list_remove(&seat_device->link);
@@ -118,6 +122,14 @@ static void seat_keyboard_notify_enter(struct sway_seat *seat,
118 state->pressed_keycodes, state->npressed, &keyboard->modifiers); 122 state->pressed_keycodes, state->npressed, &keyboard->modifiers);
119} 123}
120 124
125static void seat_tablet_pads_notify_enter(struct sway_seat *seat,
126 struct wlr_surface *surface) {
127 struct sway_seat_device *seat_device;
128 wl_list_for_each(seat_device, &seat->devices, link) {
129 sway_tablet_pad_notify_enter(seat_device->tablet_pad, surface);
130 }
131}
132
121/** 133/**
122 * If con is a view, set it as active and enable keyboard input. 134 * If con is a view, set it as active and enable keyboard input.
123 * If con is a container, set all child views as active and don't enable 135 * If con is a container, set all child views as active and don't enable
@@ -138,6 +150,7 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
138#endif 150#endif
139 151
140 seat_keyboard_notify_enter(seat, view->surface); 152 seat_keyboard_notify_enter(seat, view->surface);
153 seat_tablet_pads_notify_enter(seat, view->surface);
141 154
142 struct wlr_pointer_constraint_v1 *constraint = 155 struct wlr_pointer_constraint_v1 *constraint =
143 wlr_pointer_constraints_v1_constraint_for_surface( 156 wlr_pointer_constraints_v1_constraint_for_surface(
@@ -638,14 +651,23 @@ static void seat_configure_touch(struct sway_seat *seat,
638 651
639static void seat_configure_tablet_tool(struct sway_seat *seat, 652static void seat_configure_tablet_tool(struct sway_seat *seat,
640 struct sway_seat_device *sway_device) { 653 struct sway_seat_device *sway_device) {
641 if ((seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) { 654 if (!sway_device->tablet) {
642 seat_configure_xcursor(seat); 655 sway_device->tablet = sway_tablet_create(seat, sway_device);
643 } 656 }
657 sway_configure_tablet(sway_device->tablet);
644 wlr_cursor_attach_input_device(seat->cursor->cursor, 658 wlr_cursor_attach_input_device(seat->cursor->cursor,
645 sway_device->input_device->wlr_device); 659 sway_device->input_device->wlr_device);
646 seat_apply_input_config(seat, sway_device); 660 seat_apply_input_config(seat, sway_device);
647} 661}
648 662
663static void seat_configure_tablet_pad(struct sway_seat *seat,
664 struct sway_seat_device *sway_device) {
665 if (!sway_device->tablet) {
666 sway_device->tablet_pad = sway_tablet_pad_create(seat, sway_device);
667 }
668 sway_configure_tablet_pad(sway_device->tablet_pad);
669}
670
649static struct sway_seat_device *seat_get_device(struct sway_seat *seat, 671static struct sway_seat_device *seat_get_device(struct sway_seat *seat,
650 struct sway_input_device *input_device) { 672 struct sway_input_device *input_device) {
651 struct sway_seat_device *seat_device = NULL; 673 struct sway_seat_device *seat_device = NULL;
@@ -682,7 +704,7 @@ void seat_configure_device(struct sway_seat *seat,
682 seat_configure_tablet_tool(seat, seat_device); 704 seat_configure_tablet_tool(seat, seat_device);
683 break; 705 break;
684 case WLR_INPUT_DEVICE_TABLET_PAD: 706 case WLR_INPUT_DEVICE_TABLET_PAD:
685 sway_log(SWAY_DEBUG, "TODO: configure tablet pad"); 707 seat_configure_tablet_pad(seat, seat_device);
686 break; 708 break;
687 } 709 }
688} 710}
@@ -1079,6 +1101,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
1079 seat->has_focus = false; 1101 seat->has_focus = false;
1080 } 1102 }
1081 seat_keyboard_notify_enter(seat, surface); 1103 seat_keyboard_notify_enter(seat, surface);
1104 seat_tablet_pads_notify_enter(seat, surface);
1082} 1105}
1083 1106
1084void seat_set_focus_layer(struct sway_seat *seat, 1107void seat_set_focus_layer(struct sway_seat *seat,
diff --git a/sway/input/tablet.c b/sway/input/tablet.c
new file mode 100644
index 00000000..b0d4d0c6
--- /dev/null
+++ b/sway/input/tablet.c
@@ -0,0 +1,345 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdlib.h>
3#include <wlr/backend/libinput.h>
4#include <wlr/types/wlr_tablet_v2.h>
5#include "log.h"
6#include "sway/input/cursor.h"
7#include "sway/input/seat.h"
8#include "sway/input/tablet.h"
9
10static void handle_pad_tablet_destroy(struct wl_listener *listener, void *data) {
11 struct sway_tablet_pad *pad =
12 wl_container_of(listener, pad, tablet_destroy);
13
14 pad->tablet = NULL;
15
16 wl_list_remove(&pad->tablet_destroy.link);
17 wl_list_init(&pad->tablet_destroy.link);
18}
19
20static void attach_tablet_pad(struct sway_tablet_pad *tablet_pad,
21 struct sway_tablet *tablet) {
22 sway_log(SWAY_DEBUG, "Attaching tablet pad \"%s\" to tablet tool \"%s\"",
23 tablet_pad->seat_device->input_device->wlr_device->name,
24 tablet->seat_device->input_device->wlr_device->name);
25
26 tablet_pad->tablet = tablet;
27
28 wl_list_remove(&tablet_pad->tablet_destroy.link);
29 tablet_pad->tablet_destroy.notify = handle_pad_tablet_destroy;
30 wl_signal_add(&tablet->seat_device->input_device->wlr_device->events.destroy,
31 &tablet_pad->tablet_destroy);
32}
33
34struct sway_tablet *sway_tablet_create(struct sway_seat *seat,
35 struct sway_seat_device *device) {
36 struct sway_tablet *tablet =
37 calloc(1, sizeof(struct sway_tablet));
38 if (!sway_assert(tablet, "could not allocate sway tablet for seat")) {
39 return NULL;
40 }
41
42 wl_list_insert(&seat->cursor->tablets, &tablet->link);
43
44 device->tablet = tablet;
45 tablet->seat_device = device;
46
47 return tablet;
48}
49
50void sway_configure_tablet(struct sway_tablet *tablet) {
51 struct wlr_input_device *device =
52 tablet->seat_device->input_device->wlr_device;
53 struct sway_seat *seat = tablet->seat_device->sway_seat;
54
55 if ((seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
56 seat_configure_xcursor(seat);
57 }
58
59 tablet->tablet_v2 =
60 wlr_tablet_create(server.tablet_v2, seat->wlr_seat, device);
61
62 /* Search for a sibling tablet pad */
63 if (!wlr_input_device_is_libinput(device)) {
64 /* We can only do this on libinput devices */
65 return;
66 }
67
68 struct libinput_device_group *group =
69 libinput_device_get_device_group(wlr_libinput_get_device_handle(device));
70 struct sway_tablet_pad *tablet_pad;
71 wl_list_for_each(tablet_pad, &seat->cursor->tablet_pads, link) {
72 struct wlr_input_device *pad_device =
73 tablet_pad->seat_device->input_device->wlr_device;
74 if (!wlr_input_device_is_libinput(pad_device)) {
75 continue;
76 }
77
78 struct libinput_device_group *pad_group =
79 libinput_device_get_device_group(wlr_libinput_get_device_handle(pad_device));
80
81 if (pad_group == group) {
82 attach_tablet_pad(tablet_pad, tablet);
83 break;
84 }
85 }
86}
87
88void sway_tablet_destroy(struct sway_tablet *tablet) {
89 if (!tablet) {
90 return;
91 }
92 wl_list_remove(&tablet->link);
93 free(tablet);
94}
95
96static void handle_tablet_tool_set_cursor(struct wl_listener *listener, void *data) {
97 struct sway_tablet_tool *tool =
98 wl_container_of(listener, tool, set_cursor);
99 struct wlr_tablet_v2_event_cursor *event = data;
100
101 struct sway_cursor *cursor = tool->seat->cursor;
102 if (!seatop_allows_set_cursor(cursor->seat)) {
103 return;
104 }
105
106 struct wl_client *focused_client = NULL;
107 struct wlr_surface *focused_surface =
108 cursor->seat->wlr_seat->pointer_state.focused_surface;
109 if (focused_surface != NULL) {
110 focused_client = wl_resource_get_client(focused_surface->resource);
111 }
112
113 // TODO: check cursor mode
114 if (focused_client == NULL ||
115 event->seat_client->client != focused_client) {
116 sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client");
117 return;
118 }
119
120 cursor_set_image_surface(cursor, event->surface, event->hotspot_x,
121 event->hotspot_y, focused_client);
122}
123
124static void handle_tablet_tool_destroy(struct wl_listener *listener, void *data) {
125 struct sway_tablet_tool *tool =
126 wl_container_of(listener, tool, tool_destroy);
127
128 wl_list_remove(&tool->tool_destroy.link);
129 wl_list_remove(&tool->set_cursor.link);
130
131 free(tool);
132}
133
134void sway_tablet_tool_configure(struct sway_tablet *tablet,
135 struct wlr_tablet_tool *wlr_tool) {
136 struct sway_tablet_tool *tool =
137 calloc(1, sizeof(struct sway_tablet_tool));
138 if (!sway_assert(tool, "could not allocate sway tablet tool for tablet")) {
139 return;
140 }
141
142 tool->seat = tablet->seat_device->sway_seat;
143 tool->tablet = tablet;
144 tool->tablet_v2_tool =
145 wlr_tablet_tool_create(server.tablet_v2,
146 tablet->seat_device->sway_seat->wlr_seat, wlr_tool);
147
148 tool->tool_destroy.notify = handle_tablet_tool_destroy;
149 wl_signal_add(&wlr_tool->events.destroy, &tool->tool_destroy);
150
151 tool->set_cursor.notify = handle_tablet_tool_set_cursor;
152 wl_signal_add(&tool->tablet_v2_tool->events.set_cursor,
153 &tool->set_cursor);
154
155 wlr_tool->data = tool;
156}
157
158static void handle_tablet_pad_attach(struct wl_listener *listener,
159 void *data) {
160 struct sway_tablet_pad *pad = wl_container_of(listener, pad, attach);
161 struct wlr_tablet_tool *wlr_tool = data;
162 struct sway_tablet_tool *tool = wlr_tool->data;
163
164 if (!tool) {
165 return;
166 }
167
168 attach_tablet_pad(pad, tool->tablet);
169}
170
171static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
172 struct sway_tablet_pad *pad = wl_container_of(listener, pad, ring);
173 struct wlr_event_tablet_pad_ring *event = data;
174
175 if (!pad->current_surface) {
176 return;
177 }
178
179 wlr_tablet_v2_tablet_pad_notify_ring(pad->tablet_v2_pad,
180 event->ring, event->position,
181 event->source == WLR_TABLET_PAD_RING_SOURCE_FINGER,
182 event->time_msec);
183}
184
185static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
186 struct sway_tablet_pad *pad = wl_container_of(listener, pad, strip);
187 struct wlr_event_tablet_pad_strip *event = data;
188
189 if (!pad->current_surface) {
190 return;
191 }
192
193 wlr_tablet_v2_tablet_pad_notify_strip(pad->tablet_v2_pad,
194 event->strip, event->position,
195 event->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER,
196 event->time_msec);
197}
198
199static void handle_tablet_pad_button(struct wl_listener *listener, void *data) {
200 struct sway_tablet_pad *pad = wl_container_of(listener, pad, button);
201 struct wlr_event_tablet_pad_button *event = data;
202
203 if (!pad->current_surface) {
204 return;
205 }
206
207 wlr_tablet_v2_tablet_pad_notify_mode(pad->tablet_v2_pad,
208 event->group, event->mode, event->time_msec);
209
210 wlr_tablet_v2_tablet_pad_notify_button(pad->tablet_v2_pad,
211 event->button, event->time_msec,
212 (enum zwp_tablet_pad_v2_button_state)event->state);
213}
214
215struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
216 struct sway_seat_device *device) {
217 struct sway_tablet_pad *tablet_pad =
218 calloc(1, sizeof(struct sway_tablet_pad));
219 if (!sway_assert(tablet_pad, "could not allocate sway tablet")) {
220 return NULL;
221 }
222
223 tablet_pad->seat_device = device;
224 wl_list_init(&tablet_pad->attach.link);
225 wl_list_init(&tablet_pad->button.link);
226 wl_list_init(&tablet_pad->strip.link);
227 wl_list_init(&tablet_pad->ring.link);
228 wl_list_init(&tablet_pad->surface_destroy.link);
229 wl_list_init(&tablet_pad->tablet_destroy.link);
230
231 wl_list_insert(&seat->cursor->tablet_pads, &tablet_pad->link);
232
233 return tablet_pad;
234}
235
236void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
237 struct wlr_input_device *device =
238 tablet_pad->seat_device->input_device->wlr_device;
239 struct sway_seat *seat = tablet_pad->seat_device->sway_seat;
240
241 tablet_pad->tablet_v2_pad =
242 wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, device);
243
244 wl_list_remove(&tablet_pad->attach.link);
245 tablet_pad->attach.notify = handle_tablet_pad_attach;
246 wl_signal_add(&device->tablet_pad->events.attach_tablet,
247 &tablet_pad->attach);
248
249 wl_list_remove(&tablet_pad->button.link);
250 tablet_pad->button.notify = handle_tablet_pad_button;
251 wl_signal_add(&device->tablet_pad->events.button, &tablet_pad->button);
252
253 wl_list_remove(&tablet_pad->strip.link);
254 tablet_pad->strip.notify = handle_tablet_pad_strip;
255 wl_signal_add(&device->tablet_pad->events.strip, &tablet_pad->strip);
256
257 wl_list_remove(&tablet_pad->ring.link);
258 tablet_pad->ring.notify = handle_tablet_pad_ring;
259 wl_signal_add(&device->tablet_pad->events.ring, &tablet_pad->ring);
260
261 /* Search for a sibling tablet */
262 if (!wlr_input_device_is_libinput(device)) {
263 /* We can only do this on libinput devices */
264 return;
265 }
266
267 struct libinput_device_group *group =
268 libinput_device_get_device_group(wlr_libinput_get_device_handle(device));
269 struct sway_tablet *tool;
270 wl_list_for_each(tool, &seat->cursor->tablets, link) {
271 struct wlr_input_device *tablet =
272 tool->seat_device->input_device->wlr_device;
273 if (!wlr_input_device_is_libinput(tablet)) {
274 continue;
275 }
276
277 struct libinput_device_group *tablet_group =
278 libinput_device_get_device_group(wlr_libinput_get_device_handle(tablet));
279
280 if (tablet_group == group) {
281 attach_tablet_pad(tablet_pad, tool);
282 break;
283 }
284 }
285}
286
287void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad) {
288 if (!tablet_pad) {
289 return;
290 }
291
292 wl_list_remove(&tablet_pad->link);
293 wl_list_remove(&tablet_pad->attach.link);
294 wl_list_remove(&tablet_pad->button.link);
295 wl_list_remove(&tablet_pad->strip.link);
296 wl_list_remove(&tablet_pad->ring.link);
297 wl_list_remove(&tablet_pad->surface_destroy.link);
298 wl_list_remove(&tablet_pad->tablet_destroy.link);
299
300 free(tablet_pad);
301}
302
303static void handle_pad_tablet_surface_destroy(struct wl_listener *listener,
304 void *data) {
305 struct sway_tablet_pad *tablet_pad =
306 wl_container_of(listener, tablet_pad, surface_destroy);
307
308 wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad->tablet_v2_pad,
309 tablet_pad->current_surface);
310 wl_list_remove(&tablet_pad->surface_destroy.link);
311 wl_list_init(&tablet_pad->surface_destroy.link);
312 tablet_pad->current_surface = NULL;
313}
314
315void sway_tablet_pad_notify_enter(struct sway_tablet_pad *tablet_pad,
316 struct wlr_surface *surface) {
317 if (!tablet_pad || !tablet_pad->tablet) {
318 return;
319 }
320
321 if (surface == tablet_pad->current_surface) {
322 return;
323 }
324
325 /* Leave current surface */
326 if (tablet_pad->current_surface) {
327 wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad->tablet_v2_pad,
328 tablet_pad->current_surface);
329 wl_list_remove(&tablet_pad->surface_destroy.link);
330 wl_list_init(&tablet_pad->surface_destroy.link);
331 tablet_pad->current_surface = NULL;
332 }
333
334 if (!wlr_surface_accepts_tablet_v2(tablet_pad->tablet->tablet_v2, surface)) {
335 return;
336 }
337
338 wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad->tablet_v2_pad,
339 tablet_pad->tablet->tablet_v2, surface);
340
341 tablet_pad->current_surface = surface;
342 wl_list_remove(&tablet_pad->surface_destroy.link);
343 tablet_pad->surface_destroy.notify = handle_pad_tablet_surface_destroy;
344 wl_signal_add(&surface->events.destroy, &tablet_pad->surface_destroy);
345}
diff --git a/sway/meson.build b/sway/meson.build
index 4783c58f..24628100 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -31,6 +31,7 @@ sway_sources = files(
31 'input/seatop_resize_floating.c', 31 'input/seatop_resize_floating.c',
32 'input/seatop_resize_tiling.c', 32 'input/seatop_resize_tiling.c',
33 'input/switch.c', 33 'input/switch.c',
34 'input/tablet.c',
34 35
35 'config/bar.c', 36 'config/bar.c',
36 'config/output.c', 37 'config/output.c',
diff --git a/sway/server.c b/sway/server.c
index aee2cc87..e2d54947 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -19,6 +19,7 @@
19#include <wlr/types/wlr_relative_pointer_v1.h> 19#include <wlr/types/wlr_relative_pointer_v1.h>
20#include <wlr/types/wlr_screencopy_v1.h> 20#include <wlr/types/wlr_screencopy_v1.h>
21#include <wlr/types/wlr_server_decoration.h> 21#include <wlr/types/wlr_server_decoration.h>
22#include <wlr/types/wlr_tablet_v2.h>
22#include <wlr/types/wlr_xcursor_manager.h> 23#include <wlr/types/wlr_xcursor_manager.h>
23#include <wlr/types/wlr_xdg_decoration_v1.h> 24#include <wlr/types/wlr_xdg_decoration_v1.h>
24#include <wlr/types/wlr_xdg_output_v1.h> 25#include <wlr/types/wlr_xdg_output_v1.h>
@@ -86,6 +87,8 @@ bool server_init(struct sway_server *server) {
86 &server->xdg_shell_surface); 87 &server->xdg_shell_surface);
87 server->xdg_shell_surface.notify = handle_xdg_shell_surface; 88 server->xdg_shell_surface.notify = handle_xdg_shell_surface;
88 89
90 server->tablet_v2 = wlr_tablet_v2_create(server->wl_display);
91
89 server->server_decoration_manager = 92 server->server_decoration_manager =
90 wlr_server_decoration_manager_create(server->wl_display); 93 wlr_server_decoration_manager_create(server->wl_display);
91 wlr_server_decoration_manager_set_default_mode( 94 wlr_server_decoration_manager_set_default_mode(