diff options
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 242 |
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 @@ #include <wlr/types/wlr_box.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_tablet_v2.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/util/region.h> #include "list.h" @@ -20,6 +21,7 @@ #include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/input/keyboard.h" +#include "sway/input/tablet.h" #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" @@ -443,72 +445,224 @@ static void apply_mapping_from_region(struct wlr_input_device *device, *y = apply_mapping_from_coord(y1, y2, *y); } +static void handle_tablet_tool_position(struct sway_cursor *cursor, + struct sway_tablet *tablet, + struct wlr_tablet_tool *tool, + bool change_x, bool change_y, + double x, double y, double dx, double dy, + int32_t time_msec) { + if (!change_x && !change_y) { + return; + } + + struct sway_input_device *input_device = tablet->seat_device->input_device; + struct input_config *ic = input_device_get_config(input_device); + if (ic != NULL && ic->mapped_from_region != NULL) { + apply_mapping_from_region(input_device->wlr_device, + ic->mapped_from_region, &x, &y); + } + + switch (tool->type) { + case WLR_TABLET_TOOL_TYPE_MOUSE: + wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy); + break; + default: + wlr_cursor_warp_absolute(cursor->cursor, input_device->wlr_device, + change_x ? x : NAN, change_y ? y : NAN); + } + + double sx, sy; + struct wlr_surface *surface = NULL; + struct sway_seat *seat = cursor->seat; + node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, + &surface, &sx, &sy); + struct sway_tablet_tool *sway_tool = tool->data; + + if (!surface || !wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) { + wlr_tablet_v2_tablet_tool_notify_proximity_out(sway_tool->tablet_v2_tool); + cursor_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy); + return; + } + + wlr_tablet_v2_tablet_tool_notify_proximity_in(sway_tool->tablet_v2_tool, + tablet->tablet_v2, surface); + + wlr_tablet_v2_tablet_tool_notify_motion(sway_tool->tablet_v2_tool, sx, sy); +} + static void handle_tool_axis(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis); wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); struct wlr_event_tablet_tool_axis *event = data; - struct sway_input_device *input_device = event->device->data; + struct sway_tablet_tool *sway_tool = event->tool->data; - double x = NAN, y = NAN; - if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { - x = event->x; + if (!sway_tool) { + sway_log(SWAY_DEBUG, "tool axis before proximity"); + return; } - if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - y = event->y; + + handle_tablet_tool_position(cursor, sway_tool->tablet, event->tool, + event->updated_axes & WLR_TABLET_TOOL_AXIS_X, + event->updated_axes & WLR_TABLET_TOOL_AXIS_Y, + event->x, event->y, event->dx, event->dy, event->time_msec); + + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) { + wlr_tablet_v2_tablet_tool_notify_pressure( + sway_tool->tablet_v2_tool, event->pressure); } - struct input_config *ic = input_device_get_config(input_device); - if (ic != NULL && ic->mapped_from_region != NULL) { - apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) { + wlr_tablet_v2_tablet_tool_notify_distance( + sway_tool->tablet_v2_tool, event->distance); } - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, - x, y, &lx, &ly); + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) { + sway_tool->tilt_x = event->tilt_x; + } - double dx = lx - cursor->cursor->x; - double dy = ly - cursor->cursor->y; + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) { + sway_tool->tilt_y = event->tilt_y; + } - cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - transaction_commit_dirty(); + if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) { + wlr_tablet_v2_tablet_tool_notify_tilt( + sway_tool->tablet_v2_tool, + sway_tool->tilt_x, sway_tool->tilt_y); + } + + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) { + wlr_tablet_v2_tablet_tool_notify_rotation( + sway_tool->tablet_v2_tool, event->rotation); + } + + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) { + wlr_tablet_v2_tablet_tool_notify_slider( + sway_tool->tablet_v2_tool, event->slider); + } + + if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) { + wlr_tablet_v2_tablet_tool_notify_wheel( + sway_tool->tablet_v2_tool, event->wheel_delta, 0); + } } static void handle_tool_tip(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip); wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); struct wlr_event_tablet_tool_tip *event = data; - dispatch_cursor_button(cursor, event->device, event->time_msec, - BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? - WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - transaction_commit_dirty(); + struct sway_tablet_tool *sway_tool = event->tool->data; + struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; + struct sway_seat *seat = cursor->seat; + + double sx, sy; + struct wlr_surface *surface = NULL; + node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, + &surface, &sx, &sy); + + if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { + dispatch_cursor_button(cursor, event->device, event->time_msec, + BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? + WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); + wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); + transaction_commit_dirty(); + return; + } + + if (event->state == WLR_TABLET_TOOL_TIP_DOWN) { + wlr_tablet_v2_tablet_tool_notify_down(sway_tool->tablet_v2_tool); + wlr_tablet_tool_v2_start_implicit_grab(sway_tool->tablet_v2_tool); + } else { + wlr_tablet_v2_tablet_tool_notify_up(sway_tool->tablet_v2_tool); + } +} + +static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor, + struct wlr_input_device *device) { + struct sway_tablet *tablet; + wl_list_for_each(tablet, &cursor->tablets, link) { + if (tablet->seat_device->input_device->wlr_device == device) { + return tablet; + } + } + return NULL; +} + +static void handle_tool_proximity(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_proximity); + wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + struct wlr_event_tablet_tool_proximity *event = data; + + struct wlr_tablet_tool *tool = event->tool; + if (!tool->data) { + struct sway_tablet *tablet = get_tablet_for_device(cursor, event->device); + if (!tablet) { + sway_log(SWAY_ERROR, "no tablet for tablet tool"); + return; + } + sway_tablet_tool_configure(tablet, tool); + } + + struct sway_tablet_tool *sway_tool = tool->data; + if (!sway_tool) { + sway_log(SWAY_ERROR, "tablet tool not initialized"); + return; + } + + if (event->state == WLR_TABLET_TOOL_PROXIMITY_OUT) { + wlr_tablet_v2_tablet_tool_notify_proximity_out(sway_tool->tablet_v2_tool); + return; + } + + handle_tablet_tool_position(cursor, sway_tool->tablet, event->tool, + true, true, event->x, event->y, 0, 0, event->time_msec); } static void handle_tool_button(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button); wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); struct wlr_event_tablet_tool_button *event = data; - // TODO: the user may want to configure which tool buttons are mapped to - // which simulated pointer buttons - switch (event->state) { - case WLR_BUTTON_PRESSED: - if (cursor->tool_buttons == 0) { - dispatch_cursor_button(cursor, event->device, - event->time_msec, BTN_RIGHT, event->state); - } - cursor->tool_buttons++; - break; - case WLR_BUTTON_RELEASED: - if (cursor->tool_buttons == 1) { - dispatch_cursor_button(cursor, event->device, - event->time_msec, BTN_RIGHT, event->state); + struct sway_tablet_tool *sway_tool = event->tool->data; + struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; + struct sway_seat *seat = cursor->seat; + + if (!sway_tool) { + sway_log(SWAY_DEBUG, "tool button before proximity"); + return; + } + + double sx, sy; + struct wlr_surface *surface = NULL; + + node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, + &surface, &sx, &sy); + + if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { + // TODO: the user may want to configure which tool buttons are mapped to + // which simulated pointer buttons + switch (event->state) { + case WLR_BUTTON_PRESSED: + if (cursor->tool_buttons == 0) { + dispatch_cursor_button(cursor, event->device, + event->time_msec, BTN_RIGHT, event->state); + } + cursor->tool_buttons++; + break; + case WLR_BUTTON_RELEASED: + if (cursor->tool_buttons == 1) { + dispatch_cursor_button(cursor, event->device, + event->time_msec, BTN_RIGHT, event->state); + } + cursor->tool_buttons--; + break; } - cursor->tool_buttons--; - break; + wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); + transaction_commit_dirty(); + return; } - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - transaction_commit_dirty(); + + wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool, + (enum zwp_tablet_pad_v2_button_state)event->button, + (enum zwp_tablet_pad_v2_button_state)event->state); } static void check_constraint_region(struct sway_cursor *cursor) { @@ -698,9 +852,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { &cursor->touch_motion); cursor->touch_motion.notify = handle_touch_motion; - // TODO: tablet protocol support - // Note: We should emulate pointer events for clients that don't support the - // tablet protocol when the time comes wl_signal_add(&wlr_cursor->events.tablet_tool_axis, &cursor->tool_axis); cursor->tool_axis.notify = handle_tool_axis; @@ -708,6 +859,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); cursor->tool_tip.notify = handle_tool_tip; + wl_signal_add(&wlr_cursor->events.tablet_tool_proximity, &cursor->tool_proximity); + cursor->tool_proximity.notify = handle_tool_proximity; + wl_signal_add(&wlr_cursor->events.tablet_tool_button, &cursor->tool_button); cursor->tool_button.notify = handle_tool_button; @@ -716,6 +870,8 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { cursor->request_set_cursor.notify = handle_request_set_cursor; wl_list_init(&cursor->constraint_commit.link); + wl_list_init(&cursor->tablets); + wl_list_init(&cursor->tablet_pads); cursor->cursor = wlr_cursor; |