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);