diff --git a/backend/libinput/events.c b/backend/libinput/events.c index a7a6c114..93f8c527 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -287,6 +287,24 @@ void handle_libinput_event(struct wlr_libinput_backend *backend, case LIBINPUT_EVENT_SWITCH_TOGGLE: handle_switch_toggle(event, libinput_dev); break; + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + handle_pointer_swipe_begin(event, libinput_dev); + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + handle_pointer_swipe_update(event, libinput_dev); + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + handle_pointer_swipe_end(event, libinput_dev); + break; + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: + handle_pointer_pinch_begin(event, libinput_dev); + break; + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + handle_pointer_pinch_update(event, libinput_dev); + break; + case LIBINPUT_EVENT_GESTURE_PINCH_END: + handle_pointer_pinch_end(event, libinput_dev); + break; default: wlr_log(WLR_DEBUG, "Unknown libinput event %d", event_type); break; diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 0df16a10..2e799df6 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -140,3 +140,123 @@ void handle_pointer_axis(struct libinput_event *event, } wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); } + +void handle_pointer_swipe_begin(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_swipe_begin wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .fingers = libinput_event_gesture_get_finger_count(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_begin, &wlr_event); +} + +void handle_pointer_swipe_update(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_swipe_update wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .fingers = libinput_event_gesture_get_finger_count(gevent), + .dx = libinput_event_gesture_get_dx(gevent), + .dy = libinput_event_gesture_get_dy(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_update, &wlr_event); +} + +void handle_pointer_swipe_end(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_swipe_end wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .cancelled = libinput_event_gesture_get_cancelled(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_end, &wlr_event); +} + +void handle_pointer_pinch_begin(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_pinch_begin wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .fingers = libinput_event_gesture_get_finger_count(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_begin, &wlr_event); +} + +void handle_pointer_pinch_update(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_pinch_update wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .fingers = libinput_event_gesture_get_finger_count(gevent), + .dx = libinput_event_gesture_get_dx(gevent), + .dy = libinput_event_gesture_get_dy(gevent), + .scale = libinput_event_gesture_get_scale(gevent), + .rotation = libinput_event_gesture_get_angle_delta(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_update, &wlr_event); +} + +void handle_pointer_pinch_end(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); + return; + } + struct libinput_event_gesture *gevent = + libinput_event_get_gesture_event(event); + struct wlr_event_pointer_pinch_end wlr_event = { + .device = wlr_dev, + .time_msec = + usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), + .cancelled = libinput_event_gesture_get_cancelled(gevent), + }; + wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_end, &wlr_event); +} diff --git a/include/backend/libinput.h b/include/backend/libinput.h index f4886956..ddb81a5a 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -54,6 +54,18 @@ void handle_pointer_button(struct libinput_event *event, struct libinput_device *device); void handle_pointer_axis(struct libinput_event *event, struct libinput_device *device); +void handle_pointer_swipe_begin(struct libinput_event *event, + struct libinput_device *device); +void handle_pointer_swipe_update(struct libinput_event *event, + struct libinput_device *device); +void handle_pointer_swipe_end(struct libinput_event *event, + struct libinput_device *device); +void handle_pointer_pinch_begin(struct libinput_event *event, + struct libinput_device *device); +void handle_pointer_pinch_update(struct libinput_event *event, + struct libinput_device *device); +void handle_pointer_pinch_end(struct libinput_event *event, + struct libinput_device *device); struct wlr_switch *create_libinput_switch( struct libinput_device *device); diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index d1db6856..0d6b6014 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -39,6 +39,12 @@ struct roots_cursor { struct wl_listener button; struct wl_listener axis; struct wl_listener frame; + struct wl_listener swipe_begin; + struct wl_listener swipe_update; + struct wl_listener swipe_end; + struct wl_listener pinch_begin; + struct wl_listener pinch_update; + struct wl_listener pinch_end; struct wl_listener touch_down; struct wl_listener touch_up; diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 56d2a129..d8fc53e2 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct roots_desktop { struct wlr_presentation *presentation; struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager_v1; struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; + struct wlr_pointer_gestures_v1 *pointer_gestures; struct wl_listener new_output; struct wl_listener layout_change; diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build index 86f128b6..82715ad1 100644 --- a/include/wlr/types/meson.build +++ b/include/wlr/types/meson.build @@ -25,6 +25,7 @@ install_headers( 'wlr_output_layout.h', 'wlr_output.h', 'wlr_pointer_constraints_v1.h', + 'wlr_pointer_gestures_v1.h', 'wlr_pointer.h', 'wlr_presentation_time.h', 'wlr_primary_selection.h', diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 6475669c..192ba8a0 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -52,6 +52,12 @@ struct wlr_cursor { struct wl_signal button; struct wl_signal axis; struct wl_signal frame; + struct wl_signal swipe_begin; + struct wl_signal swipe_update; + struct wl_signal swipe_end; + struct wl_signal pinch_begin; + struct wl_signal pinch_update; + struct wl_signal pinch_end; struct wl_signal touch_up; struct wl_signal touch_down; diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 9dfe7aaa..486e1bc9 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -24,6 +24,12 @@ struct wlr_pointer { struct wl_signal button; struct wl_signal axis; struct wl_signal frame; + struct wl_signal swipe_begin; + struct wl_signal swipe_update; + struct wl_signal swipe_end; + struct wl_signal pinch_begin; + struct wl_signal pinch_update; + struct wl_signal pinch_end; } events; void *data; @@ -71,4 +77,50 @@ struct wlr_event_pointer_axis { int32_t delta_discrete; }; +struct wlr_event_pointer_swipe_begin { + struct wlr_input_device *device; + uint32_t time_msec; + uint32_t fingers; +}; + +struct wlr_event_pointer_swipe_update { + struct wlr_input_device *device; + uint32_t time_msec; + uint32_t fingers; + // Relative coordinates of the logical center of the gesture + // compared to the previous event. + double dx, dy; +}; + +struct wlr_event_pointer_swipe_end { + struct wlr_input_device *device; + uint32_t time_msec; + bool cancelled; +}; + +struct wlr_event_pointer_pinch_begin { + struct wlr_input_device *device; + uint32_t time_msec; + uint32_t fingers; +}; + +struct wlr_event_pointer_pinch_update { + struct wlr_input_device *device; + uint32_t time_msec; + uint32_t fingers; + // Relative coordinates of the logical center of the gesture + // compared to the previous event. + double dx, dy; + // Absolute scale compared to the begin event + double scale; + // Relative angle in degrees clockwise compared to the previous event. + double rotation; +}; + +struct wlr_event_pointer_pinch_end { + struct wlr_input_device *device; + uint32_t time_msec; + bool cancelled; +}; + #endif diff --git a/include/wlr/types/wlr_pointer_gestures_v1.h b/include/wlr/types/wlr_pointer_gestures_v1.h new file mode 100644 index 00000000..7caf0f53 --- /dev/null +++ b/include/wlr/types/wlr_pointer_gestures_v1.h @@ -0,0 +1,73 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_POINTER_GESTURES_V1_H +#define WLR_TYPES_WLR_POINTER_GESTURES_V1_H + +#include +#include +#include + +struct wlr_pointer_gestures_v1 { + struct wl_global *global; + struct wl_list resources; // wl_resource_get_link + struct wl_list swipes; // wl_resource_get_link + struct wl_list pinches; // wl_resource_get_link + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_pointer_gestures_v1 *wlr_pointer_gestures_v1_create( + struct wl_display *display); + +void wlr_pointer_gestures_v1_send_swipe_begin( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + uint32_t fingers); +void wlr_pointer_gestures_v1_send_swipe_update( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + double dx, + double dy); +void wlr_pointer_gestures_v1_send_swipe_end( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + bool cancelled); + +void wlr_pointer_gestures_v1_send_pinch_begin( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + uint32_t fingers); +void wlr_pointer_gestures_v1_send_pinch_update( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + double dx, + double dy, + double scale, + double rotation); +void wlr_pointer_gestures_v1_send_pinch_end( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + bool cancelled); + +void wlr_pointer_gestures_v1_destroy( + struct wlr_pointer_gestures_v1 *pointer_gestures_v1); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 9faa6358..c9cc5be9 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -17,6 +17,7 @@ protocols = [ [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], [wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'], [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], diff --git a/rootston/desktop.c b/rootston/desktop.c index d65266e5..fcb530cf 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -1084,6 +1084,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, wlr_foreign_toplevel_manager_v1_create(server->wl_display); desktop->relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server->wl_display); + desktop->pointer_gestures = + wlr_pointer_gestures_v1_create(server->wl_display); wlr_data_control_manager_v1_create(server->wl_display); diff --git a/rootston/seat.c b/rootston/seat.c index c69be8ab..a6281f50 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -85,6 +85,67 @@ static void handle_cursor_frame(struct wl_listener *listener, void *data) { roots_cursor_handle_frame(cursor); } +static void handle_swipe_begin(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, swipe_begin); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_swipe_begin *event = data; + wlr_pointer_gestures_v1_send_swipe_begin(gestures, cursor->seat->seat, + event->time_msec, event->fingers); +} + +static void handle_swipe_update(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, swipe_update); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_swipe_update *event = data; + wlr_pointer_gestures_v1_send_swipe_update(gestures, cursor->seat->seat, + event->time_msec, event->dx, event->dy); +} + +static void handle_swipe_end(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, swipe_end); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_swipe_end *event = data; + wlr_pointer_gestures_v1_send_swipe_end(gestures, cursor->seat->seat, + event->time_msec, event->cancelled); +} + +static void handle_pinch_begin(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, pinch_begin); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_pinch_begin *event = data; + wlr_pointer_gestures_v1_send_pinch_begin(gestures, cursor->seat->seat, + event->time_msec, event->fingers); +} + +static void handle_pinch_update(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, pinch_update); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_pinch_update *event = data; + wlr_pointer_gestures_v1_send_pinch_update(gestures, cursor->seat->seat, + event->time_msec, event->dx, event->dy, + event->scale, event->rotation); +} + +static void handle_pinch_end(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, pinch_end); + struct wlr_pointer_gestures_v1 *gestures = + cursor->seat->input->server->desktop->pointer_gestures; + struct wlr_event_pointer_pinch_end *event = data; + wlr_pointer_gestures_v1_send_pinch_end(gestures, cursor->seat->seat, + event->time_msec, event->cancelled); +} + static void handle_switch_toggle(struct wl_listener *listener, void *data) { struct roots_switch *lid_switch = wl_container_of(listener, lid_switch, toggle); @@ -454,6 +515,24 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { wl_signal_add(&wlr_cursor->events.frame, &seat->cursor->frame); seat->cursor->frame.notify = handle_cursor_frame; + wl_signal_add(&wlr_cursor->events.swipe_begin, &seat->cursor->swipe_begin); + seat->cursor->swipe_begin.notify = handle_swipe_begin; + + wl_signal_add(&wlr_cursor->events.swipe_update, &seat->cursor->swipe_update); + seat->cursor->swipe_update.notify = handle_swipe_update; + + wl_signal_add(&wlr_cursor->events.swipe_end, &seat->cursor->swipe_end); + seat->cursor->swipe_end.notify = handle_swipe_end; + + wl_signal_add(&wlr_cursor->events.pinch_begin, &seat->cursor->pinch_begin); + seat->cursor->pinch_begin.notify = handle_pinch_begin; + + wl_signal_add(&wlr_cursor->events.pinch_update, &seat->cursor->pinch_update); + seat->cursor->pinch_update.notify = handle_pinch_update; + + wl_signal_add(&wlr_cursor->events.pinch_end, &seat->cursor->pinch_end); + seat->cursor->pinch_end.notify = handle_pinch_end; + wl_signal_add(&wlr_cursor->events.touch_down, &seat->cursor->touch_down); seat->cursor->touch_down.notify = handle_touch_down; diff --git a/types/meson.build b/types/meson.build index 0c108d75..d459c1e4 100644 --- a/types/meson.build +++ b/types/meson.build @@ -48,6 +48,7 @@ lib_wlr_types = static_library( 'wlr_output_layout.c', 'wlr_output.c', 'wlr_pointer_constraints_v1.c', + 'wlr_pointer_gestures_v1.c', 'wlr_pointer.c', 'wlr_presentation_time.c', 'wlr_primary_selection.c', diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 5da865e5..19176a13 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -22,6 +22,12 @@ struct wlr_cursor_device { struct wl_listener button; struct wl_listener axis; struct wl_listener frame; + struct wl_listener swipe_begin; + struct wl_listener swipe_update; + struct wl_listener swipe_end; + struct wl_listener pinch_begin; + struct wl_listener pinch_update; + struct wl_listener pinch_end; struct wl_listener touch_down; struct wl_listener touch_up; @@ -83,6 +89,12 @@ struct wlr_cursor *wlr_cursor_create(void) { wl_signal_init(&cur->events.button); wl_signal_init(&cur->events.axis); wl_signal_init(&cur->events.frame); + wl_signal_init(&cur->events.swipe_begin); + wl_signal_init(&cur->events.swipe_update); + wl_signal_init(&cur->events.swipe_end); + wl_signal_init(&cur->events.pinch_begin); + wl_signal_init(&cur->events.pinch_update); + wl_signal_init(&cur->events.pinch_end); // touch signals wl_signal_init(&cur->events.touch_up); @@ -136,6 +148,12 @@ static void cursor_device_destroy(struct wlr_cursor_device *c_device) { wl_list_remove(&c_device->button.link); wl_list_remove(&c_device->axis.link); wl_list_remove(&c_device->frame.link); + wl_list_remove(&c_device->swipe_begin.link); + wl_list_remove(&c_device->swipe_update.link); + wl_list_remove(&c_device->swipe_end.link); + wl_list_remove(&c_device->pinch_begin.link); + wl_list_remove(&c_device->pinch_update.link); + wl_list_remove(&c_device->pinch_end.link); } else if (dev->type == WLR_INPUT_DEVICE_TOUCH) { wl_list_remove(&c_device->touch_down.link); wl_list_remove(&c_device->touch_up.link); @@ -423,6 +441,42 @@ static void handle_pointer_frame(struct wl_listener *listener, void *data) { wlr_signal_emit_safe(&device->cursor->events.frame, device->cursor); } +static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_swipe_begin *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_begin); + wlr_signal_emit_safe(&device->cursor->events.swipe_begin, event); +} + +static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_swipe_update *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_update); + wlr_signal_emit_safe(&device->cursor->events.swipe_update, event); +} + +static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_swipe_end *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_end); + wlr_signal_emit_safe(&device->cursor->events.swipe_end, event); +} + +static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_pinch_begin *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_begin); + wlr_signal_emit_safe(&device->cursor->events.pinch_begin, event); +} + +static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_pinch_update *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_update); + wlr_signal_emit_safe(&device->cursor->events.pinch_update, event); +} + +static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_pinch_end *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_end); + wlr_signal_emit_safe(&device->cursor->events.pinch_end, event); +} + static void handle_touch_up(struct wl_listener *listener, void *data) { struct wlr_event_touch_up *event = data; struct wlr_cursor_device *device; @@ -549,6 +603,24 @@ static struct wlr_cursor_device *cursor_device_create( wl_signal_add(&device->pointer->events.frame, &c_device->frame); c_device->frame.notify = handle_pointer_frame; + + wl_signal_add(&device->pointer->events.swipe_begin, &c_device->swipe_begin); + c_device->swipe_begin.notify = handle_pointer_swipe_begin; + + wl_signal_add(&device->pointer->events.swipe_update, &c_device->swipe_update); + c_device->swipe_update.notify = handle_pointer_swipe_update; + + wl_signal_add(&device->pointer->events.swipe_end, &c_device->swipe_end); + c_device->swipe_end.notify = handle_pointer_swipe_end; + + wl_signal_add(&device->pointer->events.pinch_begin, &c_device->pinch_begin); + c_device->pinch_begin.notify = handle_pointer_pinch_begin; + + wl_signal_add(&device->pointer->events.pinch_update, &c_device->pinch_update); + c_device->pinch_update.notify = handle_pointer_pinch_update; + + wl_signal_add(&device->pointer->events.pinch_end, &c_device->pinch_end); + c_device->pinch_end.notify = handle_pointer_pinch_end; } else if (device->type == WLR_INPUT_DEVICE_TOUCH) { wl_signal_add(&device->touch->events.motion, &c_device->touch_motion); c_device->touch_motion.notify = handle_touch_motion; diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index d7d1515a..6d50ef0b 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -12,6 +12,12 @@ void wlr_pointer_init(struct wlr_pointer *pointer, wl_signal_init(&pointer->events.button); wl_signal_init(&pointer->events.axis); wl_signal_init(&pointer->events.frame); + wl_signal_init(&pointer->events.swipe_begin); + wl_signal_init(&pointer->events.swipe_update); + wl_signal_init(&pointer->events.swipe_end); + wl_signal_init(&pointer->events.pinch_begin); + wl_signal_init(&pointer->events.pinch_update); + wl_signal_init(&pointer->events.pinch_end); } void wlr_pointer_destroy(struct wlr_pointer *pointer) { diff --git a/types/wlr_pointer_gestures_v1.c b/types/wlr_pointer_gestures_v1.c new file mode 100644 index 00000000..33b9db0f --- /dev/null +++ b/types/wlr_pointer_gestures_v1.c @@ -0,0 +1,339 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + +#include +#include +#include +#include +#include +#include +#include "util/signal.h" +#include "pointer-gestures-unstable-v1-protocol.h" + +#define POINTER_GESTURES_VERSION 1 + +static void resource_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void resource_remove_from_list(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static const struct zwp_pointer_gestures_v1_interface gestures_impl; +static const struct zwp_pointer_gesture_swipe_v1_interface swipe_impl; +static const struct zwp_pointer_gesture_pinch_v1_interface pinch_impl; + +static struct wlr_pointer_gestures_v1 *pointer_gestures_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwp_pointer_gestures_v1_interface, &gestures_impl)); + return wl_resource_get_user_data(resource); +} + +static struct wlr_seat *seat_from_pointer_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwp_pointer_gesture_swipe_v1_interface, &swipe_impl) || + wl_resource_instance_of(resource, + &zwp_pointer_gesture_pinch_v1_interface, &pinch_impl)); + return wl_resource_get_user_data(resource); +} + +void wlr_pointer_gestures_v1_send_swipe_begin( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + uint32_t fingers) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + uint32_t serial = wl_display_next_serial( + wl_client_get_display(focus_client)); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->swipes) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_swipe_v1_send_begin(gesture, serial, + time_msec, focus->resource, fingers); + } +} + +void wlr_pointer_gestures_v1_send_swipe_update( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + double dx, + double dy) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->swipes) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_swipe_v1_send_update(gesture, time_msec, + wl_fixed_from_double(dx), wl_fixed_from_double(dy)); + } +} + +void wlr_pointer_gestures_v1_send_swipe_end( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + bool cancelled) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + uint32_t serial = wl_display_next_serial( + wl_client_get_display(focus_client)); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->swipes) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_swipe_v1_send_end(gesture, serial, + time_msec, cancelled); + } +} + +static const struct zwp_pointer_gesture_swipe_v1_interface swipe_impl = { + .destroy = resource_handle_destroy, +}; + +static void get_swipe_gesture(struct wl_client *client, + struct wl_resource *gestures_resource, + uint32_t id, + struct wl_resource *pointer_resource) { + struct wlr_seat_client *seat_client = + wlr_seat_client_from_pointer_resource(pointer_resource); + struct wlr_seat *seat = NULL; + + if (seat_client != NULL) { + seat = seat_client->seat; + } + // Otherwise, the resource will be inert + // (NULL seat, so all seat comparisons will fail) + + struct wlr_pointer_gestures_v1 *gestures = + pointer_gestures_from_resource(gestures_resource); + + struct wl_resource *gesture = wl_resource_create(client, + &zwp_pointer_gesture_swipe_v1_interface, + wl_resource_get_version(gestures_resource), + id); + if (gesture == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(gesture, &swipe_impl, seat, + resource_remove_from_list); + wl_list_insert(&gestures->swipes, wl_resource_get_link(gesture)); +} + +void wlr_pointer_gestures_v1_send_pinch_begin( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + uint32_t fingers) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + uint32_t serial = wl_display_next_serial( + wl_client_get_display(focus_client)); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->pinches) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_pinch_v1_send_begin(gesture, serial, + time_msec, focus->resource, fingers); + } +} + +void wlr_pointer_gestures_v1_send_pinch_update( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + double dx, + double dy, + double scale, + double rotation) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->pinches) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_pinch_v1_send_update(gesture, time_msec, + wl_fixed_from_double(dx), wl_fixed_from_double(dy), + wl_fixed_from_double(scale), + wl_fixed_from_double(rotation)); + } +} + +void wlr_pointer_gestures_v1_send_pinch_end( + struct wlr_pointer_gestures_v1 *gestures, + struct wlr_seat *seat, + uint32_t time_msec, + bool cancelled) { + struct wlr_surface *focus = seat->pointer_state.focused_surface; + if (focus == NULL) { + return; + } + + struct wl_client *focus_client = wl_resource_get_client(focus->resource); + uint32_t serial = wl_display_next_serial( + wl_client_get_display(focus_client)); + + struct wl_resource *gesture; + wl_resource_for_each(gesture, &gestures->pinches) { + struct wlr_seat *gesture_seat = seat_from_pointer_resource(gesture); + struct wl_client *gesture_client = wl_resource_get_client(gesture); + if (gesture_seat != seat || gesture_client != focus_client) { + continue; + } + zwp_pointer_gesture_pinch_v1_send_end(gesture, serial, + time_msec, cancelled); + } +} + +static const struct zwp_pointer_gesture_pinch_v1_interface pinch_impl = { + .destroy = resource_handle_destroy, +}; + +static void get_pinch_gesture(struct wl_client *client, + struct wl_resource *gestures_resource, + uint32_t id, + struct wl_resource *pointer_resource) { + struct wlr_seat_client *seat_client = + wlr_seat_client_from_pointer_resource(pointer_resource); + struct wlr_seat *seat = NULL; + + if (seat_client != NULL) { + seat = seat_client->seat; + } + // Otherwise, the resource will be inert + // (NULL seat, so all seat comparisons will fail) + + struct wlr_pointer_gestures_v1 *gestures = + pointer_gestures_from_resource(gestures_resource); + + struct wl_resource *gesture = wl_resource_create(client, + &zwp_pointer_gesture_pinch_v1_interface, + wl_resource_get_version(gestures_resource), + id); + if (gesture == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(gesture, &pinch_impl, seat, + resource_remove_from_list); + wl_list_insert(&gestures->pinches, wl_resource_get_link(gesture)); +} + +static const struct zwp_pointer_gestures_v1_interface gestures_impl = { + .get_swipe_gesture = get_swipe_gesture, + .get_pinch_gesture = get_pinch_gesture, +}; + +static void pointer_gestures_v1_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_pointer_gestures_v1 *gestures = data; + + struct wl_resource *resource = wl_resource_create(wl_client, + &zwp_pointer_gestures_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(resource, + &gestures_impl, gestures, resource_remove_from_list); + wl_list_insert(&gestures->resources, wl_resource_get_link(resource)); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_pointer_gestures_v1 *tablet = + wl_container_of(listener, tablet, display_destroy); + wlr_pointer_gestures_v1_destroy(tablet); +} + +void wlr_pointer_gestures_v1_destroy(struct wlr_pointer_gestures_v1 *gestures) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &gestures->resources) { + wl_resource_destroy(resource); + } + wl_resource_for_each_safe(resource, tmp, &gestures->swipes) { + wl_resource_destroy(resource); + } + wl_resource_for_each_safe(resource, tmp, &gestures->pinches) { + wl_resource_destroy(resource); + } + wl_global_destroy(gestures->global); + free(gestures); +} + +struct wlr_pointer_gestures_v1 *wlr_pointer_gestures_v1_create( + struct wl_display *display) { + struct wlr_pointer_gestures_v1 *gestures = + calloc(1, sizeof(struct wlr_pointer_gestures_v1)); + if (!gestures) { + return NULL; + } + + wl_list_init(&gestures->resources); + wl_list_init(&gestures->swipes); + wl_list_init(&gestures->pinches); + + gestures->global = wl_global_create(display, + &zwp_pointer_gestures_v1_interface, POINTER_GESTURES_VERSION, + gestures, pointer_gestures_v1_bind); + if (gestures->global == NULL) { + free(gestures); + return NULL; + } + + gestures->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &gestures->display_destroy); + + return gestures; +}