diff --git a/docs/news.md b/docs/news.md index c832fa16..7a422b14 100644 --- a/docs/news.md +++ b/docs/news.md @@ -14,12 +14,11 @@ 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 +### Support for trackpad zoom and rotate on macOS and Wayland -Trackpad zoom and rotate events are now supported on macOS using +Trackpad zoom and rotate events are now supported on macOS and Wayland using [glfwSetTrackpadZoomCallback](@ref glfwSetTrackpadZoomCallback) and [glfwSetTrackpadRotateCallback](@ref glfwSetTrackpadRotateCallback). These -events have not yet been implemented and currently will not emit anything on -Windows, X11, and Wayland. +events will not yet emit anything on Windows or X11. ## Caveats {#caveats} diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index bebaf8e4..4152b648 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1880,7 +1880,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffse * @endcode * * @param[in] window The window that received the event. - * @param[in] scale The manigification amount + * @param[in] scale The manigification amount, as a scale factor * * @sa @ref glfwSetTrackpadZoomCallback * @@ -1897,7 +1897,7 @@ typedef void (* GLFWtrackpadzoomfun)(GLFWwindow* window, double scale); * @endcode * * @param[in] window The window that received the event. - * @param[in] angle The rotation amount + * @param[in] angle The rotation amount, in degrees * * @sa @ref glfwSetTrackpadRotateCallback * diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 463b898d..cbcc7b87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -104,6 +104,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 05cb2e51..ea84d9ab 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -618,8 +618,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { 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); + _glfwInputTrackpadZoom(window, magnification + 1.0); } - (void)rotateWithEvent:(NSEvent *)event diff --git a/src/wl_init.c b/src/wl_init.c index 76054bc6..3c63ad84 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 "wayland-pointer-gestures-unstable-v1-client-protocol-code.h" +#undef types + static void wmBaseHandlePing(void* userData, struct xdg_wm_base* wmBase, uint32_t serial) @@ -207,6 +212,13 @@ static void registryHandleGlobal(void* userData, wl_registry_bind(registry, name, &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); } } @@ -984,6 +996,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 f3e8cba2..71da0913 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -117,6 +117,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 @@ -435,6 +436,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; @@ -466,6 +469,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; @@ -686,4 +691,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 2e842aaa..09493134 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 //////