diff options
Diffstat (limited to 'sway/input')
-rw-r--r-- | sway/input/cursor.c | 89 | ||||
-rw-r--r-- | sway/input/seat.c | 56 | ||||
-rw-r--r-- | sway/input/seatop_default.c | 310 |
3 files changed, 403 insertions, 52 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 0b2f03a2..e87594ee 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -928,14 +928,28 @@ static void handle_request_pointer_set_cursor(struct wl_listener *listener, event->hotspot_y, focused_client); } +static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of( + listener, cursor, hold_begin); + struct wlr_pointer_hold_begin_event *event = data; + cursor_handle_activity_from_device(cursor, &event->pointer->base); + seatop_hold_begin(cursor->seat, event); +} + +static void handle_pointer_hold_end(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of( + listener, cursor, hold_end); + struct wlr_pointer_hold_end_event *event = data; + cursor_handle_activity_from_device(cursor, &event->pointer->base); + seatop_hold_end(cursor->seat, event); +} + static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of( listener, cursor, pinch_begin); struct wlr_pointer_pinch_begin_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_pinch_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); + seatop_pinch_begin(cursor->seat, event); } static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) { @@ -943,10 +957,7 @@ static void handle_pointer_pinch_update(struct wl_listener *listener, void *data listener, cursor, pinch_update); struct wlr_pointer_pinch_update_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_pinch_update( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->dx, event->dy, - event->scale, event->rotation); + seatop_pinch_update(cursor->seat, event); } static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { @@ -954,9 +965,7 @@ static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { listener, cursor, pinch_end); struct wlr_pointer_pinch_end_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_pinch_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->cancelled); + seatop_pinch_end(cursor->seat, event); } static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) { @@ -964,9 +973,7 @@ static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) listener, cursor, swipe_begin); struct wlr_pointer_swipe_begin_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_swipe_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); + seatop_swipe_begin(cursor->seat, event); } static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) { @@ -974,9 +981,7 @@ static void handle_pointer_swipe_update(struct wl_listener *listener, void *data listener, cursor, swipe_update); struct wlr_pointer_swipe_update_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_swipe_update( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->dx, event->dy); + seatop_swipe_update(cursor->seat, event); } static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { @@ -984,29 +989,7 @@ static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { listener, cursor, swipe_end); struct wlr_pointer_swipe_end_event *event = data; cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_swipe_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->cancelled); -} - -static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, hold_begin); - struct wlr_pointer_hold_begin_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_hold_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); -} - -static void handle_pointer_hold_end(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, hold_end); - struct wlr_pointer_hold_end_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - wlr_pointer_gestures_v1_send_hold_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->cancelled); + seatop_swipe_end(cursor->seat, event); } static void handle_image_surface_destroy(struct wl_listener *listener, @@ -1080,14 +1063,14 @@ void sway_cursor_destroy(struct sway_cursor *cursor) { wl_event_source_remove(cursor->hide_source); wl_list_remove(&cursor->image_surface_destroy.link); + wl_list_remove(&cursor->hold_begin.link); + wl_list_remove(&cursor->hold_end.link); wl_list_remove(&cursor->pinch_begin.link); wl_list_remove(&cursor->pinch_update.link); wl_list_remove(&cursor->pinch_end.link); wl_list_remove(&cursor->swipe_begin.link); wl_list_remove(&cursor->swipe_update.link); wl_list_remove(&cursor->swipe_end.link); - wl_list_remove(&cursor->hold_begin.link); - wl_list_remove(&cursor->hold_end.link); wl_list_remove(&cursor->motion.link); wl_list_remove(&cursor->motion_absolute.link); wl_list_remove(&cursor->button.link); @@ -1131,23 +1114,27 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_list_init(&cursor->image_surface_destroy.link); cursor->image_surface_destroy.notify = handle_image_surface_destroy; + // gesture events cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display); - cursor->pinch_begin.notify = handle_pointer_pinch_begin; + + wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); + cursor->hold_begin.notify = handle_pointer_hold_begin; + wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); + cursor->hold_end.notify = handle_pointer_hold_end; + wl_signal_add(&wlr_cursor->events.pinch_begin, &cursor->pinch_begin); - cursor->pinch_update.notify = handle_pointer_pinch_update; + cursor->pinch_begin.notify = handle_pointer_pinch_begin; wl_signal_add(&wlr_cursor->events.pinch_update, &cursor->pinch_update); - cursor->pinch_end.notify = handle_pointer_pinch_end; + cursor->pinch_update.notify = handle_pointer_pinch_update; wl_signal_add(&wlr_cursor->events.pinch_end, &cursor->pinch_end); - cursor->swipe_begin.notify = handle_pointer_swipe_begin; + cursor->pinch_end.notify = handle_pointer_pinch_end; + wl_signal_add(&wlr_cursor->events.swipe_begin, &cursor->swipe_begin); - cursor->swipe_update.notify = handle_pointer_swipe_update; + cursor->swipe_begin.notify = handle_pointer_swipe_begin; wl_signal_add(&wlr_cursor->events.swipe_update, &cursor->swipe_update); - cursor->swipe_end.notify = handle_pointer_swipe_end; + cursor->swipe_update.notify = handle_pointer_swipe_update; wl_signal_add(&wlr_cursor->events.swipe_end, &cursor->swipe_end); - cursor->hold_begin.notify = handle_pointer_hold_begin; - wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); - cursor->hold_end.notify = handle_pointer_hold_end; - wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); + cursor->swipe_end.notify = handle_pointer_swipe_end; // input events wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); diff --git a/sway/input/seat.c b/sway/input/seat.c index 11c78154..fe61e0fe 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1614,6 +1614,62 @@ void seatop_tablet_tool_motion(struct sway_seat *seat, } } +void seatop_hold_begin(struct sway_seat *seat, + struct wlr_pointer_hold_begin_event *event) { + if (seat->seatop_impl->hold_begin) { + seat->seatop_impl->hold_begin(seat, event); + } +} + +void seatop_hold_end(struct sway_seat *seat, + struct wlr_pointer_hold_end_event *event) { + if (seat->seatop_impl->hold_end) { + seat->seatop_impl->hold_end(seat, event); + } +} + +void seatop_pinch_begin(struct sway_seat *seat, + struct wlr_pointer_pinch_begin_event *event) { + if (seat->seatop_impl->pinch_begin) { + seat->seatop_impl->pinch_begin(seat, event); + } +} + +void seatop_pinch_update(struct sway_seat *seat, + struct wlr_pointer_pinch_update_event *event) { + if (seat->seatop_impl->pinch_update) { + seat->seatop_impl->pinch_update(seat, event); + } +} + +void seatop_pinch_end(struct sway_seat *seat, + struct wlr_pointer_pinch_end_event *event) { + if (seat->seatop_impl->pinch_end) { + seat->seatop_impl->pinch_end(seat, event); + } +} + +void seatop_swipe_begin(struct sway_seat *seat, + struct wlr_pointer_swipe_begin_event *event) { + if (seat->seatop_impl->swipe_begin) { + seat->seatop_impl->swipe_begin(seat, event); + } +} + +void seatop_swipe_update(struct sway_seat *seat, + struct wlr_pointer_swipe_update_event *event) { + if (seat->seatop_impl->swipe_update) { + seat->seatop_impl->swipe_update(seat, event); + } +} + +void seatop_swipe_end(struct sway_seat *seat, + struct wlr_pointer_swipe_end_event *event) { + if (seat->seatop_impl->swipe_end) { + seat->seatop_impl->swipe_end(seat, event); + } +} + void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) { if (seat->seatop_impl->rebase) { seat->seatop_impl->rebase(seat, time_msec); diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index 15d1ca8b..2684e55a 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -4,6 +4,7 @@ #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_tablet_v2.h> #include <wlr/types/wlr_xcursor_manager.h> +#include "gesture.h" #include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/input/seat.h" @@ -20,6 +21,7 @@ struct seatop_default_event { struct sway_node *previous_node; uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; size_t pressed_button_count; + struct gesture_tracker gestures; }; /*-----------------------------------------\ @@ -750,6 +752,304 @@ static void handle_pointer_axis(struct sway_seat *seat, } } +/*------------------------------------\ + * Functions used by gesture support / + *----------------------------------*/ + +/** + * Check gesture binding for a specific gesture type and finger count. + * Returns true if binding is present, false otherwise + */ +static bool gesture_binding_check(list_t *bindings, enum gesture_type type, + uint8_t fingers, struct sway_input_device *device) { + char *input = + device ? input_device_get_identifier(device->wlr_device) : strdup("*"); + + for (int i = 0; i < bindings->length; ++i) { + struct sway_gesture_binding *binding = bindings->items[i]; + + // Check type and finger count + if (!gesture_check(&binding->gesture, type, fingers)) { + continue; + } + + // Check that input matches + if (strcmp(binding->input, "*") != 0 && + strcmp(binding->input, input) != 0) { + continue; + } + + free(input); + + return true; + } + + free(input); + + return false; +} + +/** + * Return the gesture binding which matches gesture type, finger count + * and direction, otherwise return null. + */ +static struct sway_gesture_binding* gesture_binding_match( + list_t *bindings, struct gesture *gesture, const char *input) { + struct sway_gesture_binding *current = NULL; + + // Find best matching binding + for (int i = 0; i < bindings->length; ++i) { + struct sway_gesture_binding *binding = bindings->items[i]; + bool exact = binding->flags & BINDING_EXACT; + + // Check gesture matching + if (!gesture_match(&binding->gesture, gesture, exact)) { + continue; + } + + // Check input matching + if (strcmp(binding->input, "*") != 0 && + strcmp(binding->input, input) != 0) { + continue; + } + + // If we already have a match ... + if (current) { + // ... check if input matching is equivalent + if (strcmp(current->input, binding->input) == 0) { + + // ... - do not override an exact binding + if (!exact && current->flags & BINDING_EXACT) { + continue; + } + + // ... - and ensure direction matching is better or equal + if (gesture_compare(¤t->gesture, &binding->gesture) > 0) { + continue; + } + } else if (strcmp(binding->input, "*") == 0) { + // ... do not accept worse input match + continue; + } + } + + // Accept newer or better match + current = binding; + + // If exact binding and input is found, quit search + if (strcmp(current->input, input) == 0 && + gesture_compare(¤t->gesture, gesture) == 0) { + break; + } + } // for all gesture bindings + + return current; +} + +// Wrapper around gesture_tracker_end to use tracker with sway bindings +static struct sway_gesture_binding* gesture_tracker_end_and_match( + struct gesture_tracker *tracker, struct sway_input_device* device) { + // Determine name of input that received gesture + char *input = device + ? input_device_get_identifier(device->wlr_device) + : strdup("*"); + + // Match tracking result to binding + struct gesture *gesture = gesture_tracker_end(tracker); + struct sway_gesture_binding *binding = gesture_binding_match( + config->current_mode->gesture_bindings, gesture, input); + free(gesture); + free(input); + + return binding; +} + +// Small wrapper around seat_execute_command to work on gesture bindings +static void gesture_binding_execute(struct sway_seat *seat, + struct sway_gesture_binding *binding) { + struct sway_binding *dummy_binding = + calloc(1, sizeof(struct sway_binding)); + dummy_binding->type = BINDING_GESTURE; + dummy_binding->command = binding->command; + + char *description = gesture_to_string(&binding->gesture); + sway_log(SWAY_DEBUG, "executing gesture binding: %s", description); + free(description); + + seat_execute_command(seat, dummy_binding); + + free(dummy_binding); +} + +static void handle_hold_begin(struct sway_seat *seat, + struct wlr_pointer_hold_begin_event *event) { + // Start tracking gesture if there is a matching binding ... + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + list_t *bindings = config->current_mode->gesture_bindings; + if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) { + struct seatop_default_event *seatop = seat->seatop_data; + gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers); + } else { + // ... otherwise forward to client + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_hold_begin( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->fingers); + } +} + +static void handle_hold_end(struct sway_seat *seat, + struct wlr_pointer_hold_end_event *event) { + // Ensure that gesture is being tracked and was not cancelled + struct seatop_default_event *seatop = seat->seatop_data; + if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) { + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_hold_end( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->cancelled); + return; + } + if (event->cancelled) { + gesture_tracker_cancel(&seatop->gestures); + return; + } + + // End gesture tracking and execute matched binding + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + struct sway_gesture_binding *binding = gesture_tracker_end_and_match( + &seatop->gestures, device); + + if (binding) { + gesture_binding_execute(seat, binding); + } +} + +static void handle_pinch_begin(struct sway_seat *seat, + struct wlr_pointer_pinch_begin_event *event) { + // Start tracking gesture if there is a matching binding ... + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + list_t *bindings = config->current_mode->gesture_bindings; + if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) { + struct seatop_default_event *seatop = seat->seatop_data; + gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers); + } else { + // ... otherwise forward to client + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_pinch_begin( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->fingers); + } +} + +static void handle_pinch_update(struct sway_seat *seat, + struct wlr_pointer_pinch_update_event *event) { + // Update any ongoing tracking ... + struct seatop_default_event *seatop = seat->seatop_data; + if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { + gesture_tracker_update(&seatop->gestures, event->dx, event->dy, + event->scale, event->rotation); + } else { + // ... otherwise forward to client + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_pinch_update( + cursor->pointer_gestures, + cursor->seat->wlr_seat, + event->time_msec, event->dx, event->dy, + event->scale, event->rotation); + } +} + +static void handle_pinch_end(struct sway_seat *seat, + struct wlr_pointer_pinch_end_event *event) { + // Ensure that gesture is being tracked and was not cancelled + struct seatop_default_event *seatop = seat->seatop_data; + if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_pinch_end( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->cancelled); + return; + } + if (event->cancelled) { + gesture_tracker_cancel(&seatop->gestures); + return; + } + + // End gesture tracking and execute matched binding + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + struct sway_gesture_binding *binding = gesture_tracker_end_and_match( + &seatop->gestures, device); + + if (binding) { + gesture_binding_execute(seat, binding); + } +} + +static void handle_swipe_begin(struct sway_seat *seat, + struct wlr_pointer_swipe_begin_event *event) { + // Start tracking gesture if there is a matching binding ... + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + list_t *bindings = config->current_mode->gesture_bindings; + if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) { + struct seatop_default_event *seatop = seat->seatop_data; + gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers); + } else { + // ... otherwise forward to client + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_swipe_begin( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->fingers); + } +} + +static void handle_swipe_update(struct sway_seat *seat, + struct wlr_pointer_swipe_update_event *event) { + + // Update any ongoing tracking ... + struct seatop_default_event *seatop = seat->seatop_data; + if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { + gesture_tracker_update(&seatop->gestures, + event->dx, event->dy, NAN, NAN); + } else { + // ... otherwise forward to client + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_swipe_update( + cursor->pointer_gestures, cursor->seat->wlr_seat, + event->time_msec, event->dx, event->dy); + } +} + +static void handle_swipe_end(struct sway_seat *seat, + struct wlr_pointer_swipe_end_event *event) { + // Ensure gesture is being tracked and was not cancelled + struct seatop_default_event *seatop = seat->seatop_data; + if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { + struct sway_cursor *cursor = seat->cursor; + wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures, + cursor->seat->wlr_seat, event->time_msec, event->cancelled); + return; + } + if (event->cancelled) { + gesture_tracker_cancel(&seatop->gestures); + return; + } + + // End gesture tracking and execute matched binding + struct sway_input_device *device = + event->pointer ? event->pointer->base.data : NULL; + struct sway_gesture_binding *binding = gesture_tracker_end_and_match( + &seatop->gestures, device); + + if (binding) { + gesture_binding_execute(seat, binding); + } +} + /*----------------------------------\ * Functions used by handle_rebase / *--------------------------------*/ @@ -779,6 +1079,14 @@ static const struct sway_seatop_impl seatop_impl = { .pointer_axis = handle_pointer_axis, .tablet_tool_tip = handle_tablet_tool_tip, .tablet_tool_motion = handle_tablet_tool_motion, + .hold_begin = handle_hold_begin, + .hold_end = handle_hold_end, + .pinch_begin = handle_pinch_begin, + .pinch_update = handle_pinch_update, + .pinch_end = handle_pinch_end, + .swipe_begin = handle_swipe_begin, + .swipe_update = handle_swipe_update, + .swipe_end = handle_swipe_end, .rebase = handle_rebase, .allow_set_cursor = true, }; @@ -789,8 +1097,8 @@ void seatop_begin_default(struct sway_seat *seat) { struct seatop_default_event *e = calloc(1, sizeof(struct seatop_default_event)); sway_assert(e, "Unable to allocate seatop_default_event"); + seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seatop_rebase(seat, 0); } |