diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4fc27126..f86661d8 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -295,6 +295,7 @@ video tutorials. - Jonas Ådahl - Lasse Öörni - Leonard König + - pfgithub - All the unmentioned and anonymous contributors in the GLFW community, for bug reports, patches, feedback, testing and encouragement diff --git a/README.md b/README.md index 52306188..91646506 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,8 @@ information on what to include when reporting a bug. - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to `GLFW_NATIVE_CONTEXT_API` (#2518) + - [Cocoa & Wayland] Added `glfwSetTrackpadZoomCallback` and `glfwSetTrackpadRotateCallback` + for trackpad zoom and rotate events (#90) ## Contact diff --git a/deps/wayland/pointer-gestures-unstable-v1.xml b/deps/wayland/pointer-gestures-unstable-v1.xml new file mode 100644 index 00000000..f92a1160 --- /dev/null +++ b/deps/wayland/pointer-gestures-unstable-v1.xml @@ -0,0 +1,253 @@ + + + + + + A global interface to provide semantic touchpad gestures for a given + pointer. + + Three gestures are currently supported: swipe, pinch, and hold. + Pinch and swipe gestures follow a three-stage cycle: begin, update, + end, hold gestures follow a two-stage cycle: begin and end. All + gestures are identified by a unique id. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + Create a swipe gesture object. See the + wl_pointer_gesture_swipe interface for details. + + + + + + + + Create a pinch gesture object. See the + wl_pointer_gesture_pinch interface for details. + + + + + + + + + + Destroy the pointer gesture object. Swipe, pinch and hold objects + created via this gesture object remain valid. + + + + + + + + Create a hold gesture object. See the + wl_pointer_gesture_hold interface for details. + + + + + + + + + + A swipe gesture object notifies a client about a multi-finger swipe + gesture detected on an indirect input device such as a touchpad. + The gesture is usually initiated by multiple fingers moving in the + same direction but once initiated the direction may change. + The precise conditions of when such a gesture is detected are + implementation-dependent. + + A gesture consists of three stages: begin, update (optional) and end. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a multi-finger swipe gesture is detected + on the device. + + + + + + + + + + This event is sent when a multi-finger swipe gesture changes the + position of the logical center. + + The dx and dy coordinates are relative coordinates of the logical + center of the gesture compared to the previous event. + + + + + + + + + This event is sent when a multi-finger swipe gesture ceases to + be valid. This may happen when one or more fingers are lifted or + the gesture is cancelled. + + When a gesture is cancelled, the client should undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + + + A pinch gesture object notifies a client about a multi-finger pinch + gesture detected on an indirect input device such as a touchpad. + The gesture is usually initiated by multiple fingers moving towards + each other or away from each other, or by two or more fingers rotating + around a logical center of gravity. The precise conditions of when + such a gesture is detected are implementation-dependent. + + A gesture consists of three stages: begin, update (optional) and end. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a multi-finger pinch gesture is detected + on the device. + + + + + + + + + + This event is sent when a multi-finger pinch gesture changes the + position of the logical center, the rotation or the relative scale. + + The dx and dy coordinates are relative coordinates in the + surface coordinate space of the logical center of the gesture. + + The scale factor is an absolute scale compared to the + pointer_gesture_pinch.begin event, e.g. a scale of 2 means the fingers + are now twice as far apart as on pointer_gesture_pinch.begin. + + The rotation is the relative angle in degrees clockwise compared to the previous + pointer_gesture_pinch.begin or pointer_gesture_pinch.update event. + + + + + + + + + + + This event is sent when a multi-finger pinch gesture ceases to + be valid. This may happen when one or more fingers are lifted or + the gesture is cancelled. + + When a gesture is cancelled, the client should undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + + + + A hold gesture object notifies a client about a single- or + multi-finger hold gesture detected on an indirect input device such as + a touchpad. The gesture is usually initiated by one or more fingers + being held down without significant movement. The precise conditions + of when such a gesture is detected are implementation-dependent. + + In particular, this gesture may be used to cancel kinetic scrolling. + + A hold gesture consists of two stages: begin and end. Unlike pinch and + swipe there is no update stage. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a hold gesture is detected on the device. + + + + + + + + + + This event is sent when a hold gesture ceases to + be valid. This may happen when the holding fingers are lifted or + the gesture is cancelled, for example if the fingers move past an + implementation-defined threshold, the finger count changes or the hold + gesture changes into a different type of gesture. + + When a gesture is cancelled, the client may need to undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + diff --git a/docs/compat.md b/docs/compat.md index 5072d5c1..e85d723e 100644 --- a/docs/compat.md +++ b/docs/compat.md @@ -158,6 +158,12 @@ less than the actual scale. [fractional-scale-v1]: https://wayland.app/protocols/fractional-scale-v1 +GLFW uses the [pointer-gestures-unstable-v1][] protocol to handle trackpad +pinch and rotate gestures. If the running compositor does not support this +protocol, trackpad pinch and rotate gestures will not be emitted. + +[pointer-gestures-unstable-v1]: https://wayland.app/protocols/pointer-gestures-unstable-v1 + ## GLX extensions {#compat_glx} diff --git a/docs/input.md b/docs/input.md index 3ef1aebe..2bfa9c7d 100644 --- a/docs/input.md +++ b/docs/input.md @@ -581,6 +581,42 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) A normal mouse wheel, being vertical, provides offsets along the Y-axis. +### Trackpad zoom and rotate {#input_mouse_trackpad_gestures} + +Trackpad events are currently only available on macOS and Wayland (Linux). + +If you wish to be notified when a zoom gesture is performed on a trackpad, +set the trackpadZoom callback. + +```c +glfwSetTrackpadZoomCallback(window, trackpad_zoom_callback); +``` + +The callback function receives the scale of the zoom, which is a ratio that +should be multiplied by the current zoom level to get the new zoom level. + +```c +static void trackpad_zoom_callback(GLFWwindow* window, double scale) +{ + my_app->zoom_level *= scale; +} +``` + +For trackpad rotate gestures, set the trackpadRotateCallback. + +```c +glfwSetTrackpadRotateCallback(window, trackpad_rotate_callback); +``` + +The callback function recieves the angle, in degrees, to rotate by. + +```c +static void trackpad_rotate_callback(GLFWwindow* window, double angle) +{ + my_app->rotation_angle_degrees += angle; +} +``` + ## Joystick input {#joystick} diff --git a/docs/news.md b/docs/news.md index 148d0871..7a422b14 100644 --- a/docs/news.md +++ b/docs/news.md @@ -14,6 +14,12 @@ values over 8. For compatibility with older versions, the @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode needs to be set to make use of this. +### Support for trackpad zoom and rotate on macOS and Wayland + +Trackpad zoom and rotate events are now supported on macOS and Wayland using +[glfwSetTrackpadZoomCallback](@ref glfwSetTrackpadZoomCallback) and [glfwSetTrackpadRotateCallback](@ref glfwSetTrackpadRotateCallback). These +events will not yet emit anything on Windows or X11. + ## Caveats {#caveats} ## Deprecations {#deprecations} diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 79b06288..20d548e2 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1871,6 +1871,41 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); */ typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); +/*! @brief The function pointer type for trackpad zoom callbacks. + * + * This is the function pointer type for trackpad zoom callbacks. A zoom + * callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, double scale) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] scale The manigification amount, to be multiplied by the current + * scale factor to get the new scale factor. + * + * @sa @ref glfwSetTrackpadZoomCallback + * + * @ingroup input + */ +typedef void (* GLFWtrackpadzoomfun)(GLFWwindow* window, double scale); + +/*! @brief The function pointer type for trackpad rotate callbacks. + * + * This is the function pointer type for trackpad rotate callbacks. A rotate + * callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, double angle) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] angle The rotation amount, in degrees + * + * @sa @ref glfwSetTrackpadRotateCallback + * + * @ingroup input + */ +typedef void (* GLFWtrackpadrotatefun)(GLFWwindow* window, double angle); + /*! @brief The function pointer type for keyboard key callbacks. * * This is the function pointer type for keyboard key callbacks. A keyboard @@ -5430,6 +5465,66 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback); +/*! @brief Sets the trackpad zoom callback. + * + * This function sets the trackpad zoom of the specified window, which is + * called when a trackpad magnification gesture is used on macOS. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new trackpad zoom callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double scale) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWtrackpadzoomfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_trackpad_gestures + * + * @since Added in version 3.5. + * + * @ingroup input + */ +GLFWAPI GLFWtrackpadzoomfun glfwSetTrackpadZoomCallback(GLFWwindow* window, GLFWtrackpadzoomfun callback); + +/*! @brief Sets the trackpad rotate callback. + * + * This function sets the trackpad rotate of the specified window, which is + * called when a trackpad rotation gesture is used on macOS. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new trackpad rotate callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double angle) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWtrackpadrotatefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_trackpad_gestures + * + * @since Added in version 3.5. + * + * @ingroup input + */ +GLFWAPI GLFWtrackpadrotatefun glfwSetTrackpadRotateCallback(GLFWwindow* window, GLFWtrackpadrotatefun callback); + /*! @brief Sets the path drop callback. * * This function sets the path drop callback of the specified window, which is diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a085b2b..5c050f34 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,6 +105,7 @@ if (GLFW_BUILD_WAYLAND) generate_wayland_protocol("fractional-scale-v1.xml") generate_wayland_protocol("xdg-activation-v1.xml") generate_wayland_protocol("xdg-decoration-unstable-v1.xml") + generate_wayland_protocol("pointer-gestures-unstable-v1.xml") endif() if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index e69b5fe0..ea84d9ab 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -614,6 +614,24 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _glfwInputScroll(window, deltaX, deltaY); } +- (void)magnifyWithEvent:(NSEvent *)event +{ + double magnification = [event magnification]; + + // 1.0 is added to convert the magnification value to a scale factor, + // as suggested in apple documentation + if (fabs(magnification) > 0.0) + _glfwInputTrackpadZoom(window, magnification + 1.0); +} + +- (void)rotateWithEvent:(NSEvent *)event +{ + double rotation = [event rotation]; + + if (fabs(rotation) > 0.0) + _glfwInputTrackpadRotate(window, rotation); +} + - (NSDragOperation)draggingEntered:(id )sender { // HACK: We don't know what to say here because we don't know what the diff --git a/src/input.c b/src/input.c index c619eefc..17c66b64 100644 --- a/src/input.c +++ b/src/input.c @@ -342,6 +342,30 @@ void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); } +// Notifies shared code of a trackpad zoom event +// +void _glfwInputTrackpadZoom(_GLFWwindow* window, double scale) +{ + assert(window != NULL); + assert(scale > -FLT_MAX); + assert(scale < FLT_MAX); + + if (window->callbacks.trackpadZoom) + window->callbacks.trackpadZoom((GLFWwindow*) window, scale); +} + +// Notifies shared code of a trackpad rotate event +// +void _glfwInputTrackpadRotate(_GLFWwindow* window, double angle) +{ + assert(window != NULL); + assert(angle > -FLT_MAX); + assert(angle < FLT_MAX); + + if (window->callbacks.trackpadRotate) + window->callbacks.trackpadRotate((GLFWwindow*) window, angle); +} + // Notifies shared code of a mouse button click event // void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) @@ -1034,6 +1058,28 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, return cbfun; } +GLFWAPI GLFWtrackpadzoomfun glfwSetTrackpadZoomCallback(GLFWwindow* handle, + GLFWtrackpadzoomfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP(GLFWtrackpadzoomfun, window->callbacks.trackpadZoom, cbfun); + return cbfun; +} + +GLFWAPI GLFWtrackpadrotatefun glfwSetTrackpadRotateCallback(GLFWwindow* handle, + GLFWtrackpadrotatefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP(GLFWtrackpadrotatefun, window->callbacks.trackpadRotate, cbfun); + return cbfun; +} + GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); diff --git a/src/internal.h b/src/internal.h index 4f097aa8..7a58cbae 100644 --- a/src/internal.h +++ b/src/internal.h @@ -577,6 +577,8 @@ struct _GLFWwindow GLFWcursorposfun cursorPos; GLFWcursorenterfun cursorEnter; GLFWscrollfun scroll; + GLFWtrackpadzoomfun trackpadZoom; + GLFWtrackpadrotatefun trackpadRotate; GLFWkeyfun key; GLFWcharfun character; GLFWcharmodsfun charmods; @@ -935,6 +937,8 @@ void _glfwInputKey(_GLFWwindow* window, void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); +void _glfwInputTrackpadZoom(_GLFWwindow* window, double scale); +void _glfwInputTrackpadRotate(_GLFWwindow* window, double angle); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); diff --git a/src/wl_init.c b/src/wl_init.c index ef9e4503..9e0c11ec 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -49,6 +49,7 @@ #include "fractional-scale-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" +#include "pointer-gestures-unstable-v1-client-protocol.h" // NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of // wl_interface pointers 'types', making it impossible to combine several unmodified @@ -91,6 +92,10 @@ #include "idle-inhibit-unstable-v1-client-protocol-code.h" #undef types +#define types _glfw_pointer_gestures_types +#include "pointer-gestures-unstable-v1-client-protocol-code.h" +#undef types + static void wmBaseHandlePing(void* userData, struct xdg_wm_base* wmBase, uint32_t serial) @@ -208,6 +213,14 @@ static void registryHandleGlobal(void* userData, &wp_fractional_scale_manager_v1_interface, 1); } + else if (strcmp(interface, "zwp_pointer_gestures_v1") == 0) + { + _glfw.wl.pointerGestures = + wl_registry_bind(registry, name, + &zwp_pointer_gestures_v1_interface, + 1); + _glfwAddPointerGesturesListeners(_glfw.wl.pointerGestures); + } } static void registryHandleGlobalRemove(void* userData, @@ -988,6 +1001,10 @@ void _glfwTerminateWayland(void) xdg_activation_v1_destroy(_glfw.wl.activationManager); if (_glfw.wl.fractionalScaleManager) wp_fractional_scale_manager_v1_destroy(_glfw.wl.fractionalScaleManager); + if (_glfw.wl.pinchGesture) + zwp_pointer_gesture_pinch_v1_destroy(_glfw.wl.pinchGesture); + if (_glfw.wl.pointerGestures) + zwp_pointer_gestures_v1_destroy(_glfw.wl.pointerGestures); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/src/wl_platform.h b/src/wl_platform.h index afa6f50a..cc1a0588 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -116,6 +116,7 @@ struct wl_output; #define zwp_pointer_constraints_v1_interface _glfw_zwp_pointer_constraints_v1_interface #define zwp_relative_pointer_v1_interface _glfw_zwp_relative_pointer_v1_interface #define zwp_relative_pointer_manager_v1_interface _glfw_zwp_relative_pointer_manager_v1_interface +#define zwp_pointer_gestures_v1_interface _glfw_zwp_pointer_gestures_v1_interface #define wp_viewport_interface _glfw_wp_viewport_interface #define wp_viewporter_interface _glfw_wp_viewporter_interface #define xdg_toplevel_interface _glfw_xdg_toplevel_interface @@ -438,6 +439,8 @@ typedef struct _GLFWlibraryWayland struct zwp_idle_inhibit_manager_v1* idleInhibitManager; struct xdg_activation_v1* activationManager; struct wp_fractional_scale_manager_v1* fractionalScaleManager; + struct zwp_pointer_gestures_v1* pointerGestures; + struct zwp_pointer_gesture_pinch_v1* pinchGesture; _GLFWofferWayland* offers; unsigned int offerCount; @@ -469,6 +472,8 @@ typedef struct _GLFWlibraryWayland short int scancodes[GLFW_KEY_LAST + 1]; char keynames[GLFW_KEY_LAST + 1][5]; + double pinchGesturePreviousScale; + struct { void* handle; struct xkb_context* context; @@ -691,4 +696,5 @@ void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window); void _glfwAddSeatListenerWayland(struct wl_seat* seat); void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device); +void _glfwAddPointerGesturesListeners(struct zwp_pointer_gestures_v1* pointer_gestures); diff --git a/src/wl_window.c b/src/wl_window.c index 72c1a402..3f2b6099 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -51,6 +51,7 @@ #include "xdg-activation-v1-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" #include "fractional-scale-v1-client-protocol.h" +#include "pointer-gestures-unstable-v1-client-protocol.h" #define GLFW_BORDER_SIZE 4 #define GLFW_CAPTION_HEIGHT 24 @@ -1631,6 +1632,53 @@ static const struct wl_pointer_listener pointerListener = pointerHandleAxis, }; +static void pointerGesturesHandlePinchBegin(void *userData, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + _glfw.wl.pinchGesturePreviousScale = 1.0; +} + +static void pointerGesturesHandlePinchMotion(void *userData, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t time, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t scale, + wl_fixed_t rotation) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + double zoom_value = wl_fixed_to_double(scale); + double prev_zoom_value = _glfw.wl.pinchGesturePreviousScale; + double zoom_delta = zoom_value / prev_zoom_value; + _glfw.wl.pinchGesturePreviousScale = zoom_value; + + double rotation_value = wl_fixed_to_double(rotation); + + _glfwInputTrackpadZoom(window, zoom_delta); + _glfwInputTrackpadRotate(window, rotation_value); +} + +static void pointerGesturesHandlePinchEnd(void *userData, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + _glfw.wl.pinchGesturePreviousScale = 1.0; +} + +static const struct zwp_pointer_gesture_pinch_v1_listener pinchGestureListener = +{ + pointerGesturesHandlePinchBegin, + pointerGesturesHandlePinchMotion, + pointerGesturesHandlePinchEnd, +}; + static void keyboardHandleKeymap(void* userData, struct wl_keyboard* keyboard, uint32_t format, @@ -1885,6 +1933,8 @@ static void seatHandleCapabilities(void* userData, { _glfw.wl.pointer = wl_seat_get_pointer(seat); wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + + _glfwAddPointerGesturesListeners(_glfw.wl.pointerGestures); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) { @@ -2120,6 +2170,21 @@ void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device) wl_data_device_add_listener(device, &dataDeviceListener, NULL); } +void _glfwAddPointerGesturesListeners(struct zwp_pointer_gestures_v1* pointer_gestures) +{ + if (_glfw.wl.pinchGesture) return; + if (!_glfw.wl.pointer) return; + + _glfw.wl.pinchGesture = + zwp_pointer_gestures_v1_get_pinch_gesture( + pointer_gestures, + _glfw.wl.pointer); + zwp_pointer_gesture_pinch_v1_add_listener(_glfw.wl.pinchGesture, + &pinchGestureListener, + NULL); + // zwp_pointer_gestures_v1 +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// diff --git a/tests/events.c b/tests/events.c index ab3b99a7..f3c68949 100644 --- a/tests/events.c +++ b/tests/events.c @@ -397,6 +397,20 @@ static void scroll_callback(GLFWwindow* window, double x, double y) counter++, slot->number, glfwGetTime(), x, y); } +static void trackpad_zoom_callback(GLFWwindow* window, double scale) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Trackpad Zoom: %0.3f\n", + counter++, slot->number, glfwGetTime(), scale); +} + +static void trackpad_rotate_callback(GLFWwindow* window, double angle) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Trackpad Rotate: %0.3f\n", + counter++, slot->number, glfwGetTime(), angle); +} + static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { Slot* slot = glfwGetWindowUserPointer(window); @@ -647,6 +661,8 @@ int main(int argc, char** argv) glfwSetCursorPosCallback(slots[i].window, cursor_position_callback); glfwSetCursorEnterCallback(slots[i].window, cursor_enter_callback); glfwSetScrollCallback(slots[i].window, scroll_callback); + glfwSetTrackpadZoomCallback(slots[i].window, trackpad_zoom_callback); + glfwSetTrackpadRotateCallback(slots[i].window, trackpad_rotate_callback); glfwSetKeyCallback(slots[i].window, key_callback); glfwSetCharCallback(slots[i].window, char_callback); glfwSetDropCallback(slots[i].window, drop_callback);