diff options
-rw-r--r-- | include/sway/input/cursor.h | 3 | ||||
-rw-r--r-- | include/sway/input/seat.h | 2 | ||||
-rw-r--r-- | include/sway/input/tablet.h | 62 | ||||
-rw-r--r-- | include/sway/server.h | 2 | ||||
-rw-r--r-- | protocols/meson.build | 1 | ||||
-rw-r--r-- | sway/input/cursor.c | 242 | ||||
-rw-r--r-- | sway/input/seat.c | 29 | ||||
-rw-r--r-- | sway/input/tablet.c | 345 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/server.c | 3 |
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 | |||
5 | struct sway_seat; | ||
6 | struct wlr_tablet_tool; | ||
7 | |||
8 | struct sway_tablet { | ||
9 | struct wl_list link; | ||
10 | struct sway_seat_device *seat_device; | ||
11 | struct wlr_tablet_v2_tablet *tablet_v2; | ||
12 | }; | ||
13 | |||
14 | struct 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 | |||
25 | struct 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 | |||
42 | struct sway_tablet *sway_tablet_create(struct sway_seat *seat, | ||
43 | struct sway_seat_device *device); | ||
44 | |||
45 | void sway_configure_tablet(struct sway_tablet *tablet); | ||
46 | |||
47 | void sway_tablet_destroy(struct sway_tablet *tablet); | ||
48 | |||
49 | void sway_tablet_tool_configure(struct sway_tablet *tablet, | ||
50 | struct wlr_tablet_tool *wlr_tool); | ||
51 | |||
52 | struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat, | ||
53 | struct sway_seat_device *device); | ||
54 | |||
55 | void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad); | ||
56 | |||
57 | void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad); | ||
58 | |||
59 | void 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 | ||
448 | static 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 | |||
446 | static void handle_tool_axis(struct wl_listener *listener, void *data) { | 493 | static 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 | ||
477 | static void handle_tool_tip(struct wl_listener *listener, void *data) { | 549 | static 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 | |||
579 | static 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 | |||
590 | static 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 | ||
488 | static void handle_tool_button(struct wl_listener *listener, void *data) { | 620 | static 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 | ||
514 | static void check_constraint_region(struct sway_cursor *cursor) { | 668 | static 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 | ||
125 | static 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 | ||
639 | static void seat_configure_tablet_tool(struct sway_seat *seat, | 652 | static 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 | ||
663 | static 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 | |||
649 | static struct sway_seat_device *seat_get_device(struct sway_seat *seat, | 671 | static 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 | ||
1084 | void seat_set_focus_layer(struct sway_seat *seat, | 1107 | void 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 | |||
10 | static 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 | |||
20 | static 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 | |||
34 | struct 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 | |||
50 | void 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 | |||
88 | void sway_tablet_destroy(struct sway_tablet *tablet) { | ||
89 | if (!tablet) { | ||
90 | return; | ||
91 | } | ||
92 | wl_list_remove(&tablet->link); | ||
93 | free(tablet); | ||
94 | } | ||
95 | |||
96 | static 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 | |||
124 | static 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 | |||
134 | void 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 | |||
158 | static 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 | |||
171 | static 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 | |||
185 | static 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 | |||
199 | static 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 | |||
215 | struct 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 | |||
236 | void 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 | |||
287 | void 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 | |||
303 | static 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 | |||
315 | void 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( |