[Bf-blender-cvs] [8bb211a7716] master: GHOST/Wayland: multi-touch gesture support
Campbell Barton
noreply at git.blender.org
Sat Oct 22 09:02:26 CEST 2022
Commit: 8bb211a771642144ac75ba6be0c1897c836a6276
Author: Campbell Barton
Date: Sat Oct 22 16:49:09 2022 +1100
Branches: master
https://developer.blender.org/rB8bb211a771642144ac75ba6be0c1897c836a6276
GHOST/Wayland: multi-touch gesture support
Add support for zoom & rotate gestures, hold and swipe may
be used in the future although swipe maps to 2D smooth-scroll for
Gnome & KDE.
Tested to work with Apple track-pad & Wacom tablet on Gnome & KDE.
===================================================================
M intern/ghost/CMakeLists.txt
M intern/ghost/intern/GHOST_SystemWayland.cpp
M intern/ghost/intern/GHOST_SystemWayland.h
===================================================================
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index c05f2a327b1..fb10530bfae 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -372,6 +372,10 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
)
+ # Pointer-gestures (multi-touch).
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml"
+ )
# Tablet.
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml"
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 39f392e62b9..442e51d4f7c 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -51,6 +51,7 @@
/* Generated by `wayland-scanner`. */
#include <pointer-constraints-unstable-v1-client-protocol.h>
+#include <pointer-gestures-unstable-v1-client-protocol.h>
#include <primary-selection-unstable-v1-client-protocol.h>
#include <relative-pointer-unstable-v1-client-protocol.h>
#include <tablet-unstable-v2-client-protocol.h>
@@ -461,6 +462,39 @@ struct GWL_SeatStatePointerScroll {
enum wl_pointer_axis_source axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
};
+/**
+ * Utility struct to access rounded values from a scaled `wl_fixed_t`,
+ * without loosing information.
+ *
+ * As the rounded result is rounded to a lower precision integer,
+ * the high precision value is accumulated and converted to an integer to
+ * prevent the accumulation of rounded values giving an inaccurate result.
+ *
+ * \note This is simple but doesn't read well when expanded multiple times inline.
+ */
+struct GWL_ScaledFixedT {
+ wl_fixed_t value = 0;
+ wl_fixed_t factor = 1;
+};
+
+static int gwl_scaled_fixed_t_add_and_calc_rounded_delta(GWL_ScaledFixedT *sf,
+ const wl_fixed_t add)
+{
+ const int result_prev = wl_fixed_to_int(sf->value * sf->factor);
+ sf->value += add;
+ const int result_curr = wl_fixed_to_int(sf->value * sf->factor);
+ return result_curr - result_prev;
+}
+
+/**
+ * Gesture state.
+ * This is needed so the gesture values can be converted to deltas.
+ */
+struct GWL_SeatStatePointerGesture_Pinch {
+ GWL_ScaledFixedT scale;
+ GWL_ScaledFixedT rotation;
+};
+
/**
* State of the keyboard (in #GWL_Seat).
*/
@@ -570,6 +604,10 @@ struct GWL_Seat {
struct wl_keyboard *wl_keyboard = nullptr;
struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr;
+ struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold = nullptr;
+ struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch = nullptr;
+ struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe = nullptr;
+
/** All currently active tablet tools (needed for changing the cursor). */
std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
@@ -578,6 +616,7 @@ struct GWL_Seat {
GWL_SeatStatePointer pointer;
GWL_SeatStatePointerScroll pointer_scroll;
+ GWL_SeatStatePointerGesture_Pinch pointer_gesture_pinch;
/** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */
GWL_SeatStatePointer tablet;
@@ -683,6 +722,7 @@ struct GWL_Display {
struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr;
struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr;
struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr;
+ struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr;
@@ -844,8 +884,8 @@ static void display_destroy(GWL_Display *display)
zwp_pointer_constraints_v1_destroy(display->wp_pointer_constraints);
}
- if (display->wp_primary_selection_device_manager) {
- zwp_primary_selection_device_manager_v1_destroy(display->wp_primary_selection_device_manager);
+ if (display->wp_pointer_gestures) {
+ zwp_pointer_gestures_v1_destroy(display->wp_pointer_gestures);
}
if (display->wl_compositor) {
@@ -2269,6 +2309,223 @@ static const struct wl_pointer_listener pointer_listener = {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer Gesture: Hold), #zwp_pointer_gesture_hold_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_POINTER_GESTURE_HOLD = {"ghost.wl.handle.pointer_gesture.hold"};
+#define LOG (&LOG_WL_POINTER_GESTURE_HOLD)
+
+static void gesture_hold_handle_begin(
+ void * /*data*/,
+ struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*surface*/,
+ uint32_t fingers)
+{
+ CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers);
+}
+
+static void gesture_hold_handle_end(
+ void * /*data*/,
+ struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ int32_t cancelled)
+{
+ CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled);
+}
+
+static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = {
+ gesture_hold_handle_begin,
+ gesture_hold_handle_end,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer Gesture: Pinch), #zwp_pointer_gesture_pinch_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_POINTER_GESTURE_PINCH = {"ghost.wl.handle.pointer_gesture.pinch"};
+#define LOG (&LOG_WL_POINTER_GESTURE_PINCH)
+
+static void gesture_pinch_handle_begin(void *data,
+ struct zwp_pointer_gesture_pinch_v1 * /*pinch*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*surface*/,
+ uint32_t fingers)
+{
+ CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers);
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ /* Reset defaults. */
+ seat->pointer_gesture_pinch = GWL_SeatStatePointerGesture_Pinch{};
+
+ GHOST_WindowWayland *win = nullptr;
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ win = ghost_wl_surface_user_data(wl_surface_focus);
+ }
+ const wl_fixed_t win_scale = win ? win->scale() : 1;
+
+ /* NOTE(@campbellbarton): Scale factors match Blender's operators & default preferences.
+ * For these values to work correctly, operator logic will need to be changed not to scale input
+ * by the region size (as with 3D view zoom) or preference for 3D view orbit sensitivity.
+ *
+ * By working "correctly" I mean that a rotation action where the users fingers rotate to
+ * opposite locations should always rotate the viewport 180d, since users will expect the
+ * physical location of their fingers to match the viewport.
+ * Similarly with zoom, the scale value from the pinch action can be mapped to a zoom level
+ * although unlike rotation, an inexact mapping is less noticeable.
+ * Users may even prefer the zoom level to be scaled - which could be a preference. */
+ seat->pointer_gesture_pinch.scale.value = wl_fixed_from_int(1);
+ /* The value 300 matches a value used in clip & image zoom operators.
+ * It seems OK for the 3D view too. */
+ seat->pointer_gesture_pinch.scale.factor = 300 * win_scale;
+ /* The value 5 is used on macOS and roughly maps 1:1 with turntable rotation,
+ * although preferences can scale the sensitivity (which would be skipped ideally). */
+ seat->pointer_gesture_pinch.rotation.factor = 5 * win_scale;
+}
+
+static void gesture_pinch_handle_update(void *data,
+ struct zwp_pointer_gesture_pinch_v1 * /*pinch*/,
+ uint32_t /*time*/,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t scale,
+ wl_fixed_t rotation)
+{
+ CLOG_INFO(LOG,
+ 2,
+ "update (dx=%.3f, dy=%.3f, scale=%.3f, rotation=%.3f)",
+ wl_fixed_to_double(dx),
+ wl_fixed_to_double(dy),
+ wl_fixed_to_double(scale),
+ wl_fixed_to_double(rotation));
+
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+
+ GHOST_WindowWayland *win = nullptr;
+
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ win = ghost_wl_surface_user_data(wl_surface_focus);
+ }
+
+ /* Scale defaults to `wl_fixed_from_int(1)` which may change while pinching.
+ * This needs to be converted to a delta. */
+ const wl_fixed_t scale_delta = scale - seat->pointer_gesture_pinch.scale.value;
+ const int scale_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta(
+ &seat->pointer_gesture_pinch.scale, scale_delta);
+
+ /* Rotation in degrees, unlike scale this is a delta. */
+ const int rotation_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta(
+ &seat->pointer_gesture_pinch.rotation, rotation);
+
+ if (win) {
+ const wl_fixed_t win_scale = win->scale();
+ const int32_t event_xy[2] = {
+ wl_fixed_to_int(win_scale * seat->pointer.xy[0]),
+ wl_fixed_to_int(win_scale * seat->pointer.xy[1]),
+ };
+ if (scale_as_delta_px) {
+ seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(),
+ win,
+ GHOST_kTrackpadEventMagnify,
+ event_xy[0],
+ event_xy[1],
+ scale_as_delta_px,
+ 0,
+ false));
+ }
+
+ if (rotation_as_delta_px) {
+ seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(),
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list